/*************************************************************************** * output.cc -- Handles the Nmap output system. This currently involves * * console-style human readable output, XML output, Script | #include #include #include #include /* Workaround for lack of namespace std on HP-UX 11.00 */ namespace std {}; using namespace std; extern NmapOps o; static const char *logtypes[LOG_NUM_FILES]=LOG_NAMES; /* Used in creating skript kiddie style output. |<-R4d! */ static void skid_output(char *s) { int i; for (i=0; s[i]; i++) /* We need a 50/50 chance here, use a random number */ if ((get_random_u8() & 0x01) == 0) /* Substitutions commented out are not known to me, but maybe look nice */ switch(s[i]) { case 'A': s[i]='4'; break; /* case 'B': s[i]='8'; break; case 'b': s[i]='6'; break; case 'c': s[i]='k'; break; case 'C': s[i]='K'; break; */ case 'e': case 'E': s[i]='3'; break; case 'i': case 'I': s[i]="!|1"[get_random_u8() % 3]; break; /* case 'k': s[i]='c'; break; case 'K': s[i]='C'; break;*/ case 'o': case 'O': s[i]='0'; break; case 's': case 'S': if (s[i+1] && !isalnum((int) (unsigned char) s[i+1])) s[i] = 'z'; else s[i] = '$'; break; case 'z': s[i]='s'; break; case 'Z': s[i]='S'; break; } else { if (s[i] >= 'A' && s[i] <= 'Z' && (get_random_u8() % 3 == 0)) { s[i] += 'a'-'A'; /* 1/3 chance of lower-case */ } else if (s[i] >= 'a' && s[i] <= 'z' && (get_random_u8() % 3 == 0)) { s[i] -= 'a'-'A'; /* 1/3 chance of upper-case */ } } } /* Remove all "\nSF:" from fingerprints */ static char* xml_sf_convert (const char* str) { char *temp = (char *) safe_malloc(strlen(str) + 1); char *dst = temp, *src = (char *)str; char *ampptr = 0; while(*src) { if (strncmp(src, "\nSF:", 4) == 0) { src += 4; continue; } /* Needed so "&something;" is not truncated midway */ if (*src == '&') { ampptr = dst; } else if (*src == ';') { ampptr = 0; } *dst++ = *src++; } if (ampptr != 0) { *ampptr = '\0'; } else { *dst = '\0'; } return temp; } // Creates an XML element for the information given in // serviceDeduction. This function should only be called if ether // 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) { string versionxmlstring = ""; char rpcbuf[128]; char confBuf[20]; char *xml_product = NULL, *xml_version = NULL, *xml_extrainfo = NULL; char *xml_hostname = NULL, *xml_ostype = NULL, *xml_devicetype = NULL; char *xml_servicefp = NULL, *xml_servicefp_temp = NULL; versionxmlstring = "name? sd->name : "unknown"; versionxmlstring += "\""; if (sd->product) { xml_product = xml_convert(sd->product); versionxmlstring += " product=\""; versionxmlstring += xml_product; free(xml_product); xml_product = NULL; versionxmlstring += '\"'; } if (sd->version) { xml_version = xml_convert(sd->version); versionxmlstring += " version=\""; versionxmlstring += xml_version; free(xml_version); xml_version = NULL; versionxmlstring += '\"'; } if (sd->extrainfo) { xml_extrainfo = xml_convert(sd->extrainfo); versionxmlstring += " extrainfo=\""; versionxmlstring += xml_extrainfo; free(xml_extrainfo); xml_extrainfo = NULL; versionxmlstring += '\"'; } if (sd->hostname) { xml_hostname = xml_convert(sd->hostname); versionxmlstring += " hostname=\""; versionxmlstring += xml_hostname; free(xml_hostname); xml_hostname = NULL; versionxmlstring += '\"'; } if (sd->ostype) { xml_ostype = xml_convert(sd->ostype); versionxmlstring += " ostype=\""; versionxmlstring += xml_ostype; free(xml_ostype); xml_ostype = NULL; versionxmlstring += '\"'; } if (sd->devicetype) { xml_devicetype = xml_convert(sd->devicetype); versionxmlstring += " devicetype=\""; versionxmlstring += xml_devicetype; free(xml_devicetype); xml_devicetype = NULL; versionxmlstring += '\"'; } if (sd->service_fp) { xml_servicefp_temp = xml_convert(sd->service_fp); xml_servicefp = xml_sf_convert(xml_servicefp_temp); versionxmlstring += " servicefp=\""; versionxmlstring += xml_servicefp; free(xml_servicefp_temp); xml_servicefp_temp = NULL; free(xml_servicefp); xml_servicefp = NULL; versionxmlstring += '\"'; } if (o.rpcscan && sd->rpc_status == RPC_STATUS_GOOD_PROG) { Snprintf(rpcbuf, sizeof(rpcbuf), " rpcnum=\"%li\" lowver=\"%i\" highver=\"%i\" proto=\"rpc\"", sd->rpc_program, sd->rpc_lowver, sd->rpc_highver); } else rpcbuf[0] = '\0'; versionxmlstring += " "; versionxmlstring += (sd->service_tunnel == SERVICE_TUNNEL_SSL)? "tunnel=\"ssl\" " : ""; versionxmlstring += "method=\""; versionxmlstring += (sd->dtype == SERVICE_DETECTION_TABLE)? "table" : "probed"; versionxmlstring += "\" conf=\""; Snprintf(confBuf,20,"%i",sd->name_confidence); versionxmlstring += confBuf; versionxmlstring += "\""; versionxmlstring += rpcbuf; versionxmlstring += " />"; return strdup(versionxmlstring.c_str()); } #ifdef WIN32 /* Display a warning that a device is not Ethernet and so raw sockets will be used. The warning is shown only once per unique device name. */ void win32_warn_raw_sockets(const char *devname) { static set shown_names; if (devname != NULL && shown_names.find(devname) == shown_names.end()) { error("WARNING: Using raw sockets because %s is not an ethernet device. This probably won't work on Windows.\n", devname); shown_names.insert(devname); } } /* From tcpip.cc. */ bool DnetName2PcapName(const char *dnetdev, char *pcapdev, int pcapdevlen); /* Display the mapping from libdnet interface names (like "eth0") to WinPcap interface names (like "\Device\NPF_{...}"). This is the same mapping used by eth_open and so can help diagnose connection problems. Additionally display WinPcap interface names that are not mapped to by any libdnet name, in other words the names of interfaces Nmap has no way of using.*/ static void print_iflist_pcap_mapping(const struct interface_info *iflist, int numifs) { pcap_if_t *pcap_ifs; list leftover_pcap_ifs; list::iterator leftover_p; int i; /* Build a list of "leftover" libpcap interfaces. Initially it contains all the interfaces. */ pcap_ifs = getpcapinterfaces(); for (const pcap_if_t *p = pcap_ifs; p != NULL; p = p->next) leftover_pcap_ifs.push_front(p); if (numifs > 0 || !leftover_pcap_ifs.empty()) { NmapOutputTable Tbl(1 + numifs + leftover_pcap_ifs.size(), 2); Tbl.addItem(0, 0, false, "DEV"); Tbl.addItem(0, 1, false, "WINDEVICE"); /* Show the libdnet names and what they map to. */ for (i = 0; i < numifs; i++) { char pcap_name[1024]; if (DnetName2PcapName(iflist[i].devname, pcap_name, sizeof(pcap_name))) { /* We got a name. Remove it from the list of leftovers. */ list::iterator next; for (leftover_p = leftover_pcap_ifs.begin(); leftover_p != leftover_pcap_ifs.end(); leftover_p = next) { next = leftover_p; next++; if (strcmp((*leftover_p)->name, pcap_name) == 0) leftover_pcap_ifs.erase(leftover_p); } } else { Strncpy(pcap_name, "", sizeof(pcap_name)); } Tbl.addItem(i + 1, 0, false, iflist[i].devname); Tbl.addItem(i + 1, 1, true, pcap_name); } /* Show the "leftover" libpcap interface names (those without a libdnet name that maps to them). */ for (leftover_p = leftover_pcap_ifs.begin(); leftover_p != leftover_pcap_ifs.end(); leftover_p++) { Tbl.addItem(i + 1, 0, false, ""); Tbl.addItem(i + 1, 1, false, (*leftover_p)->name); i++; } log_write(LOG_PLAIN, "%s\n", Tbl.printableTable(NULL)); log_flush_all(); } pcap_freealldevs(pcap_ifs); } #endif /* Print a detailed list of Nmap interfaces and routes to normal/skiddy/stdout output */ int print_iflist(void) { int numifs = 0, numroutes = 0; struct interface_info *iflist; struct sys_route *routes; NmapOutputTable *Tbl = NULL; iflist = getinterfaces(&numifs); int i; /* First let's handle interfaces ... */ if (numifs == 0) { log_write(LOG_PLAIN, "INTERFACES: NONE FOUND(!)\n"); } else { int devcol=0, shortdevcol=1, ipcol=2, typecol = 3, upcol = 4, maccol = 5; Tbl = new NmapOutputTable( numifs+1, 6 ); Tbl->addItem(0, devcol, false, "DEV", 3); Tbl->addItem(0, shortdevcol, false, "(SHORT)", 7); Tbl->addItem(0, ipcol, false, "IP/MASK", 7); Tbl->addItem(0, typecol, false, "TYPE", 4); Tbl->addItem(0, upcol, false, "UP", 2); Tbl->addItem(0, maccol, false, "MAC", 3); for(i=0; i < numifs; i++) { Tbl->addItem(i+1, devcol, false, iflist[i].devfullname); Tbl->addItemFormatted(i+1, shortdevcol, false, "(%s)", iflist[i].devname); Tbl->addItemFormatted(i+1, ipcol, false, "%s/%d", inet_ntop_ez(&(iflist[i].addr), sizeof(iflist[i].addr)), iflist[i].netmask_bits); if (iflist[i].device_type == devt_ethernet) { Tbl->addItem(i+1, typecol, false, "ethernet"); Tbl->addItemFormatted(i+1, maccol, false, "%02X:%02X:%02X:%02X:%02X:%02X", iflist[i].mac[0], iflist[i].mac[1], iflist[i].mac[2], iflist[i].mac[3], iflist[i].mac[4], iflist[i].mac[5]); } else if (iflist[i].device_type == devt_loopback) Tbl->addItem(i+1, typecol, false, "loopback"); else if (iflist[i].device_type == devt_p2p) Tbl->addItem(i+1, typecol, false, "point2point"); else Tbl->addItem(i+1, typecol, false, "other"); Tbl->addItem(i+1, upcol, false, (iflist[i].device_up? "up" : "down")); } log_write(LOG_PLAIN, "************************INTERFACES************************\n"); log_write(LOG_PLAIN, "%s\n", Tbl->printableTable(NULL)); log_flush_all(); delete Tbl; } #ifdef WIN32 /* Print the libdnet->libpcap interface name mapping. */ print_iflist_pcap_mapping(iflist, numifs); #endif /* OK -- time to handle routes */ routes = getsysroutes(&numroutes); u32 mask_nbo; u16 nbits; struct in_addr ia; if (numroutes == 0) { log_write(LOG_PLAIN, "ROUTES: NONE FOUND(!)\n"); } else { int dstcol=0, devcol=1, gwcol=2; Tbl = new NmapOutputTable( numroutes+1, 3 ); Tbl->addItem(0, dstcol, false, "DST/MASK", 8); Tbl->addItem(0, devcol, false, "DEV", 3); Tbl->addItem(0, gwcol, false, "GATEWAY", 7); for(i=0; i < numroutes; i++) { mask_nbo = htonl(routes[i].netmask); addr_mtob(&mask_nbo, sizeof(mask_nbo), &nbits); assert(nbits <= 32); ia.s_addr = routes[i].dest; Tbl->addItemFormatted(i+1, dstcol, false, "%s/%d", inet_ntoa(ia), nbits); Tbl->addItem(i+1, devcol, false, routes[i].device->devfullname); if (routes[i].gw.s_addr != 0) Tbl->addItem(i+1, gwcol, true, inet_ntoa(routes[i].gw)); } log_write(LOG_PLAIN, "**************************ROUTES**************************\n"); log_write(LOG_PLAIN, "%s\n", Tbl->printableTable(NULL)); log_flush_all(); delete Tbl; } 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(); string::size_type pos; char *c_result, *c_output = new char[output.length()+1]; strncpy(c_output, output.c_str(), output.length()+1); int line = 0; std::string line_prfx = "| "; char* token = strtok(c_output, "\n"); result += line_prfx + sr.get_id() + ": "; while(token != NULL) { if(line > 0) result += line_prfx; result += std::string(token) + "\n"; token = strtok(NULL, "\n"); line++; } // fix the last line pos = result.rfind(line_prfx); result.replace(pos, 3, "|_ "); // delete the unwanted trailing newline pos = result.rfind("\n"); if(pos!=std::string::npos){ result.erase(pos, strlen("\n")); } c_result = strdup(result.c_str()); delete[] c_output; return c_result; } #endif /* NOLUA */ /* Prints the familiar Nmap tabular output showing the "interesting" ports found on the machine. It also handles the Machine/Greppable output and the XML output. It is pretty ugly -- in particular I should write helper functions to handle the table creation */ void printportoutput(Target *currenths, PortList *plist) { char protocol[MAX_IPPROTOSTRLEN+1]; char rpcinfo[64]; char rpcmachineinfo[64]; char portinfo[64]; char grepvers[256]; char grepown[64]; char *p; char * xmlBuf=NULL; const char *state; char serviceinfo[64]; char *name=NULL; int i; int first = 1; struct protoent *proto; Port *current; char hostname[1200]; struct serviceDeductions sd; NmapOutputTable *Tbl = NULL; int portcol = -1; // port or IP protocol # int statecol = -1; // port/protocol state int servicecol = -1; // service or protocol name int versioncol = -1; int reasoncol = -1; // int ownercol = -1; // Used for ident scan int colno = 0; unsigned int rowno; int numrows; int numignoredports = plist->numIgnoredPorts(); vector saved_servicefps; if (o.noportscan) return; log_write(LOG_XML, ""); int prevstate = PORT_UNKNOWN; int istate; while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) { log_write(LOG_XML, "\n", statenum2str(istate), plist->getStateCounts(istate)); print_xml_state_summary(plist, istate); log_write(LOG_XML, "\n"); prevstate = istate; } if (numignoredports == plist->numports) { if (numignoredports == 0) { log_write(LOG_PLAIN, "0 ports scanned on %s\n", currenths->NameIP(hostname, sizeof(hostname))); } else { log_write(LOG_PLAIN, "%s %d scanned %s on %s %s ", (numignoredports == 1)? "The" : "All", numignoredports, (numignoredports == 1)? "port" : "ports", currenths->NameIP(hostname, sizeof(hostname)), (numignoredports == 1)? "is" : "are"); if (plist->numIgnoredStates() == 1) { log_write(LOG_PLAIN, "%s", statenum2str(plist->nextIgnoredState(PORT_UNKNOWN))); } 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"); } log_write(LOG_MACHINE,"Host: %s (%s)\tStatus: Up", currenths->targetipstr(), currenths->HostName()); log_write(LOG_XML, "\n"); return; } if (o.verbose > 1 || o.debugging) { time_t tm_secs, tm_sece; struct tm *tm; char tbufs[128]; tm_secs = currenths->StartTime(); tm_sece = currenths->EndTime(); tm = localtime(&tm_secs); if (strftime(tbufs, sizeof(tbufs), "%Y-%m-%d %H:%M:%S %Z", tm) <= 0) fatal("Unable to properly format host start time"); log_write(LOG_PLAIN,"Scanned at %s for %lds\n", tbufs, tm_sece - tm_secs); } log_write(LOG_PLAIN,"Interesting %s on %s:\n", (o.ipprotscan)? "protocols" : "ports", currenths->NameIP(hostname, sizeof(hostname))); 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; while ((istate = plist->nextIgnoredState(prevstate)) != PORT_UNKNOWN) { if (prevstate == PORT_UNKNOWN) log_write(LOG_PLAIN, "Not shown: "); 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); prevstate = istate; } if (prevstate != PORT_UNKNOWN) log_write(LOG_PLAIN, "\n"); if(o.reason) print_state_summary(plist, STATE_REASON_FULL); /* OK, now it is time to deal with the service table ... */ colno = 0; portcol = colno++; statecol = colno++; servicecol = colno++; if(o.reason) reasoncol = colno++; /* if (o.identscan) ownercol = colno++; */ if (o.servicescan || o.rpcscan) versioncol = colno++; numrows = plist->numports - numignoredports; #ifndef NOLUA int scriptrows = 0; if(plist->numscriptresults > 0) scriptrows = plist->numscriptresults; numrows += scriptrows; #endif assert(numrows > 0); numrows++; // The header counts as a row Tbl = new NmapOutputTable(numrows, colno); // Lets start with the headers if (o.ipprotscan) Tbl->addItem(0, portcol, false, "PROTOCOL", 8); else Tbl->addItem(0, portcol, false, "PORT", 4); Tbl->addItem(0, statecol, false, "STATE", 5); Tbl->addItem(0, servicecol, false, "SERVICE", 7); if (versioncol > 0) Tbl->addItem(0, versioncol, false, "VERSION", 7); if(reasoncol > 0) Tbl->addItem(0, reasoncol, false, "REASON", 6); /* if (ownercol > 0) Tbl->addItem(0, ownercol, false, "OWNER", 5); */ log_write(LOG_MACHINE,"\t%s: ", (o.ipprotscan)? "Protocols" : "Ports" ); rowno = 1; if (o.ipprotscan) { current = NULL; while( (current=plist->nextPort(current, IPPROTO_IP, 0))!=NULL ) { if (!plist->isIgnoredState(current->state)) { if (!first) log_write(LOG_MACHINE,", "); else first = 0; if(o.reason) Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason)); state = statenum2str(current->state); proto = nmap_getprotbynum(htons(current->portno)); Snprintf(portinfo, sizeof(portinfo), "%s", proto?proto->p_name: "unknown"); Tbl->addItemFormatted(rowno, portcol, false, "%d", current->portno); Tbl->addItem(rowno, statecol, true, state); Tbl->addItem(rowno, servicecol, true, portinfo); log_write(LOG_MACHINE,"%d/%s/%s/", current->portno, state, (proto)? proto->p_name : ""); log_write(LOG_XML, "portno, state, reason_str(current->reason.reason_id, SINGULAR), current->reason.ttl); if(current->reason.ip_addr.s_addr) log_write(LOG_XML, " reason_ip=\"%s\"", inet_ntoa(current->reason.ip_addr)); log_write(LOG_XML, "/>"); if (proto && proto->p_name && *proto->p_name) log_write(LOG_XML, "\n", proto->p_name); log_write(LOG_XML, "\n"); rowno++; } } } else { current = NULL; while( (current=plist->nextPort(current, TCPANDUDPANDSCTP, 0))!=NULL ) { if (!plist->isIgnoredState(current->state)) { if (!first) log_write(LOG_MACHINE,", "); else first = 0; strcpy(protocol, IPPROTO2STR(current->proto)); Snprintf(portinfo, sizeof(portinfo), "%d/%s", current->portno, protocol); state = statenum2str(current->state); current->getServiceDeductions(&sd); if (sd.service_fp && saved_servicefps.size() <= 8) saved_servicefps.push_back(sd.service_fp); if (o.rpcscan) { switch(sd.rpc_status) { case RPC_STATUS_UNTESTED: rpcinfo[0] = '\0'; strcpy(rpcmachineinfo, ""); break; case RPC_STATUS_UNKNOWN: strcpy(rpcinfo, "(RPC (Unknown Prog #))"); strcpy(rpcmachineinfo, "R"); break; case RPC_STATUS_NOT_RPC: rpcinfo[0] = '\0'; strcpy(rpcmachineinfo, "N"); break; case RPC_STATUS_GOOD_PROG: name = nmap_getrpcnamebynum(sd.rpc_program); Snprintf(rpcmachineinfo, sizeof(rpcmachineinfo), "(%s:%li*%i-%i)", (name)? name : "", sd.rpc_program, sd.rpc_lowver, sd.rpc_highver); if (!name) { Snprintf(rpcinfo, sizeof(rpcinfo), "(#%li (unknown) V%i-%i)", sd.rpc_program, sd.rpc_lowver, sd.rpc_highver); } else { if (sd.rpc_lowver == sd.rpc_highver) { Snprintf(rpcinfo, sizeof(rpcinfo), "(%s V%i)", name, sd.rpc_lowver); } else Snprintf(rpcinfo, sizeof(rpcinfo), "(%s V%i-%i)", name, sd.rpc_lowver, sd.rpc_highver); } break; default: fatal("Unknown rpc_status %d", sd.rpc_status); break; } Snprintf(serviceinfo, sizeof(serviceinfo), "%s%s%s", (sd.name)? sd.name : ((*rpcinfo)? "" : "unknown"), (sd.name)? " " : "", rpcinfo); } else { getNmapServiceName(&sd, current->state, serviceinfo, sizeof(serviceinfo)); rpcmachineinfo[0] = '\0'; } Tbl->addItem(rowno, portcol, true, portinfo); Tbl->addItem(rowno, statecol, false, state); Tbl->addItem(rowno, servicecol, true, serviceinfo); if(o.reason) Tbl->addItem(rowno, reasoncol, true, port_reason_str(current->reason)); /* if (current->owner) Tbl->addItem(rowno, ownercol, true, current->owner); */ if (*sd.fullversion) Tbl->addItem(rowno, versioncol, true, sd.fullversion); // How should we escape illegal chars in grepable output? // Well, a reasonably clean way would be backslash escapes // such as \/ and \\ . // But that makes it harder to pick // 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 and owner fields. Strncpy(grepvers, sd.fullversion, sizeof(grepvers) / sizeof(*grepvers)); p = grepvers; while((p = strchr(p, '/'))) { *p = '|'; p++; } if (!current->owner) *grepown = '\0'; else { Strncpy(grepown, current->owner, sizeof(grepown) / sizeof(*grepown)); p = grepown; while((p = strchr(p, '/'))) { *p = '|'; p++; } } if (!sd.name) serviceinfo[0] = '\0'; else { p = serviceinfo; while((p = strchr(p, '/'))) { *p = '|'; p++; } } log_write(LOG_MACHINE,"%d/%s/%s/%s/%s/%s/%s/", current->portno, state, protocol, grepown, serviceinfo, rpcmachineinfo, grepvers); log_write(LOG_XML, "", protocol, current->portno); log_write(LOG_XML, "reason.reason_id, SINGULAR), current->reason.ttl); if(current->reason.ip_addr.s_addr) log_write(LOG_XML, " reason_ip=\"%s\"", inet_ntoa(current->reason.ip_addr)); log_write(LOG_XML, "/>"); if (current->owner && *current->owner) { log_write(LOG_XML, "", current->owner); } if (sd.name || sd.service_fp){ xmlBuf = getServiceXMLBuf(&sd); if(xmlBuf){ log_write(LOG_XML, "%s", xmlBuf); free(xmlBuf); xmlBuf=NULL; } } rowno++; #ifndef NOLUA if(o.script) { ScriptResults::iterator ssr_iter; for( ssr_iter = current->scriptResults.begin(); ssr_iter != current->scriptResults.end(); ssr_iter++) { char* xml_id= xml_convert(ssr_iter->get_id().c_str()); char* xml_scriptoutput= xml_convert(ssr_iter->get_output().c_str()); log_write(LOG_XML, "