diff --git a/idle_scan.cc b/idle_scan.cc index 492186a9a..8e17c496d 100644 --- a/idle_scan.cc +++ b/idle_scan.cc @@ -926,7 +926,7 @@ static int idle_treescan(struct idle_proxy_info *proxy, Target *target, /* If our first count erroneously found and added an open port, we must delete it */ if (firstHalfSz == 1 && flatcount1 == 1 && retrycount == 0) - target->ports.forgetPort(ports[0], IPPROTO_TCP); + target->ports.removePort(ports[0], IPPROTO_TCP); } } @@ -952,7 +952,7 @@ static int idle_treescan(struct idle_proxy_info *proxy, Target *target, /* If our first count erroneously found and added an open port, we must delete it */ if (secondHalfSz == 1 && flatcount2 == 1 && retrycount == 0) - target->ports.forgetPort(ports[firstHalfSz], IPPROTO_TCP); + target->ports.removePort(ports[firstHalfSz], IPPROTO_TCP); } @@ -960,10 +960,10 @@ static int idle_treescan(struct idle_proxy_info *proxy, Target *target, } if (firstHalfSz == 1 && flatcount1 == 1) - target->ports.setPortState(ports[0], IPPROTO_TCP, PORT_OPEN); + target->ports.addPort(ports[0], IPPROTO_TCP, PORT_OPEN); if ((secondHalfSz == 1) && flatcount2 == 1) - target->ports.setPortState(ports[firstHalfSz], IPPROTO_TCP, PORT_OPEN); + target->ports.addPort(ports[firstHalfSz], IPPROTO_TCP, PORT_OPEN); return totalfound; } @@ -1043,8 +1043,8 @@ void idle_scan(Target *target, u16 *portarray, int numports, /* Now we go through the ports which were scanned but not determined to be open, and add them in the "closed" state */ for(portidx = 0; portidx < numports; portidx++) { - if (target->ports.getPortState(portarray[portidx], IPPROTO_TCP) == -1) { - target->ports.setPortState(portarray[portidx], IPPROTO_TCP, PORT_CLOSEDFILTERED); + if (target->ports.getPortEntry(portarray[portidx], IPPROTO_TCP) == NULL) { + target->ports.addPort(portarray[portidx], IPPROTO_TCP, PORT_CLOSEDFILTERED); target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_NOIPIDCHANGE, 0, 0); } else target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_IPIDCHANGE, 0, 0); diff --git a/nmap_rpc.cc b/nmap_rpc.cc index d043ffdf8..a234715f3 100644 --- a/nmap_rpc.cc +++ b/nmap_rpc.cc @@ -361,7 +361,7 @@ static int rpc_are_we_done(char *msg, int msg_len, Target *target, if (rsi->rpc_current_port->state == PORT_OPENFILTERED) { /* Received a packet, so this port is actually open */ - target->ports.setPortState(rsi->rpc_current_port->portno, + target->ports.addPort(rsi->rpc_current_port->portno, rsi->rpc_current_port->proto, PORT_OPEN); } diff --git a/nmap_rpc.h b/nmap_rpc.h index 8874ce976..5d0d96fc7 100644 --- a/nmap_rpc.h +++ b/nmap_rpc.h @@ -147,7 +147,7 @@ struct rpc_info { }; struct rpcscaninfo { - const Port *rpc_current_port; + Port *rpc_current_port; unsigned long *rpc_progs; unsigned long rpc_number; int valid_responses_this_port; /* Number of valid (RPC wise) responses we diff --git a/nse_main.cc b/nse_main.cc index 2fe96e4c2..868a470eb 100644 --- a/nse_main.cc +++ b/nse_main.cc @@ -82,14 +82,13 @@ static int ports (lua_State *L) Target *target = get_target(L, 1); PortList *plist = &(target->ports); Port *current = NULL; - Port port; lua_newtable(L); for (int i = 0; states[i] != PORT_HIGHEST_STATE; i++) - while ((current = plist->nextPort(current, &port, TCPANDUDPANDSCTP, + while ((current = plist->nextPort(current, TCPANDUDPANDSCTP, states[i])) != NULL) { lua_newtable(L); - set_portinfo(L, target, current); + set_portinfo(L, current); lua_pushboolean(L, 1); lua_rawset(L, -3); } @@ -113,10 +112,10 @@ static int port_set_output (lua_State *L) { ScriptResult sr; Target *target = get_target(L, 1); - const Port *port = get_port(L, target, 2); + Port *port = get_port(L, target, 2); sr.set_id(luaL_checkstring(L, 3)); sr.set_output(luaL_checkstring(L, 4)); - target->ports.addScriptResult(port->portno, port->proto, sr); + port->scriptResults.push_back(sr); /* increment host port script results*/ target->ports.numscriptresults++; return 0; @@ -248,7 +247,7 @@ void ScriptResult::set_output (const char *out) output = std::string(out); } -std::string ScriptResult::get_output (void) const +std::string ScriptResult::get_output (void) { return output; } @@ -258,7 +257,7 @@ void ScriptResult::set_id (const char *ident) id = std::string(ident); } -std::string ScriptResult::get_id (void) const +std::string ScriptResult::get_id (void) { return id; } diff --git a/nse_main.h b/nse_main.h index bc5fdde89..0e74d812e 100644 --- a/nse_main.h +++ b/nse_main.h @@ -20,9 +20,9 @@ class ScriptResult std::string id; public: void set_output (const char *); - std::string get_output (void) const; + std::string get_output (void); void set_id (const char *); - std::string get_id (void) const; + std::string get_id (void); }; typedef std::vector ScriptResults; diff --git a/nse_nmaplib.cc b/nse_nmaplib.cc index ce4329292..6a2cb03b0 100644 --- a/nse_nmaplib.cc +++ b/nse_nmaplib.cc @@ -28,20 +28,20 @@ extern "C" { extern NmapOps o; -void set_version(lua_State *L, const struct serviceDeductions *sd) { - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->name, "name"); +void set_version(lua_State *L, struct serviceDeductions sd) { + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.name, "name"); - lua_pushnumber(L, sd->name_confidence); + lua_pushnumber(L, sd.name_confidence); lua_setfield(L, -2, "name_confidence"); - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->product, "product"); - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->version, "version"); - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->extrainfo, "extrainfo"); - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->hostname, "hostname"); - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->ostype, "ostype"); - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->devicetype, "devicetype"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.product, "product"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.version, "version"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.extrainfo, "extrainfo"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.hostname, "hostname"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.ostype, "ostype"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.devicetype, "devicetype"); - switch(sd->service_tunnel) { + switch(sd.service_tunnel) { case(SERVICE_TUNNEL_NONE): SCRIPT_ENGINE_PUSHSTRING_NOTNULL("none", "service_tunnel"); break; @@ -54,9 +54,9 @@ void set_version(lua_State *L, const struct serviceDeductions *sd) { break; } - SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->service_fp, "service_fp"); + SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.service_fp, "service_fp"); - switch(sd->dtype) { + switch(sd.dtype) { case(SERVICE_DETECTION_TABLE): SCRIPT_ENGINE_PUSHSTRING_NOTNULL("table", "service_fp"); break; @@ -69,7 +69,7 @@ void set_version(lua_State *L, const struct serviceDeductions *sd) { break; } - switch(sd->rpc_status) { + switch(sd.rpc_status) { case(RPC_STATUS_UNTESTED): SCRIPT_ENGINE_PUSHSTRING_NOTNULL("untested", "rpc_status"); break; @@ -88,14 +88,14 @@ void set_version(lua_State *L, const struct serviceDeductions *sd) { break; } - if(sd->rpc_status == RPC_STATUS_GOOD_PROG) { - lua_pushnumber(L, sd->rpc_program); + if(sd.rpc_status == RPC_STATUS_GOOD_PROG) { + lua_pushnumber(L, sd.rpc_program); lua_setfield(L, -2, "rpc_program"); - lua_pushnumber(L, sd->rpc_lowver); + lua_pushnumber(L, sd.rpc_lowver); lua_setfield(L, -2, "rpc_lowver"); - lua_pushnumber(L, sd->rpc_highver); + lua_pushnumber(L, sd.rpc_highver); lua_setfield(L, -2, "rpc_highver"); } } @@ -103,26 +103,24 @@ void set_version(lua_State *L, const struct serviceDeductions *sd) { /* set some port state information onto the * table which is currently on the stack * */ -void set_portinfo(lua_State *L, const Target *target, const Port *port) { +void set_portinfo(lua_State *L, Port* port) { struct serviceDeductions sd; - target->ports.getServiceDeductions(port->portno, port->proto, &sd); + port->getServiceDeductions(&sd); lua_pushnumber(L, (double) port->portno); lua_setfield(L, -2, "number"); - if (sd.name != NULL) { - lua_pushstring(L, sd.name); - lua_setfield(L, -2, "service"); - } - - lua_newtable(L); - set_version(L, &sd); - lua_setfield(L, -2, "version"); + lua_pushstring(L, sd.name); + lua_setfield(L, -2, "service"); lua_pushstring(L, IPPROTO2STR(port->proto)); lua_setfield(L, -2, "protocol"); + lua_newtable(L); + set_version(L, sd); + lua_setfield(L, -2, "version"); + lua_pushstring(L, statenum2str(port->state)); lua_setfield(L, -2, "state"); @@ -421,10 +419,9 @@ done: return target; } -const Port *get_port (lua_State *L, Target *target, int index) +Port *get_port (lua_State *L, Target *target, int index) { - Port *p = NULL; - Port port; + Port *port = NULL; int portno, protocol; luaL_checktype(L, index, LUA_TTABLE); lua_getfield(L, index, "number"); @@ -438,11 +435,11 @@ const Port *get_port (lua_State *L, Target *target, int index) strcmp(lua_tostring(L, -1), "udp") == 0 ? IPPROTO_UDP : strcmp(lua_tostring(L, -1), "sctp") == 0 ? IPPROTO_SCTP : luaL_error(L, "port 'protocol' field must be \"udp\", \"sctp\" or \"tcp\""); - while ((p = target->ports.nextPort(p, &port, protocol, PORT_UNKNOWN)) != NULL) - if (p->portno == portno) + while ((port = target->ports.nextPort(port, protocol, PORT_UNKNOWN)) != NULL) + if (port->portno == portno) break; lua_pop(L, 2); - return p; + return port; } /* this function can be called from lua to obtain the port state @@ -458,7 +455,7 @@ const Port *get_port (lua_State *L, Target *target, int index) static int l_get_port_state (lua_State *L) { Target *target; - const Port *port; + Port *port; target = get_target(L, 1); port = get_port(L, target, 2); if (port == NULL) @@ -466,7 +463,7 @@ static int l_get_port_state (lua_State *L) else { lua_newtable(L); - set_portinfo(L, target, port); + set_portinfo(L, port); } return 1; } @@ -480,7 +477,7 @@ static int l_set_port_state (lua_State *L) static const int opstate[] = {PORT_OPEN, PORT_CLOSED}; static const char *op[] = {"open", "closed", NULL}; Target *target; - const Port *port; + Port *port; target = get_target(L, 1); if ((port = get_port(L, target, 2)) != NULL) { @@ -489,15 +486,17 @@ static int l_set_port_state (lua_State *L) case PORT_OPEN: if (port->state == PORT_OPEN) return 0; - target->ports.setPortState(port->portno, port->proto, PORT_OPEN); + target->ports.addPort(port->portno, port->proto, PORT_OPEN); + port->state = PORT_OPEN; break; case PORT_CLOSED: if (port->state == PORT_CLOSED) return 0; - target->ports.setPortState(port->portno, port->proto, PORT_CLOSED); + target->ports.addPort(port->portno, port->proto, PORT_CLOSED); + port->state = PORT_CLOSED; break; } - target->ports.setStateReason(port->portno, port->proto, ER_SCRIPT, 0, 0); + port->reason.reason_id = ER_SCRIPT; } return 0; } @@ -519,7 +518,7 @@ static int l_set_port_version (lua_State *L) "incomplete" }; Target *target; - const Port *port; + Port *port; enum service_tunnel_type tunnel = SERVICE_TUNNEL_NONE; enum serviceprobestate probestate = opversion[luaL_checkoption(L, 3, "hardmatched", ops)]; @@ -550,12 +549,10 @@ static int l_set_port_version (lua_State *L) luaL_argerror(L, 2, "invalid value for port.version.service_tunnel"); if (o.servicescan) - target->ports.setServiceProbeResults(port->portno, port->proto, - probestate, name, tunnel, product, + port->setServiceProbeResults(probestate, name, tunnel, product, version, extrainfo, hostname, ostype, devicetype, NULL); else - target->ports.setServiceProbeResults(port->portno, port->proto, - probestate, name, tunnel, NULL, NULL, + port->setServiceProbeResults(probestate, name, tunnel, NULL, NULL, NULL, NULL, NULL, NULL, NULL); return 0; diff --git a/nse_nmaplib.h b/nse_nmaplib.h index 3020a05cc..477287b59 100644 --- a/nse_nmaplib.h +++ b/nse_nmaplib.h @@ -7,9 +7,9 @@ class Port; int luaopen_nmap(lua_State* l); int luaopen_stdnse_c (lua_State *L); void set_hostinfo(lua_State* l, Target* currenths); -void set_portinfo(lua_State* l, const Target *target, const Port* port); +void set_portinfo(lua_State* l, Port* port); Target *get_target (lua_State *L, int index); -const Port *get_port (lua_State *L, Target *target, int index); +Port *get_port (lua_State *L, Target *target, int index); #endif diff --git a/osscan2.cc b/osscan2.cc index 812a669c9..28555c8a0 100644 --- a/osscan2.cc +++ b/osscan2.cc @@ -640,7 +640,6 @@ HostOsScanStats::~HostOsScanStats() { void HostOsScanStats::initScanStats() { Port *tport = NULL; - Port port; int i; /* Lets find an open port to use if we don't already have one */ @@ -651,11 +650,11 @@ void HostOsScanStats::initScanStats() { if (target->FPR->osscan_opentcpport > 0) openTCPPort = target->FPR->osscan_opentcpport; - else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_TCP, PORT_OPEN))) { + else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_OPEN))) { openTCPPort = tport->portno; /* If it is zero, let's try another one if there is one ) */ if (tport->portno == 0) - if ((tport = target->ports.nextPort(tport, &port, IPPROTO_TCP, PORT_OPEN))) + if ((tport = target->ports.nextPort(tport, IPPROTO_TCP, PORT_OPEN))) openTCPPort = tport->portno; target->FPR->osscan_opentcpport = openTCPPort; @@ -664,21 +663,21 @@ void HostOsScanStats::initScanStats() { /* Now we should find a closed port */ if (target->FPR->osscan_closedtcpport > 0) closedTCPPort = target->FPR->osscan_closedtcpport; - else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_TCP, PORT_CLOSED))) { + else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_CLOSED))) { closedTCPPort = tport->portno; /* If it is zero, let's try another one if there is one ) */ if (tport->portno == 0) - if ((tport = target->ports.nextPort(tport, &port, IPPROTO_TCP, PORT_CLOSED))) + if ((tport = target->ports.nextPort(tport, IPPROTO_TCP, PORT_CLOSED))) closedTCPPort = tport->portno; target->FPR->osscan_closedtcpport = closedTCPPort; - } else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_TCP, PORT_UNFILTERED))) { + } else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_UNFILTERED))) { /* Well, we will settle for unfiltered */ closedTCPPort = tport->portno; /* But again we'd prefer not to have zero */ if (tport->portno == 0) - if ((tport = target->ports.nextPort(tport, &port, IPPROTO_TCP, PORT_UNFILTERED))) + if ((tport = target->ports.nextPort(tport, IPPROTO_TCP, PORT_UNFILTERED))) closedTCPPort = tport->portno; } else { /* We'll just have to pick one at random :( */ @@ -688,19 +687,19 @@ void HostOsScanStats::initScanStats() { /* Now we should find a closed udp port */ if (target->FPR->osscan_closedudpport > 0) closedUDPPort = target->FPR->osscan_closedudpport; - else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_UDP, PORT_CLOSED))) { + else if ((tport = target->ports.nextPort(NULL, IPPROTO_UDP, PORT_CLOSED))) { closedUDPPort = tport->portno; /* Not zero, if possible */ if (tport->portno == 0) - if ((tport = target->ports.nextPort(tport, &port, IPPROTO_UDP, PORT_CLOSED))) + if ((tport = target->ports.nextPort(tport, IPPROTO_UDP, PORT_CLOSED))) closedUDPPort = tport->portno; target->FPR->osscan_closedudpport = closedUDPPort; - } else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_UDP, PORT_UNFILTERED))) { + } else if ((tport = target->ports.nextPort(NULL, IPPROTO_UDP, PORT_UNFILTERED))) { /* Well, we will settle for unfiltered */ closedUDPPort = tport->portno; /* But not zero, please */ if (tport->portno == 0) - if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_UDP, PORT_UNFILTERED))) + if ((tport = target->ports.nextPort(NULL, IPPROTO_UDP, PORT_UNFILTERED))) closedUDPPort = tport->portno; } else { /* Pick one at random. Shrug. */ diff --git a/output.cc b/output.cc index ee863cb05..88a6b876c 100644 --- a/output.cc +++ b/output.cc @@ -202,7 +202,7 @@ static char *xml_sf_convert(const char *str) { // the service name or the service fingerprint is non-null. // Returns a pointer to a buffer containing the element, // you will have to call free on it. -static char *getServiceXMLBuf(const struct serviceDeductions *sd) { +static char *getServiceXMLBuf(struct serviceDeductions *sd) { string versionxmlstring = ""; char rpcbuf[128]; char confBuf[20]; @@ -466,6 +466,33 @@ int print_iflist(void) { return 0; } +/* Fills in namebuf (as long as there is space in buflen) with the + Name nmap normal output will use to describe the port. This takes + into account to confidence level, any SSL tunneling, etc. Truncates + namebuf to 0 length if there is no room.*/ +static void getNmapServiceName(struct serviceDeductions *sd, int state, + char *namebuf, int buflen) { + const char *tunnel_prefix; + int len; + + if (sd->service_tunnel == SERVICE_TUNNEL_SSL) + tunnel_prefix = "ssl/"; + else + tunnel_prefix = ""; + + if (sd->name != NULL && strcmp(sd->name, "unknown") != 0) { + /* The port has a name and the name is not "unknown". How confident are we? */ + if (o.servicescan && state == PORT_OPEN && sd->name_confidence <= 5) + len = Snprintf(namebuf, buflen, "%s%s?", tunnel_prefix, sd->name); + else + len = Snprintf(namebuf, buflen, "%s%s", tunnel_prefix, sd->name); + } else { + len = Snprintf(namebuf, buflen, "%sunknown", tunnel_prefix); + } + if (len >= buflen || len < 0) + namebuf[0] = '\0'; +} + #ifndef NOLUA static char *formatScriptOutput(ScriptResult sr) { std::string result = std::string(), output = sr.get_output(); @@ -522,7 +549,6 @@ void printportoutput(Target * currenths, PortList * plist) { int first = 1; struct protoent *proto; Port *current; - Port port; char hostname[1200]; struct serviceDeductions sd; NmapOutputTable *Tbl = NULL; @@ -535,7 +561,6 @@ void printportoutput(Target * currenths, PortList * plist) { unsigned int rowno; int numrows; int numignoredports = plist->numIgnoredPorts(); - int numports = plist->numPorts(); vector saved_servicefps; @@ -554,7 +579,7 @@ void printportoutput(Target * currenths, PortList * plist) { prevstate = istate; } - if (numignoredports == numports) { + if (numignoredports == plist->numports) { if (numignoredports == 0) { log_write(LOG_PLAIN, "0 ports scanned on %s\n", currenths->NameIP(hostname, sizeof(hostname))); @@ -641,7 +666,7 @@ void printportoutput(Target * currenths, PortList * plist) { if (o.servicescan || o.rpcscan) versioncol = colno++; - numrows = numports - numignoredports; + numrows = plist->numports - numignoredports; #ifndef NOLUA int scriptrows = 0; @@ -672,7 +697,7 @@ void printportoutput(Target * currenths, PortList * plist) { rowno = 1; if (o.ipprotscan) { current = NULL; - while ((current = plist->nextPort(current, &port, IPPROTO_IP, 0)) != NULL) { + while ((current = plist->nextPort(current, IPPROTO_IP, 0)) != NULL) { if (!plist->isIgnoredState(current->state)) { if (!first) log_write(LOG_MACHINE, ", "); @@ -705,10 +730,8 @@ void printportoutput(Target * currenths, PortList * plist) { } } } else { - char fullversion[160]; - current = NULL; - while ((current = plist->nextPort(current, &port, TCPANDUDPANDSCTP, 0)) != NULL) { + while ((current = plist->nextPort(current, TCPANDUDPANDSCTP, 0)) != NULL) { if (!plist->isIgnoredState(current->state)) { if (!first) log_write(LOG_MACHINE, ", "); @@ -717,7 +740,7 @@ void printportoutput(Target * currenths, PortList * plist) { strcpy(protocol, IPPROTO2STR(current->proto)); Snprintf(portinfo, sizeof(portinfo), "%d/%s", current->portno, protocol); state = statenum2str(current->state); - plist->getServiceDeductions(current->portno, current->proto, &sd); + current->getServiceDeductions(&sd); if (sd.service_fp && saved_servicefps.size() <= 8) saved_servicefps.push_back(sd.service_fp); @@ -760,7 +783,7 @@ void printportoutput(Target * currenths, PortList * plist) { (sd.name) ? sd.name : ((*rpcinfo) ? "" : "unknown"), (sd.name) ? " " : "", rpcinfo); } else { - current->getNmapServiceName(serviceinfo, sizeof(serviceinfo)); + getNmapServiceName(&sd, current->state, serviceinfo, sizeof(serviceinfo)); rpcmachineinfo[0] = '\0'; } Tbl->addItem(rowno, portcol, true, portinfo); @@ -769,9 +792,8 @@ void printportoutput(Target * currenths, PortList * plist) { if (o.reason) Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason)); - sd.populateFullVersionString(fullversion, sizeof(fullversion)); - if (*fullversion) - Tbl->addItem(rowno, versioncol, true, fullversion); + if (*sd.fullversion) + Tbl->addItem(rowno, versioncol, true, sd.fullversion); // How should we escape illegal chars in grepable output? // Well, a reasonably clean way would be backslash escapes @@ -779,7 +801,7 @@ void printportoutput(Target * currenths, PortList * plist) { // out fields with awk, cut, and such. So I'm gonna use the // ugly hat (fitting to grepable output) or replacing the '/' // character with '|' in the version field. - Strncpy(grepvers, fullversion, sizeof(grepvers) / sizeof(*grepvers)); + Strncpy(grepvers, sd.fullversion, sizeof(grepvers) / sizeof(*grepvers)); p = grepvers; while ((p = strchr(p, '/'))) { *p = '|'; @@ -818,7 +840,7 @@ void printportoutput(Target * currenths, PortList * plist) { rowno++; #ifndef NOLUA if (o.script) { - ScriptResults::const_iterator ssr_iter; + ScriptResults::iterator ssr_iter; for (ssr_iter = current->scriptResults.begin(); ssr_iter != current->scriptResults.end(); ssr_iter++) { @@ -1885,7 +1907,6 @@ static int hostcmp(const char *a, const char *b) { scan (if it was performed) */ void printserviceinfooutput(Target * currenths) { Port *p = NULL; - Port port; struct serviceDeductions sd; int i, numhostnames = 0, numostypes = 0, numdevicetypes = 0; char hostname_tbl[MAX_SERVICE_INFO_FIELDS][MAXHOSTNAMELEN]; @@ -1896,12 +1917,12 @@ void printserviceinfooutput(Target * currenths) { for (i = 0; i < MAX_SERVICE_INFO_FIELDS; i++) hostname_tbl[i][0] = ostype_tbl[i][0] = devicetype_tbl[i][0] = '\0'; - while ((p = currenths->ports.nextPort(p, &port, TCPANDUDPANDSCTP, PORT_OPEN))) { + while ((p = currenths->ports.nextPort(p, TCPANDUDPANDSCTP, PORT_OPEN))) { // The following 2 lines (from portlist.h) tell us that we don't need to // worry about free()ing anything in the serviceDeductions struct. pass in // an allocated struct serviceDeductions (don't wory about initializing, and // you don't have to free any internal ptrs. - currenths->ports.getServiceDeductions(p->portno, p->proto, &sd); + p->getServiceDeductions(&sd); if (sd.hostname && !hostcmp(currenths->HostName(), sd.hostname)) { for (i = 0; i < MAX_SERVICE_INFO_FIELDS; i++) { diff --git a/portlist.cc b/portlist.cc index 59fd046eb..5872a5502 100644 --- a/portlist.cc +++ b/portlist.cc @@ -109,95 +109,42 @@ extern NmapOps o; /* option structure */ Port::Port() { portno = proto = 0; + rpc_status = RPC_STATUS_UNTESTED; + rpc_program = rpc_lowver = rpc_highver = 0; state = 0; - service = NULL; + serviceprobe_results = PROBESTATE_INITIAL; + serviceprobe_service = NULL; + serviceprobe_product = serviceprobe_version = serviceprobe_extrainfo = NULL; + serviceprobe_hostname = serviceprobe_ostype = serviceprobe_devicetype = NULL; + serviceprobe_tunnel = SERVICE_TUNNEL_NONE; + serviceprobe_fp = NULL; state_reason_init(&reason); } Port::~Port() { - if (service != NULL) { - if (service->name) - free(service->name); - if (service->product) - free(service->product); - if (service->version) - free(service->version); - if (service->extrainfo) - free(service->extrainfo); - if (service->hostname) - free(service->hostname); - if (service->ostype) - free(service->ostype); - if (service->devicetype) - free(service->devicetype); - if (service->service_fp) - free(service->service_fp); - delete service; - } -} - -/* Fills in namebuf (as long as there is space in buflen) with the - Name nmap normal output will use to describe the port. This takes - into account to confidence level, any SSL tunneling, etc. Truncates - namebuf to 0 length if there is no room.*/ -void Port::getNmapServiceName(char *namebuf, int buflen) const { - const char *tunnel_prefix; - const char *service_name; - int len; - - if (service != NULL && service->service_tunnel == SERVICE_TUNNEL_SSL) - tunnel_prefix = "ssl/"; - else - tunnel_prefix = ""; - - if (service != NULL && service->name != NULL) { - service_name = service->name; - } else { - struct servent *service; - - service = nmap_getservbyport(htons(portno), IPPROTO2STR(proto)); - if (service != NULL) - service_name = service->s_name; - else - service_name = NULL; - } - - if (service_name != NULL && strcmp(service_name, "unknown") != 0) { - /* The port has a name and the name is not "unknown". How confident are we? */ - if (o.servicescan && state == PORT_OPEN && (service == NULL || service->name_confidence <= 5)) - len = Snprintf(namebuf, buflen, "%s%s?", tunnel_prefix, service_name); - else - len = Snprintf(namebuf, buflen, "%s%s", tunnel_prefix, service_name); - } else { - len = Snprintf(namebuf, buflen, "%sunknown", tunnel_prefix); - } - if (len >= buflen || len < 0) - namebuf[0] = '\0'; -} - -serviceDeductions::serviceDeductions() { - name = NULL; - name_confidence = 0; - product = NULL; - version = NULL; - extrainfo = NULL; - hostname = NULL; - ostype = NULL; - devicetype = NULL; - service_tunnel = SERVICE_TUNNEL_NONE; - service_fp = NULL; - dtype = SERVICE_DETECTION_TABLE; - rpc_status = RPC_STATUS_UNTESTED; - rpc_program = 0; - rpc_lowver = 0; - rpc_highver = 0; + if (serviceprobe_product) + free(serviceprobe_product); + if (serviceprobe_version) + free(serviceprobe_version); + if (serviceprobe_extrainfo) + free(serviceprobe_extrainfo); + if (serviceprobe_hostname) + free(serviceprobe_hostname); + if (serviceprobe_ostype) + free(serviceprobe_ostype); + if (serviceprobe_devicetype) + free(serviceprobe_devicetype); + if (serviceprobe_service) + free(serviceprobe_service); + if (serviceprobe_fp) + free(serviceprobe_fp); } // Uses the sd->{product,version,extrainfo} if available to fill // out sd->fullversion. If unavailable, it will be set to zero length. -void serviceDeductions::populateFullVersionString(char *buf, size_t n) const { - char *dst = buf; - unsigned int spaceleft = n - 1; // Leave room for \0 +static void populateFullVersionString(struct serviceDeductions *sd) { + char *dst = sd->fullversion; + unsigned int spaceleft = sizeof(sd->fullversion) - 1; // Leave room for \0 int needpad = 0; // Do we need to pad a space between the next template? dst[0] = '\0'; @@ -209,52 +156,52 @@ void serviceDeductions::populateFullVersionString(char *buf, size_t n) const { * that bit of information. */ - if (product && spaceleft >= 8) { - if (spaceleft < strlen(product)) { - strncat(dst, product, spaceleft - 3); // Leave room for "..." + if (sd->product && spaceleft >= 8) { + if (spaceleft < strlen(sd->product)) { + strncat(dst, sd->product, spaceleft - 3); // Leave room for "..." strncat(dst, "...", spaceleft); spaceleft = 0; } else { - strncat(dst, product, spaceleft); - spaceleft -= strlen(product); + strncat(dst, sd->product, spaceleft); + spaceleft -= strlen(sd->product); } needpad = 1; } - if (version && spaceleft >= 8) { + if (sd->version && spaceleft >= 8) { if (needpad) { strncat(dst, " ", spaceleft); spaceleft--; } - if (spaceleft < strlen(version)) { - strncat(dst, version, spaceleft - 3); + if (spaceleft < strlen(sd->version)) { + strncat(dst, sd->version, spaceleft - 3); strncat(dst, "...", spaceleft); spaceleft = 0; } else { - strncat(dst, version, spaceleft); - spaceleft -= strlen(version); + strncat(dst, sd->version, spaceleft); + spaceleft -= strlen(sd->version); } needpad = 1; } - if (extrainfo && spaceleft >= 8) { + if (sd->extrainfo && spaceleft >= 8) { if (needpad) { strncat(dst, " ", spaceleft); spaceleft--; } // This time we need to trucate inside of the () so we have spaceleft - 2 strncat(dst, "(", spaceleft); - if (spaceleft - 2 < strlen(extrainfo)) { - strncat(dst, extrainfo, spaceleft - 5); + if (spaceleft - 2 < strlen(sd->extrainfo)) { + strncat(dst, sd->extrainfo, spaceleft - 5); strncat(dst, "...", spaceleft - 2); spaceleft = 1; // Fit the paren } else { - strncat(dst, extrainfo, spaceleft); - spaceleft -= (strlen(extrainfo) + 2); + strncat(dst, sd->extrainfo, spaceleft); + spaceleft -= (strlen(sd->extrainfo) + 2); } strncat(dst, ")", spaceleft); spaceleft--; @@ -267,24 +214,74 @@ void serviceDeductions::populateFullVersionString(char *buf, size_t n) const { // initializing, and you don't have to free any internal ptrs. See the // serviceDeductions definition for the fields that are populated. // Returns 0 if at least a name is available. -const void PortList::getServiceDeductions(u16 portno, int protocol, struct serviceDeductions *sd) const { - const Port *port; +int Port::getServiceDeductions(struct serviceDeductions *sd) { + struct servent *service; - port = lookupPort(portno, protocol); - if (port == NULL || port->service == NULL) { - struct servent *service; + assert(sd); + memset(sd, 0, sizeof(struct serviceDeductions)); + sd->service_fp = serviceprobe_fp; + sd->service_tunnel = serviceprobe_tunnel; + sd->rpc_status = rpc_status; + sd->rpc_program = rpc_program; + sd->rpc_lowver = rpc_lowver; + sd->rpc_highver = rpc_highver; - /* Look up the service name. */ - *sd = serviceDeductions(); - service = nmap_getservbyport(htons(portno), IPPROTO2STR(protocol)); - if (service != NULL) - sd->name = service->s_name; - else - sd->name = NULL; - sd->name_confidence = 3; - } else { - *sd = *port->service; + // First priority is RPC + if (rpc_status == RPC_STATUS_UNKNOWN || rpc_status == RPC_STATUS_GOOD_PROG ) { + assert(serviceprobe_service); + sd->name = serviceprobe_service; + sd->name_confidence = (rpc_status == RPC_STATUS_UNKNOWN)? 8 : 10; + sd->dtype = SERVICE_DETECTION_PROBED; // RPC counts as probed + sd->version = serviceprobe_version; + sd->extrainfo = serviceprobe_extrainfo; + sd->hostname = serviceprobe_hostname; + sd->ostype = serviceprobe_ostype; + sd->devicetype = serviceprobe_devicetype; + populateFullVersionString(sd); + return 0; + } else if (serviceprobe_results == PROBESTATE_FINISHED_HARDMATCHED + || serviceprobe_results == PROBESTATE_FINISHED_SOFTMATCHED) { + assert(serviceprobe_service); + sd->dtype = SERVICE_DETECTION_PROBED; + sd->name = serviceprobe_service; + sd->name_confidence = 10; + sd->product = serviceprobe_product; + sd->version = serviceprobe_version; + sd->extrainfo = serviceprobe_extrainfo; + sd->hostname = serviceprobe_hostname; + sd->ostype = serviceprobe_ostype; + sd->devicetype = serviceprobe_devicetype; + populateFullVersionString(sd); + return 0; + } else if (serviceprobe_results == PROBESTATE_EXCLUDED) { + service = nmap_getservbyport(htons(portno), IPPROTO2STR(proto)); + + if (service) sd->name = service->s_name; + + sd->name_confidence = 2; // Since we didn't even check it, we aren't very confident + sd->dtype = SERVICE_DETECTION_TABLE; + sd->product = serviceprobe_product; // Should have a string that says port was excluded + populateFullVersionString(sd); + return 0; + } else if (serviceprobe_results == PROBESTATE_FINISHED_TCPWRAPPED) { + sd->dtype = SERVICE_DETECTION_PROBED; + sd->name = "tcpwrapped"; + sd->name_confidence = 8; + return 0; } + + // So much for service detection or RPC. Maybe we can find it in the file + service = nmap_getservbyport(htons(portno), IPPROTO2STR(proto)); + if (service) { + sd->dtype = SERVICE_DETECTION_TABLE; + sd->name = service->s_name; + sd->name_confidence = 3; + return 0; + } + + // Couldn't find it. [shrug] + return -1; + } @@ -315,112 +312,72 @@ static char *cstringSanityCheck(const char* string, int len) { return result; } -void PortList::setServiceProbeResults(u16 portno, int protocol, - enum serviceprobestate sres, const char *sname, - enum service_tunnel_type tunnel, const char *product, const char *version, - const char *extrainfo, const char *hostname, const char *ostype, - const char *devicetype, const char *fingerprint) { - Port *port; +void Port::setServiceProbeResults(enum serviceprobestate sres, + const char *sname, + enum service_tunnel_type tunnel, + const char *product, const char *version, + const char *extrainfo, const char *hostname, + const char *ostype, const char *devicetype, + const char *fingerprint) { - port = createPort(portno, protocol); - if (port->service == NULL) - port->service = new serviceDeductions; + serviceprobe_results = sres; + serviceprobe_tunnel = tunnel; - if (sres == PROBESTATE_FINISHED_HARDMATCHED - || sres == PROBESTATE_FINISHED_SOFTMATCHED) { - port->service->dtype = SERVICE_DETECTION_PROBED; - port->service->name_confidence = 10; - } else if (sres == PROBESTATE_EXCLUDED) { - if (sname == NULL) { - struct servent *service; - service = nmap_getservbyport(htons(portno), IPPROTO2STR(protocol)); - if (service != NULL) - sname = service->s_name; - } - port->service->dtype = SERVICE_DETECTION_TABLE; - port->service->name_confidence = 2; // Since we didn't even check it, we aren't very confident - } else if (sres == PROBESTATE_FINISHED_TCPWRAPPED) { - port->service->dtype = SERVICE_DETECTION_PROBED; - if (sname == NULL) - sname = "tcpwrapped"; - port->service->dtype = SERVICE_DETECTION_TABLE; - port->service->name_confidence = 8; - } + if (sname) + serviceprobe_service = strdup(sname); + else + serviceprobe_service = NULL; - // port->serviceprobe_results = sres; - port->service->service_tunnel = tunnel; + if (fingerprint) + serviceprobe_fp = strdup(fingerprint); + else + serviceprobe_fp = NULL; - if (sname) - port->service->name = strdup(sname); - else - port->service->name = NULL; - - if (fingerprint) - port->service->service_fp = strdup(fingerprint); - else - port->service->service_fp = NULL; - - port->service->product = cstringSanityCheck(product, 80); - port->service->version = cstringSanityCheck(version, 80); - port->service->extrainfo = cstringSanityCheck(extrainfo, 256); - port->service->hostname = cstringSanityCheck(hostname, 80); - port->service->ostype = cstringSanityCheck(ostype, 32); - port->service->devicetype = cstringSanityCheck(devicetype, 32); + serviceprobe_product = cstringSanityCheck(product, 80); + serviceprobe_version = cstringSanityCheck(version, 80); + serviceprobe_extrainfo = cstringSanityCheck(extrainfo, 256); + serviceprobe_hostname = cstringSanityCheck(hostname, 80); + serviceprobe_ostype = cstringSanityCheck(ostype, 32); + serviceprobe_devicetype = cstringSanityCheck(devicetype, 32); } /* Sets the results of an RPC scan. if rpc_status is not RPC_STATUS_GOOD_PROGRAM, pass 0 for the other args. This function takes care of setting the port's service and version appropriately. */ -void PortList::setRPCProbeResults(u16 portno, int proto, int rpcs, unsigned long rpcp, +void Port::setRPCProbeResults(int rpcs, unsigned long rpcp, unsigned int rpcl, unsigned int rpch) { - Port *port; + rpc_status = rpcs; const char *newsvc; char verbuf[128]; - port = createPort(portno, proto); - if (port->service == NULL) - port->service = new serviceDeductions; - - port->service->rpc_status = rpcs; - if (port->service->rpc_status == RPC_STATUS_GOOD_PROG) { - port->service->rpc_program = rpcp; - port->service->rpc_lowver = rpcl; - port->service->rpc_highver = rpch; + rpc_status = rpcs; + if (rpc_status == RPC_STATUS_GOOD_PROG) { + rpc_program = rpcp; + rpc_lowver = rpcl; + rpc_highver = rpch; // Now set the service/version info newsvc = nmap_getrpcnamebynum(rpcp); if (!newsvc) newsvc = "rpc.unknownprog"; // should never happen - if (port->service->name) - free(port->service->name); - port->service->name = strdup(newsvc); - if (port->service->rpc_lowver == port->service->rpc_highver) - Snprintf(verbuf, sizeof(verbuf), "%i", port->service->rpc_lowver); + if (serviceprobe_service) + free(serviceprobe_service); + serviceprobe_service = strdup(newsvc); + serviceprobe_product = strdup(newsvc); + if (rpc_lowver == rpc_highver) + Snprintf(verbuf, sizeof(verbuf), "%i", rpc_lowver); else - Snprintf(verbuf, sizeof(verbuf), "%i-%i", port->service->rpc_lowver, port->service->rpc_highver); - port->service->version = strdup(verbuf); - Snprintf(verbuf, sizeof(verbuf), "rpc #%li", port->service->rpc_program); - port->service->extrainfo = strdup(verbuf); - port->service->name_confidence = 10; - port->service->dtype = SERVICE_DETECTION_PROBED; - } else if (port->service->rpc_status == RPC_STATUS_UNKNOWN) { - if (port->service->name) - free(port->service->name); + Snprintf(verbuf, sizeof(verbuf), "%i-%i", rpc_lowver, rpc_highver); + serviceprobe_version = strdup(verbuf); + Snprintf(verbuf, sizeof(verbuf), "rpc #%li", rpc_program); + serviceprobe_extrainfo = strdup(verbuf); + } else if (rpc_status == RPC_STATUS_UNKNOWN) { + if (serviceprobe_service) + free(serviceprobe_service); - port->service->name = strdup("rpc.unknown"); - port->service->name_confidence = 8; - port->service->dtype = SERVICE_DETECTION_PROBED; + serviceprobe_service = strdup("rpc.unknown"); } } - -void PortList::addScriptResult(u16 portno, int protocol, ScriptResult& sr) { - Port *port; - - port = createPort(portno, protocol); - - port->scriptResults.push_back(sr); -} - /*****************************************************************************/ /* Convert protocol name from in.h to enum portlist_proto. * So IPPROTO_TCP will be changed to PORTLIST_PROTO_TCP and so on. */ @@ -430,12 +387,6 @@ void PortList::addScriptResult(u16 portno, int protocol, ScriptResult& sr) { (p)==IPPROTO_SCTP ? PORTLIST_PROTO_SCTP : \ PORTLIST_PROTO_IP) -#define PORTLISTPROTO2INPROTO(p) \ - ((p)==PORTLIST_PROTO_TCP ? IPPROTO_TCP : \ - (p)==PORTLIST_PROTO_UDP ? IPPROTO_UDP : \ - (p)==PORTLIST_PROTO_SCTP ? IPPROTO_SCTP : \ - IPPROTO_IP) - PortList::PortList() { int proto; @@ -445,11 +396,9 @@ PortList::PortList() { 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]); - default_port_state[proto].proto = PORTLISTPROTO2INPROTO(proto); - default_port_state[proto].reason.reason_id = ER_NORESPONSE; - state_counts_proto[proto][default_port_state[proto].state] = port_list_count[proto]; } + numports = 0; numscriptresults = 0; idstr = NULL; } @@ -473,22 +422,8 @@ PortList::~PortList() { } } -void PortList::setDefaultPortState(u8 protocol, int state) { - int proto = INPROTO2PORTLISTPROTO(protocol); - int i; - for (i = 0; i < port_list_count[proto]; i++) { - if (port_list[proto][i] == NULL) { - state_counts_proto[proto][default_port_state[proto].state]--; - state_counts_proto[proto][state]++; - } - } - - default_port_state[proto].state = state; -} - -void PortList::setPortState(u16 portno, u8 protocol, int state) { - const Port *oldport; +int PortList::addPort(u16 portno, u8 protocol, int state) { Port *current; int proto = INPROTO2PORTLISTPROTO(protocol); @@ -510,35 +445,55 @@ void PortList::setPortState(u16 portno, u8 protocol, int state) { assert(protocol!=IPPROTO_IP || portno<256); - oldport = lookupPort(portno, protocol); - if (oldport != NULL) { + current = getPortEntry(portno, protocol); + if (current) { /* We must discount our statistics from the old values. Also warn if a complete duplicate */ - if (o.debugging && oldport->state == state) { + if (o.debugging && current->state == state) { error("Duplicate port (%hu/%s)", portno, proto2ascii(protocol)); } - state_counts_proto[proto][oldport->state]--; + state_counts_proto[proto][current->state]--; } else { - state_counts_proto[proto][default_port_state[proto].state]--; + current = new Port(); + current->portno = portno; + current->proto = protocol; + numports++; + + setPortEntry(portno, protocol, current); } - current = createPort(portno, protocol); current->state = state; state_counts_proto[proto][state]++; if(state == PORT_FILTERED || state == PORT_OPENFILTERED) setStateReason(portno, protocol, ER_NORESPONSE, 0, 0); - return; + return 0; /*success */ } -int PortList::getPortState(u16 portno, u8 protocol) { - const Port *port; +int PortList::removePort(u16 portno, u8 protocol) { + Port *answer = NULL; - port = lookupPort(portno, protocol); - if (port == NULL) + log_write(LOG_PLAIN, "Removed %d\n", portno); + + answer = getPortEntry(portno, protocol); + if (!answer) return -1; - return port->state; + setPortEntry(portno, protocol, NULL); + + if (o.verbose) { + log_write(LOG_STDOUT, "Deleting port %hu/%s, which we thought was %s\n", + portno, proto2ascii(answer->proto), + statenum2str(answer->state)); + log_flush(LOG_STDOUT); + } + + /* Discount statistics */ + state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][answer->state]--; + numports--; + + delete answer; + return 0; } /* Saves an identification string for the target containing these @@ -557,13 +512,13 @@ void PortList::setIdStr(const char *id) { int PortList::getStateCounts(int protocol, int state){ - return state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][state]; + return(state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][state]); } int PortList::getStateCounts(int state){ int sum=0, proto; for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) - sum += getStateCounts(PORTLISTPROTO2INPROTO(proto), state); + sum += state_counts_proto[proto][state]; return(sum); } @@ -577,19 +532,19 @@ int PortList::getStateCounts(int state){ function returns ports in numeric order from lowest to highest, except that if you ask for both TCP, UDP & SCTP, every TCP port will be returned before we start returning UDP and SCTP ports */ -Port *PortList::nextPort(const Port *cur, Port *next, +Port *PortList::nextPort(Port *afterthisport, int allowed_protocol, int allowed_state) { int proto; int mapped_pno; Port *port; - if (cur) { - proto = INPROTO2PORTLISTPROTO(cur->proto); + if(afterthisport) { + 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(cur->proto!=IPPROTO_IP || cur->portno<256); - mapped_pno = port_map[proto][cur->portno]; + 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 + }else { // running for the first time if (allowed_protocol == TCPANDUDPANDSCTP) proto = INPROTO2PORTLISTPROTO(IPPROTO_TCP); else if (allowed_protocol == UDPANDSCTP) @@ -602,128 +557,78 @@ Port *PortList::nextPort(const Port *cur, Port *next, if(port_list[proto] != NULL) { for(;mapped_pno < port_list_count[proto]; mapped_pno++) { port = port_list[proto][mapped_pno]; - if (port && (allowed_state==0 || port->state==allowed_state)) { - *next = *port; - return next; - } - if (!port && (allowed_state==0 || default_port_state[proto].state==allowed_state)) { - *next = default_port_state[proto]; - next->portno = port_map_rev[proto][mapped_pno]; - return next; - } + if(port && (allowed_state==0 || port->state==allowed_state)) + return(port); } } /* if all protocols, than after TCP search UDP & SCTP */ - if((!cur && allowed_protocol == TCPANDUDPANDSCTP) || - (cur && proto == INPROTO2PORTLISTPROTO(IPPROTO_TCP))) - return(nextPort(NULL, next, UDPANDSCTP, allowed_state)); + if((!afterthisport && allowed_protocol == TCPANDUDPANDSCTP) || + (afterthisport && proto == INPROTO2PORTLISTPROTO(IPPROTO_TCP))) + return(nextPort(NULL, UDPANDSCTP, allowed_state)); /* if all protocols, than after UDP search SCTP */ - if((!cur && allowed_protocol == UDPANDSCTP) || - (cur && proto == INPROTO2PORTLISTPROTO(IPPROTO_UDP))) - return(nextPort(NULL, next, IPPROTO_SCTP, allowed_state)); + if((!afterthisport && allowed_protocol == UDPANDSCTP) || + (afterthisport && proto == INPROTO2PORTLISTPROTO(IPPROTO_UDP))) + return(nextPort(NULL, IPPROTO_SCTP, allowed_state)); return(NULL); } + +Port *PortList::getPortEntry(u16 portno, u8 protocol) { + int proto = INPROTO2PORTLISTPROTO(protocol); + int mapped_pno; -/* Convert portno and protocol into the internal indices used to index - port_list. Returns false on error, true otherwise. */ -bool PortList::mapPort(u16 *portno, u8 *protocol) const { - int mapped_portno, mapped_protocol; + assert(protocol!=IPPROTO_IP || portno<256); + if(port_map[proto]==NULL || port_list[proto]==NULL) + fatal("%s(%i,%i): you're trying to access uninitialized protocol", __func__, portno, protocol); + mapped_pno = port_map[proto][portno]; - mapped_protocol = INPROTO2PORTLISTPROTO(*protocol); - - if (*protocol == IPPROTO_IP) - assert(*portno < 256); - if(port_map[mapped_protocol]==NULL || port_list[mapped_protocol]==NULL) - fatal("%s(%i,%i): you're trying to access uninitialized protocol", __func__, *portno, *protocol); - mapped_portno = port_map[mapped_protocol][*portno]; - - assert(mapped_portno < port_list_count[mapped_protocol]); - assert(mapped_portno >= 0); + assert(mapped_pno < port_list_count[proto]); + assert(mapped_pno >= 0); - *portno = mapped_portno; - *protocol = mapped_protocol; - - return true; + /* The ugly hack: we allow only port 0 to be mapped to 0 position */ + if(mapped_pno==0 && portno!=0) { + error("WARNING: %s(%i,%i): this port was not mapped", __func__, portno, protocol); + return(NULL); + }else + return(port_list[proto][mapped_pno]); } -const Port *PortList::lookupPort(u16 portno, u8 protocol) const { - if (!mapPort(&portno, &protocol)) - return NULL; +void PortList::setPortEntry(u16 portno, u8 protocol, Port *port) { + int proto = INPROTO2PORTLISTPROTO(protocol); + int mapped_pno; - return port_list[protocol][portno]; -} + assert(protocol!=IPPROTO_IP || portno<256); + if(port_map[proto]==NULL || port_list[proto]==NULL) + fatal("%s(%i,%i): you're trying to access uninitialized protocol", __func__, portno, protocol); + mapped_pno = port_map[proto][portno]; -/* Create the port if it doesn't exist; otherwise this is like lookupPort. */ -Port *PortList::createPort(u16 portno, u8 protocol) { - u16 mapped_portno; - u8 mapped_protocol; - - mapped_portno = portno; - mapped_protocol = protocol; - if (!mapPort(&mapped_portno, &mapped_protocol)) - return NULL; - - if (port_list[mapped_protocol][mapped_portno] == NULL) { - Port *p = new Port(); - p->portno = portno; - p->proto = protocol; - port_list[mapped_protocol][mapped_portno] = p; + 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: %s(%i,%i): this port was not mapped", __func__, portno, protocol); + return; } - - return port_list[mapped_protocol][mapped_portno]; -} - -int PortList::forgetPort(u16 portno, u8 protocol) { - Port *answer = NULL; - - log_write(LOG_PLAIN, "Removed %d\n", portno); - - if (!mapPort(&portno, &protocol)) - return -1; - - answer = port_list[protocol][portno]; - if (answer == NULL) - return -1; - - state_counts_proto[protocol][answer->state]--; - state_counts_proto[protocol][default_port_state[protocol].state]++; - - delete answer; - - port_list[protocol][portno] = NULL; - - if (o.verbose) { - log_write(LOG_STDOUT, "Deleting port %hu/%s, which we thought was %s\n", - portno, proto2ascii(answer->proto), - statenum2str(answer->state)); - log_flush(LOG_STDOUT); - } - - return 0; + + port_list[proto][mapped_pno] = port; } /* Just free memory used by PortList::port_map[]. Should be done somewhere * before closing nmap. */ void PortList::freePortMap(){ int proto; - for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) { + for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) if(port_map[proto]){ free(port_map[proto]); port_map[proto] = NULL; } - if (port_map_rev[proto]) { - free(port_map_rev[proto]); - port_map_rev[proto] = NULL; - } - } } u16 *PortList::port_map[PORTLIST_PROTO_MAX]; -u16 *PortList::port_map_rev[PORTLIST_PROTO_MAX]; int PortList::port_list_count[PORTLIST_PROTO_MAX]; /* This function must be runned before any PortList object is created. @@ -731,27 +636,38 @@ int PortList::port_list_count[PORTLIST_PROTO_MAX]; * 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 || port_map_rev[proto] != NULL) + if(port_map[proto]!=NULL) fatal("%s: portmap for protocol %i already initialized", __func__, 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); - port_map_rev[proto] = (u16 *) safe_zalloc(sizeof(u16) * portcount); + port_map[proto] = (u16*) safe_zalloc(sizeof(u16)*ports_max); - port_list_count[proto] = portcount; + /* 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++) { - port_map[proto][ports[i]] = i; - port_map_rev[proto][i] = ports[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[port_2,port_4,port_6] */ + * 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? :) */ } /* Cycles through the 0 or more "ignored" ports which should be @@ -845,26 +761,20 @@ int PortList::numIgnoredPorts() { return numports; } -int PortList::numPorts() const { - int proto, num = 0; - - for (proto = 0; proto < PORTLIST_PROTO_MAX; proto++) - num += port_list_count[proto]; - - return num; -} - int PortList::setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr) { Port *answer = NULL; + if(!(answer = getPortEntry(portno, proto))) + return -1; if(reason > ER_MAX) return -1; - answer = createPort(portno, proto); /* set new reason and increment its count */ answer->reason.reason_id = reason; answer->reason.ip_addr.s_addr = ip_addr; answer->reason.ttl = ttl; + answer->reason.state = answer->state; + setPortEntry(portno, proto, answer); return 0; } diff --git a/portlist.h b/portlist.h index 8985a49a7..42b6c5ab2 100644 --- a/portlist.h +++ b/portlist.h @@ -140,25 +140,25 @@ enum service_tunnel_type { SERVICE_TUNNEL_NONE, SERVICE_TUNNEL_SSL }; void random_port_cheat(u16 *ports, int portcount); struct serviceDeductions { - serviceDeductions(); - void populateFullVersionString(char *buf, size_t n) const; - - char *name; // will be NULL if can't determine + const char *name; // will be NULL if can't determine // Confidence is a number from 0 (least confident) to 10 (most // confident) expressing how accurate the service detection is // likely to be. int name_confidence; // Any of these 6 can be NULL if we weren't able to determine it - char *product; - char *version; - char *extrainfo; - char *hostname; - char *ostype; - char *devicetype; + const char *product; + const char *version; + const char *extrainfo; + const char *hostname; + const char *ostype; + const char *devicetype; // SERVICE_TUNNEL_NONE or SERVICE_TUNNEL_SSL enum service_tunnel_type service_tunnel; + // This is a combined representation of product, version, and extrainfo. + // It will be zero length if unavailable. + char fullversion[160]; // if we should give the user a service fingerprint to submit, here it is. Otherwise NULL. - char *service_fp; + const char *service_fp; enum service_detection_type dtype; // definition above int rpc_status; /* RPC_STATUS_UNTESTED means we haven't checked RPC_STATUS_UNKNOWN means the port appears to be RPC @@ -173,16 +173,42 @@ struct serviceDeductions { }; class Port { - friend class PortList; - public: Port(); ~Port(); - void getNmapServiceName(char *namebuf, int buflen) const; + + // pass in an allocated struct serviceDeductions (don't worry about initializing, and + // you don't have to free any internal ptrs. See the serviceDeductions definition for + // the fields that are populated. Returns 0 if at least a name is available. + int getServiceDeductions(struct serviceDeductions *sd); + + // sname should be NULL if sres is not + // PROBESTATE_FINISHED_MATCHED. product,version, and/or extrainfo + // will be NULL if unavailable. Note that this function makes its + // own copy of sname and product/version/extrainfo. This function + // also takes care of truncating the version strings to a + // 'reasonable' length if neccessary, and cleaning up any unprinable + // chars. (these tests are to avoid annoying DOS (or other) attacks + // by malicious services). The fingerprint should be NULL unless + // one is available and the user should submit it. tunnel must be + // SERVICE_TUNNEL_NULL (normal) or SERVICE_TUNNEL_SSL (means ssl was + // detected and we tried to tunnel through it ). + void setServiceProbeResults(enum serviceprobestate sres, const char *sname, + enum service_tunnel_type tunnel, const char *product, + const char *version, const char *hostname, + const char *ostype, const char *devicetype, + const char *extrainfo, const char *fingerprint); + + /* Sets the results of an RPC scan. if rpc_status is not + RPC_STATUS_GOOD_PROGRAM, pass 0 for the other args. This function + takes care of setting the port's service and version + appropriately. */ + void setRPCProbeResults(int rpc_status, unsigned long rpc_program, + unsigned int rpc_lowver, unsigned int rpc_highver); u16 portno; u8 proto; - u8 state; + int state; state_reason_t reason; #ifndef NOLUA @@ -190,10 +216,28 @@ class Port { #endif private: - /* This is allocated only on demand by PortList::setServiceProbeResults or - PortList::setRPCProbeResults, to save memory for the many closed or - filtered ports that don't need it. */ - serviceDeductions *service; + int rpc_status; /* RPC_STATUS_UNTESTED means we haven't checked + RPC_STATUS_UNKNOWN means the port appears to be RPC + but we couldn't find a match + RPC_STATUS_GOOD_PROG means rpc_program gives the prog # + RPC_STATUS_NOT_RPC means the port doesn't appear to + be RPC */ + unsigned long rpc_program; /* Only valid if rpc_state == RPC_STATUS_GOOD_PROG */ + unsigned int rpc_lowver; + unsigned int rpc_highver; + enum serviceprobestate serviceprobe_results; // overall results of service scan + char *serviceprobe_service; // If a service was discovered, points to the name + // Any of these next three can be NULL if the details are not available + char *serviceprobe_product; + char *serviceprobe_version; + char *serviceprobe_extrainfo; + char *serviceprobe_hostname; + char *serviceprobe_ostype; + char *serviceprobe_devicetype; + enum service_tunnel_type serviceprobe_tunnel; + // A fingerprint that the user can submit if the service wasn't recognized + char *serviceprobe_fp; + }; @@ -217,10 +261,10 @@ class PortList { /* Free memory used by port_map. It should be done somewhere before quitting*/ static void freePortMap(); - void setDefaultPortState(u8 protocol, int state); - void setPortState(u16 portno, u8 protocol, int state); - int getPortState(u16 portno, u8 protocol); - int forgetPort(u16 portno, u8 protocol); + /* Add a new port to this list. If the state has changed, it is + OK to call this function to effect the change */ + int addPort(u16 portno, u8 protocol, int state); + int removePort(u16 portno, u8 protocol); /* Saves an identification string for the target containing these ports (an IP addrss might be a good example, but set what you want). Only used when printing new port updates. Optional. A @@ -236,11 +280,17 @@ class PortList { function returns ports in numeric order from lowest to highest, except that if you ask for TCP, UDP & SCTP, all TCP ports will be returned before we start returning UDP and finally SCTP ports */ - Port *nextPort(const Port *cur, Port *next, - int allowed_protocol, int allowed_state); + Port *nextPort(Port *afterthisport, + int allowed_protocol, int allowed_state); + + /* 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 setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr); + int numports; /* Total number of ports in list in ANY state */ int numscriptresults; /* Total number of scripts which produced output */ /* Get number of ports in this state. This a sum for protocols. */ @@ -248,38 +298,6 @@ class PortList { /* Get number of ports in this state for requested protocol. */ int getStateCounts(int protocol, int state); - // sname should be NULL if sres is not - // PROBESTATE_FINISHED_MATCHED. product,version, and/or extrainfo - // will be NULL if unavailable. Note that this function makes its - // own copy of sname and product/version/extrainfo. This function - // also takes care of truncating the version strings to a - // 'reasonable' length if neccessary, and cleaning up any unprinable - // chars. (these tests are to avoid annoying DOS (or other) attacks - // by malicious services). The fingerprint should be NULL unless - // one is available and the user should submit it. tunnel must be - // SERVICE_TUNNEL_NULL (normal) or SERVICE_TUNNEL_SSL (means ssl was - // detected and we tried to tunnel through it ). - void setServiceProbeResults(u16 portno, int protocol, - enum serviceprobestate sres, const char *sname, - enum service_tunnel_type tunnel, const char *product, - const char *version, const char *hostname, - const char *ostype, const char *devicetype, - const char *extrainfo, const char *fingerprint); - - // pass in an allocated struct serviceDeductions (don't worry about initializing, and - // you don't have to free any internal ptrs. See the serviceDeductions definition for - // the fields that are populated. Returns 0 if at least a name is available. - const void getServiceDeductions(u16 portno, int protocol, struct serviceDeductions *sd) const; - - /* Sets the results of an RPC scan. if rpc_status is not - RPC_STATUS_GOOD_PROGRAM, pass 0 for the other args. This function - takes care of setting the port's service and version - appropriately. */ - void setRPCProbeResults(u16 portno, int proto, int rpc_status, unsigned long rpc_program, - unsigned int rpc_lowver, unsigned int rpc_highver); - - void addScriptResult(u16 portno, int protocol, ScriptResult& sr); - /* Cycles through the 0 or more "ignored" ports which should be consolidated for Nmap output. They are returned sorted by the number of prots in the state, starting with the most common. It @@ -295,20 +313,12 @@ class PortList { int numIgnoredStates(); int numIgnoredPorts(); - int numPorts() const; private: - bool mapPort(u16 *portno, u8 *protocol) const; - /* Get Port structure from PortList structure.*/ - const Port *lookupPort(u16 portno, u8 protocol) const; - Port *createPort(u16 portno, u8 protocol); - /* Set Port structure to PortList structure.*/ - void setPortEntry(u16 portno, u8 protocol, Port *port); - /* A string identifying the system these ports are on. Just used for printing open ports, if it is set with setIdStr() */ char *idstr; - /* Number of ports in each state per each protocol. */ + /* 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: @@ -316,10 +326,8 @@ class PortList { * Only functions: getPortEntry, setPortEntry, initializePortMap and * nextPort should access this structure directly. */ static u16 *port_map[PORTLIST_PROTO_MAX]; - static u16 *port_map_rev[PORTLIST_PROTO_MAX]; /* Number of allocated elements in port_list per each protocol. */ static int port_list_count[PORTLIST_PROTO_MAX]; - Port default_port_state[PORTLIST_PROTO_MAX]; }; #endif diff --git a/portreasons.cc b/portreasons.cc index 720abb78e..496f2c893 100644 --- a/portreasons.cc +++ b/portreasons.cc @@ -246,7 +246,6 @@ static int update_state_summary(state_reason_summary_t *head, reason_t reason_id * state_reason_summary structures using update_state_summary */ static unsigned int get_state_summary(state_reason_summary_t *head, PortList *Ports, int state) { Port *current = NULL; - Port port; state_reason_summary_t *reason; unsigned int total = 0; unsigned short proto = (o.ipprotscan) ? IPPROTO_IP : TCPANDUDPANDSCTP; @@ -255,7 +254,7 @@ static unsigned int get_state_summary(state_reason_summary_t *head, PortList *Po return 0; reason = head; - while((current = Ports->nextPort(current, &port, proto, state)) != NULL) { + while((current = Ports->nextPort(current, proto, state)) != NULL) { if(Ports->isIgnoredState(current->state)) { total++; update_state_summary(reason, current->reason.reason_id); diff --git a/portreasons.h b/portreasons.h index f0a87d970..0aef1f0ef 100644 --- a/portreasons.h +++ b/portreasons.h @@ -114,6 +114,7 @@ typedef struct port_reason { reason_t reason_id; struct in_addr ip_addr; unsigned short ttl; + int state; } state_reason_t; /* used to calculate state reason summaries. diff --git a/scan_engine.cc b/scan_engine.cc index acd0f78bd..12998c8d0 100644 --- a/scan_engine.cc +++ b/scan_engine.cc @@ -1103,6 +1103,33 @@ static bool pingprobe_is_appropriate(const UltraScanInfo *USI, return false; } +/* For the given scan type, this returns the port/host state demonstrated + by getting no response back */ +static int scantype_no_response_means(stype scantype) { + switch(scantype) { + case SYN_SCAN: + case ACK_SCAN: + case WINDOW_SCAN: + case CONNECT_SCAN: + case SCTP_INIT_SCAN: + return PORT_FILTERED; + case UDP_SCAN: + case IPPROT_SCAN: + case NULL_SCAN: + case FIN_SCAN: + case MAIMON_SCAN: + case XMAS_SCAN: + case SCTP_COOKIE_ECHO_SCAN: + return PORT_OPENFILTERED; + case PING_SCAN: + case PING_SCAN_ARP: + return HOST_DOWN; + default: + fatal("Unexpected scan type found in %s()", __func__); + } + return 0; /* Unreached */ +} + HostScanStats::HostScanStats(Target *t, UltraScanInfo *UltraSI) { target = t; USI=UltraSI; @@ -1470,46 +1497,6 @@ static void init_perf_values(struct ultra_scan_performance_vars *perf) { perf->tryno_cap = o.getMaxRetransmissions(); } -/* Initialize the state for ports that don't receive a response in all the - targets. */ -static void set_default_port_state(vector &targets, stype scantype) { - vector::iterator target; - - for (target = targets.begin(); target != targets.end(); target++) { - switch (scantype) { - case SYN_SCAN: - case ACK_SCAN: - case WINDOW_SCAN: - case CONNECT_SCAN: - (*target)->ports.setDefaultPortState(IPPROTO_TCP, PORT_FILTERED); - break; - case SCTP_INIT_SCAN: - (*target)->ports.setDefaultPortState(IPPROTO_SCTP, PORT_FILTERED); - break; - case NULL_SCAN: - case FIN_SCAN: - case MAIMON_SCAN: - case XMAS_SCAN: - (*target)->ports.setDefaultPortState(IPPROTO_TCP, PORT_OPENFILTERED); - break; - case UDP_SCAN: - (*target)->ports.setDefaultPortState(IPPROTO_UDP, PORT_OPENFILTERED); - break; - case IPPROT_SCAN: - (*target)->ports.setDefaultPortState(IPPROTO_IP, PORT_OPENFILTERED); - break; - case SCTP_COOKIE_ECHO_SCAN: - (*target)->ports.setDefaultPortState(IPPROTO_SCTP, PORT_OPENFILTERED); - break; - case PING_SCAN: - case PING_SCAN_ARP: - break; - default: - fatal("Unexpected scan type found in %s()", __func__); - } - } -} - /* Order of initializations in this function CAN BE IMPORTANT, so be careful mucking with it. */ void UltraScanInfo::Init(vector &Targets, struct scan_lists *pts, stype scantp) { @@ -1580,8 +1567,6 @@ void UltraScanInfo::Init(vector &Targets, struct scan_lists *pts, styp break; } - set_default_port_state(Targets, scantype); - init_perf_values(&perf); /* Keep a completed host around for a standard TCP MSL (2 min) */ @@ -2613,6 +2598,7 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI, u16 portno = 0; u8 proto = 0; int oldstate = PORT_TESTING; + Port *currentp; /* Whether no response means a port is open */ bool noresp_open_scan = USI->noresp_open_scan; @@ -2630,11 +2616,13 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI, portno = pspec->pd.sctp.dport; } else assert(0); - oldstate = hss->target->ports.getPortState(portno, proto); - if (oldstate == -1) { + /* First figure out the current state */ + currentp = hss->target->ports.getPortEntry(portno, proto); + if (!currentp) { oldstate = PORT_TESTING; hss->ports_finished++; } + else oldstate = currentp->state; /* printf("TCP port %hu has changed from state %s to %s!\n", portno, statenum2str(oldstate), statenum2str(newstate)); */ switch(oldstate) { @@ -2643,25 +2631,25 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI, in a SYN scan, but not neccessarily for UDP scan */ case PORT_TESTING: /* Brand new port -- add it to the list */ - hss->target->ports.setPortState(portno, proto, newstate); + hss->target->ports.addPort(portno, proto, newstate); break; case PORT_OPEN: if (newstate != PORT_OPEN) { if (noresp_open_scan) { - hss->target->ports.setPortState(portno, proto, newstate); + hss->target->ports.addPort(portno, proto, newstate); } /* Otherwise The old open takes precendence */ } break; case PORT_CLOSED: if (newstate != PORT_CLOSED) { if (!noresp_open_scan && newstate != PORT_FILTERED) - hss->target->ports.setPortState(portno, proto, newstate); + hss->target->ports.addPort(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); + hss->target->ports.addPort(portno, proto, newstate); } break; case PORT_UNFILTERED: @@ -2670,11 +2658,11 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI, 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); + hss->target->ports.addPort(portno, proto, newstate); break; case PORT_OPENFILTERED: if (newstate != PORT_OPENFILTERED) { - hss->target->ports.setPortState(portno, proto, newstate); + hss->target->ports.addPort(portno, proto, newstate); } break; default: @@ -2712,16 +2700,18 @@ void HostScanStats::boostScanDelay() { sdn.goodRespSinceDelayChanged = 0; } -/* Dismiss all probe attempts on bench -- hosts are marked down and ports will - be set to whatever the default port state is for the scan. */ +/* Dismiss all probe attempts on bench -- the ports are marked + 'filtered' or whatever is appropriate for having no response */ void HostScanStats::dismissBench() { + int newstate; + if (probe_bench.empty()) return; + newstate = scantype_no_response_means(USI->scantype); while(!probe_bench.empty()) { if (USI->ping_scan) - ultrascan_host_pspec_update(USI, this, &probe_bench.back(), HOST_DOWN); - /* Nothing to do if !USI->ping_scan. ultrascan_port_pspec_update would - allocate a Port object but we rely on the default port state to save - memory. */ + ultrascan_host_pspec_update(USI, this, &probe_bench.back(), newstate); + else + ultrascan_port_pspec_update(USI, this, &probe_bench.back(), newstate); probe_bench.pop_back(); } bench_tryno = 0; @@ -2729,6 +2719,7 @@ void HostScanStats::dismissBench() { /* Move all members of bench to retry_stack for probe retransmission */ void HostScanStats::retransmitBench() { + int newstate; if (probe_bench.empty()) return; /* Move all contents of probe_bench to the end of retry_stack, updating retry_stack_tries accordingly */ @@ -2737,6 +2728,7 @@ void HostScanStats::retransmitBench() { bench_tryno); assert(retry_stack.size() == retry_stack_tries.size()); probe_bench.erase(probe_bench.begin(), probe_bench.end()); + newstate = scantype_no_response_means(USI->scantype); bench_tryno = 0; } @@ -4937,6 +4929,7 @@ static void processData(UltraScanInfo *USI) { list::iterator probeI, nextProbeI; HostScanStats *host = NULL; UltraProbe *probe = NULL; + int newstate; unsigned int maxtries = 0; bool scanmaybedone = true; /* The whole scan is not yet done */ int expire_us = 0; @@ -5002,20 +4995,19 @@ static void processData(UltraScanInfo *USI) { if (!probe->isPing() && probe->timedout && !probe->retransmitted) { if (!tryno_mayincrease && probe->tryno >= maxtries) { + newstate = scantype_no_response_means(USI->scantype); + if (USI->ping_scan) + ultrascan_host_probe_update(USI, host, probeI, newstate, NULL); + else + ultrascan_port_probe_update(USI, host, probeI, newstate, NULL); + if (host->target->reason.reason_id == ER_UNKNOWN) + host->target->reason.reason_id = ER_NORESPONSE; if (tryno_capped && !host->retry_capped_warned) { log_write(LOG_PLAIN, "Warning: %s giving up on port because" " retransmission cap hit (%d).\n", host->target->targetipstr(), probe->tryno); host->retry_capped_warned = true; } - if (USI->ping_scan) { - ultrascan_host_probe_update(USI, host, probeI, HOST_DOWN, NULL); - } else { - /* No ultrascan_port_probe_update because that allocates a Port - object; the default port state as set by setDefaultPortState - handles these no-response ports. */ - host->destroyOutstandingProbe(probeI); - } continue; } else if (probe->tryno >= maxtries && TIMEVAL_SUBTRACT(USI->now, probe->sent) > expire_us) { @@ -5266,8 +5258,8 @@ void bounce_scan(Target *target, u16 *portarray, int numports, perror("recv problem from FTP bounce server"); } else if (res == 0) { if (timedout) - target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_FILTERED); - else target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_CLOSED); + target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_FILTERED); + else target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_CLOSED); } else { recvbuf[res] = '\0'; if (o.debugging) log_write(LOG_STDOUT, "result of LIST: %s", recvbuf); @@ -5278,7 +5270,7 @@ void bounce_scan(Target *target, u16 *portarray, int numports, res = recvtime(sd, recvbuf, 2048,10, NULL); } if (recvbuf[0] == '1' || recvbuf[0] == '2') { - target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_OPEN); + target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_OPEN); if (recvbuf[0] == '1') { res = recvtime(sd, recvbuf, 2048,5, NULL); if (res < 0) @@ -5289,7 +5281,7 @@ void bounce_scan(Target *target, u16 *portarray, int numports, if (o.debugging) log_write(LOG_STDOUT, "nxt line: %s", recvbuf); if (recvbuf[0] == '4' && recvbuf[1] == '2' && recvbuf[2] == '6') { - target->ports.forgetPort(portarray[i], IPPROTO_TCP); + target->ports.removePort(portarray[i], IPPROTO_TCP); if (o.debugging || o.verbose) log_write(LOG_STDOUT, "Changed my mind about port %i\n", portarray[i]); } @@ -5298,7 +5290,7 @@ void bounce_scan(Target *target, u16 *portarray, int numports, } } else { /* This means the port is closed ... */ - target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_CLOSED); + target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_CLOSED); } } } @@ -5370,7 +5362,6 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) { unsigned long j; struct serviceDeductions sd; bool doingOpenFiltered = false; - Port port; ScanProgressMeter *SPM = NULL; @@ -5443,11 +5434,11 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) { while(1) { if (doingOpenFiltered) { rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port, - &port, TCPANDUDPANDSCTP, + TCPANDUDPANDSCTP, PORT_OPENFILTERED); } else { rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port, - &port, TCPANDUDPANDSCTP, + TCPANDUDPANDSCTP, PORT_OPEN); if (!rsi.rpc_current_port && !o.servicescan) { doingOpenFiltered = true; @@ -5461,7 +5452,7 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) { break; // We do all open ports if no service scan if (!rsi.rpc_current_port) break; // done! - target->ports.getServiceDeductions(rsi.rpc_current_port->portno, rsi.rpc_current_port->proto, &sd); + rsi.rpc_current_port->getServiceDeductions(&sd); if (sd.name && sd.service_tunnel == SERVICE_TUNNEL_NONE && strcmp(sd.name, "rpcbind") == 0) break; // Good - an RPC port for us to scan. @@ -5603,8 +5594,7 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) { /* Now we figure out the results of the port we just RPC scanned */ - target->ports.setRPCProbeResults(rsi.rpc_current_port->portno, rsi.rpc_current_port->proto, - rsi.rpc_status, rsi.rpc_program, + rsi.rpc_current_port->setRPCProbeResults(rsi.rpc_status, rsi.rpc_program, rsi.rpc_lowver, rsi.rpc_highver); /* Time to put our RPC program scan list back together for the diff --git a/service_scan.cc b/service_scan.cc index 877048162..2c4e00312 100644 --- a/service_scan.cc +++ b/service_scan.cc @@ -149,6 +149,7 @@ public: // Note that the next 2 members are for convenience and are not destroyed w/the ServiceNFO Target *target; // the port belongs to this target host + Port *port; // The Port that this service represents (this copy is taken from inside Target) // if a match is found, it is placed here. Otherwise NULL const char *probe_matched; // If a match is found, any product/version/info/hostname/ostype/devicetype @@ -1338,6 +1339,7 @@ ServiceNFO::ServiceNFO(AllProbes *newAP) { AP = newAP; currentresp = NULL; currentresplen = 0; + port = NULL; product_matched[0] = version_matched[0] = extrainfo_matched[0] = '\0'; hostname_matched[0] = ostype_matched[0] = devicetype_matched[0] = '\0'; tunnel = SERVICE_TUNNEL_NONE; @@ -1631,7 +1633,6 @@ ServiceGroup::ServiceGroup(vector &Targets, AllProbes *AP) { unsigned int targetno; ServiceNFO *svc; Port *nxtport; - Port port; int desired_par; struct timeval now; num_hosts_timedout = 0; @@ -1643,11 +1644,12 @@ ServiceGroup::ServiceGroup(vector &Targets, AllProbes *AP) { num_hosts_timedout++; continue; } - while((nxtport = Targets[targetno]->ports.nextPort(nxtport, &port, TCPANDUDPANDSCTP, PORT_OPEN))) { + while((nxtport = Targets[targetno]->ports.nextPort(nxtport, TCPANDUDPANDSCTP, PORT_OPEN))) { svc = new ServiceNFO(AP); svc->target = Targets[targetno]; svc->portno = nxtport->portno; svc->proto = nxtport->proto; + svc->port = nxtport; services_remaining.push_back(svc); } } @@ -1660,11 +1662,12 @@ ServiceGroup::ServiceGroup(vector &Targets, AllProbes *AP) { if (Targets[targetno]->timedOut(&now)) { continue; } - while((nxtport = Targets[targetno]->ports.nextPort(nxtport, &port, TCPANDUDPANDSCTP, PORT_OPENFILTERED))) { + while((nxtport = Targets[targetno]->ports.nextPort(nxtport, TCPANDUDPANDSCTP, PORT_OPENFILTERED))) { svc = new ServiceNFO(AP); svc->target = Targets[targetno]; svc->portno = nxtport->portno; svc->proto = nxtport->proto; + svc->port = nxtport; services_remaining.push_back(svc); } } @@ -1700,8 +1703,8 @@ static void adjustPortStateIfNeccessary(ServiceNFO *svc) { char host[128]; - if (svc->target->ports.getPortState(svc->portno, svc->proto) == PORT_OPENFILTERED) { - svc->target->ports.setPortState(svc->portno, svc->proto, PORT_OPEN); + if (svc->port->state == PORT_OPENFILTERED) { + svc->target->ports.addPort(svc->portno, svc->proto, PORT_OPEN); if (svc->proto == IPPROTO_TCP) svc->target->ports.setStateReason(svc->portno, svc->proto, ER_TCPRESPONSE, 0, 0); if (svc->proto == IPPROTO_UDP) @@ -2315,8 +2318,7 @@ list::iterator svc; for(svc = SG->services_finished.begin(); svc != SG->services_finished.end(); svc++) { if ((*svc)->probe_state != PROBESTATE_FINISHED_NOMATCH) { - (*svc)->target->ports.setServiceProbeResults((*svc)->portno, (*svc)->proto, - (*svc)->probe_state, + (*svc)->port->setServiceProbeResults((*svc)->probe_state, (*svc)->probe_matched, (*svc)->tunnel, *(*svc)->product_matched? (*svc)->product_matched : NULL, @@ -2327,8 +2329,7 @@ list::iterator svc; *(*svc)->devicetype_matched? (*svc)->devicetype_matched : NULL, shouldWePrintFingerprint(*svc) ? (*svc)->getServiceFingerprint(NULL) : NULL); } else { - (*svc)->target->ports.setServiceProbeResults((*svc)->portno, (*svc)->proto, - (*svc)->probe_state, NULL, + (*svc)->port->setServiceProbeResults((*svc)->probe_state, NULL, (*svc)->tunnel, NULL, NULL, NULL, NULL, NULL, NULL, (*svc)->getServiceFingerprint(NULL)); } @@ -2371,8 +2372,7 @@ static void remove_excluded_ports(AllProbes *AP, ServiceGroup *SG) { if (o.debugging) log_write(LOG_PLAIN, "EXCLUDING %d/%s\n", svc->portno, IPPROTO2STR(svc->proto)); - svc->target->ports.setServiceProbeResults(svc->portno, svc->proto, - PROBESTATE_EXCLUDED, NULL, + svc->port->setServiceProbeResults(PROBESTATE_EXCLUDED, NULL, SERVICE_TUNNEL_NONE, "Excluded from version scan", NULL, NULL, NULL, NULL, NULL, NULL);