diff --git a/TargetGroup.cc b/TargetGroup.cc index c515ce5b8..f2cc04574 100644 --- a/TargetGroup.cc +++ b/TargetGroup.cc @@ -92,6 +92,7 @@ /* $Id$ */ +#include "tcpip.h" #include "TargetGroup.h" #include "NmapOps.h" #include "nmap_error.h" @@ -159,7 +160,6 @@ int TargetGroup::parse_expr(const char * const target_expr, int af) { char *r,*s, *target_net; char *addy[5]; char *hostexp = strdup(target_expr); - struct hostent *target; namedhost = 0; if (targets_type != TYPE_NONE) @@ -203,35 +203,37 @@ int TargetGroup::parse_expr(const char * const target_expr, int af) { break; } if (netmask != 32 || namedhost) { - struct in_addr addr; + struct addrinfo *addrs, *addr; + struct sockaddr_storage ss; + size_t sslen; targets_type = IPV4_NETMASK; - if (!inet_pton(AF_INET, target_net, &(addr))) { - if ((target = gethostbyname(target_net))) { - int count=0; - - memcpy(&(addr), target->h_addr_list[0], sizeof(addr)); - - while (target->h_addr_list[count]) { - struct sockaddr_storage ss; - struct sockaddr_in *sin = (struct sockaddr_in *) &ss; - - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr, target->h_addr_list[count], sizeof(sin->sin_addr)); - resolvedaddrs.push_back(ss); - count++; - } - - if (count > 1 && o.verbose > 1) - error("Warning: Hostname %s resolves to %d IPs. Using %s.", target_net, count, inet_ntoa(*((struct in_addr *)target->h_addr_list[0]))); - } else { - error("Failed to resolve given hostname/IP: %s. Note that you can't use '/mask' AND '1-4,7,100-' style IP ranges", target_net); - free(hostexp); - return 1; + addrs = resolve_all(target_net, AF_INET); + for (addr = addrs; addr != NULL; addr = addr->ai_next) { + if (addr->ai_family != AF_INET) + continue; + if (addr->ai_addrlen < sizeof(ss)) { + memcpy(&ss, addr->ai_addr, addr->ai_addrlen); + resolvedaddrs.push_back(ss); } - } + } + freeaddrinfo(addrs); + + if (resolvedaddrs.empty()) { + error("Failed to resolve given hostname/IP: %s. Note that you can't use '/mask' AND '1-4,7,100-' style IP ranges", target_net); + free(hostexp); + return 1; + } else { + ss = *resolvedaddrs.begin(); + sslen = sizeof(ss); + } + + if (resolvedaddrs.size() > 1 && o.verbose > 1) + error("Warning: Hostname %s resolves to %d IPs. Using %s.", target_net, resolvedaddrs.size(), inet_ntop_ez(&ss, sslen)); + if (netmask) { - unsigned long longtmp = ntohl(addr.s_addr); + struct sockaddr_in *sin = (struct sockaddr_in *) &ss; + unsigned long longtmp = ntohl(sin->sin_addr.s_addr); startaddr.s_addr = longtmp & (unsigned long) (0 - (1<<(32 - netmask))); endaddr.s_addr = longtmp | (unsigned long) ((1<<(32 - netmask)) - 1); } else { diff --git a/tcpip.cc b/tcpip.cc index 807932ed3..09604cba7 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -911,23 +911,37 @@ const char *inet_socktop(struct sockaddr_storage *ss) { return buf; } -/* Tries to resolve the given name (or literal IP) into a sockaddr - structure. The af should be PF_INET (for IPv4) or PF_INET6. Returns 0 - if hostname cannot be resolved. It is OK to pass in a sockaddr_in or - sockaddr_in6 casted to a sockaddr_storage as long as you use the matching - pf.*/ -int resolve(char *hostname, struct sockaddr_storage *ss, size_t *sslen, int pf) { +/* Tries to resolve the given name (or literal IP) into a sockaddr structure. + This function calls getaddrinfo and returns the same addrinfo linked list + that getaddrinfo produces. Returns NULL for any error or failure to resolve. + You need to call freeaddrinfo on the result. */ +struct addrinfo *resolve_all(char *hostname, int pf) +{ struct addrinfo hints; struct addrinfo *result; int rc; - assert(ss); - assert(sslen); memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; + /* Otherwise we get multiple identical addresses with different socktypes. */ + hints.ai_socktype = SOCK_DGRAM; rc = getaddrinfo(hostname, NULL, &hints, &result); - if (rc != 0 || result == NULL) - return 0; + if (rc != 0) + return NULL; + + return result; +} + +/* Tries to resolve the given name (or literal IP) into a sockaddr structure. + The af should be PF_INET (for IPv4) or PF_INET6. Returns 0 if hostname + cannot be resolved. It is OK to pass in a sockaddr_in or sockaddr_in6 casted + to a sockaddr_storage as long as you use the matching pf. */ +int resolve(char *hostname, struct sockaddr_storage *ss, size_t *sslen, int pf) { + struct addrinfo *result; + + assert(ss); + assert(sslen); + result = resolve_all(hostname, pf); assert(result->ai_addrlen > 0 && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage)); *sslen = result->ai_addrlen; diff --git a/tcpip.h b/tcpip.h index c75fd2b86..d3037b4ca 100644 --- a/tcpip.h +++ b/tcpip.h @@ -435,6 +435,11 @@ struct icmp not thread-safe and can only be used once in calls like printf() */ const char *inet_socktop(struct sockaddr_storage *ss); +/* Tries to resolve the given name (or literal IP) into a sockaddr + structure. This function calls getaddrinfo and returns the same + addrinfo linked list that getaddrinfo produces. Returns NULL for any + error or failure to resolve. */ +struct addrinfo *resolve_all(char *hostname, int pf); /* Tries to resolve the given name (or literal IP) into a sockaddr structure. The af should be PF_INET (for IPv4) or PF_INET6. Returns 0 if hostname cannot be resolved. It is OK to pass in a sockaddr_in or