1e281b19897dc21c1071802808d461627d747a877Jan Engelhardt/*
2e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	"TEE" target extension for Xtables
3e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	Copyright © Sebastian Claßen, 2007
4e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	Jan Engelhardt, 2007-2010
5e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *
6e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	based on ipt_ROUTE.c from Cédric de Launois
7e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	<delaunois@info.ucl.be>
8e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *
9e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	This program is free software; you can redistribute it and/or
10e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	modify it under the terms of the GNU General Public License
11e281b19897dc21c1071802808d461627d747a877Jan Engelhardt *	version 2 or later, as published by the Free Software Foundation.
12e281b19897dc21c1071802808d461627d747a877Jan Engelhardt */
13e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <linux/ip.h>
14e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <linux/module.h>
15cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt#include <linux/percpu.h>
16e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <linux/route.h>
17e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <linux/skbuff.h>
1822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy#include <linux/notifier.h>
19e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <net/checksum.h>
20e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <net/icmp.h>
21e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <net/ip.h>
22e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <net/ipv6.h>
23e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <net/ip6_route.h>
24e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <net/route.h>
25e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <linux/netfilter/x_tables.h>
26e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#include <linux/netfilter/xt_TEE.h>
27e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
28c0cd115667bcd23c2a31fe2114beaab3608de68cIgor Maravić#if IS_ENABLED(CONFIG_NF_CONNTRACK)
29e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#	define WITH_CONNTRACK 1
30e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#	include <net/netfilter/nf_conntrack.h>
31e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#endif
32e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
3322265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardystruct xt_tee_priv {
3422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	struct notifier_block	notifier;
3522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	struct xt_tee_tginfo	*tginfo;
3622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	int			oif;
3722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy};
3822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
39e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic const union nf_inet_addr tee_zero_address;
40cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardtstatic DEFINE_PER_CPU(bool, tee_active);
41e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
42e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic struct net *pick_net(struct sk_buff *skb)
43e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
44e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#ifdef CONFIG_NET_NS
45e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	const struct dst_entry *dst;
46e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
47e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	if (skb->dev != NULL)
48e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		return dev_net(skb->dev);
49e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	dst = skb_dst(skb);
50e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	if (dst != NULL && dst->dev != NULL)
51e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		return dev_net(dst->dev);
52e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#endif
53e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	return &init_net;
54e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
55e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
56e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic bool
57e281b19897dc21c1071802808d461627d747a877Jan Engelhardttee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
58e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
59e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	const struct iphdr *iph = ip_hdr(skb);
60e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	struct net *net = pick_net(skb);
61e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	struct rtable *rt;
629d6ec938019c6b16cb9ec96598ebe8f20de435feDavid S. Miller	struct flowi4 fl4;
63e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
649d6ec938019c6b16cb9ec96598ebe8f20de435feDavid S. Miller	memset(&fl4, 0, sizeof(fl4));
6522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	if (info->priv) {
6622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		if (info->priv->oif == -1)
6722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			return false;
689d6ec938019c6b16cb9ec96598ebe8f20de435feDavid S. Miller		fl4.flowi4_oif = info->priv->oif;
6922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	}
709d6ec938019c6b16cb9ec96598ebe8f20de435feDavid S. Miller	fl4.daddr = info->gw.ip;
719d6ec938019c6b16cb9ec96598ebe8f20de435feDavid S. Miller	fl4.flowi4_tos = RT_TOS(iph->tos);
729d6ec938019c6b16cb9ec96598ebe8f20de435feDavid S. Miller	fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
732ad5b9e4bd314fc685086b99e90e5de3bc59e26bEric Dumazet	fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
749d6ec938019c6b16cb9ec96598ebe8f20de435feDavid S. Miller	rt = ip_route_output_key(net, &fl4);
75b23dd4fe42b455af5c6e20966b7d6959fa8352eaDavid S. Miller	if (IS_ERR(rt))
76e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		return false;
77e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
7850636af715ac1ceb1872bd29a4bdcc68975c3263Eric Dumazet	skb_dst_drop(skb);
79d8d1f30b95a635dbd610dcc5eb641aca8f4768cfChangli Gao	skb_dst_set(skb, &rt->dst);
80d8d1f30b95a635dbd610dcc5eb641aca8f4768cfChangli Gao	skb->dev      = rt->dst.dev;
81e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb->protocol = htons(ETH_P_IP);
82e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	return true;
83e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
84e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
85e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic unsigned int
864b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardttee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
87e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
88e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	const struct xt_tee_tginfo *info = par->targinfo;
89e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	struct iphdr *iph;
90e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
9119e8d69c543f8f62050099892b138e981db952ccAlex Shi	if (__this_cpu_read(tee_active))
92cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt		return XT_CONTINUE;
93e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	/*
94e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
95e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * the original skb, which should continue on its way as if nothing has
96e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * happened. The copy should be independently delivered to the TEE
97e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * --gateway.
98e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 */
99e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb = pskb_copy(skb, GFP_ATOMIC);
100e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	if (skb == NULL)
101e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		return XT_CONTINUE;
102e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
103e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#ifdef WITH_CONNTRACK
104e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	/* Avoid counting cloned packets towards the original connection. */
105e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	nf_conntrack_put(skb->nfct);
1065bfddbd46a95c978f4d3c992339cbdf4f4b790a3Eric Dumazet	skb->nfct     = &nf_ct_untracked_get()->ct_general;
107e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb->nfctinfo = IP_CT_NEW;
108e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	nf_conntrack_get(skb->nfct);
109e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#endif
110e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	/*
111e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * If we are in PREROUTING/INPUT, the checksum must be recalculated
112e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * since the length could have changed as a result of defragmentation.
113e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 *
114e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * We also decrease the TTL to mitigate potential TEE loops
115e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * between two hosts.
116e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 *
117e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * Set %IP_DF so that the original source is notified of a potentially
118e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 * decreased MTU on the clone route. IPv6 does this too.
119e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	 */
120e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	iph = ip_hdr(skb);
121e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	iph->frag_off |= htons(IP_DF);
122e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	if (par->hooknum == NF_INET_PRE_ROUTING ||
123e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	    par->hooknum == NF_INET_LOCAL_IN)
124e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		--iph->ttl;
125e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	ip_send_check(iph);
126e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
127cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt	if (tee_tg_route4(skb, info)) {
12819e8d69c543f8f62050099892b138e981db952ccAlex Shi		__this_cpu_write(tee_active, true);
129cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt		ip_local_out(skb);
13019e8d69c543f8f62050099892b138e981db952ccAlex Shi		__this_cpu_write(tee_active, false);
131cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt	} else {
132e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		kfree_skb(skb);
133cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt	}
134e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	return XT_CONTINUE;
135e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
136e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
137dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6)
138e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic bool
139e281b19897dc21c1071802808d461627d747a877Jan Engelhardttee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
140e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
141e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	const struct ipv6hdr *iph = ipv6_hdr(skb);
142e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	struct net *net = pick_net(skb);
143e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	struct dst_entry *dst;
1444c9483b2fb5d2548c3cc1fe03cdd4484ceeb5d1cDavid S. Miller	struct flowi6 fl6;
145e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
1464c9483b2fb5d2548c3cc1fe03cdd4484ceeb5d1cDavid S. Miller	memset(&fl6, 0, sizeof(fl6));
14722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	if (info->priv) {
14822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		if (info->priv->oif == -1)
14922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			return false;
1504c9483b2fb5d2548c3cc1fe03cdd4484ceeb5d1cDavid S. Miller		fl6.flowi6_oif = info->priv->oif;
15122265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	}
1524c9483b2fb5d2548c3cc1fe03cdd4484ceeb5d1cDavid S. Miller	fl6.daddr = info->gw.in6;
1534c9483b2fb5d2548c3cc1fe03cdd4484ceeb5d1cDavid S. Miller	fl6.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
1545811662b15db018c740c57d037523683fd3e6123Changli Gao			   (iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
1554c9483b2fb5d2548c3cc1fe03cdd4484ceeb5d1cDavid S. Miller	dst = ip6_route_output(net, NULL, &fl6);
1565d38b1f8cf8798d4df7809b3f3e38fad4d923e85RongQing.Li	if (dst->error) {
1575d38b1f8cf8798d4df7809b3f3e38fad4d923e85RongQing.Li		dst_release(dst);
158e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		return false;
1595d38b1f8cf8798d4df7809b3f3e38fad4d923e85RongQing.Li	}
16050636af715ac1ceb1872bd29a4bdcc68975c3263Eric Dumazet	skb_dst_drop(skb);
161e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb_dst_set(skb, dst);
162e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb->dev      = dst->dev;
163e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb->protocol = htons(ETH_P_IPV6);
164e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	return true;
165e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
166e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
167e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic unsigned int
1684b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardttee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
169e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
170e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	const struct xt_tee_tginfo *info = par->targinfo;
171e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
17219e8d69c543f8f62050099892b138e981db952ccAlex Shi	if (__this_cpu_read(tee_active))
173cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt		return XT_CONTINUE;
174e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb = pskb_copy(skb, GFP_ATOMIC);
175e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	if (skb == NULL)
176e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		return XT_CONTINUE;
177e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
178e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#ifdef WITH_CONNTRACK
179e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	nf_conntrack_put(skb->nfct);
1805bfddbd46a95c978f4d3c992339cbdf4f4b790a3Eric Dumazet	skb->nfct     = &nf_ct_untracked_get()->ct_general;
181e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	skb->nfctinfo = IP_CT_NEW;
182e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	nf_conntrack_get(skb->nfct);
183e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#endif
184e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	if (par->hooknum == NF_INET_PRE_ROUTING ||
185e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	    par->hooknum == NF_INET_LOCAL_IN) {
186e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		struct ipv6hdr *iph = ipv6_hdr(skb);
187e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		--iph->hop_limit;
188e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	}
189cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt	if (tee_tg_route6(skb, info)) {
19019e8d69c543f8f62050099892b138e981db952ccAlex Shi		__this_cpu_write(tee_active, true);
191cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt		ip6_local_out(skb);
19219e8d69c543f8f62050099892b138e981db952ccAlex Shi		__this_cpu_write(tee_active, false);
193cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt	} else {
194e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		kfree_skb(skb);
195cd58bcd9787ef4c16ab6e442c4f1bf3539b3ab39Jan Engelhardt	}
196e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	return XT_CONTINUE;
197e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
198dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#endif
199e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
20022265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardystatic int tee_netdev_event(struct notifier_block *this, unsigned long event,
20122265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			    void *ptr)
20222265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy{
203351638e7deeed2ec8ce451b53d33921b3da68f83Jiri Pirko	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
20422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	struct xt_tee_priv *priv;
20522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
20622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	priv = container_of(this, struct xt_tee_priv, notifier);
20722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	switch (event) {
20822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	case NETDEV_REGISTER:
20922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		if (!strcmp(dev->name, priv->tginfo->oif))
21022265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			priv->oif = dev->ifindex;
21122265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		break;
21222265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	case NETDEV_UNREGISTER:
21322265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		if (dev->ifindex == priv->oif)
21422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			priv->oif = -1;
21522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		break;
21622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	case NETDEV_CHANGENAME:
21722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		if (!strcmp(dev->name, priv->tginfo->oif))
21822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			priv->oif = dev->ifindex;
21922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		else if (dev->ifindex == priv->oif)
22022265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			priv->oif = -1;
22122265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		break;
22222265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	}
22322265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
22422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	return NOTIFY_DONE;
22522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy}
22622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
227e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic int tee_tg_check(const struct xt_tgchk_param *par)
228e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
22922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	struct xt_tee_tginfo *info = par->targinfo;
23022265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	struct xt_tee_priv *priv;
231e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
232e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	/* 0.0.0.0 and :: not allowed */
23322265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	if (memcmp(&info->gw, &tee_zero_address,
23422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		   sizeof(tee_zero_address)) == 0)
23522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		return -EINVAL;
23622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
23722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	if (info->oif[0]) {
23822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		if (info->oif[sizeof(info->oif)-1] != '\0')
23922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			return -EINVAL;
24022265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
24122265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
24222265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		if (priv == NULL)
24322265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy			return -ENOMEM;
24422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
24522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		priv->tginfo  = info;
24622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		priv->oif     = -1;
24722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		priv->notifier.notifier_call = tee_netdev_event;
24822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		info->priv    = priv;
24922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
25022265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		register_netdevice_notifier(&priv->notifier);
25122265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	} else
25222265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		info->priv = NULL;
25322265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
25422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	return 0;
25522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy}
25622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
25722265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardystatic void tee_tg_destroy(const struct xt_tgdtor_param *par)
25822265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy{
25922265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	struct xt_tee_tginfo *info = par->targinfo;
26022265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy
26122265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	if (info->priv) {
26222265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		unregister_netdevice_notifier(&info->priv->notifier);
26322265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		kfree(info->priv);
26422265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy	}
265e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
266e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
267e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic struct xt_target tee_tg_reg[] __read_mostly = {
268e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	{
269e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.name       = "TEE",
270e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.revision   = 1,
271e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.family     = NFPROTO_IPV4,
272e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.target     = tee_tg4,
273e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.targetsize = sizeof(struct xt_tee_tginfo),
274e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.checkentry = tee_tg_check,
27522265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		.destroy    = tee_tg_destroy,
276e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.me         = THIS_MODULE,
277e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	},
278dfd56b8b38fff3586f36232db58e1e9f7885a605Eric Dumazet#if IS_ENABLED(CONFIG_IPV6)
279e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	{
280e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.name       = "TEE",
281e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.revision   = 1,
282e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.family     = NFPROTO_IPV6,
283e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.target     = tee_tg6,
284e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.targetsize = sizeof(struct xt_tee_tginfo),
285e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.checkentry = tee_tg_check,
28622265a5c3c103cf8c50be62e6c90d045eb649e6dPatrick McHardy		.destroy    = tee_tg_destroy,
287e281b19897dc21c1071802808d461627d747a877Jan Engelhardt		.me         = THIS_MODULE,
288e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	},
289e281b19897dc21c1071802808d461627d747a877Jan Engelhardt#endif
290e281b19897dc21c1071802808d461627d747a877Jan Engelhardt};
291e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
292e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic int __init tee_tg_init(void)
293e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
294e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
295e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
296e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
297e281b19897dc21c1071802808d461627d747a877Jan Engelhardtstatic void __exit tee_tg_exit(void)
298e281b19897dc21c1071802808d461627d747a877Jan Engelhardt{
299e281b19897dc21c1071802808d461627d747a877Jan Engelhardt	xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
300e281b19897dc21c1071802808d461627d747a877Jan Engelhardt}
301e281b19897dc21c1071802808d461627d747a877Jan Engelhardt
302e281b19897dc21c1071802808d461627d747a877Jan Engelhardtmodule_init(tee_tg_init);
303e281b19897dc21c1071802808d461627d747a877Jan Engelhardtmodule_exit(tee_tg_exit);
304e281b19897dc21c1071802808d461627d747a877Jan EngelhardtMODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
305e281b19897dc21c1071802808d461627d747a877Jan EngelhardtMODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
306e281b19897dc21c1071802808d461627d747a877Jan EngelhardtMODULE_DESCRIPTION("Xtables: Reroute packet copy");
307e281b19897dc21c1071802808d461627d747a877Jan EngelhardtMODULE_LICENSE("GPL");
308e281b19897dc21c1071802808d461627d747a877Jan EngelhardtMODULE_ALIAS("ipt_TEE");
309e281b19897dc21c1071802808d461627d747a877Jan EngelhardtMODULE_ALIAS("ip6t_TEE");
310