1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * (C) 2007 by Sebastian Claßen <sebastian.classen@freenet.ag> 4 * (C) 2007-2010 by Jan Engelhardt <jengelh@medozas.de> 5 * 6 * Extracted from xt_TEE.c 7 */ 8 #include <linux/ip.h> 9 #include <linux/module.h> 10 #include <linux/percpu.h> 11 #include <linux/route.h> 12 #include <linux/skbuff.h> 13 #include <linux/netfilter.h> 14 #include <net/checksum.h> 15 #include <net/icmp.h> 16 #include <net/ip.h> 17 #include <net/route.h> 18 #include <net/netfilter/ipv4/nf_dup_ipv4.h> 19 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 20 #include <net/netfilter/nf_conntrack.h> 21 #endif 22 23 static bool nf_dup_ipv4_route(struct net *net, struct sk_buff *skb, 24 const struct in_addr *gw, int oif) 25 { 26 const struct iphdr *iph = ip_hdr(skb); 27 struct rtable *rt; 28 struct flowi4 fl4; 29 30 memset(&fl4, 0, sizeof(fl4)); 31 if (oif != -1) 32 fl4.flowi4_oif = oif; 33 34 fl4.daddr = gw->s_addr; 35 fl4.flowi4_tos = RT_TOS(iph->tos); 36 fl4.flowi4_scope = RT_SCOPE_UNIVERSE; 37 fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH; 38 rt = ip_route_output_key(net, &fl4); 39 if (IS_ERR(rt)) 40 return false; 41 42 skb_dst_drop(skb); 43 skb_dst_set(skb, &rt->dst); 44 skb->dev = rt->dst.dev; 45 skb->protocol = htons(ETH_P_IP); 46 47 return true; 48 } 49 50 void nf_dup_ipv4(struct net *net, struct sk_buff *skb, unsigned int hooknum, 51 const struct in_addr *gw, int oif) 52 { 53 struct iphdr *iph; 54 55 if (this_cpu_read(nf_skb_duplicated)) 56 return; 57 /* 58 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for 59 * the original skb, which should continue on its way as if nothing has 60 * happened. The copy should be independently delivered to the gateway. 61 */ 62 skb = pskb_copy(skb, GFP_ATOMIC); 63 if (skb == NULL) 64 return; 65 66 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 67 /* Avoid counting cloned packets towards the original connection. */ 68 nf_reset_ct(skb); 69 nf_ct_set(skb, NULL, IP_CT_UNTRACKED); 70 #endif 71 /* 72 * If we are in PREROUTING/INPUT, decrease the TTL to mitigate potential 73 * loops between two hosts. 74 * 75 * Set %IP_DF so that the original source is notified of a potentially 76 * decreased MTU on the clone route. IPv6 does this too. 77 * 78 * IP header checksum will be recalculated at ip_local_out. 79 */ 80 iph = ip_hdr(skb); 81 iph->frag_off |= htons(IP_DF); 82 if (hooknum == NF_INET_PRE_ROUTING || 83 hooknum == NF_INET_LOCAL_IN) 84 --iph->ttl; 85 86 if (nf_dup_ipv4_route(net, skb, gw, oif)) { 87 __this_cpu_write(nf_skb_duplicated, true); 88 ip_local_out(net, skb->sk, skb); 89 __this_cpu_write(nf_skb_duplicated, false); 90 } else { 91 kfree_skb(skb); 92 } 93 } 94 EXPORT_SYMBOL_GPL(nf_dup_ipv4); 95 96 MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>"); 97 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 98 MODULE_DESCRIPTION("nf_dup_ipv4: Duplicate IPv4 packet"); 99 MODULE_LICENSE("GPL"); 100