/* Parse the IPv6 header and the TCP header inside. We do not * currently support parsing IPv6 extension headers or any layer 4 * protocol other than TCP. Return a packet_parse_result_t. * Note that packet_end points to the byte beyond the end of packet. */ static int parse_ipv6(struct packet *packet, u8 *header_start, u8 *packet_end, char **error) { u8 *p = header_start; packet->ipv6 = (struct ipv6 *) (p); /* Check that header fits in sniffed packet. */ const int ip_header_bytes = packet_ip_header_len(packet); assert(ip_header_bytes >= 0); assert(ip_header_bytes == sizeof(*packet->ipv6)); if (p + ip_header_bytes > packet_end) { asprintf(error, "IPv6 header overflows packet"); goto error_out; } /* Check that payload fits in sniffed packet. */ const int ip_total_bytes = (ip_header_bytes + ntohs(packet->ipv6->payload_len)); packet->ip_bytes = ip_total_bytes; if (p + ip_total_bytes > packet_end) { asprintf(error, "IPv6 payload overflows packet"); goto error_out; } assert(ip_header_bytes <= ip_total_bytes); /* Move on to the header inside. */ p += ip_header_bytes; assert(p <= packet_end); if (DEBUG_LOGGING) { char src_string[ADDR_STR_LEN]; char dst_string[ADDR_STR_LEN]; struct ip_address src_ip, dst_ip; ip_from_ipv6(&packet->ipv6->src_ip, &src_ip); ip_from_ipv6(&packet->ipv6->dst_ip, &dst_ip); DEBUGP("src IP: %s\n", ip_to_string(&src_ip, src_string)); DEBUGP("dst IP: %s\n", ip_to_string(&dst_ip, dst_string)); } /* Examine the L4 header. */ const int layer4_bytes = ip_total_bytes - ip_header_bytes; const int layer4_protocol = packet->ipv6->next_header; return parse_layer4(packet, p, layer4_protocol, layer4_bytes, packet_end, error); error_out: return PACKET_BAD; }
/* Parse the IPv6 header and the TCP header inside. We do not * currently support parsing IPv6 extension headers or any layer 4 * protocol other than TCP. Return a packet_parse_result_t. * Note that packet_end points to the byte beyond the end of packet. */ static int parse_ipv6(struct packet *packet, u8 *header_start, u8 *packet_end, char **error) { struct header *ip_header = NULL; u8 *p = header_start; const bool is_outer = (packet->ip_bytes == 0); bool is_inner = false; struct ipv6 *ipv6 = (struct ipv6 *) (p); enum packet_parse_result_t result = PACKET_BAD; /* Check that header fits in sniffed packet. */ const int ip_header_bytes = sizeof(*ipv6); if (p + ip_header_bytes > packet_end) { asprintf(error, "IPv6 header overflows packet"); goto error_out; } /* Check that payload fits in sniffed packet. */ const int ip_total_bytes = (ip_header_bytes + ntohs(ipv6->payload_len)); if (p + ip_total_bytes > packet_end) { asprintf(error, "IPv6 payload overflows packet"); goto error_out; } assert(ip_header_bytes <= ip_total_bytes); ip_header = packet_append_header(packet, HEADER_IPV6, ip_header_bytes); if (ip_header == NULL) { asprintf(error, "Too many nested headers at IPv6 header"); goto error_out; } ip_header->total_bytes = ip_total_bytes; /* Move on to the header inside. */ p += ip_header_bytes; assert(p <= packet_end); if (DEBUG_LOGGING) { char src_string[ADDR_STR_LEN]; char dst_string[ADDR_STR_LEN]; struct ip_address src_ip, dst_ip; ip_from_ipv6(&ipv6->src_ip, &src_ip); ip_from_ipv6(&ipv6->dst_ip, &dst_ip); DEBUGP("src IP: %s\n", ip_to_string(&src_ip, src_string)); DEBUGP("dst IP: %s\n", ip_to_string(&dst_ip, dst_string)); } /* Examine the L4 header. */ const int layer4_bytes = ip_total_bytes - ip_header_bytes; const int layer4_protocol = ipv6->next_header; result = parse_layer4(packet, p, layer4_protocol, layer4_bytes, packet_end, &is_inner, error); /* If this is the innermost IP header then this is the primary. */ if (is_inner) packet->ipv6 = ipv6; /* If this is the outermost IP header then this is the packet length. */ if (is_outer) packet->ip_bytes = ip_total_bytes; return result; error_out: return PACKET_BAD; }
/* Parse the IPv4 header and the TCP header inside. Return a * packet_parse_result_t. * Note that packet_end points to the byte beyond the end of packet. */ static int parse_ipv4(struct packet *packet, u8 *header_start, u8 *packet_end, char **error) { struct header *ip_header = NULL; u8 *p = header_start; const bool is_outer = (packet->ip_bytes == 0); bool is_inner = false; enum packet_parse_result_t result = PACKET_BAD; struct ipv4 *ipv4 = (struct ipv4 *) (p); const int ip_header_bytes = ipv4_header_len(ipv4); assert(ip_header_bytes >= 0); if (ip_header_bytes < sizeof(*ipv4)) { asprintf(error, "IP header too short"); goto error_out; } if (p + ip_header_bytes > packet_end) { asprintf(error, "Full IP header overflows packet"); goto error_out; } const int ip_total_bytes = ntohs(ipv4->tot_len); if (p + ip_total_bytes > packet_end) { asprintf(error, "IP payload overflows packet"); goto error_out; } if (ip_header_bytes > ip_total_bytes) { asprintf(error, "IP header bigger than datagram"); goto error_out; } if (ntohs(ipv4->frag_off) & IP_MF) { /* more fragments? */ asprintf(error, "More fragments remaining"); goto error_out; } if (ntohs(ipv4->frag_off) & IP_OFFMASK) { /* fragment offset */ asprintf(error, "Non-zero fragment offset"); goto error_out; } const u16 checksum = ipv4_checksum(ipv4, ip_header_bytes); if (checksum != 0) { asprintf(error, "Bad IP checksum"); goto error_out; } ip_header = packet_append_header(packet, HEADER_IPV4, ip_header_bytes); if (ip_header == NULL) { asprintf(error, "Too many nested headers at IPv4 header"); goto error_out; } ip_header->total_bytes = ip_total_bytes; /* Move on to the header inside. */ p += ip_header_bytes; assert(p <= packet_end); if (DEBUG_LOGGING) { char src_string[ADDR_STR_LEN]; char dst_string[ADDR_STR_LEN]; struct ip_address src_ip, dst_ip; ip_from_ipv4(&ipv4->src_ip, &src_ip); ip_from_ipv4(&ipv4->dst_ip, &dst_ip); DEBUGP("src IP: %s\n", ip_to_string(&src_ip, src_string)); DEBUGP("dst IP: %s\n", ip_to_string(&dst_ip, dst_string)); } /* Examine the L4 header. */ const int layer4_bytes = ip_total_bytes - ip_header_bytes; const int layer4_protocol = ipv4->protocol; result = parse_layer4(packet, p, layer4_protocol, layer4_bytes, packet_end, &is_inner, error); /* If this is the innermost IP header then this is the primary. */ if (is_inner) packet->ipv4 = ipv4; /* If this is the outermost IP header then this is the packet length. */ if (is_outer) packet->ip_bytes = ip_total_bytes; return result; error_out: return PACKET_BAD; }
/* Parse the IPv4 header and the TCP header inside. Return a * packet_parse_result_t. * Note that packet_end points to the byte beyond the end of packet. */ static int parse_ipv4(struct packet *packet, u8 *header_start, u8 *packet_end, char **error) { u8 *p = header_start; packet->ipv4 = (struct ipv4 *) (p); const int ip_header_bytes = packet_ip_header_len(packet); assert(ip_header_bytes >= 0); if (ip_header_bytes < sizeof(*packet->ipv4)) { asprintf(error, "IP header too short"); goto error_out; } if (p + ip_header_bytes > packet_end) { asprintf(error, "Full IP header overflows packet"); goto error_out; } const int ip_total_bytes = ntohs(packet->ipv4->tot_len); packet->ip_bytes = ip_total_bytes; if (p + ip_total_bytes > packet_end) { asprintf(error, "IP payload overflows packet"); goto error_out; } if (ip_header_bytes > ip_total_bytes) { asprintf(error, "IP header bigger than datagram"); goto error_out; } if (ntohs(packet->ipv4->frag_off) & IP_MF) { /* more fragments? */ asprintf(error, "More fragments remaining"); goto error_out; } if (ntohs(packet->ipv4->frag_off) & IP_OFFMASK) { /* fragment offset */ asprintf(error, "Non-zero fragment offset"); goto error_out; } const u16 checksum = ipv4_checksum(packet->ipv4, ip_header_bytes); if (checksum != 0) { asprintf(error, "Bad IP checksum"); goto error_out; } /* Move on to the header inside. */ p += ip_header_bytes; assert(p <= packet_end); if (DEBUG_LOGGING) { char src_string[ADDR_STR_LEN]; char dst_string[ADDR_STR_LEN]; struct ip_address src_ip, dst_ip; ip_from_ipv4(&packet->ipv4->src_ip, &src_ip); ip_from_ipv4(&packet->ipv4->dst_ip, &dst_ip); DEBUGP("src IP: %s\n", ip_to_string(&src_ip, src_string)); DEBUGP("dst IP: %s\n", ip_to_string(&dst_ip, dst_string)); } /* Examine the L4 header. */ const int layer4_bytes = ip_total_bytes - ip_header_bytes; const int layer4_protocol = packet->ipv4->protocol; return parse_layer4(packet, p, layer4_protocol, layer4_bytes, packet_end, error); error_out: return PACKET_BAD; }