From 8e54530b52fd256137740107e9fdf000f00a7a30 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 10 Oct 2007 18:25:16 -0700 Subject: 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) --- source3/lib/interface.c | 644 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 459 insertions(+), 185 deletions(-) (limited to 'source3/lib/interface.c') 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 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;iname); 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;iname); 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; } -- cgit