mirror of
https://github.com/nmap/nmap.git
synced 2025-12-10 09:49:05 +00:00
Merge from /nmap-exp/david/nmap-ipv6.
This is raw IPv6 packet support for most port and ping scans, Neighbor Discovery, and traceroute.
This commit is contained in:
44
NmapOps.cc
44
NmapOps.cc
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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()");
|
||||
@@ -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)) {
|
||||
@@ -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) {
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
|
||||
|
||||
|
||||
|
||||
21
Target.cc
21
Target.cc
@@ -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
|
||||
@@ -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) {
|
||||
@@ -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)
|
||||
@@ -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) {
|
||||
|
||||
5
Target.h
5
Target.h
@@ -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);
|
||||
|
||||
18
acinclude.m4
18
acinclude.m4
@@ -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
configure
vendored
31
configure
vendored
@@ -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"
|
||||
@@ -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?
|
||||
|
||||
@@ -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])
|
||||
@@ -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?
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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__);
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
113
libdnet-stripped/include/dnet/icmpv6.h
Normal file
113
libdnet-stripped/include/dnet/icmpv6.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* icmpv6.h
|
||||
*
|
||||
* ICMPv6.
|
||||
* RFC 4443
|
||||
*
|
||||
* $Id: $
|
||||
*/
|
||||
|
||||
#ifndef DNET_ICMPV6_H
|
||||
#define DNET_ICMPV6_H
|
||||
|
||||
#define ICMPV6_HDR_LEN 4 /* base ICMPv6 header length */
|
||||
|
||||
#ifndef __GNUC__
|
||||
#ifndef __attribute__
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
# pragma pack(1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ICMPv6 header
|
||||
*/
|
||||
struct icmpv6_hdr {
|
||||
uint8_t icmpv6_type; /* type of message, see below */
|
||||
uint8_t icmpv6_code; /* type sub code */
|
||||
uint16_t icmpv6_cksum; /* ones complement cksum of struct */
|
||||
};
|
||||
|
||||
/*
|
||||
* Types (icmpv6_type) and codes (icmpv6_code) -
|
||||
* http://www.iana.org/assignments/icmpv6-parameters
|
||||
*/
|
||||
#define ICMPV6_CODE_NONE 0 /* for types without codes */
|
||||
#define ICMPV6_UNREACH 1 /* dest unreachable, codes: */
|
||||
#define ICMPV6_UNREACH_NOROUTE 0 /* no route to dest */
|
||||
#define ICMPV6_UNREACH_PROHIB 1 /* admin prohibited */
|
||||
#define ICMPV6_UNREACH_SCOPE 2 /* beyond scope of source address */
|
||||
#define ICMPV6_UNREACH_ADDR 3 /* address unreach */
|
||||
#define ICMPV6_UNREACH_PORT 4 /* port unreach */
|
||||
#define ICMPV6_UNREACH_FILTER_PROHIB 5 /* src failed ingress/egress policy */
|
||||
#define ICMPV6_UNREACH_REJECT_ROUTE 6 /* reject route */
|
||||
#define ICMPV6_TIMEXCEED 3 /* time exceeded, code: */
|
||||
#define ICMPV6_TIMEXCEED_INTRANS 0 /* hop limit exceeded in transit */
|
||||
#define ICMPV6_TIMEXCEED_REASS 1 /* fragmetn reassembly time exceeded */
|
||||
#define ICMPV6_ECHO 128 /* echo request */
|
||||
#define ICMPV6_ECHOREPLY 129 /* echo reply */
|
||||
/*
|
||||
* Neighbor discovery types (RFC 4861)
|
||||
*/
|
||||
#define ICMPV6_NEIGHBOR_SOLICITATION 135
|
||||
#define ICMPV6_NEIGHBOR_ADVERTISEMENT 136
|
||||
|
||||
#define ICMPV6_INFOTYPE(type) (((type) & 0x80) != 0)
|
||||
|
||||
/*
|
||||
* Echo message data
|
||||
*/
|
||||
struct icmpv6_msg_echo {
|
||||
uint16_t icmpv6_id;
|
||||
uint16_t icmpv6_seq;
|
||||
uint8_t icmpv6_data __flexarr; /* optional data */
|
||||
};
|
||||
|
||||
/* Neighbor solicitation or advertisement (single hardcoded option).
|
||||
RFC 4861, sections 4.3 and 4.4. */
|
||||
struct icmpv6_msg_nd {
|
||||
uint32_t icmpv6_flags;
|
||||
ip6_addr_t icmpv6_target;
|
||||
uint8_t icmpv6_option_type;
|
||||
uint8_t icmpv6_option_length;
|
||||
eth_addr_t icmpv6_mac;
|
||||
};
|
||||
|
||||
/*
|
||||
* ICMPv6 message union
|
||||
*/
|
||||
union icmpv6_msg {
|
||||
struct icmpv6_msg_echo echo; /* ICMPV6_ECHO{REPLY} */
|
||||
struct icmpv6_msg_nd nd; /* ICMPV6_NEIGHBOR_{SOLICITATION,ADVERTISEMENT} */
|
||||
};
|
||||
|
||||
#ifndef __GNUC__
|
||||
# pragma pack()
|
||||
#endif
|
||||
|
||||
#define icmpv6_pack_hdr(hdr, type, code) do { \
|
||||
struct icmpv6_hdr *icmpv6_pack_p = (struct icmpv6_hdr *)(hdr); \
|
||||
icmpv6_pack_p->icmpv6_type = type; icmpv6_pack_p->icmpv6_code = code; \
|
||||
} while (0)
|
||||
|
||||
#define icmpv6_pack_hdr_echo(hdr, type, code, id, seq, data, len) do { \
|
||||
struct icmpv6_msg_echo *echo_pack_p = (struct icmpv6_msg_echo *)\
|
||||
((uint8_t *)(hdr) + ICMPV6_HDR_LEN); \
|
||||
icmpv6_pack_hdr(hdr, type, code); \
|
||||
echo_pack_p->icmpv6_id = htons(id); \
|
||||
echo_pack_p->icmpv6_seq = htons(seq); \
|
||||
memmove(echo_pack_p->icmpv6_data, data, len); \
|
||||
} while (0)
|
||||
|
||||
#define icmpv6_pack_hdr_ns(hdr, targetip, srcmac) do { \
|
||||
struct icmpv6_msg_nd *nd_pack_p = (struct icmpv6_msg_nd *) \
|
||||
((uint8_t *)(hdr) + ICMPV6_HDR_LEN); \
|
||||
icmpv6_pack_hdr(hdr, ICMPV6_NEIGHBOR_SOLICITATION, 0); \
|
||||
nd_pack_p->icmpv6_flags = 0; \
|
||||
memmove(&nd_pack_p->icmpv6_target, &(targetip), IP6_ADDR_LEN); \
|
||||
nd_pack_p->icmpv6_option_type = 1; \
|
||||
nd_pack_p->icmpv6_option_length = 1; \
|
||||
memmove(&nd_pack_p->icmpv6_mac, &(srcmac), ETH_ADDR_LEN); \
|
||||
} while (0)
|
||||
|
||||
#endif /* DNET_ICMPV6_H */
|
||||
@@ -138,7 +138,7 @@
|
||||
/* #undef HAVE_ROUTE_RT_MSGHDR */
|
||||
|
||||
/* Define if <netinet/in.h> has sockaddr_in6 struct. */
|
||||
// #define HAVE_SOCKADDR_IN6 1
|
||||
#define HAVE_SOCKADDR_IN6 1
|
||||
|
||||
/* Define if sockaddr struct has sa_len. */
|
||||
/* #undef HAVE_SOCKADDR_SA_LEN */
|
||||
@@ -250,6 +250,7 @@
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@
|
||||
#include <Ntddndis.h>
|
||||
|
||||
struct ifcombo {
|
||||
DWORD *idx;
|
||||
struct {
|
||||
DWORD ipv4;
|
||||
DWORD ipv6;
|
||||
} *idx;
|
||||
int cnt;
|
||||
int max;
|
||||
};
|
||||
@@ -37,8 +40,7 @@ struct ifcombo {
|
||||
|
||||
struct intf_handle {
|
||||
struct ifcombo ifcombo[MIB_IF_TYPE_MAX];
|
||||
MIB_IFTABLE *iftable;
|
||||
MIB_IPADDRTABLE *iptable;
|
||||
IP_ADAPTER_ADDRESSES *iftable;
|
||||
};
|
||||
|
||||
static char *
|
||||
@@ -46,19 +48,22 @@ _ifcombo_name(int type)
|
||||
{
|
||||
char *name = "eth"; /* XXX */
|
||||
|
||||
if (type == MIB_IF_TYPE_TOKENRING) {
|
||||
if (type == IF_TYPE_ISO88025_TOKENRING) {
|
||||
name = "tr";
|
||||
} else if (type == MIB_IF_TYPE_FDDI) {
|
||||
name = "fddi";
|
||||
} else if (type == MIB_IF_TYPE_PPP) {
|
||||
} else if (type == IF_TYPE_PPP) {
|
||||
name = "ppp";
|
||||
} else if (type == MIB_IF_TYPE_LOOPBACK) {
|
||||
} else if (type == IF_TYPE_SOFTWARE_LOOPBACK) {
|
||||
name = "lo";
|
||||
} else if (type == MIB_IF_TYPE_SLIP) {
|
||||
name = "sl";
|
||||
} else if (type == MIB_IF_TYPE_TUNNEL) {
|
||||
} else if (type == IF_TYPE_TUNNEL) {
|
||||
name = "tun";
|
||||
}
|
||||
/*
|
||||
IF_TYPE_OTHER
|
||||
IF_TYPE_ETHERNET_CSMACD
|
||||
IF_TYPE_ATM
|
||||
IF_TYPE_IEEE80211
|
||||
IF_TYPE_IEEE1394
|
||||
*/
|
||||
return (name);
|
||||
}
|
||||
|
||||
@@ -71,14 +76,10 @@ _ifcombo_type(const char *device)
|
||||
type = INTF_TYPE_ETH;
|
||||
} else if (strncmp(device, "tr", 2) == 0) {
|
||||
type = INTF_TYPE_TOKENRING;
|
||||
} else if (strncmp(device, "fd", 2) == 0) {
|
||||
type = INTF_TYPE_FDDI;
|
||||
} else if (strncmp(device, "ppp", 3) == 0) {
|
||||
type = INTF_TYPE_PPP;
|
||||
} else if (strncmp(device, "lo", 2) == 0) {
|
||||
type = INTF_TYPE_LOOPBACK;
|
||||
} else if (strncmp(device, "sl", 2) == 0) {
|
||||
type = INTF_TYPE_SLIP;
|
||||
} else if (strncmp(device, "tun", 3) == 0) {
|
||||
type = INTF_TYPE_TUN;
|
||||
}
|
||||
@@ -86,7 +87,7 @@ _ifcombo_type(const char *device)
|
||||
}
|
||||
|
||||
static void
|
||||
_ifcombo_add(struct ifcombo *ifc, DWORD idx)
|
||||
_ifcombo_add(struct ifcombo *ifc, DWORD ipv4_idx, DWORD ipv6_idx)
|
||||
{
|
||||
if (ifc->cnt == ifc->max) {
|
||||
if (ifc->idx) {
|
||||
@@ -98,17 +99,18 @@ _ifcombo_add(struct ifcombo *ifc, DWORD idx)
|
||||
ifc->idx = malloc(sizeof(ifc->idx[0]) * ifc->max);
|
||||
}
|
||||
}
|
||||
ifc->idx[ifc->cnt++] = idx;
|
||||
ifc->idx[ifc->cnt].ipv4 = ipv4_idx;
|
||||
ifc->idx[ifc->cnt].ipv6 = ipv6_idx;
|
||||
ifc->cnt++;
|
||||
}
|
||||
|
||||
/* Map an MIB_IFROW.dwType interface type into an internal interface
|
||||
type. The internal types are never exposed to users of this library;
|
||||
they exist only for the sake of ordering interface types within an
|
||||
intf_handle, which has an array of ifcombo structures ordered by
|
||||
type. Entries in an intf_handle must not be stored or accessed by a
|
||||
raw MIB_IFROW.dwType number because they will not be able to be found
|
||||
by a device name such as "net0" if the device name does not map
|
||||
exactly to the dwType. */
|
||||
/* Map an MIB interface type into an internal interface type. The
|
||||
internal types are never exposed to users of this library; they exist
|
||||
only for the sake of ordering interface types within an intf_handle,
|
||||
which has an array of ifcombo structures ordered by type. Entries in
|
||||
an intf_handle must not be stored or accessed by a raw MIB type
|
||||
number because they will not be able to be found by a device name
|
||||
such as "net0" if the device name does not map exactly to the type. */
|
||||
static int
|
||||
_if_type_canonicalize(int type)
|
||||
{
|
||||
@@ -116,11 +118,13 @@ _if_type_canonicalize(int type)
|
||||
}
|
||||
|
||||
static void
|
||||
_ifrow_to_entry(intf_t *intf, MIB_IFROW *ifrow, struct intf_entry *entry)
|
||||
_adapter_address_to_entry(intf_t *intf, IP_ADAPTER_ADDRESSES *a,
|
||||
struct intf_entry *entry)
|
||||
{
|
||||
struct addr *ap, *lap;
|
||||
int i;
|
||||
int type;
|
||||
IP_ADAPTER_UNICAST_ADDRESS *addr;
|
||||
|
||||
/* The total length of the entry may be passed inside entry.
|
||||
Remember it and clear the entry. */
|
||||
@@ -128,59 +132,68 @@ _ifrow_to_entry(intf_t *intf, MIB_IFROW *ifrow, struct intf_entry *entry)
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->intf_len = intf_len;
|
||||
|
||||
type = _if_type_canonicalize(ifrow->dwType);
|
||||
type = _if_type_canonicalize(a->IfType);
|
||||
for (i = 0; i < intf->ifcombo[type].cnt; i++) {
|
||||
if (intf->ifcombo[type].idx[i] == ifrow->dwIndex)
|
||||
if (intf->ifcombo[type].idx[i].ipv4 == a->IfIndex &&
|
||||
intf->ifcombo[type].idx[i].ipv6 == a->Ipv6IfIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* XXX - type matches MIB-II ifType. */
|
||||
snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
|
||||
_ifcombo_name(type), i);
|
||||
_ifcombo_name(a->IfType), i);
|
||||
entry->intf_type = (uint16_t)type;
|
||||
|
||||
/* Get interface flags. */
|
||||
entry->intf_flags = 0;
|
||||
if (ifrow->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP &&
|
||||
(ifrow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
|
||||
ifrow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED))
|
||||
if (a->OperStatus == IfOperStatusUp)
|
||||
entry->intf_flags |= INTF_FLAG_UP;
|
||||
if (ifrow->dwType == MIB_IF_TYPE_LOOPBACK)
|
||||
if (a->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
|
||||
entry->intf_flags |= INTF_FLAG_LOOPBACK;
|
||||
else
|
||||
entry->intf_flags |= INTF_FLAG_MULTICAST;
|
||||
|
||||
/* Get interface MTU. */
|
||||
entry->intf_mtu = ifrow->dwMtu;
|
||||
entry->intf_mtu = a->Mtu;
|
||||
|
||||
/* Get hardware address. */
|
||||
if (ifrow->dwPhysAddrLen == ETH_ADDR_LEN) {
|
||||
if (a->PhysicalAddressLength == ETH_ADDR_LEN) {
|
||||
entry->intf_link_addr.addr_type = ADDR_TYPE_ETH;
|
||||
entry->intf_link_addr.addr_bits = ETH_ADDR_BITS;
|
||||
memcpy(&entry->intf_link_addr.addr_eth, ifrow->bPhysAddr,
|
||||
memcpy(&entry->intf_link_addr.addr_eth, a->PhysicalAddress,
|
||||
ETH_ADDR_LEN);
|
||||
}
|
||||
/* Get addresses. */
|
||||
ap = entry->intf_alias_addrs;
|
||||
lap = ap + ((entry->intf_len - sizeof(*entry)) /
|
||||
sizeof(entry->intf_alias_addrs[0]));
|
||||
for (i = 0; i < (int)intf->iptable->dwNumEntries; i++) {
|
||||
if (intf->iptable->table[i].dwIndex == ifrow->dwIndex &&
|
||||
intf->iptable->table[i].dwAddr != 0) {
|
||||
for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) {
|
||||
IP_ADAPTER_PREFIX *prefix;
|
||||
unsigned short bits;
|
||||
|
||||
/* Find the netmask length. This is stored in a parallel list.
|
||||
We just take the first one with a matching address family,
|
||||
but that may not be right. Windows Vista and later has an
|
||||
OnLinkPrefixLength member that is stored right with the
|
||||
unicast address. */
|
||||
bits = 0;
|
||||
for (prefix = a->FirstPrefix; prefix != NULL; prefix = prefix->Next) {
|
||||
if (prefix->Address.lpSockaddr->sa_family == addr->Address.lpSockaddr->sa_family) {
|
||||
bits = (unsigned short) prefix->PrefixLength;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->intf_addr.addr_type == ADDR_TYPE_NONE) {
|
||||
/* Set primary address if unset. */
|
||||
entry->intf_addr.addr_type = ADDR_TYPE_IP;
|
||||
entry->intf_addr.addr_ip =
|
||||
intf->iptable->table[i].dwAddr;
|
||||
addr_mtob(&intf->iptable->table[i].dwMask,
|
||||
IP_ADDR_LEN, &entry->intf_addr.addr_bits);
|
||||
addr_ston(addr->Address.lpSockaddr, &entry->intf_addr);
|
||||
entry->intf_addr.addr_bits = bits;
|
||||
} else if (ap < lap) {
|
||||
/* Set aliases. */
|
||||
ap->addr_type = ADDR_TYPE_IP;
|
||||
ap->addr_ip = intf->iptable->table[i].dwAddr;
|
||||
addr_mtob(&intf->iptable->table[i].dwMask,
|
||||
IP_ADDR_LEN, &ap->addr_bits);
|
||||
ap++, entry->intf_alias_num++;
|
||||
}
|
||||
addr_ston(addr->Address.lpSockaddr, ap);
|
||||
ap->addr_bits = bits;
|
||||
ap++;
|
||||
entry->intf_alias_num++;
|
||||
}
|
||||
}
|
||||
entry->intf_len = (u_int) ((u_char *)ap - (u_char *)entry);
|
||||
@@ -189,58 +202,59 @@ _ifrow_to_entry(intf_t *intf, MIB_IFROW *ifrow, struct intf_entry *entry)
|
||||
static int
|
||||
_refresh_tables(intf_t *intf)
|
||||
{
|
||||
MIB_IFROW *ifrow;
|
||||
IP_ADAPTER_ADDRESSES *p;
|
||||
DWORD ret;
|
||||
ULONG len;
|
||||
u_int i, ret;
|
||||
|
||||
/* Get interface table. */
|
||||
for (len = sizeof(intf->iftable[0]); ; ) {
|
||||
if (intf->iftable)
|
||||
free(intf->iftable);
|
||||
intf->iftable = malloc(len);
|
||||
ret = GetIfTable(intf->iftable, &len, FALSE);
|
||||
if (ret == NO_ERROR)
|
||||
break;
|
||||
else if (ret != ERROR_INSUFFICIENT_BUFFER)
|
||||
return (-1);
|
||||
}
|
||||
/* Get IP address table. */
|
||||
for (len = sizeof(intf->iptable[0]); ; ) {
|
||||
if (intf->iptable)
|
||||
free(intf->iptable);
|
||||
intf->iptable = malloc(len);
|
||||
ret = GetIpAddrTable(intf->iptable, &len, FALSE);
|
||||
if (ret == NO_ERROR)
|
||||
break;
|
||||
else if (ret != ERROR_INSUFFICIENT_BUFFER)
|
||||
p = NULL;
|
||||
len = 2;
|
||||
do {
|
||||
free(p);
|
||||
p = malloc(len);
|
||||
if (p == NULL)
|
||||
return (-1);
|
||||
ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, NULL, p, &len);
|
||||
} while (ret == ERROR_BUFFER_OVERFLOW);
|
||||
|
||||
if (ret != NO_ERROR) {
|
||||
free(p);
|
||||
return (-1);
|
||||
}
|
||||
intf->iftable = p;
|
||||
|
||||
/*
|
||||
* Map "unfriendly" win32 interface indices to ours.
|
||||
* XXX - like IP_ADAPTER_INFO ComboIndex
|
||||
*/
|
||||
for (i = 0; i < intf->iftable->dwNumEntries; i++) {
|
||||
for (p = intf->iftable; p != NULL; p = p->Next) {
|
||||
int type;
|
||||
ifrow = &intf->iftable->table[i];
|
||||
type = _if_type_canonicalize(ifrow->dwType);
|
||||
if (type < MIB_IF_TYPE_MAX) {
|
||||
_ifcombo_add(&intf->ifcombo[type], ifrow->dwIndex);
|
||||
} else
|
||||
type = _if_type_canonicalize(p->IfType);
|
||||
if (type < MIB_IF_TYPE_MAX)
|
||||
_ifcombo_add(&intf->ifcombo[type], p->IfIndex, p->Ipv6IfIndex);
|
||||
else
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
_find_ifindex(intf_t *intf, const char *device)
|
||||
static IP_ADAPTER_ADDRESSES *
|
||||
_find_adapter_address(intf_t *intf, const char *device)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES *a;
|
||||
char *p = (char *)device;
|
||||
int n, type = _ifcombo_type(device);
|
||||
|
||||
while (isalpha((int) (unsigned char) *p)) p++;
|
||||
n = atoi(p);
|
||||
|
||||
return (intf->ifcombo[type].idx[n]);
|
||||
for (a = intf->iftable; a != NULL; a = a->Next) {
|
||||
if (intf->ifcombo[type].idx[n].ipv4 == a->IfIndex &&
|
||||
intf->ifcombo[type].idx[n].ipv6 == a->Ipv6IfIndex) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
intf_t *
|
||||
@@ -252,17 +266,16 @@ intf_open(void)
|
||||
int
|
||||
intf_get(intf_t *intf, struct intf_entry *entry)
|
||||
{
|
||||
MIB_IFROW ifrow;
|
||||
IP_ADAPTER_ADDRESSES *a;
|
||||
|
||||
if (_refresh_tables(intf) < 0)
|
||||
return (-1);
|
||||
|
||||
ifrow.dwIndex = _find_ifindex(intf, entry->intf_name);
|
||||
|
||||
if (GetIfEntry(&ifrow) != NO_ERROR)
|
||||
a = _find_adapter_address(intf, entry->intf_name);
|
||||
if (a == NULL)
|
||||
return (-1);
|
||||
|
||||
_ifrow_to_entry(intf, &ifrow, entry);
|
||||
_adapter_address_to_entry(intf, a, entry);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -270,9 +283,8 @@ intf_get(intf_t *intf, struct intf_entry *entry)
|
||||
int
|
||||
intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src)
|
||||
{
|
||||
MIB_IFROW ifrow;
|
||||
MIB_IPADDRROW *iprow;
|
||||
int i;
|
||||
IP_ADAPTER_ADDRESSES *a;
|
||||
IP_ADAPTER_UNICAST_ADDRESS *addr;
|
||||
|
||||
if (src->addr_type != ADDR_TYPE_IP) {
|
||||
errno = EINVAL;
|
||||
@@ -281,16 +293,17 @@ intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src)
|
||||
if (_refresh_tables(intf) < 0)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < (int)intf->iptable->dwNumEntries; i++) {
|
||||
iprow = &intf->iptable->table[i];
|
||||
if (iprow->dwAddr == src->addr_ip) {
|
||||
ifrow.dwIndex = iprow->dwIndex;
|
||||
if (GetIfEntry(&ifrow) != NO_ERROR)
|
||||
return (-1);
|
||||
_ifrow_to_entry(intf, &ifrow, entry);
|
||||
for (a = intf->iftable; a != NULL; a = a->Next) {
|
||||
for (addr = a->FirstUnicastAddress; addr != NULL; addr = addr->Next) {
|
||||
struct addr dnet_addr;
|
||||
|
||||
addr_ston(addr->Address.lpSockaddr, &dnet_addr);
|
||||
if (addr_cmp(&dnet_addr, src) == 0) {
|
||||
_adapter_address_to_entry(intf, a, entry);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
errno = ENXIO;
|
||||
return (-1);
|
||||
}
|
||||
@@ -298,25 +311,10 @@ intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src)
|
||||
int
|
||||
intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst)
|
||||
{
|
||||
MIB_IFROW ifrow;
|
||||
|
||||
if (dst->addr_type != ADDR_TYPE_IP) {
|
||||
errno = EINVAL;
|
||||
errno = ENOSYS;
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return (-1);
|
||||
}
|
||||
if (GetBestInterface(dst->addr_ip, &ifrow.dwIndex) != NO_ERROR)
|
||||
return (-1);
|
||||
|
||||
if (GetIfEntry(&ifrow) != NO_ERROR)
|
||||
return (-1);
|
||||
|
||||
if (_refresh_tables(intf) < 0)
|
||||
return (-1);
|
||||
|
||||
_ifrow_to_entry(intf, &ifrow, entry);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
intf_set(intf_t *intf, const struct intf_entry *entry)
|
||||
@@ -326,23 +324,6 @@ intf_set(intf_t *intf, const struct intf_entry *entry)
|
||||
* but what about the rest of the configuration? :-(
|
||||
* {Add,Delete}IPAddress for 2000/XP only
|
||||
*/
|
||||
#if 0
|
||||
/* Set interface address. XXX - 2000/XP only? */
|
||||
if (entry->intf_addr.addr_type == ADDR_TYPE_IP) {
|
||||
ULONG ctx = 0, inst = 0;
|
||||
UINT ip, mask;
|
||||
|
||||
memcpy(&ip, &entry->intf_addr.addr_ip, IP_ADDR_LEN);
|
||||
addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN);
|
||||
|
||||
if (AddIPAddress(ip, mask,
|
||||
_find_ifindex(intf, entry->intf_name),
|
||||
&ctx, &inst) != NO_ERROR) {
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
errno = ENOSYS;
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return (-1);
|
||||
@@ -351,18 +332,19 @@ intf_set(intf_t *intf, const struct intf_entry *entry)
|
||||
int
|
||||
intf_loop(intf_t *intf, intf_handler callback, void *arg)
|
||||
{
|
||||
IP_ADAPTER_ADDRESSES *a;
|
||||
struct intf_entry *entry;
|
||||
u_char ebuf[1024];
|
||||
int i, ret = 0;
|
||||
int ret;
|
||||
|
||||
if (_refresh_tables(intf) < 0)
|
||||
return (-1);
|
||||
|
||||
entry = (struct intf_entry *)ebuf;
|
||||
|
||||
for (i = 0; i < (int)intf->iftable->dwNumEntries; i++) {
|
||||
for (a = intf->iftable; a != NULL; a = a->Next) {
|
||||
entry->intf_len = sizeof(ebuf);
|
||||
_ifrow_to_entry(intf, &intf->iftable->table[i], entry);
|
||||
_adapter_address_to_entry(intf, a, entry);
|
||||
if ((ret = (*callback)(entry, arg)) != 0)
|
||||
break;
|
||||
}
|
||||
@@ -381,8 +363,6 @@ intf_close(intf_t *intf)
|
||||
}
|
||||
if (intf->iftable)
|
||||
free(intf->iftable);
|
||||
if (intf->iptable)
|
||||
free(intf->iptable);
|
||||
free(intf);
|
||||
}
|
||||
return (NULL);
|
||||
@@ -394,11 +374,10 @@ intf_close(intf_t *intf)
|
||||
int
|
||||
intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen)
|
||||
{
|
||||
wchar_t descr_wc[512];
|
||||
IP_ADAPTER_ADDRESSES *a;
|
||||
pcap_if_t *pcapdevs;
|
||||
pcap_if_t *pdev, *selected;
|
||||
intf_t *intf;
|
||||
MIB_IFROW ifrow;
|
||||
|
||||
if ((intf = intf_open()) == NULL)
|
||||
return (-1);
|
||||
@@ -406,77 +385,36 @@ intf_get_pcap_devname(const char *intf_name, char *pcapdev, int pcapdevlen)
|
||||
intf_close(intf);
|
||||
return (-1);
|
||||
}
|
||||
ifrow.dwIndex = _find_ifindex(intf, intf_name);
|
||||
a = _find_adapter_address(intf, intf_name);
|
||||
|
||||
if (a == NULL) {
|
||||
intf_close(intf);
|
||||
|
||||
if (GetIfEntry(&ifrow) != NO_ERROR)
|
||||
return (-1);
|
||||
|
||||
/* OID_GEN_FRIENDLY_NAME returns a wide-character string, so convert
|
||||
the description to wide characters for string comparison. */
|
||||
mbstowcs(descr_wc, ifrow.bDescr, sizeof(descr_wc) / sizeof(descr_wc[0]) - 1);
|
||||
descr_wc[sizeof(descr_wc) / sizeof(descr_wc[0]) - 1] = L'\0';
|
||||
|
||||
if (pcap_findalldevs(&pcapdevs, NULL) == -1)
|
||||
return (-1);
|
||||
|
||||
/* Loop through all the pcap devices until we find a match. pcap gets
|
||||
its interface list from the registry; dnet gets it from GetIfList.
|
||||
We must match them up using values common to both data sets. We do
|
||||
it by comparing hardware addresses and interface descriptions. */
|
||||
selected = NULL;
|
||||
for (pdev = pcapdevs; pdev != NULL; pdev = pdev->next) {
|
||||
PACKET_OID_DATA *data;
|
||||
u_char buf[512];
|
||||
LPADAPTER lpa;
|
||||
|
||||
lpa = PacketOpenAdapter(pdev->name);
|
||||
if (lpa == NULL)
|
||||
continue;
|
||||
if (lpa->hFile == INVALID_HANDLE_VALUE)
|
||||
goto close_adapter;
|
||||
|
||||
data = (PACKET_OID_DATA *) buf;
|
||||
|
||||
/* Check the MAC address if available. */
|
||||
data->Oid = OID_802_3_CURRENT_ADDRESS;
|
||||
data->Length = sizeof(buf) - sizeof(*data);
|
||||
if (!PacketRequest(lpa, FALSE, data))
|
||||
goto close_adapter;
|
||||
if (data->Length != ifrow.dwPhysAddrLen)
|
||||
goto close_adapter;
|
||||
if (memcmp(ifrow.bPhysAddr, data->Data, data->Length) != 0)
|
||||
goto close_adapter;
|
||||
|
||||
/* A hardware address match is good enough, but we will prefer
|
||||
an additional match with the description if available. */
|
||||
if (selected == NULL)
|
||||
selected = pdev;
|
||||
|
||||
/* Distinct interfaces can have the same MAC address in the
|
||||
case of "teamed" interfaces. Additionally check the
|
||||
description string. */
|
||||
data->Oid = OID_GEN_FRIENDLY_NAME;
|
||||
data->Length = sizeof(buf) - sizeof(*data);
|
||||
if (PacketRequest(lpa, FALSE, data) != TRUE)
|
||||
goto close_adapter;
|
||||
if (wcscmp(descr_wc, (wchar_t *) data->Data) != 0)
|
||||
goto close_adapter;
|
||||
|
||||
/* This matches both the hardware address and description, so
|
||||
it's the best candidate. */
|
||||
selected = pdev;
|
||||
PacketCloseAdapter(lpa);
|
||||
break;
|
||||
|
||||
close_adapter:
|
||||
PacketCloseAdapter(lpa);
|
||||
}
|
||||
|
||||
if (selected != NULL)
|
||||
strlcpy(pcapdev, selected->name, pcapdevlen);
|
||||
if (pcap_findalldevs(&pcapdevs, NULL) == -1) {
|
||||
intf_close(intf);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Loop through all the pcap devices until we find a match. */
|
||||
selected = NULL;
|
||||
for (pdev = pcapdevs; pdev != NULL; pdev = pdev->next) {
|
||||
char *name;
|
||||
|
||||
if (pdev->name == NULL)
|
||||
continue;
|
||||
name = strchr(pdev->name, '{');
|
||||
if (name == NULL)
|
||||
continue;
|
||||
if (strcmp(name, a->AdapterName) == 0)
|
||||
break;
|
||||
}
|
||||
if (pdev != NULL)
|
||||
strlcpy(pcapdev, pdev->name, pcapdevlen);
|
||||
intf_close(intf);
|
||||
pcap_freealldevs(pcapdevs);
|
||||
if (selected == NULL)
|
||||
if (pdev == NULL)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#include "dnet.h"
|
||||
|
||||
#define ROUNDUP(a) \
|
||||
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
|
||||
((a) > 0 ? (1 + (((a) - 1) | (RT_MSGHDR_ALIGNMENT - 1))) : RT_MSGHDR_ALIGNMENT)
|
||||
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
#define NEXTSA(s) \
|
||||
|
||||
@@ -228,9 +228,6 @@ route_loop(route_t *r, route_handler callback, void *arg)
|
||||
if (i < 10 || !(iflags & RTF_UP))
|
||||
continue;
|
||||
|
||||
if (entry.route_gw.addr_ip == IP_ADDR_ANY)
|
||||
continue;
|
||||
|
||||
entry.route_dst.addr_type = entry.route_gw.addr_type =
|
||||
ADDR_TYPE_IP;
|
||||
|
||||
|
||||
@@ -21,14 +21,23 @@
|
||||
|
||||
#include "dnet.h"
|
||||
|
||||
typedef DWORD (WINAPI *GETIPFORWARDTABLE2)(ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2 *);
|
||||
|
||||
struct route_handle {
|
||||
HINSTANCE iphlpapi;
|
||||
MIB_IPFORWARDTABLE *ipftable;
|
||||
MIB_IPFORWARD_TABLE2 *ipftable2;
|
||||
};
|
||||
|
||||
route_t *
|
||||
route_open(void)
|
||||
{
|
||||
return (calloc(1, sizeof(route_t)));
|
||||
route_t *r;
|
||||
|
||||
r = calloc(1, sizeof(route_t));
|
||||
r->iphlpapi = GetModuleHandle("iphlpapi.dll");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -113,8 +122,8 @@ route_get(route_t *route, struct route_entry *entry)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
route_loop(route_t *r, route_handler callback, void *arg)
|
||||
static int
|
||||
route_loop_getipforwardtable(route_t *r, route_handler callback, void *arg)
|
||||
{
|
||||
struct route_entry entry;
|
||||
ULONG len;
|
||||
@@ -149,12 +158,59 @@ route_loop(route_t *r, route_handler callback, void *arg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
route_loop_getipforwardtable2(GETIPFORWARDTABLE2 GetIpForwardTable2,
|
||||
route_t *r, route_handler callback, void *arg)
|
||||
{
|
||||
struct route_entry entry;
|
||||
ULONG i;
|
||||
int ret;
|
||||
|
||||
ret = GetIpForwardTable2(AF_UNSPEC, &r->ipftable2);
|
||||
if (ret != NO_ERROR)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < r->ipftable2->NumEntries; i++) {
|
||||
MIB_IPFORWARD_ROW2 *row;
|
||||
char buf[100];
|
||||
|
||||
row = &r->ipftable2->Table[i];
|
||||
addr_ston((struct sockaddr *) &row->DestinationPrefix.Prefix, &entry.route_dst);
|
||||
entry.route_dst.addr_bits = row->DestinationPrefix.PrefixLength;
|
||||
addr_ston((struct sockaddr *) &row->NextHop, &entry.route_gw);
|
||||
|
||||
if ((ret = (*callback)(&entry, arg)) != 0)
|
||||
return (ret);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
route_loop(route_t *r, route_handler callback, void *arg)
|
||||
{
|
||||
GETIPFORWARDTABLE2 GetIpForwardTable2;
|
||||
|
||||
/* GetIpForwardTable2 is only available on Vista and later, dynamic load. */
|
||||
GetIpForwardTable2 = NULL;
|
||||
if (r->iphlpapi != NULL)
|
||||
GetIpForwardTable2 = (GETIPFORWARDTABLE2) GetProcAddress(r->iphlpapi, "GetIpForwardTable2");
|
||||
|
||||
if (GetIpForwardTable2 == NULL)
|
||||
return route_loop_getipforwardtable(r, callback, arg);
|
||||
else
|
||||
return route_loop_getipforwardtable2(GetIpForwardTable2, r, callback, arg);
|
||||
}
|
||||
|
||||
route_t *
|
||||
route_close(route_t *r)
|
||||
{
|
||||
if (r != NULL) {
|
||||
if (r->iphlpapi != NULL)
|
||||
FreeLibrary(r->iphlpapi);
|
||||
if (r->ipftable != NULL)
|
||||
free(r->ipftable);
|
||||
if (r->ipftable2 != NULL)
|
||||
FreeMibTable(r->ipftable2);
|
||||
free(r);
|
||||
}
|
||||
return (NULL);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,17 @@ enum { OP_FAILURE = -1, OP_SUCCESS = 0 };
|
||||
#define IPPROTO_SCTP 132
|
||||
#endif
|
||||
|
||||
/* Container used for information common to IPv4 and IPv6 headers, used by
|
||||
ip_get_data. */
|
||||
struct abstract_ip_hdr {
|
||||
u8 version; /* 4 or 6. */
|
||||
struct sockaddr_storage src;
|
||||
struct sockaddr_storage dst;
|
||||
u8 proto; /* IPv4 proto or IPv6 next header. */
|
||||
u8 ttl; /* IPv4 TTL or IPv6 hop limit. */
|
||||
u8 ipid; /* IPv4 IP ID or IPv6 flow label. */
|
||||
};
|
||||
|
||||
void netutil_fatal(const char *str, ...)
|
||||
__attribute__ ((noreturn))
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
@@ -181,6 +192,17 @@ int ip_is_reserved(struct in_addr *ip);
|
||||
int arp_cache_get(struct sockaddr_storage *ss, u8 *mac);
|
||||
int arp_cache_set(struct sockaddr_storage *ss, u8 *mac);
|
||||
|
||||
const void *ip_get_data(const void *packet, unsigned int *len,
|
||||
struct abstract_ip_hdr *hdr);
|
||||
/* Get the upper-layer protocol from an IPv4 packet. */
|
||||
const void *ipv4_get_data(const struct ip *ip, unsigned int *len);
|
||||
/* Get the upper-layer protocol from an IPv6 packet. This skips over known
|
||||
extension headers. The length of the upper-layer payload is stored in *len.
|
||||
The protocol is stored in *nxt. Returns NULL in case of error. */
|
||||
const void *ipv6_get_data(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt);
|
||||
const void *icmp_get_data(const struct icmp_hdr *icmp, unsigned int *len);
|
||||
const void *icmpv6_get_data(const struct icmpv6_hdr *icmpv6, unsigned int *len);
|
||||
|
||||
/* Standard BSD internet checksum routine. */
|
||||
unsigned short in_cksum(u16 *ptr, int nbytes);
|
||||
|
||||
@@ -190,6 +212,11 @@ unsigned short in_cksum(u16 *ptr, int nbytes);
|
||||
unsigned short ipv4_pseudoheader_cksum(const struct in_addr *src,
|
||||
const struct in_addr *dst, u8 proto, u16 len, const void *hstart);
|
||||
|
||||
/* Calculate the Internet checksum of some given data concatenated with the
|
||||
IPv6 pseudo-header. See RFC 2460 section 8.1. */
|
||||
u16 ipv6_pseudoheader_cksum(const struct in6_addr *src,
|
||||
const struct in6_addr *dst, u8 nxt, u32 len, const void *hstart);
|
||||
|
||||
void sethdrinclude(int sd);
|
||||
void set_ipoptions(int sd, void *opts, size_t optslen);
|
||||
void set_ttl(int sd, int ttl);
|
||||
@@ -253,9 +280,9 @@ struct route_nfo {
|
||||
|
||||
struct sys_route {
|
||||
struct interface_info *device;
|
||||
u32 dest;
|
||||
u32 netmask;
|
||||
struct in_addr gw; /* gateway - 0 if none */
|
||||
struct sockaddr_storage dest;
|
||||
u16 netmask_bits;
|
||||
struct sockaddr_storage gw; /* gateway - 0 if none */
|
||||
};
|
||||
|
||||
struct eth_nfo {
|
||||
@@ -295,11 +322,19 @@ void tcppacketoptinfo(u8 *optp, int len, char *result, int bufsize);
|
||||
/* Convert an IP address to the device (IE ppp0 eth0) using that
|
||||
* address. Supplied "dev" must be able to hold at least 32 bytes.
|
||||
* Returns 0 on success or -1 in case of error. */
|
||||
int ipaddr2devname( char *dev, const struct in_addr *addr );
|
||||
int ipaddr2devname( char *dev, const struct sockaddr_storage *addr );
|
||||
|
||||
/* Convert a network interface name (IE ppp0 eth0) to an IPv4 address.
|
||||
/* Convert a network interface name (IE ppp0 eth0) to an IP address.
|
||||
* Returns 0 on success or -1 in case of error. */
|
||||
int devname2ipaddr(char *dev, struct in_addr *addr);
|
||||
int devname2ipaddr(char *dev, struct sockaddr_storage *addr);
|
||||
|
||||
int sockaddr_equal(const struct sockaddr_storage *a,
|
||||
const struct sockaddr_storage *b);
|
||||
|
||||
int sockaddr_equal_netmask(const struct sockaddr_storage *a,
|
||||
const struct sockaddr_storage *b, u16 nbits);
|
||||
|
||||
int sockaddr_equal_zero(const struct sockaddr_storage *s);
|
||||
|
||||
/* Returns an allocated array of struct interface_info representing the
|
||||
available interfaces. The number of interfaces is returned in *howmany. This
|
||||
@@ -392,7 +427,7 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail);
|
||||
* it should still be passed. Note that it's OK to pass either NULL or
|
||||
* an empty string as the "device", as long as spoofss==NULL. */
|
||||
int route_dst(const struct sockaddr_storage * const dst, struct route_nfo *rnfo,
|
||||
char *device, struct sockaddr_storage *spoofss);
|
||||
const char *device, const struct sockaddr_storage *spoofss);
|
||||
|
||||
/* Send an IP packet over a raw socket. */
|
||||
int send_ip_packet_sd(int sd, u8 *packet, unsigned int packetlen);
|
||||
@@ -405,6 +440,9 @@ int send_ip_packet_eth(struct eth_nfo *eth, u8 *packet, unsigned int packetlen);
|
||||
* ethernet level. */
|
||||
int send_ip_packet_eth_or_sd(int sd, struct eth_nfo *eth, u8 *packet, unsigned int packetlen);
|
||||
|
||||
/* Sends an IPv4 packet. */
|
||||
int send_ipv6_packet_eth_or_sd(int sd, struct eth_nfo *eth, const u8 *packet, unsigned int len);
|
||||
|
||||
/* Create and send all fragments of a pre-built IPv4 packet.
|
||||
* Minimal MTU for IPv4 is 68 and maximal IPv4 header size is 60
|
||||
* which gives us a right to cut TCP header after 8th byte */
|
||||
@@ -443,6 +481,23 @@ bool doArp(const char *dev, const u8 *srcmac,
|
||||
u8 *targetmac,
|
||||
void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *));
|
||||
|
||||
|
||||
/* Issues an Neighbor Solicitation for the MAC of targetss (which will be placed
|
||||
in targetmac if obtained) from the source IP (srcip) and source mac
|
||||
(srcmac) given. "The request is ussued using device dev to the
|
||||
multicast MAC address. The transmission is attempted up to 3
|
||||
times. If none of these elicit a response, false will be returned.
|
||||
If the mac is determined, true is returned. The last parameter is
|
||||
a pointer to a callback function that can be used for packet tracing.
|
||||
This is intended to be used by Nmap only. Any other calling this
|
||||
should pass NULL instead. */
|
||||
bool doND(const char *dev, const u8 *srcmac,
|
||||
const struct sockaddr_storage *srcip,
|
||||
const struct sockaddr_storage *targetip,
|
||||
u8 *targetmac,
|
||||
void (*traceArp_callback)(int, const u8 *, u32 , struct timeval *)
|
||||
) ;
|
||||
|
||||
/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
|
||||
descriptor pd. If it receives one, fills in sendermac (must pass
|
||||
in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
|
||||
|
||||
66
nmap.cc
66
nmap.cc
@@ -382,20 +382,24 @@ static unsigned short *merge_port_lists(unsigned short *port_list1, int count1,
|
||||
|
||||
void validate_scan_lists(scan_lists &ports, NmapOps &o){
|
||||
if (o.pingtype == PINGTYPE_UNKNOWN) {
|
||||
if (o.isr00t && o.pf() == PF_INET) {
|
||||
o.pingtype = DEFAULT_PING_TYPES;
|
||||
if (o.isr00t) {
|
||||
if (o.pf() == PF_INET){
|
||||
o.pingtype = DEFAULT_IPV4_PING_TYPES;
|
||||
} else {
|
||||
o.pingtype = DEFAULT_IPV6_PING_TYPES;
|
||||
}
|
||||
getpts_simple(DEFAULT_PING_ACK_PORT_SPEC, SCAN_TCP_PORT,
|
||||
&ports.ack_ping_ports, &ports.ack_ping_count);
|
||||
getpts_simple(DEFAULT_PING_SYN_PORT_SPEC, SCAN_TCP_PORT,
|
||||
&ports.syn_ping_ports, &ports.syn_ping_count);
|
||||
} else {
|
||||
o.pingtype = PINGTYPE_TCP; // if nonr00t or IPv6
|
||||
o.pingtype = PINGTYPE_TCP; // if nonr00t
|
||||
getpts_simple(DEFAULT_PING_CONNECT_PORT_SPEC, SCAN_TCP_PORT,
|
||||
&ports.syn_ping_ports, &ports.syn_ping_count);
|
||||
}
|
||||
}
|
||||
|
||||
if ((o.pingtype & PINGTYPE_TCP) && (!o.isr00t || o.pf() != PF_INET)) {
|
||||
if ((o.pingtype & PINGTYPE_TCP) && (!o.isr00t)) {
|
||||
// We will have to do a connect() style ping
|
||||
// Pretend we wanted SYN probes all along.
|
||||
if (ports.ack_ping_count > 0) {
|
||||
@@ -629,6 +633,8 @@ int nmap_main(int argc, char *argv[]) {
|
||||
{"adler32", no_argument, 0, 0},
|
||||
{"stats_every", required_argument, 0, 0},
|
||||
{"stats-every", required_argument, 0, 0},
|
||||
{"route_dst", required_argument, 0, 0},
|
||||
{"route-dst", required_argument, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -912,6 +918,27 @@ int nmap_main(int argc, char *argv[]) {
|
||||
if (d < 0)
|
||||
fatal("Argument to --stats-every cannot be negative.");
|
||||
o.stats_interval = d;
|
||||
} else if(optcmp(long_options[option_index].name, "route-dst") == 0) {
|
||||
struct sockaddr_storage ss;
|
||||
struct route_nfo rnfo;
|
||||
size_t sslen;
|
||||
|
||||
if (!resolve(optarg, 0, 0, &ss, &sslen, 0))
|
||||
fatal("Can't resolve %s.", optarg);
|
||||
|
||||
printf("%s\n", inet_ntop_ez(&ss, sslen));
|
||||
|
||||
if (!route_dst(&ss, &rnfo, o.device, o.SourceSockAddr())) {
|
||||
printf("Can't route %s (%s).", optarg, inet_ntop_ez(&ss, sslen));
|
||||
} else {
|
||||
printf("%s %s", rnfo.ii.devname, rnfo.ii.devfullname);
|
||||
printf(" srcaddr %s", inet_ntop_ez(&rnfo.srcaddr, sizeof(rnfo.srcaddr)));
|
||||
if (rnfo.direct_connect)
|
||||
printf(" direct");
|
||||
else
|
||||
printf(" nexthop %s", inet_ntop_ez(&rnfo.nexthop, sizeof(rnfo.nexthop)));
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
fatal("Unknown long option (%s) given@#!$#$", long_options[option_index].name);
|
||||
}
|
||||
@@ -929,6 +956,7 @@ int nmap_main(int argc, char *argv[]) {
|
||||
o.script = 1;
|
||||
#endif
|
||||
if (o.isr00t) {
|
||||
if (o.af() == AF_INET)
|
||||
o.osscan++;
|
||||
o.traceroute = true;
|
||||
}
|
||||
@@ -1121,7 +1149,7 @@ int nmap_main(int argc, char *argv[]) {
|
||||
else if (*optarg == 'B') {
|
||||
if (ports.ack_ping_count > 0)
|
||||
fatal("Only one -PB, -PA, or -PT option is allowed. Combine port ranges with commas.");
|
||||
o.pingtype = DEFAULT_PING_TYPES;
|
||||
o.pingtype = DEFAULT_IPV4_PING_TYPES;
|
||||
if (*(optarg + 1) != '\0') {
|
||||
getpts_simple(optarg + 1, SCAN_TCP_PORT, &ports.ack_ping_ports, &ports.ack_ping_count);
|
||||
if (ports.ack_ping_count <= 0)
|
||||
@@ -1349,14 +1377,10 @@ int nmap_main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_IPV6
|
||||
if(o.af() == AF_INET6 && o.traceroute)
|
||||
fatal("Traceroute does not support IPv6");
|
||||
#endif
|
||||
if (o.traceroute && !o.isr00t)
|
||||
fatal("Traceroute has to be run as root");
|
||||
if (o.traceroute && (o.idlescan || o.connectscan))
|
||||
fatal("Traceroute does not support idle or connect scan");
|
||||
if (o.traceroute && o.idlescan)
|
||||
fatal("Traceroute does not support idle scan");
|
||||
|
||||
if ((o.noportscan) && (portlist || o.fastscan))
|
||||
fatal("You cannot use -F (fast scan) or -p (explicit port selection) when not doing a port scan");
|
||||
@@ -1459,23 +1483,19 @@ int nmap_main(int argc, char *argv[]) {
|
||||
* --None have been specified AND
|
||||
* --We are root and doing tcp ping OR
|
||||
* --We are doing a raw sock scan and NOT pinging anyone */
|
||||
if (o.af() == AF_INET && o.v4sourceip() && !*o.device) {
|
||||
if (ipaddr2devname(o.device, o.v4sourceip()) != 0) {
|
||||
if (o.SourceSockAddr() && !*o.device) {
|
||||
if (ipaddr2devname(o.device, o.SourceSockAddr()) != 0) {
|
||||
fatal("Could not figure out what device to send the packet out on with the source address you gave me! If you are trying to sp00f your scan, this is normal, just give the -e eth0 or -e ppp0 or whatever. Otherwise you can still use -e, but I find it kindof fishy.");
|
||||
}
|
||||
}
|
||||
|
||||
if (o.af() == AF_INET && *o.device && !o.v4sourceip()) {
|
||||
struct sockaddr_in tmpsock;
|
||||
if (*o.device && !o.SourceSockAddr()) {
|
||||
struct sockaddr_storage tmpsock;
|
||||
memset(&tmpsock, 0, sizeof(tmpsock));
|
||||
if (devname2ipaddr(o.device, &(tmpsock.sin_addr)) == -1) {
|
||||
if (devname2ipaddr(o.device, &tmpsock) == -1) {
|
||||
fatal("I cannot figure out what source address to use for device %s, does it even exist?", o.device);
|
||||
}
|
||||
tmpsock.sin_family = AF_INET;
|
||||
#if HAVE_SOCKADDR_SA_LEN
|
||||
tmpsock.sin_len = sizeof(tmpsock);
|
||||
#endif
|
||||
o.setSourceSockAddr((struct sockaddr_storage *) &tmpsock, sizeof(tmpsock));
|
||||
o.setSourceSockAddr(&tmpsock, sizeof(tmpsock));
|
||||
}
|
||||
|
||||
|
||||
@@ -2001,12 +2021,10 @@ static bool target_needs_new_hostgroup(std::vector<Target *> &targets,
|
||||
cope with that, because it uses IP addresses to look up targets from
|
||||
replies. What happens is one target gets the replies for all probes
|
||||
referring to the same IP address. */
|
||||
if (o.af() == AF_INET) {
|
||||
for (it = targets.begin(); it != targets.end(); it++) {
|
||||
if ((*it)->v4host().s_addr == target->v4host().s_addr)
|
||||
if (sockaddr_storage_cmp((*it)->TargetSockAddr(), target->TargetSockAddr()) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
3
nmap.h
3
nmap.h
@@ -361,7 +361,8 @@ void *realloc();
|
||||
-PE -PA80 -PS443 -PP
|
||||
-PE -PA80 -PS443 -PP -PU40125
|
||||
We use the four-probe combination. */
|
||||
#define DEFAULT_PING_TYPES (PINGTYPE_ICMP_PING|PINGTYPE_TCP|PINGTYPE_TCP_USE_ACK|PINGTYPE_TCP_USE_SYN|PINGTYPE_ICMP_TS)
|
||||
#define DEFAULT_IPV4_PING_TYPES (PINGTYPE_ICMP_PING|PINGTYPE_TCP|PINGTYPE_TCP_USE_ACK|PINGTYPE_TCP_USE_SYN|PINGTYPE_ICMP_TS)
|
||||
#define DEFAULT_IPV6_PING_TYPES (PINGTYPE_ICMP_PING|PINGTYPE_TCP|PINGTYPE_TCP_USE_ACK|PINGTYPE_TCP_USE_SYN)
|
||||
#define DEFAULT_PING_ACK_PORT_SPEC "80"
|
||||
#define DEFAULT_PING_SYN_PORT_SPEC "443"
|
||||
/* For nonroot. */
|
||||
|
||||
@@ -130,6 +130,8 @@
|
||||
|
||||
#undef HAVE_SYS_SOCKIO_H
|
||||
|
||||
#undef HAVE_LINUX_RTNETLINK_H
|
||||
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
#undef HAVE_NET_IF_H
|
||||
@@ -196,4 +198,6 @@ extern "C" int gethostname (char *, unsigned int);
|
||||
#undef NETBSD
|
||||
#undef MACOSX
|
||||
|
||||
#undef HAVE_IPV6_IPPROTO_RAW
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
||||
@@ -287,7 +287,7 @@ static int ip_send (lua_State *L)
|
||||
usesock:
|
||||
#ifdef WIN32
|
||||
if (strlen(dev) > 0)
|
||||
win32_warn_raw_sockets(dev);
|
||||
win32_fatal_raw_sockets(dev);
|
||||
#endif
|
||||
ret = send_ip_packet(udata->sock, NULL, (u8 *) packet, lua_objlen(L, 2));
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ static int l_set_port_state (lua_State *L)
|
||||
target->ports.setPortState(p->portno, p->proto, PORT_CLOSED);
|
||||
break;
|
||||
}
|
||||
target->ports.setStateReason(p->portno, p->proto, ER_SCRIPT, 0, 0);
|
||||
target->ports.setStateReason(p->portno, p->proto, ER_SCRIPT, 0, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
26
osscan2.cc
26
osscan2.cc
@@ -934,7 +934,7 @@ HostOsScan::HostOsScan(Target *t) {
|
||||
} else {
|
||||
/* Init our raw socket */
|
||||
#ifdef WIN32
|
||||
win32_warn_raw_sockets(t->deviceName());
|
||||
win32_fatal_raw_sockets(t->deviceName());
|
||||
#endif
|
||||
if ((rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0 )
|
||||
pfatal("socket troubles in %s", __func__);
|
||||
@@ -3253,7 +3253,7 @@ static void doSeqTests(OsScanInfo *OSI, HostOsScan *HOS) {
|
||||
|
||||
struct ip *ip = NULL;
|
||||
struct link_header linkhdr;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_storage ss;
|
||||
unsigned int bytes;
|
||||
struct timeval rcvdtime;
|
||||
|
||||
@@ -3367,12 +3367,12 @@ static void doSeqTests(OsScanInfo *OSI, HostOsScan *HOS) {
|
||||
if(bytes < (4 * ip->ip_hl) + 4U)
|
||||
continue;
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = ip->ip_src.s_addr;
|
||||
sin.sin_family = AF_INET;
|
||||
hsi = OSI->findIncompleteHost((struct sockaddr_storage *) &sin);
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
((struct sockaddr_in *) &ss)->sin_addr.s_addr = ip->ip_src.s_addr;
|
||||
ss.ss_family = AF_INET;
|
||||
hsi = OSI->findIncompleteHost(&ss);
|
||||
if (!hsi) continue; /* Not from one of our targets. */
|
||||
setTargetMACIfAvailable(hsi->target, &linkhdr, ip, 0);
|
||||
setTargetMACIfAvailable(hsi->target, &linkhdr, &ss, 0);
|
||||
|
||||
goodResponse = HOS->processResp(hsi->hss, ip, bytes, &rcvdtime);
|
||||
|
||||
@@ -3417,7 +3417,7 @@ static void doTUITests(OsScanInfo *OSI, HostOsScan *HOS) {
|
||||
|
||||
struct ip *ip = NULL;
|
||||
struct link_header linkhdr;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_storage ss;
|
||||
unsigned int bytes;
|
||||
struct timeval rcvdtime;
|
||||
|
||||
@@ -3536,12 +3536,12 @@ static void doTUITests(OsScanInfo *OSI, HostOsScan *HOS) {
|
||||
if(bytes < (4 * ip->ip_hl) + 4U)
|
||||
continue;
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_addr.s_addr = ip->ip_src.s_addr;
|
||||
sin.sin_family = AF_INET;
|
||||
hsi = OSI->findIncompleteHost((struct sockaddr_storage *) &sin);
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
((struct sockaddr_in *) &ss)->sin_addr.s_addr = ip->ip_src.s_addr;
|
||||
ss.ss_family = AF_INET;
|
||||
hsi = OSI->findIncompleteHost(&ss);
|
||||
if (!hsi) continue; /* Not from one of our targets. */
|
||||
setTargetMACIfAvailable(hsi->target, &linkhdr, ip, 0);
|
||||
setTargetMACIfAvailable(hsi->target, &linkhdr, &ss, 0);
|
||||
|
||||
goodResponse = HOS->processResp(hsi->hss, ip, bytes, &rcvdtime);
|
||||
|
||||
|
||||
45
output.cc
45
output.cc
@@ -241,15 +241,13 @@ static void print_xml_service(const struct serviceDeductions *sd) {
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
/* Display a warning that a device is not Ethernet and so raw sockets
|
||||
will be used. The warning is shown only once per unique device name. */
|
||||
void win32_warn_raw_sockets(const char *devname) {
|
||||
static set<string> shown_names;
|
||||
|
||||
if (devname != NULL && shown_names.find(devname) == shown_names.end()) {
|
||||
error("WARNING: Using raw sockets because %s is not an ethernet device."
|
||||
" This probably won't work on Windows.\n", devname);
|
||||
shown_names.insert(devname);
|
||||
/* Show a fatal error explaining that an interface is not Ethernet and won't
|
||||
work on Windows. Do nothing if --send-ip (PACKET_SEND_IP_STRONG) was used. */
|
||||
void win32_fatal_raw_sockets(const char *devname) {
|
||||
if ((o.sendpref & PACKET_SEND_IP_STRONG) == 0) {
|
||||
fatal("Only ethernet devices can be used for raw scans on Windows, and\n"
|
||||
"\"%s\" is not an ethernet device. Use the --unprivileged option\n"
|
||||
"for this scan.", devname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,9 +381,7 @@ int print_iflist(void) {
|
||||
/* OK -- time to handle routes */
|
||||
errstr[0]='\0';
|
||||
routes = getsysroutes(&numroutes, errstr, sizeof(errstr));
|
||||
u32 mask_nbo;
|
||||
u16 nbits;
|
||||
struct in_addr ia;
|
||||
if (routes==NULL || numroutes<= 0) {
|
||||
log_write(LOG_PLAIN, "ROUTES: NONE FOUND(!)\n");
|
||||
if (o.debugging)
|
||||
@@ -397,15 +393,12 @@ int print_iflist(void) {
|
||||
Tbl->addItem(0, devcol, false, "DEV", 3);
|
||||
Tbl->addItem(0, gwcol, false, "GATEWAY", 7);
|
||||
for (i = 0; i < numroutes; i++) {
|
||||
mask_nbo = routes[i].netmask;
|
||||
addr_mtob(&mask_nbo, sizeof(mask_nbo), &nbits);
|
||||
assert(nbits <= 32);
|
||||
ia.s_addr = routes[i].dest;
|
||||
Tbl->addItemFormatted(i + 1, dstcol, false, "%s/%d", inet_ntoa(ia),
|
||||
nbits);
|
||||
nbits = routes[i].netmask_bits;
|
||||
Tbl->addItemFormatted(i + 1, dstcol, false, "%s/%d",
|
||||
inet_ntop_ez(&routes[i].dest, sizeof(routes[i].dest)), nbits);
|
||||
Tbl->addItem(i + 1, devcol, false, routes[i].device->devfullname);
|
||||
if (routes[i].gw.s_addr != 0)
|
||||
Tbl->addItem(i + 1, gwcol, true, inet_ntoa(routes[i].gw));
|
||||
if (!sockaddr_equal_zero(&routes[i].gw))
|
||||
Tbl->addItem(i + 1, gwcol, true, inet_ntop_ez(&routes[i].gw, sizeof(routes[i].gw)));
|
||||
}
|
||||
log_write(LOG_PLAIN, "**************************ROUTES**************************\n");
|
||||
log_write(LOG_PLAIN, "%s\n", Tbl->printableTable(NULL));
|
||||
@@ -653,8 +646,8 @@ void printportoutput(Target *currenths, PortList *plist) {
|
||||
xml_attribute("state", "%s", state);
|
||||
xml_attribute("reason", "%s", reason_str(current->reason.reason_id, SINGULAR));
|
||||
xml_attribute("reason_ttl", "%d", current->reason.ttl);
|
||||
if (current->reason.ip_addr.s_addr)
|
||||
xml_attribute("reason_ip", "%s", inet_ntoa(current->reason.ip_addr));
|
||||
if (current->reason.ip_addr.ss_family != AF_UNSPEC)
|
||||
xml_attribute("reason_ip", "%s", inet_ntop_ez(¤t->reason.ip_addr, sizeof(current->reason.ip_addr)));
|
||||
xml_close_empty_tag();
|
||||
|
||||
if (proto && proto->p_name && *proto->p_name) {
|
||||
@@ -765,8 +758,8 @@ void printportoutput(Target *currenths, PortList *plist) {
|
||||
xml_attribute("state", "%s", state);
|
||||
xml_attribute("reason", "%s", reason_str(current->reason.reason_id, SINGULAR));
|
||||
xml_attribute("reason_ttl", "%d", current->reason.ttl);
|
||||
if (current->reason.ip_addr.s_addr)
|
||||
xml_attribute("reason_ip", "%s", inet_ntoa(current->reason.ip_addr));
|
||||
if (current->reason.ip_addr.ss_family != AF_UNSPEC)
|
||||
xml_attribute("reason_ip", "%s", inet_ntop_ez(¤t->reason.ip_addr, sizeof(current->reason.ip_addr)));
|
||||
xml_close_empty_tag();
|
||||
|
||||
if (sd.name || sd.service_fp)
|
||||
@@ -2029,13 +2022,15 @@ static void printtraceroute_normal(Target *currenths) {
|
||||
} else if (probe.type == PS_SCTP) {
|
||||
log_write(LOG_PLAIN, "TRACEROUTE (using port %d/%s)\n",
|
||||
probe.pd.sctp.dport, proto2ascii_lowercase(probe.proto));
|
||||
} else if (probe.type == PS_ICMP || probe.type == PS_PROTO) {
|
||||
} else if (probe.type == PS_ICMP || probe.type == PS_ICMPV6 || probe.type == PS_PROTO) {
|
||||
struct protoent *proto = nmap_getprotbynum(htons(probe.proto));
|
||||
log_write(LOG_PLAIN, "TRACEROUTE (using proto %d/%s)\n",
|
||||
probe.proto, proto ? proto->p_name : "unknown");
|
||||
} else {
|
||||
} else if (probe.type == PS_NONE) {
|
||||
/* "Traces" of directly connected targets don't send any packets. */
|
||||
log_write(LOG_PLAIN, "TRACEROUTE\n");
|
||||
} else {
|
||||
fatal("Unknown probe type %d.", probe.type);
|
||||
}
|
||||
|
||||
row = 0;
|
||||
|
||||
6
output.h
6
output.h
@@ -136,9 +136,9 @@
|
||||
#include <string>
|
||||
|
||||
#ifdef WIN32
|
||||
/* Display a warning that a device is not Ethernet and so raw sockets
|
||||
will be used. The warning is shown only once per unique device name. */
|
||||
void win32_warn_raw_sockets(const char *devname);
|
||||
/* Show a fatal error explaining that an interface is not Ethernet and won't
|
||||
work on Windows. Do nothing if --send-ip (PACKET_SEND_IP_STRONG) was used. */
|
||||
void win32_fatal_raw_sockets(const char *devname);
|
||||
#endif
|
||||
|
||||
/* Prints the familiar Nmap tabular output showing the "interesting"
|
||||
|
||||
10
portlist.cc
10
portlist.cc
@@ -545,7 +545,7 @@ void PortList::setPortState(u16 portno, u8 protocol, int state) {
|
||||
state_counts_proto[proto][state]++;
|
||||
|
||||
if(state == PORT_FILTERED || state == PORT_OPENFILTERED)
|
||||
setStateReason(portno, protocol, ER_NORESPONSE, 0, 0);
|
||||
setStateReason(portno, protocol, ER_NORESPONSE, 0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -894,14 +894,18 @@ bool PortList::hasOpenPorts() const {
|
||||
getStateCounts(PORT_UNFILTERED) != 0;
|
||||
}
|
||||
|
||||
int PortList::setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr) {
|
||||
int PortList::setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl,
|
||||
const struct sockaddr_storage *ip_addr) {
|
||||
Port *answer = NULL;
|
||||
|
||||
answer = createPort(portno, proto);
|
||||
|
||||
/* set new reason and increment its count */
|
||||
answer->reason.reason_id = reason;
|
||||
answer->reason.ip_addr.s_addr = ip_addr;
|
||||
if (ip_addr == NULL)
|
||||
answer->reason.ip_addr.ss_family = AF_UNSPEC;
|
||||
else
|
||||
answer->reason.ip_addr = *ip_addr;
|
||||
answer->reason.ttl = ttl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ class PortList {
|
||||
Port *nextPort(const Port *cur, Port *next,
|
||||
int allowed_protocol, int allowed_state);
|
||||
|
||||
int setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr);
|
||||
int setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, const struct sockaddr_storage *ip_addr);
|
||||
|
||||
int numscriptresults; /* Total number of scripts which produced output */
|
||||
|
||||
|
||||
@@ -161,6 +161,9 @@ reason_map_type::reason_map_type(){
|
||||
reason_map[ER_UNKNOWN] = reason_string("unknown-response","unknown-responses");
|
||||
reason_map[ER_USER] = reason_string("user-set","user-sets");
|
||||
|
||||
reason_map[ER_NOROUTE] = reason_string("no-route", "no-routes");
|
||||
reason_map[ER_BEYONDSCOPE] = reason_string("beyond-scope", "beyond-scopes");
|
||||
reason_map[ER_REJECTROUTE] = reason_string("reject-route", "reject-routes");
|
||||
}
|
||||
|
||||
/* Map holding plural and singular versions of error codes */
|
||||
@@ -169,7 +172,7 @@ reason_map_type reason_map;
|
||||
/* Function to Translate ICMP codes and types to *
|
||||
* Reason Codes */
|
||||
|
||||
reason_codes icmp_to_reason(int icmp_type, int icmp_code){
|
||||
static reason_codes icmpv4_to_reason(int icmp_type, int icmp_code) {
|
||||
|
||||
switch(icmp_type){
|
||||
|
||||
@@ -212,6 +215,47 @@ reason_codes icmp_to_reason(int icmp_type, int icmp_code){
|
||||
return ER_UNKNOWN;
|
||||
};
|
||||
|
||||
static reason_codes icmpv6_to_reason(int icmp_type, int icmp_code) {
|
||||
|
||||
switch(icmp_type){
|
||||
|
||||
case ICMPV6_ECHOREPLY:
|
||||
return ER_ECHOREPLY;
|
||||
|
||||
case ICMPV6_UNREACH:
|
||||
switch(icmp_code) {
|
||||
case ICMPV6_UNREACH_NOROUTE:
|
||||
return ER_NOROUTE;
|
||||
case ICMPV6_UNREACH_PROHIB:
|
||||
return ER_ADMINPROHIBITED;
|
||||
case ICMPV6_UNREACH_SCOPE:
|
||||
return ER_BEYONDSCOPE;
|
||||
case ICMPV6_UNREACH_ADDR:
|
||||
return ER_HOSTUNREACH;
|
||||
case ICMPV6_UNREACH_PORT:
|
||||
return ER_PORTUNREACH;
|
||||
case ICMPV6_UNREACH_FILTER_PROHIB:
|
||||
return ER_ADMINPROHIBITED;
|
||||
case ICMPV6_UNREACH_REJECT_ROUTE:
|
||||
return ER_REJECTROUTE;
|
||||
}
|
||||
return ER_UNKNOWN;
|
||||
|
||||
case ICMPV6_TIMEXCEED:
|
||||
return ER_TIMEEXCEEDED;
|
||||
}
|
||||
return ER_UNKNOWN;
|
||||
};
|
||||
|
||||
reason_codes icmp_to_reason(u8 proto, int icmp_type, int icmp_code) {
|
||||
if (proto == IPPROTO_ICMP)
|
||||
return icmpv4_to_reason(icmp_type, icmp_code);
|
||||
else if (proto == IPPROTO_ICMPV6)
|
||||
return icmpv6_to_reason(icmp_type, icmp_code);
|
||||
else
|
||||
return ER_UNKNOWN;
|
||||
}
|
||||
|
||||
static void state_reason_summary_init(state_reason_summary_t *r) {
|
||||
r->reason_id = ER_UNKNOWN;
|
||||
r->count = 0;
|
||||
@@ -378,7 +422,7 @@ const char *reason_str(reason_t reason_code, unsigned int number) {
|
||||
|
||||
void state_reason_init(state_reason_t *reason) {
|
||||
reason->reason_id = ER_UNKNOWN;
|
||||
reason->ip_addr.s_addr = 0;
|
||||
reason->ip_addr.ss_family = AF_UNSPEC;
|
||||
reason->ttl = 0;
|
||||
}
|
||||
|
||||
@@ -455,7 +499,7 @@ char *port_reason_str(state_reason_t r) {
|
||||
static char reason[128];
|
||||
memset(reason,'\0', 128);
|
||||
Snprintf(reason, 128, "%s%s%s", reason_str(r.reason_id, SINGULAR),
|
||||
(r.ip_addr.s_addr==0)?"":" from ",
|
||||
(r.ip_addr.s_addr==0)?"":inet_ntoa(r.ip_addr));
|
||||
(r.ip_addr.ss_family==AF_UNSPEC)?"":" from ",
|
||||
(r.ip_addr.ss_family==AF_UNSPEC)?"":inet_ntop_ez(&r.ip_addr, sizeof(r.ip_addr)));
|
||||
return reason;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
* why a port is in a specific state */
|
||||
typedef struct port_reason {
|
||||
reason_t reason_id;
|
||||
struct in_addr ip_addr;
|
||||
struct sockaddr_storage ip_addr;
|
||||
unsigned short ttl;
|
||||
} state_reason_t;
|
||||
|
||||
@@ -152,7 +152,8 @@ enum reason_codes {
|
||||
ER_ADDRESSMASKREPLY, ER_NOIPIDCHANGE, ER_IPIDCHANGE,
|
||||
ER_ARPRESPONSE, ER_TCPRESPONSE, ER_NORESPONSE,
|
||||
ER_INITACK, ER_ABORT,
|
||||
ER_LOCALHOST, ER_SCRIPT, ER_UNKNOWN, ER_USER
|
||||
ER_LOCALHOST, ER_SCRIPT, ER_UNKNOWN, ER_USER,
|
||||
ER_NOROUTE, ER_BEYONDSCOPE, ER_REJECTROUTE,
|
||||
};
|
||||
|
||||
/* A map of reason_codes to plural and singular *
|
||||
@@ -171,7 +172,7 @@ public:
|
||||
};
|
||||
|
||||
/* Function to translate ICMP code and typ to reason code */
|
||||
reason_codes icmp_to_reason(int icmp_type, int icmp_code);
|
||||
reason_codes icmp_to_reason(u8 proto, int icmp_type, int icmp_code);
|
||||
|
||||
/* passed to the print_state_summary.
|
||||
* STATE_REASON_EMPTY will append to the current line, prefixed with " because of"
|
||||
|
||||
809
scan_engine.cc
809
scan_engine.cc
File diff suppressed because it is too large
Load Diff
@@ -117,6 +117,11 @@ struct probespec_icmpdata {
|
||||
u8 code;
|
||||
};
|
||||
|
||||
struct probespec_icmpv6data {
|
||||
u8 type;
|
||||
u8 code;
|
||||
};
|
||||
|
||||
#define PS_NONE 0
|
||||
#define PS_TCP 1
|
||||
#define PS_UDP 2
|
||||
@@ -125,6 +130,7 @@ struct probespec_icmpdata {
|
||||
#define PS_ARP 5
|
||||
#define PS_CONNECTTCP 6
|
||||
#define PS_SCTP 7
|
||||
#define PS_ICMPV6 8
|
||||
|
||||
/* The size of this structure is critical, since there can be tens of
|
||||
thousands of them stored together ... */
|
||||
@@ -138,6 +144,7 @@ typedef struct probespec {
|
||||
struct probespec_udpdata udp; /* PS_UDP */
|
||||
struct probespec_sctpdata sctp; /* PS_SCTP */
|
||||
struct probespec_icmpdata icmp; /* PS_ICMP */
|
||||
struct probespec_icmpv6data icmpv6; /* PS_ICMPV6 */
|
||||
/* Nothing needed for PS_ARP, since src mac and target IP are
|
||||
avail from target structure anyway */
|
||||
} pd;
|
||||
|
||||
@@ -1733,9 +1733,9 @@ static void adjustPortStateIfNecessary(ServiceNFO *svc) {
|
||||
if (oldstate != PORT_OPEN) {
|
||||
svc->target->ports.setPortState(svc->portno, svc->proto, PORT_OPEN);
|
||||
if (svc->proto == IPPROTO_TCP)
|
||||
svc->target->ports.setStateReason(svc->portno, svc->proto, ER_TCPRESPONSE, 0, 0);
|
||||
svc->target->ports.setStateReason(svc->portno, svc->proto, ER_TCPRESPONSE, 0, NULL);
|
||||
if (svc->proto == IPPROTO_UDP)
|
||||
svc->target->ports.setStateReason(svc->portno, svc->proto, ER_UDPRESPONSE, 0, 0);
|
||||
svc->target->ports.setStateReason(svc->portno, svc->proto, ER_UDPRESPONSE, 0, NULL);
|
||||
|
||||
if (o.verbose || o.debugging > 1) {
|
||||
svc->target->NameIP(host, sizeof(host));
|
||||
|
||||
13
targets.cc
13
targets.cc
@@ -382,9 +382,13 @@ static bool target_needs_new_hostgroup(const HostGroupState *hs, const Target *t
|
||||
return false;
|
||||
|
||||
/* There are no restrictions on non-root scans. */
|
||||
if (!(o.af() == AF_INET && o.isr00t && target->deviceName() != NULL))
|
||||
if (!(o.isr00t && target->deviceName() != NULL))
|
||||
return false;
|
||||
|
||||
/* Different address family? */
|
||||
if (hs->hostbatch[0]->af() != target->af())
|
||||
return true;
|
||||
|
||||
/* Different interface name? */
|
||||
if (hs->hostbatch[0]->deviceName() != NULL &&
|
||||
strcmp(hs->hostbatch[0]->deviceName(), target->deviceName()) != 0) {
|
||||
@@ -392,7 +396,7 @@ static bool target_needs_new_hostgroup(const HostGroupState *hs, const Target *t
|
||||
}
|
||||
|
||||
/* Different source address? */
|
||||
if (hs->hostbatch[0]->v4source().s_addr != target->v4source().s_addr)
|
||||
if (sockaddr_storage_cmp(hs->hostbatch[0]->SourceSockAddr(), target->SourceSockAddr()) != 0)
|
||||
return true;
|
||||
|
||||
/* Different direct connectedness? */
|
||||
@@ -404,7 +408,7 @@ static bool target_needs_new_hostgroup(const HostGroupState *hs, const Target *t
|
||||
replies. What happens is one target gets the replies for all probes
|
||||
referring to the same IP address. */
|
||||
for (i = 0; i < hs->current_batch_sz; i++) {
|
||||
if (hs->hostbatch[0]->v4host().s_addr == target->v4host().s_addr)
|
||||
if (sockaddr_storage_cmp(hs->hostbatch[0]->TargetSockAddr(), target->TargetSockAddr()) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -453,7 +457,7 @@ Target *nexthost(HostGroupState *hs, TargetGroup *exclude_group,
|
||||
2) We are doing tcp or udp pingscan OR
|
||||
3) We are doing a raw-mode portscan or osscan or traceroute OR
|
||||
4) We are on windows and doing ICMP ping */
|
||||
if (o.isr00t && o.af() == AF_INET &&
|
||||
if (o.isr00t &&
|
||||
((pingtype & (PINGTYPE_TCP|PINGTYPE_UDP|PINGTYPE_SCTP_INIT|PINGTYPE_PROTO|PINGTYPE_ARP)) || o.RawScan()
|
||||
#ifdef WIN32
|
||||
|| (pingtype & (PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS))
|
||||
@@ -520,6 +524,7 @@ batchfull:
|
||||
directly connected over ethernet. I may need the MAC addresses
|
||||
later anyway. */
|
||||
if (hs->hostbatch[0]->ifType() == devt_ethernet &&
|
||||
hs->hostbatch[0]->af() == AF_INET &&
|
||||
hs->hostbatch[0]->directlyConnected() &&
|
||||
o.sendpref != PACKET_SEND_IP_STRONG) {
|
||||
arpping(hs->hostbatch, hs->current_batch_sz);
|
||||
|
||||
138
tcpip.h
138
tcpip.h
@@ -253,6 +253,8 @@ class PacketTrace {
|
||||
efficient by avoiding a gettimeofday() call. */
|
||||
static void traceArp(pdirection pdir, const u8 *frame, u32 len,
|
||||
struct timeval *now);
|
||||
static void traceND(pdirection pdir, const u8 *frame, u32 len,
|
||||
struct timeval *now);
|
||||
};
|
||||
|
||||
class PacketCounter {
|
||||
@@ -418,22 +420,27 @@ bool routethrough(const struct sockaddr_storage * const dest,
|
||||
unsigned short in_cksum(u16 *ptr,int nbytes);
|
||||
|
||||
|
||||
/* Build and send a raw tcp packet. If TTL is -1, a partially random
|
||||
(but likely large enough) one is chosen */
|
||||
int send_tcp_raw( int sd, struct eth_nfo *eth,
|
||||
const struct in_addr *source, const struct in_addr *victim,
|
||||
int ttl, bool df,
|
||||
u8* ipopt, int ipoptlen,
|
||||
u16 sport, u16 dport,
|
||||
u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp,
|
||||
u8 *options, int optlen,
|
||||
char *data, u16 datalen);
|
||||
int send_udp_raw( int sd, struct eth_nfo *eth,
|
||||
struct in_addr *source, const struct in_addr *victim,
|
||||
int ttl, u16 ipid,
|
||||
u8* ipopt, int ipoptlen,
|
||||
u16 sport, u16 dport,
|
||||
char *data, u16 datalen);
|
||||
/* Send a pre-built IPv4 or IPv6 packet */
|
||||
int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet,
|
||||
unsigned int packetlen);
|
||||
|
||||
/* Builds an IP packet (including an IP header) by packing the fields
|
||||
with the given information. It allocates a new buffer to store the
|
||||
packet contents, and then returns that buffer. The packet is not
|
||||
actually sent by this function. Caller must delete the buffer when
|
||||
finished with the packet. The packet length is returned in
|
||||
packetlen, which must be a valid int pointer. */
|
||||
u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim,
|
||||
u8 proto,
|
||||
int ttl, u16 ipid, u8 tos, bool df,
|
||||
const u8* ipopt, int ipoptlen,
|
||||
const char *data, u16 datalen,
|
||||
u32 *packetlen);
|
||||
|
||||
u8 *build_ipv6_raw(const struct in6_addr *source,
|
||||
const struct in6_addr *victim, u8 tc, u32 flowlabel,
|
||||
u8 nextheader, int hoplimit,
|
||||
char *data, u16 datalen, u32 *outpacketlen);
|
||||
|
||||
/* Builds a TCP packet (including an IP header) by packing the fields
|
||||
with the given information. It allocates a new buffer to store the
|
||||
@@ -450,6 +457,33 @@ u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim,
|
||||
char *data, u16 datalen,
|
||||
u32 *packetlen);
|
||||
|
||||
u8 *build_tcp_raw_ipv6(const struct in6_addr *source,
|
||||
const struct in6_addr *victim, u8 tc, u32 flowlabel,
|
||||
u8 hoplimit, u16 sport, u16 dport, u32 seq, u32 ack,
|
||||
u8 reserved, u8 flags, u16 window, u16 urp,
|
||||
const u8 *tcpopt, int tcpoptlen, char *data,
|
||||
u16 datalen, u32 *packetlen);
|
||||
|
||||
/* Build and send a raw tcp packet. If TTL is -1, a partially random
|
||||
(but likely large enough) one is chosen */
|
||||
int send_tcp_raw( int sd, struct eth_nfo *eth,
|
||||
const struct in_addr *source, const struct in_addr *victim,
|
||||
int ttl, bool df,
|
||||
u8* ipopt, int ipoptlen,
|
||||
u16 sport, u16 dport,
|
||||
u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp,
|
||||
u8 *options, int optlen,
|
||||
char *data, u16 datalen);
|
||||
|
||||
int send_tcp_raw_decoys( int sd, struct eth_nfo *eth,
|
||||
const struct in_addr *victim,
|
||||
int ttl, bool df,
|
||||
u8* ipopt, int ipoptlen,
|
||||
u16 sport, u16 dport,
|
||||
u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp,
|
||||
u8 *options, int optlen,
|
||||
char *data, u16 datalen);
|
||||
|
||||
/* Builds a UDP packet (including an IP header) by packing the fields
|
||||
with the given information. It allocates a new buffer to store the
|
||||
packet contents, and then returns that buffer. The packet is not
|
||||
@@ -463,6 +497,25 @@ u8 *build_udp_raw(const struct in_addr *source, const struct in_addr *victim,
|
||||
const char *data, u16 datalen,
|
||||
u32 *packetlen);
|
||||
|
||||
u8 *build_udp_raw_ipv6(const struct in6_addr *source,
|
||||
const struct in6_addr *victim, u8 tc, u32 flowlabel,
|
||||
u8 hoplimit, u16 sport, u16 dport,
|
||||
char *data, u16 datalen, u32 *packetlen);
|
||||
|
||||
int send_udp_raw( int sd, struct eth_nfo *eth,
|
||||
struct in_addr *source, const struct in_addr *victim,
|
||||
int ttl, u16 ipid,
|
||||
u8* ipopt, int ipoptlen,
|
||||
u16 sport, u16 dport,
|
||||
char *data, u16 datalen);
|
||||
|
||||
int send_udp_raw_decoys( int sd, struct eth_nfo *eth,
|
||||
const struct in_addr *victim,
|
||||
int ttl, u16 ipid,
|
||||
u8* ipops, int ip,
|
||||
u16 sport, u16 dport,
|
||||
char *data, u16 datalen);
|
||||
|
||||
/* Builds an SCTP packet (including an IP header) by packing the fields
|
||||
with the given information. It allocates a new buffer to store the
|
||||
packet contents, and then returns that buffer. The packet is not
|
||||
@@ -477,6 +530,12 @@ u8 *build_sctp_raw(const struct in_addr *source, const struct in_addr *victim,
|
||||
char *data, u16 datalen,
|
||||
u32 *packetlen);
|
||||
|
||||
u8 *build_sctp_raw_ipv6(const struct in6_addr *source,
|
||||
const struct in6_addr *victim, u8 tc, u32 flowlabel,
|
||||
u8 hoplimit, u16 sport, u16 dport, u32 vtag,
|
||||
char *chunks, int chunkslen, char *data, u16 datalen,
|
||||
u32 *packetlen);
|
||||
|
||||
/* Builds an ICMP packet (including an IP header) by packing the
|
||||
fields with the given information. It allocates a new buffer to
|
||||
store the packet contents, and then returns that buffer. The
|
||||
@@ -491,6 +550,11 @@ u8 *build_icmp_raw(const struct in_addr *source, const struct in_addr *victim,
|
||||
u16 seq, unsigned short id, u8 ptype, u8 pcode,
|
||||
char *data, u16 datalen, u32 *packetlen);
|
||||
|
||||
u8 *build_icmpv6_raw(const struct in6_addr *source,
|
||||
const struct in6_addr *victim, u8 tc, u32 flowlabel,
|
||||
u8 hoplimit, u16 seq, u16 id, u8 ptype, u8 pcode,
|
||||
char *data, u16 datalen, u32 *packetlen);
|
||||
|
||||
/* Builds an IGMP packet (including an IP header) by packing the fields
|
||||
with the given information. It allocates a new buffer to store the
|
||||
packet contents, and then returns that buffer. The packet is not
|
||||
@@ -504,40 +568,6 @@ u8 *build_igmp_raw(const struct in_addr *source, const struct in_addr *victim,
|
||||
u8 ptype, u8 pcode,
|
||||
char *data, u16 datalen, u32 *packetlen);
|
||||
|
||||
/* Builds an IP packet (including an IP header) by packing the fields
|
||||
with the given information. It allocates a new buffer to store the
|
||||
packet contents, and then returns that buffer. The packet is not
|
||||
actually sent by this function. Caller must delete the buffer when
|
||||
finished with the packet. The packet length is returned in
|
||||
packetlen, which must be a valid int pointer. */
|
||||
u8 *build_ip_raw(const struct in_addr *source, const struct in_addr *victim,
|
||||
u8 proto,
|
||||
int ttl, u16 ipid, u8 tos, bool df,
|
||||
u8* ipopt, int ipoptlen,
|
||||
char *data, u16 datalen,
|
||||
u32 *packetlen);
|
||||
|
||||
/* Send a pre-built IPv4 packet */
|
||||
int send_ip_packet(int sd, struct eth_nfo *eth, u8 *packet,
|
||||
unsigned int packetlen);
|
||||
|
||||
/* Decoy versions of the raw packet sending functions ... */
|
||||
int send_tcp_raw_decoys( int sd, struct eth_nfo *eth,
|
||||
const struct in_addr *victim,
|
||||
int ttl, bool df,
|
||||
u8* ipopt, int ipoptlen,
|
||||
u16 sport, u16 dport,
|
||||
u32 seq, u32 ack, u8 reserved, u8 flags, u16 window, u16 urp,
|
||||
u8 *options, int optlen,
|
||||
char *data, u16 datalen);
|
||||
|
||||
int send_udp_raw_decoys( int sd, struct eth_nfo *eth,
|
||||
const struct in_addr *victim,
|
||||
int ttl, u16 ipid,
|
||||
u8* ipops, int ip,
|
||||
u16 sport, u16 dport,
|
||||
char *data, u16 datalen);
|
||||
|
||||
|
||||
// Returns whether the packet receive time value obtaned from libpcap
|
||||
// (and thus by readip_pcap()) should be considered valid. When
|
||||
@@ -577,13 +607,10 @@ char *getFinalPacketStats(char *buf, int buflen);
|
||||
directly connected to the src host running Nmap. If it is, set the MAC.
|
||||
|
||||
This function returns 0 if it ends up setting the MAC, nonzero otherwise
|
||||
|
||||
This function assumes that ip has already been verified as
|
||||
containing a complete IP header (or at least the first 20 bytes).
|
||||
*/
|
||||
|
||||
int setTargetMACIfAvailable(Target *target, struct link_header *linkhdr,
|
||||
struct ip *ip, int overwrite);
|
||||
const struct sockaddr_storage *src, int overwrite);
|
||||
|
||||
/* This function ensures that the next hop MAC address for a target is
|
||||
filled in. This address is the target's own MAC if it is directly
|
||||
@@ -608,6 +635,9 @@ int get_link_offset(char *device);
|
||||
char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
struct timeval *rcvdtime, struct link_header *linknfo, bool validate);
|
||||
|
||||
char *readip46_pcap(pcap_t *pd, unsigned int *len, long to_usec,
|
||||
struct timeval *rcvdtime, struct link_header *linknfo, bool validate);
|
||||
|
||||
/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
|
||||
descriptor pd. If it receives one, fills in sendermac (must pass
|
||||
in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
|
||||
|
||||
336
traceroute.cc
336
traceroute.cc
@@ -284,7 +284,7 @@ public:
|
||||
void resend(int rawsd, eth_t *ethsd, struct timeval *now = NULL);
|
||||
bool is_timedout(struct timeval *now = NULL) const;
|
||||
bool may_resend() const;
|
||||
virtual unsigned char *build_packet(const struct in_addr *source,
|
||||
virtual unsigned char *build_packet(const struct sockaddr_storage *source,
|
||||
u32 *len) const = 0;
|
||||
|
||||
static Probe *make(HostState *host, struct probespec pspec, u8 ttl);
|
||||
@@ -550,13 +550,9 @@ struct probespec HostState::get_probe(const Target *target) {
|
||||
struct probespec probe;
|
||||
|
||||
probe = target->pingprobe;
|
||||
if (probe.type == PS_NONE || probe.type == PS_ARP) {
|
||||
/* No responsive probe known? The user probably skipped both ping and
|
||||
port scan. Guess ICMP echo as the most likely to get a response. */
|
||||
probe.type = PS_ICMP;
|
||||
probe.proto = IPPROTO_ICMP;
|
||||
probe.pd.icmp.type = ICMP_ECHO;
|
||||
probe.pd.icmp.code = 0;
|
||||
if (probe.type == PS_TCP || probe.type == PS_UDP || probe.type == PS_ICMP ||
|
||||
probe.type == PS_SCTP || probe.type == PS_ICMPV6) {
|
||||
/* Nothing needed. */
|
||||
} else if (probe.type == PS_PROTO) {
|
||||
/* If this is an IP protocol probe, fill in some fields for some common
|
||||
protocols. We cheat and store them in the TCP-, UDP-, SCTP- and
|
||||
@@ -571,6 +567,22 @@ struct probespec HostState::get_probe(const Target *target) {
|
||||
} else if (probe.proto == IPPROTO_ICMP) {
|
||||
probe.pd.icmp.type = ICMP_ECHO;
|
||||
}
|
||||
} else {
|
||||
/* No responsive probe known? The user probably skipped both ping and
|
||||
port scan. Guess ICMP echo as the most likely to get a response. */
|
||||
if (target->af() == AF_INET) {
|
||||
probe.type = PS_ICMP;
|
||||
probe.proto = IPPROTO_ICMP;
|
||||
probe.pd.icmp.type = ICMP_ECHO;
|
||||
probe.pd.icmp.code = 0;
|
||||
} else if (target->af() == AF_INET6) {
|
||||
probe.type = PS_ICMPV6;
|
||||
probe.proto = IPPROTO_ICMPV6;
|
||||
probe.pd.icmp.type = ICMPV6_ECHO;
|
||||
probe.pd.icmp.code = 0;
|
||||
} else {
|
||||
fatal("Unknown address family %d", target->af());
|
||||
}
|
||||
}
|
||||
|
||||
return probe;
|
||||
@@ -606,18 +618,29 @@ void Probe::send(int rawsd, eth_t *ethsd, struct timeval *now) {
|
||||
}
|
||||
|
||||
for (decoy = 0; decoy < o.numdecoys; decoy++) {
|
||||
const struct in_addr *source;
|
||||
struct sockaddr_storage source;
|
||||
size_t source_len;
|
||||
unsigned char *packet;
|
||||
u32 packetlen;
|
||||
|
||||
if (decoy == o.decoyturn) {
|
||||
source = host->target->v4sourceip();
|
||||
source_len = sizeof(source);
|
||||
host->target->SourceSockAddr(&source, &source_len);
|
||||
sent_time = get_now(now);
|
||||
} else {
|
||||
source = &o.decoys[decoy];
|
||||
if (o.af() == AF_INET) {
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *) &source;
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_addr = o.decoys[decoy];
|
||||
} else {
|
||||
/* Decoys are IPv4-only. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
packet = this->build_packet(source, &packetlen);
|
||||
packet = this->build_packet(&source, &packetlen);
|
||||
send_ip_packet(rawsd, ethp, packet, packetlen);
|
||||
free(packet);
|
||||
}
|
||||
@@ -650,8 +673,11 @@ public:
|
||||
: Probe(host, pspec, ttl) {
|
||||
}
|
||||
|
||||
unsigned char *build_packet(const struct in_addr *source, u32 *len) const {
|
||||
return build_icmp_raw(source, host->target->v4hostip(), ttl,
|
||||
unsigned char *build_packet(const struct sockaddr_storage *source, u32 *len) const {
|
||||
const struct sockaddr_in *sin;
|
||||
assert(source->ss_family == AF_INET);
|
||||
sin = (struct sockaddr_in *) source;
|
||||
return build_icmp_raw(&sin->sin_addr, host->target->v4hostip(), ttl,
|
||||
0x0000, 0x00, false, NULL, 0, token, global_id,
|
||||
pspec.pd.icmp.type, pspec.pd.icmp.code,
|
||||
o.extra_payload, o.extra_payload_length, len);
|
||||
@@ -664,7 +690,7 @@ public:
|
||||
TCPProbe(HostState *host, struct probespec pspec, u8 ttl)
|
||||
: Probe(host, pspec, ttl) {
|
||||
}
|
||||
unsigned char *build_packet(const struct in_addr *source, u32 *len) const {
|
||||
unsigned char *build_packet(const struct sockaddr_storage *source, u32 *len) const {
|
||||
const char *tcpopts;
|
||||
int tcpoptslen;
|
||||
u32 ack;
|
||||
@@ -681,11 +707,23 @@ public:
|
||||
}
|
||||
|
||||
/* For TCP we encode the token in the source port. */
|
||||
return build_tcp_raw(source, host->target->v4hostip(), ttl,
|
||||
if (source->ss_family == AF_INET) {
|
||||
const struct sockaddr_in *sin = (struct sockaddr_in *) source;
|
||||
return build_tcp_raw(&sin->sin_addr, host->target->v4hostip(), ttl,
|
||||
get_random_u16(), get_random_u8(), false, NULL, 0,
|
||||
token ^ global_id, pspec.pd.tcp.dport, get_random_u32(), ack, 0x00,
|
||||
pspec.pd.tcp.flags, get_random_u16(), 0, (const u8 *) tcpopts, tcpoptslen,
|
||||
o.extra_payload, o.extra_payload_length, len);
|
||||
} else if (source->ss_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) source;
|
||||
return build_tcp_raw_ipv6(&sin6->sin6_addr, host->target->v6hostip(),
|
||||
0, 0, ttl,
|
||||
token ^ global_id, pspec.pd.tcp.dport, get_random_u32(), ack, 0x00,
|
||||
pspec.pd.tcp.flags, get_random_u16(), 0, (const u8 *) tcpopts, tcpoptslen,
|
||||
o.extra_payload, o.extra_payload_length, len);
|
||||
} else {
|
||||
fatal("Unknown address family %u in %s.", source->ss_family, __func__);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -695,14 +733,18 @@ public:
|
||||
UDPProbe(HostState *host, struct probespec pspec, u8 ttl)
|
||||
: Probe(host, pspec, ttl) {
|
||||
}
|
||||
unsigned char *build_packet(const struct in_addr *source, u32 *len) const {
|
||||
unsigned char *build_packet(const struct sockaddr_storage *source, u32 *len) const {
|
||||
const char *payload;
|
||||
size_t payload_length;
|
||||
const struct sockaddr_in *sin;
|
||||
|
||||
assert(source->ss_family == AF_INET);
|
||||
sin = (struct sockaddr_in *) source;
|
||||
|
||||
payload = get_udp_payload(pspec.pd.udp.dport, &payload_length);
|
||||
|
||||
/* For UDP we encode the token in the source port. */
|
||||
return build_udp_raw(source, host->target->v4hostip(), ttl,
|
||||
return build_udp_raw(&sin->sin_addr, host->target->v4hostip(), ttl,
|
||||
get_random_u16(), get_random_u8(), false, NULL, 0,
|
||||
token ^ global_id, pspec.pd.udp.dport,
|
||||
payload, payload_length, len);
|
||||
@@ -715,12 +757,16 @@ public:
|
||||
SCTPProbe(HostState *host, struct probespec pspec, u8 ttl)
|
||||
: Probe(host, pspec, ttl) {
|
||||
}
|
||||
unsigned char *build_packet(const struct in_addr *source, u32 *len) const {
|
||||
unsigned char *build_packet(const struct sockaddr_storage *source, u32 *len) const {
|
||||
struct sctp_chunkhdr_init chunk;
|
||||
const struct sockaddr_in *sin;
|
||||
|
||||
assert(source->ss_family == AF_INET);
|
||||
sin = (struct sockaddr_in *) source;
|
||||
|
||||
sctp_pack_chunkhdr_init(&chunk, SCTP_INIT, 0, sizeof(chunk),
|
||||
get_random_u32() /*itag*/, 32768, 10, 2048, get_random_u32() /*itsn*/);
|
||||
return build_sctp_raw(source, host->target->v4hostip(), ttl,
|
||||
return build_sctp_raw(&sin->sin_addr, host->target->v4hostip(), ttl,
|
||||
get_random_u16(), get_random_u8(), false, NULL, 0,
|
||||
token ^ global_id, pspec.pd.sctp.dport, 0UL,
|
||||
(char *) &chunk, sizeof(chunk),
|
||||
@@ -734,14 +780,34 @@ public:
|
||||
IPProtoProbe(HostState *host, struct probespec pspec, u8 ttl)
|
||||
: Probe(host, pspec, ttl) {
|
||||
}
|
||||
unsigned char *build_packet(const struct in_addr *source, u32 *len) const {
|
||||
unsigned char *build_packet(const struct sockaddr_storage *source, u32 *len) const {
|
||||
const struct sockaddr_in *sin;
|
||||
assert(source->ss_family == AF_INET);
|
||||
sin = (struct sockaddr_in *) source;
|
||||
/* For IP proto scan the token is put in the IP ID. */
|
||||
return build_ip_raw(source, host->target->v4hostip(), pspec.proto, ttl,
|
||||
return build_ip_raw(&sin->sin_addr, host->target->v4hostip(), pspec.proto, ttl,
|
||||
token ^ global_id, get_random_u8(), false, NULL, 0,
|
||||
o.extra_payload, o.extra_payload_length, len);
|
||||
}
|
||||
};
|
||||
|
||||
class ICMPv6Probe : public Probe
|
||||
{
|
||||
public:
|
||||
ICMPv6Probe(HostState *host, struct probespec pspec, u8 ttl)
|
||||
: Probe(host, pspec, ttl) {
|
||||
}
|
||||
|
||||
unsigned char *build_packet(const struct sockaddr_storage *source, u32 *len) const {
|
||||
const struct sockaddr_in6 *sin6;
|
||||
assert(source->ss_family == AF_INET6);
|
||||
sin6 = (struct sockaddr_in6 *) source;
|
||||
return build_icmpv6_raw(&sin6->sin6_addr, host->target->v6hostip(), 0x00, 0x0000,
|
||||
ttl, token, global_id, pspec.pd.icmp.type, pspec.pd.icmp.code,
|
||||
o.extra_payload, o.extra_payload_length, len);
|
||||
}
|
||||
};
|
||||
|
||||
Probe *Probe::make(HostState *host, struct probespec pspec, u8 ttl)
|
||||
{
|
||||
if (pspec.type == PS_ICMP || (pspec.type == PS_PROTO && pspec.proto == IPPROTO_ICMP))
|
||||
@@ -754,6 +820,8 @@ Probe *Probe::make(HostState *host, struct probespec pspec, u8 ttl)
|
||||
return new SCTPProbe(host, pspec, ttl);
|
||||
else if (pspec.type == PS_PROTO)
|
||||
return new IPProtoProbe(host, pspec, ttl);
|
||||
else if (pspec.type == PS_ICMPV6)
|
||||
return new ICMPv6Probe(host, pspec, ttl);
|
||||
else
|
||||
fatal("Unknown probespec type in traceroute");
|
||||
|
||||
@@ -776,7 +844,7 @@ TracerouteState::TracerouteState(std::vector<Target *> &targets) {
|
||||
rawsd = -1;
|
||||
} else {
|
||||
#ifdef WIN32
|
||||
win32_warn_raw_sockets(targets[0]->deviceName());
|
||||
win32_fatal_raw_sockets(targets[0]->deviceName());
|
||||
#endif
|
||||
rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
if (rawsd == -1)
|
||||
@@ -793,7 +861,7 @@ TracerouteState::TracerouteState(std::vector<Target *> &targets) {
|
||||
fatal("%s", PCAP_OPEN_ERRMSG);
|
||||
sslen = sizeof(srcaddr);
|
||||
targets[0]->SourceSockAddr(&srcaddr, &sslen);
|
||||
n = Snprintf(pcap_filter, sizeof(pcap_filter), "dst host %s",
|
||||
n = Snprintf(pcap_filter, sizeof(pcap_filter), "(ip or ip6) and dst host %s",
|
||||
ss_to_string(&srcaddr));
|
||||
assert(n < (int) sizeof(pcap_filter));
|
||||
set_pcap_filter(targets[0]->deviceFullName(), pd, pcap_filter);
|
||||
@@ -1024,113 +1092,81 @@ struct Reply {
|
||||
u16 token;
|
||||
};
|
||||
|
||||
static const void *ip_get_data(const struct ip *ip, unsigned int *len)
|
||||
{
|
||||
unsigned int header_len;
|
||||
static bool parse_encapsulated_reply(const void *ip, unsigned len, Reply *reply) {
|
||||
struct abstract_ip_hdr hdr;
|
||||
const void *data;
|
||||
|
||||
header_len = ip->ip_hl * 4;
|
||||
if (header_len > *len)
|
||||
return NULL;
|
||||
*len -= header_len;
|
||||
data = ip_get_data(ip, &len, &hdr);
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
return (char *) ip + header_len;
|
||||
}
|
||||
|
||||
static const void *icmp_get_data(const struct icmp *icmp, unsigned int *len)
|
||||
{
|
||||
unsigned int header_len;
|
||||
|
||||
if (icmp->icmp_type == ICMP_TIMEXCEED || icmp->icmp_type == ICMP_UNREACH)
|
||||
header_len = 8;
|
||||
else
|
||||
fatal("%s passed ICMP packet with unhandled type %d", __func__, icmp->icmp_type);
|
||||
if (header_len > *len)
|
||||
return NULL;
|
||||
*len -= header_len;
|
||||
|
||||
return (char *) icmp + header_len;
|
||||
}
|
||||
|
||||
static bool parse_encapsulated_reply(const struct ip *ip, unsigned int len,
|
||||
Reply *reply) {
|
||||
sockaddr_in *addr_in;
|
||||
|
||||
if (ip->ip_p == IPPROTO_ICMP) {
|
||||
const struct icmp *icmp = (struct icmp *) ip_get_data(ip, &len);
|
||||
if (icmp == NULL || len < 8 || ntohs(icmp->icmp_id) != global_id)
|
||||
if (hdr.version == 4 && hdr.proto == IPPROTO_ICMP) {
|
||||
const struct icmp *icmp = (const struct icmp *) data;
|
||||
if (len < 8 || ntohs(icmp->icmp_id) != global_id)
|
||||
return false;
|
||||
reply->token = ntohs(icmp->icmp_seq);
|
||||
} else if (ip->ip_p == IPPROTO_TCP) {
|
||||
const struct tcp_hdr *tcp = (struct tcp_hdr *) ip_get_data(ip, &len);
|
||||
if (tcp == NULL || len < 2)
|
||||
} else if (hdr.version == 6 && hdr.proto == IPPROTO_ICMPV6) {
|
||||
const struct icmpv6_msg_echo *echo = (struct icmpv6_msg_echo *) ((char *) data + sizeof(struct icmpv6_hdr));
|
||||
if (len < 8 || ntohs(echo->icmpv6_id) != global_id)
|
||||
return false;
|
||||
reply->token = ntohs(echo->icmpv6_seq);
|
||||
} else if (hdr.proto == IPPROTO_TCP) {
|
||||
const struct tcp_hdr *tcp = (const struct tcp_hdr *) data;
|
||||
if (len < 2)
|
||||
return false;
|
||||
reply->token = ntohs(tcp->th_sport) ^ global_id;
|
||||
} else if (ip->ip_p == IPPROTO_UDP) {
|
||||
const struct udp_hdr *udp = (struct udp_hdr *) ip_get_data(ip, &len);
|
||||
if (udp == NULL || len < 2)
|
||||
} else if (hdr.proto == IPPROTO_UDP) {
|
||||
const struct udp_hdr *udp = (const struct udp_hdr *) data;
|
||||
if (len < 2)
|
||||
return false;
|
||||
reply->token = ntohs(udp->uh_sport) ^ global_id;
|
||||
} else if (ip->ip_p == IPPROTO_SCTP) {
|
||||
const struct sctp_hdr *sctp = (struct sctp_hdr *) ip_get_data(ip, &len);
|
||||
if (sctp == NULL || len < 2)
|
||||
} else if (hdr.proto == IPPROTO_SCTP) {
|
||||
const struct sctp_hdr *sctp = (const struct sctp_hdr *) data;
|
||||
if (len < 2)
|
||||
return false;
|
||||
reply->token = ntohs(sctp->sh_sport) ^ global_id;
|
||||
} else {
|
||||
if (len < 6)
|
||||
return false;
|
||||
/* Check IP ID for proto scan. */
|
||||
reply->token = ntohs(ip->ip_id) ^ global_id;
|
||||
reply->token = hdr.ipid ^ global_id;
|
||||
}
|
||||
|
||||
addr_in = (struct sockaddr_in *) &reply->target_addr;
|
||||
addr_in->sin_family = AF_INET;
|
||||
addr_in->sin_addr = ip->ip_dst;
|
||||
reply->target_addr = hdr.dst;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_reply(Reply *reply, pcap_t *pd, long timeout) {
|
||||
const struct ip *ip;
|
||||
unsigned int iplen;
|
||||
struct link_header linkhdr;
|
||||
sockaddr_in *addr_in;
|
||||
static bool decode_reply(const void *ip, unsigned int len, Reply *reply) {
|
||||
struct abstract_ip_hdr hdr;
|
||||
const void *data;
|
||||
|
||||
ip = (struct ip *) readip_pcap(pd, &iplen, timeout, &reply->rcvdtime,
|
||||
&linkhdr, true);
|
||||
if (ip == NULL)
|
||||
return false;
|
||||
if (ip->ip_v != 4)
|
||||
data = ip_get_data(ip, &len, &hdr);
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
addr_in = (struct sockaddr_in *) &reply->from_addr;
|
||||
addr_in->sin_family = AF_INET;
|
||||
addr_in->sin_addr = ip->ip_src;
|
||||
reply->from_addr = hdr.src;
|
||||
|
||||
reply->ttl = ip->ip_ttl;
|
||||
|
||||
if (ip->ip_p == IPPROTO_ICMP) {
|
||||
if (hdr.version == 4 && hdr.proto == IPPROTO_ICMP) {
|
||||
/* ICMP responses comprise all the TTL exceeded messages we expect from all
|
||||
probe types, as well as actual replies from ICMP probes. */
|
||||
const struct icmp *icmp;
|
||||
unsigned int icmplen;
|
||||
|
||||
icmplen = iplen;
|
||||
icmp = (struct icmp *) ip_get_data(ip, &icmplen);
|
||||
if (icmp == NULL || icmplen < 8)
|
||||
const struct icmp_hdr *icmp = (const struct icmp_hdr *) data;
|
||||
if (len < 8)
|
||||
return false;
|
||||
if ((icmp->icmp_type == ICMP_TIMEXCEED
|
||||
&& icmp->icmp_code == ICMP_TIMEXCEED_INTRANS)
|
||||
|| icmp->icmp_type == ICMP_UNREACH) {
|
||||
/* Get the encapsulated ICMP packet. */
|
||||
iplen = icmplen;
|
||||
ip = (struct ip *) icmp_get_data(icmp, &iplen);
|
||||
if (ip == NULL || ip->ip_v != 4 || iplen < 20)
|
||||
return false;
|
||||
if (!parse_encapsulated_reply(ip, iplen, reply))
|
||||
/* Get the encapsulated IP packet. */
|
||||
const void *encaps = icmp_get_data(icmp, &len);
|
||||
if (encaps == NULL)
|
||||
return false;
|
||||
return parse_encapsulated_reply(encaps, len, reply);
|
||||
} else if (icmp->icmp_type == ICMP_ECHOREPLY
|
||||
|| icmp->icmp_type == ICMP_MASKREPLY
|
||||
|| icmp->icmp_type == ICMP_TSTAMPREPLY) {
|
||||
/* Need this alternate form of header for icmp_id and icmp_seq. */
|
||||
const struct icmp *icmp = (const struct icmp *) data;
|
||||
|
||||
if (ntohs(icmp->icmp_id) != global_id)
|
||||
return false;
|
||||
reply->token = ntohs(icmp->icmp_seq);
|
||||
@@ -1139,33 +1175,51 @@ static bool read_reply(Reply *reply, pcap_t *pd, long timeout) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (ip->ip_p == IPPROTO_TCP) {
|
||||
const struct tcp_hdr *tcp;
|
||||
unsigned int tcplen;
|
||||
} else if (hdr.version == 6 && hdr.proto == IP_PROTO_ICMPV6) {
|
||||
/* ICMPv6 responses comprise all the TTL exceeded messages we expect from
|
||||
all probe types, as well as actual replies from ICMP probes. */
|
||||
const struct icmpv6_hdr *icmpv6 = (const struct icmpv6_hdr *) data;
|
||||
if (len < 2)
|
||||
return false;
|
||||
/* TIMEXCEED, UNREACH */
|
||||
if ((icmpv6->icmpv6_type == ICMPV6_TIMEXCEED
|
||||
&& icmpv6->icmpv6_code == ICMPV6_TIMEXCEED_INTRANS)
|
||||
|| icmpv6->icmpv6_type == ICMPV6_UNREACH) {
|
||||
/* Get the encapsulated IP packet. */
|
||||
const void *encaps = icmpv6_get_data(icmpv6, &len);
|
||||
if (encaps == NULL)
|
||||
return false;
|
||||
return parse_encapsulated_reply(encaps, len, reply);
|
||||
} else if (icmpv6->icmpv6_type == ICMPV6_ECHOREPLY) {
|
||||
/* MASKREPLY, TSTAMPREPLY */
|
||||
const struct icmpv6_msg_echo *echo;
|
||||
|
||||
tcplen = iplen;
|
||||
tcp = (struct tcp_hdr *) ip_get_data(ip, &tcplen);
|
||||
if (tcp == NULL || tcplen < 4)
|
||||
if (len < sizeof(*icmpv6) + 4)
|
||||
return false;
|
||||
echo = (struct icmpv6_msg_echo *) ((char *) icmpv6 + sizeof(*icmpv6));
|
||||
if (ntohs(echo->icmpv6_id) != global_id)
|
||||
return false;
|
||||
reply->token = ntohs(echo->icmpv6_seq);
|
||||
/* Reply came directly from the target. */
|
||||
reply->target_addr = reply->from_addr;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (hdr.proto == IPPROTO_TCP) {
|
||||
const struct tcp_hdr *tcp = (const struct tcp_hdr *) data;
|
||||
if (len < 4)
|
||||
return false;
|
||||
reply->token = ntohs(tcp->th_dport) ^ global_id;
|
||||
reply->target_addr = reply->from_addr;
|
||||
} else if (ip->ip_p == IPPROTO_UDP) {
|
||||
const struct udp_hdr *udp;
|
||||
unsigned int udplen;
|
||||
|
||||
udplen = iplen;
|
||||
udp = (struct udp_hdr *) ip_get_data(ip, &udplen);
|
||||
if (udp == NULL || udplen < 4)
|
||||
} else if (hdr.proto == IPPROTO_UDP) {
|
||||
const struct udp_hdr *udp = (const struct udp_hdr *) data;
|
||||
if (len < 4)
|
||||
return false;
|
||||
reply->token = ntohs(udp->uh_dport) ^ global_id;
|
||||
reply->target_addr = reply->from_addr;
|
||||
} else if (ip->ip_p == IPPROTO_SCTP) {
|
||||
const struct sctp_hdr *sctp;
|
||||
unsigned int sctplen;
|
||||
|
||||
sctplen = iplen;
|
||||
sctp = (struct sctp_hdr *) ip_get_data(ip, &sctplen);
|
||||
if (sctp == NULL || sctplen < 4)
|
||||
} else if (hdr.proto == IPPROTO_SCTP) {
|
||||
const struct sctp_hdr *sctp = (const struct sctp_hdr *) data;
|
||||
if (len < 4)
|
||||
return false;
|
||||
reply->token = ntohs(sctp->sh_dport) ^ global_id;
|
||||
reply->target_addr = reply->from_addr;
|
||||
@@ -1176,6 +1230,20 @@ static bool read_reply(Reply *reply, pcap_t *pd, long timeout) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_reply(Reply *reply, pcap_t *pd, long timeout) {
|
||||
const struct ip *ip;
|
||||
unsigned int iplen;
|
||||
struct link_header linkhdr;
|
||||
|
||||
ip = (struct ip *) readip46_pcap(pd, &iplen, timeout, &reply->rcvdtime, &linkhdr, true);
|
||||
if (ip == NULL)
|
||||
return false;
|
||||
if (ip->ip_v == 4 || ip->ip_v == 6)
|
||||
return decode_reply(ip, iplen, reply);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void TracerouteState::read_replies(long timeout) {
|
||||
struct sockaddr_storage ss;
|
||||
struct timeval now;
|
||||
@@ -1265,12 +1333,19 @@ void TracerouteState::remove_finished_hosts() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Dummy class to use sockaddr_storage as a map key. */
|
||||
struct lt_sockaddr_storage {
|
||||
bool operator()(const struct sockaddr_storage& a, const struct sockaddr_storage& b) {
|
||||
return sockaddr_storage_cmp(&a, &b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
/* Find the reverse-DNS names of the hops. */
|
||||
void TracerouteState::resolve_hops() {
|
||||
std::set<uint32_t> addrs;
|
||||
std::set<uint32_t>::iterator addr_iter;
|
||||
std::set<sockaddr_storage, lt_sockaddr_storage> addrs;
|
||||
std::set<sockaddr_storage, lt_sockaddr_storage>::iterator addr_iter;
|
||||
std::vector<HostState *>::iterator host_iter;
|
||||
std::map<uint32_t, const char *> name_map;
|
||||
std::map<sockaddr_storage, const char *, lt_sockaddr_storage> name_map;
|
||||
Target **targets;
|
||||
Hop *hop;
|
||||
int i, n;
|
||||
@@ -1280,9 +1355,8 @@ void TracerouteState::resolve_hops() {
|
||||
inefficient. */
|
||||
for (host_iter = hosts.begin(); host_iter != hosts.end(); host_iter++) {
|
||||
for (hop = (*host_iter)->hops; hop != NULL; hop = hop->parent) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) &hop->addr;
|
||||
if (hop->addr.ss_family == AF_INET)
|
||||
addrs.insert(sin->sin_addr.s_addr);
|
||||
if (hop->addr.ss_family != AF_UNSPEC)
|
||||
addrs.insert(hop->addr);
|
||||
}
|
||||
}
|
||||
n = addrs.size();
|
||||
@@ -1292,11 +1366,8 @@ void TracerouteState::resolve_hops() {
|
||||
i = 0;
|
||||
addr_iter = addrs.begin();
|
||||
while (i < n) {
|
||||
struct sockaddr_in sin;
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = *addr_iter;
|
||||
targets[i] = new Target();
|
||||
targets[i]->setTargetSockAddr((struct sockaddr_storage *) &sin, sizeof(sin));
|
||||
targets[i]->setTargetSockAddr(&*addr_iter, sizeof(*addr_iter));
|
||||
targets[i]->flags = HOST_UP;
|
||||
i++;
|
||||
addr_iter++;
|
||||
@@ -1304,17 +1375,20 @@ void TracerouteState::resolve_hops() {
|
||||
nmap_mass_rdns(targets, n);
|
||||
/* Third, make a map from addresses to names for easy lookup. */
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sockaddr_storage ss;
|
||||
size_t ss_len;
|
||||
const char *hostname = targets[i]->HostName();
|
||||
if (*hostname == '\0')
|
||||
hostname = NULL;
|
||||
name_map[targets[i]->v4hostip()->s_addr] = hostname;
|
||||
ss_len = sizeof(ss);
|
||||
targets[i]->TargetSockAddr(&ss, &ss_len);
|
||||
name_map[ss] = hostname;
|
||||
}
|
||||
/* Finally, copy the names into the hops. */
|
||||
for (host_iter = hosts.begin(); host_iter != hosts.end(); host_iter++) {
|
||||
for (hop = (*host_iter)->hops; hop != NULL; hop = hop->parent) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) &hop->addr;
|
||||
if (hop->addr.ss_family == AF_INET) {
|
||||
const char *hostname = name_map[sin->sin_addr.s_addr];
|
||||
if (hop->addr.ss_family != AF_UNSPEC) {
|
||||
const char *hostname = name_map[hop->addr];
|
||||
if (hostname != NULL)
|
||||
hop->hostname = hostname;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user