From 8ef3ed1471eca613f1d43f602932d2c99d6e2e7c Mon Sep 17 00:00:00 2001 From: dmiller Date: Mon, 20 Apr 2026 15:21:55 +0000 Subject: [PATCH] Avoid undefined behavior from unaligned accesses --- libnetutil/netutil.cc | 320 +++++++++++++++++++++++------------------- libnetutil/netutil.h | 12 +- osscan2.cc | 312 ++++++++++++++++++++++------------------ osscan2.h | 18 +-- scan_engine_raw.cc | 285 ++++++++++++++++++++----------------- tcpip.cc | 67 ++++----- tcpip.h | 2 +- traceroute.cc | 117 +++++++-------- 8 files changed, 610 insertions(+), 523 deletions(-) diff --git a/libnetutil/netutil.cc b/libnetutil/netutil.cc index 6e81f558c..edb123f60 100644 --- a/libnetutil/netutil.cc +++ b/libnetutil/netutil.cc @@ -548,7 +548,7 @@ int mac_cache_set(const struct sockaddr_storage *ss, u8 *mac){ } /* Standard BSD internet checksum routine. Uses libdnet helper functions. */ -unsigned short in_cksum(u16 *ptr,int nbytes) { +unsigned short in_cksum(const u16 *ptr,int nbytes) { int sum; sum = ip_cksum_add(ptr, nbytes, 0); @@ -558,6 +558,9 @@ unsigned short in_cksum(u16 *ptr,int nbytes) { return 0; } +const void *ipv4_get_data(const struct ip *ip, const void *p, unsigned int *len); +const void *ipv6_get_data(const struct ip6_hdr *ip6, const void *p, unsigned int *len, u8 *nxt); +const void *ipv6_get_data_any(const struct ip6_hdr *ip6, const void *p, unsigned int *len, u8 *nxt); /* Return true iff this Next Header type is an extension header we must skip to get to the upper-layer header. Types for which neither this function nor @@ -601,7 +604,7 @@ static int ipv6_is_upperlayer(u8 type) /* upperlayer_only controls whether we require a known upper-layer protocol at the end of the chain, or return the last readable header even if it is not an upper-layer protocol (may even be another extension header). */ -static const void *ipv6_get_data_primitive(const struct ip6_hdr *ip6, +static const void *ipv6_get_data_primitive(const struct ip6_hdr *ip6, const void *packet, unsigned int *len, u8 *nxt, bool upperlayer_only) { const unsigned char *p, *end; @@ -609,7 +612,7 @@ static const void *ipv6_get_data_primitive(const struct ip6_hdr *ip6, if (*len < sizeof(*ip6)) return NULL; - p = (unsigned char *) ip6; + p = (unsigned char *) packet; end = p + *len; *nxt = ip6->ip6_nxt; @@ -630,10 +633,10 @@ static const void *ipv6_get_data_primitive(const struct ip6_hdr *ip6, static const void *ip_get_data_primitive(const void *packet, unsigned int *len, struct abstract_ip_hdr *hdr, bool upperlayer_only) { - const struct ip *ip; + struct ip ip; - ip = (struct ip *) packet; - if (*len >= 20 && ip->ip_v == 4) { + memcpy(&ip, packet, sizeof(ip)); + if (*len >= 20 && ip.ip_v == 4) { struct sockaddr_in *sin; hdr->version = 4; @@ -641,19 +644,20 @@ static const void *ip_get_data_primitive(const void *packet, unsigned int *len, sin = (struct sockaddr_in *) &hdr->src; memset(&hdr->src, 0, sizeof(hdr->src)); sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ip->ip_src.s_addr; + sin->sin_addr.s_addr = ip.ip_src.s_addr; sin = (struct sockaddr_in *) &hdr->dst; memset(&hdr->dst, 0, sizeof(hdr->dst)); sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ip->ip_dst.s_addr; + sin->sin_addr.s_addr = ip.ip_dst.s_addr; - hdr->proto = ip->ip_p; - hdr->ttl = ip->ip_ttl; - hdr->ipid = ntohs(ip->ip_id); - return ipv4_get_data(ip, len); - } else if (*len >= 40 && ip->ip_v == 6) { - const struct ip6_hdr *ip6 = (struct ip6_hdr *) ip; + hdr->proto = ip.ip_p; + hdr->ttl = ip.ip_ttl; + hdr->ipid = ntohs(ip.ip_id); + return ipv4_get_data(&ip, packet, len); + } else if (*len >= 40 && ip.ip_v == 6) { + struct ip6_hdr ip6; + memcpy(&ip6, packet, sizeof(ip6)); struct sockaddr_in6 *sin6; hdr->version = 6; @@ -661,16 +665,16 @@ static const void *ip_get_data_primitive(const void *packet, unsigned int *len, sin6 = (struct sockaddr_in6 *) &hdr->src; memset(&hdr->src, 0, sizeof(hdr->src)); sin6->sin6_family = AF_INET6; - memcpy(&sin6->sin6_addr, &ip6->ip6_src, IP6_ADDR_LEN); + memcpy(&sin6->sin6_addr, &ip6.ip6_src, IP6_ADDR_LEN); sin6 = (struct sockaddr_in6 *) &hdr->dst; memset(&hdr->dst, 0, sizeof(hdr->dst)); sin6->sin6_family = AF_INET6; - memcpy(&sin6->sin6_addr, &ip6->ip6_dst, IP6_ADDR_LEN); + memcpy(&sin6->sin6_addr, &ip6.ip6_dst, IP6_ADDR_LEN); - hdr->ttl = ip6->ip6_hlim; - hdr->ipid = ntohl(ip6->ip6_flow & IP6_FLOWLABEL_MASK); - return ipv6_get_data_primitive(ip6, len, &hdr->proto, upperlayer_only); + hdr->ttl = ip6.ip6_hlim; + hdr->ipid = ntohl(ip6.ip6_flow & IP6_FLOWLABEL_MASK); + return ipv6_get_data_primitive(&ip6, packet, len, &hdr->proto, upperlayer_only); } return NULL; @@ -694,7 +698,7 @@ const void *ip_get_data_any(const void *packet, unsigned int *len, } /* Get the upper-layer protocol from an IPv4 packet. */ -const void *ipv4_get_data(const struct ip *ip, unsigned int *len) +const void *ipv4_get_data(const struct ip *ip, const void *p, unsigned int *len) { unsigned int header_len; @@ -707,33 +711,56 @@ const void *ipv4_get_data(const struct ip *ip, unsigned int *len) return NULL; *len -= header_len; - return (char *) ip + header_len; + return (const u8 *)p + header_len; +} + +const void *ipv4_get_data(const void *p, unsigned int *len) +{ + struct ip ip; + memcpy(&ip, p, sizeof(ip)); + return ipv4_get_data(&ip, p, len); } /* Get the upper-layer protocol from an IPv6 packet. This skips over known extension headers. The length of the upper-layer payload is stored in *len. The protocol is stored in *nxt. Returns NULL in case of error. */ -const void *ipv6_get_data(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt) +const void *ipv6_get_data(const struct ip6_hdr *ip6, const void *p, unsigned int *len, u8 *nxt) { - return ipv6_get_data_primitive(ip6, len, nxt, true); + return ipv6_get_data_primitive(ip6, p, len, nxt, true); +} + +const void *ipv6_get_data(const void *p, unsigned int *len, u8 *nxt) +{ + struct ip6_hdr ip6; + memcpy(&ip6, p, sizeof(ip6)); + return ipv6_get_data(&ip6, p, len, nxt); } /* Get the protocol payload from an IPv6 packet. This skips over known extension headers. It differs from ipv6_get_data in that it will return a result even if the final header is not a known upper-layer protocol. */ -const void *ipv6_get_data_any(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt) +const void *ipv6_get_data_any(const struct ip6_hdr *ip6, const void *p, unsigned int *len, u8 *nxt) { - return ipv6_get_data_primitive(ip6, len, nxt, false); + return ipv6_get_data_primitive(ip6, p, len, nxt, false); } -const void *icmp_get_data(const struct icmp_hdr *icmp, unsigned int *len) +const void *ipv6_get_data_any(const void *p, unsigned int *len, u8 *nxt) +{ + struct ip6_hdr ip6; + memcpy(&ip6, p, sizeof(ip6)); + return ipv6_get_data_any(&ip6, p, len, nxt); +} + +const void *icmp_get_data(const void *icmp, unsigned int *len) { unsigned int header_len; + struct icmp_hdr hdr; + memcpy(&hdr, icmp, sizeof(hdr)); - if (icmp->icmp_type == ICMP_TIMEXCEED || icmp->icmp_type == ICMP_UNREACH) + if (hdr.icmp_type == ICMP_TIMEXCEED || hdr.icmp_type == ICMP_UNREACH) header_len = 8; else - netutil_fatal("%s passed ICMP packet with unhandled type %d", __func__, icmp->icmp_type); + netutil_fatal("%s passed ICMP packet with unhandled type %d", __func__, hdr.icmp_type); if (header_len > *len) return NULL; *len -= header_len; @@ -741,14 +768,16 @@ const void *icmp_get_data(const struct icmp_hdr *icmp, unsigned int *len) return (char *) icmp + header_len; } -const void *icmpv6_get_data(const struct icmpv6_hdr *icmpv6, unsigned int *len) +const void *icmpv6_get_data(const void *icmpv6, unsigned int *len) { unsigned int header_len; + struct icmpv6_hdr hdr; + memcpy(&hdr, icmpv6, sizeof(hdr)); - if (icmpv6->icmpv6_type == ICMPV6_TIMEXCEED || icmpv6->icmpv6_type == ICMPV6_UNREACH) + if (hdr.icmpv6_type == ICMPV6_TIMEXCEED || hdr.icmpv6_type == ICMPV6_UNREACH) header_len = 8; else - netutil_fatal("%s passed ICMPv6 packet with unhandled type %d", __func__, icmpv6->icmpv6_type); + netutil_fatal("%s passed ICMPv6 packet with unhandled type %d", __func__, hdr.icmpv6_type); if (header_len > *len) return NULL; *len -= header_len; @@ -2352,7 +2381,6 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { const u8 *data; unsigned int datalen; - struct tcp_hdr *tcp = NULL; /* TCP header structure. */ struct udp_hdr *udp = NULL; /* UDP header structure. */ struct sctp_hdr *sctp = NULL; /* SCTP header structure. */ static char protoinfo[1024] = ""; /* Stores final info string. */ @@ -2381,11 +2409,10 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { /* IP INFORMATION ************************************************************/ if (hdr.version == 4) { /* IPv4 */ - const struct ip *ip; + struct ip ip; + memcpy(&ip, packet, sizeof(ip)); const struct sockaddr_in *sin; - ip = (struct ip *) packet; - /* Obtain IP source and destination info */ sin = (struct sockaddr_in *) &hdr.src; inet_ntop(AF_INET, (void *)&sin->sin_addr.s_addr, srchost, sizeof(srchost)); @@ -2393,10 +2420,10 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { inet_ntop(AF_INET, (void *)&sin->sin_addr.s_addr, dsthost, sizeof(dsthost)); /* Compute fragment offset and check if flags are set */ - frag_off = 8 * (ntohs(ip->ip_off) & 8191) /* 2^13 - 1 */; - more_fragments = ntohs(ip->ip_off) & IP_MF; - dont_fragment = ntohs(ip->ip_off) & IP_DF; - reserved_flag = ntohs(ip->ip_off) & IP_RF; + frag_off = 8 * (ntohs(ip.ip_off) & 8191) /* 2^13 - 1 */; + more_fragments = ntohs(ip.ip_off) & IP_MF; + dont_fragment = ntohs(ip.ip_off) & IP_DF; + reserved_flag = ntohs(ip.ip_off) & IP_RF; /* Is this a fragmented packet? is it the last fragment? */ if (frag_off || more_fragments) { @@ -2406,33 +2433,33 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { /* Create a string with information relevant to the specified level of detail */ if (detail == LOW_DETAIL) { Snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%hu iplen=%hu%s %s%s%s", - ip->ip_ttl, (unsigned short) ntohs(ip->ip_id), (unsigned short) ntohs(ip->ip_len), fragnfo, - ip->ip_hl==5?"":"ipopts={", - ip->ip_hl==5?"":format_ip_options((u8*) ip + sizeof(struct ip), MIN((unsigned)(ip->ip_hl-5)*4,len-sizeof(struct ip))), - ip->ip_hl==5?"":"}"); + ip.ip_ttl, (unsigned short) ntohs(ip.ip_id), (unsigned short) ntohs(ip.ip_len), fragnfo, + ip.ip_hl==5?"":"ipopts={", + ip.ip_hl==5?"":format_ip_options((u8*) packet + sizeof(struct ip), MIN((unsigned)(ip.ip_hl-5)*4,len-sizeof(struct ip))), + ip.ip_hl==5?"":"}"); } else if (detail == MEDIUM_DETAIL) { Snprintf(ipinfo, sizeof(ipinfo), "ttl=%d id=%hu proto=%d csum=0x%04x iplen=%hu%s %s%s%s", - ip->ip_ttl, (unsigned short) ntohs(ip->ip_id), - ip->ip_p, ntohs(ip->ip_sum), - (unsigned short) ntohs(ip->ip_len), fragnfo, - ip->ip_hl==5?"":"ipopts={", - ip->ip_hl==5?"":format_ip_options((u8*) ip + sizeof(struct ip), MIN((unsigned)(ip->ip_hl-5)*4,len-sizeof(struct ip))), - ip->ip_hl==5?"":"}"); + ip.ip_ttl, (unsigned short) ntohs(ip.ip_id), + ip.ip_p, ntohs(ip.ip_sum), + (unsigned short) ntohs(ip.ip_len), fragnfo, + ip.ip_hl==5?"":"ipopts={", + ip.ip_hl==5?"":format_ip_options((u8*) packet + sizeof(struct ip), MIN((unsigned)(ip.ip_hl-5)*4,len-sizeof(struct ip))), + ip.ip_hl==5?"":"}"); } else if (detail == HIGH_DETAIL) { Snprintf(ipinfo, sizeof(ipinfo), "ver=%d ihl=%d tos=0x%02x iplen=%hu id=%hu%s%s%s%s foff=%d%s ttl=%d proto=%d csum=0x%04x%s%s%s", - ip->ip_v, ip->ip_hl, - ip->ip_tos, (unsigned short) ntohs(ip->ip_len), - (unsigned short) ntohs(ip->ip_id), + ip.ip_v, ip.ip_hl, + ip.ip_tos, (unsigned short) ntohs(ip.ip_len), + (unsigned short) ntohs(ip.ip_id), (reserved_flag||dont_fragment||more_fragments) ? " flg=" : "", (reserved_flag)? "x" : "", (dont_fragment)? "D" : "", (more_fragments)? "M": "", frag_off, (more_fragments) ? "+" : "", - ip->ip_ttl, ip->ip_p, - ntohs(ip->ip_sum), - ip->ip_hl==5?"":" ipopts={", - ip->ip_hl==5?"":format_ip_options((u8*) ip + sizeof(struct ip), MIN((unsigned)(ip->ip_hl-5)*4,len-sizeof(struct ip))), - ip->ip_hl==5?"":"}"); + ip.ip_ttl, ip.ip_p, + ntohs(ip.ip_sum), + ip.ip_hl==5?"":" ipopts={", + ip.ip_hl==5?"":format_ip_options((u8*) packet + sizeof(struct ip), MIN((unsigned)(ip.ip_hl-5)*4,len-sizeof(struct ip))), + ip.ip_hl==5?"":"}"); } } else { /* IPv6 */ const struct ip6_hdr *ip6; @@ -2472,7 +2499,7 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { char tcpinfo[64] = ""; char buf[32]; char tcpoptinfo[256] = ""; - tcp = (struct tcp_hdr *) data; + struct tcp_hdr tcp; /* Let's parse the TCP header. The following code is very ugly because we * have to deal with a lot of different situations. We don't want to @@ -2511,39 +2538,39 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { else if (frag_off > 0) { /* Fragmentation is on 8-byte boundaries, so 8 is the only legal value here. */ assert(frag_off == 8); - tcp = (struct tcp_hdr *)((u8 *) tcp - frag_off); // ugly? + memcpy((u8 *)&tcp + frag_off, data - frag_off, sizeof(tcp) - frag_off); /* TCP Flags */ p = tflags; /* These are basically in tcpdump order */ - if (tcp->th_flags & TH_SYN) + if (tcp.th_flags & TH_SYN) *p++ = 'S'; - if (tcp->th_flags & TH_FIN) + if (tcp.th_flags & TH_FIN) *p++ = 'F'; - if (tcp->th_flags & TH_RST) + if (tcp.th_flags & TH_RST) *p++ = 'R'; - if (tcp->th_flags & TH_PUSH) + if (tcp.th_flags & TH_PUSH) *p++ = 'P'; - if (tcp->th_flags & TH_ACK) { + if (tcp.th_flags & TH_ACK) { *p++ = 'A'; Snprintf(tcpinfo, sizeof(tcpinfo), " ack=%lu", - (unsigned long) ntohl(tcp->th_ack)); + (unsigned long) ntohl(tcp.th_ack)); } - if (tcp->th_flags & TH_URG) + if (tcp.th_flags & TH_URG) *p++ = 'U'; - if (tcp->th_flags & TH_ECE) + if (tcp.th_flags & TH_ECE) *p++ = 'E'; /* rfc 2481/3168 */ - if (tcp->th_flags & TH_CWR) + if (tcp.th_flags & TH_CWR) *p++ = 'C'; /* rfc 2481/3168 */ *p++ = '\0'; /* TCP Options */ - if ((u32) tcp->th_off * 4 > sizeof(struct tcp_hdr)) { - if (datalen < (u32) tcp->th_off * 4 - frag_off) { + if ((u32) tcp.th_off * 4 > sizeof(struct tcp_hdr)) { + if (datalen < (u32) tcp.th_off * 4 - frag_off) { Snprintf(tcpoptinfo, sizeof(tcpoptinfo), "option incomplete"); } else { - tcppacketoptinfo((u8*) tcp + sizeof(struct tcp_hdr), - tcp->th_off*4 - sizeof(struct tcp_hdr), + tcppacketoptinfo((u8*) data + sizeof(struct tcp_hdr), + tcp.th_off*4 - sizeof(struct tcp_hdr), tcpoptinfo, sizeof(tcpoptinfo)); } } @@ -2554,22 +2581,22 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { } else if (detail == MEDIUM_DETAIL) { Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:?? > %s:?? %s ack=%lu win=%hu %s IP [%s]", srchost, dsthost, tflags, - (unsigned long) ntohl(tcp->th_ack), (unsigned short) ntohs(tcp->th_win), + (unsigned long) ntohl(tcp.th_ack), (unsigned short) ntohs(tcp.th_win), tcpoptinfo, ipinfo); } else if (detail == HIGH_DETAIL) { if (datalen >= 12) { /* We have at least bytes 8-20 */ Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:?? > %s:?? %s seq=%lu ack=%lu off=%d res=%d win=%hu csum=0x%04X urp=%hu%s%s] IP [%s]", srchost, dsthost, tflags, - (unsigned long) ntohl(tcp->th_seq), - (unsigned long) ntohl(tcp->th_ack), - (u8)tcp->th_off, (u8)tcp->th_x2, (unsigned short) ntohs(tcp->th_win), - ntohs(tcp->th_sum), (unsigned short) ntohs(tcp->th_urp), + (unsigned long) ntohl(tcp.th_seq), + (unsigned long) ntohl(tcp.th_ack), + (u8)tcp.th_off, (u8)tcp.th_x2, (unsigned short) ntohs(tcp.th_win), + ntohs(tcp.th_sum), (unsigned short) ntohs(tcp.th_urp), (tcpoptinfo[0]!='\0') ? " " : "", tcpoptinfo, ipinfo); } else { /* We only have bytes 8-16 */ Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:?? > %s:?? %s ack=%lu win=%hu %s IP [%s]", srchost, dsthost, tflags, - (unsigned long) ntohl(tcp->th_ack), (unsigned short) ntohs(tcp->th_win), + (unsigned long) ntohl(tcp.th_ack), (unsigned short) ntohs(tcp.th_win), tcpoptinfo, ipinfo); } } @@ -2579,25 +2606,26 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { /* CASE 3: where the IP packet is not a fragment but for some reason, we * don't have the entire TCP header, just part of it.*/ else if (datalen < 20) { + memcpy(&tcp, data, MIN(datalen, sizeof(tcp))); /* We know we have the first 8 bytes, so what's left? */ /* We only have the first 64 bits: ports and seq number */ if (datalen < 12) { Snprintf(tcpinfo, sizeof(tcpinfo), "TCP %s:%hu > %s:%hu ?? seq=%lu (incomplete) %s", - srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, - (unsigned short) ntohs(tcp->th_dport), (unsigned long) ntohl(tcp->th_seq), ipinfo); + srchost, (unsigned short) ntohs(tcp.th_sport), dsthost, + (unsigned short) ntohs(tcp.th_dport), (unsigned long) ntohl(tcp.th_seq), ipinfo); } /* We only have the first 96 bits: ports, seq and ack number */ else if (datalen < 16) { if (detail == LOW_DETAIL) { /* We don't print ACK in low detail */ Snprintf(tcpinfo, sizeof(tcpinfo), "TCP %s:%hu > %s:%hu seq=%lu (incomplete), %s", - srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, - (unsigned short) ntohs(tcp->th_dport), (unsigned long) ntohl(tcp->th_seq), ipinfo); + srchost, (unsigned short) ntohs(tcp.th_sport), dsthost, + (unsigned short) ntohs(tcp.th_dport), (unsigned long) ntohl(tcp.th_seq), ipinfo); } else { Snprintf(tcpinfo, sizeof(tcpinfo), "TCP [%s:%hu > %s:%hu seq=%lu ack=%lu (incomplete)] IP [%s]", - srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, - (unsigned short) ntohs(tcp->th_dport), (unsigned long) ntohl(tcp->th_seq), - (unsigned long) ntohl(tcp->th_ack), ipinfo); + srchost, (unsigned short) ntohs(tcp.th_sport), dsthost, + (unsigned short) ntohs(tcp.th_dport), (unsigned long) ntohl(tcp.th_seq), + (unsigned long) ntohl(tcp.th_ack), ipinfo); } } @@ -2605,25 +2633,25 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { else { p = tflags; /* These are basically in tcpdump order */ - if (tcp->th_flags & TH_SYN) + if (tcp.th_flags & TH_SYN) *p++ = 'S'; - if (tcp->th_flags & TH_FIN) + if (tcp.th_flags & TH_FIN) *p++ = 'F'; - if (tcp->th_flags & TH_RST) + if (tcp.th_flags & TH_RST) *p++ = 'R'; - if (tcp->th_flags & TH_PUSH) + if (tcp.th_flags & TH_PUSH) *p++ = 'P'; - if (tcp->th_flags & TH_ACK) { + if (tcp.th_flags & TH_ACK) { *p++ = 'A'; Snprintf(buf, sizeof(buf), " ack=%lu", - (unsigned long) ntohl(tcp->th_ack)); + (unsigned long) ntohl(tcp.th_ack)); strncat(tcpinfo, buf, sizeof(tcpinfo) - strlen(tcpinfo) - 1); } - if (tcp->th_flags & TH_URG) + if (tcp.th_flags & TH_URG) *p++ = 'U'; - if (tcp->th_flags & TH_ECE) + if (tcp.th_flags & TH_ECE) *p++ = 'E'; /* rfc 2481/3168 */ - if (tcp->th_flags & TH_CWR) + if (tcp.th_flags & TH_CWR) *p++ = 'C'; /* rfc 2481/3168 */ *p++ = '\0'; @@ -2631,22 +2659,22 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { /* Create a string with TCP information relevant to the specified level of detail */ if (detail == LOW_DETAIL) { /* We don't print ACK in low detail */ Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:%hu > %s:%hu %s %s seq=%lu win=%hu (incomplete)", - srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport), - tflags, ipinfo, (unsigned long) ntohl(tcp->th_seq), - (unsigned short) ntohs(tcp->th_win)); + srchost, (unsigned short) ntohs(tcp.th_sport), dsthost, (unsigned short) ntohs(tcp.th_dport), + tflags, ipinfo, (unsigned long) ntohl(tcp.th_seq), + (unsigned short) ntohs(tcp.th_win)); } else if (detail == MEDIUM_DETAIL) { Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu ack=%lu win=%hu (incomplete)] IP [%s]", - srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport), - tflags, (unsigned long) ntohl(tcp->th_seq), - (unsigned long) ntohl(tcp->th_ack), - (unsigned short) ntohs(tcp->th_win), ipinfo); + srchost, (unsigned short) ntohs(tcp.th_sport), dsthost, (unsigned short) ntohs(tcp.th_dport), + tflags, (unsigned long) ntohl(tcp.th_seq), + (unsigned long) ntohl(tcp.th_ack), + (unsigned short) ntohs(tcp.th_win), ipinfo); } else if (detail == HIGH_DETAIL) { Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu ack=%lu off=%d res=%d win=%hu (incomplete)] IP [%s]", - srchost, (unsigned short) ntohs(tcp->th_sport), - dsthost, (unsigned short) ntohs(tcp->th_dport), - tflags, (unsigned long) ntohl(tcp->th_seq), - (unsigned long) ntohl(tcp->th_ack), - (u8)tcp->th_off, (u8)tcp->th_x2, (unsigned short) ntohs(tcp->th_win), + srchost, (unsigned short) ntohs(tcp.th_sport), + dsthost, (unsigned short) ntohs(tcp.th_dport), + tflags, (unsigned long) ntohl(tcp.th_seq), + (unsigned long) ntohl(tcp.th_ack), + (u8)tcp.th_off, (u8)tcp.th_x2, (unsigned short) ntohs(tcp.th_win), ipinfo); } } @@ -2655,39 +2683,40 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { /* CASE 4: where we (finally!) have a full 20 byte TCP header so we can * safely print all fields */ else { /* if (datalen >= 20) */ + memcpy(&tcp, data, MIN(datalen, sizeof(tcp))); /* TCP Flags */ p = tflags; /* These are basically in tcpdump order */ - if (tcp->th_flags & TH_SYN) + if (tcp.th_flags & TH_SYN) *p++ = 'S'; - if (tcp->th_flags & TH_FIN) + if (tcp.th_flags & TH_FIN) *p++ = 'F'; - if (tcp->th_flags & TH_RST) + if (tcp.th_flags & TH_RST) *p++ = 'R'; - if (tcp->th_flags & TH_PUSH) + if (tcp.th_flags & TH_PUSH) *p++ = 'P'; - if (tcp->th_flags & TH_ACK) { + if (tcp.th_flags & TH_ACK) { *p++ = 'A'; Snprintf(buf, sizeof(buf), " ack=%lu", - (unsigned long) ntohl(tcp->th_ack)); + (unsigned long) ntohl(tcp.th_ack)); strncat(tcpinfo, buf, sizeof(tcpinfo) - strlen(tcpinfo) - 1); } - if (tcp->th_flags & TH_URG) + if (tcp.th_flags & TH_URG) *p++ = 'U'; - if (tcp->th_flags & TH_ECE) + if (tcp.th_flags & TH_ECE) *p++ = 'E'; /* rfc 2481/3168 */ - if (tcp->th_flags & TH_CWR) + if (tcp.th_flags & TH_CWR) *p++ = 'C'; /* rfc 2481/3168 */ *p++ = '\0'; /* TCP Options */ - if ((u32) tcp->th_off * 4 > sizeof(struct tcp_hdr)) { - if (datalen < (unsigned int) tcp->th_off * 4) { + if ((u32) tcp.th_off * 4 > sizeof(struct tcp_hdr)) { + if (datalen < (unsigned int) tcp.th_off * 4) { Snprintf(tcpoptinfo, sizeof(tcpoptinfo), "option incomplete"); } else { - tcppacketoptinfo((u8*) tcp + sizeof(struct tcp_hdr), - tcp->th_off*4 - sizeof(struct tcp_hdr), + tcppacketoptinfo((u8*) data + sizeof(struct tcp_hdr), + tcp.th_off*4 - sizeof(struct tcp_hdr), tcpoptinfo, sizeof(tcpoptinfo)); } } @@ -2695,24 +2724,24 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { /* Rest of header fields */ if (detail == LOW_DETAIL) { Snprintf(protoinfo, sizeof(protoinfo), "TCP %s:%hu > %s:%hu %s %s seq=%lu win=%hu %s", - srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport), - tflags, ipinfo, (unsigned long) ntohl(tcp->th_seq), - (unsigned short) ntohs(tcp->th_win), tcpoptinfo); + srchost, (unsigned short) ntohs(tcp.th_sport), dsthost, (unsigned short) ntohs(tcp.th_dport), + tflags, ipinfo, (unsigned long) ntohl(tcp.th_seq), + (unsigned short) ntohs(tcp.th_win), tcpoptinfo); } else if (detail == MEDIUM_DETAIL) { Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu win=%hu csum=0x%04X%s%s] IP [%s]", - srchost, (unsigned short) ntohs(tcp->th_sport), dsthost, (unsigned short) ntohs(tcp->th_dport), - tflags, (unsigned long) ntohl(tcp->th_seq), - (unsigned short) ntohs(tcp->th_win), (unsigned short) ntohs(tcp->th_sum), + srchost, (unsigned short) ntohs(tcp.th_sport), dsthost, (unsigned short) ntohs(tcp.th_dport), + tflags, (unsigned long) ntohl(tcp.th_seq), + (unsigned short) ntohs(tcp.th_win), (unsigned short) ntohs(tcp.th_sum), (tcpoptinfo[0]!='\0') ? " " : "", tcpoptinfo, ipinfo); } else if (detail == HIGH_DETAIL) { Snprintf(protoinfo, sizeof(protoinfo), "TCP [%s:%hu > %s:%hu %s seq=%lu ack=%lu off=%d res=%d win=%hu csum=0x%04X urp=%hu%s%s] IP [%s]", - srchost, (unsigned short) ntohs(tcp->th_sport), - dsthost, (unsigned short) ntohs(tcp->th_dport), - tflags, (unsigned long) ntohl(tcp->th_seq), - (unsigned long) ntohl(tcp->th_ack), - (u8)tcp->th_off, (u8)tcp->th_x2, (unsigned short) ntohs(tcp->th_win), - ntohs(tcp->th_sum), (unsigned short) ntohs(tcp->th_urp), + srchost, (unsigned short) ntohs(tcp.th_sport), + dsthost, (unsigned short) ntohs(tcp.th_dport), + tflags, (unsigned long) ntohl(tcp.th_seq), + (unsigned long) ntohl(tcp.th_ack), + (u8)tcp.th_off, (u8)tcp.th_x2, (unsigned short) ntohs(tcp.th_win), + ntohs(tcp.th_sum), (unsigned short) ntohs(tcp.th_urp), (tcpoptinfo[0]!='\0') ? " " : "", tcpoptinfo, ipinfo); } @@ -2868,14 +2897,6 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { if ((ip2->ip_v != 4) || ((ip2->ip_hl * 4) < 20) || ((ip2->ip_hl * 4) > 60)) { Snprintf(icmptype, sizeof icmptype, "Destination unreachable (bogus original datagram)"); goto icmpbad; - } else { - /* We have the original datagram + the first 8 bytes of the - * transport layer header */ - if (pktlen + 8 < datalen) { - tcp = (struct tcp_hdr *) ((char *) ip2 + (ip2->ip_hl * 4)); - udp = (struct udp_hdr *) ((char *) ip2 + (ip2->ip_hl * 4)); - sctp = (struct sctp_hdr *) ((char *) ip2 + (ip2->ip_hl * 4)); - } } /* Determine the IP the original datagram was sent to */ @@ -2897,12 +2918,21 @@ const char *ippackethdrinfo(const u8 *packet, u32 len, int detail) { case 3: if (pktlen + 8 < datalen) { - if (ip2->ip_p == IPPROTO_UDP && udp) - Snprintf(icmptype, sizeof icmptype, "Port %hu unreachable", (unsigned short) ntohs(udp->uh_dport)); - else if (ip2->ip_p == IPPROTO_TCP && tcp) - Snprintf(icmptype, sizeof icmptype, "Port %hu unreachable", (unsigned short) ntohs(tcp->th_dport)); - else if (ip2->ip_p == IPPROTO_SCTP && sctp) - Snprintf(icmptype, sizeof icmptype, "Port %hu unreachable", (unsigned short) ntohs(sctp->sh_dport)); + /* We have the original datagram + the first 8 bytes of the + * transport layer header */ + const u8 *pp = (const u8 *)ip2 + (ip2->ip_hl * 4); + int offset = -1; + if (ip2->ip_p == IPPROTO_UDP) + offset = offsetof(struct udp_hdr, uh_dport); + else if (ip2->ip_p == IPPROTO_TCP) + offset = offsetof(struct tcp_hdr, th_dport); + else if (ip2->ip_p == IPPROTO_SCTP) + offset = offsetof(struct sctp_hdr, sh_dport); + + if (offset >= 0) { + pp += offset; + Snprintf(icmptype, sizeof icmptype, "Port %hu unreachable", (u16)((pp[0] << 8) + pp[1])); + } else Snprintf(icmptype, sizeof icmptype, "Port unreachable (unknown protocol %u)", ip2->ip_p); } diff --git a/libnetutil/netutil.h b/libnetutil/netutil.h index 6b024b99c..4944fe30f 100644 --- a/libnetutil/netutil.h +++ b/libnetutil/netutil.h @@ -184,17 +184,17 @@ const void *ip_get_data(const void *packet, unsigned int *len, const void *ip_get_data_any(const void *packet, unsigned int *len, struct abstract_ip_hdr *hdr); /* Get the upper-layer protocol from an IPv4 packet. */ -const void *ipv4_get_data(const struct ip *ip, unsigned int *len); +const void *ipv4_get_data(const void *ip, unsigned int *len); /* Get the upper-layer protocol from an IPv6 packet. This skips over known extension headers. The length of the upper-layer payload is stored in *len. The protocol is stored in *nxt. Returns NULL in case of error. */ -const void *ipv6_get_data(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt); -const void *ipv6_get_data_any(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt); -const void *icmp_get_data(const struct icmp_hdr *icmp, unsigned int *len); -const void *icmpv6_get_data(const struct icmpv6_hdr *icmpv6, unsigned int *len); +const void *ipv6_get_data(const void *ip6, unsigned int *len, u8 *nxt); +const void *ipv6_get_data_any(const void *ip6, unsigned int *len, u8 *nxt); +const void *icmp_get_data(const void *icmp, unsigned int *len); +const void *icmpv6_get_data(const void *icmpv6, unsigned int *len); /* Standard BSD internet checksum routine. */ -unsigned short in_cksum(u16 *ptr, int nbytes); +unsigned short in_cksum(const u16 *ptr, int nbytes); /* Calculate the Internet checksum of some given data concatentated with the IPv4 pseudo-header. See RFC 1071 and TCP/IP Illustrated sections 3.2, 11.3, diff --git a/osscan2.cc b/osscan2.cc index 5db94425b..d6d932dee 100644 --- a/osscan2.cc +++ b/osscan2.cc @@ -463,7 +463,6 @@ static void doSeqTests(OsScanInfo *OSI, HostOsScan *HOS) { unsigned int expectReplies = 0; long to_usec = 0; int timeToSleep = 0; - struct ip *ip = NULL; struct link_header linkhdr; struct sockaddr_storage ss; unsigned int bytes = 0; @@ -560,7 +559,7 @@ static void doSeqTests(OsScanInfo *OSI, HostOsScan *HOS) { if (o.debugging > 2) log_write(LOG_PLAIN, "pcap wait time is %ld.\n", to_usec); - ip = (struct ip*) readipv4_pcap(HOS->pd, &bytes, to_usec, &rcvdtime, &linkhdr, true); + const u8 *ip = readipv4_pcap(HOS->pd, &bytes, to_usec, &rcvdtime, &linkhdr, true); gettimeofday(&now, NULL); @@ -577,11 +576,15 @@ static void doSeqTests(OsScanInfo *OSI, HostOsScan *HOS) { timedout = true; } - if (bytes < (4 * ip->ip_hl) + 4U) + struct ip iphdr; + if (bytes < sizeof(iphdr)) + continue; + memcpy(&iphdr, ip, sizeof(iphdr)); + if (bytes < (4 * iphdr.ip_hl) + 4U) continue; memset(&ss, 0, sizeof(ss)); - ((struct sockaddr_in *) &ss)->sin_addr.s_addr = ip->ip_src.s_addr; + ((struct sockaddr_in *) &ss)->sin_addr.s_addr = iphdr.ip_src.s_addr; ss.ss_family = AF_INET; hsi = OSI->findIncompleteHost(&ss); if (!hsi) @@ -630,7 +633,6 @@ static void doTUITests(OsScanInfo *OSI, HostOsScan *HOS) { long to_usec; int timeToSleep = 0; - struct ip *ip = NULL; struct link_header linkhdr; struct sockaddr_storage ss; unsigned int bytes; @@ -731,7 +733,7 @@ static void doTUITests(OsScanInfo *OSI, HostOsScan *HOS) { if (o.debugging > 2) log_write(LOG_PLAIN, "pcap wait time is %ld.\n", to_usec); - ip = (struct ip*) readipv4_pcap(HOS->pd, &bytes, to_usec, &rcvdtime, &linkhdr, true); + const u8 *ip = readipv4_pcap(HOS->pd, &bytes, to_usec, &rcvdtime, &linkhdr, true); gettimeofday(&now, NULL); @@ -748,11 +750,15 @@ static void doTUITests(OsScanInfo *OSI, HostOsScan *HOS) { timedout = true; } - if (bytes < (4 * ip->ip_hl) + 4U) + struct ip iphdr; + if (bytes < sizeof(iphdr)) + continue; + memcpy(&iphdr, ip, sizeof(iphdr)); + if (bytes < (4 * iphdr.ip_hl) + 4U) continue; memset(&ss, 0, sizeof(ss)); - ((struct sockaddr_in *) &ss)->sin_addr.s_addr = ip->ip_src.s_addr; + ((struct sockaddr_in *) &ss)->sin_addr.s_addr = iphdr.ip_src.s_addr; ss.ss_family = AF_INET; hsi = OSI->findIncompleteHost(&ss); if (!hsi) @@ -1889,36 +1895,39 @@ void HostOsScan::sendTUdpProbe(HostOsScanStats *hss, int probeNo) { } -bool HostOsScan::processResp(HostOsScanStats *hss, const struct ip *ip, unsigned int len, struct timeval *rcvdtime) { - const struct ip *ip2; - const struct tcp_hdr *tcp; - const struct icmp *icmp; +bool HostOsScan::processResp(HostOsScanStats *hss, const u8 *pkt, unsigned int len, struct timeval *rcvdtime) { int testno; bool isPktUseful = false; std::list::iterator probeI; OFProbe *probe; - if (len < 20 || len < (4 * ip->ip_hl) + 4U) + struct ip ip; + if (len < sizeof(ip)) + return false; + memcpy(&ip, pkt, sizeof(ip)); + if (len < (4 * ip.ip_hl) + 4U) return false; - len -= 4 * ip->ip_hl; + len -= 4 * ip.ip_hl; - if (ip->ip_p == IPPROTO_TCP) { - if (len < 20) + if (ip.ip_p == IPPROTO_TCP) { + struct tcp_hdr tcp; + if (len < sizeof(tcp)) return false; - tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl)); - if (len < (unsigned int)(4 * tcp->th_off)) + const u8 *tcppkt = pkt + 4 * ip.ip_hl; + memcpy(&tcp, tcppkt, sizeof(tcp)); + if (len < (unsigned int)(4 * tcp.th_off)) return false; - testno = ntohs(tcp->th_dport) - tcpPortBase; + testno = ntohs(tcp.th_dport) - tcpPortBase; if (testno >= 0 && testno < NUM_SEQ_SAMPLES) { /* TSeq */ - isPktUseful = processTSeqResp(hss, ip, testno); + isPktUseful = processTSeqResp(hss, pkt, testno); if (isPktUseful) { - hss->ipid.tcp_ipids[testno] = ntohs(ip->ip_id); + hss->ipid.tcp_ipids[testno] = ntohs(ip.ip_id); probeI = hss->getActiveProbe(OFP_TSEQ, testno); - /* printf("tcp ipid = %d\n", ntohs(ip->ip_id)); */ + /* printf("tcp ipid = %d\n", ntohs(ip.ip_id)); */ } /* Use the seq response to do other tests. We don't care if it @@ -1926,17 +1935,17 @@ bool HostOsScan::processResp(HostOsScanStats *hss, const struct ip *ip, unsigned */ if (testno == 0) { /* the first reply is used to do T1 */ - processT1_7Resp(hss, ip, 0); + processT1_7Resp(hss, pkt, 0); } /* the 1st NUM_SEQ_SAMPLES replies are used to do TOps and TWin */ - processTOpsResp(hss, tcp, testno); - processTWinResp(hss, tcp, testno); + processTOpsResp(hss, tcppkt, testno); + processTWinResp(hss, &tcp, testno); } else if (testno >= NUM_SEQ_SAMPLES && testno < NUM_SEQ_SAMPLES + 6) { /* TOps/Twin */ - isPktUseful = processTOpsResp(hss, tcp, testno - NUM_SEQ_SAMPLES); - isPktUseful |= processTWinResp(hss, tcp, testno - NUM_SEQ_SAMPLES); + isPktUseful = processTOpsResp(hss, tcppkt, testno - NUM_SEQ_SAMPLES); + isPktUseful |= processTWinResp(hss, &tcp, testno - NUM_SEQ_SAMPLES); if (isPktUseful) { probeI = hss->getActiveProbe(OFP_TOPS, testno - NUM_SEQ_SAMPLES); } @@ -1944,14 +1953,14 @@ bool HostOsScan::processResp(HostOsScanStats *hss, const struct ip *ip, unsigned } else if (testno == NUM_SEQ_SAMPLES + 6) { /* TEcn */ - isPktUseful = processTEcnResp(hss, ip); + isPktUseful = processTEcnResp(hss, pkt); if (isPktUseful) { probeI = hss->getActiveProbe(OFP_TECN, 0); } } else if (testno >= NUM_SEQ_SAMPLES + 7 && testno < NUM_SEQ_SAMPLES + 14) { - isPktUseful = processT1_7Resp(hss, ip, testno - NUM_SEQ_SAMPLES - 7); + isPktUseful = processT1_7Resp(hss, pkt, testno - NUM_SEQ_SAMPLES - 7); if (isPktUseful) { probeI = hss->getActiveProbe(OFP_T1_7, testno - NUM_SEQ_SAMPLES - 7); @@ -1959,42 +1968,45 @@ bool HostOsScan::processResp(HostOsScanStats *hss, const struct ip *ip, unsigned /* Closed-port TCP IP ID sequence numbers (SEQ.CI). Uses T5, T6, and T7. T5 starts at NUM_SEQ_SAMPLES + 11. */ if (testno >= NUM_SEQ_SAMPLES + 11) - hss->ipid.tcp_closed_ipids[testno - (NUM_SEQ_SAMPLES + 11)] = ntohs(ip->ip_id); + hss->ipid.tcp_closed_ipids[testno - (NUM_SEQ_SAMPLES + 11)] = ntohs(ip.ip_id); } } } - else if (ip->ip_p == IPPROTO_ICMP) { + else if (ip.ip_p == IPPROTO_ICMP) { if (len < 8) return false; - icmp = ((struct icmp *)(((char *) ip) + 4 * ip->ip_hl)); + struct icmp icmp; + const u8 *icmppkt = pkt + 4 * ip.ip_hl; + memcpy(&icmp, icmppkt, sizeof(icmp)); /* Is it an icmp echo reply? */ - if (icmp->icmp_type == ICMP_ECHOREPLY) { - testno = ntohs(icmp->icmp_id) - icmpEchoId; + if (icmp.icmp_type == ICMP_ECHOREPLY) { + testno = ntohs(icmp.icmp_id) - icmpEchoId; if (testno == 0 || testno == 1) { - isPktUseful = processTIcmpResp(hss, ip, testno); + isPktUseful = processTIcmpResp(hss, pkt, testno); if (isPktUseful) { probeI = hss->getActiveProbe(OFP_TICMP, testno); } if (isPktUseful && probeI != hss->probesActive.end() && !(*probeI)->retransmitted) { /* Retransmitted ipid is useless. */ - hss->ipid.icmp_ipids[testno] = ntohs(ip->ip_id); - /* printf("icmp ipid = %d\n", ntohs(ip->ip_id)); */ + hss->ipid.icmp_ipids[testno] = ntohs(ip.ip_id); + /* printf("icmp ipid = %d\n", ntohs(ip.ip_id)); */ } } } /* Is it a destination port unreachable? */ - if (icmp->icmp_type == 3 && icmp->icmp_code == 3) { + if (icmp.icmp_type == 3 && icmp.icmp_code == 3) { len -= 8; /* icmp destination unreachable header len. */ if (len < 28) return false; /* must larger than an ip and an udp header length */ - ip2 = (struct ip*)((char *)icmp + 8); - len -= 4 * ip2->ip_hl; + struct ip ip2; + memcpy(&ip2, icmppkt + 8, sizeof(ip2)); + len -= 4 * ip2.ip_hl; if (len < 8) return false; - isPktUseful = processTUdpResp(hss, ip); + isPktUseful = processTUdpResp(hss, pkt); if (isPktUseful) { probeI = hss->getActiveProbe(OFP_TUDP, 0); } @@ -2605,22 +2617,25 @@ void HostOsScan::makeTWinFP(HostOsScanStats *hss) { } -bool HostOsScan::processTSeqResp(HostOsScanStats *hss, const struct ip *ip, int replyNo) { +bool HostOsScan::processTSeqResp(HostOsScanStats *hss, const u8 *pkt, int replyNo) { assert(replyNo >= 0 && replyNo < NUM_SEQ_SAMPLES); + struct ip ip; + memcpy(&ip, pkt, sizeof(ip)); - const struct tcp_hdr *tcp; int seq_response_num; /* response # for sequencing */ u32 timestamp = 0; /* TCP timestamp we receive back */ - if (hss->lastipid != 0 && ip->ip_id == hss->lastipid) { + if (hss->lastipid != 0 && ip.ip_id == hss->lastipid) { /* Probably a duplicate -- this happens sometimes when scanning localhost */ return false; } - hss->lastipid = ip->ip_id; + hss->lastipid = ip.ip_id; - tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl)); + struct tcp_hdr tcp; + const u8 *tcppkt = pkt + 4 * ip.ip_hl; + memcpy(&tcp, tcppkt, sizeof(tcp)); - if ((tcp->th_flags & TH_RST)) { + if ((tcp.th_flags & TH_RST)) { if (hss->si.responses == 0) { error("WARNING: RST from %s port %d -- is this port really open?", hss->target->targetipstr(), hss->openTCPPort); @@ -2628,11 +2643,11 @@ bool HostOsScan::processTSeqResp(HostOsScanStats *hss, const struct ip *ip, int return false; } - if ((tcp->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { - /* error("DEBUG: response is SYN|ACK to port %hu\n", ntohs(tcp->th_dport)); */ - /*readtcppacket((char *)ip, ntohs(ip->ip_len));*/ + if ((tcp.th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { + /* error("DEBUG: response is SYN|ACK to port %hu\n", ntohs(tcp.th_dport)); */ + /*readtcppacket((char *)ip, ntohs(ip.ip_len));*/ /* We use the ACK value to match up our sent with rcv'd packets */ - seq_response_num = ntohl(tcp->th_ack) - tcpSeqBase - 1; + seq_response_num = ntohl(tcp.th_ack) - tcpSeqBase - 1; /* printf("seq_response_num = %d\treplyNo = %d\n", seq_response_num, replyNo); */ if (seq_response_num != replyNo) { @@ -2641,9 +2656,9 @@ bool HostOsScan::processTSeqResp(HostOsScanStats *hss, const struct ip *ip, int error("Unable to associate os scan response with sent packet for %s.", hss->target->targetipstr()); error("Received ack: %lX; sequence sent: %lX. Packet:", - (unsigned long) ntohl(tcp->th_ack), + (unsigned long) ntohl(tcp.th_ack), (unsigned long) tcpSeqBase); - readtcppacket((unsigned char *)ip, ntohs(ip->ip_len)); + readtcppacket(pkt, ntohs(ip.ip_len)); } seq_response_num = replyNo; } @@ -2651,10 +2666,10 @@ bool HostOsScan::processTSeqResp(HostOsScanStats *hss, const struct ip *ip, int if (hss->si.seqs[seq_response_num] == 0) { /* New response found! */ hss->si.responses++; - hss->si.seqs[seq_response_num] = ntohl(tcp->th_seq); /* TCP ISN */ - hss->si.ipids[seq_response_num] = ntohs(ip->ip_id); + hss->si.seqs[seq_response_num] = ntohl(tcp.th_seq); /* TCP ISN */ + hss->si.ipids[seq_response_num] = ntohs(ip.ip_id); - if ((gettcpopt_ts(tcp, ×tamp, NULL) == 0)) + if ((gettcpopt_ts(tcppkt, ×tamp, NULL) == 0)) hss->si.ts_seqclass = TS_SEQ_UNSUPPORTED; else { if (timestamp == 0) { @@ -2662,7 +2677,7 @@ bool HostOsScan::processTSeqResp(HostOsScanStats *hss, const struct ip *ip, int } } hss->si.timestamps[seq_response_num] = timestamp; - /* printf("Response #%d -- ipid=%hu ts=%i\n", seq_response_num, ntohs(ip->ip_id), timestamp); */ + /* printf("Response #%d -- ipid=%hu ts=%i\n", seq_response_num, ntohs(ip.ip_id), timestamp); */ return true; } @@ -2672,7 +2687,7 @@ bool HostOsScan::processTSeqResp(HostOsScanStats *hss, const struct ip *ip, int } -bool HostOsScan::processTOpsResp(HostOsScanStats *hss, const struct tcp_hdr *tcp, int replyNo) { +bool HostOsScan::processTOpsResp(HostOsScanStats *hss, const u8 *tcp, int replyNo) { assert(replyNo >= 0 && replyNo < 6); char ops_buf[256]; @@ -2708,15 +2723,20 @@ bool HostOsScan::processTWinResp(HostOsScanStats *hss, const struct tcp_hdr *tcp } -bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) { +bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const u8 *pkt) { char ops_buf[256]; char quirks_buf[10]; char *p; - const struct tcp_hdr *tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl)); if (hss->FP_TEcn) return false; + struct ip ip; + memcpy(&ip, pkt, sizeof(ip)); + const u8 *tcppkt = pkt + 4 * ip.ip_hl; + struct tcp_hdr tcp; + memcpy(&tcp, tcppkt, sizeof(tcp)); + /* Create the Avals */ hss->FP_TEcn = new FingerTest(FingerPrintDef::ECN, *o.reference_FPs->MatchPoints); FingerTest &test = *hss->FP_TEcn; @@ -2724,19 +2744,19 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) { test.setAVal("R", "Y"); /* don't frag flag */ - if (ntohs(ip->ip_off) & IP_DF) + if (ntohs(ip.ip_off) & IP_DF) test.setAVal("DF", "Y"); else test.setAVal("DF", "N"); /* TTL */ - test.setAVal("T", hss->target->FPR->cp_hex(ip->ip_ttl)); + test.setAVal("T", hss->target->FPR->cp_hex(ip.ip_ttl)); /* TCP Window size */ - test.setAVal("W", hss->target->FPR->cp_hex(ntohs(tcp->th_win))); + test.setAVal("W", hss->target->FPR->cp_hex(ntohs(tcp.th_win))); /* Now for the TCP options ... */ - int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf)); + int opsParseResult = get_tcpopt_string(tcppkt, this->tcpMss, ops_buf, sizeof(ops_buf)); if (opsParseResult <= 0) { if (opsParseResult < 0 && o.debugging) @@ -2748,13 +2768,13 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) { } /* Explicit Congestion Notification support test */ - if ((tcp->th_flags & TH_ECE) && (tcp->th_flags & TH_CWR)) + if ((tcp.th_flags & TH_ECE) && (tcp.th_flags & TH_CWR)) /* echo back */ test.setAVal("CC", "S"); - else if (tcp->th_flags & TH_ECE) + else if (tcp.th_flags & TH_ECE) /* support */ test.setAVal("CC", "Y"); - else if (!(tcp->th_flags & TH_CWR)) + else if (!(tcp.th_flags & TH_CWR)) /* not support */ test.setAVal("CC", "N"); else @@ -2762,12 +2782,12 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) { /* TCP miscellaneous quirks test */ p = quirks_buf; - if (tcp->th_x2) { + if (tcp.th_x2) { /* Reserved field of TCP is not zero */ assert(p + 1 < quirks_buf + sizeof(quirks_buf)); *p++ = 'R'; } - if (!(tcp->th_flags & TH_URG) && tcp->th_urp) { + if (!(tcp.th_flags & TH_URG) && tcp.th_urp) { /* URG pointer value when urg flag not set */ assert(p + 1 < quirks_buf + sizeof(quirks_buf)); *p++ = 'U'; @@ -2779,11 +2799,9 @@ bool HostOsScan::processTEcnResp(HostOsScanStats *hss, const struct ip *ip) { } -bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int replyNo) { +bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const u8 *pkt, int replyNo) { assert(replyNo >= 0 && replyNo < 7); - const struct tcp_hdr *tcp = ((struct tcp_hdr *) (((char *) ip) + 4 * ip->ip_hl)); - int i; int length; char flags_buf[10]; @@ -2794,6 +2812,12 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int if (hss->FPtests[FP_T1_7_OFF + replyNo]) return false; + struct ip ip; + memcpy(&ip, pkt, sizeof(ip)); + const u8 *tcppkt = pkt + 4 * ip.ip_hl; + struct tcp_hdr tcp; + memcpy(&tcp, tcppkt, sizeof(tcp)); + hss->FPtests[FP_T1_7_OFF + replyNo] = new FingerTest(testid, *o.reference_FPs->MatchPoints); FingerTest &test = *hss->FPtests[FP_T1_7_OFF + replyNo]; @@ -2802,17 +2826,17 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int test.setAVal("R", "Y"); /* Next we check whether the Don't Fragment bit is set */ - if (ntohs(ip->ip_off) & IP_DF) + if (ntohs(ip.ip_off) & IP_DF) test.setAVal("DF", "Y"); else test.setAVal("DF", "N"); /* TTL */ - test.setAVal("T", hss->target->FPR->cp_hex(ip->ip_ttl)); + test.setAVal("T", hss->target->FPR->cp_hex(ip.ip_ttl)); if (replyNo != 0) { /* Now we do the TCP Window size */ - test.setAVal("W", hss->target->FPR->cp_hex(ntohs(tcp->th_win))); + test.setAVal("W", hss->target->FPR->cp_hex(ntohs(tcp.th_win))); } /* Seq test values: @@ -2821,11 +2845,11 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int A+ = ack + 1 O = other */ - if (ntohl(tcp->th_seq) == 0) + if (ntohl(tcp.th_seq) == 0) test.setAVal("S", "Z"); - else if (ntohl(tcp->th_seq) == tcpAck) + else if (ntohl(tcp.th_seq) == tcpAck) test.setAVal("S", "A"); - else if (ntohl(tcp->th_seq) == tcpAck + 1) + else if (ntohl(tcp.th_seq) == tcpAck + 1) test.setAVal("S", "A+"); else test.setAVal("S", "O"); @@ -2836,11 +2860,11 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int S+ = syn + 1 O = other */ - if (ntohl(tcp->th_ack) == 0) + if (ntohl(tcp.th_ack) == 0) test.setAVal("A", "Z"); - else if (ntohl(tcp->th_ack) == tcpSeqBase) + else if (ntohl(tcp.th_ack) == tcpSeqBase) test.setAVal("A", "S"); - else if (ntohl(tcp->th_ack) == tcpSeqBase + 1) + else if (ntohl(tcp.th_ack) == tcpSeqBase + 1) test.setAVal("A", "S+"); else test.setAVal("A", "O"); @@ -2869,7 +2893,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int assert(sizeof(flag_defs) / sizeof(flag_defs[0]) < sizeof(flags_buf)); p = flags_buf; for (i = 0; i < (int) (sizeof(flag_defs) / sizeof(flag_defs[0])); i++) { - if (tcp->th_flags & flag_defs[i].flag) + if (tcp.th_flags & flag_defs[i].flag) *p++ = flag_defs[i].c; } *p = '\0'; @@ -2879,7 +2903,7 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int char ops_buf[256]; /* Now for the TCP options ... */ - int opsParseResult = get_tcpopt_string(tcp, this->tcpMss, ops_buf, sizeof(ops_buf)); + int opsParseResult = get_tcpopt_string(tcppkt, this->tcpMss, ops_buf, sizeof(ops_buf)); if (opsParseResult <= 0) { if (opsParseResult < 0 && o.debugging) error("Option parse error for T%d response from %s.", replyNo, hss->target->targetipstr()); @@ -2891,21 +2915,21 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int } /* Rst Data CRC32 */ - length = (int) ntohs(ip->ip_len) - 4 * ip->ip_hl -4 * tcp->th_off; - if ((tcp->th_flags & TH_RST) && length>0) { - test.setAVal("RD", hss->target->FPR->cp_hex(nbase_crc32(((u8 *)tcp) + 4 * tcp->th_off, length))); + length = (int) ntohs(ip.ip_len) - 4 * ip.ip_hl -4 * tcp.th_off; + if ((tcp.th_flags & TH_RST) && length>0) { + test.setAVal("RD", hss->target->FPR->cp_hex(nbase_crc32(tcppkt + 4 * tcp.th_off, length))); } else { test.setAVal("RD", "0"); } /* TCP miscellaneous quirks test */ p = quirks_buf; - if (tcp->th_x2) { + if (tcp.th_x2) { /* Reserved field of TCP is not zero */ assert(p + 1 < quirks_buf + sizeof(quirks_buf)); *p++ = 'R'; } - if (!(tcp->th_flags & TH_URG) && tcp->th_urp) { + if (!(tcp.th_flags & TH_URG) && tcp.th_urp) { /* URG pointer value when urg flag not set */ assert(p + 1 < quirks_buf + sizeof(quirks_buf)); *p++ = 'U'; @@ -2917,31 +2941,32 @@ bool HostOsScan::processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int } -bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) { +bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const u8 *pkt) { assert(hss); - assert(ip); - - const struct icmp *icmp; - const struct ip *ip2; - unsigned short checksum; - unsigned short *checksumptr; - const struct udp_hdr *udp; - const unsigned char *datastart, *dataend; + assert(pkt); if (hss->FP_TUdp) return false; - icmp = ((struct icmp *)(((char *) ip) + 4 * ip->ip_hl)); + struct ip ip; + memcpy(&ip, pkt, sizeof(ip)); + const u8 *icmppkt = pkt + 4 * ip.ip_hl; + struct icmp icmp; + memcpy(&icmp, icmppkt, sizeof(icmp)); /* Make sure this is icmp port unreachable. */ - assert(icmp->icmp_type == 3 && icmp->icmp_code == 3); + assert(icmp.icmp_type == 3 && icmp.icmp_code == 3); - ip2 = (struct ip*)((char *)icmp + 8); - udp = (struct udp_hdr *)((char *)ip2 + 4 * ip2->ip_hl); + struct ip ip2; + const u8 *ip2pkt = icmppkt + 8; + memcpy(&ip2, ip2pkt, sizeof(ip2)); + struct udp_hdr udp; + const u8 *udppkt = ip2pkt + 4 * ip2.ip_hl; + memcpy(&udp, udppkt, sizeof(udp)); /* The ports should match. */ - if (ntohs(udp->uh_sport) != hss->upi.sport || ntohs(udp->uh_dport) != hss->upi.dport) { + if (ntohs(udp.uh_sport) != hss->upi.sport || ntohs(udp.uh_dport) != hss->upi.dport) { return false; } @@ -2956,37 +2981,37 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) { hss->target->FPR->osscan_closedudpport = hss->upi.dport; /* Now let us do an easy one, Don't fragment */ - if (ntohs(ip->ip_off) & IP_DF) + if (ntohs(ip.ip_off) & IP_DF) test.setAVal("DF", "Y"); else test.setAVal("DF", "N"); /* TTL */ - test.setAVal("T", hss->target->FPR->cp_hex(ip->ip_ttl)); + test.setAVal("T", hss->target->FPR->cp_hex(ip.ip_ttl)); /* Now we look at the IP datagram length that was returned, some machines send more of the original packet back than others */ - test.setAVal("IPL", hss->target->FPR->cp_hex(ntohs(ip->ip_len))); + test.setAVal("IPL", hss->target->FPR->cp_hex(ntohs(ip.ip_len))); /* unused filed not zero in Destination Unreachable Message */ - test.setAVal("UN", hss->target->FPR->cp_hex(ntohl(icmp->icmp_void))); + test.setAVal("UN", hss->target->FPR->cp_hex(ntohl(icmp.icmp_void))); /* OK, lets check the returned IP length, some systems @$@ this up */ - if (ntohs(ip2->ip_len) == 328) + if (ntohs(ip2.ip_len) == 328) test.setAVal("RIPL", "G"); else - test.setAVal("RIPL", hss->target->FPR->cp_hex(ntohs(ip2->ip_len))); + test.setAVal("RIPL", hss->target->FPR->cp_hex(ntohs(ip2.ip_len))); /* This next test doesn't work on Solaris because the lamers overwrite our ip_id */ #if !defined(SOLARIS) && !defined(SUNOS) && !defined(IRIX) && !defined(HPUX) /* Now lets see how they treated the ID we sent ... */ - if (ntohs(ip2->ip_id) == hss->upi.ipid) + if (ntohs(ip2.ip_id) == hss->upi.ipid) test.setAVal("RID", "G"); /* The good "expected" value */ else - test.setAVal("RID", hss->target->FPR->cp_hex(ntohs(ip2->ip_id))); + test.setAVal("RID", hss->target->FPR->cp_hex(ntohs(ip2.ip_id))); #endif @@ -2994,14 +3019,14 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) { /* Thanks to some machines not having struct ip member ip_sum we have to go with this BS */ - checksumptr = (unsigned short *) ((char *) ip2 + 10); - checksum = *checksumptr; + u16 *checksumptr = (u16 *) (ip2pkt + 10); + u16 checksum = *checksumptr; if (checksum == 0) { test.setAVal("RIPCK", "Z"); } else { *checksumptr = 0; - if (in_cksum((unsigned short *)ip2, 20) == checksum) { + if (in_cksum((const u16 *)ip2pkt, 20) == checksum) { test.setAVal("RIPCK", "G"); /* The "expected" good value */ } else { test.setAVal("RIPCK", "I"); /* They modified it */ @@ -3010,14 +3035,14 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) { } /* UDP checksum */ - if (udp->uh_sum == hss->upi.udpck) + if (udp.uh_sum == hss->upi.udpck) test.setAVal("RUCK", "G"); /* The "expected" good value */ else - test.setAVal("RUCK", hss->target->FPR->cp_hex(ntohs(udp->uh_sum))); + test.setAVal("RUCK", hss->target->FPR->cp_hex(ntohs(udp.uh_sum))); /* Finally we ensure the data is OK */ - datastart = ((unsigned char *)udp) + 8; - dataend = (unsigned char *) ip + ntohs(ip->ip_len); + const u8 *datastart = udppkt + 8; + const u8 *dataend = pkt + ntohs(ip.ip_len); while (datastart < dataend) { if (*datastart != hss->upi.patternbyte) @@ -3031,27 +3056,28 @@ bool HostOsScan::processTUdpResp(HostOsScanStats *hss, const struct ip *ip) { /* Count hop count */ if (hss->distance == -1) { - hss->distance = this->udpttl - ip2->ip_ttl + 1; + hss->distance = this->udpttl - ip2.ip_ttl + 1; } return true; } -bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int replyNo) { +bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const u8 *pkt, int replyNo) { assert(replyNo == 0 || replyNo == 1); - const struct ip *ip1, *ip2; - const struct icmp *icmp1, *icmp2; unsigned short value1, value2; if (hss->FP_TIcmp) return false; + struct ip ip; + memcpy(&ip, pkt, sizeof(ip)); + if (hss->icmpEchoReply == NULL) { /* This is the first icmp reply we get, store it and return. */ - hss->icmpEchoReply = (struct ip *) safe_malloc(ntohs(ip->ip_len)); - memcpy(hss->icmpEchoReply, ip, ntohs(ip->ip_len)); + hss->icmpEchoReply = (u8 *) safe_malloc(ntohs(ip.ip_len)); + memcpy(hss->icmpEchoReply, pkt, ntohs(ip.ip_len)); hss->storedIcmpReply = replyNo; return true; } else if (hss->storedIcmpReply == replyNo) { @@ -3059,19 +3085,31 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int return false; } + const struct ip *ip1, *ip2; + const u8 *ip1pkt, *ip2pkt; + struct ip tmp; /* Ok, now we get another reply. */ if (hss->storedIcmpReply == 0) { - ip1 = hss->icmpEchoReply; - ip2 = ip; + ip1pkt = hss->icmpEchoReply; + memcpy(&tmp, ip1pkt, sizeof(tmp)); + ip1 = &tmp; + + ip2pkt = pkt; + ip2 = &ip; } else { - ip1 = ip; - ip2 = hss->icmpEchoReply; + ip2pkt = hss->icmpEchoReply; + memcpy(&tmp, ip2pkt, sizeof(tmp)); + ip2 = &tmp; + + ip1pkt = pkt; + ip1 = &ip; } - icmp1 = ((struct icmp *)(((char *) ip1) + 4 * ip1->ip_hl)); - icmp2 = ((struct icmp *)(((char *) ip2) + 4 * ip2->ip_hl)); + struct icmp icmp1, icmp2; + memcpy(&icmp1, ip1pkt + 4 * ip1->ip_hl, sizeof(icmp1)); + memcpy(&icmp2, ip2pkt + 4 * ip2->ip_hl, sizeof(icmp2)); - assert(icmp1->icmp_type == 0 && icmp2->icmp_type == 0); + assert(icmp1.icmp_type == 0 && icmp2.icmp_type == 0); hss->FP_TIcmp= new FingerTest(FingerPrintDef::IE, *o.reference_FPs->MatchPoints); FingerTest &test = *hss->FP_TIcmp; @@ -3107,8 +3145,8 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int * S. Both use the Code that the sender uses; * O. Other. */ - value1 = icmp1->icmp_code; - value2 = icmp2->icmp_code; + value1 = icmp1.icmp_code; + value2 = icmp2.icmp_code; if (value1 == value2) { if (value1 == 0) test.setAVal("CD", "Z"); @@ -3125,17 +3163,19 @@ bool HostOsScan::processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int } -int HostOsScan::get_tcpopt_string(const struct tcp_hdr *tcp, int mss, char *result, int maxlen) const { +int HostOsScan::get_tcpopt_string(const u8 *tcp, int mss, char *result, int maxlen) const { char *p; - const char *q; + const u8 *q; u16 tmpshort; u32 tmpword; int length; int opcode; p = result; - length = (tcp->th_off * 4) - sizeof(struct tcp_hdr); - q = ((char *)tcp) + sizeof(struct tcp_hdr); + struct tcp_hdr hdr; + memcpy(&hdr, tcp, sizeof(hdr)); + length = (hdr.th_off * 4) - sizeof(struct tcp_hdr); + q = tcp + sizeof(struct tcp_hdr); /* * Example parsed result: M5B4ST11NW2 diff --git a/osscan2.h b/osscan2.h index 04731e260..4bb87ea7d 100644 --- a/osscan2.h +++ b/osscan2.h @@ -319,7 +319,7 @@ class HostOsScanStats { int TWinReplyNum; /* how many TWin replies are received. */ int TOpsReplyNum; /* how many TOps replies are received. Actually it is the same with TOpsReplyNum. */ - struct ip *icmpEchoReply; /* To store one of the two icmp replies */ + u8 *icmpEchoReply; /* To store one of the two icmp replies */ int storedIcmpReply; /* Which one of the two icmp replies is stored? */ struct udpprobeinfo upi; /* info of the udp probe we sent */ @@ -364,7 +364,7 @@ class HostOsScan { void sendNextProbe(HostOsScanStats *hss); /* Process one response. If the response is useful, return true. */ - bool processResp(HostOsScanStats *hss, const struct ip *ip, unsigned int len, struct timeval *rcvdtime); + bool processResp(HostOsScanStats *hss, const u8 *ip, unsigned int len, struct timeval *rcvdtime); /* Make up the fingerprint. */ void makeFP(HostOsScanStats *hss); @@ -403,13 +403,13 @@ private: void sendTUdpProbe(HostOsScanStats *hss, int probeNo); void sendTIcmpProbe(HostOsScanStats *hss, int probeNo); /* Response process functions. */ - bool processTSeqResp(HostOsScanStats *hss, const struct ip *ip, int replyNo); - bool processTOpsResp(HostOsScanStats *hss, const struct tcp_hdr *tcp, int replyNo); + bool processTSeqResp(HostOsScanStats *hss, const u8 *ip, int replyNo); + bool processTOpsResp(HostOsScanStats *hss, const u8 *tcp, int replyNo); bool processTWinResp(HostOsScanStats *hss, const struct tcp_hdr *tcp, int replyNo); - bool processTEcnResp(HostOsScanStats *hss, const struct ip *ip); - bool processT1_7Resp(HostOsScanStats *hss, const struct ip *ip, int replyNo); - bool processTUdpResp(HostOsScanStats *hss, const struct ip *ip); - bool processTIcmpResp(HostOsScanStats *hss, const struct ip *ip, int replyNo); + bool processTEcnResp(HostOsScanStats *hss, const u8 *ip); + bool processT1_7Resp(HostOsScanStats *hss, const u8 *ip, int replyNo); + bool processTUdpResp(HostOsScanStats *hss, const u8 *ip); + bool processTIcmpResp(HostOsScanStats *hss, const u8 *ip, int replyNo); /* Generic sending functions used by the above probe functions. */ int send_tcp_probe(HostOsScanStats *hss, @@ -428,7 +428,7 @@ private: void makeTOpsFP(HostOsScanStats *hss); void makeTWinFP(HostOsScanStats *hss); - int get_tcpopt_string(const struct tcp_hdr *tcp, int mss, char *result, int maxlen) const; + int get_tcpopt_string(const u8 *tcp, int mss, char *result, int maxlen) const; int rawsd; /* Raw socket descriptor */ netutil_eth_t *ethsd; /* Ethernet handle */ diff --git a/scan_engine_raw.cc b/scan_engine_raw.cc index a8410764d..83aa008d3 100644 --- a/scan_engine_raw.cc +++ b/scan_engine_raw.cc @@ -392,9 +392,7 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { bool adjust_timing = true; struct timeval rcvdtime; struct link_header linkhdr; - const struct ip *ip_tmp; unsigned int bytes; - const struct ppkt *ping; long to_usec; HostScanStats *hss = NULL; std::list::iterator probeI; @@ -412,10 +410,11 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { to_usec = TIMEVAL_SUBTRACT(*stime, USI->now); if (to_usec < 2000) to_usec = 2000; - ip_tmp = (struct ip *) readip_pcap(USI->pd, &bytes, to_usec, &rcvdtime, + const u8 *pkt = readip_pcap(USI->pd, &bytes, to_usec, &rcvdtime, &linkhdr, true); + gettimeofday(&USI->now, NULL); - if (!ip_tmp) { + if (!pkt) { if (TIMEVAL_BEFORE(*stime, USI->now)) { timedout = true; break; @@ -435,30 +434,34 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { */ datalen = bytes; - data = ip_get_data(ip_tmp, &datalen, &hdr); + data = ip_get_data(pkt, &datalen, &hdr); if (data == NULL) continue; // If it's not sent to us, we don't care. if (sockaddr_storage_cmp(USI->SourceSockAddr(), &hdr.dst) != 0) continue; + struct ip ip_tmp; + memcpy(&ip_tmp, pkt, sizeof(ip_tmp)); + /* First check if it is ICMP, TCP, or UDP */ if (hdr.proto == IPPROTO_ICMP || hdr.proto == IPPROTO_ICMPV6) { /* if it is our response */ - ping = (struct ppkt *) data; if (bytes < 8U) { - if (!ip_tmp->ip_off) + if (!ip_tmp.ip_off) error("Supposed ping packet is only %d bytes long!", bytes); continue; } - current_reason = icmp_to_reason(hdr.proto, ping->type, ping->code); + struct ppkt ping; + memcpy(&ping, data, sizeof(ping)); + current_reason = icmp_to_reason(hdr.proto, ping.type, ping.code); /* Echo reply, Timestamp reply, or Address Mask Reply. RFCs 792 and 950. */ /* ICMPv6 Echo reply */ if (USI->ptech.rawicmpscan - && ((hdr.proto == IPPROTO_ICMP && (ping->type == 0 || ping->type == 14 || ping->type == 18)) - || (hdr.proto == IPPROTO_ICMPV6 && ping->type == 129))) { + && ((hdr.proto == IPPROTO_ICMP && (ping.type == 0 || ping.type == 14 || ping.type == 18)) + || (hdr.proto == IPPROTO_ICMPV6 && ping.type == 129))) { hss = USI->findHost(&hdr.src); if (!hss) continue; // Not from a host that interests us @@ -485,23 +488,22 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { probeI--; probe = *probeI; - if (!icmp_probe_match(USI, probe, ping, &hdr.src, &hdr.dst, hdr.proto, hdr.ipid)) + if (!icmp_probe_match(USI, probe, &ping, &hdr.src, &hdr.dst, hdr.proto, hdr.ipid)) continue; goodone = true; newstate = HOST_UP; if (o.debugging) - log_write(LOG_STDOUT, "We got a ping packet back from %s: id = %d seq = %d checksum = %d\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), ping->id, ping->seq, ping->checksum); + log_write(LOG_STDOUT, "We got a ping packet back from %s: id = %d seq = %d checksum = %d\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), ping.id, ping.seq, ping.checksum); } } // For ICMP, the reply of TCP/UDP/ICMP packets can be Destination unreachable, source quench, or time exceeded /* For ICMPv6, the reply of TCP/UDP/ICMPV6 packets can be Destination Unreachable, * Packet Too Big, Time Exceeded and Parameter Problem.*/ - else if ((hdr.proto == IPPROTO_ICMP && (ping->type == 3 || ping->type - == 4 || ping->type == 11)) - || (hdr.proto == IPPROTO_ICMPV6 && (ping->type == 1 || ping->type == 2 - || ping->type == 3 || ping->type == 4))) { + else if ((hdr.proto == IPPROTO_ICMP && (ping.type == 3 || ping.type == 4 || ping.type == 11)) + || (hdr.proto == IPPROTO_ICMPV6 && (ping.type == 1 || ping.type == 2 + || ping.type == 3 || ping.type == 4))) { const void *encaps_data; unsigned int encaps_len; struct abstract_ip_hdr encaps_hdr; @@ -557,24 +559,29 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if ((encaps_hdr.proto == IPPROTO_ICMP || encaps_hdr.proto == IPPROTO_ICMPV6) && USI->ptech.rawicmpscan) { /* The response was based on a ping packet we sent */ - if (probe->icmpid() != ntohs(((struct icmp *) encaps_data)->icmp_id)) + struct icmp icmp; + memcpy(&icmp, encaps_data, sizeof(icmp)); + if (probe->icmpid() != ntohs(icmp.icmp_id)) continue; } else if (encaps_hdr.proto == IPPROTO_TCP && USI->ptech.rawtcpscan) { - const struct tcp_hdr *tcp = (struct tcp_hdr *) encaps_data; - if (probe->dport() != ntohs(tcp->th_dport) || - probe->sport() != ntohs(tcp->th_sport) || - probe->tcpseq() != ntohl(tcp->th_seq)) + struct tcp_hdr tcp; + memcpy(&tcp, encaps_data, sizeof(tcp)); + if (probe->dport() != ntohs(tcp.th_dport) || + probe->sport() != ntohs(tcp.th_sport) || + probe->tcpseq() != ntohl(tcp.th_seq)) continue; } else if (encaps_hdr.proto == IPPROTO_UDP && USI->ptech.rawudpscan) { - const struct udp_hdr *udp = (struct udp_hdr *) encaps_data; - if (probe->dport() != ntohs(udp->uh_dport) || - probe->sport() != ntohs(udp->uh_sport)) + struct udp_hdr udp; + memcpy(&udp, encaps_data, sizeof(udp)); + if (probe->dport() != ntohs(udp.uh_dport) || + probe->sport() != ntohs(udp.uh_sport)) continue; } else if (encaps_hdr.proto == IPPROTO_SCTP && USI->ptech.rawsctpscan) { - const struct sctp_hdr *sctp = (struct sctp_hdr *) encaps_data; - if (probe->dport() != ntohs(sctp->sh_dport) || - probe->sport() != ntohs(sctp->sh_sport) || - probe->sctpvtag() != ntohl(sctp->sh_vtag)) + struct sctp_hdr sctp; + memcpy(&sctp, encaps_data, sizeof(sctp)); + if (probe->dport() != ntohs(sctp.sh_dport) || + probe->sport() != ntohs(sctp.sh_sport) || + probe->sctpvtag() != ntohl(sctp.sh_vtag)) continue; } else if (USI->ptech.rawprotoscan) { /* Success; we already know that the address and protocol match. */ @@ -591,11 +598,11 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { continue; /* Destination unreachable. */ - if ((hdr.proto == IPPROTO_ICMP && ping->type == 3) - || (hdr.proto == IPPROTO_ICMPV6 && ping->type == 1)) { + if ((hdr.proto == IPPROTO_ICMP && ping.type == 3) + || (hdr.proto == IPPROTO_ICMPV6 && ping.type == 1)) { // If it's Port or Proto unreachable and the address matches, it's up. - if (((hdr.proto == IPPROTO_ICMP && (ping->code == 2 || ping->code == 3)) - || (hdr.proto == IPPROTO_ICMPV6 && ping->code == 4)) + if (((hdr.proto == IPPROTO_ICMP && (ping.code == 2 || ping.code == 3)) + || (hdr.proto == IPPROTO_ICMPV6 && ping.code == 4)) && sockaddr_storage_cmp(hss->target->TargetSockAddr(), &hdr.src) == 0) { /* The ICMP or ICMPv6 error came directly from the target, so it's up. */ goodone = true; @@ -619,8 +626,8 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { log_write(LOG_STDOUT, "Got destination unreachable for %s\n", hss->target->targetipstr()); } } - } else if ((hdr.proto == IPPROTO_ICMP && ping->type == 11) - || (hdr.proto == IPPROTO_ICMPV6 && ping->type == 3)) { + } else if ((hdr.proto == IPPROTO_ICMP && ping.type == 11) + || (hdr.proto == IPPROTO_ICMPV6 && ping.type == 3)) { if (o.debugging) log_write(LOG_STDOUT, "Got Time Exceeded for %s\n", hss->target->targetipstr()); goodone = 1; @@ -628,35 +635,36 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { /* I don't want anything to do with timing this. */ adjust_timing = false; } else if (hdr.proto == IPPROTO_ICMP) { - if (ping->type == 4) { + if (ping.type == 4) { if (o.debugging) log_write(LOG_STDOUT, "Got ICMP source quench\n"); usleep(50000); } else { if (o.debugging) { log_write(LOG_STDOUT, "Got ICMP message type %d code %d\n", - ping->type, ping->code); + ping.type, ping.code); } } } else if (hdr.proto == IPPROTO_ICMPV6) { - if (ping->type == 4) { + if (ping.type == 4) { if (o.debugging) log_write(LOG_STDOUT, "Got ICMPv6 Parameter Problem\n"); } else { if (o.debugging) log_write(LOG_STDOUT, "Got ICMPv6 message type %d code %d\n", - ping->type, ping->code); + ping.type, ping.code); } } } } else if (hdr.proto == IPPROTO_TCP && USI->ptech.rawtcpscan) { - const struct tcp_hdr *tcp = (struct tcp_hdr *) data; + struct tcp_hdr tcp; + memcpy(&tcp, data, sizeof(tcp)); /* Check that the packet has useful flags. */ if (o.discovery_ignore_rst - && (tcp->th_flags & TH_RST)) + && (tcp.th_flags & TH_RST)) continue; - else if (!(tcp->th_flags & TH_RST) - && ((tcp->th_flags & (TH_SYN | TH_ACK)) != (TH_SYN | TH_ACK))) + else if (!(tcp.th_flags & TH_RST) + && ((tcp.th_flags & (TH_SYN | TH_ACK)) != (TH_SYN | TH_ACK))) continue; /* Now ensure this host is even in the incomplete list */ @@ -666,8 +674,8 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { setTargetMACIfAvailable(hss->target, &linkhdr, &hdr.src, 0); probeI = hss->probes_outstanding.end(); listsz = hss->num_probes_outstanding(); - u16 sport = ntohs(tcp->th_sport); - u16 dport = ntohs(tcp->th_dport); + u16 sport = ntohs(tcp.th_sport); + u16 dport = ntohs(tcp.th_dport); goodone = false; @@ -678,7 +686,7 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (!probe->check_proto_port(hdr.proto, dport, sport)) continue; - if (!tcp_probe_match(USI, probe, tcp, &hdr.src, &hdr.dst, hdr.ipid)) + if (!tcp_probe_match(USI, probe, &tcp, &hdr.src, &hdr.dst, hdr.ipid)) continue; goodone = true; @@ -686,13 +694,13 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { /* Fill out the reason. */ if (o.pingtype & PINGTYPE_TCP_USE_SYN) { - if (tcp->th_flags & TH_RST) { + if (tcp.th_flags & TH_RST) { current_reason = ER_RESETPEER; - } else if ((tcp->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { + } else if ((tcp.th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { current_reason = ER_SYNACK; } } else if (o.pingtype & PINGTYPE_TCP_USE_ACK) { - if (tcp->th_flags & TH_RST) + if (tcp.th_flags & TH_RST) current_reason = ER_RESETPEER; } @@ -700,7 +708,8 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { log_write(LOG_STDOUT, "We got a TCP ping packet back from %s port %hu (trynum = %d)\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), sport, probe->get_tryno()); } } else if (hdr.proto == IPPROTO_UDP && USI->ptech.rawudpscan) { - const struct udp_hdr *udp = (struct udp_hdr *) data; + struct udp_hdr udp; + memcpy(&udp, data, sizeof(udp)); /* Search for this host on the incomplete list */ hss = USI->findHost(&hdr.src); if (!hss) @@ -710,8 +719,8 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { listsz = hss->num_probes_outstanding(); goodone = false; - u16 sport = ntohs(udp->uh_sport); - u16 dport = ntohs(udp->uh_dport); + u16 sport = ntohs(udp.uh_sport); + u16 dport = ntohs(udp.uh_dport); for (probenum = 0; probenum < listsz && !goodone; probenum++) { probeI--; @@ -736,9 +745,6 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { log_write(LOG_STDOUT, "In response to UDP-ping, we got UDP packet back from %s port %hu (trynum = %d)\n", inet_ntop_ez(&hdr.src, sizeof(hdr.src)), sport, probe->get_tryno()); } } else if (hdr.proto == IPPROTO_SCTP && USI->ptech.rawsctpscan) { - const struct sctp_hdr *sctp = (struct sctp_hdr *) data; - const struct dnet_sctp_chunkhdr *chunk = - (struct dnet_sctp_chunkhdr *) ((u8 *) sctp + 12); /* Search for this host on the incomplete list */ hss = USI->findHost(&hdr.src); if (!hss) @@ -747,8 +753,13 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { listsz = hss->num_probes_outstanding(); goodone = false; - u16 sport = ntohs(sctp->sh_sport); - u16 dport = ntohs(sctp->sh_dport); + struct sctp_hdr sctp; + memcpy(&sctp, data, sizeof(sctp)); + struct dnet_sctp_chunkhdr chunk; + memcpy(&chunk, (u8 *)data + 12, sizeof(chunk)); + + u16 sport = ntohs(sctp.sh_sport); + u16 dport = ntohs(sctp.sh_dport); for (probenum = 0; probenum < listsz && !goodone; probenum++) { probeI--; @@ -767,9 +778,9 @@ int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) { goodone = true; newstate = HOST_UP; - if (chunk->sch_type == SCTP_INIT_ACK) { + if (chunk.sch_type == SCTP_INIT_ACK) { current_reason = ER_INITACK; - } else if (chunk->sch_type == SCTP_ABORT) { + } else if (chunk.sch_type == SCTP_ABORT) { current_reason = ER_ABORT; } else { current_reason = ER_UNKNOWN; @@ -1670,7 +1681,8 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { } if (hdr.proto == IPPROTO_TCP && !USI->prot_scan) { - const struct tcp_hdr *tcp = (struct tcp_hdr *) data; + struct tcp_hdr tcp; + memcpy(&tcp, data, sizeof(tcp)); /* Now ensure this host is even in the incomplete list */ hss = USI->findHost(&hdr.src); if (!hss) @@ -1678,8 +1690,8 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { setTargetMACIfAvailable(hss->target, &linkhdr, &hdr.src, 0); probeI = hss->probes_outstanding.end(); listsz = hss->num_probes_outstanding(); - u16 sport = ntohs(tcp->th_sport); - u16 dport = ntohs(tcp->th_dport); + u16 sport = ntohs(tcp.th_sport); + u16 dport = ntohs(tcp.th_dport); goodone = false; @@ -1690,29 +1702,29 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (!probe->check_proto_port(hdr.proto, dport, sport)) continue; - if (!tcp_probe_match(USI, probe, tcp, &hdr.src, &hdr.dst, hdr.ipid)) + if (!tcp_probe_match(USI, probe, &tcp, &hdr.src, &hdr.dst, hdr.ipid)) continue; if (!probe->isPing()) { /* Now that response has been matched to a probe, I interpret it */ - if (USI->scantype == SYN_SCAN && (tcp->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { + if (USI->scantype == SYN_SCAN && (tcp.th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) { /* Yeah! An open port */ newstate = PORT_OPEN; current_reason = ER_SYNACK; - } else if (tcp->th_flags & TH_RST) { + } else if (tcp.th_flags & TH_RST) { current_reason = ER_RESETPEER; if (USI->scantype == WINDOW_SCAN ) { - newstate = (tcp->th_win) ? PORT_OPEN : PORT_CLOSED; + newstate = (tcp.th_win) ? PORT_OPEN : PORT_CLOSED; } else if (USI->scantype == ACK_SCAN) { newstate = PORT_UNFILTERED; } else newstate = PORT_CLOSED; - } else if (USI->scantype == SYN_SCAN && (tcp->th_flags & TH_SYN)) { + } else if (USI->scantype == SYN_SCAN && (tcp.th_flags & TH_SYN)) { /* A SYN from a TCP Split Handshake - https://nmap.org/misc/split-handshake.pdf - open port */ newstate = PORT_OPEN; current_reason = ER_SYN; } else { if (o.debugging) - error("Received scan response with unexpected TCP flags: %d", tcp->th_flags); + error("Received scan response with unexpected TCP flags: %d", tcp.th_flags); break; } } @@ -1720,8 +1732,6 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { goodone = true; } } else if (hdr.proto == IPPROTO_SCTP && !USI->prot_scan) { - const struct sctp_hdr *sctp = (struct sctp_hdr *) data; - const struct dnet_sctp_chunkhdr *chunk = (struct dnet_sctp_chunkhdr *) ((u8 *) sctp + 12); /* Now ensure this host is even in the incomplete list */ hss = USI->findHost(&hdr.src); @@ -1733,8 +1743,13 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { goodone = false; - u16 sport = ntohs(sctp->sh_sport); - u16 dport = ntohs(sctp->sh_dport); + struct sctp_hdr sctp; + memcpy(&sctp, data, sizeof(sctp)); + struct dnet_sctp_chunkhdr chunk; + memcpy(&chunk, (u8 *)data + 12, sizeof(chunk)); + + u16 sport = ntohs(sctp.sh_sport); + u16 dport = ntohs(sctp.sh_dport); /* Find the probe that provoked this response. */ for (probenum = 0; probenum < listsz && !goodone; probenum++) { @@ -1755,26 +1770,26 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (!probe->isPing()) { /* Now that response has been matched to a probe, I interpret it */ if (USI->scantype == SCTP_INIT_SCAN) { - if (chunk->sch_type == SCTP_INIT_ACK) { + if (chunk.sch_type == SCTP_INIT_ACK) { newstate = PORT_OPEN; current_reason = ER_INITACK; - } else if (chunk->sch_type == SCTP_ABORT) { + } else if (chunk.sch_type == SCTP_ABORT) { newstate = PORT_CLOSED; current_reason = ER_ABORT; } else { if (o.debugging) error("Received response with unexpected SCTP chunks: %02x", - chunk->sch_type); + chunk.sch_type); break; } } else if (USI->scantype == SCTP_COOKIE_ECHO_SCAN) { - if (chunk->sch_type == SCTP_ABORT) { + if (chunk.sch_type == SCTP_ABORT) { newstate = PORT_CLOSED; current_reason = ER_ABORT; } else { if (o.debugging) error("Received response with unexpected SCTP chunks: %02x", - chunk->sch_type); + chunk.sch_type); break; } } @@ -1786,13 +1801,12 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { const void *encaps_data; unsigned int encaps_len; struct abstract_ip_hdr encaps_hdr; - const struct icmp *icmp = NULL; - - icmp = (struct icmp *) data; + struct icmp icmp; + memcpy(&icmp, data, sizeof(icmp)); if (datalen < 8) continue; - if (icmp->icmp_type != 3 && icmp->icmp_type != 11) + if (icmp.icmp_type != 3 && icmp.icmp_type != 11) continue; encaps_len = datalen - 8; @@ -1840,29 +1854,32 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { continue; if (encaps_hdr.proto == IPPROTO_TCP && !USI->prot_scan) { - const struct tcp_hdr *tcp = (struct tcp_hdr *) encaps_data; - if (ntohs(tcp->th_sport) != probe->sport() || - ntohs(tcp->th_dport) != probe->dport() || - ntohl(tcp->th_seq) != probe->tcpseq()) + struct tcp_hdr tcp; + memcpy(&tcp, encaps_data, sizeof(tcp)); + if (ntohs(tcp.th_sport) != probe->sport() || + ntohs(tcp.th_dport) != probe->dport() || + ntohl(tcp.th_seq) != probe->tcpseq()) continue; } else if (encaps_hdr.proto == IPPROTO_SCTP && !USI->prot_scan) { - const struct sctp_hdr *sctp = (struct sctp_hdr *) encaps_data; - if (ntohs(sctp->sh_sport) != probe->sport() || - ntohs(sctp->sh_dport) != probe->dport() || - ntohl(sctp->sh_vtag) != probe->sctpvtag()) + struct sctp_hdr sctp; + memcpy(&sctp, encaps_data, sizeof(sctp)); + if (ntohs(sctp.sh_sport) != probe->sport() || + ntohs(sctp.sh_dport) != probe->dport() || + ntohl(sctp.sh_vtag) != probe->sctpvtag()) continue; } else if (encaps_hdr.proto == IPPROTO_UDP && !USI->prot_scan) { /* TODO: IPID verification */ - const struct udp_hdr *udp = (struct udp_hdr *) encaps_data; - if (ntohs(udp->uh_sport) != probe->sport() || - ntohs(udp->uh_dport) != probe->dport()) + struct udp_hdr udp; + memcpy(&udp, encaps_data, sizeof(udp)); + if (ntohs(udp.uh_sport) != probe->sport() || + ntohs(udp.uh_dport) != probe->dport()) continue; } else if (!USI->prot_scan) { assert(0); } - if (icmp->icmp_type == 3) { - switch (icmp->icmp_code) { + if (icmp.icmp_type == 3) { + switch (icmp.icmp_code) { case 0: /* Network unreachable */ newstate = PORT_FILTERED; break; @@ -1891,18 +1908,18 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { default: error("Unexpected ICMP type/code 3/%d unreachable packet:\n", - icmp->icmp_code); - nmap_hexdump((unsigned char *)icmp, datalen); + icmp.icmp_code); + nmap_hexdump((const u8*)data, datalen); break; } - current_reason = icmp_to_reason(hdr.proto, icmp->icmp_type, icmp->icmp_code); + current_reason = icmp_to_reason(hdr.proto, icmp.icmp_type, icmp.icmp_code); if (newstate == PORT_UNKNOWN) break; goodone = true; } - else if (icmp->icmp_type == 11) { /* ICMP Time Exceeded */ + else if (icmp.icmp_type == 11) { /* ICMP Time Exceeded */ newstate = PORT_FILTERED; - current_reason = icmp_to_reason(hdr.proto, icmp->icmp_type, icmp->icmp_code); + current_reason = icmp_to_reason(hdr.proto, icmp.icmp_type, icmp.icmp_code); goodone = true; } } @@ -1910,13 +1927,14 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { const void *encaps_data; unsigned int encaps_len; struct abstract_ip_hdr encaps_hdr; - const struct icmpv6_hdr *icmpv6; - - icmpv6 = (struct icmpv6_hdr *) data; if (datalen < 8) continue; - if (!(icmpv6->icmpv6_type == ICMPV6_UNREACH || icmpv6->icmpv6_type == ICMPV6_PARAMPROBLEM)) + + struct icmpv6_hdr icmpv6; + memcpy(&icmpv6, data, sizeof(icmpv6)); + + if (!(icmpv6.icmpv6_type == ICMPV6_UNREACH || icmpv6.icmpv6_type == ICMPV6_PARAMPROBLEM)) continue; encaps_len = datalen - 8; @@ -1964,29 +1982,32 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { continue; if (encaps_hdr.proto == IPPROTO_TCP && !USI->prot_scan) { - const struct tcp_hdr *tcp = (struct tcp_hdr *) encaps_data; - if (ntohs(tcp->th_sport) != probe->sport() || - ntohs(tcp->th_dport) != probe->dport() || - ntohl(tcp->th_seq) != probe->tcpseq()) + struct tcp_hdr tcp; + memcpy(&tcp, encaps_data, sizeof(tcp)); + if (ntohs(tcp.th_sport) != probe->sport() || + ntohs(tcp.th_dport) != probe->dport() || + ntohl(tcp.th_seq) != probe->tcpseq()) continue; } else if (encaps_hdr.proto == IPPROTO_SCTP && !USI->prot_scan) { - const struct sctp_hdr *sctp = (struct sctp_hdr *) encaps_data; - if (ntohs(sctp->sh_sport) != probe->sport() || - ntohs(sctp->sh_dport) != probe->dport() || - ntohl(sctp->sh_vtag) != probe->sctpvtag()) + struct sctp_hdr sctp; + memcpy(&sctp, encaps_data, sizeof(sctp)); + if (ntohs(sctp.sh_sport) != probe->sport() || + ntohs(sctp.sh_dport) != probe->dport() || + ntohl(sctp.sh_vtag) != probe->sctpvtag()) continue; } else if (encaps_hdr.proto == IPPROTO_UDP && !USI->prot_scan) { /* TODO: IPID verification */ - const struct udp_hdr *udp = (struct udp_hdr *) encaps_data; - if (ntohs(udp->uh_sport) != probe->sport() || - ntohs(udp->uh_dport) != probe->dport()) + struct udp_hdr udp; + memcpy(&udp, encaps_data, sizeof(udp)); + if (ntohs(udp.uh_sport) != probe->sport() || + ntohs(udp.uh_dport) != probe->dport()) continue; } else if (!USI->prot_scan) { assert(0); } - if (icmpv6->icmpv6_type == ICMPV6_UNREACH) { - switch (icmpv6->icmpv6_code) { + if (icmpv6.icmpv6_type == ICMPV6_UNREACH) { + switch (icmpv6.icmpv6_code) { case ICMPV6_UNREACH_NOROUTE: current_reason = ER_NOROUTE; newstate = PORT_FILTERED; @@ -2022,12 +2043,12 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { break; default: error("Unexpected ICMPv6 type/code %d/%d unreachable packet:\n", - icmpv6->icmpv6_type, icmpv6->icmpv6_code); - nmap_hexdump((unsigned char *)icmpv6, datalen); + icmpv6.icmpv6_type, icmpv6.icmpv6_code); + nmap_hexdump((unsigned char *)data, datalen); break; } - } else if (icmpv6->icmpv6_type == ICMPV6_PARAMPROBLEM) { - switch (icmpv6->icmpv6_code) { + } else if (icmpv6.icmpv6_type == ICMPV6_PARAMPROBLEM) { + switch (icmpv6.icmpv6_code) { case ICMPV6_PARAMPROBLEM_FIELD: /* "Erroneous header field encountered" means it was understood, just invalid. */ @@ -2041,23 +2062,22 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { break; default: error("Unexpected ICMPv6 type/code %d/%d unreachable packet:\n", - icmpv6->icmpv6_type, icmpv6->icmpv6_code); - nmap_hexdump((unsigned char *)icmpv6, datalen); + icmpv6.icmpv6_type, icmpv6.icmpv6_code); + nmap_hexdump((unsigned char *)data, datalen); break; } } else { error("Unexpected ICMPv6 type/code %d/%d unreachable packet:\n", - icmpv6->icmpv6_type, icmpv6->icmpv6_code); - nmap_hexdump((unsigned char *)icmpv6, datalen); + icmpv6.icmpv6_type, icmpv6.icmpv6_code); + nmap_hexdump((unsigned char *)data, datalen); break; } - current_reason = icmp_to_reason(hdr.proto, icmpv6->icmpv6_type, icmpv6->icmpv6_code); + current_reason = icmp_to_reason(hdr.proto, icmpv6.icmpv6_type, icmpv6.icmpv6_code); if (newstate == PORT_UNKNOWN) break; goodone = true; } } else if (hdr.proto == IPPROTO_UDP && !USI->prot_scan) { - const struct udp_hdr *udp = (struct udp_hdr *) data; /* Search for this host on the incomplete list */ hss = USI->findHost(&hdr.src); @@ -2065,8 +2085,12 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { continue; // Not from a host that interests us probeI = hss->probes_outstanding.end(); listsz = hss->num_probes_outstanding(); - u16 sport = ntohs(udp->uh_sport); - u16 dport = ntohs(udp->uh_dport); + + struct udp_hdr udp; + memcpy(&udp, data, sizeof(udp)); + + u16 sport = ntohs(udp.uh_sport); + u16 dport = ntohs(udp.uh_dport); goodone = false; @@ -2143,17 +2167,18 @@ bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) { if (probe->isPing()) ultrascan_ping_update(USI, hss, probeI, &rcvdtime, adjust_timing); else { - const struct icmp *icmp = (struct icmp *) data; + struct icmp icmp; + memcpy(&icmp, data, sizeof(icmp)); ultrascan_port_probe_update(USI, hss, probeI, PORT_OPEN, &rcvdtime, adjust_timing); if (sockaddr_storage_cmp(&hdr.src, &protoscanicmphackaddy) == 0) reason_sip.ss_family = AF_UNSPEC; else reason_sip = hdr.src; - if (!icmp->icmp_code && !icmp->icmp_type) + if (!icmp.icmp_code && !icmp.icmp_type) hss->target->ports.setStateReason(IPPROTO_ICMP, IPPROTO_IP, ER_ECHOREPLY, hdr.ttl, &reason_sip); else - hss->target->ports.setStateReason(IPPROTO_ICMP, IPPROTO_IP, icmp_to_reason(hdr.proto, icmp->icmp_type, icmp->icmp_code), + hss->target->ports.setStateReason(IPPROTO_ICMP, IPPROTO_IP, icmp_to_reason(hdr.proto, icmp.icmp_type, icmp.icmp_code), hdr.ttl, &reason_sip); } if (!goodone) diff --git a/tcpip.cc b/tcpip.cc index c692e6f06..d602917f3 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -166,7 +166,7 @@ void PacketTrace::traceArp(pdirection pdir, const u8 *frame, u32 len, void PacketTrace::traceND(pdirection pdir, const u8 *frame, u32 len, struct timeval *now) { struct timeval tv; - const struct ip6_hdr *ip6; + struct ip6_hdr ip6; const struct icmpv6_hdr *icmpv6; const union icmpv6_msg *msg; size_t msg_len; @@ -191,15 +191,15 @@ void PacketTrace::traceND(pdirection pdir, const u8 *frame, u32 len, else gettimeofday(&tv, NULL); - if (len < sizeof(*ip6) + sizeof(*icmpv6)) { + if (len < sizeof(ip6) + sizeof(*icmpv6)) { error("Packet tracer: ND packets must be at least %lu bytes long (is %lu).", - (unsigned long) (sizeof(*ip6) + sizeof(*icmpv6)), + (unsigned long) (sizeof(ip6) + sizeof(*icmpv6)), (unsigned long) len); return; } - ip6 = (struct ip6_hdr *) frame; - icmpv6 = (struct icmpv6_hdr *) (frame + sizeof(*ip6)); - msg = (union icmpv6_msg *) (frame + sizeof(*ip6) + sizeof(*icmpv6)); + memcpy(&ip6, frame, sizeof(ip6)); + icmpv6 = (struct icmpv6_hdr *) (frame + sizeof(ip6)); + msg = (union icmpv6_msg *) (frame + sizeof(ip6) + sizeof(*icmpv6)); msg_len = frame + len - (u8 *) msg; if (icmpv6->icmpv6_type == ICMPV6_NEIGHBOR_SOLICITATION) { @@ -227,8 +227,8 @@ void PacketTrace::traceND(pdirection pdir, const u8 *frame, u32 len, return; } - inet_ntop(AF_INET6, (void *)&ip6->ip6_src, src, sizeof(src)); - inet_ntop(AF_INET6, (void *)&ip6->ip6_dst, dst, sizeof(dst)); + inet_ntop(AF_INET6, (void *)&ip6.ip6_src, src, sizeof(src)); + inet_ntop(AF_INET6, (void *)&ip6.ip6_dst, dst, sizeof(dst)); log_write(LOG_STDOUT | LOG_NORMAL, "%s (%.4fs) %s %s > %s %s\n", (pdir == SENT) ? "SENT" : "RCVD", o.TimeSinceStart(&tv), label, src, dst, desc); @@ -1266,10 +1266,13 @@ int readudppacket(const u8 *packet, int readdata) { /* Used by validatepkt() to validate the TCP header (including option lengths). The options checked are MSS, WScale, SackOK, Sack, and Timestamp. */ static bool validateTCPhdr(const u8 *tcpc, unsigned len) { - const struct tcp_hdr *tcp = (struct tcp_hdr *) tcpc; + struct tcp_hdr tcp = {}; + if (len < sizeof(tcp)) + return false; + memcpy(&tcp, tcpc, sizeof(tcp)); unsigned hdrlen, optlen; - hdrlen = tcp->th_off * 4; + hdrlen = tcp.th_off * 4; /* Check header length */ if (hdrlen > len || hdrlen < sizeof(struct tcp_hdr)) @@ -1354,7 +1357,8 @@ static bool validateTCPhdr(const u8 *tcpc, unsigned len) { * data to the caller. */ static bool validatepkt(const u8 *ipc, unsigned *len) { - const struct ip *ip = (struct ip *) ipc; + struct ip ip; + memcpy(&ip, ipc, sizeof(ip)); const void *data; unsigned int datalen, iplen; u8 hdr; @@ -1365,20 +1369,20 @@ static bool validatepkt(const u8 *ipc, unsigned *len) { return false; } - if (ip->ip_v == 4) { + if (ip.ip_v == 4) { unsigned fragoff, iplen; datalen = *len; - data = ipv4_get_data(ip, &datalen); + data = ipv4_get_data(ipc, &datalen); if (data == NULL) { if (o.debugging >= 3) error("Rejecting IP packet because of invalid length"); return false; } - iplen = ntohs(ip->ip_len); + iplen = ntohs(ip.ip_len); - fragoff = 8 * (ntohs(ip->ip_off) & IP_OFFMASK); + fragoff = 8 * (ntohs(ip.ip_off) & IP_OFFMASK); if (fragoff) { if (o.debugging >= 3) error("Rejecting IP fragment (offset %u)", fragoff); @@ -1391,24 +1395,25 @@ static bool validatepkt(const u8 *ipc, unsigned *len) { if (*len > iplen) *len = iplen; - hdr = ip->ip_p; - } else if (ip->ip_v == 6) { - const struct ip6_hdr *ip6 = (struct ip6_hdr *) ipc; + hdr = ip.ip_p; + } else if (ip.ip_v == 6) { + struct ip6_hdr ip6; + memcpy(&ip6, ipc, sizeof(ip6)); datalen = *len; - data = ipv6_get_data(ip6, &datalen, &hdr); + data = ipv6_get_data(ipc, &datalen, &hdr); if (data == NULL) { if (o.debugging >= 3) error("Rejecting IP packet because of invalid length"); return false; } - iplen = ntohs(ip6->ip6_plen); + iplen = ntohs(ip6.ip6_plen); if (datalen > iplen) *len -= datalen - iplen; } else { if (o.debugging >= 3) - error("Rejecting IP packet because of invalid version number %u", ip->ip_v); + error("Rejecting IP packet because of invalid version number %u", ip.ip_v); return false; } @@ -1460,10 +1465,7 @@ const u8 *readipv4_pcap(pcap_t *pd, unsigned int *len, long to_usec, buf = readip_pcap(pd, len, to_usec, rcvdtime, linknfo, validate); if (buf != NULL) { - const struct ip *ip; - - ip = (struct ip *) buf; - if (*len < 1 || ip->ip_v != 4) + if (*len < 1 || (buf[0] >> 4) != 4) return NULL; } @@ -1475,13 +1477,12 @@ static bool accept_any (const unsigned char *p, const struct pcap_pkthdr *h, int } static bool accept_ip (const unsigned char *p, const struct pcap_pkthdr *h, int datalink, size_t offset) { - const struct ip *ip = NULL; if (h->caplen < offset + sizeof(struct ip)) { return false; } - ip = (struct ip *) (p + offset); - switch (ip->ip_v) { + u8 v = p[offset] >> 4; + switch (v) { case 4: case 6: break; @@ -1766,16 +1767,18 @@ int recvtime(int sd, char *buf, int len, int seconds, int *timedout) { parameters (if non-null) are filled with 0. Remember that the correct way to check for errors is to look at the return value since a zero ts or echots could possibly be valid. */ -int gettcpopt_ts(const struct tcp_hdr *tcp, u32 *timestamp, u32 *echots) { +int gettcpopt_ts(const u8 *tcppkt, u32 *timestamp, u32 *echots) { - unsigned char *p; + const u8 *p; int len = 0; int op; int oplen; + struct tcp_hdr tcp; + memcpy(&tcp, tcppkt, sizeof(tcp)); /* first we find where the tcp options start ... */ - p = ((unsigned char *) tcp) + 20; - len = 4 * tcp->th_off - 20; + p = tcppkt + 20; + len = 4 * tcp.th_off - 20; while (len > 0 && *p != 0 /* TCPOPT_EOL */ ) { op = *p++; if (op == 0 /* TCPOPT_EOL */ ) diff --git a/tcpip.h b/tcpip.h index 47b585d64..79eb43683 100644 --- a/tcpip.h +++ b/tcpip.h @@ -368,7 +368,7 @@ const u8 *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec, parameters (if non-null) are filled with 0. Remember that the correct way to check for errors is to look at the return value since a zero ts or echots could possibly be valid. */ -int gettcpopt_ts(const struct tcp_hdr *tcp, u32 *timestamp, u32 *echots); +int gettcpopt_ts(const u8 *tcppkt, u32 *timestamp, u32 *echots); /* Maximize the receive buffer of a socket descriptor (up to 500K) */ void max_rcvbuf(int sd); diff --git a/traceroute.cc b/traceroute.cc index 2a330f50b..c7bfa7a1e 100644 --- a/traceroute.cc +++ b/traceroute.cc @@ -1068,6 +1068,10 @@ struct Reply { u16 token; }; +#define ALIGN_HEADER(_Type, _Name, _Ptr, _Offset, _Len) \ +_Type _Name; \ +memcpy(&_Name, (u8 *)_Ptr + _Offset, MIN(_Len - _Offset, sizeof(_Type))); + static bool parse_encapsulated_reply(const void *ip, unsigned len, Reply *reply) { struct abstract_ip_hdr hdr; const void *data; @@ -1077,30 +1081,31 @@ static bool parse_encapsulated_reply(const void *ip, unsigned len, Reply *reply) return false; if (hdr.version == 4 && hdr.proto == IPPROTO_ICMP) { - const struct icmp *icmp = (const struct icmp *) data; - if (len < 8 || ntohs(icmp->icmp_id) != global_id) + if (len < offsetof(struct icmp, icmp_id) + 2) return false; - reply->token = ntohs(icmp->icmp_seq); + ALIGN_HEADER(struct icmp, icmp, data, 0, len); + if (ntohs(icmp.icmp_id) != global_id) + return false; + reply->token = ntohs(icmp.icmp_seq); } else if (hdr.version == 6 && hdr.proto == IPPROTO_ICMPV6) { - const struct icmpv6_msg_echo *echo = (struct icmpv6_msg_echo *) ((char *) data + sizeof(struct icmpv6_hdr)); - if (len < 8 || ntohs(echo->icmpv6_id) != global_id) + if (len < sizeof(struct icmpv6_hdr) + offsetof(struct icmpv6_msg_echo, icmpv6_seq) + 2) return false; - reply->token = ntohs(echo->icmpv6_seq); + ALIGN_HEADER(struct icmpv6_msg_echo, echo, data, sizeof(struct icmpv6_hdr), len); + if (ntohs(echo.icmpv6_id) != global_id) + return false; + reply->token = ntohs(echo.icmpv6_seq); } else if (hdr.proto == IPPROTO_TCP) { - const struct tcp_hdr *tcp = (const struct tcp_hdr *) data; - if (len < 2) - return false; - reply->token = ntohs(tcp->th_sport) ^ global_id; + if (len < offsetof(struct tcp_hdr, th_sport) + 2) return false; + ALIGN_HEADER(struct tcp_hdr, tcp, data, 0, len); + reply->token = ntohs(tcp.th_sport) ^ global_id; } else if (hdr.proto == IPPROTO_UDP) { - const struct udp_hdr *udp = (const struct udp_hdr *) data; - if (len < 2) - return false; - reply->token = ntohs(udp->uh_sport) ^ global_id; + if (len < offsetof(struct udp_hdr, uh_sport) + 2) return false; + ALIGN_HEADER(struct udp_hdr, udp, data, 0, len); + reply->token = ntohs(udp.uh_sport) ^ global_id; } else if (hdr.proto == IPPROTO_SCTP) { - const struct sctp_hdr *sctp = (const struct sctp_hdr *) data; - if (len < 2) - return false; - reply->token = ntohs(sctp->sh_sport) ^ global_id; + if (len < offsetof(struct sctp_hdr, sh_sport) + 2) return false; + ALIGN_HEADER(struct sctp_hdr, sctp, data, 0, len); + reply->token = ntohs(sctp.sh_sport) ^ global_id; } else { if (len < 6) return false; @@ -1127,26 +1132,24 @@ static bool decode_reply(const void *ip, unsigned int len, Reply *reply) { if (hdr.version == 4 && hdr.proto == IPPROTO_ICMP) { /* ICMP responses comprise all the TTL exceeded messages we expect from all probe types, as well as actual replies from ICMP probes. */ - const struct icmp_hdr *icmp = (const struct icmp_hdr *) data; - if (len < 8) - return false; - if ((icmp->icmp_type == ICMP_TIMEXCEED - && icmp->icmp_code == ICMP_TIMEXCEED_INTRANS) - || icmp->icmp_type == ICMP_UNREACH) { + ALIGN_HEADER(struct icmp_hdr, icmp, data, 0, len); + if ((icmp.icmp_type == ICMP_TIMEXCEED + && icmp.icmp_code == ICMP_TIMEXCEED_INTRANS) + || icmp.icmp_type == ICMP_UNREACH) { /* Get the encapsulated IP packet. */ - const void *encaps = icmp_get_data(icmp, &len); + const void *encaps = icmp_get_data(data, &len); if (encaps == NULL) return false; return parse_encapsulated_reply(encaps, len, reply); - } else if (icmp->icmp_type == ICMP_ECHOREPLY - || icmp->icmp_type == ICMP_MASKREPLY - || icmp->icmp_type == ICMP_TSTAMPREPLY) { + } else if (icmp.icmp_type == ICMP_ECHOREPLY + || icmp.icmp_type == ICMP_MASKREPLY + || icmp.icmp_type == ICMP_TSTAMPREPLY) { /* Need this alternate form of header for icmp_id and icmp_seq. */ - const struct icmp *icmp = (const struct icmp *) data; + ALIGN_HEADER(struct icmp, icmp, data, 0, len); - if (ntohs(icmp->icmp_id) != global_id) + if (ntohs(icmp.icmp_id) != global_id) return false; - reply->token = ntohs(icmp->icmp_seq); + reply->token = ntohs(icmp.icmp_seq); /* Reply came directly from the target. */ reply->target_addr = reply->from_addr; } else { @@ -1155,50 +1158,39 @@ static bool decode_reply(const void *ip, unsigned int len, Reply *reply) { } else if (hdr.version == 6 && hdr.proto == IP_PROTO_ICMPV6) { /* ICMPv6 responses comprise all the TTL exceeded messages we expect from all probe types, as well as actual replies from ICMP probes. */ - const struct icmpv6_hdr *icmpv6 = (const struct icmpv6_hdr *) data; - if (len < 2) - return false; + ALIGN_HEADER(struct icmpv6_hdr, icmpv6, data, 0, len); /* TIMEXCEED, UNREACH */ - if ((icmpv6->icmpv6_type == ICMPV6_TIMEXCEED - && icmpv6->icmpv6_code == ICMPV6_TIMEXCEED_INTRANS) - || icmpv6->icmpv6_type == ICMPV6_UNREACH) { + if ((icmpv6.icmpv6_type == ICMPV6_TIMEXCEED + && icmpv6.icmpv6_code == ICMPV6_TIMEXCEED_INTRANS) + || icmpv6.icmpv6_type == ICMPV6_UNREACH) { /* Get the encapsulated IP packet. */ - const void *encaps = icmpv6_get_data(icmpv6, &len); + const void *encaps = icmpv6_get_data(data, &len); if (encaps == NULL) return false; return parse_encapsulated_reply(encaps, len, reply); - } else if (icmpv6->icmpv6_type == ICMPV6_ECHOREPLY) { + } else if (icmpv6.icmpv6_type == ICMPV6_ECHOREPLY) { /* MASKREPLY, TSTAMPREPLY */ - const struct icmpv6_msg_echo *echo; + ALIGN_HEADER(struct icmpv6_msg_echo, echo, data, sizeof(icmpv6), len); - if (len < sizeof(*icmpv6) + 4) + if (ntohs(echo.icmpv6_id) != global_id) return false; - echo = (struct icmpv6_msg_echo *) ((char *) icmpv6 + sizeof(*icmpv6)); - if (ntohs(echo->icmpv6_id) != global_id) - return false; - reply->token = ntohs(echo->icmpv6_seq); + reply->token = ntohs(echo.icmpv6_seq); /* Reply came directly from the target. */ reply->target_addr = reply->from_addr; } else { return false; } } else if (hdr.proto == IPPROTO_TCP) { - const struct tcp_hdr *tcp = (const struct tcp_hdr *) data; - if (len < 4) - return false; - reply->token = ntohs(tcp->th_dport) ^ global_id; + ALIGN_HEADER(struct tcp_hdr, tcp, data, 0, len); + reply->token = ntohs(tcp.th_dport) ^ global_id; reply->target_addr = reply->from_addr; } else if (hdr.proto == IPPROTO_UDP) { - const struct udp_hdr *udp = (const struct udp_hdr *) data; - if (len < 4) - return false; - reply->token = ntohs(udp->uh_dport) ^ global_id; + ALIGN_HEADER(struct udp_hdr, udp, data, 0, len); + reply->token = ntohs(udp.uh_dport) ^ global_id; reply->target_addr = reply->from_addr; } else if (hdr.proto == IPPROTO_SCTP) { - const struct sctp_hdr *sctp = (const struct sctp_hdr *) data; - if (len < 4) - return false; - reply->token = ntohs(sctp->sh_dport) ^ global_id; + ALIGN_HEADER(struct sctp_hdr, sctp, data, 0, len); + reply->token = ntohs(sctp.sh_dport) ^ global_id; reply->target_addr = reply->from_addr; } else { return false; @@ -1208,17 +1200,14 @@ static bool decode_reply(const void *ip, unsigned int len, Reply *reply) { } static bool read_reply(Reply *reply, pcap_t *pd, long timeout) { - const struct ip *ip; + const void *ip; unsigned int iplen; struct link_header linkhdr; - ip = (struct ip *) readip_pcap(pd, &iplen, timeout, &reply->rcvdtime, &linkhdr, true); - if (ip == NULL) - return false; - if (ip->ip_v == 4 || ip->ip_v == 6) + ip = readip_pcap(pd, &iplen, timeout, &reply->rcvdtime, &linkhdr, true); + if (ip) return decode_reply(ip, iplen, reply); - else - return false; + return false; } void TracerouteState::read_replies(long timeout) {