#include NEED_ALIGN_MACRO
#endif
-/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
- other platforms don't even have that include file. So,
- if we haven't yet got a definition, let's try to find
- <sys/sockio.h>.
- */
-
-#ifndef SIOCGIFCONF
- #include <sys/sockio.h>
-#endif
-
/* sockaddr_dl is only referenced if we're using IP_RECVIF,
so only include the header in that case.
*/
#include <net/if_dl.h>
#endif
-#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
-#include <net/if_var.h>
-#include <netinet/in_var.h>
-// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
-#endif
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-#include <netdb.h>
-#include <arpa/inet.h>
-
-/* Converts a prefix length to IPv6 network mask */
-void plen_to_mask(int plen, char *addr) {
- int i;
- int colons=7; /* Number of colons in IPv6 address */
- int bits_in_block=16; /* Bits per IPv6 block */
- for(i=0; i<=colons; i++) {
- int block, ones=0xffff, ones_in_block;
- if (plen>bits_in_block) ones_in_block=bits_in_block;
- else ones_in_block=plen;
- block = ones & (ones << (bits_in_block-ones_in_block));
- i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
- plen -= ones_in_block;
- }
-}
-
-/* Gets IPv6 interface information from the /proc filesystem in linux*/
-struct ifi_info *get_ifi_info_linuxv6(int doaliases)
-{
- struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
- FILE *fp = NULL;
- int i, nitems, flags, index, plen, scope;
- struct addrinfo hints, *res0;
- int err;
- int sockfd = -1;
- struct ifreq ifr;
- char ifnameFmt[16], addrStr[32 + 7 + 1], ifname[IFNAMSIZ], lastname[IFNAMSIZ];
-
- res0=NULL;
- ifihead = NULL;
- ifipnext = &ifihead;
-
- if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
- sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
- if (sockfd < 0) {
- goto gotError;
- }
-
- // Parse /proc/net/if_inet6 according to <https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch11s04.html>.
-
- // Create a string specifier with a width of IFNAMSIZ - 1 ("%<IFNAMSIZ - 1>s") to scan the interface name. The
- // reason why we don't just use the string-ified macro expansion of IFNAMSIZ for the width is because the width
- // needs to be a decimal string and there's no guarantee that IFNAMSIZ will be defined as a decimal integer. For
- // example, it could be defined in hexadecimal or as an arithmetic expression.
-
- snprintf(ifnameFmt, sizeof(ifnameFmt), "%%%ds", IFNAMSIZ - 1);
-
- // Write the seven IPv6 address string colons and NUL terminator, i.e., "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx".
- // The remaining 32 IPv6 address characters come from /proc/net/if_inet6.
-
- for (i = 4; i < 39; i += 5) addrStr[i] = ':';
- addrStr[39] = '\0';
-
- lastname[0] = '\0';
- for (;;) {
- nitems = fscanf(fp, " %4c%4c%4c%4c%4c%4c%4c%4c %x %x %x %x",
- &addrStr[0], &addrStr[5], &addrStr[10], &addrStr[15],
- &addrStr[20], &addrStr[25], &addrStr[30], &addrStr[35],
- &index, &plen, &scope, &flags);
- if (nitems != 12) break;
-
- nitems = fscanf(fp, ifnameFmt, ifname);
- if (nitems != 1) break;
-
- if (strcmp(lastname, ifname) == 0) {
- if (doaliases == 0)
- continue; /* already processed this interface */
- }
- memcpy(lastname, ifname, IFNAMSIZ);
- ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
- if (ifi == NULL) {
- goto gotError;
- }
-
- ifipold = *ifipnext; /* need this later */
- ifiptr = ifipnext;
- *ifipnext = ifi; /* prev points to this new one */
- ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
-
- /* Add address of the interface */
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET6;
- hints.ai_flags = AI_NUMERICHOST;
- err = getaddrinfo(addrStr, NULL, &hints, &res0);
- if (err) {
- goto gotError;
- }
- ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_addr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
-
- /* Add netmask of the interface */
- char ipv6addr[INET6_ADDRSTRLEN];
- plen_to_mask(plen, ipv6addr);
- ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_netmask == NULL) {
- goto gotError;
- }
-
- ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=AF_INET6;
- ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
- inet_pton(AF_INET6, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
-
- /* Add interface name */
- memcpy(ifi->ifi_name, ifname, IFI_NAME);
-
- /* Add interface index */
- ifi->ifi_index = index;
-
- /* Add interface flags*/
- memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi->ifi_netmask);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
- ifi->ifi_flags = ifr.ifr_flags;
- freeaddrinfo(res0);
- res0=NULL;
- }
- }
- goto done;
-
-gotError:
- if (ifihead != NULL) {
- free_ifi_info(ifihead);
- ifihead = NULL;
- }
- if (res0 != NULL) {
- freeaddrinfo(res0);
- res0=NULL;
- }
-done:
- if (sockfd != -1) {
- int rv;
- rv = close(sockfd);
- assert(rv == 0);
- }
- if (fp != NULL) {
- fclose(fp);
- }
- return(ifihead); /* pointer to first structure in linked list */
-}
-#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-
-struct ifi_info *get_ifi_info(int family, int doaliases)
-{
- int junk;
- struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
- int sockfd, sockf6, len, lastlen, flags, myflags;
-#ifdef NOT_HAVE_IF_NAMETOINDEX
- int index = 200;
-#endif
- char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
- struct ifconf ifc;
- struct ifreq *ifr, ifrcopy;
- struct sockaddr_in *sinptr;
-
-#if defined(AF_INET6) && HAVE_IPV6
- struct sockaddr_in6 *sinptr6;
-#endif
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
- if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases);
-#endif
-
- sockfd = -1;
- sockf6 = -1;
- buf = NULL;
- ifihead = NULL;
-
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd < 0) {
- goto gotError;
- }
-
- lastlen = 0;
- len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
- for ( ; ; ) {
- buf = (char*)malloc(len);
- if (buf == NULL) {
- goto gotError;
- }
- ifc.ifc_len = len;
- ifc.ifc_buf = buf;
- if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
- if (errno != EINVAL || lastlen != 0) {
- goto gotError;
- }
- } else {
- if (ifc.ifc_len == lastlen)
- break; /* success, len has not changed */
- lastlen = ifc.ifc_len;
- }
- len += 10 * sizeof(struct ifreq); /* increment */
- free(buf);
- }
- ifihead = NULL;
- ifipnext = &ifihead;
- lastname[0] = 0;
-/* end get_ifi_info1 */
-
-/* include get_ifi_info2 */
- for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
- ifr = (struct ifreq *) ptr;
-
- /* Advance to next one in buffer */
- if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
- ptr += sizeof(struct ifreq);
- else
- ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
-
-// fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
-
- if (ifr->ifr_addr.sa_family != family)
- continue; /* ignore if not desired address family */
-
- myflags = 0;
- if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
- *cptr = 0; /* replace colon will null */
- if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
- if (doaliases == 0)
- continue; /* already processed this interface */
- myflags = IFI_ALIAS;
- }
- memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
-
- ifrcopy = *ifr;
- if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
- goto gotError;
- }
-
- flags = ifrcopy.ifr_flags;
- if ((flags & IFF_UP) == 0)
- continue; /* ignore if interface not up */
-
- ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
- if (ifi == NULL) {
- goto gotError;
- }
- ifipold = *ifipnext; /* need this later */
- ifiptr = ifipnext;
- *ifipnext = ifi; /* prev points to this new one */
- ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
-
- ifi->ifi_flags = flags; /* IFF_xxx values */
- ifi->ifi_myflags = myflags; /* IFI_xxx values */
-#ifndef NOT_HAVE_IF_NAMETOINDEX
- ifi->ifi_index = if_nametoindex(ifr->ifr_name);
-#else
- ifrcopy = *ifr;
-#ifdef SIOCGIFINDEX
- if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
- ifi->ifi_index = ifrcopy.ifr_index;
- else
-#endif
- ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
-#endif
- memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
- ifi->ifi_name[IFI_NAME-1] = '\0';
-/* end get_ifi_info2 */
-/* include get_ifi_info3 */
- switch (ifr->ifr_addr.sa_family) {
- case AF_INET:
- sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
- if (ifi->ifi_addr == NULL) {
- ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_addr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
-
-#ifdef SIOCGIFNETMASK
- if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
-
- ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_netmask == NULL) goto gotError;
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
- /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
- sinptr->sin_len = sizeof(struct sockaddr_in);
-#endif
- sinptr->sin_family = AF_INET;
- memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
-#endif
-
-#ifdef SIOCGIFBRDADDR
- if (flags & IFF_BROADCAST) {
- if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
- goto gotError;
- }
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
- /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
- sinptr->sin_len = sizeof( struct sockaddr_in );
-#endif
- sinptr->sin_family = AF_INET;
- ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_brdaddr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
- }
-#endif
-
-#ifdef SIOCGIFDSTADDR
- if (flags & IFF_POINTOPOINT) {
- if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
- goto gotError;
- }
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
- /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
- sinptr->sin_len = sizeof( struct sockaddr_in );
-#endif
- sinptr->sin_family = AF_INET;
- ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_dstaddr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
- }
-#endif
- }
- break;
-
-#if defined(AF_INET6) && HAVE_IPV6
- case AF_INET6:
- sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
- if (ifi->ifi_addr == NULL) {
- ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_addr == NULL) {
- goto gotError;
- }
-
- /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
- /* We need to strip that out */
- if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
- sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
- memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
-
-#ifdef SIOCGIFNETMASK_IN6
- {
- struct in6_ifreq ifr6;
- if (sockf6 == -1)
- sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
- memset(&ifr6, 0, sizeof(ifr6));
- memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name ));
- memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
- if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
- ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_netmask == NULL) goto gotError;
- sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
- memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
- }
-#endif
- }
- break;
-#endif
-
- default:
- break;
- }
- }
- goto done;
-
-gotError:
- if (ifihead != NULL) {
- free_ifi_info(ifihead);
- ifihead = NULL;
- }
-
-done:
- if (buf != NULL) {
- free(buf);
- }
- if (sockfd != -1) {
- junk = close(sockfd);
- assert(junk == 0);
- }
- if (sockf6 != -1) {
- junk = close(sockf6);
- assert(junk == 0);
- }
- return(ifihead); /* pointer to first structure in linked list */
-}
-/* end get_ifi_info3 */
-
-/* include free_ifi_info */
-void
-free_ifi_info(struct ifi_info *ifihead)
-{
- struct ifi_info *ifi, *ifinext;
-
- for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
- if (ifi->ifi_addr != NULL)
- free(ifi->ifi_addr);
- if (ifi->ifi_netmask != NULL)
- free(ifi->ifi_netmask);
- if (ifi->ifi_brdaddr != NULL)
- free(ifi->ifi_brdaddr);
- if (ifi->ifi_dstaddr != NULL)
- free(ifi->ifi_dstaddr);
- ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
- free(ifi); /* the ifi_info{} itself */
- }
-}
-/* end free_ifi_info */
-
ssize_t
recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)