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:
12
idle_scan.cc
12
idle_scan.cc
@@ -926,7 +926,7 @@ static int idle_treescan(struct idle_proxy_info *proxy, Target *target,
|
||||
/* If our first count erroneously found and added an open port,
|
||||
we must delete it */
|
||||
if (firstHalfSz == 1 && flatcount1 == 1 && retrycount == 0)
|
||||
target->ports.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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
13
nse_main.cc
13
nse_main.cc
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
21
osscan2.cc
21
osscan2.cc
@@ -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. */
|
||||
|
||||
59
output.cc
59
output.cc
@@ -202,7 +202,7 @@ static char *xml_sf_convert(const char *str) {
|
||||
// the service name or the service fingerprint is non-null.
|
||||
// Returns a pointer to a buffer containing the element,
|
||||
// you will have to call free on it.
|
||||
static char *getServiceXMLBuf(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++) {
|
||||
|
||||
594
portlist.cc
594
portlist.cc
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
142
portlist.h
142
portlist.h
@@ -140,25 +140,25 @@ enum service_tunnel_type { SERVICE_TUNNEL_NONE, SERVICE_TUNNEL_SSL };
|
||||
void random_port_cheat(u16 *ports, int portcount);
|
||||
|
||||
struct serviceDeductions {
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
140
scan_engine.cc
140
scan_engine.cc
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user