Skip to content

Commit

Permalink
Merge from /nmap-exp/david/nmap-ipv6.
Browse files Browse the repository at this point in the history
This is raw IPv6 packet support for most port and ping scans, Neighbor
Discovery, and traceroute.
  • Loading branch information
david committed Jun 8, 2011
1 parent b08c073 commit 4aa4a15
Show file tree
Hide file tree
Showing 39 changed files with 3,430 additions and 1,734 deletions.
44 changes: 18 additions & 26 deletions NmapOps.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ int NmapOps::SourceSockAddr(struct sockaddr_storage *ss, size_t *ss_len) {
return 0;
}

/* Returns a const pointer to the source address if set, or NULL if unset. */
const struct sockaddr_storage *NmapOps::SourceSockAddr() const {
if (sourcesock.ss_family == AF_UNSPEC)
return NULL;
else
return &sourcesock;
}

/* Note that it is OK to pass in a sockaddr_in or sockaddr_in6 casted
to sockaddr_storage */
void NmapOps::setSourceSockAddr(struct sockaddr_storage *ss, size_t ss_len) {
Expand All @@ -139,22 +147,6 @@ void NmapOps::setSourceSockAddr(struct sockaddr_storage *ss, size_t ss_len) {
sourcesocklen = ss_len;
}

struct in_addr NmapOps::v4source() {
const struct in_addr *addy = v4sourceip();
struct in_addr in;
if (addy) return *addy;
in.s_addr = 0;
return in;
}

const struct in_addr *NmapOps::v4sourceip() {
struct sockaddr_in *sin = (struct sockaddr_in *) &sourcesock;
if (sin->sin_family == AF_INET) {
return &(sin->sin_addr);
}
return NULL;
}

// Number of seconds since getStartTime(). The current time is an
// optional argument to avoid an extra gettimeofday() call.
float NmapOps::TimeSinceStart(const struct timeval *now) {
Expand Down Expand Up @@ -319,9 +311,9 @@ bool NmapOps::RawScan() {
return true;
if (pingtype & (PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS|PINGTYPE_TCP_USE_ACK|PINGTYPE_UDP|PINGTYPE_SCTP_INIT))
return true;
/* A SYN scan will only generate raw packets if nmap is running as root and is
not issuing IPv6 packets. Otherwise, it becomes a connect scan. */
if ((pingtype & PINGTYPE_TCP_USE_SYN) && (af() == AF_INET) && isr00t)
/* A SYN scan will only generate raw packets if nmap is running as root.
Otherwise, it becomes a connect scan. */
if ((pingtype & PINGTYPE_TCP_USE_SYN) && isr00t)
return true;

return false;
Expand All @@ -346,7 +338,7 @@ dialog where you can start NPF if you have administrator privileges.";

/* Insure that at least one scantype is selected */
if (!noportscan && !(TCPScan() || UDPScan() || SCTPScan() || ipprotscan)) {
if (isr00t && af() == AF_INET)
if (isr00t)
synscan++;
else connectscan++;
// if (verbose) error("No TCP, UDP, SCTP or ICMP scantype specified, assuming %s scan. Use -sn if you really don't want to portscan (and just want to see what hosts are up).", synscan? "SYN Stealth" : "vanilla tcp connect()");
Expand All @@ -369,8 +361,8 @@ dialog where you can start NPF if you have administrator privileges.";
error("WARNING: -S will only affect the source address used in a connect() scan if you specify one of your own addresses. Use -sS or another raw scan if you want to completely spoof your source address, but then you need to know what you're doing to obtain meaningful results.");
}

if ((pingtype & PINGTYPE_UDP) && (!isr00t || af() != AF_INET)) {
fatal("Sorry, UDP Ping (-PU) only works if you are root (because we need to read raw responses off the wire) and only for IPv4 (cause fyodor is too lazy right now to add IPv6 support and nobody has sent a patch)");
if ((pingtype & PINGTYPE_UDP) && (!isr00t)) {
fatal("Sorry, UDP Ping (-PU) only works if you are root (because we need to read raw responses off the wire)");
}

if ((pingtype & PINGTYPE_SCTP_INIT) && (!isr00t || af() != AF_INET)) {
Expand All @@ -389,8 +381,8 @@ dialog where you can start NPF if you have administrator privileges.";
fatal("-sL and -sn (skip port scan) are not valid with any other scan types");
}

if (af() == AF_INET6 && (pingtype & (PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS))) {
fatal("ICMP Echo, Timestamp and Address Mask pings are only valid for IPv4.");
if (af() == AF_INET6 && (pingtype & (PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS))) {
fatal("ICMP Timestamp and Address Mask pings are only valid for IPv4.");
}

if (sendpref == PACKET_SEND_NOPREF) {
Expand Down Expand Up @@ -482,8 +474,8 @@ dialog where you can start NPF if you have administrator privileges.";
fatal("--min-rate=%g must be less than or equal to --max-rate=%g", min_packet_send_rate, max_packet_send_rate);
}

if (af() == AF_INET6 && (generate_random_ips|numdecoys|osscan|bouncescan|fragscan|ackscan|finscan|idlescan|ipprotscan|maimonscan|nullscan|synscan|udpscan|windowscan|xmasscan|sctpinitscan|sctpcookieechoscan)) {
fatal("Sorry -- IPv6 support is currently only available for connect() scan (-sT), ping scan (-sn), and list scan (-sL). OS detection, random targets and decoys are also not supported with IPv6. Further support is under consideration.");
if (af() == AF_INET6 && (generate_random_ips|numdecoys|osscan|bouncescan|fragscan|idlescan|ipprotscan)) {
fatal("Sorry -- IPv6 support is currently only available for TCP, UDP, and SCTP port scans and list scan (-sL). OS detection, random targets and decoys are also not supported with IPv6. Further support is under consideration.");
}

/* Prevent performance values from getting out of whack */
Expand Down
4 changes: 2 additions & 2 deletions NmapOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ class NmapOps {
/* Returns 0 for success, nonzero if no source has been set or any other
failure */
int SourceSockAddr(struct sockaddr_storage *ss, size_t *ss_len);
/* Returns a const pointer to the source address if set, or NULL if unset. */
const struct sockaddr_storage *SourceSockAddr() const;
/* Note that it is OK to pass in a sockaddr_in or sockaddr_in6 casted
to sockaddr_storage */
void setSourceSockAddr(struct sockaddr_storage *ss, size_t ss_len);
Expand All @@ -116,8 +118,6 @@ class NmapOps {
// Number of seconds since getStartTime(). The current time is an
// optional argument to avoid an extra gettimeofday() call.
float TimeSinceStart(const struct timeval *now=NULL);
struct in_addr v4source();
const struct in_addr *v4sourceip();



Expand Down
21 changes: 21 additions & 0 deletions Target.cc
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ void Target::GenerateIPString() {
}
}

/* Returns the address family of the destination address. */
int Target::af() const {
return targetsock.ss_family;
}

/* Fills a sockaddr_storage with the AF_INET or AF_INET6 address
information of the target. This is a preferred way to get the
address since it is portable for IPv6 hosts. Returns 0 for
Expand All @@ -211,6 +216,10 @@ int Target::TargetSockAddr(struct sockaddr_storage *ss, size_t *ss_len) const {
return 0;
}

const struct sockaddr_storage *Target::TargetSockAddr() const {
return &targetsock;
}

/* Note that it is OK to pass in a sockaddr_in or sockaddr_in6 casted
to sockaddr_storage */
void Target::setTargetSockAddr(const struct sockaddr_storage *ss, size_t ss_len) {
Expand Down Expand Up @@ -247,6 +256,14 @@ const struct in_addr *Target::v4hostip() const {
return NULL;
}

const struct in6_addr *Target::v6hostip() const {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &targetsock;
if (sin6->sin6_family == AF_INET6) {
return &(sin6->sin6_addr);
}
return NULL;
}

/* The source address used to reach the target */
int Target::SourceSockAddr(struct sockaddr_storage *ss, size_t *ss_len) const {
if (sourcesocklen <= 0)
Expand All @@ -259,6 +276,10 @@ int Target::SourceSockAddr(struct sockaddr_storage *ss, size_t *ss_len) const {
return 0;
}

const struct sockaddr_storage *Target::SourceSockAddr() const {
return &sourcesock;
}

/* Note that it is OK to pass in a sockaddr_in or sockaddr_in6 casted
to sockaddr_storage */
void Target::setSourceSockAddr(const struct sockaddr_storage *ss, size_t ss_len) {
Expand Down
5 changes: 5 additions & 0 deletions Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,25 @@ class Target {
/* Recycles the object by freeing internal objects and reinitializing
to default state */
void Recycle();
/* Returns the address family of the destination address. */
int af() const;
/* Fills a sockaddr_storage with the AF_INET or AF_INET6 address
information of the target. This is a preferred way to get the
address since it is portable for IPv6 hosts. Returns 0 for
success. ss_len must be provided. It is not examined, but is set
to the size of the sockaddr copied in. */
int TargetSockAddr(struct sockaddr_storage *ss, size_t *ss_len) const;
const struct sockaddr_storage *TargetSockAddr() const;
/* Note that it is OK to pass in a sockaddr_in or sockaddr_in6 casted
to sockaddr_storage */
void setTargetSockAddr(const struct sockaddr_storage *ss, size_t ss_len);
// Returns IPv4 target host address or {0} if unavailable.
struct in_addr v4host() const;
const struct in_addr *v4hostip() const;
const struct in6_addr *v6hostip() const;
/* The source address used to reach the target */
int SourceSockAddr(struct sockaddr_storage *ss, size_t *ss_len) const;
const struct sockaddr_storage *SourceSockAddr() const;
/* Note that it is OK to pass in a sockaddr_in or sockaddr_in6 casted
to sockaddr_storage */
void setSourceSockAddr(const struct sockaddr_storage *ss, size_t ss_len);
Expand Down
18 changes: 18 additions & 0 deletions acinclude.m4
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,21 @@ int main() {
[AC_MSG_RESULT(cross-compiling -- assuming yes); $3])
])
])

dnl Checks if IPPROTO_RAW induces IP_HDRINCL-like behavior in AF_INET6 sockets.
dnl Defines HAVE_IPV6_IPPROTO_RAW if so. So far I only know this happens on
dnl Linux.
AC_DEFUN([CHECK_IPV6_IPPROTO_RAW],
[
AC_MSG_CHECKING(if AF_INET6 IPPROTO_RAW sockets include the packet header)
# This should be replaced with a better test, if possible.
case "$host" in
*-linux*)
AC_DEFINE(HAVE_IPV6_IPPROTO_RAW)
AC_MSG_RESULT(yes)
;;
*)
AC_MSG_RESULT(no)
;;
esac
])
31 changes: 31 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -5103,6 +5103,19 @@ fi

done

for ac_header in linux/rtnetlink.h
do :
ac_fn_c_check_header_compile "$LINENO" "linux/rtnetlink.h" "ac_cv_header_linux_rtnetlink_h" "#include <netinet/in.h>
"
if test "x$ac_cv_header_linux_rtnetlink_h" = x""yes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LINUX_RTNETLINK_H 1
_ACEOF

fi

done

for ac_header in sys/socket.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default"
Expand Down Expand Up @@ -5254,6 +5267,24 @@ if test "$ac_res" != no; then :
fi



{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if AF_INET6 IPPROTO_RAW sockets include the packet header" >&5
$as_echo_n "checking if AF_INET6 IPPROTO_RAW sockets include the packet header... " >&6; }
# This should be replaced with a better test, if possible.
case "$host" in
*-linux*)
$as_echo "#define HAVE_IPV6_IPPROTO_RAW 1" >>confdefs.h

{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
;;
*)
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
;;
esac


NDIFFDIR=ndiff

# Do they want Ndiff?
Expand Down
4 changes: 4 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ AC_SUBST(LUA_CFLAGS)

dnl Checks for header files.
AC_CHECK_HEADERS(pwd.h termios.h sys/sockio.h)
AC_CHECK_HEADERS(linux/rtnetlink.h,,,[#include <netinet/in.h>])
dnl A special check required for <net/if.h> on Darwin. See
dnl http://www.gnu.org/software/autoconf/manual/html_node/Header-Portability.html.
AC_CHECK_HEADERS([sys/socket.h])
Expand All @@ -195,6 +196,9 @@ dnl If any socket libraries needed
AC_SEARCH_LIBS(setsockopt, socket)
AC_SEARCH_LIBS(gethostbyname, nsl)

dnl Check IPv6 raw sending flavor.
CHECK_IPV6_IPPROTO_RAW

NDIFFDIR=ndiff

# Do they want Ndiff?
Expand Down
2 changes: 1 addition & 1 deletion docs/nmap.usage.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Nmap 5.51SVN ( http://nmap.org )
Nmap 5.52.IPv6.Beta1 ( http://nmap.org )
Usage: nmap [Scan Type(s)] [Options] {target specification}
TARGET SPECIFICATION:
Can pass hostnames, IP addresses, networks, etc.
Expand Down
13 changes: 4 additions & 9 deletions docs/refguide.xml
Original file line number Diff line number Diff line change
Expand Up @@ -558,9 +558,7 @@ you would expect.</para>
underlying TCP stack must have received a SYN/ACK or RST and
the host is marked available. If the connection attempt
is left hanging until a timeout is reached, the host is
marked as down. This workaround is also used for IPv6
connections, as raw IPv6 packet building support is not yet
available in Nmap.<indexterm><primary>IPv6</primary><secondary>limitations of</secondary></indexterm>
marked as down.
</para>

</listitem>
Expand Down Expand Up @@ -725,9 +723,6 @@ you would expect.</para>
packets.<indexterm><primary>raw packets</primary></indexterm>
Using SCTP INIT Pings is currently not possible for unprivileged
users.<indexterm><primary>unprivileged users</primary><secondary>limitations of</secondary></indexterm>
The same limitation applies to IPv6, which is currently not
supported for
SCTP INIT Ping.<indexterm><primary>IPv6</primary><secondary>limitations of</secondary></indexterm>
</para>

</listitem>
Expand Down Expand Up @@ -1125,7 +1120,7 @@ name, usually the first. The one exception to this is the deprecated
FTP bounce scan (<option>-b</option>). By default, Nmap performs a
SYN Scan, though it substitutes a connect scan if the user does not
have proper privileges to send raw packets (requires root access on
Unix) or if IPv6 targets were specified. Of the scans listed in this
Unix). Of the scans listed in this
section, unprivileged users can only execute connect and FTP bounce
scans.</para>

Expand Down Expand Up @@ -1170,7 +1165,7 @@ error (type 3, code 1, 2, 3, 9, 10, or 13) is received. The port is also consid
<listitem>
<para>TCP connect scan is the default TCP scan type when SYN scan is
not an option. This is the case when a user does not have raw packet
privileges or is scanning IPv6 networks. Instead of writing raw
privileges. Instead of writing raw
packets as most other scan types do, Nmap asks the underlying
operating system to establish a connection with the target machine and
port by issuing the <function>connect</function> system call. This is
Expand Down Expand Up @@ -3990,7 +3985,7 @@ hosts with at least one

<para>Since 2002, Nmap has offered IPv6 support for its most
popular features. In particular, ping scanning (TCP-only),
connect scanning, version detection, and the Nmap Scripting
port scanning, version detection, and the Nmap Scripting
Engine all support IPv6. The command syntax is the same as
usual except that you also add the <option>-6</option>
option. Of course, you must use IPv6 syntax if you specify
Expand Down
6 changes: 3 additions & 3 deletions idle_scan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName,
proxy->ethptr = &proxy->eth;
} else {
#ifdef WIN32
win32_warn_raw_sockets(proxy->host.deviceName());
win32_fatal_raw_sockets(proxy->host.deviceName());
#endif
if ((proxy->rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0 )
pfatal("socket troubles in %s", __func__);
Expand Down Expand Up @@ -1042,9 +1042,9 @@ void idle_scan(Target *target, u16 *portarray, int numports,
for(portidx = 0; portidx < numports; portidx++) {
if (target->ports.portIsDefault(portarray[portidx], IPPROTO_TCP)) {
target->ports.setPortState(portarray[portidx], IPPROTO_TCP, PORT_CLOSEDFILTERED);
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_NOIPIDCHANGE, 0, 0);
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_NOIPIDCHANGE, 0, NULL);
} else
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_IPIDCHANGE, 0, 0);
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_IPIDCHANGE, 0, NULL);
}

target->stopTimeOutClock(NULL);
Expand Down
12 changes: 12 additions & 0 deletions libdnet-stripped/include/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,15 @@ char *strsep(char **, const char *);
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif

/* Unix Network Programming, 3rd edition says that sockaddr structures in
rt_msghdr should be padded so their addresses start on a multiple of
sizeof(u_long). But on 64-bit Mac OS X 10.6 at least, this is false. Apple's
netstat code uses 4-byte padding, not 8-byte. This is relevant for IPv6
addresses, for which sa_len == 28.
http://www.opensource.apple.com/source/network_cmds/network_cmds-329.2.2/netstat.tproj/route.c */
#ifdef __APPLE__
#define RT_MSGHDR_ALIGNMENT sizeof(uint32_t)
#else
#define RT_MSGHDR_ALIGNMENT sizeof(unsigned long)
#endif
1 change: 1 addition & 0 deletions libdnet-stripped/include/dnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <dnet/addr.h>
#include <dnet/arp.h>
#include <dnet/icmp.h>
#include <dnet/icmpv6.h>
#include <dnet/tcp.h>
#include <dnet/udp.h>
#include <dnet/sctp.h>
Expand Down
Loading

0 comments on commit 4aa4a15

Please sign in to comment.