diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/lib/util_sock.c | 167 |
1 files changed, 112 insertions, 55 deletions
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 5a96bb79d6..8c5d1b6fec 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -1547,40 +1547,101 @@ int open_udp_socket(const char *host, int port) } /******************************************************************* + Return the IP addr of the remote end of a socket as a string. + Optionally return the struct sockaddr_storage. + ******************************************************************/ + +static const char *get_peer_addr_internal(int fd, + struct sockaddr_storage *pss, + socklen_t *plength) +{ + struct sockaddr_storage ss; + socklen_t length = sizeof(ss); + static char addr_buf[INET6_ADDRSTRLEN]; + + safe_strcpy(addr_buf,"0.0.0.0",sizeof(addr_buf)-1); + + if (fd == -1) { + return addr_buf; + } + + if (pss == NULL) { + pss = &ss; + } + if (plength == NULL) { + plength = &length; + } + + if (getpeername(fd, (struct sockaddr *)pss, plength) < 0) { + DEBUG(0,("getpeername failed. Error was %s\n", + strerror(errno) )); + return addr_buf; + } + + print_sockaddr(addr_buf, + sizeof(addr_buf), + pss, + *plength); + return addr_buf; +} + + +/******************************************************************* Matchname - determine if host name matches IP address. Used to confirm a hostname lookup to prevent spoof attacks. ******************************************************************/ -static bool matchname(char *remotehost,struct in_addr addr) +static bool matchname(const char *remotehost, + const struct sockaddr_storage *pss, + socklen_t len) { - struct hostent *hp; - int i; + 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; - if ((hp = sys_gethostbyname(remotehost)) == 0) { - DEBUG(0,("sys_gethostbyname(%s): lookup failure.\n", - remotehost)); + ret = getaddrinfo(remotehost, NULL, + &hints, + &res); + + if (ret || res == NULL) { + DEBUG(3,("matchname: getaddrinfo failed for " + "name %s [%s]\n", + remotehost, + gai_strerror(ret) )); return false; } /* - * Make sure that gethostbyname() returns the "correct" host name. - * Unfortunately, gethostbyname("localhost") sometimes yields - * "localhost.domain". Since the latter host name comes from the - * local DNS, we just have to trust it (all bets are off if the local - * DNS is perverted). We always check the address list, though. + * Make sure that getaddrinfo() returns the "correct" host name. */ - if (!strequal(remotehost, hp->h_name) - && !strequal(remotehost, "localhost")) { - DEBUG(0,("host name/name mismatch: %s != %s\n", - remotehost, hp->h_name)); + if (res->ai_canonname == NULL || + (!strequal(remotehost, res->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); 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) + for (ailist = res; ailist; ailist = ailist->ai_next) { + if (!ailist->ai_addr) { + continue; + } + if (addr_equal((const struct sockaddr_storage *)ailist->ai_addr, + pss)) { + freeaddrinfo(res); return true; + } } /* @@ -1589,8 +1650,14 @@ static bool matchname(char *remotehost,struct in_addr addr) * it, but that could be dangerous, too. */ - DEBUG(0,("host name/address mismatch: %s != %s\n", - inet_ntoa(addr), hp->h_name)); + DEBUG(0,("matchname: host name/address mismatch: %s != %s\n", + print_sockaddr(addr_buf, + sizeof(addr_buf), + pss, + len), + res->ai_canonname ? res->ai_canonname : "(NULL)")); + + freeaddrinfo(res); return false; } @@ -1600,12 +1667,13 @@ static bool matchname(char *remotehost,struct in_addr addr) const char *get_peer_name(int fd, bool force_lookup) { - static pstring name_buf; - pstring tmp_name; static fstring addr_buf; - struct hostent *hp; - struct in_addr addr; + static pstring name_buf; + struct sockaddr_storage ss; + socklen_t length = sizeof(ss); const char *p; + int ret; + pstring tmp_name; /* reverse lookups can be *very* expensive, and in many situations won't work because many networks don't link dhcp @@ -1615,28 +1683,37 @@ const char *get_peer_name(int fd, bool force_lookup) return get_peer_addr(fd); } - p = get_peer_addr(fd); + p = get_peer_addr_internal(fd, &ss, &length); /* it might be the same as the last one - save some DNS work */ - if (strcmp(p, addr_buf) == 0) + if (strcmp(p, addr_buf) == 0) { return name_buf; + } pstrcpy(name_buf,"UNKNOWN"); - if (fd == -1) + if (fd == -1) { return name_buf; + } fstrcpy(addr_buf, p); - addr = *interpret_addr2(p); - /* Look up the remote host name. */ - if ((hp = gethostbyaddr((char *)&addr.s_addr, - sizeof(addr.s_addr), AF_INET)) == 0) { - DEBUG(1,("Gethostbyaddr failed for %s\n",p)); + ret = getnameinfo((struct sockaddr *)&ss, + length, + name_buf, + sizeof(name_buf), + NULL, + 0, + NI_NUMERICHOST); + + if (ret) { + DEBUG(1,("get_peer_name: getnameinfo failed " + "for %s with error %s\n", + p, + gai_strerror(ret))); pstrcpy(name_buf, p); } else { - pstrcpy(name_buf,(char *)hp->h_name); - if (!matchname(name_buf, addr)) { + if (!matchname(name_buf, &ss, length)) { DEBUG(0,("Matchname failed on %s %s\n",name_buf,p)); pstrcpy(name_buf,"UNKNOWN"); } @@ -1646,7 +1723,7 @@ const char *get_peer_name(int fd, bool force_lookup) use --enable-developer or the clobber_region() call will get you */ - pstrcpy( tmp_name, name_buf ); + pstrcpy(tmp_name, name_buf ); alpha_strcpy(name_buf, tmp_name, "_-.", sizeof(name_buf)); if (strstr(name_buf,"..")) { pstrcpy(name_buf, "UNKNOWN"); @@ -1661,27 +1738,7 @@ const char *get_peer_name(int fd, bool force_lookup) const char *get_peer_addr(int fd) { - struct sockaddr_storage ss; - socklen_t length = sizeof(ss); - static char addr_buf[INET6_ADDRSTRLEN]; - - safe_strcpy(addr_buf,"0.0.0.0",sizeof(addr_buf)-1); - - if (fd == -1) { - return addr_buf; - } - - if (getpeername(fd, (struct sockaddr *)&ss, &length) < 0) { - DEBUG(0,("getpeername failed. Error was %s\n", - strerror(errno) )); - return addr_buf; - } - - print_sockaddr(addr_buf, - sizeof(addr_buf), - &ss, - length); - return addr_buf; + return get_peer_addr_internal(fd, NULL, NULL); } /******************************************************************* |