xt_TEE.c (5543B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * "TEE" target extension for Xtables 4 * Copyright © Sebastian Claßen, 2007 5 * Jan Engelhardt, 2007-2010 6 * 7 * based on ipt_ROUTE.c from Cédric de Launois 8 * <delaunois@info.ucl.be> 9 */ 10#include <linux/module.h> 11#include <linux/skbuff.h> 12#include <linux/route.h> 13#include <linux/netfilter/x_tables.h> 14#include <net/net_namespace.h> 15#include <net/netns/generic.h> 16#include <net/route.h> 17#include <net/netfilter/ipv4/nf_dup_ipv4.h> 18#include <net/netfilter/ipv6/nf_dup_ipv6.h> 19#include <linux/netfilter/xt_TEE.h> 20 21struct xt_tee_priv { 22 struct list_head list; 23 struct xt_tee_tginfo *tginfo; 24 int oif; 25}; 26 27static unsigned int tee_net_id __read_mostly; 28static const union nf_inet_addr tee_zero_address; 29 30struct tee_net { 31 struct list_head priv_list; 32 /* lock protects the priv_list */ 33 struct mutex lock; 34}; 35 36static unsigned int 37tee_tg4(struct sk_buff *skb, const struct xt_action_param *par) 38{ 39 const struct xt_tee_tginfo *info = par->targinfo; 40 int oif = info->priv ? info->priv->oif : 0; 41 42 nf_dup_ipv4(xt_net(par), skb, xt_hooknum(par), &info->gw.in, oif); 43 44 return XT_CONTINUE; 45} 46 47#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 48static unsigned int 49tee_tg6(struct sk_buff *skb, const struct xt_action_param *par) 50{ 51 const struct xt_tee_tginfo *info = par->targinfo; 52 int oif = info->priv ? info->priv->oif : 0; 53 54 nf_dup_ipv6(xt_net(par), skb, xt_hooknum(par), &info->gw.in6, oif); 55 56 return XT_CONTINUE; 57} 58#endif 59 60static int tee_netdev_event(struct notifier_block *this, unsigned long event, 61 void *ptr) 62{ 63 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 64 struct net *net = dev_net(dev); 65 struct tee_net *tn = net_generic(net, tee_net_id); 66 struct xt_tee_priv *priv; 67 68 mutex_lock(&tn->lock); 69 list_for_each_entry(priv, &tn->priv_list, list) { 70 switch (event) { 71 case NETDEV_REGISTER: 72 if (!strcmp(dev->name, priv->tginfo->oif)) 73 priv->oif = dev->ifindex; 74 break; 75 case NETDEV_UNREGISTER: 76 if (dev->ifindex == priv->oif) 77 priv->oif = -1; 78 break; 79 case NETDEV_CHANGENAME: 80 if (!strcmp(dev->name, priv->tginfo->oif)) 81 priv->oif = dev->ifindex; 82 else if (dev->ifindex == priv->oif) 83 priv->oif = -1; 84 break; 85 } 86 } 87 mutex_unlock(&tn->lock); 88 89 return NOTIFY_DONE; 90} 91 92static int tee_tg_check(const struct xt_tgchk_param *par) 93{ 94 struct tee_net *tn = net_generic(par->net, tee_net_id); 95 struct xt_tee_tginfo *info = par->targinfo; 96 struct xt_tee_priv *priv; 97 98 /* 0.0.0.0 and :: not allowed */ 99 if (memcmp(&info->gw, &tee_zero_address, 100 sizeof(tee_zero_address)) == 0) 101 return -EINVAL; 102 103 if (info->oif[0]) { 104 struct net_device *dev; 105 106 if (info->oif[sizeof(info->oif)-1] != '\0') 107 return -EINVAL; 108 109 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 110 if (priv == NULL) 111 return -ENOMEM; 112 113 priv->tginfo = info; 114 priv->oif = -1; 115 info->priv = priv; 116 117 dev = dev_get_by_name(par->net, info->oif); 118 if (dev) { 119 priv->oif = dev->ifindex; 120 dev_put(dev); 121 } 122 mutex_lock(&tn->lock); 123 list_add(&priv->list, &tn->priv_list); 124 mutex_unlock(&tn->lock); 125 } else 126 info->priv = NULL; 127 128 static_key_slow_inc(&xt_tee_enabled); 129 return 0; 130} 131 132static void tee_tg_destroy(const struct xt_tgdtor_param *par) 133{ 134 struct tee_net *tn = net_generic(par->net, tee_net_id); 135 struct xt_tee_tginfo *info = par->targinfo; 136 137 if (info->priv) { 138 mutex_lock(&tn->lock); 139 list_del(&info->priv->list); 140 mutex_unlock(&tn->lock); 141 kfree(info->priv); 142 } 143 static_key_slow_dec(&xt_tee_enabled); 144} 145 146static struct xt_target tee_tg_reg[] __read_mostly = { 147 { 148 .name = "TEE", 149 .revision = 1, 150 .family = NFPROTO_IPV4, 151 .target = tee_tg4, 152 .targetsize = sizeof(struct xt_tee_tginfo), 153 .usersize = offsetof(struct xt_tee_tginfo, priv), 154 .checkentry = tee_tg_check, 155 .destroy = tee_tg_destroy, 156 .me = THIS_MODULE, 157 }, 158#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 159 { 160 .name = "TEE", 161 .revision = 1, 162 .family = NFPROTO_IPV6, 163 .target = tee_tg6, 164 .targetsize = sizeof(struct xt_tee_tginfo), 165 .usersize = offsetof(struct xt_tee_tginfo, priv), 166 .checkentry = tee_tg_check, 167 .destroy = tee_tg_destroy, 168 .me = THIS_MODULE, 169 }, 170#endif 171}; 172 173static int __net_init tee_net_init(struct net *net) 174{ 175 struct tee_net *tn = net_generic(net, tee_net_id); 176 177 INIT_LIST_HEAD(&tn->priv_list); 178 mutex_init(&tn->lock); 179 return 0; 180} 181 182static struct pernet_operations tee_net_ops = { 183 .init = tee_net_init, 184 .id = &tee_net_id, 185 .size = sizeof(struct tee_net), 186}; 187 188static struct notifier_block tee_netdev_notifier = { 189 .notifier_call = tee_netdev_event, 190}; 191 192static int __init tee_tg_init(void) 193{ 194 int ret; 195 196 ret = register_pernet_subsys(&tee_net_ops); 197 if (ret < 0) 198 return ret; 199 200 ret = xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); 201 if (ret < 0) 202 goto cleanup_subsys; 203 204 ret = register_netdevice_notifier(&tee_netdev_notifier); 205 if (ret < 0) 206 goto unregister_targets; 207 208 return 0; 209 210unregister_targets: 211 xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); 212cleanup_subsys: 213 unregister_pernet_subsys(&tee_net_ops); 214 return ret; 215} 216 217static void __exit tee_tg_exit(void) 218{ 219 unregister_netdevice_notifier(&tee_netdev_notifier); 220 xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); 221 unregister_pernet_subsys(&tee_net_ops); 222} 223 224module_init(tee_tg_init); 225module_exit(tee_tg_exit); 226MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>"); 227MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 228MODULE_DESCRIPTION("Xtables: Reroute packet copy"); 229MODULE_LICENSE("GPL"); 230MODULE_ALIAS("ipt_TEE"); 231MODULE_ALIAS("ip6t_TEE");