1/* Kernel module to match connection tracking information. 2 * Superset of Rusty's minimalistic state match. 3 * GPL (C) 2001 Marc Boucher (marc@mbsi.ca). 4 */ 5#include <linux/module.h> 6#include <linux/skbuff.h> 7#include <linux/netfilter_ipv4/ip_conntrack.h> 8#include <linux/netfilter_ipv4/ip_tables.h> 9#include <linux/netfilter_ipv4/ipt_conntrack.h> 10 11static int 12match(const struct sk_buff *skb, 13 const struct net_device *in, 14 const struct net_device *out, 15 const void *matchinfo, 16 int offset, 17 const void *hdr, 18 u_int16_t datalen, 19 int *hotdrop) 20{ 21 const struct ipt_conntrack_info *sinfo = matchinfo; 22 struct ip_conntrack *ct; 23 enum ip_conntrack_info ctinfo; 24 unsigned int statebit; 25 26 ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); 27 28#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) 29 30 statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo); 31 if(sinfo->flags & IPT_CONNTRACK_STATE) { 32 if (ct) { 33 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != 34 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) 35 statebit |= IPT_CONNTRACK_STATE_SNAT; 36 37 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != 38 ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) 39 statebit |= IPT_CONNTRACK_STATE_DNAT; 40 } 41 42 if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE)) 43 return 0; 44 } 45 46 if(sinfo->flags & IPT_CONNTRACK_PROTO) { 47 if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO)) 48 return 0; 49 } 50 51 if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) { 52 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, IPT_CONNTRACK_ORIGSRC)) 53 return 0; 54 } 55 56 if(sinfo->flags & IPT_CONNTRACK_ORIGDST) { 57 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, IPT_CONNTRACK_ORIGDST)) 58 return 0; 59 } 60 61 if(sinfo->flags & IPT_CONNTRACK_REPLSRC) { 62 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, IPT_CONNTRACK_REPLSRC)) 63 return 0; 64 } 65 66 if(sinfo->flags & IPT_CONNTRACK_REPLDST) { 67 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, IPT_CONNTRACK_REPLDST)) 68 return 0; 69 } 70 71 if(sinfo->flags & IPT_CONNTRACK_STATUS) { 72 if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS)) 73 return 0; 74 } 75 76 if(sinfo->flags & IPT_CONNTRACK_EXPIRES) { 77 unsigned long expires; 78 79 if(!ct) 80 return 0; 81 82 expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; 83 84 if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES)) 85 return 0; 86 } 87 88 return 1; 89} 90 91static int check(const char *tablename, 92 const struct ipt_ip *ip, 93 void *matchinfo, 94 unsigned int matchsize, 95 unsigned int hook_mask) 96{ 97 if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info))) 98 return 0; 99 100 return 1; 101} 102 103static struct ipt_match conntrack_match 104= { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE }; 105 106static int __init init(void) 107{ 108 /* NULL if ip_conntrack not a module */ 109 if (ip_conntrack_module) 110 __MOD_INC_USE_COUNT(ip_conntrack_module); 111 return ipt_register_match(&conntrack_match); 112} 113 114static void __exit fini(void) 115{ 116 ipt_unregister_match(&conntrack_match); 117 if (ip_conntrack_module) 118 __MOD_DEC_USE_COUNT(ip_conntrack_module); 119} 120 121module_init(init); 122module_exit(fini); 123MODULE_LICENSE("GPL"); 124