Avoid undefined behavior from unaligned accesses

This commit is contained in:
dmiller 2026-04-20 15:21:55 +00:00
parent ab973f548a
commit 8ef3ed1471
8 changed files with 610 additions and 523 deletions

View file

@ -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);
}

View file

@ -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,

View file

@ -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<OFProbe *>::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, &timestamp, NULL) == 0))
if ((gettcpopt_ts(tcppkt, &timestamp, 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

View file

@ -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 */

View file

@ -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<UltraProbe *>::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)

View file

@ -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 */ )

View file

@ -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);

View file

@ -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) {