xt_conntrack.c revision df54aae02210e1acf3a1d2ffac9b29003835710c
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 23conntrack_mt(const struct sk_buff *skb, const struct net_device *in, 24 const struct net_device *out, const struct xt_match *match, 25 const void *matchinfo, int offset, unsigned int protoff, 26 bool *hotdrop) 27{ 28 const struct xt_conntrack_info *sinfo = matchinfo; 29 const struct nf_conn *ct; 30 enum ip_conntrack_info ctinfo; 31 unsigned int statebit; 32 33 ct = nf_ct_get(skb, &ctinfo); 34 35#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) 36 37 if (ct == &nf_conntrack_untracked) 38 statebit = XT_CONNTRACK_STATE_UNTRACKED; 39 else if (ct) 40 statebit = XT_CONNTRACK_STATE_BIT(ctinfo); 41 else 42 statebit = XT_CONNTRACK_STATE_INVALID; 43 44 if (sinfo->flags & XT_CONNTRACK_STATE) { 45 if (ct) { 46 if (test_bit(IPS_SRC_NAT_BIT, &ct->status)) 47 statebit |= XT_CONNTRACK_STATE_SNAT; 48 if (test_bit(IPS_DST_NAT_BIT, &ct->status)) 49 statebit |= XT_CONNTRACK_STATE_DNAT; 50 } 51 if (FWINV((statebit & sinfo->statemask) == 0, 52 XT_CONNTRACK_STATE)) 53 return false; 54 } 55 56 if (ct == NULL) { 57 if (sinfo->flags & ~XT_CONNTRACK_STATE) 58 return false; 59 return true; 60 } 61 62 if (sinfo->flags & XT_CONNTRACK_PROTO && 63 FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != 64 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, 65 XT_CONNTRACK_PROTO)) 66 return false; 67 68 if (sinfo->flags & XT_CONNTRACK_ORIGSRC && 69 FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip & 70 sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != 71 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, 72 XT_CONNTRACK_ORIGSRC)) 73 return false; 74 75 if (sinfo->flags & XT_CONNTRACK_ORIGDST && 76 FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip & 77 sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != 78 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, 79 XT_CONNTRACK_ORIGDST)) 80 return false; 81 82 if (sinfo->flags & XT_CONNTRACK_REPLSRC && 83 FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip & 84 sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != 85 sinfo->tuple[IP_CT_DIR_REPLY].src.ip, 86 XT_CONNTRACK_REPLSRC)) 87 return false; 88 89 if (sinfo->flags & XT_CONNTRACK_REPLDST && 90 FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip & 91 sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != 92 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, 93 XT_CONNTRACK_REPLDST)) 94 return false; 95 96 if (sinfo->flags & XT_CONNTRACK_STATUS && 97 FWINV((ct->status & sinfo->statusmask) == 0, 98 XT_CONNTRACK_STATUS)) 99 return false; 100 101 if(sinfo->flags & XT_CONNTRACK_EXPIRES) { 102 unsigned long expires = timer_pending(&ct->timeout) ? 103 (ct->timeout.expires - jiffies)/HZ : 0; 104 105 if (FWINV(!(expires >= sinfo->expires_min && 106 expires <= sinfo->expires_max), 107 XT_CONNTRACK_EXPIRES)) 108 return false; 109 } 110 return true; 111} 112 113static bool 114conntrack_mt_check(const char *tablename, const void *ip, 115 const struct xt_match *match, void *matchinfo, 116 unsigned int hook_mask) 117{ 118 if (nf_ct_l3proto_try_module_get(match->family) < 0) { 119 printk(KERN_WARNING "can't load conntrack support for " 120 "proto=%u\n", match->family); 121 return false; 122 } 123 return true; 124} 125 126static void 127conntrack_mt_destroy(const struct xt_match *match, void *matchinfo) 128{ 129 nf_ct_l3proto_module_put(match->family); 130} 131 132#ifdef CONFIG_COMPAT 133struct compat_xt_conntrack_info 134{ 135 compat_uint_t statemask; 136 compat_uint_t statusmask; 137 struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX]; 138 struct in_addr sipmsk[IP_CT_DIR_MAX]; 139 struct in_addr dipmsk[IP_CT_DIR_MAX]; 140 compat_ulong_t expires_min; 141 compat_ulong_t expires_max; 142 u_int8_t flags; 143 u_int8_t invflags; 144}; 145 146static void conntrack_mt_compat_from_user(void *dst, void *src) 147{ 148 const struct compat_xt_conntrack_info *cm = src; 149 struct xt_conntrack_info m = { 150 .statemask = cm->statemask, 151 .statusmask = cm->statusmask, 152 .expires_min = cm->expires_min, 153 .expires_max = cm->expires_max, 154 .flags = cm->flags, 155 .invflags = cm->invflags, 156 }; 157 memcpy(m.tuple, cm->tuple, sizeof(m.tuple)); 158 memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk)); 159 memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk)); 160 memcpy(dst, &m, sizeof(m)); 161} 162 163static int conntrack_mt_compat_to_user(void __user *dst, void *src) 164{ 165 const struct xt_conntrack_info *m = src; 166 struct compat_xt_conntrack_info cm = { 167 .statemask = m->statemask, 168 .statusmask = m->statusmask, 169 .expires_min = m->expires_min, 170 .expires_max = m->expires_max, 171 .flags = m->flags, 172 .invflags = m->invflags, 173 }; 174 memcpy(cm.tuple, m->tuple, sizeof(cm.tuple)); 175 memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk)); 176 memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk)); 177 return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; 178} 179#endif 180 181static struct xt_match conntrack_mt_reg __read_mostly = { 182 .name = "conntrack", 183 .match = conntrack_mt, 184 .checkentry = conntrack_mt_check, 185 .destroy = conntrack_mt_destroy, 186 .matchsize = sizeof(struct xt_conntrack_info), 187#ifdef CONFIG_COMPAT 188 .compatsize = sizeof(struct compat_xt_conntrack_info), 189 .compat_from_user = conntrack_mt_compat_from_user, 190 .compat_to_user = conntrack_mt_compat_to_user, 191#endif 192 .family = AF_INET, 193 .me = THIS_MODULE, 194}; 195 196static int __init conntrack_mt_init(void) 197{ 198 return xt_register_match(&conntrack_mt_reg); 199} 200 201static void __exit conntrack_mt_exit(void) 202{ 203 xt_unregister_match(&conntrack_mt_reg); 204} 205 206module_init(conntrack_mt_init); 207module_exit(conntrack_mt_exit); 208