From 26636d3cf72173af6a95a4e34cb312dfaf422136 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 26 Nov 2010 04:06:25 +0000 Subject: [PATCH] Remember the forward DNS name and non-scanned addresses for IPv6, just as for IPv4. This makes the output more uniform and gives NSE access to host.targetname for IPv6 hosts. This is what IPv4 output looks like: $ nmap -sL www.kame.net Nmap scan report for www.kame.net (203.178.141.194) rDNS record for 203.178.141.194: orange.kame.net Nmap done: 1 IP address (0 hosts up) scanned in 0.16 seconds $ nmap -sL www.debian.org Nmap scan report for www.debian.org (128.31.0.51) Other addresses for www.debian.org (not scanned): 206.12.19.7 rDNS record for 128.31.0.51: senfl.debian.org Nmap done: 1 IP address (0 hosts up) scanned in 0.17 seconds Here is the output before this change. Notice that the target name is missing and there is no separate "rDNS" line. $ nmap -6 -sL www.kame.net Nmap scan report for 2001:200:dff:fff1:216:3eff:feb1:44d7 Nmap done: 1 IP address (0 hosts up) scanned in 0.04 seconds $ nmap -6 -sL www.debian.org Nmap scan report for bellini.debian.org (2607:f8f0:610:4000:211:25ff:fec4:5b28) Nmap done: 1 IP address (0 hosts up) scanned in 0.11 seconds Here is the output after this change: $ ./nmap -6 -sL www.kame.net Nmap scan report for www.kame.net (2001:200:dff:fff1:216:3eff:feb1:44d7) Nmap done: 1 IP address (0 hosts up) scanned in 1.04 seconds $ ./nmap -6 -sL www.debian.org Nmap scan report for www.debian.org (2607:f8f0:610:4000:211:25ff:fec4:5b28) rDNS record for 2607:f8f0:610:4000:211:25ff:fec4:5b28: bellini.debian.org Nmap done: 1 IP address (0 hosts up) scanned in 0.07 seconds --- TargetGroup.cc | 64 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/TargetGroup.cc b/TargetGroup.cc index 984864792..4b582d338 100644 --- a/TargetGroup.cc +++ b/TargetGroup.cc @@ -308,28 +308,46 @@ int TargetGroup::parse_expr(const char * const target_expr, int af) { } else { #if HAVE_IPV6 - int rc = 0; + struct addrinfo *addrs, *addr; + struct sockaddr_storage ss; + size_t sslen; + assert(af == AF_INET6); if (strchr(hostexp, '/')) { fatal("Invalid host expression: %s -- slash not allowed. IPv6 addresses can currently only be specified individually", hostexp); } + resolvedname = hostexp; + if (strchr(hostexp, ':') == NULL) + namedhost = 1; + targets_type = IPV6_ADDRESS; - struct addrinfo hints; - struct addrinfo *result = NULL; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET6; - rc = getaddrinfo(hostexp, NULL, &hints, &result); - if (rc != 0 || result == NULL) { - error("Failed to resolve given IPv6 hostname/IP: %s. Note that you can't use '/mask' or '[1-4,7,100-]' style ranges for IPv6. Error code %d: %s", hostexp, rc, gai_strerror(rc)); - free(hostexp); - if (result) freeaddrinfo(result); - return 1; + addrs = resolve_all(hostexp, AF_INET6); + for (addr = addrs; addr != NULL; addr = addr->ai_next) { + if (addr->ai_family != AF_INET6) + continue; + if (addr->ai_addrlen < sizeof(ss)) { + memcpy(&ss, addr->ai_addr, addr->ai_addrlen); + resolvedaddrs.push_back(ss); + } } - assert(result->ai_addrlen == sizeof(struct sockaddr_in6)); - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) result->ai_addr; - memcpy(&ip6, sin6, sizeof(struct sockaddr_in6)); + freeaddrinfo(addrs); + + if (resolvedaddrs.empty()) { + error("Failed to resolve given IPv6 hostname/IP: %s. Note that you can't use '/mask' or '[1-4,7,100-]' style ranges for IPv6.", hostexp); + free(hostexp); + return 1; + } else { + ss = *resolvedaddrs.begin(); + sslen = sizeof(ss); + } + + if (resolvedaddrs.size() > 1 && o.verbose > 1) + error("Warning: Hostname %s resolves to %lu IPs. Using %s.", hostexp, (unsigned long)resolvedaddrs.size(), inet_ntop_ez(&ss, sslen)); + + assert(sizeof(ip6) <= sslen); + memcpy(&ip6, &ss, sizeof(ip6)); + ipsleft = 1; - freeaddrinfo(result); #else // HAVE_IPV6 fatal("IPv6 not supported on your platform"); #endif // HAVE_IPV6 @@ -535,21 +553,17 @@ int TargetGroup::return_last_host() { netmask. */ bool TargetGroup::is_resolved_address(const struct sockaddr_storage *ss) { - const struct sockaddr_in *sin, *sin_resolved; struct sockaddr_storage resolvedaddr; - if (targets_type != IPV4_NETMASK || ss->ss_family != AF_INET - || resolvedaddrs.empty()) { + if (resolvedaddrs.empty()) + return false; + /* We only have a single distinguished address for these target types. + IPV4_RANGES doesn't, for example. */ + if (!(targets_type == IPV4_NETMASK || targets_type == IPV6_ADDRESS)) return false; - } resolvedaddr = *resolvedaddrs.begin(); - if (resolvedaddr.ss_family != AF_INET) - return false; - sin = (struct sockaddr_in *) ss; - sin_resolved = (struct sockaddr_in *) &resolvedaddr; - - return sin->sin_addr.s_addr == sin_resolved->sin_addr.s_addr; + return sockaddr_storage_cmp(&resolvedaddr, ss) == 0; } /* Return a string of the name or address that was resolved for this group. */