diff --git a/CHANGELOG b/CHANGELOG index 5a7b7c1dc..651f8ae44 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,14 @@ o Removed the NmapFE frontend. o Updated IANA assignment IP list for random IP (-iR) generation. [Kris] +o There is no longer any artificial limit on the number of ports or + protocols that can be used for host discovery. Port lists for ping + scan now use the same syntax as the -p option except that T:, U:, + and P: are not allowed. This means that you can do + nmap -PS1-1000 target + nmap -PAhttp,https target + nmap -PU'[-]' target + 4.22SOC8 o Removed the old massping() system, since the functionality has now diff --git a/NmapOps.cc b/NmapOps.cc index 8c8a03c90..f4f3aec11 100644 --- a/NmapOps.cc +++ b/NmapOps.cc @@ -101,6 +101,7 @@ #include "nmap.h" #include "nbase.h" #include "NmapOps.h" +#include "services.h" #include "utils.h" #ifdef WIN32 #include "winfix.h" @@ -115,6 +116,10 @@ NmapOps::NmapOps() { } NmapOps::~NmapOps() { + if (ping_synprobes) free(ping_synprobes); + if (ping_ackprobes) free(ping_ackprobes); + if (ping_udpprobes) free(ping_udpprobes); + if (ping_protoprobes) free(ping_protoprobes); if (datadir) free(datadir); if (xsl_stylesheet) free(xsl_stylesheet); } @@ -203,6 +208,7 @@ void NmapOps::Initialize() { magic_port = 33000 + (get_random_uint() % 31000); magic_port_set = 0; num_ping_synprobes = num_ping_ackprobes = num_ping_udpprobes = num_ping_protoprobes = 0; + ping_synprobes = ping_ackprobes = ping_udpprobes = ping_protoprobes = NULL; timing_level = 3; max_parallelism = 0; min_parallelism = 0; @@ -304,8 +310,8 @@ void NmapOps::ValidateOptions() { if (pingtype == PINGTYPE_UNKNOWN) { if (isr00t && af() == AF_INET) pingtype = DEFAULT_PING_TYPES; else pingtype = PINGTYPE_TCP; // if nonr00t or IPv6 - num_ping_ackprobes = 1; - ping_ackprobes[0] = DEFAULT_TCP_PROBE_PORT; + getpts_simple(DEFAULT_TCP_PROBE_PORT_SPEC, SCAN_TCP_PORT, &o.ping_ackprobes, &o.num_ping_ackprobes); + assert(o.num_ping_ackprobes > 0); } /* Insure that at least one scantype is selected */ @@ -322,10 +328,12 @@ void NmapOps::ValidateOptions() { fatal("Cannot use both SYN and ACK ping probes if you are nonroot or using IPv6"); } + /* Pretend we wanted SYN probes all along. */ if (num_ping_ackprobes > 0) { - memcpy(ping_synprobes, ping_ackprobes, num_ping_ackprobes * sizeof(*ping_synprobes)); num_ping_synprobes = num_ping_ackprobes; + ping_synprobes = ping_ackprobes; num_ping_ackprobes = 0; + ping_ackprobes = NULL; } pingtype &= ~PINGTYPE_TCP_USE_ACK; pingtype |= PINGTYPE_TCP_USE_SYN; @@ -384,8 +392,8 @@ void NmapOps::ValidateOptions() { pingtype = PINGTYPE_TCP; if (num_ping_synprobes == 0) { - num_ping_synprobes = 1; - ping_synprobes[0] = DEFAULT_TCP_PROBE_PORT; + getpts_simple(DEFAULT_TCP_PROBE_PORT_SPEC, SCAN_TCP_PORT, &o.ping_synprobes, &o.num_ping_synprobes); + assert(o.num_ping_synprobes > 0); } } #endif diff --git a/NmapOps.h b/NmapOps.h index f088d7f13..60a3dbb98 100644 --- a/NmapOps.h +++ b/NmapOps.h @@ -191,13 +191,13 @@ class NmapOps { unsigned short magic_port_set; /* Was this set by user? */ int num_ping_synprobes; /* The "synprobes" are also used when doing a connect() ping */ - u16 ping_synprobes[MAX_PROBE_PORTS]; + u16 *ping_synprobes; int num_ping_ackprobes; - u16 ping_ackprobes[MAX_PROBE_PORTS]; + u16 *ping_ackprobes; int num_ping_udpprobes; - u16 ping_udpprobes[MAX_PROBE_PORTS]; + u16 *ping_udpprobes; int num_ping_protoprobes; - u16 ping_protoprobes[MAX_PROBE_PORTS]; + u16 *ping_protoprobes; /* Scan timing/politeness issues */ int timing_level; // 0-5, corresponding to Paranoid, Sneaky, Polite, Normal, Aggressive, Insane int max_parallelism; // 0 means it has not been set diff --git a/docs/refguide.xml b/docs/refguide.xml index f9e667b54..0ab0dd8b3 100644 --- a/docs/refguide.xml +++ b/docs/refguide.xml @@ -449,12 +449,15 @@ you would expect. This option sends an empty TCP packet with the SYN flag set. The default destination port is 80 (configurable - at compile time by changing DEFAULT_TCP_PROBE_PORT in - nmap.h), but an alternate port can be - specified as a parameter. A comma separated list of ports - can even be specified - (e.g. ), in - which case probes will be attempted against each port in + at compile time by changing DEFAULT_TCP_PROBE_PORT_SPEC in + nmap.h). Alternate ports can be + specified as a parameter. The syntax is the same as for the + except that port type specifiers like + T: are not allowed. Examples are + and + . Note that there + can be no space between and the port + list. If multiple probes are specified they will be sent in parallel. The SYN flag suggests to the remote system that you @@ -563,8 +566,8 @@ you would expect. and options. If no ports are specified, the default is 31338. This default can be configured at compile-time by changing - DEFAULT_UDP_PROBE_PORT in nmap.h. A - highly uncommon port is used by default because sending to + DEFAULT_UDP_PROBE_PORT_SPEC in nmap.h. + A highly uncommon port is used by default because sending to open ports is often undesirable for this particular scan type. @@ -659,11 +662,12 @@ you would expect. no protocols are specified, the default is to send multiple IP packets for ICMP (protocol 1), IGMP (protocol 2), and IP-in-IP (protocol 4). The default protocols can be - configured at compile-time by changing DEFAULT_PROTO_PROBE_PORTS - in nmap.h. Note that for the ICMP, IGMP, - TCP (protocol 6), and UDP (protocol 17), the packets are sent - with the additional headers while other protocols are sent with - no additional data beyond the IP header (unless the + configured at compile-time by changing + DEFAULT_PROTO_PROBE_PORT_SPEC in nmap.h. + Note that for the ICMP, IGMP, TCP (protocol 6), and UDP + (protocol 17), the packets are sent with the additional + headers while other protocols are sent with no additional data + beyond the IP header (unless the option is specified). This host discovery method looks for responses in the diff --git a/idle_scan.cc b/idle_scan.cc index b7f25773d..ba2c595a8 100644 --- a/idle_scan.cc +++ b/idle_scan.cc @@ -108,6 +108,7 @@ #include "osscan.h" #include "nmap.h" #include "NmapOps.h" +#include "services.h" #include "Target.h" #include "utils.h" @@ -330,9 +331,19 @@ static void initialize_idleproxy(struct idle_proxy_info *proxy, char *proxyName, fatal("Invalid port number given in IP ID zombie specification: %s", proxyName); } } else { - proxy->probe_port = (o.num_ping_synprobes > 0)? o.ping_synprobes[0] : - (o.num_ping_ackprobes > 0)? o.ping_ackprobes[0] : - DEFAULT_TCP_PROBE_PORT; + if (o.num_ping_synprobes > 0) { + proxy->probe_port = o.ping_synprobes[0]; + } else if (o.num_ping_ackprobes > 0) { + proxy->probe_port = o.ping_ackprobes[0]; + } else { + u16 *ports; + int count; + + getpts_simple(DEFAULT_TCP_PROBE_PORT_SPEC, SCAN_TCP_PORT, &ports, &count); + assert(count > 0); + proxy->probe_port = ports[0]; + free(ports); + } } proxy->host.setHostName(name); diff --git a/nmap.cc b/nmap.cc index 6efd4980e..b24619ff1 100644 --- a/nmap.cc +++ b/nmap.cc @@ -492,7 +492,6 @@ int nmap_main(int argc, char *argv[]) { Target *currenths; vector Targets; char *portlist = NULL; /* Ports list specified by user */ - char *proberr; int sourceaddrwarning = 0; /* Have we warned them yet about unguessable source addresses? */ unsigned int ideal_scan_group_sz = 0; @@ -1029,70 +1028,68 @@ int nmap_main(int argc, char *argv[]) { o.pingtype |= PINGTYPE_ARP; else if (*optarg == 'S') { o.pingtype |= (PINGTYPE_TCP|PINGTYPE_TCP_USE_SYN); - if (isdigit((int) *(optarg+1))) - { - o.num_ping_synprobes = numberlist2array(optarg+1, o.ping_synprobes, sizeof(o.ping_synprobes), &proberr); - if (o.num_ping_synprobes < 0) { - fatal("Bogus argument to -PS: %s", proberr); - } + if (*(optarg + 1) != '\0') { + getpts_simple(optarg + 1, SCAN_TCP_PORT, &o.ping_synprobes, &o.num_ping_synprobes); + if (o.num_ping_synprobes <= 0) { + fatal("Bogus argument to -PS: %s", optarg + 1); } + } if (o.num_ping_synprobes == 0) { - o.num_ping_synprobes = 1; - o.ping_synprobes[0] = DEFAULT_TCP_PROBE_PORT; + getpts_simple(DEFAULT_TCP_PROBE_PORT_SPEC, SCAN_TCP_PORT, &o.ping_synprobes, &o.num_ping_synprobes); + assert(o.num_ping_synprobes > 0); } } else if (*optarg == 'T' || *optarg == 'A') { /* NmapOps::ValidateOptions() takes care of changing this to SYN if not root or if IPv6 */ o.pingtype |= (PINGTYPE_TCP|PINGTYPE_TCP_USE_ACK); - if (isdigit((int) *(optarg+1))) { - o.num_ping_ackprobes = numberlist2array(optarg+1, o.ping_ackprobes, sizeof(o.ping_ackprobes), &proberr); - if (o.num_ping_ackprobes < 0) { - fatal("Bogus argument to -PA: %s", proberr); + if (*(optarg + 1) != '\0') { + getpts_simple(optarg + 1, SCAN_TCP_PORT, &o.ping_ackprobes, &o.num_ping_ackprobes); + if (o.num_ping_ackprobes <= 0) { + fatal("Bogus argument to -PA: %s", optarg + 1); } } if (o.num_ping_ackprobes == 0) { - o.num_ping_ackprobes = 1; - o.ping_ackprobes[0] = DEFAULT_TCP_PROBE_PORT; + getpts_simple(DEFAULT_TCP_PROBE_PORT_SPEC, SCAN_TCP_PORT, &o.ping_ackprobes, &o.num_ping_ackprobes); + assert(o.num_ping_ackprobes > 0); } } else if (*optarg == 'U') { o.pingtype |= (PINGTYPE_UDP); - if (isdigit((int) *(optarg+1))) { - o.num_ping_udpprobes = numberlist2array(optarg+1, o.ping_udpprobes, sizeof(o.ping_udpprobes), &proberr); - if (o.num_ping_udpprobes < 0) { - fatal("Bogus argument to -PU: %s", proberr); + if (*(optarg + 1) != '\0') { + getpts_simple(optarg + 1, SCAN_UDP_PORT, &o.ping_udpprobes, &o.num_ping_udpprobes); + if (o.num_ping_udpprobes <= 0) { + fatal("Bogus argument to -PU: %s", optarg + 1); } } if (o.num_ping_udpprobes == 0) { - o.num_ping_udpprobes = 1; - o.ping_udpprobes[0] = DEFAULT_UDP_PROBE_PORT; + getpts_simple(DEFAULT_UDP_PROBE_PORT_SPEC, SCAN_UDP_PORT, &o.ping_udpprobes, &o.num_ping_udpprobes); + assert(o.num_ping_udpprobes > 0); } } else if (*optarg == 'B') { o.pingtype = (PINGTYPE_TCP|PINGTYPE_TCP_USE_ACK|PINGTYPE_ICMP_PING); - if (isdigit((int) *(optarg+1))) { - o.num_ping_ackprobes = numberlist2array(optarg+1, o.ping_ackprobes, sizeof(o.ping_ackprobes), &proberr); - if (o.num_ping_ackprobes < 0) { - fatal("Bogus argument to -PB: %s", proberr); + if (*(optarg + 1) != '\0') { + getpts_simple(optarg + 1, SCAN_TCP_PORT, &o.ping_ackprobes, &o.num_ping_ackprobes); + if (o.num_ping_ackprobes <= 0) { + fatal("Bogus argument to -PB: %s", optarg + 1); } } if (o.num_ping_ackprobes == 0) { - o.num_ping_ackprobes = 1; - o.ping_ackprobes[0] = DEFAULT_TCP_PROBE_PORT; + getpts_simple(DEFAULT_TCP_PROBE_PORT_SPEC, SCAN_TCP_PORT, &o.ping_ackprobes, &o.num_ping_ackprobes); + assert(o.num_ping_ackprobes > 0); } } else if (*optarg == 'O') { o.pingtype |= PINGTYPE_PROTO; - if (isdigit((int) *(optarg+1))) { - o.num_ping_protoprobes = numberlist2array(optarg+1, o.ping_protoprobes, sizeof(o.ping_protoprobes), &proberr, 0, 255); - if (o.num_ping_protoprobes < 0) { - fatal("Bogus argument to -PO: %s", proberr); + if (*(optarg + 1) != '\0') { + getpts_simple(optarg + 1, SCAN_PROTOCOLS, &o.ping_protoprobes, &o.num_ping_protoprobes); + if (o.num_ping_protoprobes <= 0) { + fatal("Bogus argument to -PO: %s", optarg + 1); } } if (o.num_ping_protoprobes == 0) { - u16 probes[] = DEFAULT_PROTO_PROBE_PORTS; - o.num_ping_protoprobes = sizeof probes / sizeof *probes; - memcpy(o.ping_protoprobes, probes, sizeof probes); + getpts_simple(DEFAULT_PROTO_PROBE_PORT_SPEC, SCAN_PROTOCOLS, &o.ping_protoprobes, &o.num_ping_protoprobes); + assert(o.num_ping_protoprobes > 0); } } else { fatal("Illegal Argument to -P, use -PN, -PO, -PI, -PB, -PE, -PM, -PP, -PA, -PU, -PT, or -PT80 (or whatever number you want for the TCP probe destination port)"); @@ -2059,8 +2056,8 @@ void init_socket(int sd) { * the outer part of the port expression. It's "closed". */ -static void getpts_aux(char *origexpr, int nested, u8 *porttbl, int range_type, int -*portwarning); +static void getpts_aux(char *origexpr, int nested, u8 *porttbl, int range_type, + int *portwarning, bool change_range_type = true); struct scan_lists *getpts(char *origexpr) { u8 *porttbl; @@ -2125,10 +2122,49 @@ struct scan_lists *getpts(char *origexpr) { } +/* This function is like getpts except that instead of returning several lists + of ports in a struct scan_lists, it allocates only one list and stores it in + the list and count arguments. For that reason, T:, U:, and P: restrictions + are not allowed and only one bit in range_type may be set. */ +void getpts_simple(char *origexpr, int range_type, + unsigned short **list, int *count) { + u8 *porttbl; + int portwarning = 0; + int i, j; -/* getpts() (see above) is a wrapper for this function */ + /* Make sure that only one bit in range_type is set (or that range_type is 0, + which is useless but not incorrect). */ + assert((range_type & (range_type - 1)) == 0); -static void getpts_aux(char *origexpr, int nested, u8 *porttbl, int range_type, int *portwarning) { + porttbl = (u8 *) safe_zalloc(65536); + + /* Get the ports but do not allow changing the type with T:, U:, or P:. */ + getpts_aux(origexpr, 0, porttbl, range_type, &portwarning, false); + + /* Count how many are set. */ + *count = 0; + for (i = 0; i <= 65535; i++) { + if (porttbl[i] & range_type) + (*count)++; + } + + if (*count == 0) + return; + + *list = (unsigned short *) safe_zalloc(*count * sizeof(unsigned short)); + + /* Fill in the list. */ + for (i = 0, j = 0; i <= 65535; i++) { + if (porttbl[i] & range_type) + (*list)[j++] = i; + } + + free(porttbl); +} + +/* getpts() and getpts_simple() (see above) are wrappers for this function */ + +static void getpts_aux(char *origexpr, int nested, u8 *porttbl, int range_type, int *portwarning, bool change_range_type) { long rangestart = -2343242, rangeend = -9324423; char *current_range; char *endptr; @@ -2140,21 +2176,24 @@ static void getpts_aux(char *origexpr, int nested, u8 *porttbl, int range_type, while(isspace((int) *current_range)) current_range++; /* I don't know why I should allow spaces here, but I will */ - if (*current_range == 'T' && *++current_range == ':') { - current_range++; - range_type = SCAN_TCP_PORT; - continue; - } - if (*current_range == 'U' && *++current_range == ':') { - current_range++; - range_type = SCAN_UDP_PORT; - continue; - } - if (*current_range == 'P' && *++current_range == ':') { - current_range++; - range_type = SCAN_PROTOCOLS; - continue; + if (change_range_type) { + if (*current_range == 'T' && *++current_range == ':') { + current_range++; + range_type = SCAN_TCP_PORT; + continue; + } + if (*current_range == 'U' && *++current_range == ':') { + current_range++; + range_type = SCAN_UDP_PORT; + continue; + } + if (*current_range == 'P' && *++current_range == ':') { + current_range++; + range_type = SCAN_PROTOCOLS; + continue; + } } + if (*current_range == '[') { if (nested) fatal("Can't nest [] brackets in -p switch"); diff --git a/nmap.h b/nmap.h index 924c0a887..eb40c6118 100644 --- a/nmap.h +++ b/nmap.h @@ -272,13 +272,14 @@ void *realloc(); #define MAX_TIMEOUTS MAX_SOCKETS /* How many timed out connection attempts in a row before we decide the host is dead? */ -#define DEFAULT_TCP_PROBE_PORT 80 /* The port TCP probes go to if unspecified - by user -- uber hackers change this - to 113 */ -#define DEFAULT_UDP_PROBE_PORT 31338 /* The port UDP probes (esp. "ping" probes) go to if unspecified - by user */ -#define DEFAULT_PROTO_PROBE_PORTS { 1, 2, 4 } /* The IPProto ping probes to use if unspecified - by user */ +#define DEFAULT_TCP_PROBE_PORT_SPEC "80" /* The ports TCP probes go to if + unspecified by user -- uber hackers + change this to 113 */ +#define DEFAULT_UDP_PROBE_PORT_SPEC "31338" /* The port UDP probes (esp. "ping" + probes) go to if unspecified by + user */ +#define DEFAULT_PROTO_PROBE_PORT_SPEC "1,2,4" /* The IPProto ping probes to use + if unspecified by user */ #define MAX_DECOYS 128 /* How many decoys are allowed? */ @@ -412,6 +413,8 @@ int ftp_anon_connect(struct ftpinfo *ftp); /* port manipulators */ struct scan_lists *getpts(char *expr); /* someone stole the name getports()! */ +void getpts_simple(char *origexpr, int range_type, + unsigned short **list, int *count); void free_scan_lists(struct scan_lists *ports); /* socket manipulation functions */