From 6128d116b3f09ce0b055d2df89b2f7282185782e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 25 Oct 2007 18:28:36 -0700 Subject: Fix resolve name to resolve IPv6 addresses of link-local%ifaddr Jeremy. (This used to be commit e6609cab732d5cd5cc9a5ae50aee15147f2ec6ec) --- source3/lib/interfaces.c | 117 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 5 deletions(-) (limited to 'source3/lib/interfaces.c') diff --git a/source3/lib/interfaces.c b/source3/lib/interfaces.c index ee5d9dfb54..48fe249034 100644 --- a/source3/lib/interfaces.c +++ b/source3/lib/interfaces.c @@ -87,6 +87,104 @@ #include "interfaces.h" #include "lib/replace/replace.h" +/**************************************************************************** + Utility functions. +****************************************************************************/ + +/**************************************************************************** + Create a struct sockaddr_storage with the netmask bits set to 1. +****************************************************************************/ + +bool make_netmask(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + unsigned long masklen) +{ + *pss_out = *pss_in; + /* Now apply masklen bits of mask. */ +#if defined(HAVE_IPV6) + if (pss_in->ss_family == AF_INET6) { + char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr; + unsigned int i; + + if (masklen > 128) { + return false; + } + for (i = 0; masklen >= 8; masklen -= 8, i++) { + *p++ = 0xff; + } + /* Deal with the partial byte. */ + *p++ &= (0xff & ~(0xff>>masklen)); + i++; + for (;i < sizeof(struct in6_addr); i++) { + *p++ = '\0'; + } + return true; + } +#endif + if (pss_in->ss_family == AF_INET) { + if (masklen > 32) { + return false; + } + ((struct sockaddr_in *)pss_out)->sin_addr.s_addr = + htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL)); + return true; + } + return false; +} + +/**************************************************************************** + Create a struct sockaddr_storage set to the broadcast or network adress from + an incoming sockaddr_storage. +****************************************************************************/ + +static void make_bcast_or_net(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + const struct sockaddr_storage *nmask, + bool make_bcast) +{ + unsigned int i = 0, len = 0; + char *pmask = NULL; + char *p = NULL; + *pss_out = *pss_in; + + /* Set all zero netmask bits to 1. */ +#if defined(HAVE_IPV6) + if (pss_in->ss_family == AF_INET6) { + p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr; + pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr; + len = 16; + } +#endif + if (pss_in->ss_family == AF_INET) { + p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr; + pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr; + len = 4; + } + + for (i = 0; i < len; i++, p++, pmask++) { + if (make_bcast) { + *p = (*p & *pmask) | (*pmask ^ 0xff); + } else { + /* make_net */ + *p = (*p & *pmask); + } + } +} + +void make_bcast(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + const struct sockaddr_storage *nmask) +{ + make_bcast_or_net(pss_out, pss_in, nmask, true); +} + +void make_net(struct sockaddr_storage *pss_out, + const struct sockaddr_storage *pss_in, + const struct sockaddr_storage *nmask) +{ + make_bcast_or_net(pss_out, pss_in, nmask, false); +} + /**************************************************************************** Try the "standard" getifaddrs/freeifaddrs interfaces. Also gets IPv6 interfaces. @@ -137,11 +235,20 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size); memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size); - if ((ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) && - ifptr->ifa_broadaddr) { - memcpy(&ifaces[total].bcast, - ifptr->ifa_broadaddr, - copy_size); + if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) { + if (ifptr->ifa_broadaddr) { + memcpy(&ifaces[total].bcast, + ifptr->ifa_broadaddr, + copy_size); + } else { + /* For some reason ifptr->ifa_broadaddr + * is null. Make one from ifa_addr and + * ifa_netmask. + */ + make_bcast(&ifaces[total].bcast, + &ifaces[total].ip, + &ifaces[total].netmask); + } } else if ((ifaces[total].flags & IFF_POINTOPOINT) && ifptr->ifa_dstaddr ) { memcpy(&ifaces[total].bcast, -- cgit