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,
we must delete it */
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,
we must delete it */
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)
target->ports.addPort(ports[0], IPPROTO_TCP, PORT_OPEN);
target->ports.setPortState(ports[0], IPPROTO_TCP, PORT_OPEN);
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;
}
@@ -1043,8 +1043,8 @@ void idle_scan(Target *target, u16 *portarray, int numports,
/* Now we go through the ports which were scanned but not determined
to be open, and add them in the "closed" state */
for(portidx = 0; portidx < numports; portidx++) {
if (target->ports.getPortEntry(portarray[portidx], IPPROTO_TCP) == NULL) {
target->ports.addPort(portarray[portidx], IPPROTO_TCP, PORT_CLOSEDFILTERED);
if (target->ports.getPortState(portarray[portidx], IPPROTO_TCP) == -1) {
target->ports.setPortState(portarray[portidx], IPPROTO_TCP, PORT_CLOSEDFILTERED);
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_NOIPIDCHANGE, 0, 0);
} else
target->ports.setStateReason(portarray[portidx], IPPROTO_TCP, ER_IPIDCHANGE, 0, 0);

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) {
/* 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);
}

View File

@@ -147,7 +147,7 @@ struct rpc_info {
};
struct rpcscaninfo {
Port *rpc_current_port;
const Port *rpc_current_port;
unsigned long *rpc_progs;
unsigned long rpc_number;
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);
PortList *plist = &(target->ports);
Port *current = NULL;
Port port;
lua_newtable(L);
for (int i = 0; states[i] != PORT_HIGHEST_STATE; i++)
while ((current = plist->nextPort(current, TCPANDUDPANDSCTP,
while ((current = plist->nextPort(current, &port, TCPANDUDPANDSCTP,
states[i])) != NULL)
{
lua_newtable(L);
set_portinfo(L, current);
set_portinfo(L, target, current);
lua_pushboolean(L, 1);
lua_rawset(L, -3);
}
@@ -112,10 +113,10 @@ static int port_set_output (lua_State *L)
{
ScriptResult sr;
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_output(luaL_checkstring(L, 4));
port->scriptResults.push_back(sr);
target->ports.addScriptResult(port->portno, port->proto, sr);
/* increment host port script results*/
target->ports.numscriptresults++;
return 0;
@@ -247,7 +248,7 @@ void ScriptResult::set_output (const char *out)
output = std::string(out);
}
std::string ScriptResult::get_output (void)
std::string ScriptResult::get_output (void) const
{
return output;
}
@@ -257,7 +258,7 @@ void ScriptResult::set_id (const char *ident)
id = std::string(ident);
}
std::string ScriptResult::get_id (void)
std::string ScriptResult::get_id (void) const
{
return id;
}

View File

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

View File

@@ -28,20 +28,20 @@ extern "C" {
extern NmapOps o;
void set_version(lua_State *L, struct serviceDeductions sd) {
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.name, "name");
void set_version(lua_State *L, const struct serviceDeductions *sd) {
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->name, "name");
lua_pushnumber(L, sd.name_confidence);
lua_pushnumber(L, sd->name_confidence);
lua_setfield(L, -2, "name_confidence");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.product, "product");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.version, "version");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.extrainfo, "extrainfo");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.hostname, "hostname");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.ostype, "ostype");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.devicetype, "devicetype");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->product, "product");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->version, "version");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->extrainfo, "extrainfo");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->hostname, "hostname");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->ostype, "ostype");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->devicetype, "devicetype");
switch(sd.service_tunnel) {
switch(sd->service_tunnel) {
case(SERVICE_TUNNEL_NONE):
SCRIPT_ENGINE_PUSHSTRING_NOTNULL("none", "service_tunnel");
break;
@@ -54,9 +54,9 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
break;
}
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd.service_fp, "service_fp");
SCRIPT_ENGINE_PUSHSTRING_NOTNULL(sd->service_fp, "service_fp");
switch(sd.dtype) {
switch(sd->dtype) {
case(SERVICE_DETECTION_TABLE):
SCRIPT_ENGINE_PUSHSTRING_NOTNULL("table", "service_fp");
break;
@@ -69,7 +69,7 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
break;
}
switch(sd.rpc_status) {
switch(sd->rpc_status) {
case(RPC_STATUS_UNTESTED):
SCRIPT_ENGINE_PUSHSTRING_NOTNULL("untested", "rpc_status");
break;
@@ -88,14 +88,14 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
break;
}
if(sd.rpc_status == RPC_STATUS_GOOD_PROG) {
lua_pushnumber(L, sd.rpc_program);
if(sd->rpc_status == RPC_STATUS_GOOD_PROG) {
lua_pushnumber(L, sd->rpc_program);
lua_setfield(L, -2, "rpc_program");
lua_pushnumber(L, sd.rpc_lowver);
lua_pushnumber(L, sd->rpc_lowver);
lua_setfield(L, -2, "rpc_lowver");
lua_pushnumber(L, sd.rpc_highver);
lua_pushnumber(L, sd->rpc_highver);
lua_setfield(L, -2, "rpc_highver");
}
}
@@ -103,24 +103,26 @@ void set_version(lua_State *L, struct serviceDeductions sd) {
/* set some port state information onto the
* 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;
port->getServiceDeductions(&sd);
target->ports.getServiceDeductions(port->portno, port->proto, &sd);
lua_pushnumber(L, (double) port->portno);
lua_setfield(L, -2, "number");
lua_pushstring(L, sd.name);
lua_setfield(L, -2, "service");
if (sd.name != NULL) {
lua_pushstring(L, sd.name);
lua_setfield(L, -2, "service");
}
lua_newtable(L);
set_version(L, &sd);
lua_setfield(L, -2, "version");
lua_pushstring(L, IPPROTO2STR(port->proto));
lua_setfield(L, -2, "protocol");
lua_newtable(L);
set_version(L, sd);
lua_setfield(L, -2, "version");
lua_pushstring(L, statenum2str(port->state));
lua_setfield(L, -2, "state");
@@ -419,9 +421,10 @@ done:
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;
luaL_checktype(L, index, LUA_TTABLE);
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), "sctp") == 0 ? IPPROTO_SCTP :
luaL_error(L, "port 'protocol' field must be \"udp\", \"sctp\" or \"tcp\"");
while ((port = target->ports.nextPort(port, protocol, PORT_UNKNOWN)) != NULL)
if (port->portno == portno)
while ((p = target->ports.nextPort(p, &port, protocol, PORT_UNKNOWN)) != NULL)
if (p->portno == portno)
break;
lua_pop(L, 2);
return port;
return p;
}
/* 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)
{
Target *target;
Port *port;
const Port *port;
target = get_target(L, 1);
port = get_port(L, target, 2);
if (port == NULL)
@@ -463,7 +466,7 @@ static int l_get_port_state (lua_State *L)
else
{
lua_newtable(L);
set_portinfo(L, port);
set_portinfo(L, target, port);
}
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 char *op[] = {"open", "closed", NULL};
Target *target;
Port *port;
const Port *port;
target = get_target(L, 1);
if ((port = get_port(L, target, 2)) != NULL)
{
@@ -486,17 +489,15 @@ static int l_set_port_state (lua_State *L)
case PORT_OPEN:
if (port->state == PORT_OPEN)
return 0;
target->ports.addPort(port->portno, port->proto, PORT_OPEN);
port->state = PORT_OPEN;
target->ports.setPortState(port->portno, port->proto, PORT_OPEN);
break;
case PORT_CLOSED:
if (port->state == PORT_CLOSED)
return 0;
target->ports.addPort(port->portno, port->proto, PORT_CLOSED);
port->state = PORT_CLOSED;
target->ports.setPortState(port->portno, port->proto, PORT_CLOSED);
break;
}
port->reason.reason_id = ER_SCRIPT;
target->ports.setStateReason(port->portno, port->proto, ER_SCRIPT, 0, 0);
}
return 0;
}
@@ -518,7 +519,7 @@ static int l_set_port_version (lua_State *L)
"incomplete"
};
Target *target;
Port *port;
const Port *port;
enum service_tunnel_type tunnel = SERVICE_TUNNEL_NONE;
enum serviceprobestate probestate =
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");
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);
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);
return 0;

View File

@@ -7,9 +7,9 @@ class Port;
int luaopen_nmap(lua_State* l);
int luaopen_stdnse_c (lua_State *L);
void set_hostinfo(lua_State* l, Target* currenths);
void set_portinfo(lua_State* l, Port* port);
void set_portinfo(lua_State* l, const Target *target, const Port* port);
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

View File

@@ -640,6 +640,7 @@ HostOsScanStats::~HostOsScanStats() {
void HostOsScanStats::initScanStats() {
Port *tport = NULL;
Port port;
int i;
/* Lets find an open port to use if we don't already have one */
@@ -650,11 +651,11 @@ void HostOsScanStats::initScanStats() {
if (target->FPR->osscan_opentcpport > 0)
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;
/* If it is zero, let's try another one if there is one ) */
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;
target->FPR->osscan_opentcpport = openTCPPort;
@@ -663,21 +664,21 @@ void HostOsScanStats::initScanStats() {
/* Now we should find a closed port */
if (target->FPR->osscan_closedtcpport > 0)
closedTCPPort = target->FPR->osscan_closedtcpport;
else if ((tport = target->ports.nextPort(NULL, IPPROTO_TCP, PORT_CLOSED))) {
else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_TCP, PORT_CLOSED))) {
closedTCPPort = tport->portno;
/* If it is zero, let's try another one if there is one ) */
if (tport->portno == 0)
if ((tport = target->ports.nextPort(tport, IPPROTO_TCP, PORT_CLOSED)))
if ((tport = target->ports.nextPort(tport, &port, IPPROTO_TCP, PORT_CLOSED)))
closedTCPPort = tport->portno;
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 */
closedTCPPort = tport->portno;
/* But again we'd prefer not to have zero */
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;
} else {
/* We'll just have to pick one at random :( */
@@ -687,19 +688,19 @@ void HostOsScanStats::initScanStats() {
/* Now we should find a closed udp port */
if (target->FPR->osscan_closedudpport > 0)
closedUDPPort = target->FPR->osscan_closedudpport;
else if ((tport = target->ports.nextPort(NULL, IPPROTO_UDP, PORT_CLOSED))) {
else if ((tport = target->ports.nextPort(NULL, &port, IPPROTO_UDP, PORT_CLOSED))) {
closedUDPPort = tport->portno;
/* Not zero, if possible */
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;
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 */
closedUDPPort = tport->portno;
/* But not zero, please */
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;
} else {
/* 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.
// Returns a pointer to a buffer containing the element,
// you will have to call free on it.
static char *getServiceXMLBuf(struct serviceDeductions *sd) {
static char *getServiceXMLBuf(const struct serviceDeductions *sd) {
string versionxmlstring = "";
char rpcbuf[128];
char confBuf[20];
@@ -466,33 +466,6 @@ int print_iflist(void) {
return 0;
}
/* Fills in namebuf (as long as there is space in buflen) with the
Name nmap normal output will use to describe the port. This takes
into account to confidence level, any SSL tunneling, etc. Truncates
namebuf to 0 length if there is no room.*/
static void getNmapServiceName(struct serviceDeductions *sd, int state,
char *namebuf, int buflen) {
const char *tunnel_prefix;
int len;
if (sd->service_tunnel == SERVICE_TUNNEL_SSL)
tunnel_prefix = "ssl/";
else
tunnel_prefix = "";
if (sd->name != NULL && strcmp(sd->name, "unknown") != 0) {
/* The port has a name and the name is not "unknown". How confident are we? */
if (o.servicescan && state == PORT_OPEN && sd->name_confidence <= 5)
len = Snprintf(namebuf, buflen, "%s%s?", tunnel_prefix, sd->name);
else
len = Snprintf(namebuf, buflen, "%s%s", tunnel_prefix, sd->name);
} else {
len = Snprintf(namebuf, buflen, "%sunknown", tunnel_prefix);
}
if (len >= buflen || len < 0)
namebuf[0] = '\0';
}
#ifndef NOLUA
static char *formatScriptOutput(ScriptResult sr) {
std::string result = std::string(), output = sr.get_output();
@@ -549,6 +522,7 @@ void printportoutput(Target * currenths, PortList * plist) {
int first = 1;
struct protoent *proto;
Port *current;
Port port;
char hostname[1200];
struct serviceDeductions sd;
NmapOutputTable *Tbl = NULL;
@@ -561,6 +535,7 @@ void printportoutput(Target * currenths, PortList * plist) {
unsigned int rowno;
int numrows;
int numignoredports = plist->numIgnoredPorts();
int numports = plist->numPorts();
vector<const char *> saved_servicefps;
@@ -579,7 +554,7 @@ void printportoutput(Target * currenths, PortList * plist) {
prevstate = istate;
}
if (numignoredports == plist->numports) {
if (numignoredports == numports) {
if (numignoredports == 0) {
log_write(LOG_PLAIN, "0 ports scanned on %s\n",
currenths->NameIP(hostname, sizeof(hostname)));
@@ -666,7 +641,7 @@ void printportoutput(Target * currenths, PortList * plist) {
if (o.servicescan || o.rpcscan)
versioncol = colno++;
numrows = plist->numports - numignoredports;
numrows = numports - numignoredports;
#ifndef NOLUA
int scriptrows = 0;
@@ -697,7 +672,7 @@ void printportoutput(Target * currenths, PortList * plist) {
rowno = 1;
if (o.ipprotscan) {
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 (!first)
log_write(LOG_MACHINE, ", ");
@@ -730,8 +705,10 @@ void printportoutput(Target * currenths, PortList * plist) {
}
}
} else {
char fullversion[160];
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 (!first)
log_write(LOG_MACHINE, ", ");
@@ -740,7 +717,7 @@ void printportoutput(Target * currenths, PortList * plist) {
strcpy(protocol, IPPROTO2STR(current->proto));
Snprintf(portinfo, sizeof(portinfo), "%d/%s", current->portno, protocol);
state = statenum2str(current->state);
current->getServiceDeductions(&sd);
plist->getServiceDeductions(current->portno, current->proto, &sd);
if (sd.service_fp && saved_servicefps.size() <= 8)
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) ? " " : "", rpcinfo);
} else {
getNmapServiceName(&sd, current->state, serviceinfo, sizeof(serviceinfo));
current->getNmapServiceName(serviceinfo, sizeof(serviceinfo));
rpcmachineinfo[0] = '\0';
}
Tbl->addItem(rowno, portcol, true, portinfo);
@@ -792,8 +769,9 @@ void printportoutput(Target * currenths, PortList * plist) {
if (o.reason)
Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason));
if (*sd.fullversion)
Tbl->addItem(rowno, versioncol, true, sd.fullversion);
sd.populateFullVersionString(fullversion, sizeof(fullversion));
if (*fullversion)
Tbl->addItem(rowno, versioncol, true, fullversion);
// How should we escape illegal chars in grepable output?
// 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
// ugly hat (fitting to grepable output) or replacing the '/'
// character with '|' in the version field.
Strncpy(grepvers, sd.fullversion, sizeof(grepvers) / sizeof(*grepvers));
Strncpy(grepvers, fullversion, sizeof(grepvers) / sizeof(*grepvers));
p = grepvers;
while ((p = strchr(p, '/'))) {
*p = '|';
@@ -840,7 +818,7 @@ void printportoutput(Target * currenths, PortList * plist) {
rowno++;
#ifndef NOLUA
if (o.script) {
ScriptResults::iterator ssr_iter;
ScriptResults::const_iterator ssr_iter;
for (ssr_iter = current->scriptResults.begin();
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) */
void printserviceinfooutput(Target * currenths) {
Port *p = NULL;
Port port;
struct serviceDeductions sd;
int i, numhostnames = 0, numostypes = 0, numdevicetypes = 0;
char hostname_tbl[MAX_SERVICE_INFO_FIELDS][MAXHOSTNAMELEN];
@@ -1917,12 +1896,12 @@ void printserviceinfooutput(Target * currenths) {
for (i = 0; i < MAX_SERVICE_INFO_FIELDS; i++)
hostname_tbl[i][0] = ostype_tbl[i][0] = devicetype_tbl[i][0] = '\0';
while ((p = currenths->ports.nextPort(p, 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
// worry about free()ing anything in the serviceDeductions struct. pass in
// an allocated struct serviceDeductions (don't wory about initializing, and
// you don't have to free any internal ptrs.
p->getServiceDeductions(&sd);
currenths->ports.getServiceDeductions(p->portno, p->proto, &sd);
if (sd.hostname && !hostcmp(currenths->HostName(), sd.hostname)) {
for (i = 0; i < MAX_SERVICE_INFO_FIELDS; i++) {

View File

@@ -109,42 +109,95 @@ extern NmapOps o; /* option structure */
Port::Port() {
portno = proto = 0;
rpc_status = RPC_STATUS_UNTESTED;
rpc_program = rpc_lowver = rpc_highver = 0;
state = 0;
serviceprobe_results = PROBESTATE_INITIAL;
serviceprobe_service = NULL;
serviceprobe_product = serviceprobe_version = serviceprobe_extrainfo = NULL;
serviceprobe_hostname = serviceprobe_ostype = serviceprobe_devicetype = NULL;
serviceprobe_tunnel = SERVICE_TUNNEL_NONE;
serviceprobe_fp = NULL;
service = NULL;
state_reason_init(&reason);
}
Port::~Port() {
if (serviceprobe_product)
free(serviceprobe_product);
if (serviceprobe_version)
free(serviceprobe_version);
if (serviceprobe_extrainfo)
free(serviceprobe_extrainfo);
if (serviceprobe_hostname)
free(serviceprobe_hostname);
if (serviceprobe_ostype)
free(serviceprobe_ostype);
if (serviceprobe_devicetype)
free(serviceprobe_devicetype);
if (serviceprobe_service)
free(serviceprobe_service);
if (serviceprobe_fp)
free(serviceprobe_fp);
if (service != NULL) {
if (service->name)
free(service->name);
if (service->product)
free(service->product);
if (service->version)
free(service->version);
if (service->extrainfo)
free(service->extrainfo);
if (service->hostname)
free(service->hostname);
if (service->ostype)
free(service->ostype);
if (service->devicetype)
free(service->devicetype);
if (service->service_fp)
free(service->service_fp);
delete service;
}
}
/* Fills in namebuf (as long as there is space in buflen) with the
Name nmap normal output will use to describe the port. This takes
into account to confidence level, any SSL tunneling, etc. Truncates
namebuf to 0 length if there is no room.*/
void Port::getNmapServiceName(char *namebuf, int buflen) const {
const char *tunnel_prefix;
const char *service_name;
int len;
if (service != NULL && service->service_tunnel == SERVICE_TUNNEL_SSL)
tunnel_prefix = "ssl/";
else
tunnel_prefix = "";
if (service != NULL && service->name != NULL) {
service_name = service->name;
} else {
struct servent *service;
service = nmap_getservbyport(htons(portno), IPPROTO2STR(proto));
if (service != NULL)
service_name = service->s_name;
else
service_name = NULL;
}
if (service_name != NULL && strcmp(service_name, "unknown") != 0) {
/* The port has a name and the name is not "unknown". How confident are we? */
if (o.servicescan && state == PORT_OPEN && (service == NULL || service->name_confidence <= 5))
len = Snprintf(namebuf, buflen, "%s%s?", tunnel_prefix, service_name);
else
len = Snprintf(namebuf, buflen, "%s%s", tunnel_prefix, service_name);
} else {
len = Snprintf(namebuf, buflen, "%sunknown", tunnel_prefix);
}
if (len >= buflen || len < 0)
namebuf[0] = '\0';
}
serviceDeductions::serviceDeductions() {
name = NULL;
name_confidence = 0;
product = NULL;
version = NULL;
extrainfo = NULL;
hostname = NULL;
ostype = NULL;
devicetype = NULL;
service_tunnel = SERVICE_TUNNEL_NONE;
service_fp = NULL;
dtype = SERVICE_DETECTION_TABLE;
rpc_status = RPC_STATUS_UNTESTED;
rpc_program = 0;
rpc_lowver = 0;
rpc_highver = 0;
}
// Uses the sd->{product,version,extrainfo} if available to fill
// out sd->fullversion. If unavailable, it will be set to zero length.
static void populateFullVersionString(struct serviceDeductions *sd) {
char *dst = sd->fullversion;
unsigned int spaceleft = sizeof(sd->fullversion) - 1; // Leave room for \0
void serviceDeductions::populateFullVersionString(char *buf, size_t n) const {
char *dst = buf;
unsigned int spaceleft = n - 1; // Leave room for \0
int needpad = 0; // Do we need to pad a space between the next template?
dst[0] = '\0';
@@ -156,52 +209,52 @@ static void populateFullVersionString(struct serviceDeductions *sd) {
* that bit of information.
*/
if (sd->product && spaceleft >= 8) {
if (spaceleft < strlen(sd->product)) {
strncat(dst, sd->product, spaceleft - 3); // Leave room for "..."
if (product && spaceleft >= 8) {
if (spaceleft < strlen(product)) {
strncat(dst, product, spaceleft - 3); // Leave room for "..."
strncat(dst, "...", spaceleft);
spaceleft = 0;
}
else {
strncat(dst, sd->product, spaceleft);
spaceleft -= strlen(sd->product);
strncat(dst, product, spaceleft);
spaceleft -= strlen(product);
}
needpad = 1;
}
if (sd->version && spaceleft >= 8) {
if (version && spaceleft >= 8) {
if (needpad) {
strncat(dst, " ", spaceleft);
spaceleft--;
}
if (spaceleft < strlen(sd->version)) {
strncat(dst, sd->version, spaceleft - 3);
if (spaceleft < strlen(version)) {
strncat(dst, version, spaceleft - 3);
strncat(dst, "...", spaceleft);
spaceleft = 0;
}
else {
strncat(dst, sd->version, spaceleft);
spaceleft -= strlen(sd->version);
strncat(dst, version, spaceleft);
spaceleft -= strlen(version);
}
needpad = 1;
}
if (sd->extrainfo && spaceleft >= 8) {
if (extrainfo && spaceleft >= 8) {
if (needpad) {
strncat(dst, " ", spaceleft);
spaceleft--;
}
// This time we need to trucate inside of the () so we have spaceleft - 2
strncat(dst, "(", spaceleft);
if (spaceleft - 2 < strlen(sd->extrainfo)) {
strncat(dst, sd->extrainfo, spaceleft - 5);
if (spaceleft - 2 < strlen(extrainfo)) {
strncat(dst, extrainfo, spaceleft - 5);
strncat(dst, "...", spaceleft - 2);
spaceleft = 1; // Fit the paren
}
else {
strncat(dst, sd->extrainfo, spaceleft);
spaceleft -= (strlen(sd->extrainfo) + 2);
strncat(dst, extrainfo, spaceleft);
spaceleft -= (strlen(extrainfo) + 2);
}
strncat(dst, ")", 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
// serviceDeductions definition for the fields that are populated.
// Returns 0 if at least a name is available.
int Port::getServiceDeductions(struct serviceDeductions *sd) {
struct servent *service;
const void PortList::getServiceDeductions(u16 portno, int protocol, struct serviceDeductions *sd) const {
const Port *port;
assert(sd);
memset(sd, 0, sizeof(struct serviceDeductions));
sd->service_fp = serviceprobe_fp;
sd->service_tunnel = serviceprobe_tunnel;
sd->rpc_status = rpc_status;
sd->rpc_program = rpc_program;
sd->rpc_lowver = rpc_lowver;
sd->rpc_highver = rpc_highver;
port = lookupPort(portno, protocol);
if (port == NULL || port->service == NULL) {
struct servent *service;
// First priority is RPC
if (rpc_status == RPC_STATUS_UNKNOWN || rpc_status == RPC_STATUS_GOOD_PROG ) {
assert(serviceprobe_service);
sd->name = serviceprobe_service;
sd->name_confidence = (rpc_status == RPC_STATUS_UNKNOWN)? 8 : 10;
sd->dtype = SERVICE_DETECTION_PROBED; // RPC counts as probed
sd->version = serviceprobe_version;
sd->extrainfo = serviceprobe_extrainfo;
sd->hostname = serviceprobe_hostname;
sd->ostype = serviceprobe_ostype;
sd->devicetype = serviceprobe_devicetype;
populateFullVersionString(sd);
return 0;
} else if (serviceprobe_results == PROBESTATE_FINISHED_HARDMATCHED
|| serviceprobe_results == PROBESTATE_FINISHED_SOFTMATCHED) {
assert(serviceprobe_service);
sd->dtype = SERVICE_DETECTION_PROBED;
sd->name = serviceprobe_service;
sd->name_confidence = 10;
sd->product = serviceprobe_product;
sd->version = serviceprobe_version;
sd->extrainfo = serviceprobe_extrainfo;
sd->hostname = serviceprobe_hostname;
sd->ostype = serviceprobe_ostype;
sd->devicetype = serviceprobe_devicetype;
populateFullVersionString(sd);
return 0;
} else if (serviceprobe_results == PROBESTATE_EXCLUDED) {
service = nmap_getservbyport(htons(portno), IPPROTO2STR(proto));
if (service) sd->name = service->s_name;
sd->name_confidence = 2; // Since we didn't even check it, we aren't very confident
sd->dtype = SERVICE_DETECTION_TABLE;
sd->product = serviceprobe_product; // Should have a string that says port was excluded
populateFullVersionString(sd);
return 0;
} else if (serviceprobe_results == PROBESTATE_FINISHED_TCPWRAPPED) {
sd->dtype = SERVICE_DETECTION_PROBED;
sd->name = "tcpwrapped";
sd->name_confidence = 8;
return 0;
}
// So much for service detection or RPC. Maybe we can find it in the file
service = nmap_getservbyport(htons(portno), IPPROTO2STR(proto));
if (service) {
sd->dtype = SERVICE_DETECTION_TABLE;
sd->name = service->s_name;
/* Look up the service name. */
*sd = serviceDeductions();
service = nmap_getservbyport(htons(portno), IPPROTO2STR(protocol));
if (service != NULL)
sd->name = service->s_name;
else
sd->name = NULL;
sd->name_confidence = 3;
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;
}
void Port::setServiceProbeResults(enum serviceprobestate sres,
const char *sname,
enum service_tunnel_type tunnel,
const char *product, const char *version,
const char *extrainfo, const char *hostname,
const char *ostype, const char *devicetype,
const char *fingerprint) {
void PortList::setServiceProbeResults(u16 portno, int protocol,
enum serviceprobestate sres, const char *sname,
enum service_tunnel_type tunnel, const char *product, const char *version,
const char *extrainfo, const char *hostname, const char *ostype,
const char *devicetype, const char *fingerprint) {
Port *port;
serviceprobe_results = sres;
serviceprobe_tunnel = tunnel;
port = createPort(portno, protocol);
if (port->service == NULL)
port->service = new serviceDeductions;
if (sname)
serviceprobe_service = strdup(sname);
else
serviceprobe_service = NULL;
if (sres == PROBESTATE_FINISHED_HARDMATCHED
|| sres == PROBESTATE_FINISHED_SOFTMATCHED) {
port->service->dtype = SERVICE_DETECTION_PROBED;
port->service->name_confidence = 10;
} else if (sres == PROBESTATE_EXCLUDED) {
if (sname == NULL) {
struct servent *service;
service = nmap_getservbyport(htons(portno), IPPROTO2STR(protocol));
if (service != NULL)
sname = service->s_name;
}
port->service->dtype = SERVICE_DETECTION_TABLE;
port->service->name_confidence = 2; // Since we didn't even check it, we aren't very confident
} else if (sres == PROBESTATE_FINISHED_TCPWRAPPED) {
port->service->dtype = SERVICE_DETECTION_PROBED;
if (sname == NULL)
sname = "tcpwrapped";
port->service->dtype = SERVICE_DETECTION_TABLE;
port->service->name_confidence = 8;
}
if (fingerprint)
serviceprobe_fp = strdup(fingerprint);
else
serviceprobe_fp = NULL;
// port->serviceprobe_results = sres;
port->service->service_tunnel = tunnel;
serviceprobe_product = cstringSanityCheck(product, 80);
serviceprobe_version = cstringSanityCheck(version, 80);
serviceprobe_extrainfo = cstringSanityCheck(extrainfo, 256);
serviceprobe_hostname = cstringSanityCheck(hostname, 80);
serviceprobe_ostype = cstringSanityCheck(ostype, 32);
serviceprobe_devicetype = cstringSanityCheck(devicetype, 32);
if (sname)
port->service->name = strdup(sname);
else
port->service->name = NULL;
if (fingerprint)
port->service->service_fp = strdup(fingerprint);
else
port->service->service_fp = NULL;
port->service->product = cstringSanityCheck(product, 80);
port->service->version = cstringSanityCheck(version, 80);
port->service->extrainfo = cstringSanityCheck(extrainfo, 256);
port->service->hostname = cstringSanityCheck(hostname, 80);
port->service->ostype = cstringSanityCheck(ostype, 32);
port->service->devicetype = cstringSanityCheck(devicetype, 32);
}
/* 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 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) {
rpc_status = rpcs;
Port *port;
const char *newsvc;
char verbuf[128];
rpc_status = rpcs;
if (rpc_status == RPC_STATUS_GOOD_PROG) {
rpc_program = rpcp;
rpc_lowver = rpcl;
rpc_highver = rpch;
port = createPort(portno, proto);
if (port->service == NULL)
port->service = new serviceDeductions;
port->service->rpc_status = rpcs;
if (port->service->rpc_status == RPC_STATUS_GOOD_PROG) {
port->service->rpc_program = rpcp;
port->service->rpc_lowver = rpcl;
port->service->rpc_highver = rpch;
// Now set the service/version info
newsvc = nmap_getrpcnamebynum(rpcp);
if (!newsvc) newsvc = "rpc.unknownprog"; // should never happen
if (serviceprobe_service)
free(serviceprobe_service);
serviceprobe_service = strdup(newsvc);
serviceprobe_product = strdup(newsvc);
if (rpc_lowver == rpc_highver)
Snprintf(verbuf, sizeof(verbuf), "%i", rpc_lowver);
if (port->service->name)
free(port->service->name);
port->service->name = strdup(newsvc);
if (port->service->rpc_lowver == port->service->rpc_highver)
Snprintf(verbuf, sizeof(verbuf), "%i", port->service->rpc_lowver);
else
Snprintf(verbuf, sizeof(verbuf), "%i-%i", rpc_lowver, rpc_highver);
serviceprobe_version = strdup(verbuf);
Snprintf(verbuf, sizeof(verbuf), "rpc #%li", rpc_program);
serviceprobe_extrainfo = strdup(verbuf);
} else if (rpc_status == RPC_STATUS_UNKNOWN) {
if (serviceprobe_service)
free(serviceprobe_service);
Snprintf(verbuf, sizeof(verbuf), "%i-%i", port->service->rpc_lowver, port->service->rpc_highver);
port->service->version = strdup(verbuf);
Snprintf(verbuf, sizeof(verbuf), "rpc #%li", port->service->rpc_program);
port->service->extrainfo = strdup(verbuf);
port->service->name_confidence = 10;
port->service->dtype = SERVICE_DETECTION_PROBED;
} else if (port->service->rpc_status == RPC_STATUS_UNKNOWN) {
if (port->service->name)
free(port->service->name);
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.
* 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 : \
PORTLIST_PROTO_IP)
#define PORTLISTPROTO2INPROTO(p) \
((p)==PORTLIST_PROTO_TCP ? IPPROTO_TCP : \
(p)==PORTLIST_PROTO_UDP ? IPPROTO_UDP : \
(p)==PORTLIST_PROTO_SCTP ? IPPROTO_SCTP : \
IPPROTO_IP)
PortList::PortList() {
int proto;
@@ -396,9 +445,11 @@ PortList::PortList() {
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) {
if(port_list_count[proto] > 0)
port_list[proto] = (Port**) safe_zalloc(sizeof(Port*)*port_list_count[proto]);
default_port_state[proto].proto = PORTLISTPROTO2INPROTO(proto);
default_port_state[proto].reason.reason_id = ER_NORESPONSE;
state_counts_proto[proto][default_port_state[proto].state] = port_list_count[proto];
}
numports = 0;
numscriptresults = 0;
idstr = NULL;
}
@@ -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;
int proto = INPROTO2PORTLISTPROTO(protocol);
@@ -445,55 +510,35 @@ int PortList::addPort(u16 portno, u8 protocol, int state) {
assert(protocol!=IPPROTO_IP || portno<256);
current = getPortEntry(portno, protocol);
if (current) {
oldport = lookupPort(portno, protocol);
if (oldport != NULL) {
/* We must discount our statistics from the old values. Also warn
if a complete duplicate */
if (o.debugging && current->state == state) {
if (o.debugging && oldport->state == state) {
error("Duplicate port (%hu/%s)", portno, proto2ascii(protocol));
}
state_counts_proto[proto][current->state]--;
state_counts_proto[proto][oldport->state]--;
} else {
current = new Port();
current->portno = portno;
current->proto = protocol;
numports++;
setPortEntry(portno, protocol, current);
state_counts_proto[proto][default_port_state[proto].state]--;
}
current = createPort(portno, protocol);
current->state = state;
state_counts_proto[proto][state]++;
if(state == PORT_FILTERED || state == PORT_OPENFILTERED)
setStateReason(portno, protocol, ER_NORESPONSE, 0, 0);
return 0; /*success */
return;
}
int PortList::removePort(u16 portno, u8 protocol) {
Port *answer = NULL;
int PortList::getPortState(u16 portno, u8 protocol) {
const Port *port;
log_write(LOG_PLAIN, "Removed %d\n", portno);
answer = getPortEntry(portno, protocol);
if (!answer)
port = lookupPort(portno, protocol);
if (port == NULL)
return -1;
setPortEntry(portno, protocol, NULL);
if (o.verbose) {
log_write(LOG_STDOUT, "Deleting port %hu/%s, which we thought was %s\n",
portno, proto2ascii(answer->proto),
statenum2str(answer->state));
log_flush(LOG_STDOUT);
}
/* Discount statistics */
state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][answer->state]--;
numports--;
delete answer;
return 0;
return port->state;
}
/* 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){
return(state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][state]);
return state_counts_proto[INPROTO2PORTLISTPROTO(protocol)][state];
}
int PortList::getStateCounts(int state){
int sum=0, proto;
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++)
sum += state_counts_proto[proto][state];
sum += getStateCounts(PORTLISTPROTO2INPROTO(proto), state);
return(sum);
}
@@ -532,19 +577,19 @@ int PortList::getStateCounts(int state){
function returns ports in numeric order from lowest to highest,
except that if you ask for both TCP, UDP & SCTP, every TCP port
will be returned before we start returning UDP and SCTP ports */
Port *PortList::nextPort(Port *afterthisport,
Port *PortList::nextPort(const Port *cur, Port *next,
int allowed_protocol, int allowed_state) {
int proto;
int mapped_pno;
Port *port;
if(afterthisport) {
proto = INPROTO2PORTLISTPROTO(afterthisport->proto);
if (cur) {
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(afterthisport->proto!=IPPROTO_IP || afterthisport->portno<256);
mapped_pno = port_map[proto][afterthisport->portno];
assert(cur->proto!=IPPROTO_IP || cur->portno<256);
mapped_pno = port_map[proto][cur->portno];
mapped_pno++; // we're interested in next port after current
}else { // running for the first time
} else { // running for the first time
if (allowed_protocol == TCPANDUDPANDSCTP)
proto = INPROTO2PORTLISTPROTO(IPPROTO_TCP);
else if (allowed_protocol == UDPANDSCTP)
@@ -557,78 +602,128 @@ Port *PortList::nextPort(Port *afterthisport,
if(port_list[proto] != NULL) {
for(;mapped_pno < port_list_count[proto]; mapped_pno++) {
port = port_list[proto][mapped_pno];
if(port && (allowed_state==0 || port->state==allowed_state))
return(port);
if (port && (allowed_state==0 || port->state==allowed_state)) {
*next = *port;
return next;
}
if (!port && (allowed_state==0 || default_port_state[proto].state==allowed_state)) {
*next = default_port_state[proto];
next->portno = port_map_rev[proto][mapped_pno];
return next;
}
}
}
/* if all protocols, than after TCP search UDP & SCTP */
if((!afterthisport && allowed_protocol == TCPANDUDPANDSCTP) ||
(afterthisport && proto == INPROTO2PORTLISTPROTO(IPPROTO_TCP)))
return(nextPort(NULL, UDPANDSCTP, allowed_state));
if((!cur && allowed_protocol == TCPANDUDPANDSCTP) ||
(cur && proto == INPROTO2PORTLISTPROTO(IPPROTO_TCP)))
return(nextPort(NULL, next, UDPANDSCTP, allowed_state));
/* if all protocols, than after UDP search SCTP */
if((!afterthisport && allowed_protocol == UDPANDSCTP) ||
(afterthisport && proto == INPROTO2PORTLISTPROTO(IPPROTO_UDP)))
return(nextPort(NULL, IPPROTO_SCTP, allowed_state));
if((!cur && allowed_protocol == UDPANDSCTP) ||
(cur && proto == INPROTO2PORTLISTPROTO(IPPROTO_UDP)))
return(nextPort(NULL, next, IPPROTO_SCTP, allowed_state));
return(NULL);
}
Port *PortList::getPortEntry(u16 portno, u8 protocol) {
int proto = INPROTO2PORTLISTPROTO(protocol);
int mapped_pno;
/* Convert portno and protocol into the internal indices used to index
port_list. Returns false on error, true otherwise. */
bool PortList::mapPort(u16 *portno, u8 *protocol) const {
int mapped_portno, mapped_protocol;
assert(protocol!=IPPROTO_IP || portno<256);
if(port_map[proto]==NULL || port_list[proto]==NULL)
fatal("%s(%i,%i): you're trying to access uninitialized protocol", __func__, portno, protocol);
mapped_pno = port_map[proto][portno];
mapped_protocol = INPROTO2PORTLISTPROTO(*protocol);
assert(mapped_pno < port_list_count[proto]);
assert(mapped_pno >= 0);
if (*protocol == IPPROTO_IP)
assert(*portno < 256);
if(port_map[mapped_protocol]==NULL || port_list[mapped_protocol]==NULL)
fatal("%s(%i,%i): you're trying to access uninitialized protocol", __func__, *portno, *protocol);
mapped_portno = port_map[mapped_protocol][*portno];
/* The ugly hack: we allow only port 0 to be mapped to 0 position */
if(mapped_pno==0 && portno!=0) {
error("WARNING: %s(%i,%i): this port was not mapped", __func__, portno, protocol);
return(NULL);
}else
return(port_list[proto][mapped_pno]);
assert(mapped_portno < port_list_count[mapped_protocol]);
assert(mapped_portno >= 0);
*portno = mapped_portno;
*protocol = mapped_protocol;
return true;
}
void PortList::setPortEntry(u16 portno, u8 protocol, Port *port) {
int proto = INPROTO2PORTLISTPROTO(protocol);
int mapped_pno;
const Port *PortList::lookupPort(u16 portno, u8 protocol) const {
if (!mapPort(&portno, &protocol))
return NULL;
assert(protocol!=IPPROTO_IP || portno<256);
if(port_map[proto]==NULL || port_list[proto]==NULL)
fatal("%s(%i,%i): you're trying to access uninitialized protocol", __func__, portno, protocol);
mapped_pno = port_map[proto][portno];
return port_list[protocol][portno];
}
assert(mapped_pno < port_list_count[proto]);
assert(mapped_pno >= 0);
/* Create the port if it doesn't exist; otherwise this is like lookupPort. */
Port *PortList::createPort(u16 portno, u8 protocol) {
u16 mapped_portno;
u8 mapped_protocol;
/* The ugly hack: we allow only port 0 to be mapped to 0 position */
if(mapped_pno==0 && portno!=0) {
error("WARNING: %s(%i,%i): this port was not mapped", __func__, portno, protocol);
return;
mapped_portno = portno;
mapped_protocol = protocol;
if (!mapPort(&mapped_portno, &mapped_protocol))
return NULL;
if (port_list[mapped_protocol][mapped_portno] == NULL) {
Port *p = new Port();
p->portno = portno;
p->proto = protocol;
port_list[mapped_protocol][mapped_portno] = p;
}
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
* before closing nmap. */
void PortList::freePortMap(){
int proto;
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++)
for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) {
if(port_map[proto]){
free(port_map[proto]);
port_map[proto] = NULL;
}
if (port_map_rev[proto]) {
free(port_map_rev[proto]);
port_map_rev[proto] = NULL;
}
}
}
u16 *PortList::port_map[PORTLIST_PROTO_MAX];
u16 *PortList::port_map_rev[PORTLIST_PROTO_MAX];
int PortList::port_list_count[PORTLIST_PROTO_MAX];
/* This function must be runned before any PortList object is created.
@@ -636,38 +731,27 @@ int PortList::port_list_count[PORTLIST_PROTO_MAX];
* should be sorted. */
void PortList::initializePortMap(int protocol, u16 *ports, int portcount) {
int i;
int unused_zero; // aren't we using 0 port?
int ports_max = (protocol == IPPROTO_IP) ? 256 : 65536;
int proto = INPROTO2PORTLISTPROTO(protocol);
if(port_map[proto]!=NULL)
if (port_map[proto] != NULL || port_map_rev[proto] != NULL)
fatal("%s: portmap for protocol %i already initialized", __func__, protocol);
assert(port_list_count[proto]==0);
/* this memory will never be freed, but this is the way it has to be. */
port_map[proto] = (u16*) safe_zalloc(sizeof(u16)*ports_max);
port_map[proto] = (u16 *) safe_zalloc(sizeof(u16) * ports_max);
port_map_rev[proto] = (u16 *) safe_zalloc(sizeof(u16) * portcount);
/* Is zero port to be unused? */
if(portcount==0 || ports[0]!=0)
unused_zero = 1;
else
unused_zero = 0;
/* The ugly hack: if we don't use 0 port, than we need one more extra element. */
port_list_count[proto] = portcount + unused_zero;
port_list_count[proto] = portcount;
for(i=0; i < portcount; i++) {
/* The ugly hack: if we don't use 0 port, than we must start counting from 1 */
port_map[proto][ports[i]] = i + unused_zero; // yes, this is the key line
port_map[proto][ports[i]] = i;
port_map_rev[proto][i] = ports[i];
}
/* So now port_map should have such structure (lets scan 2nd,4th and 6th port):
* port_map[0,0,1,0,2,0,3,...] <- indexes to port_list structure
* port_list[0,port_2,port_4,port_6]
* But if we scan 0, 2, and 4 port:
* port_map[0,0,1,0,2,...] // yes, this 0 in first place isn't mistake
* port_list[port_0,port_2,port_4]
* And in both cases we scan three ports. Ugly, isn't it? :) */
* port_list[port_2,port_4,port_6] */
}
/* Cycles through the 0 or more "ignored" ports which should be
@@ -761,20 +845,26 @@ int PortList::numIgnoredPorts() {
return numports;
}
int PortList::numPorts() const {
int proto, num = 0;
for (proto = 0; proto < PORTLIST_PROTO_MAX; proto++)
num += port_list_count[proto];
return num;
}
int PortList::setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr) {
Port *answer = NULL;
if(!(answer = getPortEntry(portno, proto)))
return -1;
if(reason > ER_MAX)
return -1;
answer = createPort(portno, proto);
/* set new reason and increment its count */
answer->reason.reason_id = reason;
answer->reason.ip_addr.s_addr = ip_addr;
answer->reason.ttl = ttl;
answer->reason.state = answer->state;
setPortEntry(portno, proto, answer);
return 0;
}

View File

@@ -140,25 +140,25 @@ enum service_tunnel_type { SERVICE_TUNNEL_NONE, SERVICE_TUNNEL_SSL };
void random_port_cheat(u16 *ports, int portcount);
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
// confident) expressing how accurate the service detection is
// likely to be.
int name_confidence;
// Any of these 6 can be NULL if we weren't able to determine it
const char *product;
const char *version;
const char *extrainfo;
const char *hostname;
const char *ostype;
const char *devicetype;
char *product;
char *version;
char *extrainfo;
char *hostname;
char *ostype;
char *devicetype;
// SERVICE_TUNNEL_NONE or SERVICE_TUNNEL_SSL
enum service_tunnel_type service_tunnel;
// This is a combined representation of product, version, and extrainfo.
// It will be zero length if unavailable.
char fullversion[160];
// if we should give the user a service fingerprint to submit, here it is. Otherwise NULL.
const char *service_fp;
char *service_fp;
enum service_detection_type dtype; // definition above
int rpc_status; /* RPC_STATUS_UNTESTED means we haven't checked
RPC_STATUS_UNKNOWN means the port appears to be RPC
@@ -173,38 +173,12 @@ struct serviceDeductions {
};
class Port {
friend class PortList;
public:
Port();
~Port();
// 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);
void getNmapServiceName(char *namebuf, int buflen) const;
u16 portno;
u8 proto;
@@ -216,28 +190,10 @@ class Port {
#endif
private:
int rpc_status; /* RPC_STATUS_UNTESTED means we haven't checked
RPC_STATUS_UNKNOWN means the port appears to be RPC
but we couldn't find a match
RPC_STATUS_GOOD_PROG means rpc_program gives the prog #
RPC_STATUS_NOT_RPC means the port doesn't appear to
be RPC */
unsigned long rpc_program; /* Only valid if rpc_state == RPC_STATUS_GOOD_PROG */
unsigned int rpc_lowver;
unsigned int rpc_highver;
enum serviceprobestate serviceprobe_results; // overall results of service scan
char *serviceprobe_service; // If a service was discovered, points to the name
// Any of these next three can be NULL if the details are not available
char *serviceprobe_product;
char *serviceprobe_version;
char *serviceprobe_extrainfo;
char *serviceprobe_hostname;
char *serviceprobe_ostype;
char *serviceprobe_devicetype;
enum service_tunnel_type serviceprobe_tunnel;
// A fingerprint that the user can submit if the service wasn't recognized
char *serviceprobe_fp;
/* This is allocated only on demand by PortList::setServiceProbeResults or
PortList::setRPCProbeResults, to save memory for the many closed or
filtered ports that don't need it. */
serviceDeductions *service;
};
@@ -261,10 +217,10 @@ class PortList {
/* Free memory used by port_map. It should be done somewhere before quitting*/
static void freePortMap();
/* Add a new port to this list. If the state has changed, it is
OK to call this function to effect the change */
int addPort(u16 portno, u8 protocol, int state);
int removePort(u16 portno, u8 protocol);
void setDefaultPortState(u8 protocol, int state);
void setPortState(u16 portno, u8 protocol, int state);
int getPortState(u16 portno, u8 protocol);
int forgetPort(u16 portno, u8 protocol);
/* Saves an identification string for the target containing these
ports (an IP addrss might be a good example, but set what you
want). Only used when printing new port updates. Optional. A
@@ -280,17 +236,11 @@ class PortList {
function returns ports in numeric order from lowest to highest,
except that if you ask for TCP, UDP & SCTP, all TCP ports will be
returned before we start returning UDP and finally SCTP ports */
Port *nextPort(Port *afterthisport,
int allowed_protocol, int allowed_state);
/* Get Port structure from PortList structure.*/
Port *getPortEntry(u16 portno, u8 protocol);
/* Set Port structure to PortList structure.*/
void setPortEntry(u16 portno, u8 protocol, Port *port);
Port *nextPort(const Port *cur, Port *next,
int allowed_protocol, int allowed_state);
int setStateReason(u16 portno, u8 proto, reason_t reason, u8 ttl, u32 ip_addr);
int numports; /* Total number of ports in list in ANY state */
int numscriptresults; /* Total number of scripts which produced output */
/* Get number of ports in this state. This a sum for protocols. */
@@ -298,6 +248,38 @@ class PortList {
/* Get number of ports in this state for requested protocol. */
int getStateCounts(int protocol, int state);
// sname should be NULL if sres is not
// PROBESTATE_FINISHED_MATCHED. product,version, and/or extrainfo
// will be NULL if unavailable. Note that this function makes its
// own copy of sname and product/version/extrainfo. This function
// also takes care of truncating the version strings to a
// 'reasonable' length if neccessary, and cleaning up any unprinable
// chars. (these tests are to avoid annoying DOS (or other) attacks
// by malicious services). The fingerprint should be NULL unless
// one is available and the user should submit it. tunnel must be
// SERVICE_TUNNEL_NULL (normal) or SERVICE_TUNNEL_SSL (means ssl was
// detected and we tried to tunnel through it ).
void setServiceProbeResults(u16 portno, int protocol,
enum serviceprobestate sres, const char *sname,
enum service_tunnel_type tunnel, const char *product,
const char *version, const char *hostname,
const char *ostype, const char *devicetype,
const char *extrainfo, const char *fingerprint);
// pass in an allocated struct serviceDeductions (don't worry about initializing, and
// you don't have to free any internal ptrs. See the serviceDeductions definition for
// the fields that are populated. Returns 0 if at least a name is available.
const void getServiceDeductions(u16 portno, int protocol, struct serviceDeductions *sd) const;
/* Sets the results of an RPC scan. if rpc_status is not
RPC_STATUS_GOOD_PROGRAM, pass 0 for the other args. This function
takes care of setting the port's service and version
appropriately. */
void setRPCProbeResults(u16 portno, int proto, int rpc_status, unsigned long rpc_program,
unsigned int rpc_lowver, unsigned int rpc_highver);
void addScriptResult(u16 portno, int protocol, ScriptResult& sr);
/* Cycles through the 0 or more "ignored" ports which should be
consolidated for Nmap output. They are returned sorted by the
number of prots in the state, starting with the most common. It
@@ -313,12 +295,20 @@ class PortList {
int numIgnoredStates();
int numIgnoredPorts();
int numPorts() const;
private:
bool mapPort(u16 *portno, u8 *protocol) const;
/* Get Port structure from PortList structure.*/
const Port *lookupPort(u16 portno, u8 protocol) const;
Port *createPort(u16 portno, u8 protocol);
/* Set Port structure to PortList structure.*/
void setPortEntry(u16 portno, u8 protocol, Port *port);
/* A string identifying the system these ports are on. Just used for
printing open ports, if it is set with setIdStr() */
char *idstr;
/* Number of ports in each state per each protocol */
/* Number of ports in each state per each protocol. */
int state_counts_proto[PORTLIST_PROTO_MAX][PORT_HIGHEST_STATE];
Port **port_list[PORTLIST_PROTO_MAX];
protected:
@@ -326,8 +316,10 @@ class PortList {
* Only functions: getPortEntry, setPortEntry, initializePortMap and
* nextPort should access this structure directly. */
static u16 *port_map[PORTLIST_PROTO_MAX];
static u16 *port_map_rev[PORTLIST_PROTO_MAX];
/* Number of allocated elements in port_list per each protocol. */
static int port_list_count[PORTLIST_PROTO_MAX];
Port default_port_state[PORTLIST_PROTO_MAX];
};
#endif

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

View File

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

View File

@@ -1103,33 +1103,6 @@ static bool pingprobe_is_appropriate(const UltraScanInfo *USI,
return false;
}
/* For the given scan type, this returns the port/host state demonstrated
by getting no response back */
static int scantype_no_response_means(stype scantype) {
switch(scantype) {
case SYN_SCAN:
case ACK_SCAN:
case WINDOW_SCAN:
case CONNECT_SCAN:
case SCTP_INIT_SCAN:
return PORT_FILTERED;
case UDP_SCAN:
case IPPROT_SCAN:
case NULL_SCAN:
case FIN_SCAN:
case MAIMON_SCAN:
case XMAS_SCAN:
case SCTP_COOKIE_ECHO_SCAN:
return PORT_OPENFILTERED;
case PING_SCAN:
case PING_SCAN_ARP:
return HOST_DOWN;
default:
fatal("Unexpected scan type found in %s()", __func__);
}
return 0; /* Unreached */
}
HostScanStats::HostScanStats(Target *t, UltraScanInfo *UltraSI) {
target = t;
USI=UltraSI;
@@ -1497,6 +1470,46 @@ static void init_perf_values(struct ultra_scan_performance_vars *perf) {
perf->tryno_cap = o.getMaxRetransmissions();
}
/* Initialize the state for ports that don't receive a response in all the
targets. */
static void set_default_port_state(vector<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
mucking with it. */
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;
}
set_default_port_state(Targets, scantype);
init_perf_values(&perf);
/* 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;
u8 proto = 0;
int oldstate = PORT_TESTING;
Port *currentp;
/* Whether no response means a port is open */
bool noresp_open_scan = USI->noresp_open_scan;
@@ -2616,13 +2630,11 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
portno = pspec->pd.sctp.dport;
} else assert(0);
/* First figure out the current state */
currentp = hss->target->ports.getPortEntry(portno, proto);
if (!currentp) {
oldstate = hss->target->ports.getPortState(portno, proto);
if (oldstate == -1) {
oldstate = PORT_TESTING;
hss->ports_finished++;
}
else oldstate = currentp->state;
/* printf("TCP port %hu has changed from state %s to %s!\n", portno, statenum2str(oldstate), statenum2str(newstate)); */
switch(oldstate) {
@@ -2631,25 +2643,25 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
in a SYN scan, but not neccessarily for UDP scan */
case PORT_TESTING:
/* Brand new port -- add it to the list */
hss->target->ports.addPort(portno, proto, newstate);
hss->target->ports.setPortState(portno, proto, newstate);
break;
case PORT_OPEN:
if (newstate != PORT_OPEN) {
if (noresp_open_scan) {
hss->target->ports.addPort(portno, proto, newstate);
hss->target->ports.setPortState(portno, proto, newstate);
} /* Otherwise The old open takes precendence */
}
break;
case PORT_CLOSED:
if (newstate != PORT_CLOSED) {
if (!noresp_open_scan && newstate != PORT_FILTERED)
hss->target->ports.addPort(portno, proto, newstate);
hss->target->ports.setPortState(portno, proto, newstate);
}
break;
case PORT_FILTERED:
if (newstate != PORT_FILTERED) {
if (!noresp_open_scan || newstate != PORT_OPEN)
hss->target->ports.addPort(portno, proto, newstate);
hss->target->ports.setPortState(portno, proto, newstate);
}
break;
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,
though I don't expect that to ever happen */
if (newstate == PORT_OPEN || newstate == PORT_CLOSED)
hss->target->ports.addPort(portno, proto, newstate);
hss->target->ports.setPortState(portno, proto, newstate);
break;
case PORT_OPENFILTERED:
if (newstate != PORT_OPENFILTERED) {
hss->target->ports.addPort(portno, proto, newstate);
hss->target->ports.setPortState(portno, proto, newstate);
}
break;
default:
@@ -2700,18 +2712,16 @@ void HostScanStats::boostScanDelay() {
sdn.goodRespSinceDelayChanged = 0;
}
/* Dismiss all probe attempts on bench -- the ports are marked
'filtered' or whatever is appropriate for having no response */
/* Dismiss all probe attempts on bench -- hosts are marked down and ports will
be set to whatever the default port state is for the scan. */
void HostScanStats::dismissBench() {
int newstate;
if (probe_bench.empty()) return;
newstate = scantype_no_response_means(USI->scantype);
while(!probe_bench.empty()) {
if (USI->ping_scan)
ultrascan_host_pspec_update(USI, this, &probe_bench.back(), newstate);
else
ultrascan_port_pspec_update(USI, this, &probe_bench.back(), newstate);
ultrascan_host_pspec_update(USI, this, &probe_bench.back(), HOST_DOWN);
/* Nothing to do if !USI->ping_scan. ultrascan_port_pspec_update would
allocate a Port object but we rely on the default port state to save
memory. */
probe_bench.pop_back();
}
bench_tryno = 0;
@@ -2719,7 +2729,6 @@ void HostScanStats::dismissBench() {
/* Move all members of bench to retry_stack for probe retransmission */
void HostScanStats::retransmitBench() {
int newstate;
if (probe_bench.empty()) return;
/* Move all contents of probe_bench to the end of retry_stack, updating retry_stack_tries accordingly */
@@ -2728,7 +2737,6 @@ void HostScanStats::retransmitBench() {
bench_tryno);
assert(retry_stack.size() == retry_stack_tries.size());
probe_bench.erase(probe_bench.begin(), probe_bench.end());
newstate = scantype_no_response_means(USI->scantype);
bench_tryno = 0;
}
@@ -4929,7 +4937,6 @@ static void processData(UltraScanInfo *USI) {
list<UltraProbe *>::iterator probeI, nextProbeI;
HostScanStats *host = NULL;
UltraProbe *probe = NULL;
int newstate;
unsigned int maxtries = 0;
bool scanmaybedone = true; /* The whole scan is not yet done */
int expire_us = 0;
@@ -4995,19 +5002,20 @@ static void processData(UltraScanInfo *USI) {
if (!probe->isPing() && probe->timedout && !probe->retransmitted) {
if (!tryno_mayincrease && probe->tryno >= maxtries) {
newstate = scantype_no_response_means(USI->scantype);
if (USI->ping_scan)
ultrascan_host_probe_update(USI, host, probeI, newstate, NULL);
else
ultrascan_port_probe_update(USI, host, probeI, newstate, NULL);
if (host->target->reason.reason_id == ER_UNKNOWN)
host->target->reason.reason_id = ER_NORESPONSE;
if (tryno_capped && !host->retry_capped_warned) {
log_write(LOG_PLAIN, "Warning: %s giving up on port because"
" retransmission cap hit (%d).\n", host->target->targetipstr(),
probe->tryno);
host->retry_capped_warned = true;
}
if (USI->ping_scan) {
ultrascan_host_probe_update(USI, host, probeI, HOST_DOWN, NULL);
} else {
/* No ultrascan_port_probe_update because that allocates a Port
object; the default port state as set by setDefaultPortState
handles these no-response ports. */
host->destroyOutstandingProbe(probeI);
}
continue;
} else if (probe->tryno >= maxtries &&
TIMEVAL_SUBTRACT(USI->now, probe->sent) > expire_us) {
@@ -5258,8 +5266,8 @@ void bounce_scan(Target *target, u16 *portarray, int numports,
perror("recv problem from FTP bounce server");
} else if (res == 0) {
if (timedout)
target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_FILTERED);
else target->ports.addPort(portarray[i], IPPROTO_TCP, PORT_CLOSED);
target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_FILTERED);
else target->ports.setPortState(portarray[i], IPPROTO_TCP, PORT_CLOSED);
} else {
recvbuf[res] = '\0';
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);
}
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') {
res = recvtime(sd, recvbuf, 2048,5, NULL);
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 (recvbuf[0] == '4' && recvbuf[1] == '2' &&
recvbuf[2] == '6') {
target->ports.removePort(portarray[i], IPPROTO_TCP);
target->ports.forgetPort(portarray[i], IPPROTO_TCP);
if (o.debugging || o.verbose)
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 {
/* 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;
struct serviceDeductions sd;
bool doingOpenFiltered = false;
Port port;
ScanProgressMeter *SPM = NULL;
@@ -5434,11 +5443,11 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
while(1) {
if (doingOpenFiltered) {
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port,
TCPANDUDPANDSCTP,
&port, TCPANDUDPANDSCTP,
PORT_OPENFILTERED);
} else {
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port,
TCPANDUDPANDSCTP,
&port, TCPANDUDPANDSCTP,
PORT_OPEN);
if (!rsi.rpc_current_port && !o.servicescan) {
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
if (!rsi.rpc_current_port)
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 &&
strcmp(sd.name, "rpcbind") == 0)
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 */
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);
/* 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
Target *target; // the port belongs to this target host
Port *port; // The Port that this service represents (this copy is taken from inside Target)
// if a match is found, it is placed here. Otherwise NULL
const char *probe_matched;
// If a match is found, any product/version/info/hostname/ostype/devicetype
@@ -1339,7 +1338,6 @@ ServiceNFO::ServiceNFO(AllProbes *newAP) {
AP = newAP;
currentresp = NULL;
currentresplen = 0;
port = NULL;
product_matched[0] = version_matched[0] = extrainfo_matched[0] = '\0';
hostname_matched[0] = ostype_matched[0] = devicetype_matched[0] = '\0';
tunnel = SERVICE_TUNNEL_NONE;
@@ -1633,6 +1631,7 @@ ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) {
unsigned int targetno;
ServiceNFO *svc;
Port *nxtport;
Port port;
int desired_par;
struct timeval now;
num_hosts_timedout = 0;
@@ -1644,12 +1643,11 @@ ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) {
num_hosts_timedout++;
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->target = Targets[targetno];
svc->portno = nxtport->portno;
svc->proto = nxtport->proto;
svc->port = nxtport;
services_remaining.push_back(svc);
}
}
@@ -1662,12 +1660,11 @@ ServiceGroup::ServiceGroup(vector<Target *> &Targets, AllProbes *AP) {
if (Targets[targetno]->timedOut(&now)) {
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->target = Targets[targetno];
svc->portno = nxtport->portno;
svc->proto = nxtport->proto;
svc->port = nxtport;
services_remaining.push_back(svc);
}
}
@@ -1703,8 +1700,8 @@ static void adjustPortStateIfNeccessary(ServiceNFO *svc) {
char host[128];
if (svc->port->state == PORT_OPENFILTERED) {
svc->target->ports.addPort(svc->portno, svc->proto, PORT_OPEN);
if (svc->target->ports.getPortState(svc->portno, svc->proto) == PORT_OPENFILTERED) {
svc->target->ports.setPortState(svc->portno, svc->proto, PORT_OPEN);
if (svc->proto == IPPROTO_TCP)
svc->target->ports.setStateReason(svc->portno, svc->proto, ER_TCPRESPONSE, 0, 0);
if (svc->proto == IPPROTO_UDP)
@@ -2318,7 +2315,8 @@ list<ServiceNFO *>::iterator svc;
for(svc = SG->services_finished.begin(); svc != SG->services_finished.end(); svc++) {
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)->tunnel,
*(*svc)->product_matched? (*svc)->product_matched : NULL,
@@ -2329,7 +2327,8 @@ list<ServiceNFO *>::iterator svc;
*(*svc)->devicetype_matched? (*svc)->devicetype_matched : NULL,
shouldWePrintFingerprint(*svc) ? (*svc)->getServiceFingerprint(NULL) : NULL);
} 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)->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,
IPPROTO2STR(svc->proto));
svc->port->setServiceProbeResults(PROBESTATE_EXCLUDED, NULL,
svc->target->ports.setServiceProbeResults(svc->portno, svc->proto,
PROBESTATE_EXCLUDED, NULL,
SERVICE_TUNNEL_NONE,
"Excluded from version scan", NULL,
NULL, NULL, NULL, NULL, NULL);