diff options
Diffstat (limited to 'source4/lib/socket')
-rw-r--r-- | source4/lib/socket/access.c | 8 | ||||
-rw-r--r-- | source4/lib/socket/connect_multi.c | 4 | ||||
-rw-r--r-- | source4/lib/socket/interface.c | 389 | ||||
-rw-r--r-- | source4/lib/socket/netif.c | 127 | ||||
-rw-r--r-- | source4/lib/socket/netif.h | 14 | ||||
-rw-r--r-- | source4/lib/socket/socket.c | 169 | ||||
-rw-r--r-- | source4/lib/socket/socket.h | 10 | ||||
-rw-r--r-- | source4/lib/socket/socket_ip.c | 86 | ||||
-rw-r--r-- | source4/lib/socket/socket_unix.c | 16 | ||||
-rw-r--r-- | source4/lib/socket/testsuite.c | 14 | ||||
-rw-r--r-- | source4/lib/socket/wscript_build | 10 |
11 files changed, 441 insertions, 406 deletions
diff --git a/source4/lib/socket/access.c b/source4/lib/socket/access.c index ab39d63ef5..589797763f 100644 --- a/source4/lib/socket/access.c +++ b/source4/lib/socket/access.c @@ -249,9 +249,9 @@ static bool allow_access_internal(TALLOC_CTX *mem_ctx, } /* return true if access should be allowed */ -bool allow_access(TALLOC_CTX *mem_ctx, - const char **deny_list, const char **allow_list, - const char *cname, const char *caddr) +bool socket_allow_access(TALLOC_CTX *mem_ctx, + const char **deny_list, const char **allow_list, + const char *cname, const char *caddr) { bool ret; char *nc_cname = talloc_strdup(mem_ctx, cname); @@ -346,7 +346,7 @@ bool socket_check_access(struct socket_context *sock, return false; } - ret = allow_access(mem_ctx, deny_list, allow_list, name, addr->addr); + ret = socket_allow_access(mem_ctx, deny_list, allow_list, name, addr->addr); if (ret) { DEBUG(2,("socket_check_access: Allowed connection to '%s' from %s (%s)\n", diff --git a/source4/lib/socket/connect_multi.c b/source4/lib/socket/connect_multi.c index 300e5fb1e5..4ce5115e97 100644 --- a/source4/lib/socket/connect_multi.c +++ b/source4/lib/socket/connect_multi.c @@ -136,7 +136,7 @@ static void connect_multi_next_socket(struct composite_context *result) if (composite_nomem(state, result)) return; state->result = result; - result->status = socket_create("ipv4", SOCKET_TYPE_STREAM, &state->sock, 0); + result->status = socket_create(multi->server_address->family, SOCKET_TYPE_STREAM, &state->sock, 0); if (!composite_is_ok(result)) return; state->addr = socket_address_copy(state, multi->server_address); @@ -162,7 +162,7 @@ static void connect_multi_next_socket(struct composite_context *result) connect attempt state, so it will go away when this request completes */ event_add_timed(result->event_ctx, state, - timeval_current_ofs(0, MULTI_PORT_DELAY), + timeval_current_ofs_usec(MULTI_PORT_DELAY), connect_multi_timer, result); } } diff --git a/source4/lib/socket/interface.c b/source4/lib/socket/interface.c index c4411b623c..d5b610fea7 100644 --- a/source4/lib/socket/interface.c +++ b/source4/lib/socket/interface.c @@ -21,15 +21,19 @@ #include "includes.h" #include "system/network.h" +#include "param/param.h" #include "lib/socket/netif.h" #include "../lib/util/util_net.h" #include "../lib/util/dlinklist.h" -/** used for network interfaces */ +/* used for network interfaces */ struct interface { struct interface *next, *prev; - struct in_addr ip; - struct in_addr nmask; + char *name; + int flags; + struct sockaddr_storage ip; + struct sockaddr_storage netmask; + struct sockaddr_storage bcast; const char *ip_s; const char *bcast_s; const char *nmask_s; @@ -45,31 +49,51 @@ struct interface { /**************************************************************************** Try and find an interface that matches an ip. If we cannot, return NULL **************************************************************************/ -static struct interface *iface_find(struct interface *interfaces, - struct in_addr ip, bool CheckMask) +static struct interface *iface_list_find(struct interface *interfaces, + const struct sockaddr *ip, + bool check_mask) { struct interface *i; - if (is_zero_ip_v4(ip)) return interfaces; - for (i=interfaces;i;i=i->next) - if (CheckMask) { - if (same_net_v4(i->ip,ip,i->nmask)) return i; - } else if (i->ip.s_addr == ip.s_addr) return i; + if (is_address_any(ip)) { + return interfaces; + } + + for (i=interfaces;i;i=i->next) { + if (check_mask) { + if (same_net(ip, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) { + return i; + } + } else if (sockaddr_equal((struct sockaddr *)&i->ip, ip)) { + return i; + } + } return NULL; } - /**************************************************************************** add an interface to the linked list of interfaces ****************************************************************************/ -static void add_interface(TALLOC_CTX *mem_ctx, struct in_addr ip, struct in_addr nmask, struct interface **interfaces) +static void add_interface(TALLOC_CTX *mem_ctx, const struct iface_struct *ifs, struct interface **interfaces, + bool enable_ipv6) { + char addr[INET6_ADDRSTRLEN]; struct interface *iface; - struct in_addr bcast; - if (iface_find(*interfaces, ip, false)) { - DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip))); + if (iface_list_find(*interfaces, (const struct sockaddr *)&ifs->ip, false)) { + DEBUG(3,("add_interface: not adding duplicate interface %s\n", + print_sockaddr(addr, sizeof(addr), &ifs->ip) )); + return; + } + + if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) { + DEBUG(3,("not adding non-broadcast interface %s\n", + ifs->name )); + return; + } + + if (!enable_ipv6 && ifs->ip.ss_family != AF_INET) { return; } @@ -79,26 +103,40 @@ static void add_interface(TALLOC_CTX *mem_ctx, struct in_addr ip, struct in_addr ZERO_STRUCTPN(iface); - iface->ip = ip; - iface->nmask = nmask; - bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr); + iface->name = talloc_strdup(iface, 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; /* keep string versions too, to avoid people tripping over the implied static in inet_ntoa() */ - iface->ip_s = talloc_strdup(iface, inet_ntoa(iface->ip)); - iface->nmask_s = talloc_strdup(iface, inet_ntoa(iface->nmask)); - - if (nmask.s_addr != ~0) { - iface->bcast_s = talloc_strdup(iface, inet_ntoa(bcast)); - } - - DLIST_ADD_END(*interfaces, iface, struct interface *); - - DEBUG(3,("added interface ip=%s nmask=%s\n", iface->ip_s, iface->nmask_s)); + print_sockaddr(addr, sizeof(addr), &iface->ip); + DEBUG(4,("added interface %s ip=%s ", + iface->name, addr)); + iface->ip_s = talloc_strdup(iface, addr); + + print_sockaddr(addr, sizeof(addr), + &iface->bcast); + DEBUG(4,("bcast=%s ", addr)); + iface->bcast_s = talloc_strdup(iface, addr); + + print_sockaddr(addr, sizeof(addr), + &iface->netmask); + DEBUG(4,("netmask=%s\n", addr)); + iface->nmask_s = talloc_strdup(iface, addr); + + /* + this needs to be a ADD_END, as some tests (such as the + spoolss notify test) depend on the interfaces ordering + */ + DLIST_ADD_END(*interfaces, iface, NULL); } - - /** interpret a single element from a interfaces= config line @@ -114,99 +152,155 @@ static void interpret_interface(TALLOC_CTX *mem_ctx, const char *token, struct iface_struct *probed_ifaces, int total_probed, - struct interface **local_interfaces) + struct interface **local_interfaces, + bool enable_ipv6) { - 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; - char *address; - int i, added=0; + int i; + bool added=false; + bool goodaddr = false; - ip.s_addr = 0; - nmask.s_addr = 0; - /* 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(mem_ctx, probed_ifaces[i].ip, - probed_ifaces[i].netmask, - local_interfaces); - added = 1; + add_interface(mem_ctx, &probed_ifaces[i], + local_interfaces, enable_ipv6); + added = true; } } - if (added) return; + if (added) { + return; + } /* maybe it is a DNS name */ p = strchr_m(token,'/'); - if (!p) { - /* don't try to do dns lookups on wildcard names */ - if (strpbrk(token, "*?") != NULL) { + if (p == NULL) { + if (!interpret_string_addr(&ss, token, 0)) { + DEBUG(2, ("interpret_interface: Can't find address " + "for %s\n", token)); return; } - ip.s_addr = interpret_addr2(token).s_addr; + for (i=0;i<total_probed;i++) { - if (ip.s_addr == probed_ifaces[i].ip.s_addr) { - add_interface(mem_ctx, probed_ifaces[i].ip, - probed_ifaces[i].netmask, - local_interfaces); + if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip)) { + add_interface(mem_ctx, &probed_ifaces[i], + local_interfaces, enable_ipv6); return; } } - DEBUG(2,("can't determine netmask for %s\n", token)); + DEBUG(2,("interpret_interface: " + "can't determine interface for %s\n", + token)); return; } - address = talloc_strdup(mem_ctx, token); - p = strchr_m(address,'/'); - /* parse it into an IP address/netmasklength pair */ - *p++ = 0; - - ip.s_addr = interpret_addr2(address).s_addr; + *p = 0; + goodaddr = interpret_string_addr(&ss, token, 0); + *p++ = '/'; + + if (!goodaddr) { + DEBUG(2,("interpret_interface: " + "can't determine interface for %s\n", + token)); + return; + } if (strlen(p) > 2) { - nmask.s_addr = interpret_addr2(p).s_addr; + goodaddr = interpret_string_addr(&ss_mask, p, 0); + 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 (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) || + sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) { for (i=0;i<total_probed;i++) { - if (same_net_v4(ip, probed_ifaces[i].ip, nmask)) { - add_interface(mem_ctx, probed_ifaces[i].ip, nmask, - local_interfaces); - talloc_free(address); + if (same_net((struct sockaddr *)&ss, + (struct sockaddr *)&probed_ifaces[i].ip, + (struct sockaddr *)&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(mem_ctx, &probed_ifaces[i], + local_interfaces, enable_ipv6); + probed_ifaces[i].netmask = saved_mask; return; } } - DEBUG(2,("Can't determine ip for broadcast address %s\n", address)); - talloc_free(address); + DEBUG(2,("interpret_interface: Can't determine ip for " + "broadcast address %s\n", + token)); return; } - add_interface(mem_ctx, ip, nmask, local_interfaces); - talloc_free(address); + /* Just fake up the interface definition. User knows best. */ + + DEBUG(2,("interpret_interface: Adding interface %s\n", + token)); + + ZERO_STRUCT(ifs); + (void)strlcpy(ifs.name, token, sizeof(ifs.name)); + ifs.flags = IFF_BROADCAST; + ifs.ip = ss; + ifs.netmask = ss_mask; + ifs.bcast = ss_bcast; + add_interface(mem_ctx, &ifs, + local_interfaces, enable_ipv6); } /** load the list of network interfaces **/ -void load_interfaces(TALLOC_CTX *mem_ctx, const char **interfaces, struct interface **local_interfaces) +void load_interface_list(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct interface **local_interfaces) { - const char **ptr = interfaces; + const char **ptr = lpcfg_interfaces(lp_ctx); int i; - struct iface_struct ifaces[MAX_INTERFACES]; - struct in_addr loopback_ip; + struct iface_struct *ifaces; int total_probed; + bool enable_ipv6 = lpcfg_parm_bool(lp_ctx, NULL, "ipv6", "enable", true); *local_interfaces = NULL; - loopback_ip = interpret_addr2("127.0.0.1"); - /* probe the kernel for interfaces */ - total_probed = get_interfaces(ifaces, MAX_INTERFACES); + total_probed = get_interfaces(mem_ctx, &ifaces); /* if we don't have a interfaces line then use all interfaces except loopback */ @@ -215,27 +309,27 @@ void load_interfaces(TALLOC_CTX *mem_ctx, const char **interfaces, struct interf DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n")); } for (i=0;i<total_probed;i++) { - if (ifaces[i].ip.s_addr != loopback_ip.s_addr) { - add_interface(mem_ctx, ifaces[i].ip, - ifaces[i].netmask, local_interfaces); + if (!is_loopback_addr((struct sockaddr *)&ifaces[i].ip)) { + add_interface(mem_ctx, &ifaces[i], local_interfaces, enable_ipv6); } } } while (ptr && *ptr) { - interpret_interface(mem_ctx, *ptr, ifaces, total_probed, local_interfaces); + interpret_interface(mem_ctx, *ptr, ifaces, total_probed, local_interfaces, enable_ipv6); ptr++; } if (!*local_interfaces) { DEBUG(0,("WARNING: no network interfaces found\n")); } + talloc_free(ifaces); } /** how many interfaces do we have **/ -int iface_count(struct interface *ifaces) +int iface_list_count(struct interface *ifaces) { int ret = 0; struct interface *i; @@ -248,7 +342,7 @@ int iface_count(struct interface *ifaces) /** return IP of the Nth interface **/ -const char *iface_n_ip(struct interface *ifaces, int n) +const char *iface_list_n_ip(struct interface *ifaces, int n) { struct interface *i; @@ -261,10 +355,59 @@ const char *iface_n_ip(struct interface *ifaces, int n) return NULL; } + +/** + return the first IPv4 interface address we have registered + **/ +const char *iface_list_first_v4(struct interface *ifaces) +{ + struct interface *i; + + for (i=ifaces; i; i=i->next) { + if (i->ip.ss_family == AF_INET) { + return i->ip_s; + } + } + return NULL; +} + +/** + return the first IPv6 interface address we have registered + **/ +static const char *iface_list_first_v6(struct interface *ifaces) +{ + struct interface *i; + +#ifdef HAVE_IPV6 + for (i=ifaces; i; i=i->next) { + if (i->ip.ss_family == AF_INET6) { + return i->ip_s; + } + } +#endif + return NULL; +} + +/** + check if an interface is IPv4 + **/ +bool iface_list_n_is_v4(struct interface *ifaces, int n) +{ + struct interface *i; + + for (i=ifaces;i && n;i=i->next) + n--; + + if (i) { + return i->ip.ss_family == AF_INET; + } + return false; +} + /** return bcast of the Nth interface **/ -const char *iface_n_bcast(struct interface *ifaces, int n) +const char *iface_list_n_bcast(struct interface *ifaces, int n) { struct interface *i; @@ -280,7 +423,7 @@ const char *iface_n_bcast(struct interface *ifaces, int n) /** return netmask of the Nth interface **/ -const char *iface_n_netmask(struct interface *ifaces, int n) +const char *iface_list_n_netmask(struct interface *ifaces, int n) { struct interface *i; @@ -297,28 +440,37 @@ const char *iface_n_netmask(struct interface *ifaces, int n) return the local IP address that best matches a destination IP, or our first interface if none match */ -const char *iface_best_ip(struct interface *ifaces, const char *dest) +const char *iface_list_best_ip(struct interface *ifaces, const char *dest) { struct interface *iface; - struct in_addr ip; + struct sockaddr_storage ss; - ip.s_addr = interpret_addr(dest); - iface = iface_find(ifaces, ip, true); + if (!interpret_string_addr(&ss, dest, AI_NUMERICHOST)) { + return iface_list_n_ip(ifaces, 0); + } + iface = iface_list_find(ifaces, (const struct sockaddr *)&ss, true); if (iface) { return iface->ip_s; } - return iface_n_ip(ifaces, 0); +#ifdef HAVE_IPV6 + if (ss.ss_family == AF_INET6) { + return iface_list_first_v6(ifaces); + } +#endif + return iface_list_first_v4(ifaces); } /** return true if an IP is one one of our local networks */ -bool iface_is_local(struct interface *ifaces, const char *dest) +bool iface_list_is_local(struct interface *ifaces, const char *dest) { - struct in_addr ip; + struct sockaddr_storage ss; - ip.s_addr = interpret_addr(dest); - if (iface_find(ifaces, ip, true)) { + if (!interpret_string_addr(&ss, dest, AI_NUMERICHOST)) { + return false; + } + if (iface_list_find(ifaces, (const struct sockaddr *)&ss, true)) { return true; } return false; @@ -327,9 +479,50 @@ bool iface_is_local(struct interface *ifaces, const char *dest) /** return true if a IP matches a IP/netmask pair */ -bool iface_same_net(const char *ip1, const char *ip2, const char *netmask) +bool iface_list_same_net(const char *ip1, const char *ip2, const char *netmask) { - return same_net_v4(interpret_addr2(ip1), - interpret_addr2(ip2), - interpret_addr2(netmask)); + struct sockaddr_storage ip1_ss, ip2_ss, nm_ss; + + if (!interpret_string_addr(&ip1_ss, ip1, AI_NUMERICHOST)) { + return false; + } + if (!interpret_string_addr(&ip2_ss, ip2, AI_NUMERICHOST)) { + return false; + } + if (!interpret_string_addr(&nm_ss, netmask, AI_NUMERICHOST)) { + return false; + } + + return same_net((struct sockaddr *)&ip1_ss, + (struct sockaddr *)&ip2_ss, + (struct sockaddr *)&nm_ss); +} + +/** + return the list of wildcard interfaces + this will include the IPv4 0.0.0.0, and may include IPv6 :: + it is overridden by the 'socket address' option in smb.conf +*/ +const char **iface_list_wildcard(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx) +{ + const char **ret; + const char *socket_address; + + /* the user may have configured a specific address */ + socket_address = lpcfg_socket_address(lp_ctx); + if (strcmp(socket_address, "") != 0) { + ret = (const char **)str_list_make(mem_ctx, socket_address, NULL); + return ret; + } + + ret = (const char **)str_list_make(mem_ctx, "0.0.0.0", NULL); + if (ret == NULL) return NULL; + +#ifdef HAVE_IPV6 + if (lpcfg_parm_bool(lp_ctx, NULL, "ipv6", "enable", true)) { + return str_list_add(ret, "::"); + } +#endif + + return ret; } diff --git a/source4/lib/socket/netif.c b/source4/lib/socket/netif.c deleted file mode 100644 index e36f268bde..0000000000 --- a/source4/lib/socket/netif.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - Unix SMB/CIFS implementation. - return a list of network interfaces - Copyright (C) Andrew Tridgell 1998 - Copyright (C) Jeremy Allison 2007 - Copyright (C) Jelmer Vernooij 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 - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - - -/* working out the interfaces for a OS is an incredibly non-portable - thing. We have several possible implementations below, and autoconf - tries each of them to see what works - - Note that this file does _not_ include includes.h. That is so this code - can be called directly from the autoconf tests. That also means - this code cannot use any of the normal Samba debug stuff or defines. - This is standalone code. - -*/ - -#include "includes.h" -#include "system/network.h" -#include "netif.h" -#include "lib/util/tsort.h" - -/**************************************************************************** - Try the "standard" getifaddrs/freeifaddrs interfaces. - Also gets IPv6 interfaces. -****************************************************************************/ - -/**************************************************************************** - Get the netmask address for a local interface. -****************************************************************************/ - -static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ - struct ifaddrs *iflist = NULL; - struct ifaddrs *ifptr = NULL; - int total = 0; - - if (getifaddrs(&iflist) < 0) { - return -1; - } - - /* Loop through interfaces, looking for given IP address */ - for (ifptr = iflist, total = 0; - ifptr != NULL && total < max_interfaces; - ifptr = ifptr->ifa_next) { - - memset(&ifaces[total], '\0', sizeof(ifaces[total])); - - if (!ifptr->ifa_addr || !ifptr->ifa_netmask) { - continue; - } - - /* Check the interface is up. */ - if (!(ifptr->ifa_flags & IFF_UP)) { - continue; - } - - /* We don't support IPv6 *yet* */ - if (ifptr->ifa_addr->sa_family != AF_INET) { - continue; - } - - ifaces[total].ip = ((struct sockaddr_in *)ifptr->ifa_addr)->sin_addr; - ifaces[total].netmask = ((struct sockaddr_in *)ifptr->ifa_netmask)->sin_addr; - - strlcpy(ifaces[total].name, ifptr->ifa_name, - sizeof(ifaces[total].name)); - total++; - } - - freeifaddrs(iflist); - - return total; -} - -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 = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr); - if (r) return r; - r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr); - return r; -} - -/* this wrapper is used to remove duplicates from the interface list generated - above */ -int get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ - int total, i, j; - - total = _get_interfaces(ifaces, max_interfaces); - if (total <= 0) return total; - - /* now we need to remove duplicates */ - TYPESAFE_QSORT(ifaces, total, iface_comp); - - for (i=1;i<total;) { - if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) { - for (j=i-1;j<total-1;j++) { - ifaces[j] = ifaces[j+1]; - } - total--; - } else { - i++; - } - } - - return total; -} diff --git a/source4/lib/socket/netif.h b/source4/lib/socket/netif.h index 417c6e074f..1d90a4fd13 100644 --- a/source4/lib/socket/netif.h +++ b/source4/lib/socket/netif.h @@ -20,17 +20,5 @@ */ #include "system/network.h" - -struct iface_struct { - char name[16]; - struct in_addr ip; - struct in_addr netmask; -}; - -struct interface; - -#define MAX_INTERFACES 128 - -#ifndef AUTOCONF_TEST +#include "lib/socket/interfaces.h" #include "lib/socket/netif_proto.h" -#endif diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c index 4b5cecab34..2dbdaad11d 100644 --- a/source4/lib/socket/socket.c +++ b/source4/lib/socket/socket.c @@ -451,7 +451,7 @@ _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock) } fd = dup(sock->fd); if (fd == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } close(sock->fd); sock->fd = fd; @@ -473,6 +473,11 @@ _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx, return NULL; } + if (strcmp(family, "ip") == 0 && is_ipaddress_v6(host)) { + /* leaving as "ip" would force IPv4 */ + family = "ipv6"; + } + addr->family = family; addr->addr = talloc_strdup(addr, host); if (!addr->addr) { @@ -498,7 +503,19 @@ _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx if (!addr) { return NULL; } - addr->family = NULL; + switch (sockaddr->sa_family) { + case AF_INET: + addr->family = "ipv4"; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + addr->family = "ipv6"; + break; +#endif + case AF_UNIX: + addr->family = "unix"; + break; + } addr->addr = NULL; addr->port = 0; addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen); @@ -510,6 +527,50 @@ _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx return addr; } + +/* + Create a new socket_address from sockaddr_storage + */ +_PUBLIC_ struct socket_address *socket_address_from_sockaddr_storage(TALLOC_CTX *mem_ctx, + const struct sockaddr_storage *sockaddr, + uint16_t port) +{ + struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address); + char addr_str[INET6_ADDRSTRLEN+1]; + const char *str; + + if (!addr) { + return NULL; + } + addr->port = port; + switch (sockaddr->ss_family) { + case AF_INET: + addr->family = "ipv4"; + break; +#ifdef HAVE_IPV6 + case AF_INET6: + addr->family = "ipv6"; + break; +#endif + default: + talloc_free(addr); + return NULL; + } + + str = print_sockaddr(addr_str, sizeof(addr_str), sockaddr); + if (str == NULL) { + talloc_free(addr); + return NULL; + } + addr->addr = talloc_strdup(addr, str); + if (addr->addr == NULL) { + talloc_free(addr); + return NULL; + } + + return addr; +} + /* Copy a socket_address structure */ struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx, const struct socket_address *oaddr) @@ -567,110 +628,6 @@ _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum return NULL; } -enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON}; - -static const struct { - const char *name; - int level; - int option; - int value; - int opttype; -} socket_options[] = { - {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL}, - {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL}, - {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL}, -#ifdef TCP_NODELAY - {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL}, -#endif -#ifdef IPTOS_LOWDELAY - {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON}, -#endif -#ifdef IPTOS_THROUGHPUT - {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON}, -#endif -#ifdef SO_REUSEPORT - {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL}, -#endif -#ifdef SO_SNDBUF - {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT}, -#endif -#ifdef SO_RCVBUF - {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT}, -#endif -#ifdef SO_SNDLOWAT - {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT}, -#endif -#ifdef SO_RCVLOWAT - {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT}, -#endif -#ifdef SO_SNDTIMEO - {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT}, -#endif -#ifdef SO_RCVTIMEO - {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT}, -#endif - {NULL,0,0,0,0}}; - - -/** - Set user socket options. -**/ -_PUBLIC_ void set_socket_options(int fd, const char *options) -{ - const char **options_list = (const char **)str_list_make(NULL, options, " \t,"); - int j; - - if (!options_list) - return; - - for (j = 0; options_list[j]; j++) { - const char *tok = options_list[j]; - int ret=0,i; - int value = 1; - char *p; - bool got_value = false; - - if ((p = strchr(tok,'='))) { - *p = 0; - value = atoi(p+1); - got_value = true; - } - - for (i=0;socket_options[i].name;i++) - if (strequal(socket_options[i].name,tok)) - break; - - if (!socket_options[i].name) { - DEBUG(0,("Unknown socket option %s\n",tok)); - continue; - } - - switch (socket_options[i].opttype) { - case OPT_BOOL: - case OPT_INT: - ret = setsockopt(fd,socket_options[i].level, - socket_options[i].option,(char *)&value,sizeof(int)); - break; - - case OPT_ON: - if (got_value) - DEBUG(0,("syntax error - %s does not take a value\n",tok)); - - { - int on = socket_options[i].value; - ret = setsockopt(fd,socket_options[i].level, - socket_options[i].option,(char *)&on,sizeof(int)); - } - break; - } - - if (ret != 0) - DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) )); - } - - talloc_free(options_list); -} - /* set some flags on a socket */ diff --git a/source4/lib/socket/socket.h b/source4/lib/socket/socket.h index 4a744797b3..e00b61ba6c 100644 --- a/source4/lib/socket/socket.h +++ b/source4/lib/socket/socket.h @@ -174,14 +174,18 @@ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx, struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx, struct sockaddr *sockaddr, size_t addrlen); +struct sockaddr_storage; +struct socket_address *socket_address_from_sockaddr_storage(TALLOC_CTX *mem_ctx, + const struct sockaddr_storage *sockaddr, + uint16_t port); _PUBLIC_ void socket_address_set_port(struct socket_address *a, uint16_t port); struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx, const struct socket_address *oaddr); const struct socket_ops *socket_getops_byname(const char *name, enum socket_type type); -bool allow_access(TALLOC_CTX *mem_ctx, - const char **deny_list, const char **allow_list, - const char *cname, const char *caddr); +bool socket_allow_access(TALLOC_CTX *mem_ctx, + const char **deny_list, const char **allow_list, + const char *cname, const char *caddr); bool socket_check_access(struct socket_context *sock, const char *service_name, const char **allow_list, const char **deny_list); diff --git a/source4/lib/socket/socket_ip.c b/source4/lib/socket/socket_ip.c index 4e66653252..80f7d333f3 100644 --- a/source4/lib/socket/socket_ip.c +++ b/source4/lib/socket/socket_ip.c @@ -47,7 +47,7 @@ static NTSTATUS ipv4_init(struct socket_context *sock) sock->fd = socket(PF_INET, type, 0); if (sock->fd == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } sock->backend_name = "ipv4"; @@ -70,16 +70,16 @@ static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags) for non-blocking connect */ ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } if (error != 0) { - return map_nt_error_from_unix(error); + return map_nt_error_from_unix_common(error); } if (!(flags & SOCKET_FLAG_BLOCK)) { ret = set_blocking(sock->fd, false); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -102,7 +102,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock, if (my_address && my_address->sockaddr) { ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } else if (my_address) { my_ip = interpret_addr2(my_address->addr); @@ -119,7 +119,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock, ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } } @@ -127,7 +127,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock, if (srv_address->sockaddr) { ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } else { srv_ip = interpret_addr2(srv_address->addr); @@ -147,7 +147,7 @@ static NTSTATUS ipv4_connect(struct socket_context *sock, ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr)); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -186,20 +186,20 @@ static NTSTATUS ipv4_listen(struct socket_context *sock, } if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } if (sock->type == SOCKET_TYPE_STREAM) { ret = listen(sock->fd, queue_size); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } if (!(flags & SOCKET_FLAG_BLOCK)) { ret = set_blocking(sock->fd, false); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -220,14 +220,14 @@ static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context * new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len); if (new_fd == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } if (!(sock->flags & SOCKET_FLAG_BLOCK)) { int ret = set_blocking(new_fd, false); if (ret == -1) { close(new_fd); - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -268,7 +268,7 @@ static NTSTATUS ip_recv(struct socket_context *sock, void *buf, if (gotlen == 0) { return NT_STATUS_END_OF_FILE; } else if (gotlen == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } *nread = gotlen; @@ -311,7 +311,7 @@ static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf, return NT_STATUS_END_OF_FILE; } else if (gotlen == -1) { talloc_free(src); - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } src->sockaddrlen = from_len; @@ -342,7 +342,7 @@ static NTSTATUS ip_send(struct socket_context *sock, len = send(sock->fd, blob->data, blob->length, 0); if (len == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } *sendlen = len; @@ -383,7 +383,7 @@ static NTSTATUS ipv4_sendto(struct socket_context *sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr)); } if (len == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } *sendlen = len; @@ -518,7 +518,7 @@ static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending) *npending = value; return NT_STATUS_OK; } - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } static const struct socket_ops ipv4_ops = { @@ -604,7 +604,7 @@ static NTSTATUS ipv6_init(struct socket_context *sock) sock->fd = socket(PF_INET6, type, 0); if (sock->fd == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } sock->backend_name = "ipv6"; @@ -623,7 +623,7 @@ static NTSTATUS ipv6_tcp_connect(struct socket_context *sock, if (my_address && my_address->sockaddr) { ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } else if (my_address) { struct in6_addr my_ip; @@ -638,7 +638,7 @@ static NTSTATUS ipv6_tcp_connect(struct socket_context *sock, ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } } @@ -661,15 +661,28 @@ static NTSTATUS ipv6_tcp_connect(struct socket_context *sock, ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr)); } if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } return ip_connect_complete(sock, flags); } +/* + fix the sin6_scope_id based on the address interface + */ +static void fix_scope_id(struct sockaddr_in6 *in6, + const char *address) +{ + const char *p = strchr(address, '%'); + if (p != NULL) { + in6->sin6_scope_id = if_nametoindex(p+1); + } +} + + static NTSTATUS ipv6_listen(struct socket_context *sock, - const struct socket_address *my_address, - int queue_size, uint32_t flags) + const struct socket_address *my_address, + int queue_size, uint32_t flags) { struct sockaddr_in6 my_addr; struct in6_addr ip_addr; @@ -680,31 +693,38 @@ static NTSTATUS ipv6_listen(struct socket_context *sock, if (my_address->sockaddr) { ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen); } else { + int one = 1; ip_addr = interpret_addr6(my_address->addr); ZERO_STRUCT(my_addr); my_addr.sin6_addr = ip_addr; my_addr.sin6_port = htons(my_address->port); my_addr.sin6_family = PF_INET6; - - ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); + fix_scope_id(&my_addr, my_address->addr); + + /* when binding on ipv6 we always want to only bind on v6 */ + ret = setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, + (const void *)&one, sizeof(one)); + if (ret != -1) { + ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); + } } if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } if (sock->type == SOCKET_TYPE_STREAM) { ret = listen(sock->fd, queue_size); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } if (!(flags & SOCKET_FLAG_BLOCK)) { ret = set_blocking(sock->fd, false); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -725,14 +745,14 @@ static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_conte new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len); if (new_fd == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } if (!(sock->flags & SOCKET_FLAG_BLOCK)) { int ret = set_blocking(new_fd, false); if (ret == -1) { close(new_fd); - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -796,7 +816,7 @@ static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf, return NT_STATUS_END_OF_FILE; } else if (gotlen == -1) { talloc_free(src); - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } src->sockaddrlen = from_len; @@ -847,7 +867,7 @@ static NTSTATUS ipv6_sendto(struct socket_context *sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr)); } if (len == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } *sendlen = len; diff --git a/source4/lib/socket/socket_unix.c b/source4/lib/socket/socket_unix.c index f1fa0a3a30..d492f01268 100644 --- a/source4/lib/socket/socket_unix.c +++ b/source4/lib/socket/socket_unix.c @@ -33,7 +33,7 @@ _PUBLIC_ const struct socket_ops *socket_unixdom_ops(enum socket_type type); */ static NTSTATUS unixdom_error(int ernum) { - return map_nt_error_from_unix(ernum); + return map_nt_error_from_unix_common(ernum); } static NTSTATUS unixdom_init(struct socket_context *sock) @@ -53,7 +53,7 @@ static NTSTATUS unixdom_init(struct socket_context *sock) sock->fd = socket(PF_UNIX, type, 0); if (sock->fd == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } sock->private_data = NULL; @@ -76,16 +76,16 @@ static NTSTATUS unixdom_connect_complete(struct socket_context *sock, uint32_t f for non-blocking connect */ ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } if (error != 0) { - return map_nt_error_from_unix(error); + return map_nt_error_from_unix_common(error); } if (!(flags & SOCKET_FLAG_BLOCK)) { ret = set_blocking(sock->fd, false); if (ret == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -194,7 +194,7 @@ static NTSTATUS unixdom_accept(struct socket_context *sock, int ret = set_blocking(new_fd, false); if (ret == -1) { close(new_fd); - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } } @@ -280,7 +280,7 @@ static NTSTATUS unixdom_sendto(struct socket_context *sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr)); } if (len == -1) { - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } *sendlen = len; @@ -390,7 +390,7 @@ static NTSTATUS unixdom_pending(struct socket_context *sock, size_t *npending) *npending = value; return NT_STATUS_OK; } - return map_nt_error_from_unix(errno); + return map_nt_error_from_unix_common(errno); } static const struct socket_ops unixdom_ops = { diff --git a/source4/lib/socket/testsuite.c b/source4/lib/socket/testsuite.c index 2489277433..357e4ae5df 100644 --- a/source4/lib/socket/testsuite.c +++ b/source4/lib/socket/testsuite.c @@ -42,7 +42,7 @@ static bool test_udp(struct torture_context *tctx) TALLOC_CTX *mem_ctx = tctx; struct interface *ifaces; - load_interfaces(tctx, lpcfg_interfaces(tctx->lp_ctx), &ifaces); + load_interface_list(tctx, tctx->lp_ctx, &ifaces); status = socket_create("ip", SOCKET_TYPE_DGRAM, &sock1, 0); torture_assert_ntstatus_ok(tctx, status, "creating DGRAM IP socket 1"); @@ -53,7 +53,7 @@ static bool test_udp(struct torture_context *tctx) talloc_steal(mem_ctx, sock2); localhost = socket_address_from_strings(sock1, sock1->backend_name, - iface_best_ip(ifaces, "127.0.0.1"), 0); + iface_list_best_ip(ifaces, "127.0.0.1"), 0); torture_assert(tctx, localhost, "Localhost not found"); @@ -62,10 +62,10 @@ static bool test_udp(struct torture_context *tctx) srv_addr = socket_get_my_addr(sock1, mem_ctx); torture_assert(tctx, srv_addr != NULL && - strcmp(srv_addr->addr, iface_best_ip(ifaces, "127.0.0.1")) == 0, + strcmp(srv_addr->addr, iface_list_best_ip(ifaces, "127.0.0.1")) == 0, talloc_asprintf(tctx, "Expected server address of %s but got %s", - iface_best_ip(ifaces, "127.0.0.1"), srv_addr ? srv_addr->addr : NULL)); + iface_list_best_ip(ifaces, "127.0.0.1"), srv_addr ? srv_addr->addr : NULL)); torture_comment(tctx, "server port is %d\n", srv_addr->port); @@ -135,9 +135,9 @@ static bool test_tcp(struct torture_context *tctx) torture_assert_ntstatus_ok(tctx, status, "creating IP stream socket 1"); talloc_steal(mem_ctx, sock2); - load_interfaces(tctx, lpcfg_interfaces(tctx->lp_ctx), &ifaces); + load_interface_list(tctx, tctx->lp_ctx, &ifaces); localhost = socket_address_from_strings(sock1, sock1->backend_name, - iface_best_ip(ifaces, "127.0.0.1"), 0); + iface_list_best_ip(ifaces, "127.0.0.1"), 0); torture_assert(tctx, localhost, "Localhost not found"); status = socket_listen(sock1, localhost, 0, 0); @@ -147,7 +147,7 @@ static bool test_tcp(struct torture_context *tctx) torture_assert(tctx, srv_addr && srv_addr->addr, "Unexpected socket_get_my_addr NULL\n"); - torture_assert_str_equal(tctx, srv_addr->addr, iface_best_ip(ifaces, "127.0.0.1"), + torture_assert_str_equal(tctx, srv_addr->addr, iface_list_best_ip(ifaces, "127.0.0.1"), "Unexpected server address"); torture_comment(tctx, "server port is %d\n", srv_addr->port); diff --git a/source4/lib/socket/wscript_build b/source4/lib/socket/wscript_build index e2ff9b078a..c10970d17a 100644 --- a/source4/lib/socket/wscript_build +++ b/source4/lib/socket/wscript_build @@ -1,11 +1,11 @@ #!/usr/bin/env python bld.SAMBA_LIBRARY('netif', - source='interface.c netif.c', - autoproto='netif_proto.h', - deps='samba-util', - private_library=True - ) + source='interface.c', + deps='samba-util interfaces samba-hostconfig', + private_library=True, + autoproto='netif_proto.h' + ) bld.SAMBA_MODULE('socket_ip', source='socket_ip.c', |