From 40d78569d29745e159e8b0738a30118bbae56266 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 6 Sep 2008 04:12:34 +0000 Subject: [PATCH] Use the cached timing ping probe as the traceroute probe in all situations. --- CHANGELOG | 7 ++ traceroute.cc | 302 +++++++++++++------------------------------------- traceroute.h | 27 +---- 3 files changed, 88 insertions(+), 248 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1650d589c..172a07155 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,13 @@ o zenmap scan inventory place holder. o zenmap radialnet integration place holder. +o --traceroute now uses the timing ping probe saved from host + discovery and port scanning instead of finding its own probe. The + timing ping probe is always the best probe for eliciting a response + Nmap knows of. This will have the most effect on traceroute after a + ping scan, where traceroute would sometimes pick the wrong probe and + traceroute would fail even though the target was up. + o Expanded nmap-services to include information on how frequently each port number is found open. The results were generated by scanning tens of millions of IPs on the Internet. [Fyodor] diff --git a/traceroute.cc b/traceroute.cc index 39e8f9171..79b83ba13 100644 --- a/traceroute.cc +++ b/traceroute.cc @@ -227,85 +227,6 @@ Traceroute::Traceroute (const char *device_name, devtype type, const scan_lists /* rely on each group using the same device */ pd = my_pcap_open_live (device_name, 100, o.spoofsource ? 1 : 0, 2); - scaninfo.initial_proto = IPPROTO_IP; - scaninfo.open_response = 0; - scaninfo.open_state = PORT_OPEN; - scaninfo.closed_state = PORT_CLOSED; - scaninfo.ipproto = false; - - /* Set up which protocols, tcp flags and responsive - * states to use with the current scan type. - * - * Horribly messy but it is better then peppering - * the nmap source code with references to traceroute */ - if (o.synscan) { - scaninfo.scan_flags = TH_SYN; - scaninfo.open_response = TH_SYN | TH_ACK; - scaninfo.closed_response = TH_RST; - } else if (o.ackscan) { - scaninfo.scan_flags = TH_ACK; - scaninfo.open_response = TH_RST; - scaninfo.closed_response = TH_RST; - scaninfo.open_state = PORT_UNFILTERED; - scaninfo.closed_state = PORT_UNFILTERED; - } else if (o.finscan) { - scaninfo.scan_flags = TH_FIN; - scaninfo.closed_response = TH_RST; - } else if (o.xmasscan) { - scaninfo.scan_flags = TH_FIN | TH_URG | TH_PUSH; - scaninfo.closed_response = TH_RST; - } else if (o.nullscan) { - scaninfo.scan_flags = 0; - scaninfo.closed_response = TH_RST; - } else if (o.windowscan) { - scaninfo.scan_flags = TH_ACK; - scaninfo.open_response = TH_RST; - scaninfo.closed_response = TH_RST; - } else if (o.maimonscan) { - scaninfo.scan_flags = TH_FIN | TH_ACK; - scaninfo.open_response = TH_RST; - scaninfo.closed_response = TH_RST; - } - - if (o.udpscan) - scaninfo.initial_proto = IPPROTO_UDP; - if (o.synscan || o.finscan || o.xmasscan || o.nullscan || - o.ackscan || o.windowscan || o.maimonscan) - scaninfo.initial_proto = IPPROTO_TCP; - - if (o.ipprotscan) - scaninfo.ipproto = true; - - if(o.pingscan) { - scaninfo.open_state = HOST_UP; - if (o.pingtype & PINGTYPE_TCP_USE_SYN) { - scaninfo.scan_flags = TH_SYN; - scaninfo.open_response = TH_SYN | TH_ACK; - scaninfo.closed_response = TH_RST; - scaninfo.initial_proto = IPPROTO_TCP; - } else if (o.pingtype & PINGTYPE_TCP_USE_ACK) { - scaninfo.scan_flags = TH_ACK; - scaninfo.open_response = TH_RST; - scaninfo.closed_response = TH_RST; - scaninfo.initial_proto = IPPROTO_TCP; - } else if (o.pingtype & PINGTYPE_UDP) { - scaninfo.initial_proto = IPPROTO_UDP; - } else if (o.pingtype & PINGTYPE_ICMP_PING) { - scaninfo.initial_proto = IPPROTO_ICMP; - scaninfo.icmp_type = ICMP_ECHO; - } else if (o.pingtype & PINGTYPE_ICMP_TS) { - scaninfo.initial_proto = IPPROTO_ICMP; - scaninfo.icmp_type = ICMP_TIMESTAMP; - } else if(o.pingtype & PINGTYPE_ICMP_MASK) { - scaninfo.initial_proto = IPPROTO_ICMP; - scaninfo.icmp_type = ICMP_ADDRESS; - } else if (o.pingtype & PINGTYPE_PROTO) { - scaninfo.ipproto = true; - } - } - - if (o.scanflags != -1) - scaninfo.scan_flags = o.scanflags; memset (commonPath, 0, sizeof (commonPath)); } @@ -327,86 +248,26 @@ Traceroute::~Traceroute () { /* get an open or closed port from the portlist. Traceroute requires a positive response, * positive responses are generated by different port states depending on the type of scan */ -inline int -Traceroute::getTracePort (u8 proto, Target * t) { - u16 open_port = 1; - u16 closed_port = 1; - u16 filtered_port = 1; - u16 port = 0; - int state = -1; - Port *np; +inline const probespec +Traceroute::getTraceProbe (Target * t) { + struct probespec probe; - /* Use the first specified port for ping traceroutes */ - if (o.pingscan) { - if (o.pingtype & PINGTYPE_TCP_USE_SYN) - return scanlists->syn_ping_ports[0]; - else if (o.pingtype & PINGTYPE_TCP_USE_ACK) - return scanlists->ack_ping_ports[0]; - else if (o.pingtype & PINGTYPE_UDP) - return scanlists->udp_ping_ports[0]; - else if (o.pingtype & PINGTYPE_PROTO) { - // Initialize protocol header information - port = scanlists->proto_ping_ports[0]; - goto ipproto; - } else - return 0; - } - - if (proto == IPPROTO_TCP) { - /* can't use filtered ports for tcp */ - filtered_port = 0; - open_port = (!scaninfo.open_response) ? 0 : 1; - } - - /* For UDP we try for a closed port, then an open one. For everything else - * we try the opposite. When all else fails, we try for filtered */ - if (proto == IPPROTO_UDP) { - if (closed_port && t->ports.getStateCounts (proto, scaninfo.closed_state)) - state = scaninfo.closed_state; - else if (open_port && t->ports.getStateCounts (proto, scaninfo.open_state)) - state = scaninfo.open_state; - } else { - if (open_port && t->ports.getStateCounts (proto, scaninfo.open_state)) - state = scaninfo.open_state; - else if (closed_port && t->ports.getStateCounts (proto, scaninfo.closed_state)) - state = scaninfo.closed_state; - } - - if (state == -1 && filtered_port && - t->ports.getStateCounts (proto, PORT_FILTERED)) { - state = PORT_FILTERED; - if (o.verbose) - log_write (LOG_PLAIN, "%s: only filtered %s available, results may be incorrect\n", - t->targetipstr (), scaninfo.ipproto ? "protocols" : "ports"); - } - - if (state == -1) - return -1; - - np = t->ports.nextPort (NULL, proto, state); - if (!np) - return -1; - - port = np->portno; - -ipproto: - /* If this is a protocol scan/ping traceroute and we are using - * one of the major protocols, set up the required information - * so we include the correct protocol headers */ - if (proto == IPPROTO_IP) { - if (port == IPPROTO_TCP) { - scaninfo.initial_proto = IPPROTO_TCP; - scaninfo.scan_flags = TH_ACK; - scaninfo.open_response = TH_RST; - scaninfo.closed_response = TH_RST; - } else if (port == IPPROTO_UDP) { - scaninfo.initial_proto = IPPROTO_UDP; - } else if (port == IPPROTO_ICMP) { - scaninfo.initial_proto = IPPROTO_ICMP; - scaninfo.icmp_type = ICMP_ECHO; + probe = t->pingprobe; + /* If this is an IP protocol probe, fill in some fields for some common + protocols. We cheat and store them in the TCP-, UDP-, and ICMP-specific + fields. Traceroute::sendProbe checks for them there. */ + if (probe.type == PS_PROTO) { + if (probe.proto == IPPROTO_TCP) { + probe.pd.tcp.flags = TH_ACK; + probe.pd.tcp.dport = get_random_u16(); + } else if (probe.proto == IPPROTO_UDP) { + probe.pd.udp.dport = get_random_u16(); + } else if (probe.proto == IPPROTO_ICMP) { + probe.pd.icmp.type = ICMP_ECHO; } } - return port; + + return probe; } /* finite state machine that reads all incoming packets @@ -480,7 +341,7 @@ Traceroute::readTraceResponses () { if (tp->ipreplysrc.s_addr) break; - if ((tg->proto == IPPROTO_UDP && (ip2 && ip2->ip_p == IPPROTO_UDP)) || + if ((tg->probe.proto == IPPROTO_UDP && (ip2 && ip2->ip_p == IPPROTO_UDP)) || (icmp->icmp_type == ICMP_DEST_UNREACH)) { switch (icmp->icmp_code) { /* reply from a closed port */ @@ -502,7 +363,7 @@ Traceroute::readTraceResponses () { } } /* icmp ping scan replies */ - else if (tg->proto == IPPROTO_ICMP && (icmp->icmp_type == ICMP_ECHOREPLY || + else if (tg->probe.proto == IPPROTO_ICMP && (icmp->icmp_type == ICMP_ECHOREPLY || icmp->icmp_type == ICMP_ADDRESSREPLY || icmp->icmp_type == ICMP_TIMESTAMPREPLY)) { if (tp->probeType () == PROBE_TTL) { tg->setHopDistance (get_initial_ttl_guess (ip->ip_ttl), ip->ip_ttl); @@ -562,8 +423,8 @@ Traceroute::readTraceResponses () { /* We have reached the destination host and the * trace can stop for this target */ - if (tcp->th_flags & scaninfo.open_response || tcp->th_flags & scaninfo.closed_response) { - + if ((tcp->th_flags & TH_RST) == TH_RST + || (tcp->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { /* We might have got a late reply */ if (tp->timing.getState () == P_TIMEDOUT) tp->timing.setState (P_OK); @@ -643,16 +504,14 @@ Traceroute::readTraceResponses () { inline void Traceroute::sendTTLProbes (vector < Target * >&Targets, vector < Target * >&valid_targets) { Target *t = NULL; - long dport = 0; + struct probespec probe; u16 sport = 0; - u8 proto; TraceProbe *tp; TraceGroup *tg = NULL; vector < Target * >::iterator it = Targets.begin (); for (; it != Targets.end (); ++it) { t = *it; - proto = scaninfo.initial_proto; /* No point in tracing directly connected nodes */ if (t->directlyConnected ()) @@ -665,36 +524,19 @@ Traceroute::sendTTLProbes (vector < Target * >&Targets, vector < Target * >&vali } /* Determine active port to probe */ - if ((dport = getTracePort (proto, t)) == -1) { - /* If we could not find a responsive tcp port then try - * to find a responsive udp port */ - if (o.udpscan && proto != IPPROTO_UDP) { - proto = IPPROTO_UDP; - dport = getTracePort (proto, t); - } - } - - if (dport == -1) { + probe = getTraceProbe (t); + if (probe.type == PS_NONE) { if (o.verbose > 1) log_write (LOG_STDOUT, "%s: no responsive %s\n", - t->targetipstr (), scaninfo.ipproto ? "protocols" : "ports"); + t->targetipstr (), "probes"); continue; } - /* If this is a protocol scan/ping, getTracePort() returns - * a protocol number so we need a random destination - * port */ - if (scaninfo.ipproto) { - proto = dport; - dport = get_random_u16 (); - scaninfo.initial_proto = IPPROTO_IP; - } - /* start off with a random source port and increment * it for each probes sent. The source port is the * distinguishing value used to identify each probe */ sport = get_random_u16 (); - tg = new TraceGroup (t->v4hostip ()->s_addr, sport, dport, proto); + tg = new TraceGroup (t->v4hostip ()->s_addr, sport, probe); tg->src_mac_addr = t->SrcMACAddress (); tg->nxt_mac_addr = t->NextHopMACAddress (); tg->sport++; @@ -705,8 +547,8 @@ Traceroute::sendTTLProbes (vector < Target * >&Targets, vector < Target * >&vali if (t->distance != -1) { tg->setHopDistance (0, t->distance); } else { - tp = new TraceProbe (proto, t->v4hostip ()->s_addr, - t->v4sourceip ()->s_addr, sport, dport); + tp = new TraceProbe (t->v4hostip ()->s_addr, + t->v4sourceip ()->s_addr, sport, probe); tp->setProbeType (PROBE_TTL); tp->ttl = o.ttl; tg->TraceProbes[sport] = tp; @@ -731,9 +573,9 @@ Traceroute::sendProbe (TraceProbe * tp) { struct eth_nfo eth; struct eth_nfo *ethptr = NULL; - if (scaninfo.scan_flags & TH_ACK) + if (tp->probe.type == PS_TCP && (tp->probe.pd.tcp.flags & TH_ACK) == TH_ACK) ack = rand (); - if (scaninfo.scan_flags & TH_SYN) { + if (tp->probe.type == PS_TCP && (tp->probe.pd.tcp.flags & TH_SYN) == TH_SYN) { tcpopts = (u8 *) "\x02\x04\x05\xb4"; tcpoptslen = 4; } @@ -764,7 +606,6 @@ Traceroute::sendProbe (TraceProbe * tp) { } tg->sport++; tp->ttl = tg->ttl; - tp->dport = tg->dport; tg->incRemaining (); } else { /* this probe is a retransmission */ @@ -781,29 +622,34 @@ Traceroute::sendProbe (TraceProbe * tp) { else source = o.decoys[decoy]; - switch (tp->proto) { - case IPPROTO_TCP: + /* For TCP, UDP, and ICMP, also check if the probe is an IP proto probe + whose protocol happens to be one of those protocols. The + protocol-specific fields will have been filled in by + Traceroute::getTraceProbe. */ + if (tp->probe.type == PS_TCP + || (tp->probe.type == PS_PROTO && tp->probe.proto == IPPROTO_TCP)) { packet = build_tcp_raw (&source, &tp->ipdst, tp->ttl, get_random_u16 (), - get_random_u8 (), 0, NULL, 0, tp->sport, tp->dport, - get_random_u32 (), ack, 0, scaninfo.scan_flags, + get_random_u8 (), false, NULL, 0, tp->sport, tp->probe.pd.tcp.dport, + get_random_u32 (), ack, 0, tp->probe.pd.tcp.flags, get_random_u16 (), 0, tcpopts, tcpoptslen, o.extra_payload, o.extra_payload_length, &packetlen); - break; - case IPPROTO_UDP: + } else if (tp->probe.type == PS_UDP + || (tp->probe.type == PS_PROTO && tp->probe.proto == IPPROTO_UDP)) { packet = build_udp_raw (&source, &tp->ipdst, tp->ttl, get_random_u16 (), get_random_u8 (), false, NULL, 0, tp->sport, - tp->dport, o.extra_payload, o.extra_payload_length, &packetlen); - break; - case IPPROTO_ICMP: + tp->probe.pd.udp.dport, o.extra_payload, o.extra_payload_length, &packetlen); + } else if (tp->probe.type == PS_ICMP + || (tp->probe.type == PS_PROTO && tp->probe.proto == IPPROTO_ICMP)) { packet = build_icmp_raw (&source, &tp->ipdst, tp->ttl, 0, 0, false, - NULL, 0, get_random_u16 (), tp->sport, scaninfo.icmp_type, 0, + NULL, 0, get_random_u16 (), tp->sport, tp->probe.pd.icmp.type, 0, o.extra_payload, o.extra_payload_length, &packetlen); - break; - default: - packet = build_ip_raw (&source, &tp->ipdst, tp->proto, tp->ttl, tp->sport, - get_random_u8 (), false, NULL, 0, o.extra_payload, - o.extra_payload_length, &packetlen); + } else if (tp->probe.type == PS_PROTO) { + packet = build_ip_raw(&source, &tp->ipdst, tp->probe.proto, tp->ttl, + tp->sport, get_random_u8 (), false, NULL, 0, + o.extra_payload, o.extra_payload_length, &packetlen); + } else { + fatal("Unknown probespec type %d in %s\n", tp->probe.type, __func__); } send_ip_packet (fd, ethptr, packet, packetlen); free (packet); @@ -891,8 +737,8 @@ Traceroute::trace (vector < Target * >&Targets) { if (tg->getState () != G_OK || !tg->hopDistance) continue; - tp = new TraceProbe (tg->proto, t->v4hostip ()->s_addr, - t->v4sourceip ()->s_addr, tg->sport, 0); + tp = new TraceProbe (t->v4hostip ()->s_addr, + t->v4sourceip ()->s_addr, tg->sport, tg->probe); sendProbe (tp); } @@ -993,7 +839,6 @@ Traceroute::outputTarget (Target * t) { TraceGroup *tg = NULL; NmapOutputTable *Tbl = NULL; - struct protoent *proto; bool last_consolidation = false; bool common_consolidation = false; char row_count = 0; @@ -1108,11 +953,14 @@ Traceroute::outputTarget (Target * t) { } /* Traceroute header and footer */ - proto = nmap_getprotbynum(htons(tg->proto)); - if(o.ipprotscan || (o.pingscan && !(o.pingtype & PINGTYPE_TCP || o.pingtype & PINGTYPE_UDP))) - log_write(LOG_PLAIN, "\nTRACEROUTE (using proto %d/%s)\n", tg->proto, proto?proto->p_name:"unknown"); - else - log_write(LOG_PLAIN, "\nTRACEROUTE (using port %d/%s)\n", tg->dport, proto2ascii(tg->proto)); + if (tg->probe.type == PS_TCP) { + log_write(LOG_PLAIN, "\nTRACEROUTE (using port %d/%s)\n", tg->probe.pd.tcp.dport, proto2ascii(tg->probe.proto)); + } else if (tg->probe.type == PS_UDP) { + log_write(LOG_PLAIN, "\nTRACEROUTE (using port %d/%s)\n", tg->probe.pd.udp.dport, proto2ascii(tg->probe.proto)); + } else if (tg->probe.type == PS_ICMP || tg->probe.type == PS_PROTO) { + struct protoent *proto = nmap_getprotbynum(htons(tg->probe.proto)); + log_write(LOG_PLAIN, "\nTRACEROUTE (using proto %d/%s)\n", tg->probe.proto, proto?proto->p_name:"unknown"); + } log_write (LOG_PLAIN, "%s", Tbl->printableTable(NULL)); if(G_TTL(tg->getState())) @@ -1130,19 +978,23 @@ Traceroute::outputXMLTrace(TraceGroup * tg) { map < u16, TraceProbe * >::const_iterator it; TraceProbe *tp = NULL; const char *hostname_tmp = NULL; - struct protoent *proto; struct in_addr addr; long timediff; short ttl_count; /* XML traceroute header */ log_write(LOG_XML, "dport); - if((proto = nmap_getprotbynum(htons(tg->proto)))) - log_write(LOG_XML, "proto=\"%s\"", proto->p_name); - else - log_write(LOG_XML, "proto=\"%d\"", tg->proto); + if (tg->probe.type == PS_TCP) { + log_write(LOG_XML, "port=\"%d\" ", tg->probe.pd.tcp.dport); + } else if (tg->probe.type == PS_UDP) { + log_write(LOG_XML, "port=\"%d\" ", tg->probe.pd.udp.dport); + } else if (tg->probe.type == PS_ICMP || tg->probe.type == PS_PROTO) { + struct protoent *proto = nmap_getprotbynum(htons(tg->probe.proto)); + if (proto == NULL) + log_write(LOG_XML, "proto=\"%d\"", tg->probe.proto); + else + log_write(LOG_XML, "proto=\"%s\"", proto->p_name); + } log_write(LOG_XML, ">\n"); /* add missing hosts host from the common path */ @@ -1185,11 +1037,10 @@ Traceroute::outputXMLTrace(TraceGroup * tg) { log_flush(LOG_XML); } -TraceGroup::TraceGroup (u32 dip, u16 sport, u16 dport, u8 proto) { +TraceGroup::TraceGroup (u32 dip, u16 sport, struct probespec& probe) { this->ipdst = dip; - this->dport = dport; this->sport = sport; - this->proto = proto; + this->probe = probe; ttl = 0; state = G_OK; remaining = 0; @@ -1263,7 +1114,7 @@ TraceGroup::retransmissions (vector < TraceProbe * >&retrans) { if (droppedPackets > 10 && (droppedPackets / ((double) droppedPackets + repliedPackets) > threshold)) { if (!scanDelay) - scanDelay = (proto == IPPROTO_TCP) ? 5 : 50; + scanDelay = (probe.type == PS_TCP) ? 5 : 50; else scanDelay = MIN (scanDelay * 2, MAX (scanDelay, 800)); droppedPackets = 0; @@ -1349,10 +1200,9 @@ TraceGroup::setHopDistance (u8 hop_distance, u8 ttl) { return this->hopDistance; } -TraceProbe::TraceProbe (u8 proto, u32 dip, u32 sip, u16 sport, u16 dport) { - this->proto = proto; +TraceProbe::TraceProbe (u32 dip, u32 sip, u16 sport, struct probespec& probe) { this->sport = sport; - this->dport = dport; + this->probe = probe; ipdst.s_addr = dip; ipsrc.s_addr = sip; ipreplysrc.s_addr = 0; diff --git a/traceroute.h b/traceroute.h index 40f692173..7076e6fde 100644 --- a/traceroute.h +++ b/traceroute.h @@ -172,20 +172,6 @@ class NmapOutputTable; -/* various pieces of scan data used by - * traceroute to find responsive ports - * and match probes */ -struct scan_info { - u8 initial_proto; - u8 icmp_type; - u8 scan_flags; - u8 open_response; - u8 open_state; - u8 closed_response; - u8 closed_state; - bool ipproto; -}; - /* Keeps track of each probes timing state */ class TimeInfo { public: @@ -217,7 +203,7 @@ class TimeInfo { * ttl. Traceprobes are stored inside tracegroups. */ class TraceProbe { public: - TraceProbe (u8 proto, u32 dip, u32 sip, u16 sport, u16 dport); + TraceProbe (u32 dip, u32 sip, u16 sport, struct probespec& probe); ~TraceProbe (); /* Return the ip address and resolved hostname in a string @@ -244,9 +230,8 @@ class TraceProbe { struct in_addr ipdst; struct in_addr ipsrc; struct in_addr ipreplysrc; + struct probespec probe; u16 sport; - u16 dport; - u8 proto; u8 ttl; char **hostname; @@ -260,7 +245,7 @@ class TraceProbe { * the ip */ class TraceGroup { public: - TraceGroup (u32 dip, u16 dport, u16 sport, u8 proto); + TraceGroup (u32 dip, u16 sport, struct probespec& probe); ~TraceGroup (); /* map of all probes sent to this TraceGroups IP address. The map * is keyed by the source port of the probe */ @@ -295,9 +280,8 @@ class TraceGroup { u16 repliedPackets; u8 consecTimeouts; /* protocol information */ - u8 proto; + struct probespec probe; u16 sport; - u16 dport; u32 ipdst; /* estimated ttl distance to target */ u8 hopDistance; @@ -344,7 +328,6 @@ class Traceroute { * the groups destination IP address */ std::map < u32, TraceGroup * >TraceGroups; - struct scan_info scaninfo; const struct scan_lists * scanlists; Target **hops; pcap_t *pd; @@ -355,7 +338,7 @@ class Traceroute { /* called by outputTarget to log XML data */ void outputXMLTrace (TraceGroup * tg); /* find a responsive port for t based on scan results */ - int getTracePort (u8 proto, Target * t); + const probespec getTraceProbe (Target * t); /* sendTTLProbes() guesses the hop distance to a * target by actively probing the host. */ void sendTTLProbes (std::vector < Target * >&Targets, std::vector < Target * >&vaild_targets);