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 */