diff options
author | Jeremy Allison <jra@samba.org> | 2007-10-10 18:25:16 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2007-10-10 18:25:16 -0700 |
commit | 8e54530b52fd256137740107e9fdf000f00a7a30 (patch) | |
tree | f9ca56cc0b2eff78c3550c924c79ee4ca0666fd2 /source3/lib | |
parent | 0ec55a246238b6cfb3727942c20cd55a16ab4d4a (diff) | |
download | samba-8e54530b52fd256137740107e9fdf000f00a7a30.tar.gz samba-8e54530b52fd256137740107e9fdf000f00a7a30.tar.bz2 samba-8e54530b52fd256137740107e9fdf000f00a7a30.zip |
Add start of IPv6 implementation. Currently most of this is avoiding
IPv6 in winbindd, but moves most of the socket functions that were
wrongly in lib/util.c into lib/util_sock.c and provides generic
IPv4/6 independent versions of most things. Still lots of work
to do, but now I can see how I'll fix the access check code.
Nasty part that remains is the name resolution code which is
used to returning arrays of in_addr structs.
Jeremy.
(This used to be commit 3f6bd0e1ec5cc6670f3d08f76fc2cd94c9cd1a08)
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/access.c | 2 | ||||
-rw-r--r-- | source3/lib/interface.c | 644 | ||||
-rw-r--r-- | source3/lib/interfaces.c | 258 | ||||
-rw-r--r-- | source3/lib/util.c | 189 | ||||
-rw-r--r-- | source3/lib/util_sock.c | 515 | ||||
-rw-r--r-- | source3/lib/wins_srv.c | 10 |
6 files changed, 1112 insertions, 506 deletions
diff --git a/source3/lib/access.c b/source3/lib/access.c index 303e3ed4c4..17f4c367eb 100644 --- a/source3/lib/access.c +++ b/source3/lib/access.c @@ -279,7 +279,7 @@ static BOOL only_ipaddrs_in_list(const char** list) continue; } - if (!is_ipaddress(*list)) { + if (!is_ipaddress_v4(*list)) { /* * if we failed, make sure that it was not because the token * was a network/netmask pair. Only network/netmask pairs diff --git a/source3/lib/interface.c b/source3/lib/interface.c index 5982d82e47..1471a06f46 100644 --- a/source3/lib/interface.c +++ b/source3/lib/interface.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. multiple interface handling Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,66 +23,404 @@ static struct iface_struct *probed_ifaces; static int total_probed; -struct in_addr allones_ip; -struct in_addr loopback_ip; - static struct interface *local_interfaces; -#define ALLONES ((uint32)0xFFFFFFFF) -#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES)) -#define MKNETADDR(_IP, _NM) (_IP & _NM) +/**************************************************************************** + Check if an IP is one of mine. +**************************************************************************/ + +bool ismyaddr(const struct sockaddr_storage *ip) +{ + struct interface *i; + for (i=local_interfaces;i;i=i->next) { + if (addr_equal(&i->ip,ip)) { + return true; + } + } + return false; +} + +bool ismyip_v4(struct in_addr ip) +{ + struct sockaddr_storage ss; + in_addr_to_sockaddr_storage(&ss, ip); + return ismyaddr(&ss); +} /**************************************************************************** Try and find an interface that matches an ip. If we cannot, return NULL. **************************************************************************/ -static struct interface *iface_find(struct in_addr ip, BOOL CheckMask) +static struct interface *iface_find(const struct sockaddr_storage *ip, + bool check_mask) { struct interface *i; - if (is_zero_ip(ip)) return local_interfaces; - for (i=local_interfaces;i;i=i->next) - if (CheckMask) { - if (same_net(i->ip,ip,i->nmask)) return i; - } else if ((i->ip).s_addr == ip.s_addr) return i; + if (is_address_any(ip)) { + return local_interfaces; + } + + for (i=local_interfaces;i;i=i->next) { + if (check_mask) { + if (same_net(ip, &i->ip, &i->netmask)) { + return i; + } + } else if (addr_equal(&i->ip, ip)) { + return i; + } + } return NULL; } /**************************************************************************** + Check if a packet is from a local (known) net. +**************************************************************************/ + +bool is_local_net(const struct sockaddr_storage *from) +{ + struct interface *i; + for (i=local_interfaces;i;i=i->next) { + if (same_net(from, &i->ip, &i->netmask)) { + return true; + } + } + return false; +} + +/**************************************************************************** + Check if a packet is from a local (known) net. +**************************************************************************/ + +bool is_local_net_v4(struct in_addr from) +{ + struct sockaddr_storage ss; + + in_addr_to_sockaddr_storage(&ss, from); + return is_local_net(&ss); +} + +/**************************************************************************** + How many interfaces do we have ? +**************************************************************************/ + +int iface_count(void) +{ + int ret = 0; + struct interface *i; + + for (i=local_interfaces;i;i=i->next) { + ret++; + } + return ret; +} + +/**************************************************************************** + How many interfaces do we have (v4 only) ? +**************************************************************************/ + +int iface_count_v4(void) +{ + int ret = 0; + struct interface *i; + + for (i=local_interfaces;i;i=i->next) { + if (i->ip.ss_family == AF_INET) { + ret++; + } + } + return ret; +} + +/**************************************************************************** + Return a pointer to the in_addr of the first IPv4 interface. +**************************************************************************/ + +const struct in_addr *first_ipv4_iface(void) +{ + struct interface *i; + + for (i=local_interfaces;i ;i=i->next) { + if (i->ip.ss_family == AF_INET) { + break; + } + } + + if (!i) { + return NULL; + } + return &((const struct sockaddr_in *)&i->ip)->sin_addr; +} + +/**************************************************************************** + Return the Nth interface. +**************************************************************************/ + +struct interface *get_interface(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) { + n--; + } + + if (i) { + return i; + } + return NULL; +} + +/**************************************************************************** + Return IP sockaddr_storage of the Nth interface. +**************************************************************************/ + +const struct sockaddr_storage *iface_n_sockaddr_storage(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) { + n--; + } + + if (i) { + return &i->ip; + } + return NULL; +} + +/**************************************************************************** + Return IPv4 of the Nth interface (if a v4 address). NULL otherwise. +**************************************************************************/ + +const struct in_addr *iface_n_ip_v4(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) { + n--; + } + + if (i && i->ip.ss_family == AF_INET) { + return &((const struct sockaddr_in *)&i->ip)->sin_addr; + } + return NULL; +} + +/**************************************************************************** + Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise. +**************************************************************************/ + +const struct in_addr *iface_n_bcast_v4(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) { + n--; + } + + if (i && i->ip.ss_family == AF_INET) { + return &((const struct sockaddr_in *)&i->bcast)->sin_addr; + } + return NULL; +} + +/**************************************************************************** + Return bcast of the Nth interface. +**************************************************************************/ + +const struct sockaddr_storage *iface_n_bcast(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) { + n--; + } + + if (i) { + return &i->bcast; + } + return NULL; +} + +/* these 3 functions return the ip/bcast/nmask for the interface + most appropriate for the given ip address. If they can't find + an appropriate interface they return the requested field of the + first known interface. */ + +const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip) +{ + struct interface *i = iface_find(ip, true); + if (i) { + return &i->ip; + } + + /* Search for the first interface with + * matching address family. */ + + for (i=local_interfaces;i;i=i->next) { + if (i->ip.ss_family == ip->ss_family) { + return &i->ip; + } + } + return NULL; +} + +/* + return True if a IP is directly reachable on one of our interfaces +*/ + +bool iface_local(struct sockaddr_storage *ip) +{ + return iface_find(ip, True) ? true : false; +} + +/**************************************************************************** Add an interface to the linked list of interfaces. ****************************************************************************/ -static void add_interface(struct in_addr ip, struct in_addr nmask) +static void add_interface(const struct iface_struct *ifs) { + char addr[INET6_ADDRSTRLEN]; struct interface *iface; - if (iface_find(ip, False)) { - DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip))); + + if (iface_find(&ifs->ip, False)) { + DEBUG(3,("add_interface: not adding duplicate interface %s\n", + print_sockaddr(addr, sizeof(addr), + &ifs->ip, sizeof(struct sockaddr_storage)) )); return; } -#if !defined(__s390__) - if (ip_equal(nmask, allones_ip)) { + if (!(ifs->flags & IFF_BROADCAST)) { DEBUG(3,("not adding non-broadcast interface %s\n", - inet_ntoa(ip))); + ifs->name )); return; } -#endif iface = SMB_MALLOC_P(struct interface); - if (!iface) return; + if (!iface) { + return; + } ZERO_STRUCTPN(iface); - iface->ip = ip; - iface->nmask = nmask; - iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr); + iface->name = SMB_STRDUP(ifs->name); + if (!iface->name) { + SAFE_FREE(iface); + return; + } + iface->flags = ifs->flags; + iface->ip = ifs->ip; + iface->netmask = ifs->netmask; + iface->bcast = ifs->bcast; DLIST_ADD(local_interfaces, iface); - DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip))); - DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast))); - DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask))); + DEBUG(2,("added interface %s ip=%s ", + iface->name, + print_sockaddr(addr, sizeof(addr), + &iface->ip, sizeof(struct sockaddr_storage)) )); + DEBUG(2,("bcast=%s ", + print_sockaddr(addr, sizeof(addr), + &iface->bcast, + sizeof(struct sockaddr_storage)) )); + DEBUG(2,("netmask=%s\n", + print_sockaddr(addr, sizeof(addr), + &iface->netmask, + sizeof(struct sockaddr_storage)) )); +} + +/**************************************************************************** + Create a struct sockaddr_storage with the netmask bits set to 1. +****************************************************************************/ + +static 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(AF_INET6) + 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(AF_INET6) + 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); + } + } +} + +static 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); +} + +static 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); } /**************************************************************************** @@ -98,68 +437,121 @@ static void add_interface(struct in_addr ip, struct in_addr nmask) static void interpret_interface(char *token) { - struct in_addr ip, nmask; + struct sockaddr_storage ss; + struct sockaddr_storage ss_mask; + struct sockaddr_storage ss_net; + struct sockaddr_storage ss_bcast; + struct iface_struct ifs; char *p; - int i, added=0; - - zero_ip(&ip); - zero_ip(&nmask); + int i; + bool added=false; + bool goodaddr = false; /* first check if it is an interface name */ for (i=0;i<total_probed;i++) { if (gen_fnmatch(token, probed_ifaces[i].name) == 0) { - add_interface(probed_ifaces[i].iface_addr.ip, - probed_ifaces[i].iface_netmask.netmask); - added = 1; + add_interface(&probed_ifaces[i]); + added = true; } } - if (added) return; + if (added) { + return; + } /* maybe it is a DNS name */ p = strchr_m(token,'/'); - if (!p) { - ip = *interpret_addr2(token); + if (!p && interpret_string_addr(&ss, token)) { for (i=0;i<total_probed;i++) { - if (ip.s_addr == probed_ifaces[i].iface_addr.ip.s_addr - && !ip_equal(allones_ip, - probed_ifaces[i].iface_netmask.netmask)) { - add_interface(probed_ifaces[i].iface_addr.ip, - probed_ifaces[i].iface_netmask.netmask); + if (addr_equal(&ss, &probed_ifaces[i].ip)) { + add_interface(&probed_ifaces[i]); return; } } - DEBUG(2,("can't determine netmask for %s\n", token)); + DEBUG(2,("interpret_interface: " + "can't determine interface for %s\n", + token)); return; } /* parse it into an IP address/netmasklength pair */ *p = 0; - ip = *interpret_addr2(token); + goodaddr = interpret_string_addr(&ss, token); *p++ = '/'; + if (!goodaddr) { + DEBUG(2,("interpret_interface: " + "can't determine interface for %s\n", + token)); + return; + } + if (strlen(p) > 2) { - nmask = *interpret_addr2(p); + goodaddr = interpret_string_addr(&ss_mask, p); + if (!goodaddr) { + DEBUG(2,("interpret_interface: " + "can't determine netmask from %s\n", + p)); + return; + } } else { - nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES)); + char *endp = NULL; + unsigned long val = strtoul(p, &endp, 0); + if (p == endp || (endp && *endp != '\0')) { + DEBUG(2,("interpret_interface: " + "can't determine netmask value from %s\n", + p)); + return; + } + if (!make_netmask(&ss_mask, &ss, val)) { + DEBUG(2,("interpret_interface: " + "can't apply netmask value %lu from %s\n", + val, + p)); + return; + } } - /* maybe the first component was a broadcast address */ - if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) || - ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) { + make_bcast(&ss_bcast, &ss, &ss_mask); + make_net(&ss_net, &ss, &ss_mask); + + /* Maybe the first component was a broadcast address. */ + if (addr_equal(&ss_bcast, &ss) || addr_equal(&ss_net, &ss)) { for (i=0;i<total_probed;i++) { - if (same_net(ip, probed_ifaces[i].iface_addr.ip, - nmask)) { - add_interface(probed_ifaces[i].iface_addr.ip, - nmask); + if (same_net(&ss, &probed_ifaces[i].ip, &ss_mask)) { + /* Temporarily replace netmask on + * the detected interface - user knows + * best.... */ + struct sockaddr_storage saved_mask = + probed_ifaces[i].netmask; + probed_ifaces[i].netmask = ss_mask; + DEBUG(2,("interpret_interface: " + "using netmask value %s from " + "config file on interface %s\n", + p, + probed_ifaces[i].name)); + add_interface(&probed_ifaces[i]); + probed_ifaces[i].netmask = saved_mask; return; } } - DEBUG(2,("Can't determine ip for broadcast address %s\n", - token)); + DEBUG(2,("interpret_interface: Can't determine ip for " + "broadcast address %s\n", + token)); return; } - add_interface(ip, nmask); + /* Just fake up the interface definition. User knows best. */ + + DEBUG(2,("interpret_interface: Adding interface %s\n", + token)); + + ZERO_STRUCT(ifs); + safe_strcpy(ifs.name, token, sizeof(ifs.name)-1); + ifs.flags = IFF_BROADCAST; + ifs.ip = ss; + ifs.netmask = ss_mask; + ifs.bcast = ss_bcast; + add_interface(&ifs); } /**************************************************************************** @@ -168,14 +560,9 @@ static void interpret_interface(char *token) void load_interfaces(void) { - const char **ptr; - int i; struct iface_struct ifaces[MAX_INTERFACES]; - - ptr = lp_interfaces(); - - allones_ip = *interpret_addr2("255.255.255.255"); - loopback_ip = *interpret_addr2("127.0.0.1"); + const char **ptr = lp_interfaces(); + int i; SAFE_FREE(probed_ifaces); @@ -183,11 +570,11 @@ void load_interfaces(void) while (local_interfaces) { struct interface *iface = local_interfaces; DLIST_REMOVE(local_interfaces, local_interfaces); - ZERO_STRUCTPN(iface); + SAFE_FREE(iface->name); SAFE_FREE(iface); } - /* probe the kernel for interfaces */ + /* Probe the kernel for interfaces */ total_probed = get_interfaces(ifaces, MAX_INTERFACES); if (total_probed > 0) { @@ -208,15 +595,8 @@ void load_interfaces(void) exit(1); } for (i=0;i<total_probed;i++) { - if ( -#if !defined(__s390__) - probed_ifaces[i].iface_netmask.netmask.s_addr != - allones_ip.s_addr && -#endif - probed_ifaces[i].iface_addr.ip.s_addr != - loopback_ip.s_addr) { - add_interface(probed_ifaces[i].iface_addr.ip, - probed_ifaces[i].iface_netmask.netmask); + if (probed_ifaces[i].flags & IFF_BROADCAST) { + add_interface(&probed_ifaces[i]); } } return; @@ -244,7 +624,7 @@ void gfree_interfaces(void) while (local_interfaces) { struct interface *iface = local_interfaces; DLIST_REMOVE(local_interfaces, local_interfaces); - ZERO_STRUCTPN(iface); + SAFE_FREE(iface->name); SAFE_FREE(iface); } @@ -255,7 +635,7 @@ void gfree_interfaces(void) Return True if the list of probed interfaces has changed. ****************************************************************************/ -BOOL interfaces_changed(void) +bool interfaces_changed(void) { int n; struct iface_struct ifaces[MAX_INTERFACES]; @@ -263,115 +643,9 @@ BOOL interfaces_changed(void) n = get_interfaces(ifaces, MAX_INTERFACES); if ((n > 0 )&& (n != total_probed || - memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) { - return True; - } - - return False; -} - -/**************************************************************************** - Check if an IP is one of mine. -**************************************************************************/ - -BOOL ismyip(struct in_addr ip) -{ - struct interface *i; - for (i=local_interfaces;i;i=i->next) - if (ip_equal(i->ip,ip)) return True; - return False; -} - -/**************************************************************************** - Check if a packet is from a local (known) net. -**************************************************************************/ - -BOOL is_local_net(struct in_addr from) -{ - struct interface *i; - for (i=local_interfaces;i;i=i->next) { - if((from.s_addr & i->nmask.s_addr) == - (i->ip.s_addr & i->nmask.s_addr)) - return True; + memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) { + return true; } - return False; -} - -/**************************************************************************** - How many interfaces do we have -**************************************************************************/ - -int iface_count(void) -{ - int ret = 0; - struct interface *i; - - for (i=local_interfaces;i;i=i->next) - ret++; - return ret; -} - -/**************************************************************************** - Return the Nth interface. -**************************************************************************/ - -struct interface *get_interface(int n) -{ - struct interface *i; - - for (i=local_interfaces;i && n;i=i->next) - n--; - - if (i) return i; - return NULL; -} - -/**************************************************************************** - Return IP of the Nth interface. -**************************************************************************/ - -struct in_addr *iface_n_ip(int n) -{ - struct interface *i; - - for (i=local_interfaces;i && n;i=i->next) - n--; - - if (i) return &i->ip; - return NULL; -} - -/**************************************************************************** - Return bcast of the Nth interface. -**************************************************************************/ - -struct in_addr *iface_n_bcast(int n) -{ - struct interface *i; - - for (i=local_interfaces;i && n;i=i->next) - n--; - - if (i) return &i->bcast; - return NULL; -} -/* these 3 functions return the ip/bcast/nmask for the interface - most appropriate for the given ip address. If they can't find - an appropriate interface they return the requested field of the - first known interface. */ - -struct in_addr *iface_ip(struct in_addr ip) -{ - struct interface *i = iface_find(ip, True); - return(i ? &i->ip : &local_interfaces->ip); -} - -/* - return True if a IP is directly reachable on one of our interfaces -*/ - -BOOL iface_local(struct in_addr ip) -{ - return iface_find(ip, True) ? True : False; + return false; } diff --git a/source3/lib/interfaces.c b/source3/lib/interfaces.c index 632b38f2b6..c56155c64e 100644 --- a/source3/lib/interfaces.c +++ b/source3/lib/interfaces.c @@ -101,6 +101,7 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) struct ifaddrs *iflist = NULL; struct ifaddrs *ifptr = NULL; int total = 0; + size_t copy_size; if (getifaddrs(&iflist) < 0) { return -1; @@ -111,25 +112,40 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) ifptr != NULL && total < max_interfaces; ifptr = ifptr->ifa_next) { + memset(&ifaces[total], '\0', sizeof(ifaces[total])); + + copy_size = sizeof(struct sockaddr_in); + if (!ifptr->ifa_addr || !ifptr->ifa_netmask) { continue; } - /* Skip ipv6 for now. */ - if (ifptr->ifa_addr->sa_family != AF_INET) { - continue; - } - if (!(ifptr->ifa_flags & IFF_UP)) { + ifaces[total].flags = ifptr->ifa_flags; + + /* Check the interface is up. */ + if (!(ifaces[total].flags & IFF_UP)) { continue; } - ifaces[total].sa_family = ifptr->ifa_addr->sa_family; - - ifaces[total].iface_addr.ip = - ((struct sockaddr_in *)ifptr->ifa_addr)->sin_addr; +#ifdef AF_INET6 + if (ifptr->ifa_addr->sa_family == AF_INET6) { + copy_size = sizeof(struct sockaddr_in6); + } +#endif - ifaces[total].iface_netmask.netmask = - ((struct sockaddr_in *)ifptr->ifa_netmask)->sin_addr; + memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size); + memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size); + if (ifaces[total].flags & IFF_BROADCAST) { + memcpy(&ifaces[total].bcast, + ifptr->ifa_broadaddr, + copy_size); + } else if (ifaces[total].flags & IFF_POINTOPOINT) { + memcpy(&ifaces[total].bcast, + ifptr->ifa_dstaddr, + copy_size); + } else { + continue; + } strncpy(ifaces[total].name, ifptr->ifa_name, sizeof(ifaces[total].name)-1); @@ -162,9 +178,6 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) int fd, i, n; struct ifreq *ifr=NULL; int total = 0; - struct in_addr ipaddr; - struct in_addr nmask; - char *iname; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; @@ -184,32 +197,54 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) /* Loop through interfaces, looking for given IP address */ for (i=n-1;i>=0 && total < max_interfaces;i--) { - if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) { + + memset(&ifaces[total], '\0', sizeof(ifaces[total])); + + /* Check the interface is up. */ + if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) { continue; } - iname = ifr[i].ifr_name; - ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr; + ifaces[total].flags = ifr[i].ifr_flags; - if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) { + if (!(flags & IFF_UP)) { continue; } - if (!(ifr[i].ifr_flags & IFF_UP)) { + if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) { continue; } + strncpy(ifaces[total].name, ifr[i].ifr_name, + sizeof(ifaces[total].name)-1); + ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; + + memcpy(&ifaces[total].ip, &ifr[i].ifr_addr, + sizeof(struct sockaddr_in)); + if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) { continue; } - nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr; + memcpy(&ifaces[total].netmask, &ifr[i].ifr_netmask, + sizeof(struct sockaddr_in)); + + if (ifaces[total].flags & IFF_BROADCAST) { + if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) { + continue; + } + memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr, + sizeof(struct sockaddr_in)); + } else if (ifaces[total].flags & IFF_POINTOPOINT) { + if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) { + continue; + } + memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr, + sizeof(struct sockaddr_in)); + } else { + continue; + } - strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1); - ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - ifaces[total].sa_family = AF_INET; - ifaces[total].iface_addr.ip = ipaddr; - ifaces[total].iface_netmask.netmask = nmask; total++; } @@ -239,9 +274,6 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) int fd, i, n; struct ifreq *ifr=NULL; int total = 0; - struct in_addr ipaddr; - struct in_addr nmask; - char *iname; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; @@ -271,6 +303,9 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) /* Loop through interfaces */ for (i = 0; i<n && total < max_interfaces; i++) { + + memset(&ifaces[total], '\0', sizeof(ifaces[total])); + ifreq = ifr[i]; strioctl.ic_cmd = SIOCGIFFLAGS; @@ -280,7 +315,9 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) continue; } - if (!(ifreq.ifr_flags & IFF_UP)) { + ifaces[total].flags = ifreq.ifr_flags; + + if (!(ifaces[total].flags & IFF_UP)) { continue; } @@ -291,8 +328,12 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) continue; } - ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr; - iname = ifreq.ifr_name; + strncpy(ifaces[total].name, iname, + sizeof(ifaces[total].name)-1); + ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; + + memcpy(&ifaces[total].ip, &ifreq.ifr_addr, + sizeof(struct sockaddr_in)); strioctl.ic_cmd = SIOCGIFNETMASK; strioctl.ic_dp = (char *)&ifreq; @@ -301,13 +342,30 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) continue; } - nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; + memcpy(&ifaces[total].netmask, &ifreq.ifr_addr, + sizeof(struct sockaddr_in)); - strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1); - ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - ifaces[total].sa_family = AF_INET; - ifaces[total].iface_addr.ip = ipaddr; - ifaces[total].iface_netmask.netmask = nmask; + if (ifaces[total].flags & IFF_BROADCAST) { + strioctl.ic_cmd = SIOCGIFBRDADDR; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(fd, I_STR, &strioctl) != 0) { + continue; + } + memcpy(&ifaces[total].bcast, &ifreq.ifr_broadaddr, + sizeof(struct sockaddr_in)); + } else if (ifaces[total].flags & IFF_POINTOPOINT) { + strioctl.ic_cmd = SIOCGIFDSTADDR; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(fd, I_STR, &strioctl) != 0) { + continue; + } + memcpy(&ifaces[total].bcast, &ifreq.ifr_dstaddr, + sizeof(struct sockaddr_in)); + } else { + continue; + } total++; } @@ -331,9 +389,6 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) int fd, i; struct ifconf ifc; struct ifreq *ifr=NULL; - struct in_addr ipaddr; - struct in_addr nmask; - char *iname; int total = 0; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { @@ -357,34 +412,54 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) while (i > 0 && total < max_interfaces) { uint_t inc; + memset(&ifaces[total], '\0', sizeof(ifaces[total])); + inc = ifr->ifr_addr.sa_len; - if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { + if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { goto next; } - ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr; - iname = ifr->ifr_name; + ifaces[total].flags = ifr->ifr_flags; - if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { + if (!(ifaces[total].flags & IFF_UP)) { goto next; } - if (!(ifr->ifr_flags & IFF_UP)) { + if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { goto next; } + memcpy(&ifaces[total].ip, &ifr->ifr_addr, + sizeof(struct sockaddr_in)); + + strncpy(ifaces[total].name, ifr->ifr_name, + sizeof(ifaces[total].name)-1); + ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; + if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { goto next; } - nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; + memcpy(&ifaces[total].netmask, &ifr->ifr_addr, + sizeof(struct sockaddr_in)); + + if (ifaces[total].flags & IFF_BROADCAST) { + if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) { + continue; + } + memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr, + sizeof(struct sockaddr_in)); + } else if (ifaces[total].flags & IFF_POINTOPOINT) { + if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) { + continue; + } + memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr, + sizeof(struct sockaddr_in)); + } else { + continue; + } - strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1); - ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - ifaces[total].sa_family = AF_INET; - ifaces[total].iface_addr.ip = ipaddr; - ifaces[total].iface_netmask.netmask = nmask; total++; @@ -421,25 +496,36 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) static int iface_comp(struct iface_struct *i1, struct iface_struct *i2) { int r; - r = strcmp(i1->name, i2->name); - if (r) { - return r; - } - r = i1->sa_family - i2->sa_family; - if (r) { - return r; - } #ifdef AF_INET6 - if (i1->sa_family == AF_INET6) { - r = memcmp(&i1->iface_addr.ip6, - &i2->iface_addr.ip6, + /* + * If we have IPv6 - sort these interfaces lower + * than any IPv4 ones. + */ + if (i1->ip.ss_family == AF_INET6 && + i2->ip.ss_family == AF_INET) { + return -1; + } else if (i1->ip.ss_family == AF_INET && + i2->ip.ss_family == AF_INET6) { + return 1; + } + + if (i1->ip.ss_family == AF_INET6) { + struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip; + struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip; + + r = memcmp(&s1->sin6_addr, + &s2->sin6_addr, sizeof(struct in6_addr)); if (r) { return r; } - r = memcmp(&i1->iface_netmask.netmask6, - &i1->iface_netmask.netmask6, + + s1 = (struct sockaddr_in6 *)&i1->netmask; + s2 = (struct sockaddr_in6 *)&i2->netmask; + + r = memcmp(&s1->sin6_addr, + &s2->sin6_addr, sizeof(struct in6_addr)); if (r) { return r; @@ -447,14 +533,21 @@ static int iface_comp(struct iface_struct *i1, struct iface_struct *i2) } #endif - if (i1->sa_family == AF_INET) { - r = ntohl(i1->iface_addr.ip.s_addr) - - ntohl(i2->iface_addr.ip.s_addr); + if (i1->ip.ss_family == AF_INET) { + struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip; + struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip; + + r = ntohl(s1->sin_addr.s_addr) - + ntohl(s2->sin_addr.s_addr); if (r) { return r; } - r = ntohl(i1->iface_netmask.netmask.s_addr) - - ntohl(i2->iface_netmask.netmask.s_addr); + + s1 = (struct sockaddr_in *)&i1->netmask; + s2 = (struct sockaddr_in *)&i2->netmask; + + r = ntohl(s1->sin_addr.s_addr) - + ntohl(s2->sin_addr.s_addr); } return r; } @@ -503,15 +596,26 @@ int get_interfaces(struct iface_struct *ifaces, int max_interfaces) for (i=0;i<total;i++) { char addr[INET6_ADDRSTRLEN]; + int ret; printf("%-10s ", ifaces[i].name); - printf("IP=%s ", inet_ntop(ifaces[i].sa_family, - (const void *)&ifaces[i].iface_addr.ip, - addr, - sizeof(addr))); - printf("NETMASK=%s\n", inet_ntop(ifaces[i].sa_family, - (const void *)&ifaces[i].iface_netmask.netmask, - addr, - sizeof(addr))); + addr[0] = '\0'; + ret = getnameinfo((struct sockaddr *)&ifaces[i].ip, + sizeof(ifaces[i].ip), + addr, sizeof(addr), + NULL, 0, NI_NUMERICHOST); + printf("IP=%s ", addr); + addr[0] = '\0'; + ret = getnameinfo((struct sockaddr *)&ifaces[i].netmask, + sizeof(ifaces[i].netmask), + addr, sizeof(addr), + NULL, 0, NI_NUMERICHOST); + printf("NETMASK=%s ", addr); + addr[0] = '\0'; + ret = getnameinfo((struct sockaddr *)&ifaces[i].bcast, + sizeof(ifaces[i].bcast), + addr, sizeof(addr), + NULL, 0, NI_NUMERICHOST); + printf("BCAST=%s\n", addr); } return 0; } diff --git a/source3/lib/util.c b/source3/lib/util.c index adbebb04d4..f457e53c47 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -1286,102 +1286,6 @@ int interpret_protocol(const char *str,int def) return(def); } -/**************************************************************************** - Return true if a string could be a pure IP address. -****************************************************************************/ - -BOOL is_ipaddress(const char *str) -{ - BOOL pure_address = True; - int i; - - for (i=0; pure_address && str[i]; i++) - if (!(isdigit((int)str[i]) || str[i] == '.')) - pure_address = False; - - /* Check that a pure number is not misinterpreted as an IP */ - pure_address = pure_address && (strchr_m(str, '.') != NULL); - - return pure_address; -} - -/**************************************************************************** - Interpret an internet address or name into an IP address in 4 byte form. -****************************************************************************/ - -uint32 interpret_addr(const char *str) -{ - struct hostent *hp; - uint32 res; - - if (strcmp(str,"0.0.0.0") == 0) - return(0); - if (strcmp(str,"255.255.255.255") == 0) - return(0xFFFFFFFF); - - /* if it's in the form of an IP address then get the lib to interpret it */ - if (is_ipaddress(str)) { - res = inet_addr(str); - } else { - /* otherwise assume it's a network name of some sort and use - sys_gethostbyname */ - if ((hp = sys_gethostbyname(str)) == 0) { - DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str)); - return 0; - } - - if(hp->h_addr == NULL) { - DEBUG(3,("sys_gethostbyname: host address is invalid for host %s\n",str)); - return 0; - } - putip((char *)&res,(char *)hp->h_addr); - } - - if (res == (uint32)-1) - return(0); - - return(res); -} - -/******************************************************************* - A convenient addition to interpret_addr(). -******************************************************************/ - -struct in_addr *interpret_addr2(const char *str) -{ - static struct in_addr ret; - uint32 a = interpret_addr(str); - ret.s_addr = a; - return(&ret); -} - -/******************************************************************* - Check if an IP is the 0.0.0.0. -******************************************************************/ - -BOOL is_zero_ip(struct in_addr ip) -{ - uint32 a; - putip((char *)&a,(char *)&ip); - return(a == 0); -} - -/******************************************************************* - Set an IP to 0.0.0.0. -******************************************************************/ - -void zero_ip(struct in_addr *ip) -{ - static BOOL init; - static struct in_addr ipzero; - - if (!init) { - ipzero = *interpret_addr2("0.0.0.0"); - init = True; - } - - *ip = ipzero; -} #if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT)) /****************************************************************** @@ -1506,22 +1410,6 @@ char *automount_lookup(const char *user_name) #endif /* WITH_NISPLUS_HOME */ #endif -/******************************************************************* - Are two IPs on the same subnet? -********************************************************************/ - -BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) -{ - uint32 net1,net2,nmask; - - nmask = ntohl(mask.s_addr); - net1 = ntohl(ip1.s_addr); - net2 = ntohl(ip2.s_addr); - - return((net1 & nmask) == (net2 & nmask)); -} - - /**************************************************************************** Check if a process exists. Does this work on all unixes? ****************************************************************************/ @@ -2097,83 +1985,6 @@ BOOL is_myname(const char *s) return(ret); } -BOOL is_myname_or_ipaddr(const char *s) -{ - fstring name, dnsname; - char *servername; - - if ( !s ) - return False; - - /* santize the string from '\\name' */ - - fstrcpy( name, s ); - - servername = strrchr_m( name, '\\' ); - if ( !servername ) - servername = name; - else - servername++; - - /* optimize for the common case */ - - if (strequal(servername, global_myname())) - return True; - - /* check for an alias */ - - if (is_myname(servername)) - return True; - - /* check for loopback */ - - if (strequal(servername, "127.0.0.1")) - return True; - - if (strequal(servername, "localhost")) - return True; - - /* maybe it's my dns name */ - - if ( get_mydnsfullname( dnsname ) ) - if ( strequal( servername, dnsname ) ) - return True; - - /* handle possible CNAME records */ - - if ( !is_ipaddress( servername ) ) { - /* use DNS to resolve the name, but only the first address */ - struct hostent *hp; - - if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { - struct in_addr return_ip; - putip( (char*)&return_ip, (char*)hp->h_addr ); - fstrcpy( name, inet_ntoa( return_ip ) ); - servername = name; - } - } - - /* maybe its an IP address? */ - if (is_ipaddress(servername)) { - struct iface_struct nics[MAX_INTERFACES]; - int i, n; - uint32 ip; - - ip = interpret_addr(servername); - if ((ip==0) || (ip==0xffffffff)) - return False; - - n = get_interfaces(nics, MAX_INTERFACES); - for (i=0; i<n; i++) { - if (ip == nics[i].iface_addr.ip.s_addr) - return True; - } - } - - /* no match */ - return False; -} - /******************************************************************* Is the name specified our workgroup/domain. Returns true if it is equal, false otherwise. diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 1508ddfce3..7a1a05ec29 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -29,33 +29,353 @@ static int client_fd = -1; static char client_ip_string[INET6_ADDRSTRLEN]; /**************************************************************************** - Pritn out an IPv4 or IPv6 address from a struct sockaddr_storage. + Return true if a string could be a pure IPv4 address. ****************************************************************************/ -char *print_sockaddr(char *dest, - size_t destlen, - struct sockaddr_storage *psa) +bool is_ipaddress_v4(const char *str) { - if (destlen > 0) { - dest[0] = '\0'; + bool pure_address = true; + int i; + + for (i=0; pure_address && str[i]; i++) { + if (!(isdigit((int)str[i]) || str[i] == '.')) { + pure_address = false; + } + } + + /* Check that a pure number is not misinterpreted as an IP */ + pure_address = pure_address && (strchr_m(str, '.') != NULL); + return pure_address; +} + +/**************************************************************************** + Interpret an internet address or name into an IP address in 4 byte form. +****************************************************************************/ + +uint32 interpret_addr(const char *str) +{ + struct hostent *hp; + uint32 res; + + if (strcmp(str,"0.0.0.0") == 0) + return(0); + if (strcmp(str,"255.255.255.255") == 0) + return(0xFFFFFFFF); + + /* if it's in the form of an IP address then + * get the lib to interpret it */ + if (is_ipaddress_v4(str)) { + res = inet_addr(str); + } else { + /* otherwise assume it's a network name of some sort and use + sys_gethostbyname */ + if ((hp = sys_gethostbyname(str)) == 0) { + DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str)); + return 0; + } + + if(hp->h_addr == NULL) { + DEBUG(3,("sys_gethostbyname: host address is " + "invalid for host %s\n",str)); + return 0; + } + putip((char *)&res,(char *)hp->h_addr); + } + + if (res == (uint32)-1) + return(0); + + return(res); +} + +/******************************************************************* + A convenient addition to interpret_addr(). +******************************************************************/ + +struct in_addr *interpret_addr2(const char *str) +{ + static struct in_addr ret; + uint32 a = interpret_addr(str); + ret.s_addr = a; + return(&ret); +} + +/******************************************************************* + Map a text hostname or IP address (IPv4 or IPv6) into a + struct sockaddr_storage. +******************************************************************/ + +bool interpret_string_addr(struct sockaddr_storage *pss, const char *str) +{ + int ret; + struct addrinfo *res = NULL; + struct addrinfo hints; + + memset(pss,'\0', sizeof(*pss)); + + memset(&hints, '\0', sizeof(hints)); + /* By default make sure it supports TCP. */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + + ret = getaddrinfo(str, NULL, + &hints, + &res); + + if (ret) { + DEBUG(3,("interpret_string_addr: getaddrinfo failed for " + "name %s [%s]\n", + str, + gai_strerror(ret) )); + return false; + } + + /* Copy the first sockaddr. */ + memcpy(pss, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return true; +} + +/******************************************************************* + Check if an IPv7 is 127.0.0.1 +******************************************************************/ + +bool is_loopback_ip_v4(struct in_addr ip) +{ + struct in_addr a; + a.s_addr = htonl(INADDR_LOOPBACK); + return(ip.s_addr == a.s_addr); +} + +/******************************************************************* + Check if a struct sockaddr_storage is the loopback address. +******************************************************************/ + +bool is_loopback_addr(const struct sockaddr_storage *pss) +{ +#if defined(AF_INET6) + if (pss->ss_family == AF_INET) { + struct in6_addr *pin6 = &((struct sockaddr_in6 *)pss)->sin6_addr; + return IN6_IS_ADDR_LOOPBACK(pin6); + } +#endif + if (pss->ss_family == AF_INET) { + struct in_addr *pin = &((struct sockaddr_in *)pss)->sin_addr; + return is_loopback_ip_v4(*pin); + } + return false; +} + +/******************************************************************* + Check if an IPv4 is 0.0.0.0. +******************************************************************/ + +bool is_zero_ip_v4(struct in_addr ip) +{ + uint32 a; + putip((char *)&a,(char *)&ip); + return(a == 0); +} + +/******************************************************************* + Check if a struct sockaddr_storage has an unspecified address. +******************************************************************/ + +bool is_zero_addr(const struct sockaddr_storage *pss) +{ +#if defined(AF_INET6) + if (pss->ss_family == AF_INET) { + struct in6_addr *pin6 = &((struct sockaddr_in6 *)pss)->sin6_addr; + return IN6_IS_ADDR_UNSPECIFIED(pin6); + } +#endif + if (pss->ss_family == AF_INET) { + struct in_addr *pin = &((struct sockaddr_in *)pss)->sin_addr; + return is_zero_ip_v4(*pin); } + return false; +} + +/******************************************************************* + Set an IP to 0.0.0.0. +******************************************************************/ + +void zero_ip_v4(struct in_addr *ip) +{ + static bool init; + static struct in_addr ipzero; + + if (!init) { + ipzero = *interpret_addr2("0.0.0.0"); + init = true; + } + + *ip = ipzero; +} + +/******************************************************************* + Are two IPs on the same subnet - IPv4 version ? +********************************************************************/ + +bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) +{ + uint32 net1,net2,nmask; + + nmask = ntohl(mask.s_addr); + net1 = ntohl(ip1.s_addr); + net2 = ntohl(ip2.s_addr); + + return((net1 & nmask) == (net2 & nmask)); +} + +/******************************************************************* + Convert an IPv4 struct in_addr to a struct sockaddr_storage. +********************************************************************/ + +void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss, + struct in_addr ip) +{ + struct sockaddr_in *sa = (struct sockaddr_in *)ss; + memset(ss, '\0', sizeof(*ss)); + ss->ss_family = AF_INET; + sa->sin_addr = ip; +} + +#ifdef AF_INET6 +/******************************************************************* + Convert an IPv6 struct in_addr to a struct sockaddr_storage. +********************************************************************/ + +void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss, + struct in6_addr ip) +{ + struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss; + memset(ss, '\0', sizeof(*ss)); + ss->ss_family = AF_INET6; + sa->sin6_addr = ip; +} +#endif + +/******************************************************************* + Are two IPs on the same subnet? +********************************************************************/ + +bool same_net(const struct sockaddr_storage *ip1, + const struct sockaddr_storage *ip2, + const struct sockaddr_storage *mask) +{ + if (ip1->ss_family != ip2->ss_family) { + /* Never on the same net. */ + return false; + } + +#ifdef AF_INET6 + if (ip1->ss_family == AF_INET6) { + struct sockaddr_in6 ip1_6 = *(struct sockaddr_in6 *)ip1; + struct sockaddr_in6 ip2_6 = *(struct sockaddr_in6 *)ip2; + struct sockaddr_in6 mask_6 = *(struct sockaddr_in6 *)mask; + char *p1 = (char *)&ip1_6.sin6_addr; + char *p2 = (char *)&ip2_6.sin6_addr; + char *m = (char *)&mask_6.sin6_addr; + int i; + + for (i = 0; i < sizeof(struct in6_addr); i++) { + *p1++ &= *m; + *p2++ &= *m; + m++; + } + return (memcmp(&ip1_6.sin6_addr, + &ip2_6.sin6_addr, + sizeof(struct in6_addr)) == 0); + } +#endif + if (ip1->ss_family == AF_INET) { + return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr, + ((const struct sockaddr_in *)ip2)->sin_addr, + ((const struct sockaddr_in *)mask)->sin_addr); + } + return false; +} + +/******************************************************************* + Are two sockaddr_storage's the same family and address ? Ignore port etc. +********************************************************************/ + +bool addr_equal(const struct sockaddr_storage *ip1, + const struct sockaddr_storage *ip2) +{ + if (ip1->ss_family != ip2->ss_family) { + /* Never the same. */ + return false; + } + +#ifdef AF_INET6 + if (ip1->ss_family == AF_INET6) { + return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr, + &((const struct sockaddr_in6 *)ip2)->sin6_addr, + sizeof(struct in6_addr)) == 0); + } +#endif + if (ip1->ss_family == AF_INET) { + return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr, + &((const struct sockaddr_in *)ip2)->sin_addr, + sizeof(struct in_addr)) == 0); + } + return false; +} + + +/**************************************************************************** + Is an IP address the INADDR_ANY or in6addr_any value ? +****************************************************************************/ + +bool is_address_any(const struct sockaddr_storage *psa) +{ #ifdef AF_INET6 if (psa->ss_family == AF_INET6) { - inet_ntop(AF_INET6, - &((struct sockaddr_in6 *)psa)->sin6_addr, - dest, - destlen); + struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)psa; + if (memcmp(&in6addr_any, + &si6->sin6_addr, + sizeof(in6addr_any)) == 0) { + return true; + } + return false; } #endif if (psa->ss_family == AF_INET) { - inet_ntop(AF_INET, - &((struct sockaddr_in *)psa)->sin_addr, - dest, - destlen); + struct sockaddr_in *si = (struct sockaddr_in *)psa; + if (si->sin_addr.s_addr == INADDR_ANY) { + return true; + } + return false; } + return false; +} + +/**************************************************************************** + Print out an IPv4 or IPv6 address from a struct sockaddr_storage. +****************************************************************************/ + +char *print_sockaddr(char *dest, + size_t destlen, + const struct sockaddr_storage *psa, + socklen_t psalen) +{ + if (destlen > 0) { + dest[0] = '\0'; + } + (void)getnameinfo((const struct sockaddr *)psa, + psalen, + dest, destlen, + NULL, 0, + NI_NUMERICHOST); return dest; } +/**************************************************************************** + Set the global client_fd variable. +****************************************************************************/ + void client_setfd(int fd) { client_fd = fd; @@ -64,6 +384,10 @@ void client_setfd(int fd) sizeof(client_ip_string)-1); } +/**************************************************************************** + Return a static string of an IP address (IPv4 or IPv6). +****************************************************************************/ + static char *get_socket_addr(int fd) { struct sockaddr_storage sa; @@ -87,9 +411,13 @@ static char *get_socket_addr(int fd) return addr_buf; } - return print_sockaddr(addr_buf, sizeof(addr_buf), &sa); + return print_sockaddr(addr_buf, sizeof(addr_buf), &sa, length); } +/**************************************************************************** + Return the port number we've bound to on a socket. +****************************************************************************/ + static int get_socket_port(int fd) { struct sockaddr_storage sa; @@ -118,7 +446,7 @@ static int get_socket_port(int fd) char *client_name(void) { - return get_peer_name(client_fd,False); + return get_peer_name(client_fd,false); } char *client_addr(void) @@ -142,7 +470,7 @@ int smb_read_error = 0; Determine if a file descriptor is in fact a socket. ****************************************************************************/ -BOOL is_a_socket(int fd) +bool is_a_socket(int fd) { int v; socklen_t l; @@ -247,12 +575,12 @@ void set_socket_options(int fd, const char *options) int ret=0,i; int value = 1; char *p; - BOOL got_value = False; + bool got_value = false; if ((p = strchr_m(tok,'='))) { *p = 0; value = atoi(p+1); - got_value = True; + got_value = true; } for (i=0;socket_options[i].name;i++) @@ -559,7 +887,7 @@ ssize_t write_data(int fd, const char *buffer, size_t N) Send a keepalive packet (rfc1002). ****************************************************************************/ -BOOL send_keepalive(int client) +bool send_keepalive(int client) { unsigned char buf[4]; @@ -583,7 +911,7 @@ static ssize_t read_smb_length_return_keepalive(int fd, { ssize_t len=0; int msg_type; - BOOL ok = False; + bool ok = false; while (!ok) { if (timeout > 0) { @@ -809,23 +1137,23 @@ static ssize_t receive_smb_raw_talloc(TALLOC_CTX *mem_ctx, int fd, Checks the MAC on signed packets. ****************************************************************************/ -BOOL receive_smb(int fd, char *buffer, unsigned int timeout) +bool receive_smb(int fd, char *buffer, unsigned int timeout) { if (receive_smb_raw(fd, buffer, timeout, 0) < 0) { - return False; + return false; } /* Check the incoming SMB signature. */ - if (!srv_check_sign_mac(buffer, True)) { + if (!srv_check_sign_mac(buffer, true)) { DEBUG(0, ("receive_smb: SMB Signature verification " "failed on incoming packet!\n")); if (smb_read_error == 0) { smb_read_error = READ_BAD_SIG; } - return False; + return false; } - return True; + return true; } ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer, @@ -840,7 +1168,7 @@ ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer, } /* Check the incoming SMB signature. */ - if (!srv_check_sign_mac(*buffer, True)) { + if (!srv_check_sign_mac(*buffer, true)) { DEBUG(0, ("receive_smb: SMB Signature verification failed on " "incoming packet!\n")); if (smb_read_error == 0) { @@ -856,7 +1184,7 @@ ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx, int fd, char **buffer, Send an smb to a fd. ****************************************************************************/ -BOOL send_smb(int fd, char *buffer) +bool send_smb(int fd, char *buffer) { size_t len; size_t nwritten=0; @@ -872,12 +1200,12 @@ BOOL send_smb(int fd, char *buffer) if (ret <= 0) { DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n", (int)len,(int)ret, strerror(errno) )); - return False; + return false; } nwritten += ret; } - return True; + return true; } /**************************************************************************** @@ -888,7 +1216,7 @@ int open_socket_in(int type, int port, int dlevel, uint32 socket_addr, - BOOL rebind ) + bool rebind ) { struct sockaddr_in sock; int res; @@ -919,7 +1247,7 @@ int open_socket_in(int type, if( DEBUGLVL( dlevel ) ) { dbgtext( "open_socket_in(): setsockopt: " ); dbgtext( "SO_REUSEADDR = %s ", - val?"True":"False" ); + val?"true":"false" ); dbgtext( "on port %d failed ", port ); dbgtext( "with error = %s\n", strerror(errno) ); } @@ -930,7 +1258,7 @@ int open_socket_in(int type, if( DEBUGLVL( dlevel ) ) { dbgtext( "open_socket_in(): setsockopt: "); dbgtext( "SO_REUSEPORT = %s ", - val?"True":"False" ); + val?"true":"false" ); dbgtext( "on port %d failed ", port ); dbgtext( "with error = %s\n", strerror(errno) ); } @@ -984,7 +1312,7 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout) sock_out.sin_family = PF_INET; /* set it non-blocking */ - set_blocking(res,False); + set_blocking(res,false); DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port)); @@ -1029,7 +1357,7 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout) } /* set it blocking again */ - set_blocking(res,True); + set_blocking(res,true); return res; } @@ -1040,12 +1368,12 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout) of DC's all of which are equivalent for our purposes. **************************************************************************/ -BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs, +bool open_any_socket_out(struct sockaddr_in *addrs, int num_addrs, int timeout, int *fd_index, int *fd) { int i, resulting_index, res; int *sockets; - BOOL good_connect; + bool good_connect; fd_set r_fds, wr_fds; struct timeval tv; @@ -1058,7 +1386,7 @@ BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs, sockets = SMB_MALLOC_ARRAY(int, num_addrs); if (sockets == NULL) - return False; + return false; resulting_index = -1; @@ -1069,11 +1397,11 @@ BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs, sockets[i] = socket(PF_INET, SOCK_STREAM, 0); if (sockets[i] < 0) goto done; - set_blocking(sockets[i], False); + set_blocking(sockets[i], false); } connect_again: - good_connect = False; + good_connect = false; for (i=0; i<num_addrs; i++) { @@ -1095,7 +1423,7 @@ BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs, errno == EAGAIN || errno == EINTR) { /* These are the error messages that something is progressing. */ - good_connect = True; + good_connect = true; } else if (errno != 0) { /* There was a direct error */ close(sockets[i]); @@ -1180,7 +1508,7 @@ BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs, if (resulting_index >= 0) { *fd_index = resulting_index; *fd = sockets[*fd_index]; - set_blocking(*fd, True); + set_blocking(*fd, true); } free(sockets); @@ -1223,7 +1551,7 @@ int open_udp_socket(const char *host, int port) confirm a hostname lookup to prevent spoof attacks. ******************************************************************/ -static BOOL matchname(char *remotehost,struct in_addr addr) +static bool matchname(char *remotehost,struct in_addr addr) { struct hostent *hp; int i; @@ -1231,7 +1559,7 @@ static BOOL matchname(char *remotehost,struct in_addr addr) if ((hp = sys_gethostbyname(remotehost)) == 0) { DEBUG(0,("sys_gethostbyname(%s): lookup failure.\n", remotehost)); - return False; + return false; } /* @@ -1246,13 +1574,13 @@ static BOOL matchname(char *remotehost,struct in_addr addr) && !strequal(remotehost, "localhost")) { DEBUG(0,("host name/name mismatch: %s != %s\n", remotehost, hp->h_name)); - return False; + return false; } /* Look up the host address in the address list we just got. */ for (i = 0; hp->h_addr_list[i]; i++) { if (memcmp(hp->h_addr_list[i], (char *)&addr,sizeof(addr)) == 0) - return True; + return true; } /* @@ -1263,14 +1591,14 @@ static BOOL matchname(char *remotehost,struct in_addr addr) DEBUG(0,("host name/address mismatch: %s != %s\n", inet_ntoa(addr), hp->h_name)); - return False; + return false; } /******************************************************************* Return the DNS name of the remote end of a socket. ******************************************************************/ -char *get_peer_name(int fd, BOOL force_lookup) +char *get_peer_name(int fd, bool force_lookup) { static pstring name_buf; pstring tmp_name; @@ -1283,7 +1611,7 @@ char *get_peer_name(int fd, BOOL force_lookup) situations won't work because many networks don't link dhcp with dns. To avoid the delay we avoid the lookup if possible */ - if (!lp_hostname_lookups() && (force_lookup == False)) { + if (!lp_hostname_lookups() && (force_lookup == false)) { return get_peer_addr(fd); } @@ -1450,3 +1778,92 @@ out_umask: return -1; #endif /* HAVE_UNIXSOCKET */ } + +/************************************************************ + Is this my name ? Needs fixing for IPv6. +************************************************************/ + +bool is_myname_or_ipaddr(const char *s) +{ + fstring name, dnsname; + char *servername; + + if ( !s ) + return false; + + /* santize the string from '\\name' */ + + fstrcpy( name, s ); + + servername = strrchr_m( name, '\\' ); + if ( !servername ) + servername = name; + else + servername++; + + /* optimize for the common case */ + + if (strequal(servername, global_myname())) + return true; + + /* check for an alias */ + + if (is_myname(servername)) + return true; + + /* check for loopback */ + + if (strequal(servername, "127.0.0.1")) + return true; + + if (strequal(servername, "localhost")) + return true; + + /* maybe it's my dns name */ + + if ( get_mydnsfullname( dnsname ) ) + if ( strequal( servername, dnsname ) ) + return true; + + /* handle possible CNAME records */ + + if ( !is_ipaddress_v4( servername ) ) { + /* use DNS to resolve the name, but only the first address */ + struct hostent *hp; + + if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { + struct in_addr return_ip; + putip( (char*)&return_ip, (char*)hp->h_addr ); + fstrcpy( name, inet_ntoa( return_ip ) ); + servername = name; + } + } + + /* maybe its an IP address? */ + if (is_ipaddress_v4(servername)) { + struct sockaddr_storage ss; + struct iface_struct nics[MAX_INTERFACES]; + int i, n; + struct in_addr ip; + + ip = *interpret_addr2(servername); + if (is_zero_ip_v4(ip) || is_loopback_ip_v4(ip)) { + return false; + } + + in_addr_to_sockaddr_storage(&ss, ip); + + n = get_interfaces(nics, MAX_INTERFACES); + for (i=0; i<n; i++) { + if (nics[i].ip.ss_family != AF_INET) { + continue; + } + if (addr_equal(&nics[i].ip, &ss)) { + return true; + } + } + } + + /* no match */ + return false; +} diff --git a/source3/lib/wins_srv.c b/source3/lib/wins_srv.c index 4faa65c18d..6344568122 100644 --- a/source3/lib/wins_srv.c +++ b/source3/lib/wins_srv.c @@ -21,8 +21,6 @@ #include "includes.h" -extern struct in_addr loopback_ip; - /* This is pretty much a complete rewrite of the earlier code. The main aim of the rewrite is to add support for having multiple wins server @@ -134,7 +132,7 @@ void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip) { char *keystr; - if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip)) + if (is_zero_ip_v4(wins_ip) || wins_srv_is_dead(wins_ip, src_ip)) return; keystr = wins_srv_keystr(wins_ip, src_ip); @@ -284,13 +282,15 @@ struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip) /* if we are a wins server then we always just talk to ourselves */ if (lp_wins_support()) { + struct in_addr loopback_ip; + loopback_ip.s_addr = htonl(INADDR_LOOPBACK); return loopback_ip; } list = lp_wins_server_list(); if (!list || !list[0]) { struct in_addr ip; - zero_ip(&ip); + zero_ip_v4(&ip); return ip; } @@ -322,7 +322,7 @@ struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip) } /* this can't happen?? */ - zero_ip(&t_ip.ip); + zero_ip_v4(&t_ip.ip); return t_ip.ip; } |