Index: scan_engine.cc =================================================================== --- scan_engine.cc (revision 31696) +++ scan_engine.cc (working copy) @@ -235,6 +235,14 @@ return ""; // Unreached } +struct ppkt { /* Beginning of ICMP Echo/Timestamp header */ + u8 type; + u8 code; + u16 checksum; + u16 id; + u16 seq; +}; + class ConnectProbe { public: ConnectProbe(); @@ -242,6 +250,10 @@ int sd; /* Socket descriptor used for connection. -1 if not valid. */ }; +struct IPExtraProbeData_icmp { + u16 ident; +}; + struct IPExtraProbeData_tcp { u16 sport; u32 seq; /* host byte order (like the other fields */ @@ -259,6 +271,7 @@ struct IPExtraProbeData { u16 ipid; /* host byte order */ union { + struct IPExtraProbeData_icmp icmp; struct IPExtraProbeData_tcp tcp; struct IPExtraProbeData_udp udp; struct IPExtraProbeData_sctp sctp; @@ -318,6 +331,7 @@ u16 ipid() const { return probes.IP.ipid; } + u16 icmpid() const; // ICMP ident if protocol is ICMP u32 tcpseq() const; // TCP sequence number if protocol is TCP u32 sctpvtag() const; // SCTP vtag if protocol is SCTP /* Number, such as IPPROTO_TCP, IPPROTO_UDP, etc. */ @@ -904,6 +918,7 @@ struct tcp_hdr *tcp = NULL; struct udp_hdr *udp = NULL; struct sctp_hdr *sctp = NULL; + struct ppkt *icmp = NULL; const void *data; u8 hdr; @@ -939,12 +954,20 @@ sctp = (struct sctp_hdr *) data; probes.IP.pd.sctp.sport = ntohs(sctp->sh_sport); probes.IP.pd.sctp.vtag = ntohl(sctp->sh_vtag); + } else if (hdr == IPPROTO_ICMP) { + icmp = (struct ppkt *) data; + probes.IP.pd.icmp.ident = ntohs(icmp->id); } mypspec = *pspec; return; } +u16 UltraProbe::icmpid() const { + assert(mypspec.proto == IPPROTO_ICMP); + return probes.IP.pd.icmp.ident; +} + u32 UltraProbe::tcpseq() const { if (mypspec.proto == IPPROTO_TCP) return probes.IP.pd.tcp.seq; @@ -2527,6 +2550,46 @@ return true; } +static bool icmp_probe_match(const UltraScanInfo *USI, const UltraProbe *probe, + const struct ppkt *ping, + const struct sockaddr_storage *target_src, + const struct sockaddr_storage *src, + const struct sockaddr_storage *dst, + u8 proto, + u32 ipid) { + /* Check if it is ICMP or ICMPV6. */ + if (probe->protocol() != IPPROTO_ICMPV6 && probe->protocol() != IPPROTO_ICMP) + return false; + + /* Ensure the connection info matches. */ + if (sockaddr_storage_cmp(target_src, dst) != 0) + return false; + + /* Don't match a timestamp request with an echo reply, for example. */ + if (proto == IPPROTO_ICMP && + ((ping->type == 0 && probe->pspec()->pd.icmp.type != 8) || + (ping->type == 14 && probe->pspec()->pd.icmp.type != 13) || + (ping->type == 18 && probe->pspec()->pd.icmp.type != 17))) + return false; + if (proto == IPPROTO_ICMPV6 && + (ping->type == 129 && probe->pspec()->pd.icmpv6.type != 128)) + return false; + + /* Sometimes we get false results when scanning localhost with + -p- because we scan localhost with src port = dst port and + see our outgoing packet and think it is a response. */ + if (probe->dport() == probe->sport() && + sockaddr_storage_cmp(src, dst) == 0 && + probe->ipid() == ipid) + return false; /* We saw the packet we ourselves sent */ + + /* Check that the randomly-generated ping ident matches. */ + if (ntohs(ping->id) != probe->icmpid()) + return false; + + return true; +} + static bool tcp_probe_match(const UltraScanInfo *USI, const UltraProbe *probe, const HostScanStats *hss, const struct tcp_hdr *tcp, const struct sockaddr_storage *src, const struct sockaddr_storage *dst, @@ -4959,13 +5022,7 @@ struct link_header linkhdr; struct ip *ip_tmp; unsigned int bytes; - struct ppkt { - unsigned char type; - unsigned char code; - unsigned short checksum; - unsigned short id; - unsigned short seq; - } *ping; + struct ppkt *ping; long to_usec; HostScanStats *hss = NULL; std::list::iterator probeI; @@ -5060,31 +5117,9 @@ probeI--; probe = *probeI; - /* Check if it is ICMP or ICMPV6. */ - if (probe->protocol() != IPPROTO_ICMPV6 && probe->protocol() != IPPROTO_ICMP) + if (!icmp_probe_match(USI, probe, ping, &target_src, &hdr.src, &hdr.dst, hdr.proto, hdr.ipid)) continue; - /* Ensure the connection info matches. */ - if (sockaddr_storage_cmp(&target_src, &hdr.dst) != 0) - continue; - /* Don't match a timestamp request with an echo reply, for example. */ - if (hdr.proto == IPPROTO_ICMP && - ((ping->type == 0 && probe->pspec()->pd.icmp.type != 8) || - (ping->type == 14 && probe->pspec()->pd.icmp.type != 13) || - (ping->type == 18 && probe->pspec()->pd.icmp.type != 17))) - continue; - if (hdr.proto == IPPROTO_ICMPV6 && - (ping->type == 129 && probe->pspec()->pd.icmpv6.type != 128)) - continue; - - /* Sometimes we get false results when scanning localhost with - -p- because we scan localhost with src port = dst port and - see our outgoing packet and think it is a response. */ - if (probe->dport() == probe->sport() && - sockaddr_storage_cmp(&hdr.src, &hdr.dst) == 0 && - probe->ipid() == hdr.ipid) - continue; /* We saw the packet we ourselves sent */ - goodone = true; newstate = HOST_UP;