diff -urNb old.nmap.rev/Makefile.in new.nmap.rev/Makefile.in --- old.nmap.rev/Makefile.in 2008-01-06 23:02:59.000000000 -0800 +++ new.nmap.rev/Makefile.in 2008-01-06 23:02:59.000000000 -0800 @@ -65,11 +65,11 @@ NSESTDLIB=nsestdlib endif -export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc traceroute.cc portreasons.cc $(NSE_SRC) @COMPAT_SRCS@ +export SRCS = main.cc nmap.cc targets.cc tcpip.cc nmap_error.cc utils.cc idle_scan.cc osscan.cc osscan2.cc output.cc scan_engine.cc timing.cc charpool.cc services.cc protocols.cc nmap_rpc.cc portlist.cc NmapOps.cc TargetGroup.cc Target.cc FingerPrintResults.cc service_scan.cc NmapOutputTable.cc MACLookup.cc nmap_tty.cc nmap_dns.cc traceroute.cc portreasons.cc qscan.cc $(NSE_SRC) @COMPAT_SRCS@ export HDRS = charpool.h FingerPrintResults.h global_structures.h idle_scan.h MACLookup.h nmap_amigaos.h nmap_dns.h nmap_error.h nmap.h NmapOps.h NmapOutputTable.h nmap_rpc.h nmap_tty.h nmap_winconfig.h osscan.h osscan2.h output.h portlist.h protocols.h scan_engine.h service_scan.h services.h TargetGroup.h Target.h targets.h tcpip.h timing.h utils.h traceroute.h portreasons.h $(NSE_HDRS) -OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o osscan2.o output.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o nmap_tty.o nmap_dns.o traceroute.o portreasons.o $(NSE_OBJS) @COMPAT_OBJS@ +OBJS = main.o nmap.o targets.o tcpip.o nmap_error.o utils.o idle_scan.o osscan.o osscan2.o output.o scan_engine.o timing.o charpool.o services.o protocols.o nmap_rpc.o portlist.o NmapOps.o TargetGroup.o Target.o FingerPrintResults.o service_scan.o NmapOutputTable.o MACLookup.o nmap_tty.o nmap_dns.o traceroute.o portreasons.o qscan.o $(NSE_OBJS) @COMPAT_OBJS@ # %.o : %.cc -- nope this is a GNU extension .cc.o: diff -urNb old.nmap.rev/nmap.cc new.nmap.rev/nmap.cc --- old.nmap.rev/nmap.cc 2008-01-06 23:02:59.000000000 -0800 +++ new.nmap.rev/nmap.cc 2008-01-06 23:02:59.000000000 -0800 @@ -241,6 +241,9 @@ " -b : FTP bounce scan\n" " --traceroute: Trace hop path to each host\n" " --reason: Display the reason a port is in a particular state\n" + " --qscan-delay : Average delay between qscan packets\n" + " --qscan-numtrip : Round trip times to record\n" + " --qscan-confidence : Confidence level (default 0.95)\n" "PORT SPECIFICATION AND SCAN ORDER:\n" " -p : Only scan specified ports\n" " Ex: -p22; -p1-65535; -p U:53,111,137,T:21-25,80,139,8080\n" @@ -622,6 +625,9 @@ {"port_ratio", required_argument, 0, 0}, {"top-ports", required_argument, 0, 0}, {"top_ports", required_argument, 0, 0}, + {"qscan-delay", required_argument, 0, 0}, + {"qscan-numtrips", required_argument, 0, 0}, + {"qscan-confidence", required_argument, 0, 0}, #ifndef NOLUA {"script", required_argument, 0, 0}, {"script-trace", no_argument, 0, 0}, @@ -816,6 +822,18 @@ o.mass_dns = false; } else if (optcmp(long_options[option_index].name, "dns-servers") == 0) { o.dns_servers = strdup(optarg); + } else if (optcmp(long_options[option_index].name, "qscan-delay") == 0) { + o.qscan_delay = atoi(optarg); + if (o.qscan_delay <= 0) + fatal("qscan-delay must be greater than 0"); + } else if (optcmp(long_options[option_index].name, "qscan-numtrips") == 0) { + o.qscan_numtrips = atoi(optarg); + if (o.qscan_numtrips < 3) + fatal("qscan-numtrips must be 3 or greater"); + } else if (optcmp(long_options[option_index].name, "qscan-confidence") == 0) { + o.qscan_confidence = atof(optarg); + if (o.qscan_confidence <= 0 || o.qscan_confidence >= 1.0) + fatal("qscan-confidence must be between 0 and 1"); } else if (optcmp(long_options[option_index].name, "log-errors") == 0) { o.log_errors = 1; } else if (strcmp(long_options[option_index].name, "webxml") == 0) { @@ -1133,6 +1151,7 @@ case 'N': o.nullscan = 1; break; case 'O': o.ipprotscan = 1; break; case 'P': o.pingscan = 1; break; + case 'Q': o.qscan = 1; randomize = 0; break; case 'R': o.rpcscan = 1; break; case 'S': o.synscan = 1; break; case 'W': o.windowscan = 1; break; @@ -1702,6 +1721,9 @@ if (o.ipprotscan) ultra_scan(Targets, ports, IPPROT_SCAN); + if (o.qscan) + qscan(&Targets[0], Targets.size(), ports); + /* These lame functions can only handle one target at a time */ for(targetno = 0; targetno < Targets.size(); targetno++) { currenths = Targets[targetno]; diff -urNb old.nmap.rev/nmap.h new.nmap.rev/nmap.h --- old.nmap.rev/nmap.h 2008-01-06 23:02:59.000000000 -0800 +++ new.nmap.rev/nmap.h 2008-01-06 23:02:59.000000000 -0800 @@ -443,4 +443,6 @@ int nmap_fileexistsandisreadable(char* pathname); int gather_logfile_resumption_state(char *fname, int *myargc, char ***myargv); +void qscan(Target **targets, int num_targets, struct scan_lists *ports); + #endif /* NMAP_H */ diff -urNb old.nmap.rev/NmapOps.cc new.nmap.rev/NmapOps.cc --- old.nmap.rev/NmapOps.cc 2008-01-06 23:02:59.000000000 -0800 +++ new.nmap.rev/NmapOps.cc 2008-01-06 23:02:59.000000000 -0800 @@ -238,7 +238,7 @@ version_intensity = 7; pingtype = PINGTYPE_UNKNOWN; listscan = pingscan = allowall = ackscan = bouncescan = connectscan = 0; - rpcscan = nullscan = xmasscan = fragscan = synscan = windowscan = 0; + rpcscan = nullscan = xmasscan = fragscan = synscan = windowscan = qscan = 0; maimonscan = idlescan = finscan = udpscan = ipprotscan = noresolve = 0; append_output = 0; memset(logfd, 0, sizeof(FILE *) * LOG_NUM_FILES); @@ -270,6 +270,9 @@ ipopt_lasthop = 0; release_memory = false; topportlevel = -1; + qscan_delay = 200; + qscan_numtrips = 10; + qscan_confidence = 0.95; #ifndef NOLUA script = 0; scriptversion = 0; @@ -279,7 +282,7 @@ } bool NmapOps::TCPScan() { - return ackscan|bouncescan|connectscan|finscan|idlescan|maimonscan|nullscan|synscan|windowscan|xmasscan; + return ackscan|bouncescan|connectscan|finscan|idlescan|maimonscan|nullscan|synscan|windowscan|xmasscan|qscan; } bool NmapOps::UDPScan() { @@ -291,7 +294,7 @@ IPv6 is being used. It will return false in those cases where a RawScan is not neccessarily used. */ bool NmapOps::RawScan() { - if (ackscan|finscan|idlescan|ipprotscan|maimonscan|nullscan|osscan|synscan|udpscan|windowscan|xmasscan) + if (ackscan|finscan|idlescan|ipprotscan|maimonscan|nullscan|osscan|synscan|udpscan|windowscan|xmasscan|qscan) return true; if (pingtype & (PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS|PINGTYPE_TCP_USE_ACK|PINGTYPE_UDP)) return true; diff -urNb old.nmap.rev/NmapOps.h new.nmap.rev/NmapOps.h --- old.nmap.rev/NmapOps.h 2008-01-06 23:02:59.000000000 -0800 +++ new.nmap.rev/NmapOps.h 2008-01-06 23:02:59.000000000 -0800 @@ -296,6 +296,7 @@ int ipprotscan; int maimonscan; int nullscan; + int qscan; int rpcscan; int synscan; int udpscan; @@ -322,6 +323,9 @@ bool log_errors; bool traceroute; bool reason; + int qscan_delay; + int qscan_numtrips; + double qscan_confidence; #ifndef NOLUA int script; diff -urNb old.nmap.rev/output.cc new.nmap.rev/output.cc --- old.nmap.rev/output.cc 2008-01-06 23:02:59.000000000 -0800 +++ new.nmap.rev/output.cc 2008-01-06 23:02:59.000000000 -0800 @@ -453,6 +453,9 @@ vector saved_servicefps; + // QScan doesn't print port status information at all! + if (o.qscan) return; + log_write(LOG_XML, ""); int prevstate = PORT_UNKNOWN; int istate; diff -urNb old.nmap.rev/qscan.cc new.nmap.rev/qscan.cc --- old.nmap.rev/qscan.cc 1969-12-31 16:00:00.000000000 -0800 +++ new.nmap.rev/qscan.cc 2008-01-06 23:02:59.000000000 -0800 @@ -0,0 +1,389 @@ +#include +#include +#include +#include +#include + +#include "nmap.h" +#include "Target.h" +#include "NmapOps.h" +#include "nmap_tty.h" +#include "utils.h" +#include "timing.h" + + +// Outstanding probe window +#define OWIN_SIZE 6 +#define TIMEOUT_NUM 10 + +struct qtarg_s { + Target *t; + int port; + + struct timeval owin[OWIN_SIZE]; + int owin_offset; + int recvs, trans; + + int num; + double mean, s_knuth; // Variance = s_knuth/(n-1) + + int family; + + struct qtarg_s *next; +}; + +static int rawsd, tcpPortBase; +static pcap_t *pd; +static struct eth_nfo eth; +static struct eth_nfo *ethptr; +static struct qtarg_s *qtargbase; +static ScanProgressMeter *SPM; +static int total_n=0, total_n_needed; + + +extern NmapOps o; + + +// Calculates the intermediate statistic 't given +// the quantity, mean, and standard deviation of 2 samples. +double calculate_t(int n1, int n2, double u1, double u2, double s1, double s2) { + double a, b; + double dof = n1 + n2 - 2; + + a = ((double)n1 + n2) / (n1 * n2); + b = ((n1-1) * (s1*s1)) + ((n2-1) * (s2*s2)); + b /= dof; + + return fabs(u1 - u2) / sqrt(a*b); + +} + +/* http://www.owlnet.rice.edu/~elec428/projects/tinv.c + * Uncredited ? + * tinv(p,dof) returns the inverse t-distribution value for probability + * 'p and degrees of freedom 'dof. It does this by looking up the appropriate + * value in the array tinv_array. Only dof between 1 and 20 are exact. + * For dof > 20, tinv() returns approximations. Also, only probabilities + * of 0.75, 0.9, 0.95, 0.975, 0.99, 0.995, and 0.9995 are provided. + * + * If p is not one of the 7 provided values, or if dof is not greater than or + * equal to 1, tinv() causes the program to exit. + */ + +double tinv(double p, int dof) { + int dofindex,pindex; + + double tinv_array[31][7] = { + {1.0000, 3.0777, 6.3138, 12.7062, 31.8207, 63.6574, 636.6192}, /* 1 */ + {0.8165, 1.8856, 2.9200, 4.3027, 6.9646, 9.9248, 31.5991}, /* 2 */ + {0.7649, 1.6377, 2.3534, 3.1824, 4.5407, 5.8409, 12.9240}, /* 3 */ + {0.7407, 1.5332, 2.1318, 2.7764, 3.7649, 4.6041, 8.6103}, /* 4 */ + {0.7267, 1.4759, 2.0150, 2.5706, 3.3649, 4.0322, 6.8688}, /* 5 */ + {0.7176, 1.4398, 1.9432, 2.4469, 3.1427, 3.7074, 5.9588}, /* 6 */ + {0.7111, 1.4149, 1.8946, 2.3646, 2.9980, 3.4995, 5.4079}, /* 7 */ + {0.7064, 1.3968, 1.8595, 3.3060, 2.8965, 3.3554, 5.0413}, /* 8 */ + {0.7027, 1.3830, 1.8331, 2.2622, 2.8214, 3.2498, 4.7809}, /* 9 */ + {0.6998, 1.3722, 1.8125, 2.2281, 2.7638, 1.1693, 4.5869}, /* 10 */ + {0.6974, 1.3634, 1.7959, 2.2010, 2.7181, 3.1058, 4.4370}, /* 11 */ + {0.6955, 1.3562, 1.7823, 2.1788, 2.6810, 3.0545, 4.3178}, /* 12 */ + {0.6938, 1.3502, 1.7709, 2.1604, 2.6403, 3.0123, 4.2208}, /* 13 */ + {0.6924, 1.3450, 1.7613, 2.1448, 2.6245, 2.9768, 4.1405}, /* 14 */ + {0.6912, 1.3406, 1.7531, 2.1315, 2.6025, 2.9467, 4.0728}, /* 15 */ + {0.6901, 1.3368, 1.7459, 2.1199, 2.5835, 2.9208, 4.0150}, /* 16 */ + {0.6892, 1.3334, 1.7396, 2.1098, 2.5669, 2.8982, 3.9651}, /* 17 */ + {0.6884, 1.3304, 1.7341, 2.1009, 2.5524, 2.8784, 3.9216}, /* 18 */ + {0.6876, 1.3277, 1.7291, 2.0930, 2.5395, 2.8609, 3.8834}, /* 19 */ + {0.6870, 1.3253, 1.7247, 2.0860, 2.5280, 2.8453, 3.8495}, /* 20 */ + {0.6844, 1.3163, 1.7081, 2.0595, 2.4851, 2.7874, 3.7251}, /* 25 */ + {0.6828, 1.3104, 1.6973, 2.0423, 2.4573, 2.7500, 3.6460}, /* 30 */ + {0.6816, 1.3062, 1.6896, 2.0301, 2.4377, 2.7238, 3.5911}, /* 35 */ + {0.6807, 1.3031, 1.6839, 2.0211, 2.4233, 2.7045, 3.5510}, /* 40 */ + {0.6800, 1.3006, 1.6794, 2.0141, 2.4121, 2.6896, 3.5203}, /* 45 */ + {0.6794, 1.2987, 1.6759, 2.0086, 2.4033, 2.6778, 3.4960}, /* 50 */ + {0.6786, 1.2958, 1.6706, 2.0003, 2.3901, 2.6603, 3.4602}, /* 60 */ + {0.6780, 1.2938, 1.6669, 1.9944, 2.3808, 2.6479, 3.4350}, /* 70 */ + {0.6776, 1.2922, 1.6641, 1.9901, 2.3739, 2.6387, 3.4163}, /* 80 */ + {0.6772, 1.2910, 1.6620, 1.9867, 2.3685, 2.6316, 3.4019}, /* 90 */ + {0.6770, 1.2901, 1.6602, 1.9840, 2.3642, 2.6259, 3.3905}}; /* 100 */ + + if (dof >= 1 && dof <= 20) dofindex = dof-1; + else if (dof < 25) dofindex = 19; + else if (dof < 30) dofindex = 20; + else if (dof < 35) dofindex = 21; + else if (dof < 40) dofindex = 22; + else if (dof < 45) dofindex = 23; + else if (dof < 50) dofindex = 24; + else if (dof < 60) dofindex = 25; + else if (dof < 70) dofindex = 26; + else if (dof < 80) dofindex = 27; + else if (dof < 90) dofindex = 28; + else if (dof < 100) dofindex = 29; + else if (dof >= 100) dofindex = 30; + else + { + printf("tinv: degrees of freedom must be at least 1\n"); + exit(1); + } + + if (p == .75) pindex = 0; + else if (p == .9) pindex = 1; + else if (p == .95) pindex = 2; + else if (p == .975) pindex = 3; + else if (p == .99) pindex = 4; + else if (p == .995) pindex = 5; + else if (p == .9995) pindex = 6; + else + { + printf("tinv: probability not tabulated\n"); + exit(1); + } + + return(tinv_array[dofindex][pindex]); +} + + + +void qscan_transmit(struct qtarg_s *qt, struct timeval *now) { + send_tcp_raw(rawsd, ethptr, qt->t->v4sourceip(), qt->t->v4hostip(), o.ttl, false, NULL, 0, + tcpPortBase + qt->owin_offset, qt->port, get_random_u32(), get_random_u32(), 0, TH_SYN, + 0, 0, NULL, 0, NULL, 0); + + qt->owin[qt->owin_offset].tv_sec = now->tv_sec; + qt->owin[qt->owin_offset].tv_usec = now->tv_usec; + + qt->owin_offset = (qt->owin_offset+1) % OWIN_SIZE; + + qt->trans++; +} + + +// Numerically stable running tally of n, mean, and variance. +// Algorithm from: +// Donald E. Knuth (1998). The Art of Computer Programming, volume 2: +// Seminumerical Algorithms, 3rd edn., p. 232. Boston: Addison-Wesley. +void update_statistics(struct qtarg_s *qt, double rtt_ms) { + double delta; + + total_n++; + qt->num++; + delta = rtt_ms - qt->mean; + qt->mean += delta/qt->num; + qt->s_knuth += delta * (rtt_ms - qt->mean); +} + + +void qscan_families() { + struct qtarg_s *qti, *qtj; + double t, critical_value; + int curr_family = 0; + + for (qti=qtargbase; qti; qti=qti->next) { + if (qti->family != -1) continue; + + qti->family = curr_family++; + + for (qtj=qti->next; qtj; qtj=qtj->next) { + if (qtj->family != -1) continue; + + t = calculate_t(qti->num, qtj->num, + qti->mean, qtj->mean, + sqrt(qti->s_knuth/(qti->num-1)), sqrt(qtj->s_knuth/(qtj->num-1))); + + critical_value = tinv(o.qscan_confidence, qti->num + qtj->num - 2); + + if (t < critical_value) qtj->family = qti->family; + } + } + +} + + +void qscan_parse_packet(struct ip *myip, struct timeval *seen) { + struct tcp_hdr *tcp; + int sport, dport; + struct in_addr saddr; + struct qtarg_s *qt; + double rtt_ms; + + saddr = myip->ip_src; + tcp = (struct tcp_hdr *) ((u8 *) myip + myip->ip_hl * 4); + sport = ntohs(tcp->th_sport); + dport = ntohs(tcp->th_dport); + + // We're only after resets or syn|acks.. + if ((tcp->th_flags & TH_RST) == 0 && tcp->th_flags != (TH_SYN|TH_ACK)) return; + + if (dport < tcpPortBase || dport >= (tcpPortBase + OWIN_SIZE)) return; + + for (qt=qtargbase; qt!=NULL; qt=qt->next) + if (memcmp(qt->t->v4hostip(), &saddr, sizeof(struct in_addr)) == 0 + && sport == qt->port) break; + + if (qt == NULL) return; + + // Something fisy going on if this returns: An unexpected reply... + // We'll just ignore for now. + if (qt->owin[dport - tcpPortBase].tv_sec == -1) return; + + rtt_ms = TIMEVAL_SUBTRACT(*seen, qt->owin[dport - tcpPortBase]) / 1000.0; + + if (qt->recvs++ > OWIN_SIZE) + update_statistics(qt, rtt_ms); + + qt->owin[dport - tcpPortBase].tv_sec = -1; +} + + +void qscan_run() { + struct qtarg_s *qt = qtargbase, *qtp; + struct timeval tv, now, seen; + struct ip *myip; + unsigned int len; + int minpackets; + int finished=0; + + while(1) { + gettimeofday(&now, NULL); + qscan_transmit(qt, &now); + + qt = qt->next; + if (qt == NULL) qt = qtargbase; + + // Random wait from N/2 to 3N/2 ms between transmissions + TIMEVAL_MSEC_ADD(tv, now, (get_random_u16() % o.qscan_delay) + (o.qscan_delay / 2)); + + do { + if (keyWasPressed()) + SPM->printStats((double) total_n / total_n_needed, NULL); + + myip = (struct ip *) readip_pcap(pd, &len, TIMEVAL_SUBTRACT(tv, now), &seen, NULL); + + if (myip != NULL) + qscan_parse_packet(myip, &seen); + + for (qtp=qtargbase, minpackets=o.qscan_numtrips; qtp!=NULL; qtp=qtp->next) + if ((qtp->trans-TIMEOUT_NUM) < qtp->recvs && qtp->num < minpackets) minpackets = qtp->num; + + if (!finished && minpackets == o.qscan_numtrips) { + finished=1; + gettimeofday(&now, NULL); + TIMEVAL_MSEC_ADD(tv, now, (o.qscan_delay*3)/2); + } + + gettimeofday(&now, NULL); + } while(TIMEVAL_SUBTRACT(tv, now) > 0); + + if (finished) return; + } +} + + + +void qscan(Target **targets, int num_targets, struct scan_lists *ports) { + int i, j, k; + struct qtarg_s *qt, *qt2; + char pcap_filter[2048]; + + if (num_targets == 0 || ports->tcp_count == 0) + fatal("Qscan: No targets or no TCP ports specified"); + + rawsd = -1; + qtargbase = NULL; + tcpPortBase = o.magic_port_set? o.magic_port : o.magic_port + get_random_u8(); + total_n_needed = num_targets * ports->tcp_count * o.qscan_numtrips; + + // Initialise our main linked list + for (i=0; itcp_count-1; j>=0; j--) { + qt = (struct qtarg_s *) malloc(sizeof(struct qtarg_s)); + if (qt == NULL) fatal("Qscan: out of memory"); + + qt->t = targets[i]; + qt->port = ports->tcp_ports[j]; + + for (k=0; kowin[k].tv_sec = -1; + + qt->owin_offset = 0; + qt->recvs = qt->trans = 0; + + qt->num = 0; + qt->mean = qt->s_knuth = 0; + + qt->family = -1; + + qt->next = qtargbase; + qtargbase = qt; + } + } + + // Initialise our raw sending socket + // Assume, for now, that all target packets will be sent on same + // ethernet device + if ((o.sendpref & PACKET_SEND_ETH) && targets[0]->ifType() == devt_ethernet) { + memcpy(eth.srcmac, targets[0]->SrcMACAddress(), 6); + memcpy(eth.dstmac, targets[0]->NextHopMACAddress(), 6); + if ((eth.ethsd = eth_open_cached(targets[0]->deviceName())) == NULL) + fatal("%s: Failed to open ethernet device (%s)", __FUNCTION__, targets[0]->deviceName()); + rawsd = -1; + ethptr = ð + } else { + /* Init our raw socket */ + if ((rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0 ) + pfatal("socket troubles in qscan"); + unblock_socket(rawsd); + broadcast_socket(rawsd); +#ifndef WIN32 + sethdrinclude(rawsd); +#endif + ethptr = NULL; + eth.ethsd = NULL; + } + + + // Initialise our pcap descriptor + + pd = my_pcap_open_live(targets[0]->deviceName(), 8192, (o.spoofsource)? 1 : 0, 1); + + snprintf(pcap_filter, sizeof(pcap_filter), "tcp and dst host %s", inet_ntoa(targets[0]->v4source())); + + if (o.debugging > 2) printf("Qscan pcap filter: %s\n", pcap_filter); + set_pcap_filter(targets[0]->deviceName(), pd, pcap_filter); + + + + // Let's do it! + + printf("Qscan parameters: round trips: %d, avg delay = %dms, confidence = %g\n", o.qscan_numtrips, o.qscan_delay, o.qscan_confidence); + + SPM = new ScanProgressMeter("QScan"); + + qscan_run(); + + SPM->endTask(NULL, NULL); + delete SPM; + + qscan_families(); + + printf(" Target:Port Fam uRTT +/- Stddev Loss (%%)\n"); + for(qt = qtargbase; qt != NULL; qt=qt->next) { + if (qt->num == 0) + printf("%15s:%-5d ? N/A +/- N/A %3.0f\n", qt->t->targetipstr(), qt->port, 100* (1.0 - ((double)qt->recvs / qt->trans))); + else + printf("%15s:%-5d %c %5.1f +/- %5.1f %3.0f\n", qt->t->targetipstr(), qt->port, 'A'+qt->family, qt->mean, sqrt(qt->s_knuth/(qt->num-1)), 100* (1.0 - ((double)qt->recvs / qt->trans))); + } + + + // Clean up + + pcap_close(pd); + + if (rawsd < 0) close(rawsd); + + for(qt = qtargbase; qt != NULL;) { + qt2 = qt->next; + free(qt); + qt = qt2; + } + +}