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                int ret;
  93
  94                if (info->oif[sizeof(info->oif)-1] != '\0')
  95                        return -EINVAL;
  96
  97                priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  98                if (priv == NULL)
  99                        return -ENOMEM;
 100
 101                priv->tginfo  = info;
 102                priv->oif     = -1;
 103                priv->notifier.notifier_call = tee_netdev_event;
 104                info->priv    = priv;
 105
 106                ret = register_netdevice_notifier(&priv->notifier);
 107                if (ret) {
 108                        kfree(priv);
 109                        return ret;
 110                }
 111        } else
 112                info->priv = NULL;
 113
 114        static_key_slow_inc(&xt_tee_enabled);
 115        return 0;
 116}
 117
 118static void tee_tg_destroy(const struct xt_tgdtor_param *par)
 119{
 120        struct xt_tee_tginfo *info = par->targinfo;
 121
 122        if (info->priv) {
 123                unregister_netdevice_notifier(&info->priv->notifier);
 124                kfree(info->priv);
 125        }
 126        static_key_slow_dec(&xt_tee_enabled);
 127}
 128
 129static struct xt_target tee_tg_reg[] __read_mostly = {
 130        {
 131                .name       = "TEE",
 132                .revision   = 1,
 133                .family     = NFPROTO_IPV4,
 134                .target     = tee_tg4,
 135                .targetsize = sizeof(struct xt_tee_tginfo),
 136                .checkentry = tee_tg_check,
 137                .destroy    = tee_tg_destroy,
 138                .me         = THIS_MODULE,
 139        },
 140#if IS_ENABLED(CONFIG_IPV6)
 141        {
 142                .name       = "TEE",
 143                .revision   = 1,
 144                .family     = NFPROTO_IPV6,
 145                .target     = tee_tg6,
 146                .targetsize = sizeof(struct xt_tee_tginfo),
 147                .checkentry = tee_tg_check,
 148                .destroy    = tee_tg_destroy,
 149                .me         = THIS_MODULE,
 150        },
 151#endif
 152};
 153
 154static int __init tee_tg_init(void)
 155{
 156        return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
 157}
 158
 159static void __exit tee_tg_exit(void)
 160{
 161        xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
 162}
 163
 164module_init(tee_tg_init);
 165module_exit(tee_tg_exit);
 166MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
 167MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 168MODULE_DESCRIPTION("Xtables: Reroute packet copy");
 169MODULE_LICENSE("GPL");
 170MODULE_ALIAS("ipt_TEE");
 171MODULE_ALIAS("ip6t_TEE");
 172