1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-11 18:29:03 +00:00

Majek's Portlist change patch

This commit is contained in:
fyodor
2006-05-14 05:00:58 +00:00
parent 396a6c6d48
commit 37fac543b5
10 changed files with 295 additions and 230 deletions

View File

@@ -1,11 +1,30 @@
# Nmap Changelog ($Id$); -*-text-*- # Nmap Changelog ($Id$); -*-text-*-
o Integrated all of your submissions (about a thousand) from the first
quarter of this year! Please keep 'em coming! The DB has increased
from 3,153 signatures representing 381 protocols in 4.03 to 3,441
signatures representing 401 protocols. No other tool comes close!
Many of the already existing match lines were improved too. Thanks
to Version Detection Czar Doug Hoyte for doing this.
o Fixed a couple possible memory leaks reported by Ted Kremenek
(kremenek(a)cs.stanford.edu) from the Stanford University sofware
static analysis lab ("Checker" project).
o Nmap now prints a warning when you specify a target name which o Nmap now prints a warning when you specify a target name which
resolves to multiple IP addresses. Nmap proceeds to scan only the resolves to multiple IP addresses. Nmap proceeds to scan only the
first of those addresses (as it always has done). Thanks to Doug first of those addresses (as it always has done). Thanks to Doug
Hoyte for the patch. The warning looks like this: Hoyte for the patch. The warning looks like this:
Warning: Hostname google.com resolves to 3 IPs. Using 66.102.7.99. Warning: Hostname google.com resolves to 3 IPs. Using 66.102.7.99.
o Changed the PortList class to use much more efficient data
structures and algorithms which take advantage of Nmap-specific
behavior patterns. Thanks to majek04 (majek(a)forest.one.pl) for
the patch.
o Disallow --host-timeout values of less than 1500ms, print a warning
for values less than 15s.
Nmap 4.03 Nmap 4.03
o Updated the LibPCRE build system to add the -fno-thread-jumps option o Updated the LibPCRE build system to add the -fno-thread-jumps option

View File

@@ -2,7 +2,7 @@
.\" It was generated using the DocBook XSL Stylesheets (version 1.69.1). .\" It was generated using the DocBook XSL Stylesheets (version 1.69.1).
.\" Instead of manually editing it, you probably should edit the DocBook XML .\" Instead of manually editing it, you probably should edit the DocBook XML
.\" source for it and then use the DocBook XSL Stylesheets to regenerate it. .\" source for it and then use the DocBook XSL Stylesheets to regenerate it.
.TH "NMAP" "1" "04/22/2006" "" "Nmap Reference Guide" .TH "NMAP" "1" "05/10/2006" "" "Nmap Reference Guide"
.\" disable hyphenation .\" disable hyphenation
.nh .nh
.\" disable justification (adjust text to left margin only) .\" disable justification (adjust text to left margin only)
@@ -377,9 +377,9 @@ do reverse DNS resolution on the target IP addresses. Normally this is only perf
By default, Nmap resolves IP addresses by sending queries directly to the name servers configured on your host and then listening for responses. Many requests (often dozens) are performed in parallel for performance. Specify this option if you wish to use your system resolver instead (one IP at a time via the getnameinfo() call). This is slower and rarely useful unless there is a bug in the Nmap DNS code \-\- please contact us if that is the case. The system resolver is always used for IPv6 scans. By default, Nmap resolves IP addresses by sending queries directly to the name servers configured on your host and then listening for responses. Many requests (often dozens) are performed in parallel for performance. Specify this option if you wish to use your system resolver instead (one IP at a time via the getnameinfo() call). This is slower and rarely useful unless there is a bug in the Nmap DNS code \-\- please contact us if that is the case. The system resolver is always used for IPv6 scans.
.TP .TP
\fB\-\-dns\-servers <server1[,server2],...> \fR (Servers to use for reverse DNS queries) \fB\-\-dns\-servers <server1[,server2],...> \fR (Servers to use for reverse DNS queries)
Normally Nmap will try to determine the DNS servers from your resolv.conf file (UNIX) or the registry (Win32). Alternatively, you may use this option to specify your own servers. This option is not honored if you are using By default Nmap will try to determine your DNS servers (for rDNS resolution) from your resolv.conf file (UNIX) or the registry (Win32). Alternatively, you may use this option to specify alternate servers. This option is not honored if you are using
\fB\-\-system\-dns\fR \fB\-\-system\-dns\fR
or an IPv6 scan. Using multiple DNS servers is often faster than querying just one. or an IPv6 scan. Using multiple DNS servers is often faster and more stealthy than querying just one. The best performance is often obtained by specifying all of the authoritative servers for the target IP space.
.SH "PORT SCANNING BASICS" .SH "PORT SCANNING BASICS"
.PP .PP
While Nmap has grown in functionality over the years, it began as an efficient port scanner, and that remains its core function. The simple command While Nmap has grown in functionality over the years, it began as an efficient port scanner, and that remains its core function. The simple command

View File

@@ -1028,7 +1028,7 @@ void idle_scan(Target *target, u16 *portarray, int numports,
/* Now we go through the ports which were not determined were scanned /* Now we go through the ports which were not determined were scanned
but not determined to be open, and add them in the "closed" state */ but not determined to be open, and add them in the "closed" state */
for(portidx = 0; portidx < numports; portidx++) { for(portidx = 0; portidx < numports; portidx++) {
if (target->ports.lookupPort(portarray[portidx], IPPROTO_TCP) == NULL) { if (target->ports.getPortEntry(portarray[portidx], IPPROTO_TCP) == NULL) {
target->ports.addPort(portarray[portidx], IPPROTO_TCP, NULL, target->ports.addPort(portarray[portidx], IPPROTO_TCP, NULL,
PORT_CLOSEDFILTERED); PORT_CLOSEDFILTERED);
} }

15
nmap.cc
View File

@@ -632,10 +632,10 @@ int nmap_main(int argc, char *argv[]) {
error("Warning: Your --min-parallelism option is pretty high! This can hurt reliability."); error("Warning: Your --min-parallelism option is pretty high! This can hurt reliability.");
} }
} else if (optcmp(long_options[option_index].name, "host-timeout") == 0) { l = tval2msecs(optarg); } else if (optcmp(long_options[option_index].name, "host-timeout") == 0) { l = tval2msecs(optarg);
if (l <= 200) fatal("--host-timeout must be at least 200 milliseconds"); if (l <= 1500) fatal("--host-timeout must be greater than 1500 milliseconds");
o.host_timeout = l; o.host_timeout = l;
if (o.host_timeout < 1000) { if (o.host_timeout < 15000) {
error("host-timeout is given in milliseconds, so you specified less than a second (%lims). This is allowed but not recommended.", o.host_timeout); error("host-timeout is given in milliseconds, so you specified less than 15 seconds (%lims). This is allowed but not recommended.", o.host_timeout);
} }
} else if (strcmp(long_options[option_index].name, "ttl") == 0) { } else if (strcmp(long_options[option_index].name, "ttl") == 0) {
o.ttl = atoi(optarg); o.ttl = atoi(optarg);
@@ -1109,7 +1109,6 @@ int nmap_main(int argc, char *argv[]) {
#ifdef WIN32 #ifdef WIN32
if (o.sendpref & PACKET_SEND_IP) { if (o.sendpref & PACKET_SEND_IP) {
error("WARNING: raw IP (rather than raw ethernet) packet sending attempted on Windows. This probably won't work. Consider --send-eth next time.\n"); error("WARNING: raw IP (rather than raw ethernet) packet sending attempted on Windows. This probably won't work. Consider --send-eth next time.\n");
} }
#endif #endif
if (spoofmac) { if (spoofmac) {
@@ -1297,6 +1296,14 @@ int nmap_main(int argc, char *argv[]) {
if (o.debugging > 1) log_write(LOG_STDOUT, "The max # of sockets we are using is: %d\n", o.max_parallelism); if (o.debugging > 1) log_write(LOG_STDOUT, "The max # of sockets we are using is: %d\n", o.max_parallelism);
/* Before we randomize the ports scanned, we must initialize PortList class. */
if (o.ipprotscan)
PortList::initializePortMap(IPPROTO_IP, ports->prots, ports->prot_count);
if (o.TCPScan())
PortList::initializePortMap(IPPROTO_TCP, ports->tcp_ports, ports->tcp_count);
if (o.UDPScan())
PortList::initializePortMap(IPPROTO_UDP, ports->udp_ports, ports->udp_count);
if (randomize) { if (randomize) {
if (ports->tcp_count) { if (ports->tcp_count) {
shortfry(ports->tcp_ports, ports->tcp_count); shortfry(ports->tcp_ports, ports->tcp_count);

View File

@@ -581,16 +581,16 @@ static FingerPrint *get_fingerprint(Target *target, struct seq_info *si) {
target->FPR->osscan_opentcpport = -1; target->FPR->osscan_opentcpport = -1;
target->FPR->osscan_closedtcpport = -1; target->FPR->osscan_closedtcpport = -1;
tport = NULL; tport = NULL;
if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_OPEN, false))) { if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_OPEN))) {
openport = tport->portno; openport = tport->portno;
target->FPR->osscan_opentcpport = tport->portno; target->FPR->osscan_opentcpport = tport->portno;
} }
/* Now we should find a closed port */ /* Now we should find a closed port */
if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_CLOSED, false))) { if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_CLOSED))) {
closedport = tport->portno; closedport = tport->portno;
target->FPR->osscan_closedtcpport = tport->portno; target->FPR->osscan_closedtcpport = tport->portno;
} else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_UNFILTERED, false))) { } else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_UNFILTERED))) {
/* Well, we will settle for unfiltered */ /* Well, we will settle for unfiltered */
closedport = tport->portno; closedport = tport->portno;
} else { } else {
@@ -1445,9 +1445,9 @@ o.current_scantype = OS_SCAN;
target->FPR = new FingerPrintResults; target->FPR = new FingerPrintResults;
memset(si, 0, sizeof(si)); memset(si, 0, sizeof(si));
if (target->ports.state_counts_tcp[PORT_OPEN] == 0 || if (target->ports.getStateCounts(IPPROTO_TCP, PORT_OPEN) == 0 ||
(target->ports.state_counts_tcp[PORT_CLOSED] == 0 && (target->ports.getStateCounts(IPPROTO_TCP, PORT_CLOSED) == 0 &&
target->ports.state_counts_tcp[PORT_UNFILTERED] == 0)) { target->ports.getStateCounts(IPPROTO_TCP, PORT_UNFILTERED) == 0)) {
if (o.osscan_limit) { if (o.osscan_limit) {
if (o.verbose) if (o.verbose)
log_write(LOG_STDOUT|LOG_NORMAL|LOG_SKID, "Skipping OS Scan due to absence of open (or perhaps closed) ports\n"); log_write(LOG_STDOUT|LOG_NORMAL|LOG_SKID, "Skipping OS Scan due to absence of open (or perhaps closed) ports\n");

View File

@@ -380,10 +380,9 @@ void printportoutput(Target *currenths, PortList *plist) {
struct protoent *proto; struct protoent *proto;
Port *current; Port *current;
int numignoredports; int numignoredports;
int portno;
char hostname[1200]; char hostname[1200];
int istate = plist->getIgnoredPortState(); int istate = plist->getIgnoredPortState();
numignoredports = plist->state_counts[istate]; numignoredports = plist->getStateCounts(istate);
struct serviceDeductions sd; struct serviceDeductions sd;
NmapOutputTable *Tbl = NULL; NmapOutputTable *Tbl = NULL;
int portcol = -1; // port or IP protocol # int portcol = -1; // port or IP protocol #
@@ -437,13 +436,13 @@ void printportoutput(Target *currenths, PortList *plist) {
if (o.servicescan || o.rpcscan) if (o.servicescan || o.rpcscan)
versioncol = colno++; versioncol = colno++;
numrows = plist->state_counts[PORT_CLOSED] + numrows = plist->getStateCounts(PORT_CLOSED) +
plist->state_counts[PORT_OPEN] + plist->state_counts[PORT_FILTERED] + plist->getStateCounts(PORT_OPEN) + plist->getStateCounts(PORT_FILTERED) +
plist->state_counts[PORT_UNFILTERED] + plist->getStateCounts(PORT_UNFILTERED) +
plist->state_counts[PORT_OPENFILTERED] + plist->getStateCounts(PORT_OPENFILTERED) +
plist->state_counts[PORT_CLOSEDFILTERED]; plist->getStateCounts(PORT_CLOSEDFILTERED);
if (istate != PORT_UNKNOWN) if (istate != PORT_UNKNOWN)
numrows -= plist->state_counts[istate]; numrows -= plist->getStateCounts(istate);
assert(numrows > 0); assert(numrows > 0);
numrows++; // The header counts as a row numrows++; // The header counts as a row
@@ -463,12 +462,10 @@ void printportoutput(Target *currenths, PortList *plist) {
log_write(LOG_MACHINE,"\t%s: ", (o.ipprotscan)? "Protocols" : "Ports" ); log_write(LOG_MACHINE,"\t%s: ", (o.ipprotscan)? "Protocols" : "Ports" );
current = NULL;
rowno = 1; rowno = 1;
if (o.ipprotscan) { if (o.ipprotscan) {
for (portno = 0; portno < 256; portno++) { current = NULL;
if (!plist->ip_prots[portno]) continue; while( (current=plist->nextPort(current, IPPROTO_IP, 0))!=NULL ) {
current = plist->ip_prots[portno];
if (current->state != istate) { if (current->state != istate) {
if (!first) log_write(LOG_MACHINE,", "); if (!first) log_write(LOG_MACHINE,", ");
else first = 0; else first = 0;
@@ -476,7 +473,7 @@ void printportoutput(Target *currenths, PortList *plist) {
proto = nmap_getprotbynum(htons(current->portno)); proto = nmap_getprotbynum(htons(current->portno));
snprintf(portinfo, sizeof(portinfo), "%-24s", snprintf(portinfo, sizeof(portinfo), "%-24s",
proto?proto->p_name: "unknown"); proto?proto->p_name: "unknown");
Tbl->addItemFormatted(rowno, portcol, "%d", portno); Tbl->addItemFormatted(rowno, portcol, "%d", current->portno);
Tbl->addItem(rowno, statecol, true, state); Tbl->addItem(rowno, statecol, true, state);
Tbl->addItem(rowno, servicecol, true, portinfo); Tbl->addItem(rowno, servicecol, true, portinfo);
log_write(LOG_MACHINE,"%d/%s/%s/", current->portno, state, log_write(LOG_MACHINE,"%d/%s/%s/", current->portno, state,
@@ -489,20 +486,8 @@ void printportoutput(Target *currenths, PortList *plist) {
} }
} }
} else { } else {
map<u16,Port*>::iterator tcpIter = plist->tcp_ports.begin(); current = NULL;
map<u16,Port*>::iterator udpIter = plist->udp_ports.begin(); while( (current=plist->nextPort(current, TCPANDUDP, 0))!=NULL ) {
while (tcpIter != plist->tcp_ports.end() || udpIter != plist->udp_ports.end()) {
// If the udp iterator is at the end, then we always read from tcp and vica-versa
if (tcpIter != plist->tcp_ports.end() && (udpIter == plist->udp_ports.end() || tcpIter->first <= udpIter->first)) {
current = tcpIter->second;
tcpIter++;
} else {
current = udpIter->second;
udpIter++;
}
if (current->state != istate) { if (current->state != istate) {
if (!first) log_write(LOG_MACHINE,", "); if (!first) log_write(LOG_MACHINE,", ");
else first = 0; else first = 0;
@@ -605,8 +590,8 @@ void printportoutput(Target *currenths, PortList *plist) {
} }
/* log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"\n"); */ /* log_write(LOG_NORMAL|LOG_SKID|LOG_STDOUT,"\n"); */
if (plist->state_counts[istate] > 0) if (plist->getStateCounts(istate) > 0)
log_write(LOG_MACHINE, "\tIgnored State: %s (%d)", statenum2str(istate), plist->state_counts[istate]); log_write(LOG_MACHINE, "\tIgnored State: %s (%d)", statenum2str(istate), plist->getStateCounts(istate));
log_write(LOG_XML, "</ports>\n"); log_write(LOG_XML, "</ports>\n");
// Now we write the table for the user // Now we write the table for the user
@@ -1402,7 +1387,7 @@ void printserviceinfooutput(Target *currenths) {
for (i=0; i<MAX_SERVICE_INFO_FIELDS; i++) for (i=0; i<MAX_SERVICE_INFO_FIELDS; i++)
hostname_tbl[i][0] = ostype_tbl[i][0] = devicetype_tbl[i][0] = '\0'; hostname_tbl[i][0] = ostype_tbl[i][0] = devicetype_tbl[i][0] = '\0';
while ((p = currenths->ports.nextPort(p, 0, PORT_OPEN, false))) { while ((p = currenths->ports.nextPort(p, TCPANDUDP, PORT_OPEN))) {
// The following 2 lines (from portlist.h) tell us that we don't // The following 2 lines (from portlist.h) tell us that we don't
// need to worry about free()ing anything in the serviceDeductions struct. // need to worry about free()ing anything in the serviceDeductions struct.
// pass in an allocated struct serviceDeductions (don't wory about initializing, and // pass in an allocated struct serviceDeductions (don't wory about initializing, and

View File

@@ -396,46 +396,53 @@ void Port::setRPCProbeResults(int rpcs, unsigned long rpcp,
} }
} }
/*****************************************************************************/
/* Convert protocol name from in.h to enum portlist_proto.
* So IPPROTO_TCP will be changed to PORTLIST_PROTO_TCP and so on. */
#define INPROTO2PORTLISTPROTO(p) \
((p)==IPPROTO_TCP ? PORTLIST_PROTO_TCP : \
(p)==IPPROTO_UDP ? PORTLIST_PROTO_UDP : \
PORTLIST_PROTO_IP)
PortList::PortList() { PortList::PortList() {
memset(state_counts, 0, sizeof(state_counts)); int proto;
memset(state_counts_udp, 0, sizeof(state_counts_udp)); memset(state_counts_proto, 0, sizeof(state_counts_proto));
memset(state_counts_tcp, 0, sizeof(state_counts_tcp)); memset(port_list, 0, sizeof(port_list));
memset(state_counts_ip, 0, sizeof(state_counts_ip));
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) {
if(port_list_count[proto] > 0)
port_list[proto] = (Port**) safe_zalloc(sizeof(Port*)*port_list_count[proto]);
}
numports = 0; numports = 0;
idstr = NULL; idstr = NULL;
} }
PortList::~PortList() { PortList::~PortList() {
int proto, i;
for(map<u16,Port*>::iterator iter = tcp_ports.begin(); iter != tcp_ports.end(); iter++)
{
delete iter->second;
}
for(map<u16,Port*>::iterator iter = udp_ports.begin(); iter != udp_ports.end(); iter++)
{
delete iter->second;
}
for(map<u16,Port*>::iterator iter = ip_prots.begin(); iter != ip_prots.end(); iter++)
{
delete iter->second;
}
if (idstr) { if (idstr) {
free(idstr); free(idstr);
idstr = NULL; idstr = NULL;
} }
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) { // for every protocol
if(port_list[proto]) {
for(i=0; i < port_list_count[proto]; i++) { // free every Port
if(port_list[proto][i])
delete port_list[proto][i];
}
free(port_list[proto]);
}
}
} }
int PortList::addPort(u16 portno, u8 protocol, char *owner, int state) { int PortList::addPort(u16 portno, u8 protocol, char *owner, int state) {
Port *current = NULL; Port *current;
map < u16, Port* > *portarray = NULL; // This has to be a pointer so that we change the original and not a copy
map <u16, Port *>::iterator pt;
char msg[128]; char msg[128];
int proto = INPROTO2PORTLISTPROTO(protocol);
assert(state < PORT_HIGHEST_STATE); assert(state < PORT_HIGHEST_STATE);
@@ -451,52 +458,33 @@ int PortList::addPort(u16 portno, u8 protocol, char *owner, int state) {
} }
/* Make sure state is OK */ /* Make sure state is OK */
if (state != PORT_OPEN && state != PORT_CLOSED && state != PORT_FILTERED && if (state != PORT_OPEN && state != PORT_CLOSED && state != PORT_FILTERED &&
state != PORT_UNFILTERED && state != PORT_OPENFILTERED && state != PORT_UNFILTERED && state != PORT_OPENFILTERED &&
state != PORT_CLOSEDFILTERED) state != PORT_CLOSEDFILTERED)
fatal("addPort: attempt to add port number %d with illegal state %d\n", portno, state); fatal("addPort: attempt to add port number %d with illegal state %d\n", portno, state);
if (protocol == IPPROTO_TCP) { assert(protocol!=IPPROTO_IP || portno<256);
portarray = &tcp_ports;
} else if (protocol == IPPROTO_UDP) {
portarray = &udp_ports;
} else if (protocol == IPPROTO_IP) {
assert(portno < 256);
portarray = &ip_prots;
} else fatal("addPort: attempted port insertion with invalid protocol");
pt = portarray->find(portno); current = getPortEntry(portno, protocol);
if (pt != portarray->end()) { if (current) {
/* We must discount our statistics from the old values. Also warn /* We must discount our statistics from the old values. Also warn
if a complete duplicate */ if a complete duplicate */
current = pt->second;
if (o.debugging && current->state == state && (!owner || !*owner)) { if (o.debugging && current->state == state && (!owner || !*owner)) {
error("Duplicate port (%hu/%s)\n", portno, proto2ascii(protocol)); error("Duplicate port (%hu/%s)\n", portno, proto2ascii(protocol));
} }
state_counts[current->state]--; state_counts_proto[proto][current->state]--;
if (current->proto == IPPROTO_TCP) {
state_counts_tcp[current->state]--;
} else if (current->proto == IPPROTO_UDP) {
state_counts_udp[current->state]--;
} else
state_counts_ip[current->state]--;
} else { } else {
current = new Port(); current = new Port();
(*portarray)[portno] = current;
numports++;
current->portno = portno; current->portno = portno;
current->proto = protocol;
numports++;
setPortEntry(portno, protocol, current);
} }
state_counts[state]++;
current->state = state; current->state = state;
if (protocol == IPPROTO_TCP) { state_counts_proto[proto][state]++;
state_counts_tcp[state]++;
} else if (protocol == IPPROTO_UDP) {
state_counts_udp[state]++;
} else
state_counts_ip[state]++;
current->proto = protocol;
if (owner && *owner) { if (owner && *owner) {
if (current->owner) if (current->owner)
@@ -512,22 +500,12 @@ int PortList::removePort(u16 portno, u8 protocol) {
printf("Removed %d\n", portno); printf("Removed %d\n", portno);
if (protocol == IPPROTO_TCP) { answer = getPortEntry(portno, protocol);
answer = tcp_ports[portno];
tcp_ports.erase(portno);
}
if (protocol == IPPROTO_UDP) {
answer = udp_ports[portno];
udp_ports.erase(portno);
} else if (protocol == IPPROTO_IP) {
answer = ip_prots[portno];
ip_prots.erase(portno);
}
if (!answer) if (!answer)
return -1; return -1;
setPortEntry(portno, protocol, NULL);
if (o.verbose) { if (o.verbose) {
log_write(LOG_STDOUT, "Deleting port %hu/%s, which we thought was %s\n", log_write(LOG_STDOUT, "Deleting port %hu/%s, which we thought was %s\n",
portno, proto2ascii(answer->proto), portno, proto2ascii(answer->proto),
@@ -535,6 +513,10 @@ int PortList::removePort(u16 portno, u8 protocol) {
log_flush(LOG_STDOUT); log_flush(LOG_STDOUT);
} }
/* Discount statistics */
state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][answer->state]--;
numports--;
delete answer; delete answer;
return 0; return 0;
} }
@@ -553,117 +535,167 @@ void PortList::setIdStr(const char *id) {
snprintf(idstr, len, " on %s", id); snprintf(idstr, len, " on %s", id);
} }
Port *PortList::lookupPort(u16 portno, u8 protocol) {
map <u16, Port *>::iterator pt;
if (protocol == IPPROTO_TCP) {
pt = tcp_ports.find(portno);
if (pt != tcp_ports.end())
return pt->second;
}
else if (protocol == IPPROTO_UDP) { int PortList::getStateCounts(int protocol, int state){
pt = udp_ports.find(portno); return(state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][state]);
if (pt != udp_ports.end())
return pt->second;
}
else if (protocol == IPPROTO_IP) {
pt = ip_prots.find(portno);
if (pt != ip_prots.end())
return pt->second;
}
return NULL;
} }
int PortList::getIgnoredPortState() { int PortList::getStateCounts(int state){
int ignored = PORT_UNKNOWN; int sum=0, proto;
int ignoredNum = 0; for(proto=0; proto < PORTLIST_PROTO_MAX; proto++)
int i; sum += state_counts_proto[proto][state];
for(i=0; i < PORT_HIGHEST_STATE; i++) { return(sum);
if (i == PORT_OPEN || i == PORT_UNKNOWN || i == PORT_TESTING ||
i == PORT_FRESH) continue; /* Cannot be ignored */
if (state_counts[i] > ignoredNum) {
ignored = i;
ignoredNum = state_counts[i];
}
}
if (state_counts[ignored] < 15)
ignored = PORT_UNKNOWN;
return ignored;
} }
/* A function for iterating through the ports. Give NULL for the /* A function for iterating through the ports. Give NULL for the
first "afterthisport". Then supply the most recent returned port first "afterthisport". Then supply the most recent returned port
for each subsequent call. When no more matching ports remain, NULL for each subsequent call. When no more matching ports remain, NULL
will be returned. To restrict returned ports to just one protocol, will be returned. To restrict returned ports to just one protocol,
specify IPPROTO_TCP or IPPROTO_UDP for allowed_protocol. A 0 for specify IPPROTO_TCP or IPPROTO_UDP for allowed_protocol. A TCPANDUDP
allowed_protocol matches either. allowed_state works in the same for allowed_protocol matches either. A 0 for allowed_state matches
fashion as allowed_protocol. This function returns ports in numeric all possible states. This function returns ports in numeric
order from lowest to highest, except that if you ask for both TCP & order from lowest to highest, except that if you ask for both TCP &
UDP, every TCP port will be returned before we start returning UDP UDP, every TCP port will be returned before we start returning UDP
ports. */ ports */
Port *PortList::nextPort(Port *afterthisport, Port *PortList::nextPort(Port *afterthisport,
u8 allowed_protocol, int allowed_state, int allowed_protocol, int allowed_state) {
bool allow_portzero) { int proto;
int mapped_pno;
Port *port;
/* These two are chosen because they come right "before" port 1/tcp */ if(afterthisport) {
map<u16,Port*>::iterator iter; proto = INPROTO2PORTLISTPROTO(afterthisport->proto);
assert(port_map[proto]!=NULL); // Hmm, it's not posible to handle port that doesn't have anything in map
assert(afterthisport->proto!=IPPROTO_IP || afterthisport->portno<256);
mapped_pno = port_map[proto][afterthisport->portno];
mapped_pno++; // we're interested in next port after current
}else { // running for the first time
if(allowed_protocol == TCPANDUDP) // if both protocols, then first search TCP
proto = INPROTO2PORTLISTPROTO(IPPROTO_TCP);
else
proto = INPROTO2PORTLISTPROTO(allowed_protocol);
mapped_pno = 0;
}
if (afterthisport) { if(port_list[proto] != NULL) {
if (afterthisport->proto == IPPROTO_TCP) { for(;mapped_pno < port_list_count[proto]; mapped_pno++) {
iter = tcp_ports.find(afterthisport->portno); port = port_list[proto][mapped_pno];
assert(iter != tcp_ports.end()); if(port && (allowed_state==0 || port->state==allowed_state))
iter++; return(port);
while(iter != tcp_ports.end()) { }
if (!allowed_state || iter->second->state == allowed_state) }
return iter->second;
iter++; /* if all protocols, than after TCP search UDP */
} if(allowed_protocol == TCPANDUDP && proto == INPROTO2PORTLISTPROTO(IPPROTO_TCP))
/* No more TCP ports ... */ return(nextPort(NULL, IPPROTO_UDP, allowed_state));
if (allowed_protocol != 0)
return NULL; return(NULL);
}
iter = udp_ports.begin(); Port *PortList::getPortEntry(u16 portno, u8 protocol) {
} else { int proto = INPROTO2PORTLISTPROTO(protocol);
assert(afterthisport->proto == IPPROTO_UDP); int mapped_pno;
iter = udp_ports.find(afterthisport->portno);
assert(iter != udp_ports.end());
iter++;
}
while(iter != udp_ports.end()) {
if (!allowed_state || iter->second->state == allowed_state)
return iter->second;
iter++;
}
return NULL;
}
// First-time call - try TCP ports first assert(protocol!=IPPROTO_IP || portno<256);
if (allowed_protocol == 0 || allowed_protocol == IPPROTO_TCP) { if(port_map[proto]==NULL || port_list[proto]==NULL)
iter = tcp_ports.begin(); fatal("getPortEntry(%i,%i): you're trying to access uninitialized protocol", portno, protocol);
while (iter != tcp_ports.end()) { mapped_pno = port_map[proto][portno];
if (!allowed_state || iter->second->state == allowed_state)
return iter->second; assert(mapped_pno < port_list_count[proto]);
iter++; assert(mapped_pno >= 0);
/* The ugly hack: we allow only port 0 to be mapped to 0 position */
if(mapped_pno==0 && portno!=0) {
error("WARNING: getPortEntry(%i,%i): this port was not mapped", portno, protocol);
return(NULL);
}else
return(port_list[proto][mapped_pno]);
}
void PortList::setPortEntry(u16 portno, u8 protocol, Port *port) {
int proto = INPROTO2PORTLISTPROTO(protocol);
int mapped_pno;
assert(protocol!=IPPROTO_IP || portno<256);
if(port_map[proto]==NULL || port_list[proto]==NULL)
fatal("setPortEntry(%i,%i): you're trying to access uninitialized protocol", portno, protocol);
mapped_pno = port_map[proto][portno];
assert(mapped_pno < port_list_count[proto]);
assert(mapped_pno >= 0);
/* The ugly hack: we allow only port 0 to be mapped to 0 position */
if(mapped_pno==0 && portno!=0) {
error("WARNING: setPortEntry(%i,%i): this port was not mapped", portno, protocol);
return;
}
port_list[proto][mapped_pno] = port;
}
u16 *PortList::port_map[PORTLIST_PROTO_MAX];
int PortList::port_list_count[PORTLIST_PROTO_MAX];
/* This function must be runned before any PortList object is created.
* It must be runned for every used protocol. The data in "ports"
* should be sorted. */
void PortList::initializePortMap(int protocol, u16 *ports, int portcount) {
int i;
int unused_zero; // aren't we using 0 port?
int ports_max = (protocol == IPPROTO_IP) ? 256 : 65536;
int proto = INPROTO2PORTLISTPROTO(protocol);
if(port_map[proto]!=NULL)
fatal("initializePortMap: portmap for protocol %i already initialized", protocol);
assert(port_list_count[proto]==0);
/* this memory will never be freed, but this is the way it has to be. */
port_map[proto] = (u16*) safe_zalloc(sizeof(u16)*ports_max);
/* Is zero port to be unused? */
if(portcount==0 || ports[0]!=0)
unused_zero = 1;
else
unused_zero = 0;
/* The ugly hack: if we don't use 0 port, than we need one more extra element. */
port_list_count[proto] = portcount + unused_zero;
for(i=0; i < portcount; i++) {
/* The ugly hack: if we don't use 0 port, than we must start counting from 1 */
port_map[proto][ports[i]] = i + unused_zero; // yes, this is the key line
}
/* So now port_map should have such structure (lets scan 2nd,4th and 6th port):
* port_map[0,0,1,0,2,0,3,...] <- indexes to port_list structure
* port_list[0,port_2,port_4,port_6]
* But if we scan 0, 2, and 4 port:
* port_map[0,0,1,0,2,...] // yes, this 0 in first place isn't mistake
* port_list[port_0,port_2,port_4]
* And in both cases we scan three ports. Ugly, isn't it? :) */
}
/* Choose the state that is not so important to print on the user's screen. */
int PortList::getIgnoredPortState() {
int ignored = PORT_UNKNOWN;
int ignoredNum = 0;
int i, s;
for(i=0; i < PORT_HIGHEST_STATE; i++) {
if (i == PORT_OPEN || i == PORT_UNKNOWN || i == PORT_TESTING ||
i == PORT_FRESH) continue; /* Cannot be ignored */
s = getStateCounts(i);
if (s > ignoredNum) {
ignored = i;
ignoredNum = s;
} }
} }
// Maybe we'll have better luck with UDP if (ignoredNum < 15)
if (allowed_protocol == 0 || allowed_protocol == IPPROTO_UDP) { ignored = PORT_UNKNOWN;
iter = udp_ports.begin();
while (iter != udp_ports.end()) { return ignored;
if (!allowed_state || iter->second->state == allowed_state)
return iter->second;
iter++;
}
}
// Nuthing found
return NULL;
} }

View File

@@ -118,6 +118,8 @@
#define PORT_HIGHEST_STATE 9 /* ***IMPORTANT -- BUMP THIS UP WHEN STATES ARE #define PORT_HIGHEST_STATE 9 /* ***IMPORTANT -- BUMP THIS UP WHEN STATES ARE
ADDED *** */ ADDED *** */
#define TCPANDUDP IPPROTO_MAX
#define CONF_NONE 0 #define CONF_NONE 0
#define CONF_LOW 1 #define CONF_LOW 1
#define CONF_HIGH 2 #define CONF_HIGH 2
@@ -248,10 +250,22 @@ class Port {
}; };
/* Needed enums to address some arrays. This values
* should never be used directly. Use INPROTO2PORTLISTPROTO macro */
enum portlist_proto { // PortList Protocols
PORTLIST_PROTO_TCP = 0,
PORTLIST_PROTO_UDP = 1,
PORTLIST_PROTO_IP = 2,
PORTLIST_PROTO_MAX = 3
};
class PortList { class PortList {
public: public:
PortList(); PortList();
~PortList(); ~PortList();
/* Set ports that will be scanned for each protocol. This function
* must be called before any PortList object will be created. */
static void initializePortMap(int protocol, u16 *ports, int portcount);
/* Add a new port to this list. If the state has changed, it is /* Add a new port to this list. If the state has changed, it is
OK to call this function to effect the change */ OK to call this function to effect the change */
int addPort(u16 portno, u8 protocol, char *owner, int state); int addPort(u16 portno, u8 protocol, char *owner, int state);
@@ -261,38 +275,48 @@ class PortList {
want). Only used when printing new port updates. Optional. A want). Only used when printing new port updates. Optional. A
copy is made. */ copy is made. */
void setIdStr(const char *id); void setIdStr(const char *id);
/* A function for iterating through the ports. Give NULL for the /* A function for iterating through the ports. Give NULL for the
first "afterthisport". Then supply the most recent returned port first "afterthisport". Then supply the most recent returned port
for each subsequent call. When no more matching ports remain, NULL for each subsequent call. When no more matching ports remain, NULL
will be returned. To restrict returned ports to just one protocol, will be returned. To restrict returned ports to just one protocol,
specify IPPROTO_TCP or IPPROTO_UDP for allowed_protocol. A 0 for specify IPPROTO_TCP or IPPROTO_UDP for allowed_protocol. A TCPANDUDP
allowed_protocol matches either. allowed_state works in the same for allowed_protocol matches either. A 0 for allowed_state matches
fashion as allowed_protocol. This function returns ports in numeric all possible states. This function returns ports in numeric
order from lowest to highest, except that if you ask for both TCP & order from lowest to highest, except that if you ask for both TCP &
UDP, every TCP port will be returned before we start returning UDP UDP, every TCP port will be returned before we start returning UDP
ports */ ports */
Port *nextPort(Port *afterthisport, Port *nextPort(Port *afterthisport,
u8 allowed_protocol, int allowed_state, int allowed_protocol, int allowed_state);
bool allow_portzero);
Port *lookupPort(u16 portno, u8 protocol); /* Get Port structure from PortList structure.*/
Port *getPortEntry(u16 portno, u8 protocol);
/* Set Port structure to PortList structure.*/
void setPortEntry(u16 portno, u8 protocol, Port *port);
int state_counts[PORT_HIGHEST_STATE]; /* How many ports in list are in each
state */
int state_counts_udp[PORT_HIGHEST_STATE];
int state_counts_tcp[PORT_HIGHEST_STATE];
int state_counts_ip[PORT_HIGHEST_STATE];
int getIgnoredPortState(); /* The state of the port we ignore for output */
int numports; /* Total number of ports in list in ANY state */ int numports; /* Total number of ports in list in ANY state */
// map<int,char*> foomap;
std::map < u16, Port *> udp_ports; /* Get number of ports in this state. This a sum for protocols. */
std::map < u16, Port* > tcp_ports; int getStateCounts(int state);
std::map < u16, Port* > ip_prots; /* Get number of ports in this state for requested protocol. */
int getStateCounts(int protocol, int state);
/* The state of the port we ignore for output */
int getIgnoredPortState();
private: private:
/* A string identifying the system these ports are on. Just used for /* A string identifying the system these ports are on. Just used for
printing open ports, if it is set with setIdStr() */ printing open ports, if it is set with setIdStr() */
char *idstr; char *idstr;
/* Number of ports in each state per each protocol */
int state_counts_proto[PORTLIST_PROTO_MAX][PORT_HIGHEST_STATE];
Port **port_list[PORTLIST_PROTO_MAX];
protected:
/* Mapps port_number to index in port_list array.
* Only functions: getPortEntry, setPortEntry, initializePortMap and
* nextPort should access this structure directly. */
static u16 *port_map[PORTLIST_PROTO_MAX];
/* Number of allocated elements in port_list per each protocol. */
static int port_list_count[PORTLIST_PROTO_MAX];
}; };
#endif #endif

View File

@@ -1683,7 +1683,7 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
} else assert(0); } else assert(0);
/* First figure out the current state */ /* First figure out the current state */
currentp = hss->target->ports.lookupPort(portno, proto); currentp = hss->target->ports.getPortEntry(portno, proto);
if (!currentp) { if (!currentp) {
oldstate = PORT_TESTING; oldstate = PORT_TESTING;
hss->ports_finished++; hss->ports_finished++;
@@ -3632,8 +3632,8 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
if (scantype != RPC_SCAN) if (scantype != RPC_SCAN)
fatal("pos_scan now handles only rpc scan"); fatal("pos_scan now handles only rpc scan");
if (target->ports.state_counts[PORT_OPEN] == 0 && if (target->ports.getStateCounts(PORT_OPEN) == 0 &&
(o.servicescan || target->ports.state_counts[PORT_OPENFILTERED] == 0)) (o.servicescan || target->ports.getStateCounts(PORT_OPENFILTERED) == 0))
return; // RPC Scan only works against already known-open ports return; // RPC Scan only works against already known-open ports
if (o.debugging) if (o.debugging)
@@ -3708,11 +3708,11 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
/* Make sure we have ports left to scan */ /* Make sure we have ports left to scan */
while(1) { while(1) {
if (doingOpenFiltered) { if (doingOpenFiltered) {
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port, 0, rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port, TCPANDUDP,
PORT_OPENFILTERED, true); PORT_OPENFILTERED);
} else { } else {
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port, rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port,
0, PORT_OPEN, true); TCPANDUDP, PORT_OPEN);
if (!rsi.rpc_current_port && !o.servicescan) { if (!rsi.rpc_current_port && !o.servicescan) {
doingOpenFiltered = true; doingOpenFiltered = true;
continue; continue;

View File

@@ -1606,8 +1606,7 @@ ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) {
num_hosts_timedout++; num_hosts_timedout++;
continue; continue;
} }
while((nxtport = Targets[targetno]->ports.nextPort(nxtport, 0, PORT_OPEN, while((nxtport = Targets[targetno]->ports.nextPort(nxtport, TCPANDUDP, PORT_OPEN))) {
true))) {
svc = new ServiceNFO(AP); svc = new ServiceNFO(AP);
svc->target = Targets[targetno]; svc->target = Targets[targetno];
svc->portno = nxtport->portno; svc->portno = nxtport->portno;
@@ -1625,8 +1624,7 @@ ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) {
if (Targets[targetno]->timedOut(&now)) { if (Targets[targetno]->timedOut(&now)) {
continue; continue;
} }
while((nxtport = Targets[targetno]->ports.nextPort(nxtport, 0, while((nxtport = Targets[targetno]->ports.nextPort(nxtport, TCPANDUDP, PORT_OPENFILTERED))) {
PORT_OPENFILTERED, true))) {
svc = new ServiceNFO(AP); svc = new ServiceNFO(AP);
svc->target = Targets[targetno]; svc->target = Targets[targetno];
svc->portno = nxtport->portno; svc->portno = nxtport->portno;