int getifmaddrs(struct ifmaddrs **pif) { int icnt = 1; int dcnt = 0; int ntry = 0; size_t len; size_t needed; int mib[6]; int i; char *buf; char *data; char *next; char *p; struct ifma_msghdr *ifmam; struct ifmaddrs *ifa, *ift; struct rt_msghdr *rtm; struct sockaddr *sa; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_IFMALIST; mib[5] = 0; /* no flags */ do { if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return (-1); if ((buf = malloc(needed)) == NULL) return (-1); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { free(buf); return (-1); } free(buf); buf = NULL; } } while (buf == NULL); for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_NEWMADDR: ifmam = (struct ifma_msghdr *)(void *)rtm; if ((ifmam->ifmam_addrs & RTA_IFA) == 0) break; icnt++; p = (char *)(ifmam + 1); for (i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); dcnt += len; p += len; } break; } } data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt); if (data == NULL) { free(buf); return (-1); } ifa = (struct ifmaddrs *)(void *)data; data += sizeof(struct ifmaddrs) * icnt; memset(ifa, 0, sizeof(struct ifmaddrs) * icnt); ift = ifa; for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_NEWMADDR: ifmam = (struct ifma_msghdr *)(void *)rtm; if ((ifmam->ifmam_addrs & RTA_IFA) == 0) break; p = (char *)(ifmam + 1); for (i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); switch (i) { case RTAX_GATEWAY: ift->ifma_lladdr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; case RTAX_IFP: ift->ifma_name = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; case RTAX_IFA: ift->ifma_addr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; default: data += len; break; } p += len; } ift->ifma_next = ift + 1; ift = ift->ifma_next; break; } } free(buf); if (ift > ifa) { ift--; ift->ifma_next = NULL; *pif = ifa; } else { *pif = NULL; free(ifa); } return (0); }
int getifaddrs(struct ifaddrs **pif) { int icnt = 1; // Interface count int dcnt = 0; // Data [length] count int ncnt = 0; // Length of interface names char buf[1024]; int i, sock; struct ifconf ifc; struct ifreq *ifr, *lifr; char *data, *names; struct ifaddrs *ifa, *ift; ifc.ifc_buf = buf; ifc.ifc_len = sizeof(buf); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return (-1); i = ioctl(sock, SIOCGIFCONF, (char *)&ifc); close(sock); if (i < 0) return (-1); ifr = ifc.ifc_req; lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; while (ifr < lifr) { struct sockaddr *sa; sa = &ifr->ifr_addr; ++icnt; dcnt += SA_RLEN(sa); ncnt += sizeof(ifr->ifr_name) + 1; if (SA_LEN(sa) < sizeof(*sa)) ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa)); else ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); } if (icnt + dcnt + ncnt == 1) { // Nothing found *pif = NULL; free(buf); return (0); } data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); if (data == NULL) { free(buf); return(-1); } ifa = (struct ifaddrs *)(void *)data; data += sizeof(struct ifaddrs) * icnt; names = data + dcnt; memset(ifa, 0, sizeof(struct ifaddrs) * icnt); ift = ifa; ifr = ifc.ifc_req; lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; while (ifr < lifr) { struct sockaddr *sa; ift->ifa_name = names; names[sizeof(ifr->ifr_name)] = 0; strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name)); while (*names++) ; ift->ifa_addr = (struct sockaddr *)data; sa = &ifr->ifr_addr; memcpy(data, sa, SA_LEN(sa)); data += SA_RLEN(sa); if (SA_LEN(sa) < sizeof(*sa)) ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa)); else ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); ift = (ift->ifa_next = ift + 1); } if (--ift >= ifa) { ift->ifa_next = NULL; *pif = ifa; } else { *pif = NULL; free(ifa); } return (0); }
void ProcessInterfaceWatchNotify(int s) { char buf[4096]; ssize_t len; char tmp[64]; struct rt_msghdr * rtm; struct if_msghdr * ifm; struct ifa_msghdr * ifam; #ifdef RTM_IFANNOUNCE struct if_announcemsghdr * ifanm; #endif char * p; struct sockaddr * sa; unsigned int ext_if_name_index = 0; len = recv(s, buf, sizeof(buf), 0); if(len < 0) { syslog(LOG_ERR, "ProcessInterfaceWatchNotify recv: %m"); return; } if(ext_if_name) { ext_if_name_index = if_nametoindex(ext_if_name); } rtm = (struct rt_msghdr *)buf; syslog(LOG_DEBUG, "%u rt_msg : msglen=%d version=%d type=%d", (unsigned)len, rtm->rtm_msglen, rtm->rtm_version, rtm->rtm_type); switch(rtm->rtm_type) { case RTM_IFINFO: /* iface going up/down etc. */ ifm = (struct if_msghdr *)buf; syslog(LOG_DEBUG, " RTM_IFINFO: addrs=%x flags=%x index=%hu", ifm->ifm_addrs, ifm->ifm_flags, ifm->ifm_index); break; case RTM_ADD: /* Add Route */ syslog(LOG_DEBUG, " RTM_ADD"); break; case RTM_DELETE: /* Delete Route */ syslog(LOG_DEBUG, " RTM_DELETE"); break; case RTM_CHANGE: /* Change Metrics or flags */ syslog(LOG_DEBUG, " RTM_CHANGE"); break; case RTM_GET: /* Report Metrics */ syslog(LOG_DEBUG, " RTM_GET"); break; #ifdef RTM_IFANNOUNCE case RTM_IFANNOUNCE: /* iface arrival/departure */ ifanm = (struct if_announcemsghdr *)buf; syslog(LOG_DEBUG, " RTM_IFANNOUNCE: index=%hu what=%hu ifname=%s", ifanm->ifan_index, ifanm->ifan_what, ifanm->ifan_name); break; #endif #ifdef RTM_IEEE80211 case RTM_IEEE80211: /* IEEE80211 wireless event */ syslog(LOG_DEBUG, " RTM_IEEE80211"); break; #endif case RTM_NEWADDR: /* address being added to iface */ ifam = (struct ifa_msghdr *)buf; syslog(LOG_DEBUG, " RTM_NEWADDR: addrs=%x flags=%x index=%hu", ifam->ifam_addrs, ifam->ifam_flags, ifam->ifam_index); p = buf + sizeof(struct ifa_msghdr); while(p < buf + len) { sa = (struct sockaddr *)p; sockaddr_to_string(sa, tmp, sizeof(tmp)); syslog(LOG_DEBUG, " %s", tmp); p += SA_RLEN(sa); } if(ifam->ifam_index == ext_if_name_index) { should_send_public_address_change_notif = 1; } break; case RTM_DELADDR: /* address being removed from iface */ ifam = (struct ifa_msghdr *)buf; if(ifam->ifam_index == ext_if_name_index) { should_send_public_address_change_notif = 1; } break; default: syslog(LOG_DEBUG, "unprocessed RTM message type=%d", rtm->rtm_type); } }
int getifaddrs(struct ifaddrs **pif) { int icnt = 1; int dcnt = 0; int ncnt = 0; int ntry = 0; int mib[6]; size_t needed; char *buf; char *next; struct ifaddrs *cif = NULL; char *p, *p0; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *dl; struct sockaddr *sa; struct ifaddrs *ifa, *ift; u_short idx = 0; int i; size_t len, alen; char *data; char *names; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* no flags */ do { /* * We'll try to get addresses several times in case that * the number of addresses is unexpectedly increased during * the two sysctl calls. This should rarely happen, but we'll * try to do our best for applications that assume success of * this library (which should usually be the case). * Portability note: since FreeBSD does not add margin of * memory at the first sysctl, the possibility of failure on * the second sysctl call is a bit higher. */ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return (-1); if ((buf = malloc(needed)) == NULL) return (-1); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { free(buf); return (-1); } free(buf); buf = NULL; } } while (buf == NULL); for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)rtm; if (ifm->ifm_addrs & RTA_IFP) { idx = ifm->ifm_index; ++icnt; dl = (struct sockaddr_dl *)(void *)(ifm + 1); dcnt += SA_RLEN((struct sockaddr *)(void*)dl) + ALIGNBYTES; dcnt += sizeof(ifm->ifm_data); ncnt += dl->sdl_nlen + 1; } else idx = 0; break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)rtm; if (idx && ifam->ifam_index != idx) abort(); /* this cannot happen */ #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD) if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) break; p = (char *)(void *)(ifam + 1); ++icnt; /* Scan to look for length of address */ alen = 0; for (p0 = p, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_IFA) { alen = len; break; } p += len; } for (p = p0, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_NETMASK && SA_LEN(sa) == 0) dcnt += alen; else dcnt += len; p += len; } break; } } if (icnt + dcnt + ncnt == 1) { *pif = NULL; free(buf); return (0); } data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); if (data == NULL) { free(buf); return(-1); } ifa = (struct ifaddrs *)(void *)data; data += sizeof(struct ifaddrs) * icnt; names = data + dcnt; memset(ifa, 0, sizeof(struct ifaddrs) * icnt); ift = ifa; idx = 0; for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)rtm; if (ifm->ifm_addrs & RTA_IFP) { idx = ifm->ifm_index; dl = (struct sockaddr_dl *)(void *)(ifm + 1); cif = ift; ift->ifa_name = names; ift->ifa_flags = (int)ifm->ifm_flags; memcpy(names, dl->sdl_data, (size_t)dl->sdl_nlen); names[dl->sdl_nlen] = 0; names += dl->sdl_nlen + 1; ift->ifa_addr = (struct sockaddr *)(void *)data; memcpy(data, dl, (size_t)SA_LEN((struct sockaddr *) (void *)dl)); data += SA_RLEN((struct sockaddr *)(void *)dl); /* ifm_data needs to be aligned */ ift->ifa_data = data = (void *)ALIGN(data); memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data)); data += sizeof(ifm->ifm_data); ift = (ift->ifa_next = ift + 1); } else idx = 0; break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)rtm; if (idx && ifam->ifam_index != idx) abort(); /* this cannot happen */ if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) break; ift->ifa_name = cif->ifa_name; ift->ifa_flags = cif->ifa_flags; ift->ifa_data = NULL; p = (char *)(void *)(ifam + 1); /* Scan to look for length of address */ alen = 0; for (p0 = p, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_IFA) { alen = len; break; } p += len; } for (p = p0, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); switch (i) { case RTAX_IFA: ift->ifa_addr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; case RTAX_NETMASK: ift->ifa_netmask = (struct sockaddr *)(void *)data; if (SA_LEN(sa) == 0) { memset(data, 0, alen); data += alen; break; } memcpy(data, p, len); data += len; break; case RTAX_BRD: ift->ifa_broadaddr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; } p += len; } ift = (ift->ifa_next = ift + 1); break; } } free(buf); if (--ift >= ifa) { ift->ifa_next = NULL; *pif = ifa; } else { *pif = NULL; free(ifa); } return (0); }
/** * Process the message and add/drop multicast membership if needed */ int ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6) { struct lan_addr_s * lan_addr; ssize_t len; char buffer[4096]; #ifdef __linux__ struct iovec iov; struct msghdr hdr; struct nlmsghdr *nlhdr; struct ifaddrmsg *ifa; struct rtattr *rta; int ifa_len; iov.iov_base = buffer; iov.iov_len = sizeof(buffer); memset(&hdr, 0, sizeof(hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; len = recvmsg(s, &hdr, 0); if(len < 0) { syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m"); return -1; } for(nlhdr = (struct nlmsghdr *)buffer; NLMSG_OK(nlhdr, len); nlhdr = NLMSG_NEXT(nlhdr, len)) { int is_del = 0; char address[48]; char ifname[IFNAMSIZ]; address[0] = '\0'; ifname[0] = '\0'; if(nlhdr->nlmsg_type == NLMSG_DONE) break; switch(nlhdr->nlmsg_type) { /* case RTM_NEWLINK: */ /* case RTM_DELLINK: */ case RTM_DELADDR: is_del = 1; case RTM_NEWADDR: /* http://linux-hacks.blogspot.fr/2009/01/sample-code-to-learn-netlink.html */ ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr); rta = (struct rtattr *)IFA_RTA(ifa); ifa_len = IFA_PAYLOAD(nlhdr); syslog(LOG_DEBUG, "%s %s index=%d fam=%d prefixlen=%d flags=%d scope=%d", "ProcessInterfaceWatchNotify", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", ifa->ifa_index, ifa->ifa_family, ifa->ifa_prefixlen, ifa->ifa_flags, ifa->ifa_scope); for(;RTA_OK(rta, ifa_len); rta = RTA_NEXT(rta, ifa_len)) { /*RTA_DATA(rta)*/ /*rta_type : IFA_ADDRESS, IFA_LOCAL, etc. */ char tmp[128]; memset(tmp, 0, sizeof(tmp)); switch(rta->rta_type) { case IFA_ADDRESS: case IFA_LOCAL: case IFA_BROADCAST: case IFA_ANYCAST: inet_ntop(ifa->ifa_family, RTA_DATA(rta), tmp, sizeof(tmp)); if(rta->rta_type == IFA_ADDRESS) strncpy(address, tmp, sizeof(address)); break; case IFA_LABEL: strncpy(tmp, RTA_DATA(rta), sizeof(tmp)); strncpy(ifname, tmp, sizeof(ifname)); break; case IFA_CACHEINFO: { struct ifa_cacheinfo *cache_info; cache_info = RTA_DATA(rta); snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u", cache_info->ifa_valid, cache_info->ifa_prefered); } break; default: strncpy(tmp, "*unknown*", sizeof(tmp)); } syslog(LOG_DEBUG, " rta_len=%d rta_type=%d '%s'", rta->rta_len, rta->rta_type, tmp); } syslog(LOG_INFO, "%s: %s/%d %s", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", address, ifa->ifa_prefixlen, ifname); for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { if((0 == strcmp(address, lan_addr->str)) || (0 == strcmp(ifname, lan_addr->ifname)) || (ifa->ifa_index == lan_addr->index)) { if(ifa->ifa_family == AF_INET) AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del); else if(ifa->ifa_family == AF_INET6) AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del); break; } } break; default: syslog(LOG_DEBUG, "unknown nlmsg_type=%d", nlhdr->nlmsg_type); } } #else /* __linux__ */ struct rt_msghdr * rtm; struct ifa_msghdr * ifam; int is_del = 0; char tmp[64]; char * p; struct sockaddr * sa; int addr; char address[48]; char ifname[IFNAMSIZ]; int family = AF_UNSPEC; int prefixlen = 0; address[0] = '\0'; ifname[0] = '\0'; len = recv(s, buffer, sizeof(buffer), 0); if(len < 0) { syslog(LOG_ERR, "%s recv: %m", "ProcessInterfaceWatchNotify"); return -1; } rtm = (struct rt_msghdr *)buffer; switch(rtm->rtm_type) { case RTM_DELADDR: is_del = 1; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)buffer; syslog(LOG_DEBUG, "%s %s len=%d/%hu index=%hu addrs=%x flags=%x", "ProcessInterfaceWatchNotify", is_del?"RTM_DELADDR":"RTM_NEWADDR", (int)len, ifam->ifam_msglen, ifam->ifam_index, ifam->ifam_addrs, ifam->ifam_flags); p = buffer + sizeof(struct ifa_msghdr); addr = 1; while(p < buffer + len) { sa = (struct sockaddr *)p; while(!(addr & ifam->ifam_addrs) && (addr <= ifam->ifam_addrs)) addr = addr << 1; sockaddr_to_string(sa, tmp, sizeof(tmp)); syslog(LOG_DEBUG, " %s", tmp); switch(addr) { case RTA_DST: case RTA_GATEWAY: break; case RTA_NETMASK: if(sa->sa_family == AF_INET #if defined(__OpenBSD__) || (sa->sa_family == 0 && sa->sa_len <= sizeof(struct sockaddr_in)) #endif ) { uint32_t sin_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); while((prefixlen < 32) && ((sin_addr & (1 << (31 - prefixlen))) != 0)) prefixlen++; } else if(sa->sa_family == AF_INET6 #if defined(__OpenBSD__) || (sa->sa_family == 0 && sa->sa_len == sizeof(struct sockaddr_in6)) #endif ) { int i = 0; uint8_t * q = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; while((*q == 0xff) && (i < 16)) { prefixlen += 8; q++; i++; } if(i < 16) { i = 0; while((i < 8) && ((*q & (1 << (7 - i))) != 0)) i++; prefixlen += i; } } break; case RTA_GENMASK: break; case RTA_IFP: #ifdef AF_LINK if(sa->sa_family == AF_LINK) { struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa; memset(ifname, 0, sizeof(ifname)); memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen); } #endif break; case RTA_IFA: family = sa->sa_family; if(sa->sa_family == AF_INET) { inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, address, sizeof(address)); } else if(sa->sa_family == AF_INET6) { inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, address, sizeof(address)); } break; case RTA_AUTHOR: break; case RTA_BRD: break; } #if 0 syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x", (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3], (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x", (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7], (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7]); #endif p += SA_RLEN(sa); addr = addr << 1; } syslog(LOG_INFO, "%s: %s/%d %s", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", address, prefixlen, ifname); for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { if((0 == strcmp(address, lan_addr->str)) || (0 == strcmp(ifname, lan_addr->ifname)) || (ifam->ifam_index == lan_addr->index)) { if(family == AF_INET) AddDropMulticastMembership(s_ssdp, lan_addr, 0, is_del); else if(family == AF_INET6) AddDropMulticastMembership(s_ssdp6, lan_addr, 1, is_del); break; } } break; default: syslog(LOG_DEBUG, "Unknown RTM message : rtm->rtm_type=%d len=%d", rtm->rtm_type, (int)len); } #endif return 0; }
int getifaddrs(struct ifaddrs **pif) { int icnt = 1; // Interface count int dcnt = 0; // Data [length] count int ncnt = 0; // Length of interface names char *buf; #define IF_WORK_SPACE_SZ 1024 int i, sock; #ifdef CYGPKG_NET_INET6 int sock6; struct in6_ifreq ifrq6; #endif struct ifconf ifc; struct ifreq *ifr, *lifr; struct ifreq ifrq; char *data, *names; struct ifaddrs *ifa, *ift; buf = malloc(IF_WORK_SPACE_SZ); if (buf == NULL) return (-1); ifc.ifc_buf = buf; ifc.ifc_len = IF_WORK_SPACE_SZ; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { free(buf); return (-1); } i = ioctl(sock, SIOCGIFCONF, (char *)&ifc); if (i < 0) { close(sock); free(buf); return (-1); } ifr = ifc.ifc_req; lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; while (ifr < lifr) { struct sockaddr *sa; sa = &ifr->ifr_addr; ++icnt; dcnt += SA_RLEN(sa) * 3; /* addr, mask, brdcst */ ncnt += sizeof(ifr->ifr_name) + 1; if (SA_LEN(sa) < sizeof(*sa)) ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa)); else ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); } if (icnt + dcnt + ncnt == 1) { // Nothing found *pif = NULL; free(buf); close(sock); return (0); } data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); if (data == NULL) { free(buf); close(sock); return(-1); } ifa = (struct ifaddrs *)(void *)data; data += sizeof(struct ifaddrs) * icnt; names = data + dcnt; memset(ifa, 0, sizeof(struct ifaddrs) * icnt); ift = ifa; ifr = ifc.ifc_req; #ifdef CYGPKG_NET_INET6 if ((sock6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0) { free(buf); free(ifa); close(sock); return (-1); } #endif while (ifr < lifr) { struct sockaddr * sa; ift->ifa_name = names; names[sizeof(ifr->ifr_name)] = 0; strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name)); while (*names++) ; ift->ifa_addr = (struct sockaddr *)data; sa = &ifr->ifr_addr; memcpy(data, sa, SA_LEN(sa)); data += SA_RLEN(sa); if ((sa->sa_family == AF_INET) || (sa->sa_family == AF_INET6)) { struct sockaddr *sa_netmask = NULL; struct sockaddr *sa_broadcast = NULL; struct sockaddr *sa_dst = NULL; memset(&ifrq,0,sizeof(ifrq)); strcpy(ifrq.ifr_name,ifr->ifr_name); ioctl( sock, SIOCGIFFLAGS, &ifrq ); ift->ifa_flags = ifrq.ifr_flags; memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr)); if (sa->sa_family == AF_INET) { ioctl(sock, SIOCGIFNETMASK, &ifrq); sa_netmask = &ifrq.ifr_addr; } #ifdef CYGPKG_NET_INET6 if (sa->sa_family == AF_INET6) { memset(&ifrq6,0,sizeof(ifrq)); strcpy(ifrq6.ifr_name,ifr->ifr_name); memcpy(&ifrq6.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr)); ioctl(sock6, SIOCGIFNETMASK_IN6, &ifrq6); sa_netmask = (struct sockaddr *)&ifrq6.ifr_addr; } #endif ift->ifa_netmask = (struct sockaddr *)data; memcpy(data, sa_netmask, SA_LEN(sa_netmask)); data += SA_RLEN(sa_netmask); memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr)); if ((sa->sa_family == AF_INET) && (ift->ifa_flags & IFF_BROADCAST)) { if (ioctl(sock, SIOCGIFBRDADDR, &ifrq) == 0) { sa_broadcast = &ifrq.ifr_addr; ift->ifa_broadaddr = (struct sockaddr *)data; memcpy(data, sa_broadcast, SA_LEN(sa_broadcast)); data += SA_RLEN(sa_broadcast); } } memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr)); if ((sa->sa_family == AF_INET) && (ift->ifa_flags & IFF_POINTOPOINT)) { if (ioctl(sock, SIOCGIFDSTADDR, &ifrq) == 0) { sa_dst = &ifrq.ifr_addr; ift->ifa_dstaddr = (struct sockaddr *)data; memcpy(data, sa_dst, SA_LEN(sa_dst)); data += SA_RLEN(sa_dst); } } } if (SA_LEN(sa) < sizeof(*sa)) ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa)); else ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); ift = (ift->ifa_next = ift + 1); } free(buf); if (--ift >= ifa) { ift->ifa_next = NULL; *pif = ifa; } else { *pif = NULL; free(ifa); } #ifdef CYGPKG_NET_INET6 close(sock6); #endif close(sock); return (0); }
int getifaddrs(struct ifaddrs **pif) { int icnt = 1; int dcnt = 0; int ncnt = 0; int mib[6]; size_t needed; char *buf; char *next; struct ifaddrs cif; char *p, *p0; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr *sa; struct ifaddrs *ifa, *ift; u_short idx = 0; int i; size_t len, alen; char *data; char *names; _DIAGASSERT(pif != NULL); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* no flags */ if (sysctl(mib, __arraycount(mib), NULL, &needed, NULL, 0) < 0) return (-1); if ((buf = malloc(needed)) == NULL) return (-1); if (sysctl(mib, __arraycount(mib), buf, &needed, NULL, 0) < 0) { free(buf); return (-1); } for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)rtm; if (ifm->ifm_addrs & RTA_IFP) { const struct sockaddr_dl *dl; idx = ifm->ifm_index; ++icnt; dl = (struct sockaddr_dl *)(void *)(ifm + 1); dcnt += SA_RLEN((const struct sockaddr *)(const void *)dl) + ALIGNBYTES; dcnt += sizeof(ifm->ifm_data); ncnt += dl->sdl_nlen + 1; } else idx = 0; break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)rtm; if (idx && ifam->ifam_index != idx) abort(); /* this cannot happen */ #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD) if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) break; p = (char *)(void *)(ifam + 1); ++icnt; /* Scan to look for length of address */ alen = 0; for (p0 = p, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_IFA) { alen = len; break; } p += len; } for (p = p0, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_NETMASK && sa->sa_len == 0) dcnt += alen; else dcnt += len; p += len; } break; } } if (icnt + dcnt + ncnt == 1) { *pif = NULL; free(buf); return (0); } data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); if (data == NULL) { free(buf); return(-1); } ifa = (struct ifaddrs *)(void *)data; data += sizeof(struct ifaddrs) * icnt; names = data + dcnt; memset(ifa, 0, sizeof(struct ifaddrs) * icnt); ift = ifa; idx = 0; for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)rtm; if (ifm->ifm_addrs & RTA_IFP) { const struct sockaddr_dl *dl; idx = ifm->ifm_index; dl = (struct sockaddr_dl *)(void *)(ifm + 1); memset(&cif, 0, sizeof(cif)); cif.ifa_name = names; cif.ifa_flags = (int)ifm->ifm_flags; memcpy(names, dl->sdl_data, (size_t)dl->sdl_nlen); names[dl->sdl_nlen] = 0; names += dl->sdl_nlen + 1; cif.ifa_addr = (struct sockaddr *)(void *)data; memcpy(data, dl, (size_t)dl->sdl_len); data += SA_RLEN((const struct sockaddr *)(const void *)dl); /* ifm_data needs to be aligned */ cif.ifa_data = data = (void *)ALIGN(data); memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data)); data += sizeof(ifm->ifm_data); } else idx = 0; break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)rtm; if (idx && ifam->ifam_index != idx) abort(); /* this cannot happen */ if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) break; ift->ifa_name = cif.ifa_name; ift->ifa_flags = cif.ifa_flags; ift->ifa_data = NULL; p = (char *)(void *)(ifam + 1); /* Scan to look for length of address */ alen = 0; for (p0 = p, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_IFA) { alen = len; break; } p += len; } for (p = p0, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); switch (i) { case RTAX_IFA: ift->ifa_addr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; if (ift->ifa_addr->sa_family == AF_LINK) ift->ifa_data = cif.ifa_data; break; case RTAX_NETMASK: ift->ifa_netmask = (struct sockaddr *)(void *)data; if (sa->sa_len == 0) { memset(data, 0, alen); data += alen; break; } memcpy(data, p, len); data += len; break; case RTAX_BRD: ift->ifa_broadaddr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; } p += len; } ift = (ift->ifa_next = ift + 1); break; } } free(buf); if (--ift >= ifa) { ift->ifa_next = NULL; *pif = ifa; } else { *pif = NULL; free(ifa); } return (0); }
int getifaddrs(struct ifaddrs **pif) { int icnt = 1; int dcnt = 0; int ncnt = 0; #ifdef NET_RT_IFLIST int mib[6]; size_t needed; char *buf; char *next; struct ifaddrs *cif = 0; char *p, *p0; struct rt_msghdr *rtm; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr_dl *dl; struct sockaddr *sa; struct ifaddrs *ifa, *ift; u_short idx = 0; #else /* NET_RT_IFLIST */ struct ifaddrs *ifa, *ift; char buf[1024]; int m, sock; struct ifconf ifc; struct ifreq *ifr; struct ifreq *lifr; #endif /* NET_RT_IFLIST */ int i; size_t len, alen; char *data; char *names; #ifdef NET_RT_IFLIST mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* no flags */ if (__sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return (-1); if ((buf = malloc(needed)) == NULL) return (-1); if (__sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); return (-1); } for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)rtm; if (ifm->ifm_addrs & RTA_IFP) { idx = ifm->ifm_index; ++icnt; dl = (struct sockaddr_dl *)(void *)(ifm + 1); dcnt += SA_RLEN((struct sockaddr *)(void*)dl) + ALIGNBYTES; #ifdef HAVE_IFM_DATA dcnt += sizeof(ifm->ifm_data); #endif /* HAVE_IFM_DATA */ ncnt += dl->sdl_nlen + 1; } else idx = 0; break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)rtm; if (idx && ifam->ifam_index != idx) abort(); /* this cannot happen */ #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD) if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) break; p = (char *)(void *)(ifam + 1); ++icnt; #ifdef HAVE_IFAM_DATA dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES; #endif /* HAVE_IFAM_DATA */ /* Scan to look for length of address */ alen = 0; for (p0 = p, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_IFA) { alen = len; break; } p += len; } for (p = p0, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_NETMASK && SA_LEN(sa) == 0) dcnt += alen; else dcnt += len; p += len; } break; } } #else /* NET_RT_IFLIST */ ifc.ifc_buf = buf; ifc.ifc_len = sizeof(buf); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return (-1); i = ioctl(sock, SIOCGIFCONF, (char *)&ifc); close(sock); if (i < 0) return (-1); ifr = ifc.ifc_req; lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; while (ifr < lifr) { struct sockaddr *sa; sa = &ifr->ifr_addr; ++icnt; dcnt += SA_RLEN(sa); ncnt += sizeof(ifr->ifr_name) + 1; if (SA_LEN(sa) < sizeof(*sa)) ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa)); else ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); } #endif /* NET_RT_IFLIST */ if (icnt + dcnt + ncnt == 1) { *pif = NULL; free(buf); return (0); } data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); if (data == NULL) { free(buf); return(-1); } ifa = (struct ifaddrs *)(void *)data; data += sizeof(struct ifaddrs) * icnt; names = data + dcnt; memset(ifa, 0, sizeof(struct ifaddrs) * icnt); ift = ifa; #ifdef NET_RT_IFLIST idx = 0; for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)next; if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)rtm; if (ifm->ifm_addrs & RTA_IFP) { idx = ifm->ifm_index; dl = (struct sockaddr_dl *)(void *)(ifm + 1); cif = ift; ift->ifa_name = names; ift->ifa_flags = (int)ifm->ifm_flags; memcpy(names, dl->sdl_data, (size_t)dl->sdl_nlen); names[dl->sdl_nlen] = 0; names += dl->sdl_nlen + 1; ift->ifa_addr = (struct sockaddr *)(void *)data; memcpy(data, dl, (size_t)SA_LEN((struct sockaddr *) (void *)dl)); data += SA_RLEN((struct sockaddr *)(void *)dl); #ifdef HAVE_IFM_DATA /* ifm_data needs to be aligned */ ift->ifa_data = data = (void *)ALIGN(data); memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data)); data += sizeof(ifm->ifm_data); #else /* HAVE_IFM_DATA */ ift->ifa_data = NULL; #endif /* HAVE_IFM_DATA */ ift = (ift->ifa_next = ift + 1); } else idx = 0; break; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)rtm; if (idx && ifam->ifam_index != idx) abort(); /* this cannot happen */ if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) break; ift->ifa_name = cif->ifa_name; ift->ifa_flags = cif->ifa_flags; ift->ifa_data = NULL; p = (char *)(void *)(ifam + 1); /* Scan to look for length of address */ alen = 0; for (p0 = p, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); if (i == RTAX_IFA) { alen = len; break; } p += len; } for (p = p0, i = 0; i < RTAX_MAX; i++) { if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) == 0) continue; sa = (struct sockaddr *)(void *)p; len = SA_RLEN(sa); switch (i) { case RTAX_IFA: ift->ifa_addr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; case RTAX_NETMASK: ift->ifa_netmask = (struct sockaddr *)(void *)data; if (SA_LEN(sa) == 0) { memset(data, 0, alen); data += alen; break; } memcpy(data, p, len); data += len; break; case RTAX_BRD: ift->ifa_broadaddr = (struct sockaddr *)(void *)data; memcpy(data, p, len); data += len; break; } p += len; } #ifdef HAVE_IFAM_DATA /* ifam_data needs to be aligned */ ift->ifa_data = data = (void *)ALIGN(data); memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data)); data += sizeof(ifam->ifam_data); #endif /* HAVE_IFAM_DATA */ ift = (ift->ifa_next = ift + 1); break; } } free(buf); #else /* NET_RT_IFLIST */ ifr = ifc.ifc_req; lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; while (ifr < lifr) { struct sockaddr *sa; ift->ifa_name = names; names[sizeof(ifr->ifr_name)] = 0; strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name)); while (*names++) ; ift->ifa_addr = (struct sockaddr *)data; sa = &ifr->ifr_addr; memcpy(data, sa, SA_LEN(sa)); data += SA_RLEN(sa); ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); ift = (ift->ifa_next = ift + 1); } #endif /* NET_RT_IFLIST */ if (--ift >= ifa) { ift->ifa_next = NULL; *pif = ifa; } else { *pif = NULL; free(ifa); } return (0); }