Skip to content

Commit

Permalink
Enhance output to print proto, reason, and port list for ignored ports
Browse files Browse the repository at this point in the history
Normal output will report count, protocol, and reason for each group of
ports in an ignored state (usually closed or filtered when there are
more than 25 ports in one of those states).

XML output will contain a consolidated list of port numbers as well.
  • Loading branch information
bonsaiviking committed Dec 17, 2020
1 parent 19daadf commit 38671f2
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 158 deletions.
140 changes: 73 additions & 67 deletions output.cc
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ static char *formatScriptOutput(const ScriptResult &sr) {
}
#endif /* NOLUA */

/* Output a list of ports, compressing ranges like 80-85 */
static void output_rangelist_given_ports(int logt, unsigned short *ports, int numports);

/* Prints the familiar Nmap tabular output showing the "interesting"
ports found on the machine. It also handles the Machine/Grepable
output and the XML output. It is pretty ugly -- in particular I
Expand Down Expand Up @@ -523,60 +526,16 @@ void printportoutput(Target *currenths, PortList *plist) {
int numrows;
int numignoredports = plist->numIgnoredPorts();
int numports = plist->numPorts();
state_reason_summary_t *reasons, *currentr;

std::vector<const char *> saved_servicefps;

if (o.noportscan || numports == 0)
return;

xml_start_tag("ports");
int prevstate = PORT_UNKNOWN;
int istate;

while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
xml_open_start_tag("extraports");
xml_attribute("state", "%s", statenum2str(istate));
xml_attribute("count", "%d", plist->getStateCounts(istate));
xml_close_start_tag();
xml_newline();
print_xml_state_summary(plist, istate);
xml_end_tag();
xml_newline();
prevstate = istate;
}

if (numignoredports == numports) {
log_write(LOG_PLAIN, "All %d scanned ports on %s are ",
numignoredports,
currenths->NameIP(hostname, sizeof(hostname)));
log_write(LOG_MACHINE, "Host: %s (%s)\t%s: ",
currenths->targetipstr(), currenths->HostName(),
(o.ipprotscan) ? "Protocols" : "Ports");

if (plist->numIgnoredStates() == 1) {
istate = plist->nextIgnoredState(PORT_UNKNOWN);
log_write(LOG_PLAIN, "%s", statenum2str(istate));
/* Grepable output supports only one ignored state. */
log_write(LOG_MACHINE, "\tIgnored State: %s (%d)",
statenum2str(istate), plist->getStateCounts(istate));
} else {
prevstate = PORT_UNKNOWN;
while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
if (prevstate != PORT_UNKNOWN)
log_write(LOG_PLAIN, " or ");
log_write(LOG_PLAIN, "%s (%d)", statenum2str(istate),
plist->getStateCounts(istate));
prevstate = istate;
}
}
if (o.reason)
print_state_summary(plist, STATE_REASON_EMPTY);
log_write(LOG_PLAIN, "\n");

xml_end_tag(); /* ports */
xml_newline();
return;
}
log_write(LOG_MACHINE, "Host: %s (%s)", currenths->targetipstr(),
currenths->HostName());

if ((o.verbose > 1 || o.debugging) && currenths->StartTime()) {
time_t tm_secs, tm_sece;
Expand All @@ -603,35 +562,82 @@ void printportoutput(Target *currenths, PortList *plist) {
}
}
}
log_write(LOG_MACHINE, "Host: %s (%s)", currenths->targetipstr(),
currenths->HostName());

/* Show line like:
Not shown: 3995 closed ports, 514 filtered ports
if appropriate (note that states are reverse-sorted by # of ports) */
prevstate = PORT_UNKNOWN;
int prevstate = PORT_UNKNOWN;
int istate;

while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) {
if (prevstate == PORT_UNKNOWN)
i = plist->getStateCounts(istate);
xml_open_start_tag("extraports");
xml_attribute("state", "%s", statenum2str(istate));
xml_attribute("count", "%d", i);
xml_close_start_tag();
xml_newline();

/* Show line like:
Not shown: 98 open|filtered udp ports (no-response), 59 closed tcp ports (reset)
if appropriate (note that states are reverse-sorted by # of ports) */
if (prevstate == PORT_UNKNOWN) {
// First time through, check special case
if (numignoredports == numports) {
log_write(LOG_PLAIN, "All %d scanned ports on %s are in ignored states.\n",
numignoredports, currenths->NameIP(hostname, sizeof(hostname)));
log_write(LOG_MACHINE, "\t%s: ", (o.ipprotscan) ? "Protocols" : "Ports");
/* Grepable output supports only one ignored state. */
if (plist->numIgnoredStates() == 1) {
log_write(LOG_MACHINE, "\tIgnored State: %s (%d)", statenum2str(istate), i);
}
}
log_write(LOG_PLAIN, "Not shown: ");
else
} else {
log_write(LOG_PLAIN, ", ");
char desc[32];
if (o.ipprotscan)
Snprintf(desc, sizeof(desc),
(plist->getStateCounts(istate) ==
1) ? "protocol" : "protocols");
else
Snprintf(desc, sizeof(desc),
(plist->getStateCounts(istate) == 1) ? "port" : "ports");
log_write(LOG_PLAIN, "%d %s %s", plist->getStateCounts(istate),
statenum2str(istate), desc);
}

if((currentr = reasons = get_state_reason_summary(plist, istate)) == NULL) {
log_write(LOG_PLAIN, "%d %s %s%s", i, statenum2str(istate),
o.ipprotscan ? "protocol" : "port",
plist->getStateCounts(istate) == 1 ? "" : "s");
prevstate = istate;
continue;
}

while(currentr != NULL) {
if(currentr->count > 0) {
xml_open_start_tag("extrareasons");
xml_attribute("reason", "%s", reason_str(currentr->reason_id, SINGULAR));
xml_attribute("count", "%d", currentr->count);
xml_attribute("proto", "%s", IPPROTO2STR(currentr->proto));
xml_write_raw(" ports=\"");
output_rangelist_given_ports(LOG_XML, currentr->ports, currentr->count);
xml_write_raw("\"");
xml_close_empty_tag();
xml_newline();

if (currentr != reasons)
log_write(LOG_PLAIN, ", ");
log_write(LOG_PLAIN, "%d %s %s %s%s (%s)",
currentr->count, statenum2str(istate), IPPROTO2STR(currentr->proto),
o.ipprotscan ? "protocol" : "port",
plist->getStateCounts(istate) == 1 ? "" : "s",
reason_str(currentr->reason_id, SINGULAR));
}
currentr = currentr->next;
}
state_reason_summary_dinit(reasons);
xml_end_tag();
xml_newline();
prevstate = istate;
}

log_write(LOG_PLAIN, "\n");

if (o.reason)
print_state_summary(plist, STATE_REASON_FULL);
if (numignoredports == numports) {
// Nothing left to show.
xml_end_tag(); /* ports */
xml_newline();
log_flush_all();
return;
}

/* OK, now it is time to deal with the service table ... */
colno = 0;
Expand Down
93 changes: 11 additions & 82 deletions portreasons.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,9 @@
#include "winfix.h"
#endif
#include "portlist.h"
#include "output.h"
#include "NmapOps.h"
#include "portreasons.h"
#include "Target.h"
#include "xml.h"

extern NmapOps o;

Expand Down Expand Up @@ -252,7 +250,7 @@ static void state_reason_summary_init(state_reason_summary_t *r) {
r->next = NULL;
}

static void state_reason_summary_dinit(state_reason_summary_t *r) {
void state_reason_summary_dinit(state_reason_summary_t *r) {
state_reason_summary_t *tmp;

while(r != NULL) {
Expand All @@ -262,19 +260,6 @@ static void state_reason_summary_dinit(state_reason_summary_t *r) {
}
}

/* Counts how different valid state reasons exist */
static int state_summary_size(state_reason_summary_t *head) {
state_reason_summary_t *current = head;
int size = 0;

while(current) {
if(current->count > 0)
size++;
current = current->next;
}
return size;
}

/* Simon Tatham's linked list merge sort
*
* Merge sort works really well on linked lists
Expand Down Expand Up @@ -333,28 +318,29 @@ static state_reason_summary_t *reason_sort(state_reason_summary_t *list) {
}

/* Builds and aggregates reason state summary messages */
static int update_state_summary(state_reason_summary_t *head, reason_t reason_id) {
static int update_state_summary(state_reason_summary_t *head, Port *port) {
state_reason_summary_t *tmp = head;

if(tmp == NULL)
return -1;

while(1) {
if(tmp->reason_id == reason_id) {
tmp->count++;
return 0;
if(tmp->reason_id == port->reason.reason_id && tmp->proto == port->proto) {
break;
}

if(tmp->next == NULL) {
tmp->next = (state_reason_summary_t *)safe_malloc(sizeof(state_reason_summary_t));
tmp = tmp->next;
state_reason_summary_init(tmp);
tmp->reason_id = port->reason.reason_id;
tmp->proto = port->proto;
break;
}
tmp = tmp->next;
}
state_reason_summary_init(tmp);
tmp->reason_id = reason_id;
tmp->count = 1;
tmp->ports[tmp->count] = port->portno;
tmp->count++;
return 0;
}

Expand All @@ -374,14 +360,14 @@ static unsigned int get_state_summary(state_reason_summary_t *head, PortList *Po
while((current = Ports->nextPort(current, &port, proto, state)) != NULL) {
if(Ports->isIgnoredState(current->state, NULL)) {
total++;
update_state_summary(reason, current->reason.reason_id);
update_state_summary(reason, current);
}
}
return total;
}

/* parse and sort reason summary for main print_* functions */
static state_reason_summary_t *print_state_summary_internal(PortList *Ports, int state) {
state_reason_summary_t *get_state_reason_summary(PortList *Ports, int state) {
state_reason_summary_t *reason_head;

reason_head = (state_reason_summary_t *)safe_malloc(sizeof(state_reason_summary_t));
Expand Down Expand Up @@ -416,63 +402,6 @@ void state_reason_init(state_reason_t *reason) {
reason->ttl = 0;
}

/* Main external interface to converting, building, sorting and
* printing plain-text state reason summaries */
void print_state_summary(PortList *Ports, unsigned short type) {
state_reason_summary_t *reason_head, *currentr;
bool first_time = true;
const char *separator = ", ";
int states;

if((reason_head = print_state_summary_internal(Ports, 0)) == NULL)
return;

if(type == STATE_REASON_EMPTY)
log_write(LOG_PLAIN, " because of");
else if(type == STATE_REASON_FULL)
log_write(LOG_PLAIN, "Reason:");
else
assert(0);

states = state_summary_size(reason_head);
currentr = reason_head;

while(currentr != NULL) {
if(states == 1 && (!first_time))
separator = " and ";
if(currentr->count > 0) {
log_write(LOG_PLAIN, "%s%d %s", (first_time) ? " " : separator,
currentr->count, reason_str(currentr->reason_id, currentr->count));
first_time = false;

}
states--;
currentr = currentr->next;
}
if(type == STATE_REASON_FULL)
log_write(LOG_PLAIN, "\n");
state_reason_summary_dinit(reason_head);
}

void print_xml_state_summary(PortList *Ports, int state) {
state_reason_summary_t *reason_head, *currentr;

if((currentr = reason_head = print_state_summary_internal(Ports, state)) == NULL)
return;

while(currentr != NULL) {
if(currentr->count > 0) {
xml_open_start_tag("extrareasons");
xml_attribute("reason", "%s", reason_str(currentr->reason_id, currentr->count));
xml_attribute("count", "%d", currentr->count);
xml_close_empty_tag();
xml_newline();
}
currentr = currentr->next;
}
state_reason_summary_dinit(reason_head);
}

/* converts target into reason message for ping scans. Uses a static
* buffer so new values overwrite old values */
char *target_reason_str(Target *t) {
Expand Down
15 changes: 6 additions & 9 deletions portreasons.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ typedef struct port_reason_summary {
reason_t reason_id;
unsigned int count;
struct port_reason_summary *next;
unsigned short proto;
unsigned short ports[0xffff+1];
} state_reason_summary_t;


Expand Down Expand Up @@ -146,12 +148,6 @@ class reason_map_type{
/* Function to translate ICMP code and typ to reason code */
reason_codes icmp_to_reason(u8 proto, int icmp_type, int icmp_code);

/* passed to the print_state_summary.
* STATE_REASON_EMPTY will append to the current line, prefixed with " because of"
* STATE_REASON_FULL will start a new line, prefixed with "Reason:" */
#define STATE_REASON_EMPTY 0
#define STATE_REASON_FULL 1

/* Passed to reason_str to determine if string should be in
* plural of singular form */
#define SINGULAR 1
Expand All @@ -164,9 +160,10 @@ void state_reason_init(state_reason_t *reason);
* port the plural is used, otherwise the singular is used. */
const char *reason_str(reason_t reason_id, unsigned int number);

/* Displays reason summary messages */
void print_state_summary(PortList *Ports, unsigned short type);
void print_xml_state_summary(PortList *Ports, int state);
/* Returns a linked list of reasons why ports are in a given state */
state_reason_summary_t *get_state_reason_summary(PortList *Ports, int state);
/* Frees the linked list from get_state_reason_summary */
void state_reason_summary_dinit(state_reason_summary_t *r);

/* Build an output string based on reason and source ip address.
* Uses static return value so previous values will be over
Expand Down

0 comments on commit 38671f2

Please sign in to comment.