]>
Commit | Line | Data |
---|---|---|
bbde9fc1 PNA |
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> | |
a82b0e63 | 14 | #include <linux/netfilter.h> |
bbde9fc1 PNA |
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 | ||
206e8c00 EB |
22 | static bool nf_dup_ipv6_route(struct net *net, struct sk_buff *skb, |
23 | const struct in6_addr *gw, int oif) | |
bbde9fc1 PNA |
24 | { |
25 | const struct ipv6hdr *iph = ipv6_hdr(skb); | |
bbde9fc1 PNA |
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; | |
59e26423 PNA |
34 | fl6.flowlabel = (__force __be32)(((iph->flow_lbl[0] & 0xF) << 16) | |
35 | (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]); | |
83170f3b | 36 | fl6.flowi6_flags = FLOWI_FLAG_KNOWN_NH; |
bbde9fc1 PNA |
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 | ||
206e8c00 | 50 | void nf_dup_ipv6(struct net *net, struct sk_buff *skb, unsigned int hooknum, |
bbde9fc1 PNA |
51 | const struct in6_addr *gw, int oif) |
52 | { | |
d877f071 | 53 | if (this_cpu_read(nf_skb_duplicated)) |
bbde9fc1 PNA |
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_conntrack_put(skb->nfct); | |
61 | skb->nfct = &nf_ct_untracked_get()->ct_general; | |
62 | skb->nfctinfo = IP_CT_NEW; | |
63 | nf_conntrack_get(skb->nfct); | |
64 | #endif | |
65 | if (hooknum == NF_INET_PRE_ROUTING || | |
66 | hooknum == NF_INET_LOCAL_IN) { | |
67 | struct ipv6hdr *iph = ipv6_hdr(skb); | |
68 | --iph->hop_limit; | |
69 | } | |
206e8c00 | 70 | if (nf_dup_ipv6_route(net, skb, gw, oif)) { |
bbde9fc1 | 71 | __this_cpu_write(nf_skb_duplicated, true); |
33224b16 | 72 | ip6_local_out(net, skb->sk, skb); |
bbde9fc1 PNA |
73 | __this_cpu_write(nf_skb_duplicated, false); |
74 | } else { | |
75 | kfree_skb(skb); | |
76 | } | |
77 | } | |
78 | EXPORT_SYMBOL_GPL(nf_dup_ipv6); | |
79 | ||
80 | MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>"); | |
81 | MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); | |
82 | MODULE_DESCRIPTION("nf_dup_ipv6: IPv6 packet duplication"); | |
83 | MODULE_LICENSE("GPL"); |