diff --git a/portlist.cc b/portlist.cc index 7ca4763f7..4ea5b8437 100644 --- a/portlist.cc +++ b/portlist.cc @@ -459,8 +459,7 @@ void PortList::setDefaultPortState(u8 protocol, int state) { default_port_state[proto].state = state; } -void PortList::setPortState(u16 portno, u8 protocol, int state) { - const Port *oldport; +void PortList::setPortState(u16 portno, u8 protocol, int state, int *oldstate) { Port *current; int proto = INPROTO2PORTLISTPROTO(protocol); @@ -492,8 +491,10 @@ void PortList::setPortState(u16 portno, u8 protocol, int state) { error("Duplicate port (%hu/%s)", portno, proto2ascii_lowercase(protocol)); } state_counts_proto[proto][current->state]--; + if (oldstate) *oldstate = current->state; } else { state_counts_proto[proto][default_port_state[proto].state]--; + if (oldstate) *oldstate = PORT_TESTING; } current->state = state; diff --git a/portlist.h b/portlist.h index dbb166253..eee0fff6f 100644 --- a/portlist.h +++ b/portlist.h @@ -183,7 +183,7 @@ class PortList { static void freePortMap(); void setDefaultPortState(u8 protocol, int state); - void setPortState(u16 portno, u8 protocol, int state); + void setPortState(u16 portno, u8 protocol, int state, int *oldstate=NULL); int getPortState(u16 portno, u8 protocol); int forgetPort(u16 portno, u8 protocol); bool portIsDefault(u16 portno, u8 protocol); diff --git a/scan_engine.cc b/scan_engine.cc index 34c284cec..4ac914146 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -1859,57 +1859,52 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI, portno = pspec->pd.sctp.dport; } else assert(0); - if (hss->target->ports.portIsDefault(portno, proto)) { - oldstate = PORT_TESTING; - hss->ports_finished++; - } else { - oldstate = hss->target->ports.getPortState(portno, proto); - } + // Set new port state, pending checks for valid state transitions + hss->target->ports.setPortState(portno, proto, newstate, &oldstate); /* printf("TCP port %hu has changed from state %s to %s!\n", portno, statenum2str(oldstate), statenum2str(newstate)); */ - switch (oldstate) { - /* TODO: I need more code here to determine when a state should - be overridden, for example PORT_OPEN trumps PORT_FILTERED - in a SYN scan, but not necessarily for UDP scan */ - case PORT_TESTING: - /* Brand new port -- add it to the list */ - hss->target->ports.setPortState(portno, proto, newstate); - break; - case PORT_OPEN: - if (newstate != PORT_OPEN) { - if (noresp_open_scan) { - hss->target->ports.setPortState(portno, proto, newstate); - } /* Otherwise The old open takes precedence */ + if (newstate != oldstate) { + // Check for conditions that mean we should ignore newstate (revert to oldstate) + switch (oldstate) { + /* TODO: I need more code here to determine when a state should + be overridden, for example PORT_OPEN trumps PORT_FILTERED + in a SYN scan, but not necessarily for UDP scan */ + case PORT_TESTING: + /* Brand new port -- add it to the list */ + hss->ports_finished++; + break; + case PORT_OPEN: + // Changing from open to anything else only valid for noresp_open_scan + if (!noresp_open_scan) { + hss->target->ports.setPortState(portno, proto, oldstate); + } + break; + case PORT_CLOSED: + // Changing from closed to filtered is never allowed. + // Changing from closed to anything else is never valid for noresp_open_scan + if (noresp_open_scan || newstate == PORT_FILTERED) + hss->target->ports.setPortState(portno, proto, oldstate); + break; + case PORT_FILTERED: + // Changing from filtered to open is not allowed for noresp_open_scan + if (noresp_open_scan && newstate == PORT_OPEN) + hss->target->ports.setPortState(portno, proto, oldstate); + break; + case PORT_UNFILTERED: + /* This could happen in an ACK scan if I receive a RST and then an + ICMP filtered message. I'm gonna stick with unfiltered in that + case. I'll change it if the new state is open or closed, + though I don't expect that to ever happen */ + if (newstate != PORT_OPEN && newstate != PORT_CLOSED) + hss->target->ports.setPortState(portno, proto, oldstate); + break; + case PORT_OPENFILTERED: + // Always accepted. + break; + default: + fatal("Unexpected port state: %d\n", oldstate); + break; } - break; - case PORT_CLOSED: - if (newstate != PORT_CLOSED) { - if (!noresp_open_scan && newstate != PORT_FILTERED) - hss->target->ports.setPortState(portno, proto, newstate); - } - break; - case PORT_FILTERED: - if (newstate != PORT_FILTERED) { - if (!noresp_open_scan || newstate != PORT_OPEN) - hss->target->ports.setPortState(portno, proto, newstate); - } - break; - case PORT_UNFILTERED: - /* This could happen in an ACK scan if I receive a RST and then an - ICMP filtered message. I'm gonna stick with unfiltered in that - case. I'll change it if the new state is open or closed, - though I don't expect that to ever happen */ - if (newstate == PORT_OPEN || newstate == PORT_CLOSED) - hss->target->ports.setPortState(portno, proto, newstate); - break; - case PORT_OPENFILTERED: - if (newstate != PORT_OPENFILTERED) { - hss->target->ports.setPortState(portno, proto, newstate); - } - break; - default: - fatal("Unexpected port state: %d\n", oldstate); - break; } return oldstate != newstate;