linux/net/netfilter/xt_CONNMARK.c
<<
>>
Prefs
   1/* This kernel module is used to modify the connection mark values, or
   2 * to optionally restore the skb nfmark from the connection mark
   3 *
   4 * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
   5 * by Henrik Nordstrom <hno@marasystems.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20 */
  21#include <linux/module.h>
  22#include <linux/skbuff.h>
  23#include <linux/ip.h>
  24#include <net/checksum.h>
  25
  26MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
  27MODULE_DESCRIPTION("IP tables CONNMARK matching module");
  28MODULE_LICENSE("GPL");
  29MODULE_ALIAS("ipt_CONNMARK");
  30MODULE_ALIAS("ip6t_CONNMARK");
  31
  32#include <linux/netfilter/x_tables.h>
  33#include <linux/netfilter/xt_CONNMARK.h>
  34#include <net/netfilter/nf_conntrack_ecache.h>
  35
  36static unsigned int
  37target(struct sk_buff *skb,
  38       const struct net_device *in,
  39       const struct net_device *out,
  40       unsigned int hooknum,
  41       const struct xt_target *target,
  42       const void *targinfo)
  43{
  44        const struct xt_connmark_target_info *markinfo = targinfo;
  45        struct nf_conn *ct;
  46        enum ip_conntrack_info ctinfo;
  47        u_int32_t diff;
  48        u_int32_t mark;
  49        u_int32_t newmark;
  50
  51        ct = nf_ct_get(skb, &ctinfo);
  52        if (ct) {
  53                switch(markinfo->mode) {
  54                case XT_CONNMARK_SET:
  55                        newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
  56                        if (newmark != ct->mark) {
  57                                ct->mark = newmark;
  58                                nf_conntrack_event_cache(IPCT_MARK, skb);
  59                        }
  60                        break;
  61                case XT_CONNMARK_SAVE:
  62                        newmark = (ct->mark & ~markinfo->mask) |
  63                                  (skb->mark & markinfo->mask);
  64                        if (ct->mark != newmark) {
  65                                ct->mark = newmark;
  66                                nf_conntrack_event_cache(IPCT_MARK, skb);
  67                        }
  68                        break;
  69                case XT_CONNMARK_RESTORE:
  70                        mark = skb->mark;
  71                        diff = (ct->mark ^ mark) & markinfo->mask;
  72                        skb->mark = mark ^ diff;
  73                        break;
  74                }
  75        }
  76
  77        return XT_CONTINUE;
  78}
  79
  80static bool
  81checkentry(const char *tablename,
  82           const void *entry,
  83           const struct xt_target *target,
  84           void *targinfo,
  85           unsigned int hook_mask)
  86{
  87        const struct xt_connmark_target_info *matchinfo = targinfo;
  88
  89        if (matchinfo->mode == XT_CONNMARK_RESTORE) {
  90                if (strcmp(tablename, "mangle") != 0) {
  91                        printk(KERN_WARNING "CONNMARK: restore can only be "
  92                               "called from \"mangle\" table, not \"%s\"\n",
  93                               tablename);
  94                        return false;
  95                }
  96        }
  97        if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
  98                printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
  99                return false;
 100        }
 101        if (nf_ct_l3proto_try_module_get(target->family) < 0) {
 102                printk(KERN_WARNING "can't load conntrack support for "
 103                                    "proto=%d\n", target->family);
 104                return false;
 105        }
 106        return true;
 107}
 108
 109static void
 110destroy(const struct xt_target *target, void *targinfo)
 111{
 112        nf_ct_l3proto_module_put(target->family);
 113}
 114
 115#ifdef CONFIG_COMPAT
 116struct compat_xt_connmark_target_info {
 117        compat_ulong_t  mark, mask;
 118        u_int8_t        mode;
 119        u_int8_t        __pad1;
 120        u_int16_t       __pad2;
 121};
 122
 123static void compat_from_user(void *dst, void *src)
 124{
 125        const struct compat_xt_connmark_target_info *cm = src;
 126        struct xt_connmark_target_info m = {
 127                .mark   = cm->mark,
 128                .mask   = cm->mask,
 129                .mode   = cm->mode,
 130        };
 131        memcpy(dst, &m, sizeof(m));
 132}
 133
 134static int compat_to_user(void __user *dst, void *src)
 135{
 136        const struct xt_connmark_target_info *m = src;
 137        struct compat_xt_connmark_target_info cm = {
 138                .mark   = m->mark,
 139                .mask   = m->mask,
 140                .mode   = m->mode,
 141        };
 142        return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
 143}
 144#endif /* CONFIG_COMPAT */
 145
 146static struct xt_target xt_connmark_target[] __read_mostly = {
 147        {
 148                .name           = "CONNMARK",
 149                .family         = AF_INET,
 150                .checkentry     = checkentry,
 151                .destroy        = destroy,
 152                .target         = target,
 153                .targetsize     = sizeof(struct xt_connmark_target_info),
 154#ifdef CONFIG_COMPAT
 155                .compatsize     = sizeof(struct compat_xt_connmark_target_info),
 156                .compat_from_user = compat_from_user,
 157                .compat_to_user = compat_to_user,
 158#endif
 159                .me             = THIS_MODULE
 160        },
 161        {
 162                .name           = "CONNMARK",
 163                .family         = AF_INET6,
 164                .checkentry     = checkentry,
 165                .destroy        = destroy,
 166                .target         = target,
 167                .targetsize     = sizeof(struct xt_connmark_target_info),
 168                .me             = THIS_MODULE
 169        },
 170};
 171
 172static int __init xt_connmark_init(void)
 173{
 174        return xt_register_targets(xt_connmark_target,
 175                                   ARRAY_SIZE(xt_connmark_target));
 176}
 177
 178static void __exit xt_connmark_fini(void)
 179{
 180        xt_unregister_targets(xt_connmark_target,
 181                              ARRAY_SIZE(xt_connmark_target));
 182}
 183
 184module_init(xt_connmark_init);
 185module_exit(xt_connmark_fini);
 186