xref: /openbmc/linux/net/netfilter/xt_TEE.c (revision b85d4594)
1 /*
2  *	"TEE" target extension for Xtables
3  *	Copyright © Sebastian Claßen, 2007
4  *	Jan Engelhardt, 2007-2010
5  *
6  *	based on ipt_ROUTE.c from Cédric de Launois
7  *	<delaunois@info.ucl.be>
8  *
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.
12  */
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
15 #include <linux/route.h>
16 #include <linux/netfilter/x_tables.h>
17 #include <net/route.h>
18 #include <net/netfilter/ipv4/nf_dup_ipv4.h>
19 #include <net/netfilter/ipv6/nf_dup_ipv6.h>
20 #include <linux/netfilter/xt_TEE.h>
21 
22 struct xt_tee_priv {
23 	struct notifier_block	notifier;
24 	struct xt_tee_tginfo	*tginfo;
25 	int			oif;
26 };
27 
28 static const union nf_inet_addr tee_zero_address;
29 
30 static unsigned int
31 tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
32 {
33 	const struct xt_tee_tginfo *info = par->targinfo;
34 
35 	nf_dup_ipv4(skb, par->hooknum, &info->gw.in, info->priv->oif);
36 
37 	return XT_CONTINUE;
38 }
39 
40 #if IS_ENABLED(CONFIG_NF_DUP_IPV6)
41 static unsigned int
42 tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
43 {
44 	const struct xt_tee_tginfo *info = par->targinfo;
45 
46 	nf_dup_ipv6(skb, par->hooknum, &info->gw.in6, info->priv->oif);
47 
48 	return XT_CONTINUE;
49 }
50 #endif
51 
52 static int tee_netdev_event(struct notifier_block *this, unsigned long event,
53 			    void *ptr)
54 {
55 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
56 	struct xt_tee_priv *priv;
57 
58 	priv = container_of(this, struct xt_tee_priv, notifier);
59 	switch (event) {
60 	case NETDEV_REGISTER:
61 		if (!strcmp(dev->name, priv->tginfo->oif))
62 			priv->oif = dev->ifindex;
63 		break;
64 	case NETDEV_UNREGISTER:
65 		if (dev->ifindex == priv->oif)
66 			priv->oif = -1;
67 		break;
68 	case NETDEV_CHANGENAME:
69 		if (!strcmp(dev->name, priv->tginfo->oif))
70 			priv->oif = dev->ifindex;
71 		else if (dev->ifindex == priv->oif)
72 			priv->oif = -1;
73 		break;
74 	}
75 
76 	return NOTIFY_DONE;
77 }
78 
79 static int tee_tg_check(const struct xt_tgchk_param *par)
80 {
81 	struct xt_tee_tginfo *info = par->targinfo;
82 	struct xt_tee_priv *priv;
83 
84 	/* 0.0.0.0 and :: not allowed */
85 	if (memcmp(&info->gw, &tee_zero_address,
86 		   sizeof(tee_zero_address)) == 0)
87 		return -EINVAL;
88 
89 	if (info->oif[0]) {
90 		if (info->oif[sizeof(info->oif)-1] != '\0')
91 			return -EINVAL;
92 
93 		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
94 		if (priv == NULL)
95 			return -ENOMEM;
96 
97 		priv->tginfo  = info;
98 		priv->oif     = -1;
99 		priv->notifier.notifier_call = tee_netdev_event;
100 		info->priv    = priv;
101 
102 		register_netdevice_notifier(&priv->notifier);
103 	} else
104 		info->priv = NULL;
105 
106 	static_key_slow_inc(&xt_tee_enabled);
107 	return 0;
108 }
109 
110 static void tee_tg_destroy(const struct xt_tgdtor_param *par)
111 {
112 	struct xt_tee_tginfo *info = par->targinfo;
113 
114 	if (info->priv) {
115 		unregister_netdevice_notifier(&info->priv->notifier);
116 		kfree(info->priv);
117 	}
118 	static_key_slow_dec(&xt_tee_enabled);
119 }
120 
121 static struct xt_target tee_tg_reg[] __read_mostly = {
122 	{
123 		.name       = "TEE",
124 		.revision   = 1,
125 		.family     = NFPROTO_IPV4,
126 		.target     = tee_tg4,
127 		.targetsize = sizeof(struct xt_tee_tginfo),
128 		.checkentry = tee_tg_check,
129 		.destroy    = tee_tg_destroy,
130 		.me         = THIS_MODULE,
131 	},
132 #if IS_ENABLED(CONFIG_NF_DUP_IPV6)
133 	{
134 		.name       = "TEE",
135 		.revision   = 1,
136 		.family     = NFPROTO_IPV6,
137 		.target     = tee_tg6,
138 		.targetsize = sizeof(struct xt_tee_tginfo),
139 		.checkentry = tee_tg_check,
140 		.destroy    = tee_tg_destroy,
141 		.me         = THIS_MODULE,
142 	},
143 #endif
144 };
145 
146 static int __init tee_tg_init(void)
147 {
148 	return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
149 }
150 
151 static void __exit tee_tg_exit(void)
152 {
153 	xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
154 }
155 
156 module_init(tee_tg_init);
157 module_exit(tee_tg_exit);
158 MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
159 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
160 MODULE_DESCRIPTION("Xtables: Reroute packet copy");
161 MODULE_LICENSE("GPL");
162 MODULE_ALIAS("ipt_TEE");
163 MODULE_ALIAS("ip6t_TEE");
164