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/module.h> 9 #include <linux/percpu.h> 10 #include <linux/skbuff.h> 11 #include <linux/netfilter.h> 12 #include <net/ipv6.h> 13 #include <net/ip6_route.h> 14 #include <net/netfilter/ipv6/nf_dup_ipv6.h> 15 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 16 #include <net/netfilter/nf_conntrack.h> 17 #endif 18 nf_dup_ipv6_route(struct net * net,struct sk_buff * skb,const struct in6_addr * gw,int oif)19 static bool nf_dup_ipv6_route(struct net *net, struct sk_buff *skb, 20 const struct in6_addr *gw, int oif) 21 { 22 const struct ipv6hdr *iph = ipv6_hdr(skb); 23 struct dst_entry *dst; 24 struct flowi6 fl6; 25 26 memset(&fl6, 0, sizeof(fl6)); 27 if (oif != -1) 28 fl6.flowi6_oif = oif; 29 30 fl6.daddr = *gw; 31 fl6.flowlabel = (__force __be32)(((iph->flow_lbl[0] & 0xF) << 16) | 32 (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]); 33 fl6.flowi6_flags = FLOWI_FLAG_KNOWN_NH; 34 dst = ip6_route_output(net, NULL, &fl6); 35 if (dst->error) { 36 dst_release(dst); 37 return false; 38 } 39 skb_dst_drop(skb); 40 skb_dst_set(skb, dst); 41 skb->dev = dst->dev; 42 skb->protocol = htons(ETH_P_IPV6); 43 44 return true; 45 } 46 nf_dup_ipv6(struct net * net,struct sk_buff * skb,unsigned int hooknum,const struct in6_addr * gw,int oif)47 void nf_dup_ipv6(struct net *net, struct sk_buff *skb, unsigned int hooknum, 48 const struct in6_addr *gw, int oif) 49 { 50 if (this_cpu_read(nf_skb_duplicated)) 51 return; 52 skb = pskb_copy(skb, GFP_ATOMIC); 53 if (skb == NULL) 54 return; 55 56 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 57 nf_reset_ct(skb); 58 nf_ct_set(skb, NULL, IP_CT_UNTRACKED); 59 #endif 60 if (hooknum == NF_INET_PRE_ROUTING || 61 hooknum == NF_INET_LOCAL_IN) { 62 struct ipv6hdr *iph = ipv6_hdr(skb); 63 --iph->hop_limit; 64 } 65 if (nf_dup_ipv6_route(net, skb, gw, oif)) { 66 __this_cpu_write(nf_skb_duplicated, true); 67 ip6_local_out(net, skb->sk, skb); 68 __this_cpu_write(nf_skb_duplicated, false); 69 } else { 70 kfree_skb(skb); 71 } 72 } 73 EXPORT_SYMBOL_GPL(nf_dup_ipv6); 74 75 MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>"); 76 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 77 MODULE_DESCRIPTION("nf_dup_ipv6: IPv6 packet duplication"); 78 MODULE_LICENSE("GPL"); 79