summaryrefslogtreecommitdiff
path: root/source3/lib/util_sock.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-10-15 16:11:48 -0700
committerJeremy Allison <jra@samba.org>2007-10-15 16:11:48 -0700
commit666f50b01f282e520c59b94944d4b1583168d46a (patch)
tree9acb499f1bdfdb1a285a3392708b0c942fc2c17e /source3/lib/util_sock.c
parent48cd61d30ed46e2c61c0df9d510f50ae7a11accd (diff)
downloadsamba-666f50b01f282e520c59b94944d4b1583168d46a.tar.gz
samba-666f50b01f282e520c59b94944d4b1583168d46a.tar.bz2
samba-666f50b01f282e520c59b94944d4b1583168d46a.zip
Move to protocol independent code in most of lib/util_sock.c
We don't use gethostbyname any more except in one case where we're looking for host aliases (I don't know how to do that with getaddrinfo yet). New function should be getaddrinfo(). Next step will be fixing lib/access.c, and then changing libsmb/namequery.c to cope with IPv6 address returns. Jeremy. (This used to be commit 4a56b697b6adcf095e25895c4a9ba3192ed34124)
Diffstat (limited to 'source3/lib/util_sock.c')
-rw-r--r--source3/lib/util_sock.c337
1 files changed, 223 insertions, 114 deletions
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index 8079932620..eb3b35339c 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -29,63 +29,133 @@ static int client_fd = -1;
static char client_ip_string[INET6_ADDRSTRLEN];
/****************************************************************************
- Return true if a string could be a pure IPv4 address.
+ Return true if a string could be an IPv4 address.
****************************************************************************/
bool is_ipaddress_v4(const char *str)
{
- bool pure_address = true;
- int i;
+ int ret = -1;
+ struct in_addr dest;
- for (i=0; pure_address && str[i]; i++) {
- if (!(isdigit((int)str[i]) || str[i] == '.')) {
- pure_address = false;
- }
+ ret = inet_pton(AF_INET, str, &dest);
+ if (ret > 0) {
+ return true;
}
+ return false;
+}
- /* Check that a pure number is not misinterpreted as an IP */
- pure_address = pure_address && (strchr_m(str, '.') != NULL);
- return pure_address;
+/****************************************************************************
+ Return true if a string could be an IPv4 or IPv6 address.
+****************************************************************************/
+
+bool is_ipaddress(const char *str)
+{
+ int ret = -1;
+
+#if defined(AF_INET6)
+ struct in6_addr dest6;
+
+ ret = inet_pton(AF_INET6, str, &dest6);
+ if (ret > 0) {
+ return true;
+ }
+#endif
+ return is_ipaddress_v4(str);
+}
+
+/*******************************************************************
+ Wrap getaddrinfo...
+******************************************************************/
+
+static bool interpret_string_addr_internal(struct addrinfo **ppres,
+ const char *str, int flags)
+{
+ int ret;
+ struct addrinfo hints;
+
+ memset(&hints, '\0', sizeof(hints));
+ /* By default make sure it supports TCP. */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = flags;
+
+ ret = getaddrinfo(str, NULL,
+ &hints,
+ ppres);
+ if (ret) {
+ DEBUG(3,("interpret_string_addr_interal: getaddrinfo failed "
+ "for name %s [%s]\n",
+ str,
+ gai_strerror(ret) ));
+ return false;
+ }
+ return true;
}
/****************************************************************************
Interpret an internet address or name into an IP address in 4 byte form.
+ RETURNS IN NETWORK BYTE ORDER (big endian).
****************************************************************************/
uint32 interpret_addr(const char *str)
{
- struct hostent *hp;
- uint32 res;
+ uint32 ret;
- 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
+ /* 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);
+ struct in_addr dest;
+
+ if (inet_pton(AF_INET, str, &dest) <= 0) {
+ /* Error - this shouldn't happen ! */
+ DEBUG(0,("interpret_addr: inet_pton failed "
+ "host %s\n",
+ str));
+ return 0;
+ }
+ ret = dest.s_addr; /* NETWORK BYTE ORDER ! */
} 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));
+ /* Otherwise assume it's a network name of some sort and use
+ getadddrinfo. */
+ struct addrinfo *res = NULL;
+ struct addrinfo *res_list = NULL;
+ if (!interpret_string_addr_internal(&res_list,
+ str,
+ AI_ADDRCONFIG)) {
+ DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
return 0;
}
- if(hp->h_addr == NULL) {
- DEBUG(3,("sys_gethostbyname: host address is "
+ /* Find the first IPv4 address. */
+ for (res = res_list; res; res = res->ai_next) {
+ if (res->ai_family != AF_INET) {
+ continue;
+ }
+ if (res->ai_addr == NULL) {
+ continue;
+ }
+ break;
+ }
+ if(res == NULL) {
+ DEBUG(3,("interpret_addr: host address is "
"invalid for host %s\n",str));
+ if (res_list) {
+ freeaddrinfo(res_list);
+ }
return 0;
}
- putip((char *)&res,(char *)hp->h_addr);
+ putip((char *)&ret,
+ &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr);
+ if (res_list) {
+ freeaddrinfo(res_list);
+ }
}
- if (res == (uint32)-1)
- return(0);
+ /* This is so bogus - all callers need fixing... JRA. */
+ if (ret == (uint32)-1) {
+ return 0;
+ }
- return(res);
+ return ret;
}
/*******************************************************************
@@ -105,31 +175,20 @@ struct in_addr *interpret_addr2(const char *str)
struct sockaddr_storage.
******************************************************************/
-bool interpret_string_addr(struct sockaddr_storage *pss, const char *str)
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags)
{
- 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) ));
+ if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) {
+ return false;
+ }
+ if (!res) {
return false;
}
-
/* Copy the first sockaddr. */
memcpy(pss, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
@@ -155,7 +214,8 @@ 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;
+ struct in6_addr *pin6 =
+ &((struct sockaddr_in6 *)pss)->sin6_addr;
return IN6_IS_ADDR_LOOPBACK(pin6);
}
#endif
@@ -185,7 +245,8 @@ 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;
+ struct in6_addr *pin6 =
+ &((struct sockaddr_in6 *)pss)->sin6_addr;
return IN6_IS_ADDR_UNSPECIFIED(pin6);
}
#endif
@@ -1215,7 +1276,7 @@ bool send_smb(int fd, char *buffer)
int open_socket_in(int type,
int port,
int dlevel,
- uint32 socket_addr,
+ uint32 socket_addr, /* NETWORK BYTE ORDER */
bool rebind )
{
struct sockaddr_in sock;
@@ -1595,22 +1656,14 @@ static bool matchname(const char *remotehost,
const struct sockaddr_storage *pss,
socklen_t len)
{
- struct addrinfo hints;
struct addrinfo *res = NULL;
struct addrinfo *ailist = NULL;
char addr_buf[INET6_ADDRSTRLEN];
- int ret = -1;
-
- memset(&hints,'\0',sizeof(struct addrinfo));
- /* By default make sure it supports TCP. */
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_ADDRCONFIG|AI_CANONNAME;
-
- ret = getaddrinfo(remotehost, NULL,
- &hints,
- &res);
+ bool ret = interpret_string_addr_internal(&ailist,
+ remotehost,
+ AI_ADDRCONFIG|AI_CANONNAME);
- if (ret || res == NULL) {
+ if (!ret || ailist == NULL) {
DEBUG(3,("matchname: getaddrinfo failed for "
"name %s [%s]\n",
remotehost,
@@ -1622,24 +1675,25 @@ static bool matchname(const char *remotehost,
* Make sure that getaddrinfo() returns the "correct" host name.
*/
- if (res->ai_canonname == NULL ||
- (!strequal(remotehost, res->ai_canonname) &&
+ if (ailist->ai_canonname == NULL ||
+ (!strequal(remotehost, ailist->ai_canonname) &&
!strequal(remotehost, "localhost"))) {
DEBUG(0,("matchname: host name/name mismatch: %s != %s\n",
remotehost,
- res->ai_canonname ? res->ai_canonname : "(NULL)"));
- freeaddrinfo(res);
+ ailist->ai_canonname ?
+ ailist->ai_canonname : "(NULL)"));
+ freeaddrinfo(ailist);
return false;
}
/* Look up the host address in the address list we just got. */
- for (ailist = res; ailist; ailist = ailist->ai_next) {
- if (!ailist->ai_addr) {
+ for (res = ailist; res; res = res->ai_next) {
+ if (!res->ai_addr) {
continue;
}
- if (addr_equal((const struct sockaddr_storage *)ailist->ai_addr,
+ if (addr_equal((const struct sockaddr_storage *)res->ai_addr,
pss)) {
- freeaddrinfo(res);
+ freeaddrinfo(ailist);
return true;
}
}
@@ -1655,9 +1709,11 @@ static bool matchname(const char *remotehost,
sizeof(addr_buf),
pss,
len),
- res->ai_canonname ? res->ai_canonname : "(NULL)"));
+ ailist->ai_canonname ? ailist->ai_canonname : "(NULL)"));
- freeaddrinfo(res);
+ if (ailist) {
+ freeaddrinfo(ailist);
+ }
return false;
}
@@ -1837,8 +1893,62 @@ out_umask:
#endif /* HAVE_UNIXSOCKET */
}
+/****************************************************************************
+ Get my own canonical name, including domain.
+****************************************************************************/
+
+bool get_mydnsfullname(fstring my_dnsname)
+{
+ static fstring dnshostname;
+
+ if (!*dnshostname) {
+ struct addrinfo *res = NULL;
+ bool ret;
+
+ /* get my host name */
+ if (gethostname(dnshostname, sizeof(dnshostname)) == -1) {
+ *dnshostname = '\0';
+ DEBUG(0,("get_mydnsfullname: gethostname failed\n"));
+ return false;
+ }
+
+ /* Ensure null termination. */
+ dnshostname[sizeof(dnshostname)-1] = '\0';
+
+ ret = interpret_string_addr_internal(&res,
+ dnshostname,
+ AI_ADDRCONFIG|AI_CANONNAME);
+
+ if (!ret || res == NULL) {
+ DEBUG(3,("get_mydnsfullname: getaddrinfo failed for "
+ "name %s [%s]\n",
+ dnshostname,
+ gai_strerror(ret) ));
+ return false;
+ }
+
+ /*
+ * Make sure that getaddrinfo() returns the "correct" host name.
+ */
+
+ if (res->ai_canonname == NULL) {
+ DEBUG(3,("get_mydnsfullname: failed to get "
+ "canonical name for %s\n",
+ dnshostname));
+ freeaddrinfo(res);
+ return false;
+ }
+
+
+ fstrcpy(dnshostname, res->ai_canonname);
+ freeaddrinfo(res);
+ }
+ fstrcpy(my_dnsname, dnshostname);
+ return true;
+}
+
/************************************************************
- Is this my name ? Needs fixing for IPv6.
+ Is this my name ?
************************************************************/
bool is_myname_or_ipaddr(const char *s)
@@ -1846,83 +1956,82 @@ bool is_myname_or_ipaddr(const char *s)
fstring name, dnsname;
char *servername;
- if ( !s ) {
+ if (!s) {
return false;
}
- /* santize the string from '\\name' */
+ /* Santize the string from '\\name' */
+ fstrcpy(name, s);
- fstrcpy( name, s );
-
- servername = strrchr_m( name, '\\' );
- if ( !servername )
+ servername = strrchr_m(name, '\\' );
+ if (!servername) {
servername = name;
- else
+ } else {
servername++;
+ }
- /* optimize for the common case */
-
- if (strequal(servername, global_myname()))
+ /* Optimize for the common case */
+ if (strequal(servername, global_myname())) {
return true;
+ }
- /* check for an alias */
-
- if (is_myname(servername))
+ /* Check for an alias */
+ if (is_myname(servername)) {
return true;
+ }
- /* check for loopback */
-
- if (strequal(servername, "127.0.0.1"))
+ /* Check for loopback */
+ if (strequal(servername, "127.0.0.1") ||
+ strequal(servername, "::1")) {
return true;
+ }
- if (strequal(servername, "localhost"))
+ if (strequal(servername, "localhost")) {
return true;
+ }
- /* maybe it's my dns name */
-
- if ( get_mydnsfullname( dnsname ) )
- if ( strequal( servername, dnsname ) )
+ /* 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 ) );
+ /* Handle possible CNAME records - convert to an IP addr. */
+ 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(name,
+ sizeof(name),
+ &ss,
+ sizeof(ss));
servername = name;
}
}
- /* maybe its an IP address? */
- if (is_ipaddress_v4(servername)) {
+ /* Maybe its an IP address? */
+ if (is_ipaddress(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)) {
+ if (!interpret_string_addr(&ss, servername, AI_NUMERICHOST)) {
return false;
}
- in_addr_to_sockaddr_storage(&ss, ip);
+ if (is_zero_addr(&ss) || is_loopback_addr(&ss)) {
+ return false;
+ }
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 */
+ /* No match */
return false;
}