linux/net/netfilter/xt_TEE.c
<<
>>
Prefs
   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
  22struct xt_tee_priv {
  23        struct list_head        list;
  24        struct xt_tee_tginfo    *tginfo;
  25        int                     oif;
  26};
  27
  28static const union nf_inet_addr tee_zero_address;
  29
  30static unsigned int
  31tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
  32{
  33        const struct xt_tee_tginfo *info = par->targinfo;
  34        int oif = info->priv ? info->priv->oif : 0;
  35
  36        nf_dup_ipv4(xt_net(par), skb, xt_hooknum(par), &info->gw.in, oif);
  37
  38        return XT_CONTINUE;
  39}
  40
  41#if IS_ENABLED(CONFIG_IPV6)
  42static unsigned int
  43tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
  44{
  45        const struct xt_tee_tginfo *info = par->targinfo;
  46        int oif = info->priv ? info->priv->oif : 0;
  47
  48        nf_dup_ipv6(xt_net(par), skb, xt_hooknum(par), &info->gw.in6, oif);
  49
  50        return XT_CONTINUE;
  51}
  52#endif
  53
  54static DEFINE_MUTEX(priv_list_mutex);
  55static LIST_HEAD(priv_list);
  56
  57static int tee_netdev_event(struct notifier_block *this, unsigned long event,
  58                            void *ptr)
  59{
  60        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  61        struct xt_tee_priv *priv;
  62
  63        mutex_lock(&priv_list_mutex);
  64        list_for_each_entry(priv, &priv_list, list) {
  65                switch (event) {
  66                case NETDEV_REGISTER:
  67                        if (!strcmp(dev->name, priv->tginfo->oif))
  68                                priv->oif = dev->ifindex;
  69                        break;
  70                case NETDEV_UNREGISTER:
  71                        if (dev->ifindex == priv->oif)
  72                                priv->oif = -1;
  73                        break;
  74                case NETDEV_CHANGENAME:
  75                        if (!strcmp(dev->name, priv->tginfo->oif))
  76                                priv->oif = dev->ifindex;
  77                        else if (dev->ifindex == priv->oif)
  78                                priv->oif = -1;
  79                        break;
  80                }
  81        }
  82        mutex_unlock(&priv_list_mutex);
  83
  84        return NOTIFY_DONE;
  85}
  86
  87static int tee_tg_check(const struct xt_tgchk_param *par)
  88{
  89        struct xt_tee_tginfo *info = par->targinfo;
  90        struct xt_tee_priv *priv;
  91
  92        /* 0.0.0.0 and :: not allowed */
  93        if (memcmp(&info->gw, &tee_zero_address,
  94                   sizeof(tee_zero_address)) == 0)
  95                return -EINVAL;
  96
  97        if (info->oif[0]) {
  98                if (info->oif[sizeof(info->oif)-1] != '\0')
  99                        return -EINVAL;
 100
 101                priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 102                if (priv == NULL)
 103                        return -ENOMEM;
 104
 105                priv->tginfo  = info;
 106                priv->oif     = -1;
 107                info->priv    = priv;
 108
 109                mutex_lock(&priv_list_mutex);
 110                list_add(&priv->list, &priv_list);
 111                mutex_unlock(&priv_list_mutex);
 112        } else
 113                info->priv = NULL;
 114
 115        static_key_slow_inc(&xt_tee_enabled);
 116        return 0;
 117}
 118
 119static void tee_tg_destroy(const struct xt_tgdtor_param *par)
 120{
 121        struct xt_tee_tginfo *info = par->targinfo;
 122
 123        if (info->priv) {
 124                mutex_lock(&priv_list_mutex);
 125                list_del(&info->priv->list);
 126                mutex_unlock(&priv_list_mutex);
 127                kfree(info->priv);
 128        }
 129        static_key_slow_dec(&xt_tee_enabled);
 130}
 131
 132static struct xt_target tee_tg_reg[] __read_mostly = {
 133        {
 134                .name       = "TEE",
 135                .revision   = 1,
 136                .family     = NFPROTO_IPV4,
 137                .target     = tee_tg4,
 138                .targetsize = sizeof(struct xt_tee_tginfo),
 139                .usersize   = offsetof(struct xt_tee_tginfo, priv),
 140                .checkentry = tee_tg_check,
 141                .destroy    = tee_tg_destroy,
 142                .me         = THIS_MODULE,
 143        },
 144#if IS_ENABLED(CONFIG_IPV6)
 145        {
 146                .name       = "TEE",
 147                .revision   = 1,
 148                .family     = NFPROTO_IPV6,
 149                .target     = tee_tg6,
 150                .targetsize = sizeof(struct xt_tee_tginfo),
 151                .usersize   = offsetof(struct xt_tee_tginfo, priv),
 152                .checkentry = tee_tg_check,
 153                .destroy    = tee_tg_destroy,
 154                .me         = THIS_MODULE,
 155        },
 156#endif
 157};
 158
 159static struct notifier_block tee_netdev_notifier = {
 160        .notifier_call = tee_netdev_event,
 161};
 162
 163static int __init tee_tg_init(void)
 164{
 165        int ret;
 166
 167        ret = xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
 168        if (ret)
 169                return ret;
 170        ret = register_netdevice_notifier(&tee_netdev_notifier);
 171        if (ret) {
 172                xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
 173                return ret;
 174        }
 175
 176        return 0;
 177}
 178
 179static void __exit tee_tg_exit(void)
 180{
 181        unregister_netdevice_notifier(&tee_netdev_notifier);
 182        xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
 183}
 184
 185module_init(tee_tg_init);
 186module_exit(tee_tg_exit);
 187MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
 188MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 189MODULE_DESCRIPTION("Xtables: Reroute packet copy");
 190MODULE_LICENSE("GPL");
 191MODULE_ALIAS("ipt_TEE");
 192MODULE_ALIAS("ip6t_TEE");
 193