xt_conntrack.c revision 5d04bff096180f032de8b9b12153a8a1b4009b8d
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 14#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) 15#include <linux/netfilter_ipv4/ip_conntrack.h> 16#include <linux/netfilter_ipv4/ip_conntrack_tuple.h> 17#else 18#include <net/netfilter/nf_conntrack.h> 19#endif 20 21#include <linux/netfilter/x_tables.h> 22#include <linux/netfilter/xt_conntrack.h> 23 24MODULE_LICENSE("GPL"); 25MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); 26MODULE_DESCRIPTION("iptables connection tracking match module"); 27MODULE_ALIAS("ipt_conntrack"); 28 29#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) 30 31static int 32match(const struct sk_buff *skb, 33 const struct net_device *in, 34 const struct net_device *out, 35 const void *matchinfo, 36 int offset, 37 unsigned int protoff, 38 int *hotdrop) 39{ 40 const struct xt_conntrack_info *sinfo = matchinfo; 41 struct ip_conntrack *ct; 42 enum ip_conntrack_info ctinfo; 43 unsigned int statebit; 44 45 ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); 46 47#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) 48 49 if (ct == &ip_conntrack_untracked) 50 statebit = XT_CONNTRACK_STATE_UNTRACKED; 51 else if (ct) 52 statebit = XT_CONNTRACK_STATE_BIT(ctinfo); 53 else 54 statebit = XT_CONNTRACK_STATE_INVALID; 55 56 if(sinfo->flags & XT_CONNTRACK_STATE) { 57 if (ct) { 58 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != 59 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) 60 statebit |= XT_CONNTRACK_STATE_SNAT; 61 62 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != 63 ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) 64 statebit |= XT_CONNTRACK_STATE_DNAT; 65 } 66 67 if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) 68 return 0; 69 } 70 71 if(sinfo->flags & XT_CONNTRACK_PROTO) { 72 if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) 73 return 0; 74 } 75 76 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { 77 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC)) 78 return 0; 79 } 80 81 if(sinfo->flags & XT_CONNTRACK_ORIGDST) { 82 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST)) 83 return 0; 84 } 85 86 if(sinfo->flags & XT_CONNTRACK_REPLSRC) { 87 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC)) 88 return 0; 89 } 90 91 if(sinfo->flags & XT_CONNTRACK_REPLDST) { 92 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST)) 93 return 0; 94 } 95 96 if(sinfo->flags & XT_CONNTRACK_STATUS) { 97 if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) 98 return 0; 99 } 100 101 if(sinfo->flags & XT_CONNTRACK_EXPIRES) { 102 unsigned long expires; 103 104 if(!ct) 105 return 0; 106 107 expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; 108 109 if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) 110 return 0; 111 } 112 113 return 1; 114} 115 116#else /* CONFIG_IP_NF_CONNTRACK */ 117static int 118match(const struct sk_buff *skb, 119 const struct net_device *in, 120 const struct net_device *out, 121 const void *matchinfo, 122 int offset, 123 unsigned int protoff, 124 int *hotdrop) 125{ 126 const struct xt_conntrack_info *sinfo = matchinfo; 127 struct nf_conn *ct; 128 enum ip_conntrack_info ctinfo; 129 unsigned int statebit; 130 131 ct = nf_ct_get((struct sk_buff *)skb, &ctinfo); 132 133#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) 134 135 if (ct == &nf_conntrack_untracked) 136 statebit = XT_CONNTRACK_STATE_UNTRACKED; 137 else if (ct) 138 statebit = XT_CONNTRACK_STATE_BIT(ctinfo); 139 else 140 statebit = XT_CONNTRACK_STATE_INVALID; 141 142 if(sinfo->flags & XT_CONNTRACK_STATE) { 143 if (ct) { 144 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip != 145 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) 146 statebit |= XT_CONNTRACK_STATE_SNAT; 147 148 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip != 149 ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) 150 statebit |= XT_CONNTRACK_STATE_DNAT; 151 } 152 153 if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) 154 return 0; 155 } 156 157 if(sinfo->flags & XT_CONNTRACK_PROTO) { 158 if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) 159 return 0; 160 } 161 162 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { 163 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC)) 164 return 0; 165 } 166 167 if(sinfo->flags & XT_CONNTRACK_ORIGDST) { 168 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST)) 169 return 0; 170 } 171 172 if(sinfo->flags & XT_CONNTRACK_REPLSRC) { 173 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC)) 174 return 0; 175 } 176 177 if(sinfo->flags & XT_CONNTRACK_REPLDST) { 178 if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST)) 179 return 0; 180 } 181 182 if(sinfo->flags & XT_CONNTRACK_STATUS) { 183 if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) 184 return 0; 185 } 186 187 if(sinfo->flags & XT_CONNTRACK_EXPIRES) { 188 unsigned long expires; 189 190 if(!ct) 191 return 0; 192 193 expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; 194 195 if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) 196 return 0; 197 } 198 199 return 1; 200} 201 202#endif /* CONFIG_NF_IP_CONNTRACK */ 203 204static struct xt_match conntrack_match = { 205 .name = "conntrack", 206 .match = match, 207 .matchsize = sizeof(struct xt_conntrack_info), 208 .me = THIS_MODULE, 209}; 210 211static int __init init(void) 212{ 213 int ret; 214 need_conntrack(); 215 ret = xt_register_match(AF_INET, &conntrack_match); 216 217 return ret; 218} 219 220static void __exit fini(void) 221{ 222 xt_unregister_match(AF_INET, &conntrack_match); 223} 224 225module_init(init); 226module_exit(fini); 227