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