static int whine_if_too_big(struct packet *in, struct packet *out) { unsigned int len; unsigned int mtu; if (pkt_l3_proto(in) == L3PROTO_IPV4 && !is_dont_fragment_set(pkt_ip4_hdr(in))) return 0; len = pkt_len(out); mtu = get_nexthop_mtu(out); if (len > mtu) { /* * We don't have to worry about ICMP errors causing this because the translate code already * truncates them. */ log_debug("Packet is too big (len: %u, mtu: %u).", len, mtu); switch (pkt_l3_proto(out)) { case L3PROTO_IPV6: mtu -= 20; break; case L3PROTO_IPV4: mtu += 20; break; } icmp64_send(out, ICMPERR_FRAG_NEEDED, mtu); return -EINVAL; } return 0; }
/** * Main F&U routine. Called during the processing of every packet. * * Decides if "skb" should be processed, updating binding and session information. * * @param[in] skb packet being translated. * @param[in] tuple skb's summary. * @return indicator of what should happen to skb. */ verdict filtering_and_updating(struct packet *pkt, struct tuple *in_tuple) { struct ipv6hdr *hdr_ip6; verdict result = VERDICT_CONTINUE; log_debug("Step 2: Filtering and Updating"); switch (pkt_l3_proto(pkt)) { case L3PROTO_IPV6: /* ICMP errors should not be filtered or affect the tables. */ if (pkt_is_icmp6_error(pkt)) { log_debug("Packet is ICMPv6 error; skipping step..."); return VERDICT_CONTINUE; } /* Get rid of hairpinning loops and unwanted packets. */ hdr_ip6 = pkt_ip6_hdr(pkt); if (pool6_contains(&hdr_ip6->saddr)) { log_debug("Hairpinning loop. Dropping..."); inc_stats(pkt, IPSTATS_MIB_INADDRERRORS); return VERDICT_DROP; } if (!pool6_contains(&hdr_ip6->daddr)) { log_debug("Packet was rejected by pool6; dropping..."); inc_stats(pkt, IPSTATS_MIB_INADDRERRORS); return VERDICT_DROP; } break; case L3PROTO_IPV4: /* ICMP errors should not be filtered or affect the tables. */ if (pkt_is_icmp4_error(pkt)) { log_debug("Packet is ICMPv4 error; skipping step..."); return VERDICT_CONTINUE; } /* Get rid of unexpected packets */ if (!pool4_contains(pkt_ip4_hdr(pkt)->daddr)) { log_debug("Packet was rejected by pool4; dropping..."); inc_stats(pkt, IPSTATS_MIB_INADDRERRORS); return VERDICT_DROP; } break; } /* Process packet, according to its protocol. */ switch (pkt_l4_proto(pkt)) { case L4PROTO_UDP: switch (pkt_l3_proto(pkt)) { case L3PROTO_IPV6: result = ipv6_simple(pkt, in_tuple); break; case L3PROTO_IPV4: result = ipv4_simple(pkt, in_tuple); break; } break; case L4PROTO_TCP: result = tcp(pkt, in_tuple); break; case L4PROTO_ICMP: switch (pkt_l3_proto(pkt)) { case L3PROTO_IPV6: if (config_get_filter_icmpv6_info()) { log_debug("Packet is ICMPv6 info (ping); dropping due to policy."); inc_stats(pkt, IPSTATS_MIB_INDISCARDS); return VERDICT_DROP; } result = ipv6_simple(pkt, in_tuple); break; case L3PROTO_IPV4: result = ipv4_simple(pkt, in_tuple); break; } break; case L4PROTO_OTHER: WARN(true, "Unknown layer 4 protocol (%d)...", pkt_l4_proto(pkt)); break; } log_debug("Done: Step 2."); return result; }
/** * Checks whether "pkt" is a hairpin packet. * * @param pkt outgoing packet the NAT64 would send if it's not a hairpin. * @return whether pkt is a hairpin packet. */ bool is_hairpin(struct packet *pkt) { return (pkt_l3_proto(pkt) == L3PROTO_IPV4) ? pool4_contains(pkt_ip4_hdr(pkt)->daddr) : false; }