static verdict ipv4_icmp_err(struct sk_buff *skb, struct tuple *tuple4) { struct iphdr *inner_ipv4 = (struct iphdr *) (icmp_hdr(skb) + 1); struct udphdr *inner_udp; struct tcphdr *inner_tcp; struct icmphdr *inner_icmp; tuple4->src.addr4.l3.s_addr = inner_ipv4->daddr; tuple4->dst.addr4.l3.s_addr = inner_ipv4->saddr; switch (inner_ipv4->protocol) { case IPPROTO_UDP: inner_udp = ipv4_extract_l4_hdr(inner_ipv4); tuple4->src.addr4.l4 = be16_to_cpu(inner_udp->dest); tuple4->dst.addr4.l4 = be16_to_cpu(inner_udp->source); tuple4->l4_proto = L4PROTO_UDP; break; case IPPROTO_TCP: inner_tcp = ipv4_extract_l4_hdr(inner_ipv4); tuple4->src.addr4.l4 = be16_to_cpu(inner_tcp->dest); tuple4->dst.addr4.l4 = be16_to_cpu(inner_tcp->source); tuple4->l4_proto = L4PROTO_TCP; break; case IPPROTO_ICMP: inner_icmp = ipv4_extract_l4_hdr(inner_ipv4); if (is_icmp4_error(inner_icmp->type)) { log_debug("Packet is a ICMP error containing a ICMP error."); inc_stats(skb, IPSTATS_MIB_INHDRERRORS); return VER_DROP; } tuple4->src.addr4.l4 = be16_to_cpu(inner_icmp->un.echo.id); tuple4->dst.addr4.l4 = tuple4->src.addr4.l4; tuple4->l4_proto = L4PROTO_ICMP; break; default: log_debug("Packet's inner packet is not UDP, TCP or ICMP (%d)", inner_ipv4->protocol); inc_stats(skb, IPSTATS_MIB_INUNKNOWNPROTOS); return VER_DROP; } tuple4->l3_proto = L3PROTO_IPV4; return VER_CONTINUE; }
static bool ipv4_icmp_err(struct iphdr *hdr_ipv4, struct icmphdr *hdr_icmp, struct tuple *tuple) { struct iphdr *inner_ipv4 = (struct iphdr *) (hdr_icmp + 1); struct udphdr *inner_udp; struct tcphdr *inner_tcp; /* struct icmphdr *inner_icmp; */ tuple->src.addr.ipv4.s_addr = inner_ipv4->daddr; tuple->dst.addr.ipv4.s_addr = inner_ipv4->saddr; switch (inner_ipv4->protocol) { case IPPROTO_UDP: inner_udp = ipv4_extract_l4_hdr(inner_ipv4); tuple->src.l4_id = be16_to_cpu(inner_udp->dest); tuple->dst.l4_id = be16_to_cpu(inner_udp->source); break; case IPPROTO_TCP: inner_tcp = ipv4_extract_l4_hdr(inner_ipv4); tuple->src.l4_id = be16_to_cpu(inner_tcp->dest); tuple->dst.l4_id = be16_to_cpu(inner_tcp->source); break; case IPPROTO_ICMP: /* We're not supporting ICMP inside ICMP yet. */ return false; /* inner_icmp = ipv4_extract_l4_hdr(inner_ipv4); if (is_icmp4_error(inner_icmp->type)) return false; tuple->src.l4_id = be16_to_cpu(inner_icmp->un.echo.id); tuple->dst.l4_id = tuple->src.l4_id; break; */ default: log_warning("Packet's inner packet is not UDP, TCP or ICMP (%d)", inner_ipv4->protocol); return false; } tuple->l3_proto = PF_INET; tuple->l4_proto = inner_ipv4->protocol; return true; }
static verdict ipv4_icmp_err(struct iphdr *hdr_ipv4, struct icmphdr *hdr_icmp, struct tuple *tuple) { struct iphdr *inner_ipv4 = (struct iphdr *) (hdr_icmp + 1); struct udphdr *inner_udp; struct tcphdr *inner_tcp; struct icmphdr *inner_icmp; tuple->src.addr.ipv4.s_addr = inner_ipv4->daddr; tuple->dst.addr.ipv4.s_addr = inner_ipv4->saddr; switch (inner_ipv4->protocol) { case IPPROTO_UDP: inner_udp = ipv4_extract_l4_hdr(inner_ipv4); tuple->src.l4_id = be16_to_cpu(inner_udp->dest); tuple->dst.l4_id = be16_to_cpu(inner_udp->source); tuple->l4_proto = L4PROTO_UDP; break; case IPPROTO_TCP: inner_tcp = ipv4_extract_l4_hdr(inner_ipv4); tuple->src.l4_id = be16_to_cpu(inner_tcp->dest); tuple->dst.l4_id = be16_to_cpu(inner_tcp->source); tuple->l4_proto = L4PROTO_TCP; break; case IPPROTO_ICMP: inner_icmp = ipv4_extract_l4_hdr(inner_ipv4); if (is_icmp4_error(inner_icmp->type)) { log_debug("Packet is a ICMP error containing a ICMP error."); return VER_DROP; } tuple->src.l4_id = be16_to_cpu(inner_icmp->un.echo.id); tuple->dst.l4_id = tuple->src.l4_id; tuple->l4_proto = L4PROTO_ICMP; break; default: log_warning("Packet's inner packet is not UDP, TCP or ICMP (%d)", inner_ipv4->protocol); return VER_DROP; } tuple->l3_proto = L3PROTO_IPV4; return VER_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; }