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 notifier_block   notifier;
  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(par->net, skb, par->hooknum, &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(par->net, skb, par->hooknum, &info->gw.in6, oif);
  49
  50        return XT_CONTINUE;
  51}
  52#endif
  53
  54static int tee_netdev_event(struct notifier_block *this, unsigned long event,
  55                            void *ptr)
  56{
  57        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  58        struct xt_tee_priv *priv;
  59
  60        priv = container_of(this, struct xt_tee_priv, notifier);
  61        switch (event) {
  62        case NETDEV_REGISTER:
  63                if (!strcmp(dev->name, priv->tginfo->oif))
  64                        priv->oif = dev->ifindex;
  65                break;
  66        case NETDEV_UNREGISTER:
  67                if (dev->ifindex == priv->oif)
  68                        priv->oif = -1;
  69                break;
  70        case NETDEV_CHANGENAME:
  71                if (!strcmp(dev->name, priv->tginfo->oif))
  72                        priv->oif = dev->ifindex;
  73                else if (dev->ifindex == priv->oif)
  74                        priv->oif = -1;
  75                break;
  76        }
  77
  78        return NOTIFY_DONE;
  79}
  80
  81static int tee_tg_check(const struct xt_tgchk_param *par)
  82{
  83        struct xt_tee_tginfo *info = par->targinfo;
  84        struct xt_tee_priv *priv;
  85
  86        /* 0.0.0.0 and :: not allowed */
  87        if (memcmp(&info->gw, &tee_zero_address,
  88                   sizeof(tee_zero_address)) == 0)
  89                return -EINVAL;
  90
  91        if (info->oif[0]) {
  92                if (info->oif[sizeof(info->oif)-1] != '\0')
  93                        return -EINVAL;
  94
  95                priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  96                if (priv == NULL)
  97                        return -ENOMEM;
  98
  99                priv->tginfo  = info;
 100                priv->oif     = -1;
 101                priv->notifier.notifier_call = tee_netdev_event;
 102                info->priv    = priv;
 103
 104                register_netdevice_notifier(&priv->notifier);
 105        } else
 106                info->priv = NULL;
 107
 108        static_key_slow_inc(&xt_tee_enabled);
 109        return 0;
 110}
 111
 112static void tee_tg_destroy(const struct xt_tgdtor_param *par)
 113{
 114        struct xt_tee_tginfo *info = par->targinfo;
 115
 116        if (info->priv) {
 117                unregister_netdevice_notifier(&info->priv->notifier);
 118                kfree(info->priv);
 119        }
 120        static_key_slow_dec(&xt_tee_enabled);
 121}
 122
 123static struct xt_target tee_tg_reg[] __read_mostly = {
 124        {
 125                .name       = "TEE",
 126                .revision   = 1,
 127                .family     = NFPROTO_IPV4,
 128                .target     = tee_tg4,
 129                .targetsize = sizeof(struct xt_tee_tginfo),
 130                .checkentry = tee_tg_check,
 131                .destroy    = tee_tg_destroy,
 132                .me         = THIS_MODULE,
 133        },
 134#if IS_ENABLED(CONFIG_IPV6)
 135        {
 136                .name       = "TEE",
 137                .revision   = 1,
 138                .family     = NFPROTO_IPV6,
 139                .target     = tee_tg6,
 140                .targetsize = sizeof(struct xt_tee_tginfo),
 141                .checkentry = tee_tg_check,
 142                .destroy    = tee_tg_destroy,
 143                .me         = THIS_MODULE,
 144        },
 145#endif
 146};
 147
 148static int __init tee_tg_init(void)
 149{
 150        return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
 151}
 152
 153static void __exit tee_tg_exit(void)
 154{
 155        xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
 156}
 157
 158module_init(tee_tg_init);
 159module_exit(tee_tg_exit);
 160MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
 161MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 162MODULE_DESCRIPTION("Xtables: Reroute packet copy");
 163MODULE_LICENSE("GPL");
 164MODULE_ALIAS("ipt_TEE");
 165MODULE_ALIAS("ip6t_TEE");
 166