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/x_tables.h>
22 #include <linux/netfilter/xt_conntrack.h>
23 #include <net/netfilter/nf_conntrack_compat.h>
25 MODULE_LICENSE("GPL");
26 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
27 MODULE_DESCRIPTION("iptables connection tracking match module");
28 MODULE_ALIAS("ipt_conntrack");
30 #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
33 match(const struct sk_buff
*skb
,
34 const struct net_device
*in
,
35 const struct net_device
*out
,
36 const struct xt_match
*match
,
37 const void *matchinfo
,
42 const struct xt_conntrack_info
*sinfo
= matchinfo
;
43 struct ip_conntrack
*ct
;
44 enum ip_conntrack_info ctinfo
;
45 unsigned int statebit
;
47 ct
= ip_conntrack_get((struct sk_buff
*)skb
, &ctinfo
);
49 #define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & invflg))
51 if (ct
== &ip_conntrack_untracked
)
52 statebit
= XT_CONNTRACK_STATE_UNTRACKED
;
54 statebit
= XT_CONNTRACK_STATE_BIT(ctinfo
);
56 statebit
= XT_CONNTRACK_STATE_INVALID
;
58 if (sinfo
->flags
& XT_CONNTRACK_STATE
) {
60 if (test_bit(IPS_SRC_NAT_BIT
, &ct
->status
))
61 statebit
|= XT_CONNTRACK_STATE_SNAT
;
62 if (test_bit(IPS_DST_NAT_BIT
, &ct
->status
))
63 statebit
|= XT_CONNTRACK_STATE_DNAT
;
65 if (FWINV((statebit
& sinfo
->statemask
) == 0,
71 if (sinfo
->flags
& ~XT_CONNTRACK_STATE
)
76 if (sinfo
->flags
& XT_CONNTRACK_PROTO
&&
77 FWINV(ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.protonum
!=
78 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.protonum
,
82 if (sinfo
->flags
& XT_CONNTRACK_ORIGSRC
&&
83 FWINV((ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.src
.ip
&
84 sinfo
->sipmsk
[IP_CT_DIR_ORIGINAL
].s_addr
) !=
85 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].src
.ip
,
86 XT_CONNTRACK_ORIGSRC
))
89 if (sinfo
->flags
& XT_CONNTRACK_ORIGDST
&&
90 FWINV((ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.ip
&
91 sinfo
->dipmsk
[IP_CT_DIR_ORIGINAL
].s_addr
) !=
92 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.ip
,
93 XT_CONNTRACK_ORIGDST
))
96 if (sinfo
->flags
& XT_CONNTRACK_REPLSRC
&&
97 FWINV((ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.src
.ip
&
98 sinfo
->sipmsk
[IP_CT_DIR_REPLY
].s_addr
) !=
99 sinfo
->tuple
[IP_CT_DIR_REPLY
].src
.ip
,
100 XT_CONNTRACK_REPLSRC
))
103 if (sinfo
->flags
& XT_CONNTRACK_REPLDST
&&
104 FWINV((ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.dst
.ip
&
105 sinfo
->dipmsk
[IP_CT_DIR_REPLY
].s_addr
) !=
106 sinfo
->tuple
[IP_CT_DIR_REPLY
].dst
.ip
,
107 XT_CONNTRACK_REPLDST
))
110 if (sinfo
->flags
& XT_CONNTRACK_STATUS
&&
111 FWINV((ct
->status
& sinfo
->statusmask
) == 0,
112 XT_CONNTRACK_STATUS
))
115 if (sinfo
->flags
& XT_CONNTRACK_EXPIRES
) {
116 unsigned long expires
= timer_pending(&ct
->timeout
) ?
117 (ct
->timeout
.expires
- jiffies
)/HZ
: 0;
119 if (FWINV(!(expires
>= sinfo
->expires_min
&&
120 expires
<= sinfo
->expires_max
),
121 XT_CONNTRACK_EXPIRES
))
127 #else /* CONFIG_IP_NF_CONNTRACK */
129 match(const struct sk_buff
*skb
,
130 const struct net_device
*in
,
131 const struct net_device
*out
,
132 const struct xt_match
*match
,
133 const void *matchinfo
,
135 unsigned int protoff
,
138 const struct xt_conntrack_info
*sinfo
= matchinfo
;
140 enum ip_conntrack_info ctinfo
;
141 unsigned int statebit
;
143 ct
= nf_ct_get((struct sk_buff
*)skb
, &ctinfo
);
145 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
147 if (ct
== &nf_conntrack_untracked
)
148 statebit
= XT_CONNTRACK_STATE_UNTRACKED
;
150 statebit
= XT_CONNTRACK_STATE_BIT(ctinfo
);
152 statebit
= XT_CONNTRACK_STATE_INVALID
;
154 if (sinfo
->flags
& XT_CONNTRACK_STATE
) {
156 if (test_bit(IPS_SRC_NAT_BIT
, &ct
->status
))
157 statebit
|= XT_CONNTRACK_STATE_SNAT
;
158 if (test_bit(IPS_DST_NAT_BIT
, &ct
->status
))
159 statebit
|= XT_CONNTRACK_STATE_DNAT
;
161 if (FWINV((statebit
& sinfo
->statemask
) == 0,
167 if (sinfo
->flags
& ~XT_CONNTRACK_STATE
)
172 if (sinfo
->flags
& XT_CONNTRACK_PROTO
&&
173 FWINV(ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.protonum
!=
174 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.protonum
,
178 if (sinfo
->flags
& XT_CONNTRACK_ORIGSRC
&&
179 FWINV((ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.src
.u3
.ip
&
180 sinfo
->sipmsk
[IP_CT_DIR_ORIGINAL
].s_addr
) !=
181 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].src
.ip
,
182 XT_CONNTRACK_ORIGSRC
))
185 if (sinfo
->flags
& XT_CONNTRACK_ORIGDST
&&
186 FWINV((ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.u3
.ip
&
187 sinfo
->dipmsk
[IP_CT_DIR_ORIGINAL
].s_addr
) !=
188 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.ip
,
189 XT_CONNTRACK_ORIGDST
))
192 if (sinfo
->flags
& XT_CONNTRACK_REPLSRC
&&
193 FWINV((ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.src
.u3
.ip
&
194 sinfo
->sipmsk
[IP_CT_DIR_REPLY
].s_addr
) !=
195 sinfo
->tuple
[IP_CT_DIR_REPLY
].src
.ip
,
196 XT_CONNTRACK_REPLSRC
))
199 if (sinfo
->flags
& XT_CONNTRACK_REPLDST
&&
200 FWINV((ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.dst
.u3
.ip
&
201 sinfo
->dipmsk
[IP_CT_DIR_REPLY
].s_addr
) !=
202 sinfo
->tuple
[IP_CT_DIR_REPLY
].dst
.ip
,
203 XT_CONNTRACK_REPLDST
))
206 if (sinfo
->flags
& XT_CONNTRACK_STATUS
&&
207 FWINV((ct
->status
& sinfo
->statusmask
) == 0,
208 XT_CONNTRACK_STATUS
))
211 if(sinfo
->flags
& XT_CONNTRACK_EXPIRES
) {
212 unsigned long expires
= timer_pending(&ct
->timeout
) ?
213 (ct
->timeout
.expires
- jiffies
)/HZ
: 0;
215 if (FWINV(!(expires
>= sinfo
->expires_min
&&
216 expires
<= sinfo
->expires_max
),
217 XT_CONNTRACK_EXPIRES
))
223 #endif /* CONFIG_NF_IP_CONNTRACK */
226 checkentry(const char *tablename
,
228 const struct xt_match
*match
,
230 unsigned int hook_mask
)
232 if (nf_ct_l3proto_try_module_get(match
->family
) < 0) {
233 printk(KERN_WARNING
"can't load conntrack support for "
234 "proto=%d\n", match
->family
);
240 static void destroy(const struct xt_match
*match
, void *matchinfo
)
242 nf_ct_l3proto_module_put(match
->family
);
245 static struct xt_match conntrack_match
= {
248 .checkentry
= checkentry
,
250 .matchsize
= sizeof(struct xt_conntrack_info
),
255 static int __init
xt_conntrack_init(void)
257 return xt_register_match(&conntrack_match
);
260 static void __exit
xt_conntrack_fini(void)
262 xt_unregister_match(&conntrack_match
);
265 module_init(xt_conntrack_init
);
266 module_exit(xt_conntrack_fini
);