📄 ifaddrs.c
字号:
pid_t pid = getpid (); int seq; int result; int build; /* 0 or 1 *//* ---------------------------------- */ /* initialize */ icnt = dlen = xlen = nlen = 0; nlmsg_list = nlmsg_end = NULL; if (ifap) *ifap = NULL;/* ---------------------------------- */ /* open socket and bind */ sd = nl_open (); if (sd < 0) return -1;/* ---------------------------------- */ /* gather info */ if ((seq = nl_getlist (sd, 0, RTM_GETLINK, &nlmsg_list, &nlmsg_end)) < 0) { free_nlmsglist (nlmsg_list); nl_close (sd); return -1; } if ((seq = nl_getlist (sd, seq + 1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0) { free_nlmsglist (nlmsg_list); nl_close (sd); return -1; }/* ---------------------------------- */ /* Estimate size of result buffer and fill it */ for (build = 0; build <= 1; build++) { struct ifaddrs *ifl = NULL, *ifa = NULL; struct nlmsghdr *nlh, *nlh0; void *data = NULL, *xdata = NULL, *ifdata = NULL; char *ifname = NULL, **iflist = NULL; uint16_t *ifflist = NULL; struct rtmaddr_ifamap ifamap; if (build) { ifa = data = calloc (1, NLMSG_ALIGN (sizeof (struct ifaddrs[icnt])) + dlen + xlen + nlen); ifdata = calloc (1, NLMSG_ALIGN (sizeof (char *[max_ifindex + 1])) + NLMSG_ALIGN (sizeof (uint16_t[max_ifindex + 1]))); if (ifap != NULL) *ifap = (ifdata != NULL) ? ifa : NULL; else { free_data (data, ifdata); result = 0; break; } if (data == NULL || ifdata == NULL) { free_data (data, ifdata); result = -1; break; } ifl = NULL; data += NLMSG_ALIGN (sizeof (struct ifaddrs)) * icnt; xdata = data + dlen; ifname = xdata + xlen; iflist = ifdata; ifflist = ((void *) iflist) + NLMSG_ALIGN (sizeof (char *[max_ifindex + 1])); } for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next) { int nlmlen = nlm->size; if (!(nlh0 = nlm->nlh)) continue; for (nlh = nlh0; NLMSG_OK (nlh, nlmlen); nlh = NLMSG_NEXT (nlh, nlmlen)) { struct ifinfomsg *ifim = NULL; struct ifaddrmsg *ifam = NULL; struct rtattr *rta; size_t nlm_struct_size = 0; sa_family_t nlm_family = 0; uint32_t nlm_scope = 0, nlm_index = 0;#ifndef IFA_NETMASK size_t sockaddr_size = 0; uint32_t nlm_prefixlen = 0;#endif size_t rtasize; memset (&ifamap, 0, sizeof (ifamap)); /* check if the message is what we want */ if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq) continue; if (nlh->nlmsg_type == NLMSG_DONE) { break; /* ok */ } switch (nlh->nlmsg_type) { case RTM_NEWLINK: ifim = (struct ifinfomsg *) NLMSG_DATA (nlh); nlm_struct_size = sizeof (*ifim); nlm_family = ifim->ifi_family; nlm_scope = 0; nlm_index = ifim->ifi_index; nlm_prefixlen = 0; if (build) ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; break; case RTM_NEWADDR: ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh); nlm_struct_size = sizeof (*ifam); nlm_family = ifam->ifa_family; nlm_scope = ifam->ifa_scope; nlm_index = ifam->ifa_index; nlm_prefixlen = ifam->ifa_prefixlen; if (build) ifa->ifa_flags = ifflist[nlm_index]; break; default: continue; } if (!build) { if (max_ifindex < nlm_index) max_ifindex = nlm_index; } else { if (ifl != NULL) ifl->ifa_next = ifa; } rtasize = NLMSG_PAYLOAD (nlh, nlmlen) - NLMSG_ALIGN (nlm_struct_size); for (rta = (struct rtattr *) (((char *) NLMSG_DATA (nlh)) + NLMSG_ALIGN (nlm_struct_size)); RTA_OK (rta, rtasize); rta = RTA_NEXT (rta, rtasize)) { struct sockaddr **sap = NULL; void *rtadata = RTA_DATA (rta); size_t rtapayload = RTA_PAYLOAD (rta); socklen_t sa_len; switch (nlh->nlmsg_type) { case RTM_NEWLINK: switch (rta->rta_type) { case IFLA_ADDRESS: case IFLA_BROADCAST: if (build) { sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa-> ifa_broadaddr; *sap = (struct sockaddr *) data; } sa_len = ifa_sa_len (AF_PACKET, rtapayload); if (rta->rta_type == IFLA_ADDRESS) sockaddr_size = NLMSG_ALIGN (sa_len); if (!build) { dlen += NLMSG_ALIGN (sa_len); } else { memset (*sap, 0, sa_len); ifa_make_sockaddr (AF_PACKET, *sap, rtadata, rtapayload, 0, 0); ((struct sockaddr_ll *) *sap)->sll_ifindex = nlm_index; ((struct sockaddr_ll *) *sap)->sll_hatype = ifim->ifi_type; data += NLMSG_ALIGN (sa_len); } break; case IFLA_IFNAME: /* Name of Interface */ if (!build) nlen += NLMSG_ALIGN (rtapayload + 1); else { ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifa->ifa_name; strncpy (ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN (rtapayload + 1); } break; case IFLA_STATS: /* Statistics of Interface */ if (!build) xlen += NLMSG_ALIGN (rtapayload); else { ifa->ifa_data = xdata; memcpy (ifa->ifa_data, rtadata, rtapayload); xdata += NLMSG_ALIGN (rtapayload); } break; case IFLA_UNSPEC: break; case IFLA_MTU: break; case IFLA_LINK: break; case IFLA_QDISC: break; default: ; } break; case RTM_NEWADDR: if (nlm_family == AF_PACKET) break; switch (rta->rta_type) { case IFA_ADDRESS: ifamap.address = rtadata; ifamap.address_len = rtapayload; break; case IFA_LOCAL: ifamap.local = rtadata; ifamap.local_len = rtapayload; break; case IFA_BROADCAST: ifamap.broadcast = rtadata; ifamap.broadcast_len = rtapayload; break;#ifdef HAVE_IFADDRS_IFA_ANYCAST case IFA_ANYCAST: ifamap.anycast = rtadata; ifamap.anycast_len = rtapayload; break;#endif case IFA_LABEL: if (!build) nlen += NLMSG_ALIGN (rtapayload + 1); else { ifa->ifa_name = ifname; if (iflist[nlm_index] == NULL) iflist[nlm_index] = ifname; strncpy (ifa->ifa_name, rtadata, rtapayload); ifa->ifa_name[rtapayload] = '\0'; ifname += NLMSG_ALIGN (rtapayload + 1); } break; case IFA_UNSPEC: break; case IFA_CACHEINFO: break; default: ; } } } if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) { if (!ifamap.local) { ifamap.local = ifamap.address; ifamap.local_len = ifamap.address_len; } if (!ifamap.address) { ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address_len != ifamap.local_len || (ifamap.address != NULL && memcmp (ifamap.address, ifamap.local, ifamap.address_len))) { /* p2p; address is peer and local is ours */ ifamap.broadcast = ifamap.address; ifamap.broadcast_len = ifamap.address_len; ifamap.address = ifamap.local; ifamap.address_len = ifamap.local_len; } if (ifamap.address) {#ifndef IFA_NETMASK sockaddr_size = NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.address_len));#endif if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.address_len)); else { ifa->ifa_addr = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.address_len)); } }#ifdef IFA_NETMASK if (ifamap.netmask) { if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.netmask_len)); else { ifa->ifa_netmask = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.netmask_len)); } }#endif if (ifamap.broadcast) { if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.broadcast_len)); else { ifa->ifa_broadaddr = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.broadcast_len)); } }#ifdef HAVE_IFADDRS_IFA_ANYCAST if (ifamap.anycast) { if (!build) dlen += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.anycast_len)); else { ifa->ifa_anycast = (struct sockaddr *) data; ifa_make_sockaddr (nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, nlm_scope, nlm_index); data += NLMSG_ALIGN (ifa_sa_len (nlm_family, ifamap.anycast_len)); } }#endif } if (!build) {#ifndef IFA_NETMASK dlen += sockaddr_size;#endif icnt++; } else { if (ifa->ifa_name == NULL) ifa->ifa_name = iflist[nlm_index];#ifndef IFA_NETMASK if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_UNSPEC && ifa->ifa_addr->sa_family != AF_PACKET) { ifa->ifa_netmask = (struct sockaddr *) data; ifa_make_sockaddr_mask (ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); } data += sockaddr_size;#endif ifl = ifa++; } } } if (!build) { if (icnt == 0 && (dlen + nlen + xlen == 0)) { if (ifap != NULL) *ifap = NULL; break; /* cannot found any addresses */ } } else free_data (NULL, ifdata); }/* ---------------------------------- */ /* Finalize */ free_nlmsglist (nlmsg_list); nl_close (sd); return 0;}/* ---------------------------------------------------------------------- */voidfreeifaddrs (struct ifaddrs *ifa){ free (ifa);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -