1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 12:41:29 +00:00

Make a new function called resolve_all in tcpip.cc, which is like

resolve except that it returns all resolved addresses. Use this new
function to resolve IPv4 addresses instead of gethostbyname in
TargetGroup.cc. The gethostbyname code assumed that only IPv4 addresses
would be returned. If the resolver returned IPv6 addresses, TargetGroup
would blindly copy the first four bytes of the IPv6 address into the
IPv4 struct. This was first reported by Mats Erik Andersson at
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=584301; he also
suggested the fix.
This commit is contained in:
david
2010-06-19 00:13:44 +00:00
parent bf9e17778c
commit d90b7b15a7
3 changed files with 57 additions and 36 deletions

View File

@@ -92,6 +92,7 @@
/* $Id$ */ /* $Id$ */
#include "tcpip.h"
#include "TargetGroup.h" #include "TargetGroup.h"
#include "NmapOps.h" #include "NmapOps.h"
#include "nmap_error.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 *r,*s, *target_net;
char *addy[5]; char *addy[5];
char *hostexp = strdup(target_expr); char *hostexp = strdup(target_expr);
struct hostent *target;
namedhost = 0; namedhost = 0;
if (targets_type != TYPE_NONE) if (targets_type != TYPE_NONE)
@@ -203,35 +203,37 @@ int TargetGroup::parse_expr(const char * const target_expr, int af) {
break; break;
} }
if (netmask != 32 || namedhost) { if (netmask != 32 || namedhost) {
struct in_addr addr; struct addrinfo *addrs, *addr;
struct sockaddr_storage ss;
size_t sslen;
targets_type = IPV4_NETMASK; targets_type = IPV4_NETMASK;
if (!inet_pton(AF_INET, target_net, &(addr))) { addrs = resolve_all(target_net, AF_INET);
if ((target = gethostbyname(target_net))) { for (addr = addrs; addr != NULL; addr = addr->ai_next) {
int count=0; if (addr->ai_family != AF_INET)
continue;
memcpy(&(addr), target->h_addr_list[0], sizeof(addr)); if (addr->ai_addrlen < sizeof(ss)) {
memcpy(&ss, addr->ai_addr, addr->ai_addrlen);
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); resolvedaddrs.push_back(ss);
count++;
} }
}
freeaddrinfo(addrs);
if (count > 1 && o.verbose > 1) if (resolvedaddrs.empty()) {
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); 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); free(hostexp);
return 1; 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) { 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))); startaddr.s_addr = longtmp & (unsigned long) (0 - (1<<(32 - netmask)));
endaddr.s_addr = longtmp | (unsigned long) ((1<<(32 - netmask)) - 1); endaddr.s_addr = longtmp | (unsigned long) ((1<<(32 - netmask)) - 1);
} else { } else {

View File

@@ -911,23 +911,37 @@ const char *inet_socktop(struct sockaddr_storage *ss) {
return buf; return buf;
} }
/* Tries to resolve the given name (or literal IP) into a sockaddr /* Tries to resolve the given name (or literal IP) into a sockaddr structure.
structure. The af should be PF_INET (for IPv4) or PF_INET6. Returns 0 This function calls getaddrinfo and returns the same addrinfo linked list
if hostname cannot be resolved. It is OK to pass in a sockaddr_in or that getaddrinfo produces. Returns NULL for any error or failure to resolve.
sockaddr_in6 casted to a sockaddr_storage as long as you use the matching You need to call freeaddrinfo on the result. */
pf.*/ struct addrinfo *resolve_all(char *hostname, int pf)
int resolve(char *hostname, struct sockaddr_storage *ss, size_t *sslen, int pf) { {
struct addrinfo hints; struct addrinfo hints;
struct addrinfo *result; struct addrinfo *result;
int rc; int rc;
assert(ss);
assert(sslen);
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = pf; hints.ai_family = pf;
/* Otherwise we get multiple identical addresses with different socktypes. */
hints.ai_socktype = SOCK_DGRAM;
rc = getaddrinfo(hostname, NULL, &hints, &result); rc = getaddrinfo(hostname, NULL, &hints, &result);
if (rc != 0 || result == NULL) if (rc != 0)
return 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 assert(result->ai_addrlen > 0
&& result->ai_addrlen <= (int) sizeof(struct sockaddr_storage)); && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage));
*sslen = result->ai_addrlen; *sslen = result->ai_addrlen;

View File

@@ -435,6 +435,11 @@ struct icmp
not thread-safe and can only be used once in calls like printf() not thread-safe and can only be used once in calls like printf()
*/ */
const char *inet_socktop(struct sockaddr_storage *ss); 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 /* 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 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 if hostname cannot be resolved. It is OK to pass in a sockaddr_in or