2 * "TEE" target extension for Xtables
3 * Copyright © Sebastian Claßen, 2007
4 * Jan Engelhardt, 2007-2010
6 * based on ipt_ROUTE.c from Cédric de Launois
7 * <delaunois@info.ucl.be>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 or later, as published by the Free Software Foundation.
14 #include <linux/module.h>
15 #include <linux/percpu.h>
16 #include <linux/route.h>
17 #include <linux/skbuff.h>
18 #include <linux/notifier.h>
19 #include <net/checksum.h>
23 #include <net/ip6_route.h>
24 #include <net/route.h>
25 #include <linux/netfilter/x_tables.h>
26 #include <linux/netfilter/xt_TEE.h>
28 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
29 # define WITH_CONNTRACK 1
30 # include <net/netfilter/nf_conntrack.h>
34 struct notifier_block notifier
;
35 struct xt_tee_tginfo
*tginfo
;
39 static const union nf_inet_addr tee_zero_address
;
41 static struct net
*pick_net(struct sk_buff
*skb
)
44 const struct dst_entry
*dst
;
47 return dev_net(skb
->dev
);
49 if (dst
!= NULL
&& dst
->dev
!= NULL
)
50 return dev_net(dst
->dev
);
56 tee_tg_route4(struct sk_buff
*skb
, const struct xt_tee_tginfo
*info
)
58 const struct iphdr
*iph
= ip_hdr(skb
);
59 struct net
*net
= pick_net(skb
);
63 memset(&fl4
, 0, sizeof(fl4
));
65 if (info
->priv
->oif
== -1)
67 fl4
.flowi4_oif
= info
->priv
->oif
;
69 fl4
.daddr
= info
->gw
.ip
;
70 fl4
.flowi4_tos
= RT_TOS(iph
->tos
);
71 fl4
.flowi4_scope
= RT_SCOPE_UNIVERSE
;
72 fl4
.flowi4_flags
= FLOWI_FLAG_KNOWN_NH
;
73 rt
= ip_route_output_key(net
, &fl4
);
78 skb_dst_set(skb
, &rt
->dst
);
79 skb
->dev
= rt
->dst
.dev
;
80 skb
->protocol
= htons(ETH_P_IP
);
85 tee_tg4(struct sk_buff
*skb
, const struct xt_action_param
*par
)
87 const struct xt_tee_tginfo
*info
= par
->targinfo
;
90 if (__this_cpu_read(nf_skb_duplicated
))
93 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
94 * the original skb, which should continue on its way as if nothing has
95 * happened. The copy should be independently delivered to the TEE
98 skb
= pskb_copy(skb
, GFP_ATOMIC
);
102 #ifdef WITH_CONNTRACK
103 /* Avoid counting cloned packets towards the original connection. */
104 nf_conntrack_put(skb
->nfct
);
105 skb
->nfct
= &nf_ct_untracked_get()->ct_general
;
106 skb
->nfctinfo
= IP_CT_NEW
;
107 nf_conntrack_get(skb
->nfct
);
110 * If we are in PREROUTING/INPUT, the checksum must be recalculated
111 * since the length could have changed as a result of defragmentation.
113 * We also decrease the TTL to mitigate potential TEE loops
116 * Set %IP_DF so that the original source is notified of a potentially
117 * decreased MTU on the clone route. IPv6 does this too.
120 iph
->frag_off
|= htons(IP_DF
);
121 if (par
->hooknum
== NF_INET_PRE_ROUTING
||
122 par
->hooknum
== NF_INET_LOCAL_IN
)
126 if (tee_tg_route4(skb
, info
)) {
127 __this_cpu_write(nf_skb_duplicated
, true);
129 __this_cpu_write(nf_skb_duplicated
, false);
136 #if IS_ENABLED(CONFIG_IPV6)
138 tee_tg_route6(struct sk_buff
*skb
, const struct xt_tee_tginfo
*info
)
140 const struct ipv6hdr
*iph
= ipv6_hdr(skb
);
141 struct net
*net
= pick_net(skb
);
142 struct dst_entry
*dst
;
145 memset(&fl6
, 0, sizeof(fl6
));
147 if (info
->priv
->oif
== -1)
149 fl6
.flowi6_oif
= info
->priv
->oif
;
151 fl6
.daddr
= info
->gw
.in6
;
152 fl6
.flowlabel
= ((iph
->flow_lbl
[0] & 0xF) << 16) |
153 (iph
->flow_lbl
[1] << 8) | iph
->flow_lbl
[2];
154 fl6
.flowi6_flags
= FLOWI_FLAG_KNOWN_NH
;
155 dst
= ip6_route_output(net
, NULL
, &fl6
);
161 skb_dst_set(skb
, dst
);
163 skb
->protocol
= htons(ETH_P_IPV6
);
168 tee_tg6(struct sk_buff
*skb
, const struct xt_action_param
*par
)
170 const struct xt_tee_tginfo
*info
= par
->targinfo
;
172 if (__this_cpu_read(nf_skb_duplicated
))
174 skb
= pskb_copy(skb
, GFP_ATOMIC
);
178 #ifdef WITH_CONNTRACK
179 nf_conntrack_put(skb
->nfct
);
180 skb
->nfct
= &nf_ct_untracked_get()->ct_general
;
181 skb
->nfctinfo
= IP_CT_NEW
;
182 nf_conntrack_get(skb
->nfct
);
184 if (par
->hooknum
== NF_INET_PRE_ROUTING
||
185 par
->hooknum
== NF_INET_LOCAL_IN
) {
186 struct ipv6hdr
*iph
= ipv6_hdr(skb
);
189 if (tee_tg_route6(skb
, info
)) {
190 __this_cpu_write(nf_skb_duplicated
, true);
192 __this_cpu_write(nf_skb_duplicated
, false);
200 static int tee_netdev_event(struct notifier_block
*this, unsigned long event
,
203 struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
204 struct xt_tee_priv
*priv
;
206 priv
= container_of(this, struct xt_tee_priv
, notifier
);
208 case NETDEV_REGISTER
:
209 if (!strcmp(dev
->name
, priv
->tginfo
->oif
))
210 priv
->oif
= dev
->ifindex
;
212 case NETDEV_UNREGISTER
:
213 if (dev
->ifindex
== priv
->oif
)
216 case NETDEV_CHANGENAME
:
217 if (!strcmp(dev
->name
, priv
->tginfo
->oif
))
218 priv
->oif
= dev
->ifindex
;
219 else if (dev
->ifindex
== priv
->oif
)
227 static int tee_tg_check(const struct xt_tgchk_param
*par
)
229 struct xt_tee_tginfo
*info
= par
->targinfo
;
230 struct xt_tee_priv
*priv
;
232 /* 0.0.0.0 and :: not allowed */
233 if (memcmp(&info
->gw
, &tee_zero_address
,
234 sizeof(tee_zero_address
)) == 0)
238 if (info
->oif
[sizeof(info
->oif
)-1] != '\0')
241 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
247 priv
->notifier
.notifier_call
= tee_netdev_event
;
250 register_netdevice_notifier(&priv
->notifier
);
254 static_key_slow_inc(&xt_tee_enabled
);
258 static void tee_tg_destroy(const struct xt_tgdtor_param
*par
)
260 struct xt_tee_tginfo
*info
= par
->targinfo
;
263 unregister_netdevice_notifier(&info
->priv
->notifier
);
266 static_key_slow_dec(&xt_tee_enabled
);
269 static struct xt_target tee_tg_reg
[] __read_mostly
= {
273 .family
= NFPROTO_IPV4
,
275 .targetsize
= sizeof(struct xt_tee_tginfo
),
276 .checkentry
= tee_tg_check
,
277 .destroy
= tee_tg_destroy
,
280 #if IS_ENABLED(CONFIG_IPV6)
284 .family
= NFPROTO_IPV6
,
286 .targetsize
= sizeof(struct xt_tee_tginfo
),
287 .checkentry
= tee_tg_check
,
288 .destroy
= tee_tg_destroy
,
294 static int __init
tee_tg_init(void)
296 return xt_register_targets(tee_tg_reg
, ARRAY_SIZE(tee_tg_reg
));
299 static void __exit
tee_tg_exit(void)
301 xt_unregister_targets(tee_tg_reg
, ARRAY_SIZE(tee_tg_reg
));
304 module_init(tee_tg_init
);
305 module_exit(tee_tg_exit
);
306 MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
307 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
308 MODULE_DESCRIPTION("Xtables: Reroute packet copy");
309 MODULE_LICENSE("GPL");
310 MODULE_ALIAS("ipt_TEE");
311 MODULE_ALIAS("ip6t_TEE");