diff options
author | Jeremy Allison <jra@samba.org> | 2011-03-24 11:55:38 -0700 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2011-06-14 12:57:31 +0200 |
commit | 0b1101ae0684186150da58aaf1ca2feb81ce66ae (patch) | |
tree | 172a8d8e89e35bc5e1b4d5af8715fa33450d1628 /source3/lib | |
parent | 4b0f3693bed64ab3b3d433e1e45d3e8c56f50afc (diff) | |
download | samba-0b1101ae0684186150da58aaf1ca2feb81ce66ae.tar.gz |
Fix is_myname_or_ipaddr() to be robust against strange DNS setups.
If IPv6 DNS names are turned on, but Samba isn't configured to
listen on an IPv6 interface, then is_myname_or_ipaddr() can return
false on a valid DNS name that it should detect is our own. If the
IPv6 addr is returned by preference, then looking at the first addr
only causes is_myname_or_ipaddr() to fail. We need to look at all the
addresses returned by the DNS lookup and check all of them against
our interface list. This is an order N^2 lookup, but there shouldn't
be enough addresses to make this a practical problem.
Jeremy.
Fix bug #8038 - Connecting to a printer can return INVALID_PARAMETER when IPv6
DNS names are turned on.
(cherry picked from commit 80078cb6ef2e6976cb5ab25a86157bca22c836a2)
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/util_sock.c | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 7a573ad5204..1441560470c 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -1839,13 +1839,46 @@ const char *get_mydnsfullname(void) } /************************************************************ + Is this my ip address ? +************************************************************/ + +static bool is_my_ipaddr(const char *ipaddr_str) +{ + struct sockaddr_storage ss; + struct iface_struct *nics; + int i, n; + + if (!interpret_string_addr(&ss, ipaddr_str, AI_NUMERICHOST)) { + return false; + } + + if (ismyaddr((struct sockaddr *)&ss)) { + return true; + } + + if (is_zero_addr((struct sockaddr *)&ss) || + is_loopback_addr((struct sockaddr *)&ss)) { + return false; + } + + n = get_interfaces(talloc_tos(), &nics); + for (i=0; i<n; i++) { + if (sockaddr_equal((struct sockaddr *)&nics[i].ip, (struct sockaddr *)&ss)) { + TALLOC_FREE(nics); + return true; + } + } + TALLOC_FREE(nics); + return false; +} + +/************************************************************ Is this my name ? ************************************************************/ bool is_myname_or_ipaddr(const char *s) { TALLOC_CTX *ctx = talloc_tos(); - char addr[INET6_ADDRSTRLEN]; char *name = NULL; const char *dnsname; char *servername = NULL; @@ -1893,45 +1926,38 @@ bool is_myname_or_ipaddr(const char *s) return true; } - /* Handle possible CNAME records - convert to an IP addr. */ + /* Handle possible CNAME records - convert to an IP addr. list. */ if (!is_ipaddress(servername)) { - /* Use DNS to resolve the name, but only the first address */ - struct sockaddr_storage ss; - if (interpret_string_addr(&ss, servername, 0)) { - print_sockaddr(addr, - sizeof(addr), - &ss); - servername = addr; - } - } + /* Use DNS to resolve the name, check all addresses. */ + struct addrinfo *p = NULL; + struct addrinfo *res = NULL; - /* Maybe its an IP address? */ - if (is_ipaddress(servername)) { - struct sockaddr_storage ss; - struct iface_struct *nics; - int i, n; - - if (!interpret_string_addr(&ss, servername, AI_NUMERICHOST)) { + if (!interpret_string_addr_internal(&res, + servername, + AI_ADDRCONFIG)) { return false; } - if (ismyaddr((struct sockaddr *)&ss)) { - return true; - } - - if (is_zero_addr((struct sockaddr *)&ss) || - is_loopback_addr((struct sockaddr *)&ss)) { - return false; - } + for (p = res; p; p = p->ai_next) { + char addr[INET6_ADDRSTRLEN]; + struct sockaddr_storage ss; - n = get_interfaces(talloc_tos(), &nics); - for (i=0; i<n; i++) { - if (sockaddr_equal((struct sockaddr *)&nics[i].ip, (struct sockaddr *)&ss)) { - TALLOC_FREE(nics); + ZERO_STRUCT(ss); + memcpy(&ss, p->ai_addr, p->ai_addrlen); + print_sockaddr(addr, + sizeof(addr), + &ss); + if (is_my_ipaddr(addr)) { + freeaddrinfo(res); return true; } } - TALLOC_FREE(nics); + freeaddrinfo(res); + } + + /* Maybe its an IP address? */ + if (is_ipaddress(servername)) { + return is_my_ipaddr(servername); } /* No match */ |