1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 12:41:29 +00:00

Merge from /nmap-exp/david/nmap-mem. This brings in two memory-reducing

changes. The first is that Port objects don't allocate memory for
service and RPC results unless that information is set. This reduces the
size of a bare Port from 92 to 40 bytes on my machine. The second change
is that PortList now has the notion of a "default port state," which is
the state of any ports that didn't receive a response. These ports don't
need an allocated Port object, which saves a lot of memory in scans
where most ports didn't get a response.
This commit is contained in:
david
2009-12-19 21:26:14 +00:00
parent 9f0e11f035
commit b838242e01
15 changed files with 593 additions and 517 deletions

View File

@@ -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, /* If our first count erroneously found and added an open port,
we must delete it */ we must delete it */
if (firstHalfSz == 1 && flatcount1 == 1 && retrycount == 0) if (firstHalfSz == 1 && flatcount1 == 1 && retrycount == 0)
target->ports.removePort(ports[0], IPPROTO_TCP); target->ports.forgetPort(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, /* If our first count erroneously found and added an open port,
we must delete it */ we must delete it */
if (secondHalfSz == 1 && flatcount2 == 1 && retrycount == 0) if (secondHalfSz == 1 && flatcount2 == 1 && retrycount == 0)
target->ports.removePort(ports[firstHalfSz], IPPROTO_TCP); target->ports.forgetPort(ports[firstHalfSz], IPPROTO_TCP);
} }
@@ -960,10 +960,10 @@ static int idle_treescan(struct idle_proxy_info *proxy, Target *target,
} }
if (firstHalfSz == 1 && flatcount1 == 1) if (firstHalfSz == 1 && flatcount1 == 1)
target->ports.addPort(ports[0], IPPROTO_TCP, PORT_OPEN); target->ports.setPortState(ports[0], IPPROTO_TCP, PORT_OPEN);
if ((secondHalfSz == 1) && flatcount2 == 1) if ((secondHalfSz == 1) && flatcount2 == 1)
target->ports.addPort(ports[firstHalfSz], IPPROTO_TCP, PORT_OPEN); target->ports.setPortState(ports[firstHalfSz], IPPROTO_TCP, PORT_OPEN);
return totalfound; 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 /* Now we go through the ports which were scanned but not determined
to be open, and add them in the "closed" state */ 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.getPortEntry(portarray[portidx], IPPROTO_TCP) == NULL) { if (target->ports.getPortState(portarray[portidx], IPPROTO_TCP) == -1) {
target->ports.addPort(portarray[portidx], IPPROTO_TCP, PORT_CLOSEDFILTERED); target->ports.setPortState(portarray[portidx], IPPROTO_TCP, PORT_CLOSEDFILTERED);
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_NOIPIDCHANGE, 0, 0); target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_NOIPIDCHANGE, 0, 0);
} else } else
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_IPIDCHANGE, 0, 0); target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_IPIDCHANGE, 0, 0);

View File

@@ -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) { if (rsi->rpc_current_port->state == PORT_OPENFILTERED) {
/* Received a packet, so this port is actually open */ /* Received a packet, so this port is actually open */
target->ports.addPort(rsi->rpc_current_port->portno, target->ports.setPortState(rsi->rpc_current_port->portno,
rsi->rpc_current_port->proto, PORT_OPEN); rsi->rpc_current_port->proto, PORT_OPEN);
} }

View File

@@ -147,7 +147,7 @@ struct rpc_info {
}; };
struct rpcscaninfo { struct rpcscaninfo {
Port *rpc_current_port; const Port *rpc_current_port;
unsigned long *rpc_progs; unsigned long *rpc_progs;
unsigned long rpc_number; unsigned long rpc_number;
int valid_responses_this_port; /* Number of valid (RPC wise) responses we int valid_responses_this_port; /* Number of valid (RPC wise) responses we

View File

@@ -82,13 +82,14 @@ static int ports (lua_State *L)
Target *target = get_target(L, 1); Target *target = get_target(L, 1);
PortList *plist = &(target->ports); PortList *plist = &(target->ports);
Port *current = NULL; Port *current = NULL;
Port port;
lua_newtable(L); lua_newtable(L);
for (int i = 0; states[i] != PORT_HIGHEST_STATE; i++) for (int i = 0; states[i] != PORT_HIGHEST_STATE; i++)
while ((current = plist->nextPort(current, TCPANDUDPANDSCTP, while ((current = plist->nextPort(current, &port, TCPANDUDPANDSCTP,
states[i])) != NULL) states[i])) != NULL)
{ {
lua_newtable(L); lua_newtable(L);
set_portinfo(L, current); set_portinfo(L, target, current);
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
lua_rawset(L, -3); lua_rawset(L, -3);
} }
@@ -112,10 +113,10 @@ static int port_set_output (lua_State *L)
{ {
ScriptResult sr; ScriptResult sr;
Target *target = get_target(L, 1); Target *target = get_target(L, 1);
Port *port = get_port(L, target, 2); const Port *port = get_port(L, target, 2);
sr.set_id(luaL_checkstring(L, 3)); sr.set_id(luaL_checkstring(L, 3));
sr.set_output(luaL_checkstring(L, 4)); sr.set_output(luaL_checkstring(L, 4));
port->scriptResults.push_back(sr); target->ports.addScriptResult(port->portno, port->proto, sr);
/* increment host port script results*/ /* increment host port script results*/
target->ports.numscriptresults++; target->ports.numscriptresults++;
return 0; return 0;
@@ -247,7 +248,7 @@ void ScriptResult::set_output (const char *out)
output = std::string(out); output = std::string(out);
} }
std::string ScriptResult::get_output (void) std::string ScriptResult::get_output (void) const
{ {
return output; return output;
} }
@@ -257,7 +258,7 @@ void ScriptResult::set_id (const char *ident)
id = std::string(ident); id = std::string(ident);
} }
std::string ScriptResult::get_id (void) std::string ScriptResult::get_id (void) const
{ {
return id; return id;
} }

View File

@@ -20,9 +20,9 @@ class ScriptResult
std::string id; std::string id;
public: public:
void set_output (const char *); void set_output (const char *);
std::string get_output (void); std::string get_output (void) const;
void set_id (const char *); void set_id (const char *);
std::string get_id (void); std::string get_id (void) const;
}; };
typedef std::vector<ScriptResult> ScriptResults; typedef std::vector<ScriptResult> ScriptResults;

View File

@@ -28,20 +28,20 @@ extern "C" {
extern NmapOps o; extern NmapOps o;
void set_version(lua_State *L, struct serviceDeductions sd) { void set_version(lua_State *L, const struct serviceDeductions *sd) {
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.name, "name"); 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"); lua_setfield(L, -2, "name_confidence");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.product, "product"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->product, "product");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.version, "version"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->version, "version");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.extrainfo, "extrainfo"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->extrainfo, "extrainfo");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.hostname, "hostname"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->hostname, "hostname");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.ostype, "ostype"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->ostype, "ostype");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.devicetype, "devicetype"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->devicetype, "devicetype");
switch(sd.service_tunnel) { switch(sd->service_tunnel) {
case(SERVICE_TUNNEL_NONE): case(SERVICE_TUNNEL_NONE):
SCRIPT_ENGINE_PUSHSTRING_NOTNULL("none", "service_tunnel"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL("none", "service_tunnel");
break; break;
@@ -54,9 +54,9 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
break; 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): case(SERVICE_DETECTION_TABLE):
SCRIPT_ENGINE_PUSHSTRING_NOTNULL("table", "service_fp"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL("table", "service_fp");
break; break;
@@ -69,7 +69,7 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
break; break;
} }
switch(sd.rpc_status) { switch(sd->rpc_status) {
case(RPC_STATUS_UNTESTED): case(RPC_STATUS_UNTESTED):
SCRIPT_ENGINE_PUSHSTRING_NOTNULL("untested", "rpc_status"); SCRIPT_ENGINE_PUSHSTRING_NOTNULL("untested", "rpc_status");
break; break;
@@ -88,14 +88,14 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
break; break;
} }
if(sd.rpc_status == RPC_STATUS_GOOD_PROG) { if(sd->rpc_status == RPC_STATUS_GOOD_PROG) {
lua_pushnumber(L, sd.rpc_program); lua_pushnumber(L, sd->rpc_program);
lua_setfield(L, -2, "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_setfield(L, -2, "rpc_lowver");
lua_pushnumber(L, sd.rpc_highver); lua_pushnumber(L, sd->rpc_highver);
lua_setfield(L, -2, "rpc_highver"); lua_setfield(L, -2, "rpc_highver");
} }
} }
@@ -103,24 +103,26 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
/* set some port state information onto the /* set some port state information onto the
* table which is currently on the stack * table which is currently on the stack
* */ * */
void set_portinfo(lua_State *L, Port* port) { void set_portinfo(lua_State *L, const Target *target, const Port *port) {
struct serviceDeductions sd; struct serviceDeductions sd;
port->getServiceDeductions(&sd); target->ports.getServiceDeductions(port->portno, port->proto, &sd);
lua_pushnumber(L, (double) port->portno); lua_pushnumber(L, (double) port->portno);
lua_setfield(L, -2, "number"); lua_setfield(L, -2, "number");
if (sd.name != NULL) {
lua_pushstring(L, sd.name); lua_pushstring(L, sd.name);
lua_setfield(L, -2, "service"); lua_setfield(L, -2, "service");
}
lua_newtable(L);
set_version(L, &sd);
lua_setfield(L, -2, "version");
lua_pushstring(L, IPPROTO2STR(port->proto)); lua_pushstring(L, IPPROTO2STR(port->proto));
lua_setfield(L, -2, "protocol"); lua_setfield(L, -2, "protocol");
lua_newtable(L);
set_version(L, sd);
lua_setfield(L, -2, "version");
lua_pushstring(L, statenum2str(port->state)); lua_pushstring(L, statenum2str(port->state));
lua_setfield(L, -2, "state"); lua_setfield(L, -2, "state");
@@ -419,9 +421,10 @@ done:
return target; return target;
} }
Port *get_port (lua_State *L, Target *target, int index) const Port *get_port (lua_State *L, Target *target, int index)
{ {
Port *port = NULL; Port *p = NULL;
Port port;
int portno, protocol; int portno, protocol;
luaL_checktype(L, index, LUA_TTABLE); luaL_checktype(L, index, LUA_TTABLE);
lua_getfield(L, index, "number"); lua_getfield(L, index, "number");
@@ -435,11 +438,11 @@ Port *get_port (lua_State *L, Target *target, int index)
strcmp(lua_tostring(L, -1), "udp") == 0 ? IPPROTO_UDP : strcmp(lua_tostring(L, -1), "udp") == 0 ? IPPROTO_UDP :
strcmp(lua_tostring(L, -1), "sctp") == 0 ? IPPROTO_SCTP : strcmp(lua_tostring(L, -1), "sctp") == 0 ? IPPROTO_SCTP :
luaL_error(L, "port 'protocol' field must be \"udp\", \"sctp\" or \"tcp\""); luaL_error(L, "port 'protocol' field must be \"udp\", \"sctp\" or \"tcp\"");
while ((port = target->ports.nextPort(port, protocol, PORT_UNKNOWN)) != NULL) while ((p = target->ports.nextPort(p, &port, protocol, PORT_UNKNOWN)) != NULL)
if (port->portno == portno) if (p->portno == portno)
break; break;
lua_pop(L, 2); lua_pop(L, 2);
return port; return p;
} }
/* this function can be called from lua to obtain the port state /* this function can be called from lua to obtain the port state
@@ -455,7 +458,7 @@ Port *get_port (lua_State *L, Target *target, int index)
static int l_get_port_state (lua_State *L) static int l_get_port_state (lua_State *L)
{ {
Target *target; Target *target;
Port *port; const Port *port;
target = get_target(L, 1); target = get_target(L, 1);
port = get_port(L, target, 2); port = get_port(L, target, 2);
if (port == NULL) if (port == NULL)
@@ -463,7 +466,7 @@ static int l_get_port_state (lua_State *L)
else else
{ {
lua_newtable(L); lua_newtable(L);
set_portinfo(L, port); set_portinfo(L, target, port);
} }
return 1; return 1;
} }
@@ -477,7 +480,7 @@ static int l_set_port_state (lua_State *L)
static const int opstate[] = {PORT_OPEN, PORT_CLOSED}; static const int opstate[] = {PORT_OPEN, PORT_CLOSED};
static const char *op[] = {"open", "closed", NULL}; static const char *op[] = {"open", "closed", NULL};
Target *target; Target *target;
Port *port; const Port *port;
target = get_target(L, 1); target = get_target(L, 1);
if ((port = get_port(L, target, 2)) != NULL) if ((port = get_port(L, target, 2)) != NULL)
{ {
@@ -486,17 +489,15 @@ static int l_set_port_state (lua_State *L)
case PORT_OPEN: case PORT_OPEN:
if (port->state == PORT_OPEN) if (port->state == PORT_OPEN)
return 0; return 0;
target->ports.addPort(port->portno, port->proto, PORT_OPEN); target->ports.setPortState(port->portno, port->proto, PORT_OPEN);
port->state = PORT_OPEN;
break; break;
case PORT_CLOSED: case PORT_CLOSED:
if (port->state == PORT_CLOSED) if (port->state == PORT_CLOSED)
return 0; return 0;
target->ports.addPort(port->portno, port->proto, PORT_CLOSED); target->ports.setPortState(port->portno, port->proto, PORT_CLOSED);
port->state = PORT_CLOSED;
break; break;
} }
port->reason.reason_id = ER_SCRIPT; target->ports.setStateReason(port->portno, port->proto, ER_SCRIPT, 0, 0);
} }
return 0; return 0;
} }
@@ -518,7 +519,7 @@ static int l_set_port_version (lua_State *L)
"incomplete" "incomplete"
}; };
Target *target; Target *target;
Port *port; const Port *port;
enum service_tunnel_type tunnel = SERVICE_TUNNEL_NONE; enum service_tunnel_type tunnel = SERVICE_TUNNEL_NONE;
enum serviceprobestate probestate = enum serviceprobestate probestate =
opversion[luaL_checkoption(L, 3, "hardmatched", ops)]; opversion[luaL_checkoption(L, 3, "hardmatched", ops)];
@@ -549,10 +550,12 @@ static int l_set_port_version (lua_State *L)
luaL_argerror(L, 2, "invalid value for port.version.service_tunnel"); luaL_argerror(L, 2, "invalid value for port.version.service_tunnel");
if (o.servicescan) if (o.servicescan)
port->setServiceProbeResults(probestate, name, tunnel, product, target->ports.setServiceProbeResults(port->portno, port->proto,
probestate, name, tunnel, product,
version, extrainfo, hostname, ostype, devicetype, NULL); version, extrainfo, hostname, ostype, devicetype, NULL);
else else
port->setServiceProbeResults(probestate, name, tunnel, NULL, NULL, target->ports.setServiceProbeResults(port->portno, port->proto,
probestate, name, tunnel, NULL, NULL,
NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL);
return 0; return 0;

View File

@@ -7,9 +7,9 @@ class Port;
int luaopen_nmap(lua_State* l); int luaopen_nmap(lua_State* l);
int luaopen_stdnse_c (lua_State *L); int luaopen_stdnse_c (lua_State *L);
void set_hostinfo(lua_State* l, Target* currenths); void set_hostinfo(lua_State* l, Target* currenths);
void set_portinfo(lua_State* l, Port* port); void set_portinfo(lua_State* l, const Target *target, const Port* port);
Target *get_target (lua_State *L, int index); Target *get_target (lua_State *L, int index);
Port *get_port (lua_State *L, Target *target, int index); const Port *get_port (lua_State *L, Target *target, int index);
#endif #endif

View File

@@ -640,6 +640,7 @@ HostOsScanStats::~HostOsScanStats() {
void HostOsScanStats::initScanStats() { void HostOsScanStats::initScanStats() {
Port *tport = NULL; Port *tport = NULL;
Port port;
int i; int i;
/* Lets find an open port to use if we don't already have one */ /* Lets find an open port to use if we don't already have one */
@@ -650,11 +651,11 @@ void HostOsScanStats::initScanStats() {
if (target->FPR->osscan_opentcpport > 0) if (target->FPR->osscan_opentcpport > 0)
openTCPPort = target->FPR->osscan_opentcpport; openTCPPort = target->FPR->osscan_opentcpport;
else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_OPEN))) { else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_TCP, PORT_OPEN))) {
openTCPPort = tport->portno; openTCPPort = tport->portno;
/* If it is zero, let's try another one if there is one ) */ /* If it is zero, let's try another one if there is one ) */
if (tport->portno == 0) if (tport->portno == 0)
if ((tport = target->ports.nextPort(tport, IPPROTO_TCP, PORT_OPEN))) if ((tport = target->ports.nextPort(tport, &port, IPPROTO_TCP, PORT_OPEN)))
openTCPPort = tport->portno; openTCPPort = tport->portno;
target->FPR->osscan_opentcpport = openTCPPort; target->FPR->osscan_opentcpport = openTCPPort;
@@ -663,21 +664,21 @@ void HostOsScanStats::initScanStats() {
/* Now we should find a closed port */ /* Now we should find a closed port */
if (target->FPR->osscan_closedtcpport > 0) if (target->FPR->osscan_closedtcpport > 0)
closedTCPPort = target->FPR->osscan_closedtcpport; closedTCPPort = target->FPR->osscan_closedtcpport;
else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_CLOSED))) { else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_TCP, PORT_CLOSED))) {
closedTCPPort = tport->portno; closedTCPPort = tport->portno;
/* If it is zero, let's try another one if there is one ) */ /* If it is zero, let's try another one if there is one ) */
if (tport->portno == 0) if (tport->portno == 0)
if ((tport = target->ports.nextPort(tport, IPPROTO_TCP, PORT_CLOSED))) if ((tport = target->ports.nextPort(tport, &port, IPPROTO_TCP, PORT_CLOSED)))
closedTCPPort = tport->portno; closedTCPPort = tport->portno;
target->FPR->osscan_closedtcpport = closedTCPPort; target->FPR->osscan_closedtcpport = closedTCPPort;
} else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_UNFILTERED))) { } else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_TCP, PORT_UNFILTERED))) {
/* Well, we will settle for unfiltered */ /* Well, we will settle for unfiltered */
closedTCPPort = tport->portno; closedTCPPort = tport->portno;
/* But again we'd prefer not to have zero */ /* But again we'd prefer not to have zero */
if (tport->portno == 0) if (tport->portno == 0)
if ((tport = target->ports.nextPort(tport, IPPROTO_TCP, PORT_UNFILTERED))) if ((tport = target->ports.nextPort(tport, &port, IPPROTO_TCP, PORT_UNFILTERED)))
closedTCPPort = tport->portno; closedTCPPort = tport->portno;
} else { } else {
/* We'll just have to pick one at random :( */ /* We'll just have to pick one at random :( */
@@ -687,19 +688,19 @@ void HostOsScanStats::initScanStats() {
/* Now we should find a closed udp port */ /* Now we should find a closed udp port */
if (target->FPR->osscan_closedudpport > 0) if (target->FPR->osscan_closedudpport > 0)
closedUDPPort = target->FPR->osscan_closedudpport; closedUDPPort = target->FPR->osscan_closedudpport;
else if ((tport = target->ports.nextPort(NULL, IPPROTO_UDP, PORT_CLOSED))) { else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_UDP, PORT_CLOSED))) {
closedUDPPort = tport->portno; closedUDPPort = tport->portno;
/* Not zero, if possible */ /* Not zero, if possible */
if (tport->portno == 0) if (tport->portno == 0)
if ((tport = target->ports.nextPort(tport, IPPROTO_UDP, PORT_CLOSED))) if ((tport = target->ports.nextPort(tport, &port, IPPROTO_UDP, PORT_CLOSED)))
closedUDPPort = tport->portno; closedUDPPort = tport->portno;
target->FPR->osscan_closedudpport = closedUDPPort; target->FPR->osscan_closedudpport = closedUDPPort;
} else if ((tport = target->ports.nextPort(NULL, IPPROTO_UDP, PORT_UNFILTERED))) { } else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_UDP, PORT_UNFILTERED))) {
/* Well, we will settle for unfiltered */ /* Well, we will settle for unfiltered */
closedUDPPort = tport->portno; closedUDPPort = tport->portno;
/* But not zero, please */ /* But not zero, please */
if (tport->portno == 0) if (tport->portno == 0)
if ((tport = target->ports.nextPort(NULL, IPPROTO_UDP, PORT_UNFILTERED))) if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_UDP, PORT_UNFILTERED)))
closedUDPPort = tport->portno; closedUDPPort = tport->portno;
} else { } else {
/* Pick one at random. Shrug. */ /* Pick one at random. Shrug. */

View File

@@ -202,7 +202,7 @@ static char *xml_sf_convert(const char *str) {
// the service name or the service fingerprint is non-null. // the service name or the service fingerprint is non-null.
// Returns a pointer to a buffer containing the element, // Returns a pointer to a buffer containing the element,
// you will have to call free on it. // you will have to call free on it.
static char *getServiceXMLBuf(struct serviceDeductions *sd) { static char *getServiceXMLBuf(const struct serviceDeductions *sd) {
string versionxmlstring = ""; string versionxmlstring = "";
char rpcbuf[128]; char rpcbuf[128];
char confBuf[20]; char confBuf[20];
@@ -466,33 +466,6 @@ int print_iflist(void) {
return 0; 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 #ifndef NOLUA
static char *formatScriptOutput(ScriptResult sr) { static char *formatScriptOutput(ScriptResult sr) {
std::string result = std::string(), output = sr.get_output(); std::string result = std::string(), output = sr.get_output();
@@ -549,6 +522,7 @@ void printportoutput(Target * currenths, PortList * plist) {
int first = 1; int first = 1;
struct protoent *proto; struct protoent *proto;
Port *current; Port *current;
Port port;
char hostname[1200]; char hostname[1200];
struct serviceDeductions sd; struct serviceDeductions sd;
NmapOutputTable *Tbl = NULL; NmapOutputTable *Tbl = NULL;
@@ -561,6 +535,7 @@ void printportoutput(Target * currenths, PortList * plist) {
unsigned int rowno; unsigned int rowno;
int numrows; int numrows;
int numignoredports = plist->numIgnoredPorts(); int numignoredports = plist->numIgnoredPorts();
int numports = plist->numPorts();
vector<const char *> saved_servicefps; vector<const char *> saved_servicefps;
@@ -579,7 +554,7 @@ void printportoutput(Target * currenths, PortList * plist) {
prevstate = istate; prevstate = istate;
} }
if (numignoredports == plist->numports) { if (numignoredports == numports) {
if (numignoredports == 0) { if (numignoredports == 0) {
log_write(LOG_PLAIN, "0 ports scanned on %s\n", log_write(LOG_PLAIN, "0 ports scanned on %s\n",
currenths->NameIP(hostname, sizeof(hostname))); currenths->NameIP(hostname, sizeof(hostname)));
@@ -666,7 +641,7 @@ void printportoutput(Target * currenths, PortList * plist) {
if (o.servicescan || o.rpcscan) if (o.servicescan || o.rpcscan)
versioncol = colno++; versioncol = colno++;
numrows = plist->numports - numignoredports; numrows = numports - numignoredports;
#ifndef NOLUA #ifndef NOLUA
int scriptrows = 0; int scriptrows = 0;
@@ -697,7 +672,7 @@ void printportoutput(Target * currenths, PortList * plist) {
rowno = 1; rowno = 1;
if (o.ipprotscan) { if (o.ipprotscan) {
current = NULL; current = NULL;
while ((current = plist->nextPort(current, IPPROTO_IP, 0)) != NULL) { while ((current = plist->nextPort(current, &port, IPPROTO_IP, 0)) != NULL) {
if (!plist->isIgnoredState(current->state)) { if (!plist->isIgnoredState(current->state)) {
if (!first) if (!first)
log_write(LOG_MACHINE, ", "); log_write(LOG_MACHINE, ", ");
@@ -730,8 +705,10 @@ void printportoutput(Target * currenths, PortList * plist) {
} }
} }
} else { } else {
char fullversion[160];
current = NULL; current = NULL;
while ((current = plist->nextPort(current, TCPANDUDPANDSCTP, 0)) != NULL) { while ((current = plist->nextPort(current, &port, TCPANDUDPANDSCTP, 0)) != NULL) {
if (!plist->isIgnoredState(current->state)) { if (!plist->isIgnoredState(current->state)) {
if (!first) if (!first)
log_write(LOG_MACHINE, ", "); log_write(LOG_MACHINE, ", ");
@@ -740,7 +717,7 @@ void printportoutput(Target * currenths, PortList * plist) {
strcpy(protocol, IPPROTO2STR(current->proto)); strcpy(protocol, IPPROTO2STR(current->proto));
Snprintf(portinfo, sizeof(portinfo), "%d/%s", current->portno, protocol); Snprintf(portinfo, sizeof(portinfo), "%d/%s", current->portno, protocol);
state = statenum2str(current->state); state = statenum2str(current->state);
current->getServiceDeductions(&sd); plist->getServiceDeductions(current->portno, current->proto, &sd);
if (sd.service_fp && saved_servicefps.size() <= 8) if (sd.service_fp && saved_servicefps.size() <= 8)
saved_servicefps.push_back(sd.service_fp); saved_servicefps.push_back(sd.service_fp);
@@ -783,7 +760,7 @@ void printportoutput(Target * currenths, PortList * plist) {
(sd.name) ? sd.name : ((*rpcinfo) ? "" : "unknown"), (sd.name) ? sd.name : ((*rpcinfo) ? "" : "unknown"),
(sd.name) ? " " : "", rpcinfo); (sd.name) ? " " : "", rpcinfo);
} else { } else {
getNmapServiceName(&sd, current->state, serviceinfo, sizeof(serviceinfo)); current->getNmapServiceName(serviceinfo, sizeof(serviceinfo));
rpcmachineinfo[0] = '\0'; rpcmachineinfo[0] = '\0';
} }
Tbl->addItem(rowno, portcol, true, portinfo); Tbl->addItem(rowno, portcol, true, portinfo);
@@ -792,8 +769,9 @@ void printportoutput(Target * currenths, PortList * plist) {
if (o.reason) if (o.reason)
Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason)); Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason));
if (*sd.fullversion) sd.populateFullVersionString(fullversion, sizeof(fullversion));
Tbl->addItem(rowno, versioncol, true, sd.fullversion); if (*fullversion)
Tbl->addItem(rowno, versioncol, true, fullversion);
// How should we escape illegal chars in grepable output? // How should we escape illegal chars in grepable output?
// Well, a reasonably clean way would be backslash escapes // Well, a reasonably clean way would be backslash escapes
@@ -801,7 +779,7 @@ void printportoutput(Target * currenths, PortList * plist) {
// out fields with awk, cut, and such. So I'm gonna use the // out fields with awk, cut, and such. So I'm gonna use the
// ugly hat (fitting to grepable output) or replacing the '/' // ugly hat (fitting to grepable output) or replacing the '/'
// character with '|' in the version field. // character with '|' in the version field.
Strncpy(grepvers, sd.fullversion, sizeof(grepvers) / sizeof(*grepvers)); Strncpy(grepvers, fullversion, sizeof(grepvers) / sizeof(*grepvers));
p = grepvers; p = grepvers;
while ((p = strchr(p, '/'))) { while ((p = strchr(p, '/'))) {
*p = '|'; *p = '|';
@@ -840,7 +818,7 @@ void printportoutput(Target * currenths, PortList * plist) {
rowno++; rowno++;
#ifndef NOLUA #ifndef NOLUA
if (o.script) { if (o.script) {
ScriptResults::iterator ssr_iter; ScriptResults::const_iterator ssr_iter;
for (ssr_iter = current->scriptResults.begin(); for (ssr_iter = current->scriptResults.begin();
ssr_iter != current->scriptResults.end(); ssr_iter++) { ssr_iter != current->scriptResults.end(); ssr_iter++) {
@@ -1907,6 +1885,7 @@ static int hostcmp(const char *a, const char *b) {
scan (if it was performed) */ scan (if it was performed) */
void printserviceinfooutput(Target * currenths) { void printserviceinfooutput(Target * currenths) {
Port *p = NULL; Port *p = NULL;
Port port;
struct serviceDeductions sd; struct serviceDeductions sd;
int i, numhostnames = 0, numostypes = 0, numdevicetypes = 0; int i, numhostnames = 0, numostypes = 0, numdevicetypes = 0;
char hostname_tbl[MAX_SERVICE_INFO_FIELDS][MAXHOSTNAMELEN]; char hostname_tbl[MAX_SERVICE_INFO_FIELDS][MAXHOSTNAMELEN];
@@ -1917,12 +1896,12 @@ 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, TCPANDUDPANDSCTP, PORT_OPEN))) { while ((p = currenths->ports.nextPort(p, &port, TCPANDUDPANDSCTP, PORT_OPEN))) {
// The following 2 lines (from portlist.h) tell us that we don't need to // 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 // worry about free()ing anything in the serviceDeductions struct. pass in
// an allocated struct serviceDeductions (don't wory about initializing, and // an allocated struct serviceDeductions (don't wory about initializing, and
// you don't have to free any internal ptrs. // you don't have to free any internal ptrs.
p->getServiceDeductions(&sd); currenths->ports.getServiceDeductions(p->portno, p->proto, &sd);
if (sd.hostname && !hostcmp(currenths->HostName(), sd.hostname)) { if (sd.hostname && !hostcmp(currenths->HostName(), sd.hostname)) {
for (i = 0; i < MAX_SERVICE_INFO_FIELDS; i++) { for (i = 0; i < MAX_SERVICE_INFO_FIELDS; i++) {

View File

@@ -109,42 +109,95 @@ extern NmapOps o; /* option structure */
Port::Port() { Port::Port() {
portno = proto = 0; portno = proto = 0;
rpc_status = RPC_STATUS_UNTESTED;
rpc_program = rpc_lowver = rpc_highver = 0;
state = 0; state = 0;
serviceprobe_results = PROBESTATE_INITIAL; service = NULL;
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); state_reason_init(&reason);
} }
Port::~Port() { Port::~Port() {
if (serviceprobe_product) if (service != NULL) {
free(serviceprobe_product); if (service->name)
if (serviceprobe_version) free(service->name);
free(serviceprobe_version); if (service->product)
if (serviceprobe_extrainfo) free(service->product);
free(serviceprobe_extrainfo); if (service->version)
if (serviceprobe_hostname) free(service->version);
free(serviceprobe_hostname); if (service->extrainfo)
if (serviceprobe_ostype) free(service->extrainfo);
free(serviceprobe_ostype); if (service->hostname)
if (serviceprobe_devicetype) free(service->hostname);
free(serviceprobe_devicetype); if (service->ostype)
if (serviceprobe_service) free(service->ostype);
free(serviceprobe_service); if (service->devicetype)
if (serviceprobe_fp) free(service->devicetype);
free(serviceprobe_fp); 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;
} }
// Uses the sd->{product,version,extrainfo} if available to fill // Uses the sd->{product,version,extrainfo} if available to fill
// out sd->fullversion. If unavailable, it will be set to zero length. // out sd->fullversion. If unavailable, it will be set to zero length.
static void populateFullVersionString(struct serviceDeductions *sd) { void serviceDeductions::populateFullVersionString(char *buf, size_t n) const {
char *dst = sd->fullversion; char *dst = buf;
unsigned int spaceleft = sizeof(sd->fullversion) - 1; // Leave room for \0 unsigned int spaceleft = n - 1; // Leave room for \0
int needpad = 0; // Do we need to pad a space between the next template? int needpad = 0; // Do we need to pad a space between the next template?
dst[0] = '\0'; dst[0] = '\0';
@@ -156,52 +209,52 @@ static void populateFullVersionString(struct serviceDeductions *sd) {
* that bit of information. * that bit of information.
*/ */
if (sd->product && spaceleft >= 8) { if (product && spaceleft >= 8) {
if (spaceleft < strlen(sd->product)) { if (spaceleft < strlen(product)) {
strncat(dst, sd->product, spaceleft - 3); // Leave room for "..." strncat(dst, product, spaceleft - 3); // Leave room for "..."
strncat(dst, "...", spaceleft); strncat(dst, "...", spaceleft);
spaceleft = 0; spaceleft = 0;
} }
else { else {
strncat(dst, sd->product, spaceleft); strncat(dst, product, spaceleft);
spaceleft -= strlen(sd->product); spaceleft -= strlen(product);
} }
needpad = 1; needpad = 1;
} }
if (sd->version && spaceleft >= 8) { if (version && spaceleft >= 8) {
if (needpad) { if (needpad) {
strncat(dst, " ", spaceleft); strncat(dst, " ", spaceleft);
spaceleft--; spaceleft--;
} }
if (spaceleft < strlen(sd->version)) { if (spaceleft < strlen(version)) {
strncat(dst, sd->version, spaceleft - 3); strncat(dst, version, spaceleft - 3);
strncat(dst, "...", spaceleft); strncat(dst, "...", spaceleft);
spaceleft = 0; spaceleft = 0;
} }
else { else {
strncat(dst, sd->version, spaceleft); strncat(dst, version, spaceleft);
spaceleft -= strlen(sd->version); spaceleft -= strlen(version);
} }
needpad = 1; needpad = 1;
} }
if (sd->extrainfo && spaceleft >= 8) { if (extrainfo && spaceleft >= 8) {
if (needpad) { if (needpad) {
strncat(dst, " ", spaceleft); strncat(dst, " ", spaceleft);
spaceleft--; spaceleft--;
} }
// This time we need to trucate inside of the () so we have spaceleft - 2 // This time we need to trucate inside of the () so we have spaceleft - 2
strncat(dst, "(", spaceleft); strncat(dst, "(", spaceleft);
if (spaceleft - 2 < strlen(sd->extrainfo)) { if (spaceleft - 2 < strlen(extrainfo)) {
strncat(dst, sd->extrainfo, spaceleft - 5); strncat(dst, extrainfo, spaceleft - 5);
strncat(dst, "...", spaceleft - 2); strncat(dst, "...", spaceleft - 2);
spaceleft = 1; // Fit the paren spaceleft = 1; // Fit the paren
} }
else { else {
strncat(dst, sd->extrainfo, spaceleft); strncat(dst, extrainfo, spaceleft);
spaceleft -= (strlen(sd->extrainfo) + 2); spaceleft -= (strlen(extrainfo) + 2);
} }
strncat(dst, ")", spaceleft); strncat(dst, ")", spaceleft);
spaceleft--; spaceleft--;
@@ -214,74 +267,24 @@ static void populateFullVersionString(struct serviceDeductions *sd) {
// initializing, and you don't have to free any internal ptrs. See the // initializing, and you don't have to free any internal ptrs. See the
// serviceDeductions definition for the fields that are populated. // serviceDeductions definition for the fields that are populated.
// Returns 0 if at least a name is available. // Returns 0 if at least a name is available.
int Port::getServiceDeductions(struct serviceDeductions *sd) { const void PortList::getServiceDeductions(u16 portno, int protocol, struct serviceDeductions *sd) const {
const Port *port;
port = lookupPort(portno, protocol);
if (port == NULL || port->service == NULL) {
struct servent *service; struct servent *service;
assert(sd); /* Look up the service name. */
memset(sd, 0, sizeof(struct serviceDeductions)); *sd = serviceDeductions();
sd->service_fp = serviceprobe_fp; service = nmap_getservbyport(htons(portno), IPPROTO2STR(protocol));
sd->service_tunnel = serviceprobe_tunnel; if (service != NULL)
sd->rpc_status = rpc_status;
sd->rpc_program = rpc_program;
sd->rpc_lowver = rpc_lowver;
sd->rpc_highver = rpc_highver;
// 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 = service->s_name;
else
sd->name = NULL;
sd->name_confidence = 3; sd->name_confidence = 3;
return 0; } else {
*sd = *port->service;
} }
// Couldn't find it. [shrug]
return -1;
} }
@@ -312,72 +315,112 @@ static char *cstringSanityCheck(const char* string, int len) {
return result; return result;
} }
void Port::setServiceProbeResults(enum serviceprobestate sres, void PortList::setServiceProbeResults(u16 portno, int protocol,
const char *sname, enum serviceprobestate sres, const char *sname,
enum service_tunnel_type tunnel, enum service_tunnel_type tunnel, const char *product, const char *version,
const char *product, const char *version, const char *extrainfo, const char *hostname, const char *ostype,
const char *extrainfo, const char *hostname, const char *devicetype, const char *fingerprint) {
const char *ostype, const char *devicetype, Port *port;
const char *fingerprint) {
serviceprobe_results = sres; port = createPort(portno, protocol);
serviceprobe_tunnel = tunnel; if (port->service == NULL)
port->service = new serviceDeductions;
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;
}
// port->serviceprobe_results = sres;
port->service->service_tunnel = tunnel;
if (sname) if (sname)
serviceprobe_service = strdup(sname); port->service->name = strdup(sname);
else else
serviceprobe_service = NULL; port->service->name = NULL;
if (fingerprint) if (fingerprint)
serviceprobe_fp = strdup(fingerprint); port->service->service_fp = strdup(fingerprint);
else else
serviceprobe_fp = NULL; port->service->service_fp = NULL;
serviceprobe_product = cstringSanityCheck(product, 80); port->service->product = cstringSanityCheck(product, 80);
serviceprobe_version = cstringSanityCheck(version, 80); port->service->version = cstringSanityCheck(version, 80);
serviceprobe_extrainfo = cstringSanityCheck(extrainfo, 256); port->service->extrainfo = cstringSanityCheck(extrainfo, 256);
serviceprobe_hostname = cstringSanityCheck(hostname, 80); port->service->hostname = cstringSanityCheck(hostname, 80);
serviceprobe_ostype = cstringSanityCheck(ostype, 32); port->service->ostype = cstringSanityCheck(ostype, 32);
serviceprobe_devicetype = cstringSanityCheck(devicetype, 32); port->service->devicetype = cstringSanityCheck(devicetype, 32);
} }
/* Sets the results of an RPC scan. if rpc_status is not /* Sets the results of an RPC scan. if rpc_status is not
RPC_STATUS_GOOD_PROGRAM, pass 0 for the other args. This function RPC_STATUS_GOOD_PROGRAM, pass 0 for the other args. This function
takes care of setting the port's service and version appropriately. */ takes care of setting the port's service and version appropriately. */
void Port::setRPCProbeResults(int rpcs, unsigned long rpcp, void PortList::setRPCProbeResults(u16 portno, int proto, int rpcs, unsigned long rpcp,
unsigned int rpcl, unsigned int rpch) { unsigned int rpcl, unsigned int rpch) {
rpc_status = rpcs; Port *port;
const char *newsvc; const char *newsvc;
char verbuf[128]; char verbuf[128];
rpc_status = rpcs; port = createPort(portno, proto);
if (rpc_status == RPC_STATUS_GOOD_PROG) { if (port->service == NULL)
rpc_program = rpcp; port->service = new serviceDeductions;
rpc_lowver = rpcl;
rpc_highver = rpch; 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;
// Now set the service/version info // Now set the service/version info
newsvc = nmap_getrpcnamebynum(rpcp); newsvc = nmap_getrpcnamebynum(rpcp);
if (!newsvc) newsvc = "rpc.unknownprog"; // should never happen if (!newsvc) newsvc = "rpc.unknownprog"; // should never happen
if (serviceprobe_service) if (port->service->name)
free(serviceprobe_service); free(port->service->name);
serviceprobe_service = strdup(newsvc); port->service->name = strdup(newsvc);
serviceprobe_product = strdup(newsvc); if (port->service->rpc_lowver == port->service->rpc_highver)
if (rpc_lowver == rpc_highver) Snprintf(verbuf, sizeof(verbuf), "%i", port->service->rpc_lowver);
Snprintf(verbuf, sizeof(verbuf), "%i", rpc_lowver);
else else
Snprintf(verbuf, sizeof(verbuf), "%i-%i", rpc_lowver, rpc_highver); Snprintf(verbuf, sizeof(verbuf), "%i-%i", port->service->rpc_lowver, port->service->rpc_highver);
serviceprobe_version = strdup(verbuf); port->service->version = strdup(verbuf);
Snprintf(verbuf, sizeof(verbuf), "rpc #%li", rpc_program); Snprintf(verbuf, sizeof(verbuf), "rpc #%li", port->service->rpc_program);
serviceprobe_extrainfo = strdup(verbuf); port->service->extrainfo = strdup(verbuf);
} else if (rpc_status == RPC_STATUS_UNKNOWN) { port->service->name_confidence = 10;
if (serviceprobe_service) port->service->dtype = SERVICE_DETECTION_PROBED;
free(serviceprobe_service); } else if (port->service->rpc_status == RPC_STATUS_UNKNOWN) {
if (port->service->name)
free(port->service->name);
serviceprobe_service = strdup("rpc.unknown"); port->service->name = strdup("rpc.unknown");
port->service->name_confidence = 8;
port->service->dtype = SERVICE_DETECTION_PROBED;
} }
} }
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. /* Convert protocol name from in.h to enum portlist_proto.
* So IPPROTO_TCP will be changed to PORTLIST_PROTO_TCP and so on. */ * So IPPROTO_TCP will be changed to PORTLIST_PROTO_TCP and so on. */
@@ -387,6 +430,12 @@ void Port::setRPCProbeResults(int rpcs, unsigned long rpcp,
(p)==IPPROTO_SCTP ? PORTLIST_PROTO_SCTP : \ (p)==IPPROTO_SCTP ? PORTLIST_PROTO_SCTP : \
PORTLIST_PROTO_IP) 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() { PortList::PortList() {
int proto; int proto;
@@ -396,9 +445,11 @@ PortList::PortList() {
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) { for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) {
if(port_list_count[proto] > 0) if(port_list_count[proto] > 0)
port_list[proto] = (Port**) safe_zalloc(sizeof(Port*)*port_list_count[proto]); 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; numscriptresults = 0;
idstr = NULL; idstr = NULL;
} }
@@ -422,8 +473,22 @@ PortList::~PortList() {
} }
} }
void PortList::setDefaultPortState(u8 protocol, int state) {
int proto = INPROTO2PORTLISTPROTO(protocol);
int i;
int PortList::addPort(u16 portno, u8 protocol, int state) { 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;
Port *current; Port *current;
int proto = INPROTO2PORTLISTPROTO(protocol); int proto = INPROTO2PORTLISTPROTO(protocol);
@@ -445,55 +510,35 @@ int PortList::addPort(u16 portno, u8 protocol, int state) {
assert(protocol!=IPPROTO_IP || portno<256); assert(protocol!=IPPROTO_IP || portno<256);
current = getPortEntry(portno, protocol); oldport = lookupPort(portno, protocol);
if (current) { if (oldport != NULL) {
/* 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 */
if (o.debugging && current->state == state) { if (o.debugging && oldport->state == state) {
error("Duplicate port (%hu/%s)", portno, proto2ascii(protocol)); error("Duplicate port (%hu/%s)", portno, proto2ascii(protocol));
} }
state_counts_proto[proto][current->state]--; state_counts_proto[proto][oldport->state]--;
} else { } else {
current = new Port(); state_counts_proto[proto][default_port_state[proto].state]--;
current->portno = portno;
current->proto = protocol;
numports++;
setPortEntry(portno, protocol, current);
} }
current = createPort(portno, protocol);
current->state = state; current->state = state;
state_counts_proto[proto][state]++; state_counts_proto[proto][state]++;
if(state == PORT_FILTERED || state == PORT_OPENFILTERED) if(state == PORT_FILTERED || state == PORT_OPENFILTERED)
setStateReason(portno, protocol, ER_NORESPONSE, 0, 0); setStateReason(portno, protocol, ER_NORESPONSE, 0, 0);
return 0; /*success */ return;
} }
int PortList::removePort(u16 portno, u8 protocol) { int PortList::getPortState(u16 portno, u8 protocol) {
Port *answer = NULL; const Port *port;
log_write(LOG_PLAIN, "Removed %d\n", portno); port = lookupPort(portno, protocol);
if (port == NULL)
answer = getPortEntry(portno, protocol);
if (!answer)
return -1; return -1;
setPortEntry(portno, protocol, NULL); return port->state;
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 /* Saves an identification string for the target containing these
@@ -512,13 +557,13 @@ void PortList::setIdStr(const char *id) {
int PortList::getStateCounts(int protocol, int state){ 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 PortList::getStateCounts(int state){
int sum=0, proto; int sum=0, proto;
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) for(proto=0; proto < PORTLIST_PROTO_MAX; proto++)
sum += state_counts_proto[proto][state]; sum += getStateCounts(PORTLISTPROTO2INPROTO(proto), state);
return(sum); return(sum);
} }
@@ -532,19 +577,19 @@ int PortList::getStateCounts(int state){
function returns ports in numeric order from lowest to highest, function returns ports in numeric order from lowest to highest,
except that if you ask for both TCP, UDP & SCTP, every TCP port except that if you ask for both TCP, UDP & SCTP, every TCP port
will be returned before we start returning UDP and SCTP ports */ will be returned before we start returning UDP and SCTP ports */
Port *PortList::nextPort(Port *afterthisport, Port *PortList::nextPort(const Port *cur, Port *next,
int allowed_protocol, int allowed_state) { int allowed_protocol, int allowed_state) {
int proto; int proto;
int mapped_pno; int mapped_pno;
Port *port; Port *port;
if(afterthisport) { if (cur) {
proto = INPROTO2PORTLISTPROTO(afterthisport->proto); proto = INPROTO2PORTLISTPROTO(cur->proto);
assert(port_map[proto]!=NULL); // Hmm, it's not posible to handle port that doesn't have anything in map 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); assert(cur->proto!=IPPROTO_IP || cur->portno<256);
mapped_pno = port_map[proto][afterthisport->portno]; mapped_pno = port_map[proto][cur->portno];
mapped_pno++; // we're interested in next port after current 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) if (allowed_protocol == TCPANDUDPANDSCTP)
proto = INPROTO2PORTLISTPROTO(IPPROTO_TCP); proto = INPROTO2PORTLISTPROTO(IPPROTO_TCP);
else if (allowed_protocol == UDPANDSCTP) else if (allowed_protocol == UDPANDSCTP)
@@ -557,78 +602,128 @@ Port *PortList::nextPort(Port *afterthisport,
if(port_list[proto] != NULL) { if(port_list[proto] != NULL) {
for(;mapped_pno < port_list_count[proto]; mapped_pno++) { for(;mapped_pno < port_list_count[proto]; mapped_pno++) {
port = port_list[proto][mapped_pno]; port = port_list[proto][mapped_pno];
if(port && (allowed_state==0 || port->state==allowed_state)) if (port && (allowed_state==0 || port->state==allowed_state)) {
return(port); *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 all protocols, than after TCP search UDP & SCTP */ /* if all protocols, than after TCP search UDP & SCTP */
if((!afterthisport && allowed_protocol == TCPANDUDPANDSCTP) || if((!cur && allowed_protocol == TCPANDUDPANDSCTP) ||
(afterthisport && proto == INPROTO2PORTLISTPROTO(IPPROTO_TCP))) (cur && proto == INPROTO2PORTLISTPROTO(IPPROTO_TCP)))
return(nextPort(NULL, UDPANDSCTP, allowed_state)); return(nextPort(NULL, next, UDPANDSCTP, allowed_state));
/* if all protocols, than after UDP search SCTP */ /* if all protocols, than after UDP search SCTP */
if((!afterthisport && allowed_protocol == UDPANDSCTP) || if((!cur && allowed_protocol == UDPANDSCTP) ||
(afterthisport && proto == INPROTO2PORTLISTPROTO(IPPROTO_UDP))) (cur && proto == INPROTO2PORTLISTPROTO(IPPROTO_UDP)))
return(nextPort(NULL, IPPROTO_SCTP, allowed_state)); return(nextPort(NULL, next, IPPROTO_SCTP, allowed_state));
return(NULL); return(NULL);
} }
Port *PortList::getPortEntry(u16 portno, u8 protocol) { /* Convert portno and protocol into the internal indices used to index
int proto = INPROTO2PORTLISTPROTO(protocol); port_list. Returns false on error, true otherwise. */
int mapped_pno; bool PortList::mapPort(u16 *portno, u8 *protocol) const {
int mapped_portno, mapped_protocol;
assert(protocol!=IPPROTO_IP || portno<256); mapped_protocol = INPROTO2PORTLISTPROTO(*protocol);
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];
assert(mapped_pno < port_list_count[proto]); if (*protocol == IPPROTO_IP)
assert(mapped_pno >= 0); 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];
/* The ugly hack: we allow only port 0 to be mapped to 0 position */ assert(mapped_portno < port_list_count[mapped_protocol]);
if(mapped_pno==0 && portno!=0) { assert(mapped_portno >= 0);
error("WARNING: %s(%i,%i): this port was not mapped", __func__, portno, protocol);
return(NULL); *portno = mapped_portno;
}else *protocol = mapped_protocol;
return(port_list[proto][mapped_pno]);
return true;
} }
void PortList::setPortEntry(u16 portno, u8 protocol, Port *port) { const Port *PortList::lookupPort(u16 portno, u8 protocol) const {
int proto = INPROTO2PORTLISTPROTO(protocol); if (!mapPort(&portno, &protocol))
int mapped_pno; return NULL;
assert(protocol!=IPPROTO_IP || portno<256); return port_list[protocol][portno];
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];
assert(mapped_pno < port_list_count[proto]); /* Create the port if it doesn't exist; otherwise this is like lookupPort. */
assert(mapped_pno >= 0); Port *PortList::createPort(u16 portno, u8 protocol) {
u16 mapped_portno;
u8 mapped_protocol;
/* The ugly hack: we allow only port 0 to be mapped to 0 position */ mapped_portno = portno;
if(mapped_pno==0 && portno!=0) { mapped_protocol = protocol;
error("WARNING: %s(%i,%i): this port was not mapped", __func__, portno, protocol); if (!mapPort(&mapped_portno, &mapped_protocol))
return; 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;
} }
port_list[proto][mapped_pno] = port; 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;
} }
/* Just free memory used by PortList::port_map[]. Should be done somewhere /* Just free memory used by PortList::port_map[]. Should be done somewhere
* before closing nmap. */ * before closing nmap. */
void PortList::freePortMap(){ void PortList::freePortMap(){
int proto; int proto;
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) {
if(port_map[proto]){ if(port_map[proto]){
free(port_map[proto]); free(port_map[proto]);
port_map[proto] = NULL; 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[PORTLIST_PROTO_MAX];
u16 *PortList::port_map_rev[PORTLIST_PROTO_MAX];
int PortList::port_list_count[PORTLIST_PROTO_MAX]; int PortList::port_list_count[PORTLIST_PROTO_MAX];
/* This function must be runned before any PortList object is created. /* This function must be runned before any PortList object is created.
@@ -636,38 +731,27 @@ int PortList::port_list_count[PORTLIST_PROTO_MAX];
* should be sorted. */ * should be sorted. */
void PortList::initializePortMap(int protocol, u16 *ports, int portcount) { void PortList::initializePortMap(int protocol, u16 *ports, int portcount) {
int i; int i;
int unused_zero; // aren't we using 0 port?
int ports_max = (protocol == IPPROTO_IP) ? 256 : 65536; int ports_max = (protocol == IPPROTO_IP) ? 256 : 65536;
int proto = INPROTO2PORTLISTPROTO(protocol); int proto = INPROTO2PORTLISTPROTO(protocol);
if(port_map[proto]!=NULL) if (port_map[proto] != NULL || port_map_rev[proto] != NULL)
fatal("%s: portmap for protocol %i already initialized", __func__, protocol); fatal("%s: portmap for protocol %i already initialized", __func__, protocol);
assert(port_list_count[proto]==0); assert(port_list_count[proto]==0);
/* this memory will never be freed, but this is the way it has to be. */ /* 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[proto] = (u16 *) safe_zalloc(sizeof(u16) * ports_max);
port_map_rev[proto] = (u16 *) safe_zalloc(sizeof(u16) * portcount);
/* Is zero port to be unused? */ port_list_count[proto] = portcount;
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++) { 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;
port_map[proto][ports[i]] = i + unused_zero; // yes, this is the key line port_map_rev[proto][i] = ports[i];
} }
/* So now port_map should have such structure (lets scan 2nd,4th and 6th port): /* 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_map[0,0,1,0,2,0,3,...] <- indexes to port_list structure
* port_list[0,port_2,port_4,port_6] * port_list[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 /* Cycles through the 0 or more "ignored" ports which should be
@@ -761,20 +845,26 @@ int PortList::numIgnoredPorts() {
return numports; 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) { int PortList::setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr) {
Port *answer = NULL; Port *answer = NULL;
if(!(answer = getPortEntry(portno, proto)))
return -1;
if(reason > ER_MAX) if(reason > ER_MAX)
return -1; return -1;
answer = createPort(portno, proto);
/* set new reason and increment its count */ /* set new reason and increment its count */
answer->reason.reason_id = reason; answer->reason.reason_id = reason;
answer->reason.ip_addr.s_addr = ip_addr; answer->reason.ip_addr.s_addr = ip_addr;
answer->reason.ttl = ttl; answer->reason.ttl = ttl;
answer->reason.state = answer->state;
setPortEntry(portno, proto, answer);
return 0; return 0;
} }

View File

@@ -140,25 +140,25 @@ enum service_tunnel_type { SERVICE_TUNNEL_NONE, SERVICE_TUNNEL_SSL };
void random_port_cheat(u16 *ports, int portcount); void random_port_cheat(u16 *ports, int portcount);
struct serviceDeductions { struct serviceDeductions {
const char *name; // will be NULL if can't determine serviceDeductions();
void populateFullVersionString(char *buf, size_t n) const;
char *name; // will be NULL if can't determine
// Confidence is a number from 0 (least confident) to 10 (most // Confidence is a number from 0 (least confident) to 10 (most
// confident) expressing how accurate the service detection is // confident) expressing how accurate the service detection is
// likely to be. // likely to be.
int name_confidence; int name_confidence;
// Any of these 6 can be NULL if we weren't able to determine it // Any of these 6 can be NULL if we weren't able to determine it
const char *product; char *product;
const char *version; char *version;
const char *extrainfo; char *extrainfo;
const char *hostname; char *hostname;
const char *ostype; char *ostype;
const char *devicetype; char *devicetype;
// SERVICE_TUNNEL_NONE or SERVICE_TUNNEL_SSL // SERVICE_TUNNEL_NONE or SERVICE_TUNNEL_SSL
enum service_tunnel_type service_tunnel; 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. // if we should give the user a service fingerprint to submit, here it is. Otherwise NULL.
const char *service_fp; char *service_fp;
enum service_detection_type dtype; // definition above enum service_detection_type dtype; // definition above
int rpc_status; /* RPC_STATUS_UNTESTED means we haven't checked int rpc_status; /* RPC_STATUS_UNTESTED means we haven't checked
RPC_STATUS_UNKNOWN means the port appears to be RPC RPC_STATUS_UNKNOWN means the port appears to be RPC
@@ -173,38 +173,12 @@ struct serviceDeductions {
}; };
class Port { class Port {
friend class PortList;
public: public:
Port(); Port();
~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; u16 portno;
u8 proto; u8 proto;
@@ -216,28 +190,10 @@ class Port {
#endif #endif
private: private:
int rpc_status; /* RPC_STATUS_UNTESTED means we haven't checked /* This is allocated only on demand by PortList::setServiceProbeResults or
RPC_STATUS_UNKNOWN means the port appears to be RPC PortList::setRPCProbeResults, to save memory for the many closed or
but we couldn't find a match filtered ports that don't need it. */
RPC_STATUS_GOOD_PROG means rpc_program gives the prog # serviceDeductions *service;
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;
}; };
@@ -261,10 +217,10 @@ class PortList {
/* Free memory used by port_map. It should be done somewhere before quitting*/ /* Free memory used by port_map. It should be done somewhere before quitting*/
static void freePortMap(); static void freePortMap();
/* Add a new port to this list. If the state has changed, it is void setDefaultPortState(u8 protocol, int state);
OK to call this function to effect the change */ void setPortState(u16 portno, u8 protocol, int state);
int addPort(u16 portno, u8 protocol, int state); int getPortState(u16 portno, u8 protocol);
int removePort(u16 portno, u8 protocol); int forgetPort(u16 portno, u8 protocol);
/* Saves an identification string for the target containing these /* Saves an identification string for the target containing these
ports (an IP addrss might be a good example, but set what you ports (an IP addrss might be a good example, but set what you
want). Only used when printing new port updates. Optional. A want). Only used when printing new port updates. Optional. A
@@ -280,17 +236,11 @@ class PortList {
function returns ports in numeric order from lowest to highest, function returns ports in numeric order from lowest to highest,
except that if you ask for TCP, UDP & SCTP, all TCP ports will be except that if you ask for TCP, UDP & SCTP, all TCP ports will be
returned before we start returning UDP and finally SCTP ports */ returned before we start returning UDP and finally SCTP ports */
Port *nextPort(Port *afterthisport, Port *nextPort(const Port *cur, Port *next,
int allowed_protocol, int allowed_state); 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 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 */ int numscriptresults; /* Total number of scripts which produced output */
/* Get number of ports in this state. This a sum for protocols. */ /* Get number of ports in this state. This a sum for protocols. */
@@ -298,6 +248,38 @@ class PortList {
/* Get number of ports in this state for requested protocol. */ /* Get number of ports in this state for requested protocol. */
int getStateCounts(int protocol, int state); 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 /* Cycles through the 0 or more "ignored" ports which should be
consolidated for Nmap output. They are returned sorted by the consolidated for Nmap output. They are returned sorted by the
number of prots in the state, starting with the most common. It number of prots in the state, starting with the most common. It
@@ -313,12 +295,20 @@ class PortList {
int numIgnoredStates(); int numIgnoredStates();
int numIgnoredPorts(); int numIgnoredPorts();
int numPorts() const;
private: 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 /* 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 */ /* Number of ports in each state per each protocol. */
int state_counts_proto[PORTLIST_PROTO_MAX][PORT_HIGHEST_STATE]; int state_counts_proto[PORTLIST_PROTO_MAX][PORT_HIGHEST_STATE];
Port **port_list[PORTLIST_PROTO_MAX]; Port **port_list[PORTLIST_PROTO_MAX];
protected: protected:
@@ -326,8 +316,10 @@ class PortList {
* Only functions: getPortEntry, setPortEntry, initializePortMap and * Only functions: getPortEntry, setPortEntry, initializePortMap and
* nextPort should access this structure directly. */ * nextPort should access this structure directly. */
static u16 *port_map[PORTLIST_PROTO_MAX]; 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. */ /* Number of allocated elements in port_list per each protocol. */
static int port_list_count[PORTLIST_PROTO_MAX]; static int port_list_count[PORTLIST_PROTO_MAX];
Port default_port_state[PORTLIST_PROTO_MAX];
}; };
#endif #endif

View File

@@ -246,6 +246,7 @@ static int update_state_summary(state_reason_summary_t *head, reason_t reason_id
* state_reason_summary structures using update_state_summary */ * state_reason_summary structures using update_state_summary */
static unsigned int get_state_summary(state_reason_summary_t *head, PortList *Ports, int state) { static unsigned int get_state_summary(state_reason_summary_t *head, PortList *Ports, int state) {
Port *current = NULL; Port *current = NULL;
Port port;
state_reason_summary_t *reason; state_reason_summary_t *reason;
unsigned int total = 0; unsigned int total = 0;
unsigned short proto = (o.ipprotscan) ? IPPROTO_IP : TCPANDUDPANDSCTP; unsigned short proto = (o.ipprotscan) ? IPPROTO_IP : TCPANDUDPANDSCTP;
@@ -254,7 +255,7 @@ static unsigned int get_state_summary(state_reason_summary_t *head, PortList *Po
return 0; return 0;
reason = head; reason = head;
while((current = Ports->nextPort(current, proto, state)) != NULL) { while((current = Ports->nextPort(current, &port, proto, state)) != NULL) {
if(Ports->isIgnoredState(current->state)) { if(Ports->isIgnoredState(current->state)) {
total++; total++;
update_state_summary(reason, current->reason.reason_id); update_state_summary(reason, current->reason.reason_id);

View File

@@ -114,7 +114,6 @@ typedef struct port_reason {
reason_t reason_id; reason_t reason_id;
struct in_addr ip_addr; struct in_addr ip_addr;
unsigned short ttl; unsigned short ttl;
int state;
} state_reason_t; } state_reason_t;
/* used to calculate state reason summaries. /* used to calculate state reason summaries.

View File

@@ -1103,33 +1103,6 @@ static bool pingprobe_is_appropriate(const UltraScanInfo *USI,
return false; 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) { HostScanStats::HostScanStats(Target *t, UltraScanInfo *UltraSI) {
target = t; target = t;
USI=UltraSI; USI=UltraSI;
@@ -1497,6 +1470,46 @@ static void init_perf_values(struct ultra_scan_performance_vars *perf) {
perf->tryno_cap = o.getMaxRetransmissions(); 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<Target *> &targets, stype scantype) {
vector<Target *>::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 /* Order of initializations in this function CAN BE IMPORTANT, so be careful
mucking with it. */ mucking with it. */
void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, stype scantp) { void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, stype scantp) {
@@ -1567,6 +1580,8 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
break; break;
} }
set_default_port_state(Targets, scantype);
init_perf_values(&perf); init_perf_values(&perf);
/* Keep a completed host around for a standard TCP MSL (2 min) */ /* Keep a completed host around for a standard TCP MSL (2 min) */
@@ -2598,7 +2613,6 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
u16 portno = 0; u16 portno = 0;
u8 proto = 0; u8 proto = 0;
int oldstate = PORT_TESTING; int oldstate = PORT_TESTING;
Port *currentp;
/* Whether no response means a port is open */ /* Whether no response means a port is open */
bool noresp_open_scan = USI->noresp_open_scan; bool noresp_open_scan = USI->noresp_open_scan;
@@ -2616,13 +2630,11 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
portno = pspec->pd.sctp.dport; portno = pspec->pd.sctp.dport;
} else assert(0); } else assert(0);
/* First figure out the current state */ oldstate = hss->target->ports.getPortState(portno, proto);
currentp = hss->target->ports.getPortEntry(portno, proto); if (oldstate == -1) {
if (!currentp) {
oldstate = PORT_TESTING; oldstate = PORT_TESTING;
hss->ports_finished++; hss->ports_finished++;
} }
else oldstate = currentp->state;
/* printf("TCP port %hu has changed from state %s to %s!\n", portno, statenum2str(oldstate), statenum2str(newstate)); */ /* printf("TCP port %hu has changed from state %s to %s!\n", portno, statenum2str(oldstate), statenum2str(newstate)); */
switch(oldstate) { switch(oldstate) {
@@ -2631,25 +2643,25 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
in a SYN scan, but not neccessarily for UDP scan */ in a SYN scan, but not neccessarily for UDP scan */
case PORT_TESTING: case PORT_TESTING:
/* Brand new port -- add it to the list */ /* Brand new port -- add it to the list */
hss->target->ports.addPort(portno, proto, newstate); hss->target->ports.setPortState(portno, proto, newstate);
break; break;
case PORT_OPEN: case PORT_OPEN:
if (newstate != PORT_OPEN) { if (newstate != PORT_OPEN) {
if (noresp_open_scan) { if (noresp_open_scan) {
hss->target->ports.addPort(portno, proto, newstate); hss->target->ports.setPortState(portno, proto, newstate);
} /* Otherwise The old open takes precendence */ } /* Otherwise The old open takes precendence */
} }
break; break;
case PORT_CLOSED: case PORT_CLOSED:
if (newstate != PORT_CLOSED) { if (newstate != PORT_CLOSED) {
if (!noresp_open_scan && newstate != PORT_FILTERED) if (!noresp_open_scan && newstate != PORT_FILTERED)
hss->target->ports.addPort(portno, proto, newstate); hss->target->ports.setPortState(portno, proto, newstate);
} }
break; break;
case PORT_FILTERED: case PORT_FILTERED:
if (newstate != PORT_FILTERED) { if (newstate != PORT_FILTERED) {
if (!noresp_open_scan || newstate != PORT_OPEN) if (!noresp_open_scan || newstate != PORT_OPEN)
hss->target->ports.addPort(portno, proto, newstate); hss->target->ports.setPortState(portno, proto, newstate);
} }
break; break;
case PORT_UNFILTERED: case PORT_UNFILTERED:
@@ -2658,11 +2670,11 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
case. I'll change it if the new state is open or closed, case. I'll change it if the new state is open or closed,
though I don't expect that to ever happen */ though I don't expect that to ever happen */
if (newstate == PORT_OPEN || newstate == PORT_CLOSED) if (newstate == PORT_OPEN || newstate == PORT_CLOSED)
hss->target->ports.addPort(portno, proto, newstate); hss->target->ports.setPortState(portno, proto, newstate);
break; break;
case PORT_OPENFILTERED: case PORT_OPENFILTERED:
if (newstate != PORT_OPENFILTERED) { if (newstate != PORT_OPENFILTERED) {
hss->target->ports.addPort(portno, proto, newstate); hss->target->ports.setPortState(portno, proto, newstate);
} }
break; break;
default: default:
@@ -2700,18 +2712,16 @@ void HostScanStats::boostScanDelay() {
sdn.goodRespSinceDelayChanged = 0; sdn.goodRespSinceDelayChanged = 0;
} }
/* Dismiss all probe attempts on bench -- the ports are marked /* Dismiss all probe attempts on bench -- hosts are marked down and ports will
'filtered' or whatever is appropriate for having no response */ be set to whatever the default port state is for the scan. */
void HostScanStats::dismissBench() { void HostScanStats::dismissBench() {
int newstate;
if (probe_bench.empty()) return; if (probe_bench.empty()) return;
newstate = scantype_no_response_means(USI->scantype);
while(!probe_bench.empty()) { while(!probe_bench.empty()) {
if (USI->ping_scan) if (USI->ping_scan)
ultrascan_host_pspec_update(USI, this, &probe_bench.back(), newstate); ultrascan_host_pspec_update(USI, this, &probe_bench.back(), HOST_DOWN);
else /* Nothing to do if !USI->ping_scan. ultrascan_port_pspec_update would
ultrascan_port_pspec_update(USI, this, &probe_bench.back(), newstate); allocate a Port object but we rely on the default port state to save
memory. */
probe_bench.pop_back(); probe_bench.pop_back();
} }
bench_tryno = 0; bench_tryno = 0;
@@ -2719,7 +2729,6 @@ void HostScanStats::dismissBench() {
/* Move all members of bench to retry_stack for probe retransmission */ /* Move all members of bench to retry_stack for probe retransmission */
void HostScanStats::retransmitBench() { void HostScanStats::retransmitBench() {
int newstate;
if (probe_bench.empty()) return; if (probe_bench.empty()) return;
/* Move all contents of probe_bench to the end of retry_stack, updating retry_stack_tries accordingly */ /* Move all contents of probe_bench to the end of retry_stack, updating retry_stack_tries accordingly */
@@ -2728,7 +2737,6 @@ void HostScanStats::retransmitBench() {
bench_tryno); bench_tryno);
assert(retry_stack.size() == retry_stack_tries.size()); assert(retry_stack.size() == retry_stack_tries.size());
probe_bench.erase(probe_bench.begin(), probe_bench.end()); probe_bench.erase(probe_bench.begin(), probe_bench.end());
newstate = scantype_no_response_means(USI->scantype);
bench_tryno = 0; bench_tryno = 0;
} }
@@ -4929,7 +4937,6 @@ static void processData(UltraScanInfo *USI) {
list<UltraProbe *>::iterator probeI, nextProbeI; list<UltraProbe *>::iterator probeI, nextProbeI;
HostScanStats *host = NULL; HostScanStats *host = NULL;
UltraProbe *probe = NULL; UltraProbe *probe = NULL;
int newstate;
unsigned int maxtries = 0; unsigned int maxtries = 0;
bool scanmaybedone = true; /* The whole scan is not yet done */ bool scanmaybedone = true; /* The whole scan is not yet done */
int expire_us = 0; int expire_us = 0;
@@ -4995,19 +5002,20 @@ static void processData(UltraScanInfo *USI) {
if (!probe->isPing() && probe->timedout && !probe->retransmitted) { if (!probe->isPing() && probe->timedout && !probe->retransmitted) {
if (!tryno_mayincrease && probe->tryno >= maxtries) { 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) { if (tryno_capped && !host->retry_capped_warned) {
log_write(LOG_PLAIN, "Warning: %s giving up on port because" log_write(LOG_PLAIN, "Warning: %s giving up on port because"
" retransmission cap hit (%d).\n", host->target->targetipstr(), " retransmission cap hit (%d).\n", host->target->targetipstr(),
probe->tryno); probe->tryno);
host->retry_capped_warned = true; 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; continue;
} else if (probe->tryno >= maxtries && } else if (probe->tryno >= maxtries &&
TIMEVAL_SUBTRACT(USI->now, probe->sent) > expire_us) { TIMEVAL_SUBTRACT(USI->now, probe->sent) > expire_us) {
@@ -5258,8 +5266,8 @@ void bounce_scan(Target *target, u16 *portarray, int numports,
perror("recv problem from FTP bounce server"); perror("recv problem from FTP bounce server");
} else if (res == 0) { } else if (res == 0) {
if (timedout) if (timedout)
target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_FILTERED); target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_FILTERED);
else target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_CLOSED); else target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_CLOSED);
} else { } else {
recvbuf[res] = '\0'; recvbuf[res] = '\0';
if (o.debugging) log_write(LOG_STDOUT, "result of LIST: %s", recvbuf); if (o.debugging) log_write(LOG_STDOUT, "result of LIST: %s", recvbuf);
@@ -5270,7 +5278,7 @@ void bounce_scan(Target *target, u16 *portarray, int numports,
res = recvtime(sd, recvbuf, 2048,10, NULL); res = recvtime(sd, recvbuf, 2048,10, NULL);
} }
if (recvbuf[0] == '1' || recvbuf[0] == '2') { if (recvbuf[0] == '1' || recvbuf[0] == '2') {
target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_OPEN); target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_OPEN);
if (recvbuf[0] == '1') { if (recvbuf[0] == '1') {
res = recvtime(sd, recvbuf, 2048,5, NULL); res = recvtime(sd, recvbuf, 2048,5, NULL);
if (res < 0) if (res < 0)
@@ -5281,7 +5289,7 @@ void bounce_scan(Target *target, u16 *portarray, int numports,
if (o.debugging) log_write(LOG_STDOUT, "nxt line: %s", recvbuf); if (o.debugging) log_write(LOG_STDOUT, "nxt line: %s", recvbuf);
if (recvbuf[0] == '4' && recvbuf[1] == '2' && if (recvbuf[0] == '4' && recvbuf[1] == '2' &&
recvbuf[2] == '6') { recvbuf[2] == '6') {
target->ports.removePort(portarray[i], IPPROTO_TCP); target->ports.forgetPort(portarray[i], IPPROTO_TCP);
if (o.debugging || o.verbose) if (o.debugging || o.verbose)
log_write(LOG_STDOUT, "Changed my mind about port %i\n", portarray[i]); log_write(LOG_STDOUT, "Changed my mind about port %i\n", portarray[i]);
} }
@@ -5290,7 +5298,7 @@ void bounce_scan(Target *target, u16 *portarray, int numports,
} }
} else { } else {
/* This means the port is closed ... */ /* This means the port is closed ... */
target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_CLOSED); target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_CLOSED);
} }
} }
} }
@@ -5362,6 +5370,7 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
unsigned long j; unsigned long j;
struct serviceDeductions sd; struct serviceDeductions sd;
bool doingOpenFiltered = false; bool doingOpenFiltered = false;
Port port;
ScanProgressMeter *SPM = NULL; ScanProgressMeter *SPM = NULL;
@@ -5434,11 +5443,11 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
while(1) { while(1) {
if (doingOpenFiltered) { if (doingOpenFiltered) {
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port, rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port,
TCPANDUDPANDSCTP, &port, TCPANDUDPANDSCTP,
PORT_OPENFILTERED); 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,
TCPANDUDPANDSCTP, &port, TCPANDUDPANDSCTP,
PORT_OPEN); PORT_OPEN);
if (!rsi.rpc_current_port && !o.servicescan) { if (!rsi.rpc_current_port && !o.servicescan) {
doingOpenFiltered = true; doingOpenFiltered = true;
@@ -5452,7 +5461,7 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
break; // We do all open ports if no service scan break; // We do all open ports if no service scan
if (!rsi.rpc_current_port) if (!rsi.rpc_current_port)
break; // done! break; // done!
rsi.rpc_current_port->getServiceDeductions(&sd); target->ports.getServiceDeductions(rsi.rpc_current_port->portno, rsi.rpc_current_port->proto, &sd);
if (sd.name && sd.service_tunnel == SERVICE_TUNNEL_NONE && if (sd.name && sd.service_tunnel == SERVICE_TUNNEL_NONE &&
strcmp(sd.name, "rpcbind") == 0) strcmp(sd.name, "rpcbind") == 0)
break; // Good - an RPC port for us to scan. break; // Good - an RPC port for us to scan.
@@ -5594,7 +5603,8 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
/* Now we figure out the results of the port we just RPC scanned */ /* Now we figure out the results of the port we just RPC scanned */
rsi.rpc_current_port->setRPCProbeResults(rsi.rpc_status, rsi.rpc_program, target->ports.setRPCProbeResults(rsi.rpc_current_port->portno, rsi.rpc_current_port->proto,
rsi.rpc_status, rsi.rpc_program,
rsi.rpc_lowver, rsi.rpc_highver); rsi.rpc_lowver, rsi.rpc_highver);
/* Time to put our RPC program scan list back together for the /* Time to put our RPC program scan list back together for the

View File

@@ -149,7 +149,6 @@ public:
// Note that the next 2 members are for convenience and are not destroyed w/the ServiceNFO // 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 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 // if a match is found, it is placed here. Otherwise NULL
const char *probe_matched; const char *probe_matched;
// If a match is found, any product/version/info/hostname/ostype/devicetype // If a match is found, any product/version/info/hostname/ostype/devicetype
@@ -1339,7 +1338,6 @@ ServiceNFO::ServiceNFO(AllProbes *newAP) {
AP = newAP; AP = newAP;
currentresp = NULL; currentresp = NULL;
currentresplen = 0; currentresplen = 0;
port = NULL;
product_matched[0] = version_matched[0] = extrainfo_matched[0] = '\0'; product_matched[0] = version_matched[0] = extrainfo_matched[0] = '\0';
hostname_matched[0] = ostype_matched[0] = devicetype_matched[0] = '\0'; hostname_matched[0] = ostype_matched[0] = devicetype_matched[0] = '\0';
tunnel = SERVICE_TUNNEL_NONE; tunnel = SERVICE_TUNNEL_NONE;
@@ -1633,6 +1631,7 @@ ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) {
unsigned int targetno; unsigned int targetno;
ServiceNFO *svc; ServiceNFO *svc;
Port *nxtport; Port *nxtport;
Port port;
int desired_par; int desired_par;
struct timeval now; struct timeval now;
num_hosts_timedout = 0; num_hosts_timedout = 0;
@@ -1644,12 +1643,11 @@ ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) {
num_hosts_timedout++; num_hosts_timedout++;
continue; continue;
} }
while((nxtport = Targets[targetno]->ports.nextPort(nxtport, TCPANDUDPANDSCTP, PORT_OPEN))) { while((nxtport = Targets[targetno]->ports.nextPort(nxtport, &port, TCPANDUDPANDSCTP, PORT_OPEN))) {
svc = new ServiceNFO(AP); svc = new ServiceNFO(AP);
svc->target = Targets[targetno]; svc->target = Targets[targetno];
svc->portno = nxtport->portno; svc->portno = nxtport->portno;
svc->proto = nxtport->proto; svc->proto = nxtport->proto;
svc->port = nxtport;
services_remaining.push_back(svc); services_remaining.push_back(svc);
} }
} }
@@ -1662,12 +1660,11 @@ 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, TCPANDUDPANDSCTP, PORT_OPENFILTERED))) { while((nxtport = Targets[targetno]->ports.nextPort(nxtport, &port, TCPANDUDPANDSCTP, PORT_OPENFILTERED))) {
svc = new ServiceNFO(AP); svc = new ServiceNFO(AP);
svc->target = Targets[targetno]; svc->target = Targets[targetno];
svc->portno = nxtport->portno; svc->portno = nxtport->portno;
svc->proto = nxtport->proto; svc->proto = nxtport->proto;
svc->port = nxtport;
services_remaining.push_back(svc); services_remaining.push_back(svc);
} }
} }
@@ -1703,8 +1700,8 @@ static void adjustPortStateIfNeccessary(ServiceNFO *svc) {
char host[128]; char host[128];
if (svc->port->state == PORT_OPENFILTERED) { if (svc->target->ports.getPortState(svc->portno, svc->proto) == PORT_OPENFILTERED) {
svc->target->ports.addPort(svc->portno, svc->proto, PORT_OPEN); svc->target->ports.setPortState(svc->portno, svc->proto, PORT_OPEN);
if (svc->proto == IPPROTO_TCP) if (svc->proto == IPPROTO_TCP)
svc->target->ports.setStateReason(svc->portno, svc->proto, ER_TCPRESPONSE, 0, 0); svc->target->ports.setStateReason(svc->portno, svc->proto, ER_TCPRESPONSE, 0, 0);
if (svc->proto == IPPROTO_UDP) if (svc->proto == IPPROTO_UDP)
@@ -2318,7 +2315,8 @@ list<ServiceNFO *>::iterator svc;
for(svc = SG->services_finished.begin(); svc != SG->services_finished.end(); svc++) { for(svc = SG->services_finished.begin(); svc != SG->services_finished.end(); svc++) {
if ((*svc)->probe_state != PROBESTATE_FINISHED_NOMATCH) { if ((*svc)->probe_state != PROBESTATE_FINISHED_NOMATCH) {
(*svc)->port->setServiceProbeResults((*svc)->probe_state, (*svc)->target->ports.setServiceProbeResults((*svc)->portno, (*svc)->proto,
(*svc)->probe_state,
(*svc)->probe_matched, (*svc)->probe_matched,
(*svc)->tunnel, (*svc)->tunnel,
*(*svc)->product_matched? (*svc)->product_matched : NULL, *(*svc)->product_matched? (*svc)->product_matched : NULL,
@@ -2329,7 +2327,8 @@ list<ServiceNFO *>::iterator svc;
*(*svc)->devicetype_matched? (*svc)->devicetype_matched : NULL, *(*svc)->devicetype_matched? (*svc)->devicetype_matched : NULL,
shouldWePrintFingerprint(*svc) ? (*svc)->getServiceFingerprint(NULL) : NULL); shouldWePrintFingerprint(*svc) ? (*svc)->getServiceFingerprint(NULL) : NULL);
} else { } else {
(*svc)->port->setServiceProbeResults((*svc)->probe_state, NULL, (*svc)->target->ports.setServiceProbeResults((*svc)->portno, (*svc)->proto,
(*svc)->probe_state, NULL,
(*svc)->tunnel, NULL, NULL, NULL, NULL, NULL, NULL, (*svc)->tunnel, NULL, NULL, NULL, NULL, NULL, NULL,
(*svc)->getServiceFingerprint(NULL)); (*svc)->getServiceFingerprint(NULL));
} }
@@ -2372,7 +2371,8 @@ static void remove_excluded_ports(AllProbes *AP, ServiceGroup *SG) {
if (o.debugging) log_write(LOG_PLAIN, "EXCLUDING %d/%s\n", svc->portno, if (o.debugging) log_write(LOG_PLAIN, "EXCLUDING %d/%s\n", svc->portno,
IPPROTO2STR(svc->proto)); IPPROTO2STR(svc->proto));
svc->port->setServiceProbeResults(PROBESTATE_EXCLUDED, NULL, svc->target->ports.setServiceProbeResults(svc->portno, svc->proto,
PROBESTATE_EXCLUDED, NULL,
SERVICE_TUNNEL_NONE, SERVICE_TUNNEL_NONE,
"Excluded from version scan", NULL, "Excluded from version scan", NULL,
NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL);