linux/net/netfilter/xt_connmark.c
<<
>>
Prefs
   1/*
   2 *      xt_connmark - Netfilter module to operate on connection marks
   3 *
   4 *      Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
   5 *      by Henrik Nordstrom <hno@marasystems.com>
   6 *      Copyright © CC Computer Consultants GmbH, 2007 - 2008
   7 *      Jan Engelhardt <jengelh@medozas.de>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  21 */
  22
  23#include <linux/module.h>
  24#include <linux/skbuff.h>
  25#include <net/netfilter/nf_conntrack.h>
  26#include <net/netfilter/nf_conntrack_ecache.h>
  27#include <linux/netfilter/x_tables.h>
  28#include <linux/netfilter/xt_connmark.h>
  29
  30MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
  31MODULE_DESCRIPTION("Xtables: connection mark operations");
  32MODULE_LICENSE("GPL");
  33MODULE_ALIAS("ipt_CONNMARK");
  34MODULE_ALIAS("ip6t_CONNMARK");
  35MODULE_ALIAS("ipt_connmark");
  36MODULE_ALIAS("ip6t_connmark");
  37
  38static unsigned int
  39connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
  40{
  41        enum ip_conntrack_info ctinfo;
  42        u_int32_t new_targetmark;
  43        struct nf_conn *ct;
  44        u_int32_t newmark;
  45
  46        ct = nf_ct_get(skb, &ctinfo);
  47        if (ct == NULL)
  48                return XT_CONTINUE;
  49
  50        switch (info->mode) {
  51        case XT_CONNMARK_SET:
  52                newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
  53                if (info->shift_dir == D_SHIFT_RIGHT)
  54                        newmark >>= info->shift_bits;
  55                else
  56                        newmark <<= info->shift_bits;
  57
  58                if (ct->mark != newmark) {
  59                        ct->mark = newmark;
  60                        nf_conntrack_event_cache(IPCT_MARK, ct);
  61                }
  62                break;
  63        case XT_CONNMARK_SAVE:
  64                new_targetmark = (skb->mark & info->nfmask);
  65                if (info->shift_dir == D_SHIFT_RIGHT)
  66                        new_targetmark >>= info->shift_bits;
  67                else
  68                        new_targetmark <<= info->shift_bits;
  69
  70                newmark = (ct->mark & ~info->ctmask) ^
  71                          new_targetmark;
  72                if (ct->mark != newmark) {
  73                        ct->mark = newmark;
  74                        nf_conntrack_event_cache(IPCT_MARK, ct);
  75                }
  76                break;
  77        case XT_CONNMARK_RESTORE:
  78                new_targetmark = (ct->mark & info->ctmask);
  79                if (info->shift_dir == D_SHIFT_RIGHT)
  80                        new_targetmark >>= info->shift_bits;
  81                else
  82                        new_targetmark <<= info->shift_bits;
  83
  84                newmark = (skb->mark & ~info->nfmask) ^
  85                          new_targetmark;
  86                skb->mark = newmark;
  87                break;
  88        }
  89        return XT_CONTINUE;
  90}
  91
  92static unsigned int
  93connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
  94{
  95        const struct xt_connmark_tginfo1 *info = par->targinfo;
  96        const struct xt_connmark_tginfo2 info2 = {
  97                .ctmark = info->ctmark,
  98                .ctmask = info->ctmask,
  99                .nfmask = info->nfmask,
 100                .mode   = info->mode,
 101        };
 102
 103        return connmark_tg_shift(skb, &info2);
 104}
 105
 106static unsigned int
 107connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
 108{
 109        const struct xt_connmark_tginfo2 *info = par->targinfo;
 110
 111        return connmark_tg_shift(skb, info);
 112}
 113
 114static int connmark_tg_check(const struct xt_tgchk_param *par)
 115{
 116        int ret;
 117
 118        ret = nf_ct_netns_get(par->net, par->family);
 119        if (ret < 0)
 120                pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
 121                                    par->family);
 122        return ret;
 123}
 124
 125static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
 126{
 127        nf_ct_netns_put(par->net, par->family);
 128}
 129
 130static bool
 131connmark_mt(const struct sk_buff *skb, struct xt_action_param *par)
 132{
 133        const struct xt_connmark_mtinfo1 *info = par->matchinfo;
 134        enum ip_conntrack_info ctinfo;
 135        const struct nf_conn *ct;
 136
 137        ct = nf_ct_get(skb, &ctinfo);
 138        if (ct == NULL)
 139                return false;
 140
 141        return ((ct->mark & info->mask) == info->mark) ^ info->invert;
 142}
 143
 144static int connmark_mt_check(const struct xt_mtchk_param *par)
 145{
 146        int ret;
 147
 148        ret = nf_ct_netns_get(par->net, par->family);
 149        if (ret < 0)
 150                pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
 151                                    par->family);
 152        return ret;
 153}
 154
 155static void connmark_mt_destroy(const struct xt_mtdtor_param *par)
 156{
 157        nf_ct_netns_put(par->net, par->family);
 158}
 159
 160static struct xt_target connmark_tg_reg[] __read_mostly = {
 161        {
 162                .name           = "CONNMARK",
 163                .revision       = 1,
 164                .family         = NFPROTO_UNSPEC,
 165                .checkentry     = connmark_tg_check,
 166                .target         = connmark_tg,
 167                .targetsize     = sizeof(struct xt_connmark_tginfo1),
 168                .destroy        = connmark_tg_destroy,
 169                .me             = THIS_MODULE,
 170        },
 171        {
 172                .name           = "CONNMARK",
 173                .revision       = 2,
 174                .family         = NFPROTO_UNSPEC,
 175                .checkentry     = connmark_tg_check,
 176                .target         = connmark_tg_v2,
 177                .targetsize     = sizeof(struct xt_connmark_tginfo2),
 178                .destroy        = connmark_tg_destroy,
 179                .me             = THIS_MODULE,
 180        }
 181};
 182
 183static struct xt_match connmark_mt_reg __read_mostly = {
 184        .name           = "connmark",
 185        .revision       = 1,
 186        .family         = NFPROTO_UNSPEC,
 187        .checkentry     = connmark_mt_check,
 188        .match          = connmark_mt,
 189        .matchsize      = sizeof(struct xt_connmark_mtinfo1),
 190        .destroy        = connmark_mt_destroy,
 191        .me             = THIS_MODULE,
 192};
 193
 194static int __init connmark_mt_init(void)
 195{
 196        int ret;
 197
 198        ret = xt_register_targets(connmark_tg_reg,
 199                                  ARRAY_SIZE(connmark_tg_reg));
 200        if (ret < 0)
 201                return ret;
 202        ret = xt_register_match(&connmark_mt_reg);
 203        if (ret < 0) {
 204                xt_unregister_targets(connmark_tg_reg,
 205                                      ARRAY_SIZE(connmark_tg_reg));
 206                return ret;
 207        }
 208        return 0;
 209}
 210
 211static void __exit connmark_mt_exit(void)
 212{
 213        xt_unregister_match(&connmark_mt_reg);
 214        xt_unregister_target(connmark_tg_reg);
 215}
 216
 217module_init(connmark_mt_init);
 218module_exit(connmark_mt_exit);
 219