static int decode_udp(packet_t *p, const _uint8 *bytes, size_t len) { int status = DECODE_OK; udp_t *udp = NULL; if (UDP_HDR_LEN > len) { decoder_add_error(p, "invalid UDP header length"); return call_decoder(PROTO_NAME_RAW, p, bytes, len); } udp = (udp_t *)bytes; packet_append_header(p, PROTO_NAME_UDP, (void *)udp, UDP_HDR_LEN); p->src_port = udp->src_port; p->dst_port = udp->dest_port; if ((len - UDP_HDR_LEN) > 0) { status += call_decoder_byport(ntohs(udp->src_port), p, (bytes + UDP_HDR_LEN), (len - UDP_HDR_LEN)); if (status == DECODER_NOT_FOUND) status += call_decoder_byport(ntohs(udp->dest_port), p, (bytes + UDP_HDR_LEN), (len - UDP_HDR_LEN)); if (status == DECODER_NOT_FOUND) status = call_decoder(PROTO_NAME_RAW, p, (bytes + UDP_HDR_LEN), (len - UDP_HDR_LEN)); } return status; }
static int decode_ftp(packet_t *p, const _uint8 *bytes, size_t len) { header_t *h = packet_append_header(p, PROTO_NAME_FTP, (void *)bytes, len); packet_set_payload(p, h); return DECODE_OK; }
struct packet *new_udp_packet(int address_family, enum direction_t direction, u16 udp_payload_bytes, char **error) { struct packet *packet = NULL; /* the newly-allocated result packet */ struct header *udp_header = NULL; /* the UDP header info */ /* Calculate lengths in bytes of all sections of the packet */ const int ip_option_bytes = 0; const int ip_header_bytes = (ip_header_min_len(address_family) + ip_option_bytes); const int udp_header_bytes = sizeof(struct udp); const int ip_bytes = ip_header_bytes + udp_header_bytes + udp_payload_bytes; /* Sanity-check all the various lengths */ if (ip_option_bytes & 0x3) { asprintf(error, "IP options are not padded correctly " "to ensure IP header is a multiple of 4 bytes: " "%d excess bytes", ip_option_bytes & 0x3); return NULL; } assert((udp_header_bytes & 0x3) == 0); assert((ip_header_bytes & 0x3) == 0); if (ip_bytes > MAX_UDP_DATAGRAM_BYTES) { asprintf(error, "UDP datagram too large"); return NULL; } /* Allocate and zero out a packet object of the desired size */ packet = packet_new(ip_bytes); memset(packet->buffer, 0, ip_bytes); packet->direction = direction; packet->flags = 0; packet->ecn = ECN_NONE; /* Set IP header fields */ set_packet_ip_header(packet, address_family, ip_bytes, packet->ecn, IPPROTO_UDP); udp_header = packet_append_header(packet, HEADER_UDP, sizeof(struct udp)); udp_header->total_bytes = udp_header_bytes + udp_payload_bytes; /* Find the start of UDP section of the packet */ packet->udp = (struct udp *) (ip_start(packet) + ip_header_bytes); /* Set UDP header fields */ packet->udp->src_port = htons(0); packet->udp->dst_port = htons(0); packet->udp->len = htons(udp_header_bytes + udp_payload_bytes); packet->udp->check = 0; packet->ip_bytes = ip_bytes; return packet; }
/* Send ARP Reply packet */ void inject_arp_reply(char *eth_src, char *ip_src, char *eth_target, char *ip_target) { packet_t *p = NULL; ether_t *ether = NULL; arp_t *arp; p = packet_new_empty(); ether = build_ethernet(eth_src, eth_target, ETHER_TYPE_ARP); packet_append_header(p, PROTO_NAME_ETHER, (void *)ether, ETHER_HDR_LEN); arp = build_arp_ethip(ARP_OP_REPLY, eth_src, ip_src, eth_target, ip_target); packet_append_header(p, PROTO_NAME_ARP, (void *)arp, sizeof(arp_t) + sizeof(arp_ethip_t)); inject(p); packet_free(p); free(ether); free(arp); }
/* Send custom ARP message */ void inject_arp(char *eth_src, char *eth_dst, _uint16 opcode, char *sha, char *spa, char *tha, char *tpa) { packet_t *p = NULL; ether_t *ether = NULL; arp_t *arp; p = packet_new_empty(); ether = build_ethernet(eth_src, eth_dst, ETHER_TYPE_ARP); packet_append_header(p, PROTO_NAME_ETHER, (void *)ether, ETHER_HDR_LEN); arp = build_arp_ethip(opcode, sha, spa, tha, tpa); packet_append_header(p, PROTO_NAME_ARP, (void *)arp, sizeof(arp_t) + sizeof(arp_ethip_t)); inject(p); packet_free(p); free(ether); free(arp); }
/* Parse the GRE header. Return a packet_parse_result_t. */ static int parse_gre(struct packet *packet, u8 *layer4_start, int layer4_bytes, u8 *packet_end, char **error) { struct header *gre_header = NULL; u8 *p = layer4_start; struct gre *gre = (struct gre *) p; assert(layer4_bytes >= 0); if (layer4_bytes < sizeof(struct gre)) { asprintf(error, "Truncated GRE header"); goto error_out; } if (gre->version != 0) { asprintf(error, "GRE header has unsupported version number"); goto error_out; } if (gre->has_routing) { asprintf(error, "GRE header has unsupported routing info"); goto error_out; } const int gre_header_len = gre_len(gre); if (gre_header_len < sizeof(struct gre)) { asprintf(error, "GRE header length too small for GRE header"); goto error_out; } if (gre_header_len > layer4_bytes) { asprintf(error, "GRE header length too big"); goto error_out; } assert(p + layer4_bytes <= packet_end); DEBUGP("GRE header len: %d\n", gre_header_len); gre_header = packet_append_header(packet, HEADER_GRE, gre_header_len); if (gre_header == NULL) { asprintf(error, "Too many nested headers at GRE header"); goto error_out; } gre_header->total_bytes = layer4_bytes; p += gre_header_len; assert(p <= packet_end); return parse_layer3_packet_by_proto(packet, ntohs(gre->protocol), p, packet_end, error); error_out: return PACKET_BAD; }
/* Parse the UDP header. Return a packet_parse_result_t. */ static int parse_udp(struct packet *packet, u8 *layer4_start, int layer4_bytes, u8 *packet_end, char **error) { struct header *udp_header = NULL; u8 *p = layer4_start; assert(layer4_bytes >= 0); if (layer4_bytes < sizeof(struct udp)) { asprintf(error, "Truncated UDP header"); goto error_out; } packet->udp = (struct udp *) p; const int udp_len = ntohs(packet->udp->len); const int udp_header_len = sizeof(struct udp); if (udp_len < udp_header_len) { asprintf(error, "UDP datagram length too small for UDP header"); goto error_out; } if (udp_len < layer4_bytes) { asprintf(error, "UDP datagram length too small"); goto error_out; } if (udp_len > layer4_bytes) { asprintf(error, "UDP datagram length too big"); goto error_out; } udp_header = packet_append_header(packet, HEADER_UDP, udp_header_len); if (udp_header == NULL) { asprintf(error, "Too many nested headers at UDP header"); goto error_out; } udp_header->total_bytes = layer4_bytes; p += layer4_bytes; assert(p <= packet_end); DEBUGP("UDP src port: %d\n", ntohs(packet->udp->src_port)); DEBUGP("UDP dst port: %d\n", ntohs(packet->udp->dst_port)); return PACKET_OK; error_out: return PACKET_BAD; }
static int parse_mpls(struct packet *packet, u8 *header_start, u8 *packet_end, char **error) { struct header *mpls_header = NULL; u8 *p = header_start; int mpls_header_bytes = 0; int mpls_total_bytes = packet_end - p; bool is_stack_bottom = false; do { struct mpls *mpls_entry = (struct mpls *)(p); if (p + sizeof(struct mpls) > packet_end) { asprintf(error, "MPLS stack entry overflows packet"); goto error_out; } is_stack_bottom = mpls_entry_stack(mpls_entry); p += sizeof(struct mpls); mpls_header_bytes += sizeof(struct mpls); } while (!is_stack_bottom && p < packet_end); assert(mpls_header_bytes <= mpls_total_bytes); mpls_header = packet_append_header(packet, HEADER_MPLS, mpls_header_bytes); if (mpls_header == NULL) { asprintf(error, "Too many nested headers at MPLS header"); goto error_out; } mpls_header->total_bytes = mpls_total_bytes; /* Move on to the header inside the MPLS label stack. */ assert(p <= packet_end); return parse_layer3_packet(packet, p, packet_end, error); error_out: return PACKET_BAD; }
static int decode_tcp(packet_t *p, const _uint8 *bytes, size_t len) { int status = DECODE_OK; unsigned int totlen = 0; tcp_t *tcp = NULL; if (sizeof(tcp_t) > len) goto err; tcp = (tcp_t *)bytes; totlen = TCP_HDR_LEN(tcp); if (totlen > len) goto err; packet_append_header(p, PROTO_NAME_TCP, (void *)tcp, totlen); p->src_port = tcp->src_port; p->dst_port = tcp->dest_port; /* If there is more data */ if ((len - totlen) > 0) { status += call_decoder_byport(ntohs(tcp->src_port), p, (bytes + totlen), (len - totlen)); if (status == DECODER_NOT_FOUND) status += call_decoder_byport(ntohs(tcp->dest_port), p, (bytes + totlen), (len - totlen)); if (status == DECODER_NOT_FOUND) status += call_decoder(PROTO_NAME_RAW, p, (bytes + totlen), (len - totlen)); } return status; err: decoder_add_error(p, "invalid TCP header length"); return call_decoder(PROTO_NAME_RAW, p, bytes, len); }
/* Parse the TCP header. Return a packet_parse_result_t. */ static int parse_tcp(struct packet *packet, u8 *layer4_start, int layer4_bytes, u8 *packet_end, char **error) { struct header *tcp_header = NULL; u8 *p = layer4_start; assert(layer4_bytes >= 0); if (layer4_bytes < sizeof(struct tcp)) { asprintf(error, "Truncated TCP header"); goto error_out; } packet->tcp = (struct tcp *) p; const int tcp_header_len = packet_tcp_header_len(packet); if (tcp_header_len < sizeof(struct tcp)) { asprintf(error, "TCP data offset too small"); goto error_out; } if (tcp_header_len > layer4_bytes) { asprintf(error, "TCP data offset too big"); goto error_out; } tcp_header = packet_append_header(packet, HEADER_TCP, tcp_header_len); if (tcp_header == NULL) { asprintf(error, "Too many nested headers at TCP header"); goto error_out; } tcp_header->total_bytes = layer4_bytes; p += layer4_bytes; assert(p <= packet_end); DEBUGP("TCP src port: %d\n", ntohs(packet->tcp->src_port)); DEBUGP("TCP dst port: %d\n", ntohs(packet->tcp->dst_port)); return PACKET_OK; error_out: return PACKET_BAD; }
/* Parse the ICMPv4 header. Return a packet_parse_result_t. */ static int parse_icmpv4(struct packet *packet, u8 *layer4_start, int layer4_bytes, u8 *packet_end, char **error) { struct header *icmp_header = NULL; const int icmp_header_len = sizeof(struct icmpv4); u8 *p = layer4_start; assert(layer4_bytes >= 0); /* Make sure the immediately preceding header was IPv4. */ if (packet_inner_header(packet)->type != HEADER_IPV4) { asprintf(error, "Bad IP version for IPPROTO_ICMP"); goto error_out; } if (layer4_bytes < sizeof(struct icmpv4)) { asprintf(error, "Truncated ICMPv4 header"); goto error_out; } packet->icmpv4 = (struct icmpv4 *) p; icmp_header = packet_append_header(packet, HEADER_ICMPV4, icmp_header_len); if (icmp_header == NULL) { asprintf(error, "Too many nested headers at ICMPV4 header"); goto error_out; } icmp_header->total_bytes = layer4_bytes; p += layer4_bytes; assert(p <= packet_end); return PACKET_OK; error_out: return PACKET_BAD; }
static int decode_raw(packet_t *p, const _uint8 *bytes, size_t len) { packet_append_header(p, PROTO_NAME_RAW, (void *)bytes, len); return DECODE_OK; }
/* 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; }