summaryrefslogtreecommitdiff
path: root/source3/lib/interfaces.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-10-25 18:28:36 -0700
committerJeremy Allison <jra@samba.org>2007-10-25 18:28:36 -0700
commit6128d116b3f09ce0b055d2df89b2f7282185782e (patch)
tree4ad151c7224422b1c8f4e1cdca1ffba3d29391f0 /source3/lib/interfaces.c
parent922db252728b6a9cf72f463a7ce9d5c13f04f5f8 (diff)
downloadsamba-6128d116b3f09ce0b055d2df89b2f7282185782e.tar.gz
samba-6128d116b3f09ce0b055d2df89b2f7282185782e.tar.bz2
samba-6128d116b3f09ce0b055d2df89b2f7282185782e.zip
Fix resolve name to resolve IPv6 addresses of link-local%ifaddr
Jeremy. (This used to be commit e6609cab732d5cd5cc9a5ae50aee15147f2ec6ec)
Diffstat (limited to 'source3/lib/interfaces.c')
-rw-r--r--source3/lib/interfaces.c117
1 files changed, 112 insertions, 5 deletions
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
@@ -88,6 +88,104 @@
#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,