linux/net/netfilter/xt_TEE.c
<<
>>
Prefs
   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");
 232