xamarin_getifaddrs.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. #include <assert.h>
  2. #include <errno.h>
  3. #if !defined(WIN32) && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2) && !defined(NN_COMPILER_RVCT)
  4. #include <dlfcn.h>
  5. #endif
  6. #include <limits.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #if !defined(NN_COMPILER_RVCT) && !defined(SN_TARGET_PSP2)
  11. #include <sys/types.h>
  12. #endif
  13. #if !defined(WIN32) && !defined(NN_COMPILER_RVCT)
  14. #include <sys/socket.h>
  15. #include <unistd.h>
  16. #endif
  17. #if LINUX
  18. #include <linux/netlink.h>
  19. #include <linux/rtnetlink.h>
  20. #include <linux/if_arp.h>
  21. #endif /* def LINUX */
  22. #if !defined(WIN32) && !defined(NN_COMPILER_RVCT) && !defined(SN_TARGET_PSP2)
  23. #include <netinet/in.h>
  24. #endif
  25. #if ANDROID
  26. #include <android/log.h>
  27. #endif
  28. #include "logger.h"
  29. #include "xamarin_getifaddrs.h"
  30. /* These aren't defined in android's rtnetlink.h (as of ndk 9d). We define fake values for them if
  31. * they aren't found so that the debug code works properly. We could skip them but future versions
  32. * of the NDK might include definitions for them.
  33. */
  34. #ifndef IFLA_LINKINFO
  35. #define IFLA_LINKINFO 1000
  36. #endif
  37. #ifndef IFLA_NET_NS_PID
  38. #define IFLA_NET_NS_PID 1001
  39. #endif
  40. #ifndef IFLA_IFALIAS
  41. #define IFLA_IFALIAS 1002
  42. #endif
  43. #ifndef IFLA_NUM_VF
  44. #define IFLA_NUM_VF 1003
  45. #endif
  46. #ifndef IFLA_VFINFO_LIST
  47. #define IFLA_VFINFO_LIST 1004
  48. #endif
  49. #ifndef IFLA_STATS64
  50. #define IFLA_STATS64 1005
  51. #endif
  52. #ifndef IFLA_VF_PORTS
  53. #define IFLA_VF_PORTS 1006
  54. #endif
  55. #ifndef IFLA_PORT_SELF
  56. #define IFLA_PORT_SELF 1007
  57. #endif
  58. #ifndef IFLA_AF_SPEC
  59. #define IFLA_AF_SPEC 1008
  60. #endif
  61. #ifndef IFLA_GROUP
  62. #define IFLA_GROUP 1009
  63. #endif
  64. #ifndef IFLA_NET_NS_FD
  65. #define IFLA_NET_NS_FD 1010
  66. #endif
  67. #ifndef IFLA_EXT_MASK
  68. #define IFLA_EXT_MASK 1011
  69. #endif
  70. #ifndef IFLA_PROMISCUITY
  71. #define IFLA_PROMISCUITY 1012
  72. #endif
  73. #ifndef IFLA_NUM_TX_QUEUES
  74. #define IFLA_NUM_TX_QUEUES 1013
  75. #endif
  76. #ifndef IFLA_NUM_RX_QUEUES
  77. #define IFLA_NUM_RX_QUEUES 1014
  78. #endif
  79. #ifndef IFLA_CARRIER
  80. #define IFLA_CARRIER 1015
  81. #endif
  82. #ifndef IFLA_PHYS_PORT_ID
  83. #define IFLA_PHYS_PORT_ID 1016
  84. #endif
  85. /* The amount of data we read from the kernel in one call */
  86. #define RESPONSE_BUFFER_SIZE 1024
  87. /* Maximum interface address label size, should be more than enough */
  88. #define MAX_IFA_LABEL_SIZE 1024
  89. #if LINUX
  90. /* This is the message we send to the kernel */
  91. typedef struct
  92. {
  93. struct nlmsghdr header;
  94. struct rtgenmsg message;
  95. } netlink_request;
  96. typedef struct
  97. {
  98. int sock_fd;
  99. int seq;
  100. struct sockaddr_nl them; /* kernel end */
  101. struct sockaddr_nl us; /* our end */
  102. struct msghdr message_header; /* for use with sendmsg */
  103. struct iovec payload_vector; /* Used to send netlink_request */
  104. } netlink_session;
  105. /* Turns out that quite a few link types have address length bigger than the 8 bytes allocated in
  106. * this structure as defined by the OS. Examples are Infiniband or ipv6 tunnel devices
  107. */
  108. struct sockaddr_ll_extended
  109. {
  110. unsigned short int sll_family;
  111. unsigned short int sll_protocol;
  112. int sll_ifindex;
  113. unsigned short int sll_hatype;
  114. unsigned char sll_pkttype;
  115. unsigned char sll_halen;
  116. unsigned char sll_addr[24];
  117. };
  118. static int parse_netlink_reply(netlink_session *session, struct _monodroid_ifaddrs **ifaddrs_head, struct _monodroid_ifaddrs **last_ifaddr);
  119. static struct _monodroid_ifaddrs *get_link_info(const struct nlmsghdr *message);
  120. static struct _monodroid_ifaddrs *get_link_address(const struct nlmsghdr *message, struct _monodroid_ifaddrs **ifaddrs_head);
  121. static int open_netlink_session(netlink_session *session);
  122. static int send_netlink_dump_request(netlink_session *session, int type);
  123. static int append_ifaddr(struct _monodroid_ifaddrs *addr, struct _monodroid_ifaddrs **ifaddrs_head, struct _monodroid_ifaddrs **last_ifaddr);
  124. static int fill_ll_address(struct sockaddr_ll_extended **sa, struct ifinfomsg *net_interface, void *rta_data, int rta_payload_length);
  125. static int fill_sa_address(struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_data, int rta_payload_length);
  126. static void free_single_xamarin_ifaddrs(struct _monodroid_ifaddrs **ifap);
  127. static void get_ifaddrs_impl(int(**getifaddrs_impl) (struct _monodroid_ifaddrs **ifap), void(**freeifaddrs_impl) (struct _monodroid_ifaddrs *ifa));
  128. static struct _monodroid_ifaddrs *find_interface_by_index(int index, struct _monodroid_ifaddrs **ifaddrs_head);
  129. static char *get_interface_name_by_index(int index, struct _monodroid_ifaddrs **ifaddrs_head);
  130. static int get_interface_flags_by_index(int index, struct _monodroid_ifaddrs **ifaddrs_head);
  131. static int calculate_address_netmask(struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net_address);
  132. #if DEBUG
  133. static void print_ifla_name(int id);
  134. static void print_address_list(char *title, struct _monodroid_ifaddrs *list);
  135. #endif
  136. /* We don't use 'struct ifaddrs' since that doesn't exist in Android's bionic, but since our
  137. * version of the structure is 100% compatible we can just use it instead
  138. */
  139. typedef int (*getifaddrs_impl_fptr)(struct _monodroid_ifaddrs **);
  140. typedef void (*freeifaddrs_impl_fptr)(struct _monodroid_ifaddrs *ifa);
  141. static getifaddrs_impl_fptr getifaddrs_impl = NULL;
  142. static freeifaddrs_impl_fptr freeifaddrs_impl = NULL;
  143. void
  144. _monodroid_getifaddrs_init()
  145. {
  146. get_ifaddrs_impl(&getifaddrs_impl, &freeifaddrs_impl);
  147. }
  148. int
  149. _monodroid_getifaddrs(struct _monodroid_ifaddrs **ifap)
  150. {
  151. netlink_session session;
  152. struct _monodroid_ifaddrs *ifaddrs_head;
  153. struct _monodroid_ifaddrs *last_ifaddr;
  154. int ret = -1;
  155. if (getifaddrs_impl)
  156. return (*getifaddrs_impl)(ifap);
  157. if (!ifap)
  158. {
  159. goto cleanup;
  160. }
  161. *ifap = NULL;
  162. ifaddrs_head = 0;
  163. last_ifaddr = 0;
  164. if (open_netlink_session(&session) < 0)
  165. {
  166. goto cleanup;
  167. }
  168. /* Request information about the specified link. In our case it will be all of them since we
  169. request the root of the link tree below
  170. */
  171. if ((send_netlink_dump_request(&session, RTM_GETLINK) < 0) ||
  172. (parse_netlink_reply(&session, &ifaddrs_head, &last_ifaddr) < 0) ||
  173. (send_netlink_dump_request(&session, RTM_GETADDR) < 0) ||
  174. (parse_netlink_reply(&session, &ifaddrs_head, &last_ifaddr) < 0))
  175. {
  176. _monodroid_freeifaddrs(ifaddrs_head);
  177. goto cleanup;
  178. }
  179. ret = 0;
  180. *ifap = ifaddrs_head;
  181. #if DEBUG
  182. print_address_list("Initial interfaces list", *ifap);
  183. #endif
  184. cleanup:
  185. if (session.sock_fd >= 0)
  186. {
  187. close(session.sock_fd);
  188. session.sock_fd = -1;
  189. }
  190. return ret;
  191. }
  192. void
  193. _monodroid_freeifaddrs(struct _monodroid_ifaddrs *ifa)
  194. {
  195. struct _monodroid_ifaddrs *cur, *next;
  196. if (!ifa)
  197. return;
  198. if (freeifaddrs_impl)
  199. {
  200. (*freeifaddrs_impl)(ifa);
  201. return;
  202. }
  203. #if DEBUG
  204. print_address_list("List passed to freeifaddrs", ifa);
  205. #endif
  206. cur = ifa;
  207. while (cur)
  208. {
  209. next = cur->ifa_next;
  210. free_single_xamarin_ifaddrs(&cur);
  211. cur = next;
  212. }
  213. }
  214. static void
  215. get_ifaddrs_impl(int(**getifaddrs_impl) (struct _monodroid_ifaddrs **ifap), void(**freeifaddrs_impl) (struct _monodroid_ifaddrs *ifa))
  216. {
  217. void *libc;
  218. assert(getifaddrs_impl);
  219. assert(freeifaddrs_impl);
  220. libc = dlopen("libc.so", RTLD_NOW);
  221. if (libc)
  222. {
  223. *getifaddrs_impl = dlsym(libc, "getifaddrs");
  224. if (*getifaddrs_impl)
  225. *freeifaddrs_impl = dlsym(libc, "freeifaddrs");
  226. }
  227. if (!*getifaddrs_impl)
  228. log_info(LOG_NET, "This libc does not have getifaddrs/freeifaddrs, using Xamarin's\n");
  229. else
  230. log_info(LOG_NET, "This libc has getifaddrs/freeifaddrs\n");
  231. }
  232. static void
  233. free_single_xamarin_ifaddrs(struct _monodroid_ifaddrs **ifap)
  234. {
  235. struct _monodroid_ifaddrs *ifa = ifap ? *ifap : NULL;
  236. if (!ifa)
  237. return;
  238. if (ifa->ifa_name)
  239. free(ifa->ifa_name);
  240. if (ifa->ifa_addr)
  241. free(ifa->ifa_addr);
  242. if (ifa->ifa_netmask)
  243. free(ifa->ifa_netmask);
  244. if (ifa->_monodroid_ifa_broadaddr)
  245. free(ifa->_monodroid_ifa_broadaddr);
  246. if (ifa->ifa_data)
  247. free(ifa->ifa_data);
  248. free(ifa);
  249. *ifap = NULL;
  250. }
  251. static int
  252. open_netlink_session(netlink_session *session)
  253. {
  254. assert(session != 0);
  255. memset(session, 0, sizeof(*session));
  256. session->sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  257. if (session->sock_fd == -1)
  258. {
  259. log_warn(LOG_NETLINK, "Failed to create a netlink socket. %s\n", strerror(errno));
  260. return -1;
  261. }
  262. /* Fill out addresses */
  263. session->us.nl_family = AF_NETLINK;
  264. session->us.nl_pid = getpid();
  265. session->us.nl_groups = 0;
  266. session->them.nl_family = AF_NETLINK;
  267. if (bind(session->sock_fd, (struct sockaddr *)&session->us, sizeof(session->us)) < 0)
  268. {
  269. log_warn(LOG_NETLINK, "Failed to bind to the netlink socket. %s\n", strerror(errno));
  270. return -1;
  271. }
  272. return 0;
  273. }
  274. static int
  275. send_netlink_dump_request(netlink_session *session, int type)
  276. {
  277. netlink_request request;
  278. memset(&request, 0, sizeof(request));
  279. request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
  280. /* Flags (from netlink.h):
  281. NLM_F_REQUEST - it's a request message
  282. NLM_F_DUMP - gives us the root of the link tree and returns all links matching our requested
  283. AF, which in our case means all of them (AF_PACKET)
  284. */
  285. request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
  286. request.header.nlmsg_seq = ++session->seq;
  287. request.header.nlmsg_pid = session->us.nl_pid;
  288. request.header.nlmsg_type = type;
  289. /* AF_PACKET means we want to see everything */
  290. request.message.rtgen_family = AF_PACKET;
  291. memset(&session->payload_vector, 0, sizeof(session->payload_vector));
  292. session->payload_vector.iov_len = request.header.nlmsg_len;
  293. session->payload_vector.iov_base = &request;
  294. memset(&session->message_header, 0, sizeof(session->message_header));
  295. session->message_header.msg_namelen = sizeof(session->them);
  296. session->message_header.msg_name = &session->them;
  297. session->message_header.msg_iovlen = 1;
  298. session->message_header.msg_iov = &session->payload_vector;
  299. if (sendmsg(session->sock_fd, (const struct msghdr*)&session->message_header, 0) < 0)
  300. {
  301. log_warn(LOG_NETLINK, "Failed to send netlink message. %s\n", strerror(errno));
  302. return -1;
  303. }
  304. return 0;
  305. }
  306. static int
  307. append_ifaddr(struct _monodroid_ifaddrs *addr, struct _monodroid_ifaddrs **ifaddrs_head, struct _monodroid_ifaddrs **last_ifaddr)
  308. {
  309. assert(addr);
  310. assert(ifaddrs_head);
  311. assert(last_ifaddr);
  312. if (!*ifaddrs_head)
  313. {
  314. *ifaddrs_head = *last_ifaddr = addr;
  315. if (!*ifaddrs_head)
  316. return -1;
  317. }
  318. else if (!*last_ifaddr)
  319. {
  320. struct _monodroid_ifaddrs *last = *ifaddrs_head;
  321. while (last->ifa_next)
  322. last = last->ifa_next;
  323. *last_ifaddr = last;
  324. }
  325. addr->ifa_next = NULL;
  326. if (addr == *last_ifaddr)
  327. return 0;
  328. assert(addr != *last_ifaddr);
  329. (*last_ifaddr)->ifa_next = addr;
  330. *last_ifaddr = addr;
  331. assert((*last_ifaddr)->ifa_next == NULL);
  332. return 0;
  333. }
  334. static int
  335. parse_netlink_reply(netlink_session *session, struct _monodroid_ifaddrs **ifaddrs_head, struct _monodroid_ifaddrs **last_ifaddr)
  336. {
  337. ssize_t length;
  338. struct msghdr netlink_reply;
  339. struct iovec reply_vector;
  340. struct nlmsghdr *current_message;
  341. struct _monodroid_ifaddrs *addr;
  342. unsigned char response[RESPONSE_BUFFER_SIZE];
  343. assert(session);
  344. assert(ifaddrs_head);
  345. assert(last_ifaddr);
  346. while (1)
  347. {
  348. memset(response, 0, RESPONSE_BUFFER_SIZE);
  349. memset(&reply_vector, 0, sizeof(reply_vector));
  350. reply_vector.iov_len = RESPONSE_BUFFER_SIZE;
  351. reply_vector.iov_base = response;
  352. memset(&netlink_reply, 0, sizeof(netlink_reply));
  353. netlink_reply.msg_namelen = sizeof(&session->them);
  354. netlink_reply.msg_name = &session->them;
  355. netlink_reply.msg_iovlen = 1;
  356. netlink_reply.msg_iov = &reply_vector;
  357. log_debug(LOG_NETLINK, "receiving message...\n");
  358. length = recvmsg(session->sock_fd, &netlink_reply, 0);
  359. log_debug(LOG_NETLINK, " length == %d\n", (int)length);
  360. if (length < 0)
  361. {
  362. log_debug(LOG_NETLINK, "Failed to receive reply from netlink. %s\n", strerror(errno));
  363. return -1;
  364. }
  365. if (length == 0)
  366. return 0; /* done, apparently */
  367. for (current_message = (struct nlmsghdr*)response; current_message && NLMSG_OK(current_message, length); current_message = NLMSG_NEXT(current_message, length))
  368. {
  369. log_debug(LOG_NETLINK, "next message... (type: %u)\n", current_message->nlmsg_type);
  370. switch (current_message->nlmsg_type)
  371. {
  372. /* See rtnetlink.h */
  373. case RTM_NEWLINK:
  374. log_debug(LOG_NETLINK, " dumping link...\n");
  375. addr = get_link_info(current_message);
  376. if (!addr || append_ifaddr(addr, ifaddrs_head, last_ifaddr) < 0)
  377. return -1;
  378. log_debug(LOG_NETLINK, " done\n");
  379. break;
  380. case RTM_NEWADDR:
  381. log_debug(LOG_NETLINK, " got an address\n");
  382. addr = get_link_address(current_message, ifaddrs_head);
  383. if (!addr || append_ifaddr(addr, ifaddrs_head, last_ifaddr) < 0)
  384. return -1;
  385. break;
  386. case NLMSG_DONE:
  387. log_debug(LOG_NETLINK, " message done\n");
  388. return 0;
  389. }
  390. }
  391. }
  392. }
  393. static int
  394. fill_sa_address(struct sockaddr **sa, struct ifaddrmsg *net_address, void *rta_data, int rta_payload_length)
  395. {
  396. assert(sa);
  397. assert(net_address);
  398. assert(rta_data);
  399. switch (net_address->ifa_family)
  400. {
  401. case AF_INET:
  402. {
  403. struct sockaddr_in *sa4;
  404. assert(rta_payload_length == 4); /* IPv4 address length */
  405. sa4 = (struct sockaddr_in*)calloc(1, sizeof(*sa4));
  406. if (!sa4)
  407. return -1;
  408. sa4->sin_family = AF_INET;
  409. memcpy(&sa4->sin_addr, rta_data, rta_payload_length);
  410. *sa = (struct sockaddr*)sa4;
  411. break;
  412. }
  413. case AF_INET6:
  414. {
  415. struct sockaddr_in6 *sa6;
  416. assert(rta_payload_length == 16); /* IPv6 address length */
  417. sa6 = (struct sockaddr_in6*)calloc(1, sizeof(*sa6));
  418. if (!sa6)
  419. return -1;
  420. sa6->sin6_family = AF_INET6;
  421. memcpy(&sa6->sin6_addr, rta_data, rta_payload_length);
  422. if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr))
  423. sa6->sin6_scope_id = net_address->ifa_index;
  424. *sa = (struct sockaddr*)sa6;
  425. break;
  426. }
  427. default:
  428. {
  429. struct sockaddr *sagen;
  430. assert(rta_payload_length <= sizeof(sagen->sa_data));
  431. *sa = sagen = (struct sockaddr*)calloc(1, sizeof(*sagen));
  432. if (sagen)
  433. return -1;
  434. sagen->sa_family = net_address->ifa_family;
  435. memcpy(&sagen->sa_data, rta_data, rta_payload_length);
  436. break;
  437. }
  438. }
  439. return 0;
  440. }
  441. static int
  442. fill_ll_address(struct sockaddr_ll_extended **sa, struct ifinfomsg *net_interface, void *rta_data, int rta_payload_length)
  443. {
  444. assert(sa);
  445. assert(net_interface);
  446. /* Always allocate, do not free - caller may reuse the same variable */
  447. *sa = calloc(1, sizeof(**sa));
  448. if (!*sa)
  449. return -1;
  450. (*sa)->sll_family = AF_PACKET; /* Always for physical links */
  451. /* The assert can only fail for Iniband links, which are quite unlikely to be found
  452. * in any mobile devices
  453. */
  454. log_debug(LOG_NETLINK, "rta_payload_length == %d; sizeof sll_addr == %d; hw type == 0x%X\n", rta_payload_length, sizeof((*sa)->sll_addr), net_interface->ifi_type);
  455. if (rta_payload_length > sizeof((*sa)->sll_addr))
  456. {
  457. log_info(LOG_NETLINK, "Address is too long to place in sockaddr_ll (%d > %d)", rta_payload_length, sizeof((*sa)->sll_addr));
  458. free(*sa);
  459. *sa = NULL;
  460. return -1;
  461. }
  462. (*sa)->sll_ifindex = net_interface->ifi_index;
  463. (*sa)->sll_hatype = net_interface->ifi_type;
  464. (*sa)->sll_halen = rta_payload_length;
  465. memcpy((*sa)->sll_addr, rta_data, rta_payload_length);
  466. return 0;
  467. }
  468. static struct _monodroid_ifaddrs *
  469. find_interface_by_index(int index, struct _monodroid_ifaddrs **ifaddrs_head)
  470. {
  471. struct _monodroid_ifaddrs *cur;
  472. if (!ifaddrs_head || !*ifaddrs_head)
  473. return NULL;
  474. /* Normally expensive, but with the small amount of links in the chain we'll deal with it's not
  475. * worth the extra houskeeping and memory overhead
  476. */
  477. cur = *ifaddrs_head;
  478. while (cur)
  479. {
  480. if (cur->ifa_addr && cur->ifa_addr->sa_family == AF_PACKET && ((struct sockaddr_ll_extended*)cur->ifa_addr)->sll_ifindex == index)
  481. return cur;
  482. if (cur == cur->ifa_next)
  483. break;
  484. cur = cur->ifa_next;
  485. }
  486. return NULL;
  487. }
  488. static char *
  489. get_interface_name_by_index(int index, struct _monodroid_ifaddrs **ifaddrs_head)
  490. {
  491. struct _monodroid_ifaddrs *iface = find_interface_by_index(index, ifaddrs_head);
  492. if (!iface || !iface->ifa_name)
  493. return NULL;
  494. return iface->ifa_name;
  495. }
  496. static int
  497. get_interface_flags_by_index(int index, struct _monodroid_ifaddrs **ifaddrs_head)
  498. {
  499. struct _monodroid_ifaddrs *iface = find_interface_by_index(index, ifaddrs_head);
  500. if (!iface)
  501. return 0;
  502. return iface->ifa_flags;
  503. }
  504. static int
  505. calculate_address_netmask(struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net_address)
  506. {
  507. if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_UNSPEC && ifa->ifa_addr->sa_family != AF_PACKET)
  508. {
  509. uint32_t prefix_length = 0;
  510. uint32_t data_length = 0;
  511. unsigned char *netmask_data = NULL;
  512. switch (ifa->ifa_addr->sa_family)
  513. {
  514. case AF_INET:
  515. {
  516. struct sockaddr_in *sa = (struct sockaddr_in*)calloc(1, sizeof(struct sockaddr_in));
  517. if (!sa)
  518. return -1;
  519. ifa->ifa_netmask = (struct sockaddr*)sa;
  520. prefix_length = net_address->ifa_prefixlen;
  521. if (prefix_length > 32)
  522. prefix_length = 32;
  523. data_length = sizeof(sa->sin_addr);
  524. netmask_data = (unsigned char*)&sa->sin_addr;
  525. break;
  526. }
  527. case AF_INET6:
  528. {
  529. struct sockaddr_in6 *sa = (struct sockaddr_in6*)calloc(1, sizeof(struct sockaddr_in6));
  530. if (!sa)
  531. return -1;
  532. ifa->ifa_netmask = (struct sockaddr*)sa;
  533. prefix_length = net_address->ifa_prefixlen;
  534. if (prefix_length > 128)
  535. prefix_length = 128;
  536. data_length = sizeof(sa->sin6_addr);
  537. netmask_data = (unsigned char*)&sa->sin6_addr;
  538. break;
  539. }
  540. }
  541. if (ifa->ifa_netmask && netmask_data)
  542. {
  543. /* Fill the first X bytes with 255 */
  544. uint32_t prefix_bytes = prefix_length / 8;
  545. uint32_t postfix_bytes;
  546. int i;
  547. if (prefix_bytes > data_length)
  548. {
  549. errno = EINVAL;
  550. return -1;
  551. }
  552. postfix_bytes = data_length - prefix_bytes;
  553. memset(netmask_data, 0xFF, prefix_bytes);
  554. if (postfix_bytes > 0)
  555. memset(netmask_data + prefix_bytes + 1, 0x00, postfix_bytes);
  556. log_debug(LOG_NETLINK, " calculating netmask, prefix length is %u bits (%u bytes), data length is %u bytes\n", prefix_length, prefix_bytes, data_length);
  557. if (prefix_bytes + 2 < data_length)
  558. /* Set the rest of the mask bits in the byte following the last 0xFF value */
  559. netmask_data[prefix_bytes + 1] = 0xff << (8 - (prefix_length % 8));
  560. log_debug(LOG_NETLINK, " netmask is: ");
  561. for (i = 0; i < data_length; i++)
  562. {
  563. log_debug(LOG_NETLINK, "%s%u", i == 0 ? "" : ".", (unsigned char)ifa->ifa_netmask->sa_data[i]);
  564. }
  565. log_debug(LOG_NETLINK, "\n");
  566. }
  567. }
  568. return 0;
  569. }
  570. static struct _monodroid_ifaddrs *
  571. get_link_address(const struct nlmsghdr *message, struct _monodroid_ifaddrs **ifaddrs_head)
  572. {
  573. size_t length;
  574. struct rtattr *attribute;
  575. struct ifaddrmsg *net_address;
  576. struct _monodroid_ifaddrs *ifa = NULL;
  577. struct sockaddr **sa;
  578. int payload_size;
  579. assert(message);
  580. net_address = NLMSG_DATA(message);
  581. length = IFA_PAYLOAD(message);
  582. if (length <= 0)
  583. {
  584. goto error;
  585. }
  586. ifa = calloc(1, sizeof(*ifa));
  587. if (!ifa)
  588. {
  589. goto error;
  590. }
  591. ifa->ifa_flags = get_interface_flags_by_index(net_address->ifa_index, ifaddrs_head);
  592. attribute = IFA_RTA(net_address);
  593. while (RTA_OK(attribute, length))
  594. {
  595. payload_size = RTA_PAYLOAD(attribute);
  596. sa = NULL;
  597. switch (attribute->rta_type)
  598. {
  599. case IFA_LABEL:
  600. {
  601. int room_for_trailing_null = 0;
  602. if (payload_size > MAX_IFA_LABEL_SIZE)
  603. {
  604. payload_size = MAX_IFA_LABEL_SIZE;
  605. room_for_trailing_null = 1;
  606. }
  607. if (payload_size > 0)
  608. {
  609. ifa->ifa_name = (char*)malloc(payload_size + room_for_trailing_null);
  610. if (!ifa->ifa_name)
  611. {
  612. goto error;
  613. }
  614. memcpy(ifa->ifa_name, RTA_DATA(attribute), payload_size);
  615. if (room_for_trailing_null)
  616. ifa->ifa_name[payload_size] = '\0';
  617. }
  618. break;
  619. }
  620. case IFA_LOCAL:
  621. if (ifa->ifa_addr)
  622. {
  623. /* P2P protocol, set the dst/broadcast address union from the original address.
  624. * Since ifa_addr is set it means IFA_ADDRESST occured earlier and that address
  625. * is indeed the P2P destination one.
  626. */
  627. ifa->_monodroid_ifa_dstaddr = ifa->ifa_addr;
  628. ifa->ifa_addr = 0;
  629. }
  630. sa = &ifa->ifa_addr;
  631. break;
  632. case IFA_BROADCAST:
  633. if (ifa->_monodroid_ifa_dstaddr)
  634. {
  635. /* IFA_LOCAL happened earlier, undo its effect here */
  636. free(ifa->_monodroid_ifa_dstaddr);
  637. ifa->_monodroid_ifa_dstaddr = NULL;
  638. }
  639. sa = &ifa->_monodroid_ifa_broadaddr;
  640. break;
  641. case IFA_ADDRESS:
  642. if (ifa->ifa_addr)
  643. {
  644. /* Apparently IFA_LOCAL occured earlier and we have a P2P connection
  645. * here. IFA_LOCAL carries the destination address, move it there
  646. */
  647. ifa->_monodroid_ifa_dstaddr = ifa->ifa_addr;
  648. ifa->ifa_addr = NULL;
  649. }
  650. sa = &ifa->ifa_addr;
  651. break;
  652. }
  653. if (sa)
  654. {
  655. if (fill_sa_address(sa, net_address, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0)
  656. {
  657. goto error;
  658. }
  659. }
  660. attribute = RTA_NEXT(attribute, length);
  661. }
  662. /* glibc stores the associated interface name in the address if IFA_LABEL never occured */
  663. if (!ifa->ifa_name)
  664. {
  665. char *name = get_interface_name_by_index(net_address->ifa_index, ifaddrs_head);
  666. log_debug(LOG_NETLINK, " address has no name/label, getting one from interface\n");
  667. ifa->ifa_name = name ? strdup(name) : NULL;
  668. }
  669. log_debug(LOG_NETLINK, " address label: %s\n", ifa->ifa_name);
  670. if (calculate_address_netmask(ifa, net_address) < 0)
  671. {
  672. goto error;
  673. }
  674. return ifa;
  675. error :
  676. {
  677. /* errno may be modified by free, or any other call inside the free_single_xamarin_ifaddrs
  678. * function. We don't care about errors in there since it is more important to know how we
  679. * failed to obtain the link address and not that we went OOM. Save and restore the value
  680. * after the resources are freed.
  681. */
  682. int errno_save = errno;
  683. free_single_xamarin_ifaddrs(&ifa);
  684. errno = errno_save;
  685. return NULL;
  686. }
  687. }
  688. static struct _monodroid_ifaddrs *
  689. get_link_info(const struct nlmsghdr *message)
  690. {
  691. ssize_t length;
  692. struct rtattr *attribute;
  693. struct ifinfomsg *net_interface;
  694. struct _monodroid_ifaddrs *ifa = NULL;
  695. struct sockaddr_ll_extended *sa = NULL;
  696. assert(message);
  697. net_interface = NLMSG_DATA(message);
  698. length = message->nlmsg_len - NLMSG_LENGTH(sizeof(*net_interface));
  699. if (length <= 0)
  700. {
  701. goto error;
  702. }
  703. ifa = calloc(1, sizeof(*ifa));
  704. if (!ifa)
  705. {
  706. goto error;
  707. }
  708. ifa->ifa_flags = net_interface->ifi_flags;
  709. attribute = IFLA_RTA(net_interface);
  710. while (RTA_OK(attribute, length))
  711. {
  712. switch (attribute->rta_type)
  713. {
  714. case IFLA_IFNAME:
  715. ifa->ifa_name = strdup(RTA_DATA(attribute));
  716. if (!ifa->ifa_name)
  717. {
  718. goto error;
  719. }
  720. log_debug(LOG_NETLINK, " interface name (payload length: %d; string length: %d)\n", RTA_PAYLOAD(attribute), strlen(ifa->ifa_name));
  721. log_debug(LOG_NETLINK, " %s\n", ifa->ifa_name);
  722. break;
  723. case IFLA_BROADCAST:
  724. log_debug(LOG_NETLINK, " interface broadcast (%d bytes)\n", RTA_PAYLOAD(attribute));
  725. if (fill_ll_address(&sa, net_interface, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0)
  726. {
  727. goto error;
  728. }
  729. ifa->_monodroid_ifa_broadaddr = (struct sockaddr*)sa;
  730. break;
  731. case IFLA_ADDRESS:
  732. log_debug(LOG_NETLINK, " interface address (%d bytes)\n", RTA_PAYLOAD(attribute));
  733. if (fill_ll_address(&sa, net_interface, RTA_DATA(attribute), RTA_PAYLOAD(attribute)) < 0)
  734. {
  735. goto error;
  736. }
  737. ifa->ifa_addr = (struct sockaddr*)sa;
  738. break;
  739. default:
  740. log_debug(LOG_NETLINK, " rta_type: ");
  741. #if DEBUG
  742. print_ifla_name(attribute->rta_type);
  743. #endif
  744. break;
  745. }
  746. attribute = RTA_NEXT(attribute, length);
  747. }
  748. log_debug(LOG_NETLINK, "link flags: 0x%X", ifa->ifa_flags);
  749. return ifa;
  750. error:
  751. if (sa)
  752. free(sa);
  753. free_single_xamarin_ifaddrs(&ifa);
  754. return NULL;
  755. }
  756. #else
  757. void
  758. _monodroid_getifaddrs_init(void)
  759. {
  760. }
  761. int
  762. _monodroid_getifaddrs(struct _monodroid_ifaddrs **ifap)
  763. {
  764. *ifap = NULL;
  765. return 0;
  766. }
  767. void _monodroid_freeifaddrs(struct _monodroid_ifaddrs *ifa)
  768. {
  769. }
  770. #endif
  771. #if LINUX && DEBUG
  772. #define ENUM_VALUE_ENTRY(enumvalue) { enumvalue, #enumvalue }
  773. struct enumvalue
  774. {
  775. int value;
  776. char *name;
  777. };
  778. struct enumvalue iflas[] = {
  779. ENUM_VALUE_ENTRY(IFLA_UNSPEC),
  780. ENUM_VALUE_ENTRY(IFLA_ADDRESS),
  781. ENUM_VALUE_ENTRY(IFLA_BROADCAST),
  782. ENUM_VALUE_ENTRY(IFLA_IFNAME),
  783. ENUM_VALUE_ENTRY(IFLA_MTU),
  784. ENUM_VALUE_ENTRY(IFLA_LINK),
  785. ENUM_VALUE_ENTRY(IFLA_QDISC),
  786. ENUM_VALUE_ENTRY(IFLA_STATS),
  787. ENUM_VALUE_ENTRY(IFLA_COST),
  788. ENUM_VALUE_ENTRY(IFLA_PRIORITY),
  789. ENUM_VALUE_ENTRY(IFLA_MASTER),
  790. ENUM_VALUE_ENTRY(IFLA_WIRELESS),
  791. ENUM_VALUE_ENTRY(IFLA_PROTINFO),
  792. ENUM_VALUE_ENTRY(IFLA_TXQLEN),
  793. ENUM_VALUE_ENTRY(IFLA_MAP),
  794. ENUM_VALUE_ENTRY(IFLA_WEIGHT),
  795. ENUM_VALUE_ENTRY(IFLA_OPERSTATE),
  796. ENUM_VALUE_ENTRY(IFLA_LINKMODE),
  797. ENUM_VALUE_ENTRY(IFLA_LINKINFO),
  798. ENUM_VALUE_ENTRY(IFLA_NET_NS_PID),
  799. ENUM_VALUE_ENTRY(IFLA_IFALIAS),
  800. ENUM_VALUE_ENTRY(IFLA_NUM_VF),
  801. ENUM_VALUE_ENTRY(IFLA_VFINFO_LIST),
  802. ENUM_VALUE_ENTRY(IFLA_STATS64),
  803. ENUM_VALUE_ENTRY(IFLA_VF_PORTS),
  804. ENUM_VALUE_ENTRY(IFLA_PORT_SELF),
  805. ENUM_VALUE_ENTRY(IFLA_AF_SPEC),
  806. ENUM_VALUE_ENTRY(IFLA_GROUP),
  807. ENUM_VALUE_ENTRY(IFLA_NET_NS_FD),
  808. ENUM_VALUE_ENTRY(IFLA_EXT_MASK),
  809. ENUM_VALUE_ENTRY(IFLA_PROMISCUITY),
  810. ENUM_VALUE_ENTRY(IFLA_NUM_TX_QUEUES),
  811. ENUM_VALUE_ENTRY(IFLA_NUM_RX_QUEUES),
  812. ENUM_VALUE_ENTRY(IFLA_CARRIER),
  813. ENUM_VALUE_ENTRY(IFLA_PHYS_PORT_ID),
  814. { -1, 0 }
  815. };
  816. static void
  817. print_ifla_name(int id)
  818. {
  819. int i = 0;
  820. while (1)
  821. {
  822. if (iflas[i].value == -1 && iflas[i].name == 0)
  823. {
  824. log_info(LOG_NETLINK, "Unknown ifla->name: unknown id %d\n", id);
  825. break;
  826. }
  827. if (iflas[i].value != id)
  828. {
  829. i++;
  830. continue;
  831. }
  832. log_info(LOG_NETLINK, "ifla->name: %s (%d)\n", iflas[i].name, iflas[i].value);
  833. break;
  834. }
  835. }
  836. static void
  837. print_address_list(char *title, struct _monodroid_ifaddrs *list)
  838. {
  839. struct _monodroid_ifaddrs *cur;
  840. char *msg, *tmp;
  841. if (!list)
  842. {
  843. log_info(LOG_NETLINK, "monodroid-net", "No list to print in %s", __FUNCTION__);
  844. return;
  845. }
  846. cur = list;
  847. msg = NULL;
  848. while (cur)
  849. {
  850. tmp = NULL;
  851. asprintf(&tmp, "%s%s%p (%s; %p)", msg ? msg : "", msg ? " -> " : "", cur, cur->ifa_name, cur->ifa_name);
  852. if (msg)
  853. free(msg);
  854. msg = tmp;
  855. cur = cur->ifa_next;
  856. }
  857. log_info(LOG_NETLINK, "%s: %s", title, msg ? msg : "[no addresses]");
  858. free(msg);
  859. }
  860. #endif