static verdict handle_icmp6(struct xlation *state, struct pkt_metadata const *meta) { union { struct icmp6hdr icmp; struct frag_hdr frag; } buffer; union { struct icmp6hdr *icmp; struct frag_hdr *frag; } ptr; verdict result; ptr.icmp = skb_hdr_ptr(state->in.skb, meta->l4_offset, buffer.icmp); if (!ptr.icmp) return truncated(state, "ICMPv6 header"); if (has_inner_pkt6(ptr.icmp->icmp6_type)) { result = validate_inner6(state, meta); if (result != VERDICT_CONTINUE) return result; } if (xlat_is_siit() && meta->has_frag_hdr && is_icmp6_info(ptr.icmp->icmp6_type)) { ptr.frag = skb_hdr_ptr(state->in.skb, meta->frag_offset, buffer.frag); if (!ptr.frag) return truncated(state, "fragment header"); if (is_fragmented_ipv6(ptr.frag)) { log_debug("Packet is a fragmented ping; its checksum cannot be translated."); return drop(state, JSTAT_FRAGMENTED_PING); } } return VERDICT_CONTINUE; }
bool determine_in_tuple(struct sk_buff *skb, struct tuple *tuple) { struct iphdr *hdr4; struct ipv6hdr *hdr6; struct icmphdr *icmp4; struct icmp6hdr *icmp6; struct hdr_iterator iterator; log_debug("Step 1: Determining the Incoming Tuple"); switch (be16_to_cpu(skb->protocol)) { case ETH_P_IP: hdr4 = ip_hdr(skb); switch (hdr4->protocol) { case IPPROTO_UDP: if (!ipv4_udp(hdr4, ipv4_extract_l4_hdr(hdr4), tuple)) return false; break; case IPPROTO_TCP: if (!ipv4_tcp(hdr4, ipv4_extract_l4_hdr(hdr4), tuple)) return false; break; case IPPROTO_ICMP: icmp4 = ipv4_extract_l4_hdr(hdr4); if (is_icmp4_info(icmp4->type)) { if (!ipv4_icmp_info(hdr4, icmp4, tuple)) return false; } else { if (!ipv4_icmp_err(hdr4, icmp4, tuple)) return false; } break; default: log_info("Unsupported transport protocol for IPv4: %d.", hdr4->protocol); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); return false; } break; case ETH_P_IPV6: hdr6 = ipv6_hdr(skb); hdr_iterator_init(&iterator, hdr6); hdr_iterator_last(&iterator); switch (iterator.hdr_type) { case IPPROTO_UDP: if (!ipv6_udp(hdr6, iterator.data, tuple)) return false; break; case IPPROTO_TCP: if (!ipv6_tcp(hdr6, iterator.data, tuple)) return false; break; case IPPROTO_ICMPV6: icmp6 = iterator.data; if (is_icmp6_info(icmp6->icmp6_type)) { if (!ipv6_icmp_info(hdr6, icmp6, tuple)) return false; } else { if (!ipv6_icmp_err(hdr6, icmp6, tuple)) return false; } break; default: log_info("Unsupported transport protocol for IPv6: %d.", iterator.hdr_type); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); return false; } break; default: log_info("Packet's protocol (%d) is not IPv4 or IPv6.", be16_to_cpu(skb->protocol)); return false; } log_tuple(tuple); log_debug("Done step 1."); return true; }
/** * Extracts relevant data from "skb" and stores it in the "tuple" tuple. * * @param skb packet the data will be extracted from. * @param tuple this function will populate this value using "skb"'s contents. * @return whether packet processing should continue. */ verdict determine_in_tuple(struct sk_buff *skb, struct tuple *in_tuple) { struct icmphdr *icmp4; struct icmp6hdr *icmp6; verdict result = VER_CONTINUE; log_debug("Step 1: Determining the Incoming Tuple"); switch (skb_l3_proto(skb)) { case L3PROTO_IPV4: switch (skb_l4_proto(skb)) { case L4PROTO_UDP: result = ipv4_udp(skb, in_tuple); break; case L4PROTO_TCP: result = ipv4_tcp(skb, in_tuple); break; case L4PROTO_ICMP: icmp4 = icmp_hdr(skb); if (is_icmp4_info(icmp4->type)) { result = ipv4_icmp_info(skb, in_tuple); } else if (is_icmp4_error(icmp4->type)) { result = ipv4_icmp_err(skb, in_tuple); } else { log_debug("Unknown ICMPv4 type: %u. Dropping packet...", icmp4->type); inc_stats(skb, IPSTATS_MIB_INHDRERRORS); result = VER_DROP; } break; } break; case L3PROTO_IPV6: switch (skb_l4_proto(skb)) { case L4PROTO_UDP: result = ipv6_udp(skb, in_tuple); break; case L4PROTO_TCP: result = ipv6_tcp(skb, in_tuple); break; case L4PROTO_ICMP: icmp6 = icmp6_hdr(skb); if (is_icmp6_info(icmp6->icmp6_type)) { result = ipv6_icmp_info(skb, in_tuple); } else if (is_icmp6_error(icmp6->icmp6_type)) { result = ipv6_icmp_err(skb, in_tuple); } else { log_debug("Unknown ICMPv6 type: %u. Dropping packet...", icmp6->icmp6_type); inc_stats(skb, IPSTATS_MIB_INHDRERRORS); result = VER_DROP; } break; } break; } /* * We moved the transport-protocol-not-recognized ICMP errors to packet.c because they're * covered in validations. */ log_tuple(in_tuple); log_debug("Done step 1."); return result; }
/** * Extracts relevant data from "frag" and stores it in the "tuple" tuple. * * @param frag fragment the data will be extracted from. Whether the packet is fragmented or not, * this has to be the chunk whose fragment offset is zero. * @param tuple this function will populate this value using "frag"'s contents. * @return whether packet processing should continue. */ verdict determine_in_tuple(struct fragment *frag, struct tuple *tuple) { struct iphdr *hdr4; struct ipv6hdr *hdr6; struct icmphdr *icmp4; struct icmp6hdr *icmp6; verdict result = VER_CONTINUE; log_debug("Step 1: Determining the Incoming Tuple"); switch (frag->l3_hdr.proto) { case L3PROTO_IPV4: hdr4 = frag_get_ipv4_hdr(frag); switch (frag->l4_hdr.proto) { case L4PROTO_UDP: result = ipv4_udp(hdr4, frag_get_udp_hdr(frag), tuple); break; case L4PROTO_TCP: result = ipv4_tcp(hdr4, frag_get_tcp_hdr(frag), tuple); break; case L4PROTO_ICMP: icmp4 = frag_get_icmp4_hdr(frag); if (is_icmp4_info(icmp4->type)) { result = ipv4_icmp_info(hdr4, icmp4, tuple); } else if (is_icmp4_error(icmp4->type)) { result = ipv4_icmp_err(hdr4, icmp4, tuple); } else { log_warning("Unknown ICMPv4 type: %u. Dropping packet...", icmp4->type); result = VER_DROP; } break; case L4PROTO_NONE: log_crit(ERR_ILLEGAL_NONE, "IPv4 - First fragment has no transport header."); result = VER_DROP; } break; case L3PROTO_IPV6: hdr6 = frag_get_ipv6_hdr(frag); switch (frag->l4_hdr.proto) { case L4PROTO_UDP: result = ipv6_udp(hdr6, frag_get_udp_hdr(frag), tuple); break; case L4PROTO_TCP: result = ipv6_tcp(hdr6, frag_get_tcp_hdr(frag), tuple); break; case L4PROTO_ICMP: icmp6 = frag_get_icmp6_hdr(frag); if (is_icmp6_info(icmp6->icmp6_type)) { result = ipv6_icmp_info(hdr6, icmp6, tuple); } else if (is_icmp6_error(icmp6->icmp6_type)) { result = ipv6_icmp_err(hdr6, icmp6, tuple); } else { log_warning("Unknown ICMPv6 type: %u. Dropping packet...", icmp6->icmp6_type); result = VER_DROP; } break; case L4PROTO_NONE: log_crit(ERR_ILLEGAL_NONE, "IPv6 - First fragment has no transport header."); result = VER_DROP; } break; } /* * We moved the transport-protocol-not-recognized ICMP errors to fragment_db because they're * covered in validations. */ log_tuple(tuple); log_debug("Done step 1."); return result; }