Index: NmapOps.cc =================================================================== --- NmapOps.cc (revision 33033) +++ NmapOps.cc (working copy) @@ -167,6 +167,10 @@ free(portlist); portlist = NULL; } + if (exclude_portlist) { + free(exclude_portlist); + exclude_portlist = NULL; + } if (proxy_chain) { nsock_proxychain_delete(proxy_chain); proxy_chain = NULL; @@ -382,6 +386,7 @@ inputfd = NULL; idleProxy = NULL; portlist = NULL; + exclude_portlist = NULL; proxy_chain = NULL; } Index: NmapOps.h =================================================================== --- NmapOps.h (revision 33033) +++ NmapOps.h (working copy) @@ -372,6 +372,7 @@ char *exclude_spec; FILE *inputfd; char *portlist; /* Ports list specified by user */ + char *exclude_portlist; /* exclude-ports list specified by user */ nsock_proxychain proxy_chain; Index: nmap.cc =================================================================== --- nmap.cc (revision 33033) +++ nmap.cc (working copy) @@ -255,6 +255,7 @@ "PORT SPECIFICATION AND SCAN ORDER:\n" " -p : Only scan specified ports\n" " Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080,S:9\n" + " --exclude-ports : Exclude the specified ports from scanning\n" " -F: Fast mode - Scan fewer ports than the default scan\n" " -r: Scan ports consecutively - don't randomize\n" " --top-ports : Scan most common ports\n" @@ -630,6 +631,8 @@ {"dns-servers", required_argument, 0, 0}, {"port-ratio", required_argument, 0, 0}, {"port_ratio", required_argument, 0, 0}, + {"exclude-ports", required_argument, 0, 0}, + {"exclude_ports", required_argument, 0, 0}, {"top-ports", required_argument, 0, 0}, {"top_ports", required_argument, 0, 0}, #ifndef NOLUA @@ -928,6 +931,10 @@ o.topportlevel = strtod(optarg, &ptr); if (!ptr || o.topportlevel < 0 || o.topportlevel >= 1) fatal("--port-ratio should be between [0 and 1)"); + } else if (optcmp(long_options[option_index].name, "exclude-ports") == 0) { + if (o.exclude_portlist) + fatal("Only 1 --exclude-ports option allowed, separate multiple ranges with commas."); + o.exclude_portlist = strdup(optarg); } else if (optcmp(long_options[option_index].name, "top-ports") == 0) { char *ptr; o.topportlevel = strtod(optarg, &ptr); @@ -1482,7 +1489,7 @@ else getpts((char *) (o.fastscan ? "[P:0-]" : "0-"), &ports); // Default protocols to scan } else if (!o.noportscan) { - gettoppts(o.topportlevel, o.portlist, &ports); + gettoppts(o.topportlevel, o.portlist, &ports, o.exclude_portlist); } // Uncomment the following line to use the common lisp port spec test suite @@ -1547,6 +1554,10 @@ /* Warn if setuid/setgid. */ check_setugid(); + /* Remove any ports that are in the exclusion list, if they haven't been already been handled by gettoppts() */ + if (o.topportlevel==-1) + removepts(o.exclude_portlist, &ports); + /* By now, we've got our port lists. Give the user a warning if no * ports are specified for the type of scan being requested. Other things * (such as OS ident scan) might break cause no ports were specified, but @@ -1561,6 +1572,16 @@ if (o.ipprotscan && ports.prot_count == 0) error("WARNING: protocol scan was requested, but no protocols were specified to be scanned. Skipping this scan type."); + if (o.pingtype & PINGTYPE_TCP && ports.syn_ping_count+ports.ack_ping_count == 0) + error("WARNING: a TCP ping scan was requested, but after excluding requested TCP ports, none remain. Skipping this scan type."); + if (o.pingtype & PINGTYPE_UDP && ports.udp_ping_count == 0) + error("WARNING: a UDP ping scan was requested, but after excluding requested UDP ports, none remain. Skipping this scan type."); + if (o.pingtype & PINGTYPE_SCTP_INIT && ports.sctp_ping_count == 0) + error("WARNING: a SCTP ping scan was requested, but after excluding requested SCTP ports, none remain. Skipping this scan type."); + if (o.pingtype & PINGTYPE_PROTO && ports.proto_ping_count == 0) + error("WARNING: a IP Protocol ping scan was requested, but after excluding requested protocols, none remain. Skipping this scan type."); + + /* Set up our array of decoys! */ if (o.decoyturn == -1) { o.decoyturn = (o.numdecoys == 0) ? 0 : get_random_uint() % o.numdecoys; @@ -2366,6 +2387,11 @@ range_type |= SCAN_SCTP_PORT; if (o.ipprotscan) range_type |= SCAN_PROTOCOLS; + if (o.noportscan && o.exclude_portlist) { // We want to exclude from ping scans in this case but we take port list normally and then removepts() handles it + range_type |= SCAN_TCP_PORT; + range_type |= SCAN_UDP_PORT; + range_type |= SCAN_SCTP_PORT; + } porttbl = (u8 *) safe_zalloc(65536); @@ -2462,6 +2488,80 @@ free(porttbl); } +/* removepts() takes a port specification and removes any matching ports + from the given scan_lists struct. */ + +static int remaining_ports(unsigned short int *ports, int count, unsigned short int *exclude_ports, int exclude_count, const char *type = ""); + +void removepts(const char *expr, struct scan_lists * ports) { + static struct scan_lists exclude_ports; + + if (!expr) + return; + + getpts(expr, &exclude_ports); + + #define SUBTRACT_PORTS(type,excludetype) \ + ports->type##_count = remaining_ports(ports->type##_ports, \ + ports->type##_count, \ + exclude_ports.excludetype##_ports, \ + exclude_ports.excludetype##_count, \ + #type) + + SUBTRACT_PORTS(tcp, tcp); + SUBTRACT_PORTS(udp, udp); + SUBTRACT_PORTS(sctp, sctp); + SUBTRACT_PORTS(syn_ping, tcp); + SUBTRACT_PORTS(ack_ping, tcp); + SUBTRACT_PORTS(udp_ping, udp); + SUBTRACT_PORTS(sctp_ping, sctp); + + #define prot_ports prots + SUBTRACT_PORTS(prot, prot); + SUBTRACT_PORTS(proto_ping, prot); + #undef prot_ports + + #undef SUBTRACT_PORTS + + free_scan_lists(&exclude_ports); +} + +/* This function returns the number of ports that remain after the excluded ports + are removed from the ports. It places these ports at the start of the ports array. */ +static int remaining_ports(unsigned short int *ports, int count, unsigned short int *exclude_ports, int exclude_count, const char *type) { + static bool has_been_excluded[65536]; + int i, j; + + if (count == 0 || exclude_count == 0) + return count; + + if (o.debugging > 1) + log_write(LOG_STDOUT, "Removed %s ports: ", type); + + for (i = 0; i < 65536; i++) + has_been_excluded[i] = false; + for (i = 0; i < exclude_count; i++) + has_been_excluded[exclude_ports[i]] = true; + for (i = 0, j = 0; i < count; i++) + if (!has_been_excluded[ports[i]]) + ports[j++] = ports[i]; + else if (o.debugging > 1) + log_write(LOG_STDOUT, "%d ", ports[i]); + + if (o.debugging > 1) { + if (count-j) { + log_write(LOG_STDOUT, "\n"); + } else { + log_write(LOG_STDOUT, "None\n"); + } + } + if (o.debugging && count-j) { + log_write(LOG_STDOUT, "Removed %d %s ports that would have been considered for scanning otherwise.\n", count-j, type); + } + + return j; +} + /* getpts() and getpts_simple() (see above) are wrappers for this function */ static void getpts_aux(const char *origexpr, int nested, u8 *porttbl, int range_type, int *portwarning, bool change_range_type) { @@ -2535,10 +2635,10 @@ rangestart = strtol(current_range, &endptr, 10); if (range_type & SCAN_PROTOCOLS) { if (rangestart < 0 || rangestart > 255) - fatal("Protocols to be scanned must be between 0 and 255 inclusive"); + fatal("Protocols specified must be between 0 and 255 inclusive"); } else { if (rangestart < 0 || rangestart > 65535) - fatal("Ports to be scanned must be between 0 and 65535 inclusive"); + fatal("Ports specified must be between 0 and 65535 inclusive"); } current_range = endptr; while (isspace((int) (unsigned char) *current_range)) current_range++; @@ -2582,10 +2682,10 @@ rangeend = strtol(current_range, &endptr, 10); if (range_type & SCAN_PROTOCOLS) { if (rangeend < 0 || rangeend > 255) - fatal("Protocols to be scanned must be between 0 and 255 inclusive"); + fatal("Protocols specified must be between 0 and 255 inclusive"); } else { if (rangeend < 0 || rangeend > 65535) - fatal("Ports to be scanned must be between 0 and 65535 inclusive"); + fatal("Ports specified must be between 0 and 65535 inclusive"); } current_range = endptr; } else { Index: nmap.h =================================================================== --- nmap.h (revision 33033) +++ nmap.h (working copy) @@ -436,6 +436,7 @@ void getpts(const char *expr, struct scan_lists * ports); /* someone stole the name getports()! */ void getpts_simple(const char *origexpr, int range_type, unsigned short **list, int *count); +void removepts(const char *expr, struct scan_lists * ports); void free_scan_lists(struct scan_lists *ports); /* Renamed main so that interactive mode could preprocess when necessary */ Index: services.cc =================================================================== --- services.cc (revision 33033) +++ services.cc (working copy) @@ -424,10 +424,13 @@ // If level is 1 or above, we treat it as a "top ports" directive // and return the N highest ratio ports (where N==level). // +// If the fourth parameter is not NULL, then the specified ports +// are excluded first and only then are the top N ports taken +// // This function doesn't support IP protocol scan so only call this // function if o.TCPScan() || o.UDPScan() || o.SCTPScan() -void gettoppts(double level, char *portlist, struct scan_lists * ports) { +void gettoppts(double level, char *portlist, struct scan_lists * ports, char *exclude_ports) { int ti=0, ui=0, si=0; struct scan_lists ptsdata = { 0 }; bool ptsdata_initialized = false; @@ -466,7 +469,14 @@ if (portlist){ getpts(portlist, &ptsdata); ptsdata_initialized = true; + } else if (exclude_ports) { + getpts("-", &ptsdata); + ptsdata_initialized = true; } + + if (ptsdata_initialized && exclude_ports) + removepts(exclude_ports, &ptsdata); + if (level < 1) { for (i = services_by_ratio.begin(); i != services_by_ratio.end(); i++) { current = &(*i); Index: services.h =================================================================== --- services.h (revision 33033) +++ services.h (working copy) @@ -150,7 +150,7 @@ int addportsfromservmask(char *mask, u8 *porttbl, int range_type); struct servent *nmap_getservbyport(int port, const char *proto); -void gettoppts(double level, char *portlist, struct scan_lists * ports); +void gettoppts(double level, char *portlist, struct scan_lists * ports, char *exclude_list = NULL); void free_services();