1 /* Kernel module to match connection tracking information.
2 * Superset of Rusty's minimalistic state match.
4 * (C) 2001 Marc Boucher (marc@mbsi.ca).
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.
11 #include <linux/module.h>
12 #include <linux/skbuff.h>
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>
18 #include <net/netfilter/nf_conntrack.h>
21 #include <linux/netfilter_ipv4/ip_tables.h>
22 #include <linux/netfilter_ipv4/ipt_conntrack.h>
24 MODULE_LICENSE("GPL");
25 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
26 MODULE_DESCRIPTION("iptables connection tracking match module");
28 #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
31 match(const struct sk_buff *skb,
32 const struct net_device *in,
33 const struct net_device *out,
34 const void *matchinfo,
38 const struct ipt_conntrack_info *sinfo = matchinfo;
39 struct ip_conntrack *ct;
40 enum ip_conntrack_info ctinfo;
41 unsigned int statebit;
43 ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
45 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
47 if (ct == &ip_conntrack_untracked)
48 statebit = IPT_CONNTRACK_STATE_UNTRACKED;
50 statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
52 statebit = IPT_CONNTRACK_STATE_INVALID;
54 if(sinfo->flags & IPT_CONNTRACK_STATE) {
56 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
57 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
58 statebit |= IPT_CONNTRACK_STATE_SNAT;
60 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
61 ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
62 statebit |= IPT_CONNTRACK_STATE_DNAT;
65 if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
69 if(sinfo->flags & IPT_CONNTRACK_PROTO) {
70 if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
74 if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
75 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))
79 if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
80 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))
84 if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
85 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))
89 if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
90 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))
94 if(sinfo->flags & IPT_CONNTRACK_STATUS) {
95 if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
99 if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
100 unsigned long expires;
105 expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
107 if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
114 #else /* CONFIG_IP_NF_CONNTRACK */
116 match(const struct sk_buff *skb,
117 const struct net_device *in,
118 const struct net_device *out,
119 const void *matchinfo,
123 const struct ipt_conntrack_info *sinfo = matchinfo;
125 enum ip_conntrack_info ctinfo;
126 unsigned int statebit;
128 ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
130 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
132 if (ct == &nf_conntrack_untracked)
133 statebit = IPT_CONNTRACK_STATE_UNTRACKED;
135 statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
137 statebit = IPT_CONNTRACK_STATE_INVALID;
139 if(sinfo->flags & IPT_CONNTRACK_STATE) {
141 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
142 ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
143 statebit |= IPT_CONNTRACK_STATE_SNAT;
145 if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
146 ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
147 statebit |= IPT_CONNTRACK_STATE_DNAT;
150 if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
154 if(sinfo->flags & IPT_CONNTRACK_PROTO) {
155 if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
159 if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
160 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, IPT_CONNTRACK_ORIGSRC))
164 if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
165 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, IPT_CONNTRACK_ORIGDST))
169 if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
170 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, IPT_CONNTRACK_REPLSRC))
174 if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
175 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, IPT_CONNTRACK_REPLDST))
179 if(sinfo->flags & IPT_CONNTRACK_STATUS) {
180 if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
184 if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
185 unsigned long expires;
190 expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
192 if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
199 #endif /* CONFIG_NF_IP_CONNTRACK */
201 static int check(const char *tablename,
202 const struct ipt_ip *ip,
204 unsigned int matchsize,
205 unsigned int hook_mask)
207 if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
213 static struct ipt_match conntrack_match = {
216 .checkentry = &check,
220 static int __init init(void)
223 return ipt_register_match(&conntrack_match);
226 static void __exit fini(void)
228 ipt_unregister_match(&conntrack_match);