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