1 /* 2 * (C) 2007 by Sebastian Claßen <sebastian.classen@freenet.ag> 3 * (C) 2007-2010 by Jan Engelhardt <jengelh@medozas.de> 4 * 5 * Extracted from xt_TEE.c 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 or later, as 9 * published by the Free Software Foundation. 10 */ 11 #include <linux/module.h> 12 #include <linux/percpu.h> 13 #include <linux/skbuff.h> 14 #include <linux/netfilter.h> 15 #include <net/ipv6.h> 16 #include <net/ip6_route.h> 17 #include <net/netfilter/ipv6/nf_dup_ipv6.h> 18 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 19 #include <net/netfilter/nf_conntrack.h> 20 #endif 21 22 static bool nf_dup_ipv6_route(struct net *net, struct sk_buff *skb, 23 const struct in6_addr *gw, int oif) 24 { 25 const struct ipv6hdr *iph = ipv6_hdr(skb); 26 struct dst_entry *dst; 27 struct flowi6 fl6; 28 29 memset(&fl6, 0, sizeof(fl6)); 30 if (oif != -1) 31 fl6.flowi6_oif = oif; 32 33 fl6.daddr = *gw; 34 fl6.flowlabel = (__force __be32)(((iph->flow_lbl[0] & 0xF) << 16) | 35 (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]); 36 fl6.flowi6_flags = FLOWI_FLAG_KNOWN_NH; 37 dst = ip6_route_output(net, NULL, &fl6); 38 if (dst->error) { 39 dst_release(dst); 40 return false; 41 } 42 skb_dst_drop(skb); 43 skb_dst_set(skb, dst); 44 skb->dev = dst->dev; 45 skb->protocol = htons(ETH_P_IPV6); 46 47 return true; 48 } 49 50 void nf_dup_ipv6(struct net *net, struct sk_buff *skb, unsigned int hooknum, 51 const struct in6_addr *gw, int oif) 52 { 53 if (this_cpu_read(nf_skb_duplicated)) 54 return; 55 skb = pskb_copy(skb, GFP_ATOMIC); 56 if (skb == NULL) 57 return; 58 59 #if IS_ENABLED(CONFIG_NF_CONNTRACK) 60 nf_reset(skb); 61 nf_ct_set(skb, NULL, IP_CT_UNTRACKED); 62 #endif 63 if (hooknum == NF_INET_PRE_ROUTING || 64 hooknum == NF_INET_LOCAL_IN) { 65 struct ipv6hdr *iph = ipv6_hdr(skb); 66 --iph->hop_limit; 67 } 68 if (nf_dup_ipv6_route(net, skb, gw, oif)) { 69 __this_cpu_write(nf_skb_duplicated, true); 70 ip6_local_out(net, skb->sk, skb); 71 __this_cpu_write(nf_skb_duplicated, false); 72 } else { 73 kfree_skb(skb); 74 } 75 } 76 EXPORT_SYMBOL_GPL(nf_dup_ipv6); 77 78 MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>"); 79 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 80 MODULE_DESCRIPTION("nf_dup_ipv6: IPv6 packet duplication"); 81 MODULE_LICENSE("GPL"); 82
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.