linux/net/netfilter/xt_conntrack.c
<<
>>
Prefs
   1/* Kernel module to match connection tracking information.
   2 * Superset of Rusty's minimalistic state match.
   3 *
   4 * (C) 2001  Marc Boucher (marc@mbsi.ca).
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/skbuff.h>
  13#include <linux/netfilter/x_tables.h>
  14#include <linux/netfilter/xt_conntrack.h>
  15#include <net/netfilter/nf_conntrack.h>
  16
  17MODULE_LICENSE("GPL");
  18MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
  19MODULE_DESCRIPTION("iptables connection tracking match module");
  20MODULE_ALIAS("ipt_conntrack");
  21
  22static bool
  23match(const struct sk_buff *skb,
  24      const struct net_device *in,
  25      const struct net_device *out,
  26      const struct xt_match *match,
  27      const void *matchinfo,
  28      int offset,
  29      unsigned int protoff,
  30      bool *hotdrop)
  31{
  32        const struct xt_conntrack_info *sinfo = matchinfo;
  33        const struct nf_conn *ct;
  34        enum ip_conntrack_info ctinfo;
  35        unsigned int statebit;
  36
  37        ct = nf_ct_get(skb, &ctinfo);
  38
  39#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
  40
  41        if (ct == &nf_conntrack_untracked)
  42                statebit = XT_CONNTRACK_STATE_UNTRACKED;
  43        else if (ct)
  44                statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  45        else
  46                statebit = XT_CONNTRACK_STATE_INVALID;
  47
  48        if (sinfo->flags & XT_CONNTRACK_STATE) {
  49                if (ct) {
  50                        if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
  51                                statebit |= XT_CONNTRACK_STATE_SNAT;
  52                        if (test_bit(IPS_DST_NAT_BIT, &ct->status))
  53                                statebit |= XT_CONNTRACK_STATE_DNAT;
  54                }
  55                if (FWINV((statebit & sinfo->statemask) == 0,
  56                          XT_CONNTRACK_STATE))
  57                        return false;
  58        }
  59
  60        if (ct == NULL) {
  61                if (sinfo->flags & ~XT_CONNTRACK_STATE)
  62                        return false;
  63                return true;
  64        }
  65
  66        if (sinfo->flags & XT_CONNTRACK_PROTO &&
  67            FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum !=
  68                  sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
  69                  XT_CONNTRACK_PROTO))
  70                return false;
  71
  72        if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
  73            FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip &
  74                   sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
  75                  sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
  76                  XT_CONNTRACK_ORIGSRC))
  77                return false;
  78
  79        if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
  80            FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip &
  81                   sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
  82                  sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
  83                  XT_CONNTRACK_ORIGDST))
  84                return false;
  85
  86        if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
  87            FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip &
  88                   sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
  89                  sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
  90                  XT_CONNTRACK_REPLSRC))
  91                return false;
  92
  93        if (sinfo->flags & XT_CONNTRACK_REPLDST &&
  94            FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip &
  95                   sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
  96                  sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
  97                  XT_CONNTRACK_REPLDST))
  98                return false;
  99
 100        if (sinfo->flags & XT_CONNTRACK_STATUS &&
 101            FWINV((ct->status & sinfo->statusmask) == 0,
 102                  XT_CONNTRACK_STATUS))
 103                return false;
 104
 105        if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
 106                unsigned long expires = timer_pending(&ct->timeout) ?
 107                                        (ct->timeout.expires - jiffies)/HZ : 0;
 108
 109                if (FWINV(!(expires >= sinfo->expires_min &&
 110                            expires <= sinfo->expires_max),
 111                          XT_CONNTRACK_EXPIRES))
 112                        return false;
 113        }
 114        return true;
 115}
 116
 117static bool
 118checkentry(const char *tablename,
 119           const void *ip,
 120           const struct xt_match *match,
 121           void *matchinfo,
 122           unsigned int hook_mask)
 123{
 124        if (nf_ct_l3proto_try_module_get(match->family) < 0) {
 125                printk(KERN_WARNING "can't load conntrack support for "
 126                                    "proto=%d\n", match->family);
 127                return false;
 128        }
 129        return true;
 130}
 131
 132static void destroy(const struct xt_match *match, void *matchinfo)
 133{
 134        nf_ct_l3proto_module_put(match->family);
 135}
 136
 137#ifdef CONFIG_COMPAT
 138struct compat_xt_conntrack_info
 139{
 140        compat_uint_t                   statemask;
 141        compat_uint_t                   statusmask;
 142        struct ip_conntrack_old_tuple   tuple[IP_CT_DIR_MAX];
 143        struct in_addr                  sipmsk[IP_CT_DIR_MAX];
 144        struct in_addr                  dipmsk[IP_CT_DIR_MAX];
 145        compat_ulong_t                  expires_min;
 146        compat_ulong_t                  expires_max;
 147        u_int8_t                        flags;
 148        u_int8_t                        invflags;
 149};
 150
 151static void compat_from_user(void *dst, void *src)
 152{
 153        const struct compat_xt_conntrack_info *cm = src;
 154        struct xt_conntrack_info m = {
 155                .statemask      = cm->statemask,
 156                .statusmask     = cm->statusmask,
 157                .expires_min    = cm->expires_min,
 158                .expires_max    = cm->expires_max,
 159                .flags          = cm->flags,
 160                .invflags       = cm->invflags,
 161        };
 162        memcpy(m.tuple, cm->tuple, sizeof(m.tuple));
 163        memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk));
 164        memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk));
 165        memcpy(dst, &m, sizeof(m));
 166}
 167
 168static int compat_to_user(void __user *dst, void *src)
 169{
 170        const struct xt_conntrack_info *m = src;
 171        struct compat_xt_conntrack_info cm = {
 172                .statemask      = m->statemask,
 173                .statusmask     = m->statusmask,
 174                .expires_min    = m->expires_min,
 175                .expires_max    = m->expires_max,
 176                .flags          = m->flags,
 177                .invflags       = m->invflags,
 178        };
 179        memcpy(cm.tuple, m->tuple, sizeof(cm.tuple));
 180        memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk));
 181        memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk));
 182        return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
 183}
 184#endif
 185
 186static struct xt_match conntrack_match __read_mostly = {
 187        .name           = "conntrack",
 188        .match          = match,
 189        .checkentry     = checkentry,
 190        .destroy        = destroy,
 191        .matchsize      = sizeof(struct xt_conntrack_info),
 192#ifdef CONFIG_COMPAT
 193        .compatsize     = sizeof(struct compat_xt_conntrack_info),
 194        .compat_from_user = compat_from_user,
 195        .compat_to_user = compat_to_user,
 196#endif
 197        .family         = AF_INET,
 198        .me             = THIS_MODULE,
 199};
 200
 201static int __init xt_conntrack_init(void)
 202{
 203        return xt_register_match(&conntrack_match);
 204}
 205
 206static void __exit xt_conntrack_fini(void)
 207{
 208        xt_unregister_match(&conntrack_match);
 209}
 210
 211module_init(xt_conntrack_init);
 212module_exit(xt_conntrack_fini);
 213