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>
24 MODULE_LICENSE("GPL");
25 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
26 MODULE_DESCRIPTION("iptables connection tracking match module");
27 MODULE_ALIAS("ipt_conntrack");
29 #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
32 match(const struct sk_buff
*skb
,
33 const struct net_device
*in
,
34 const struct net_device
*out
,
35 const void *matchinfo
,
40 const struct xt_conntrack_info
*sinfo
= matchinfo
;
41 struct ip_conntrack
*ct
;
42 enum ip_conntrack_info ctinfo
;
43 unsigned int statebit
;
45 ct
= ip_conntrack_get((struct sk_buff
*)skb
, &ctinfo
);
47 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
49 if (ct
== &ip_conntrack_untracked
)
50 statebit
= XT_CONNTRACK_STATE_UNTRACKED
;
52 statebit
= XT_CONNTRACK_STATE_BIT(ctinfo
);
54 statebit
= XT_CONNTRACK_STATE_INVALID
;
56 if(sinfo
->flags
& XT_CONNTRACK_STATE
) {
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
;
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
;
67 if (FWINV((statebit
& sinfo
->statemask
) == 0, XT_CONNTRACK_STATE
))
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
))
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
))
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
))
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
))
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
))
96 if(sinfo
->flags
& XT_CONNTRACK_STATUS
) {
97 if (!ct
|| FWINV((ct
->status
& sinfo
->statusmask
) == 0, XT_CONNTRACK_STATUS
))
101 if(sinfo
->flags
& XT_CONNTRACK_EXPIRES
) {
102 unsigned long expires
;
107 expires
= timer_pending(&ct
->timeout
) ? (ct
->timeout
.expires
- jiffies
)/HZ
: 0;
109 if (FWINV(!(expires
>= sinfo
->expires_min
&& expires
<= sinfo
->expires_max
), XT_CONNTRACK_EXPIRES
))
116 #else /* CONFIG_IP_NF_CONNTRACK */
118 match(const struct sk_buff
*skb
,
119 const struct net_device
*in
,
120 const struct net_device
*out
,
121 const void *matchinfo
,
123 unsigned int protoff
,
126 const struct xt_conntrack_info
*sinfo
= matchinfo
;
128 enum ip_conntrack_info ctinfo
;
129 unsigned int statebit
;
131 ct
= nf_ct_get((struct sk_buff
*)skb
, &ctinfo
);
133 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
135 if (ct
== &nf_conntrack_untracked
)
136 statebit
= XT_CONNTRACK_STATE_UNTRACKED
;
138 statebit
= XT_CONNTRACK_STATE_BIT(ctinfo
);
140 statebit
= XT_CONNTRACK_STATE_INVALID
;
142 if(sinfo
->flags
& XT_CONNTRACK_STATE
) {
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
;
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
;
153 if (FWINV((statebit
& sinfo
->statemask
) == 0, XT_CONNTRACK_STATE
))
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
))
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
))
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
))
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
))
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
))
182 if(sinfo
->flags
& XT_CONNTRACK_STATUS
) {
183 if (!ct
|| FWINV((ct
->status
& sinfo
->statusmask
) == 0, XT_CONNTRACK_STATUS
))
187 if(sinfo
->flags
& XT_CONNTRACK_EXPIRES
) {
188 unsigned long expires
;
193 expires
= timer_pending(&ct
->timeout
) ? (ct
->timeout
.expires
- jiffies
)/HZ
: 0;
195 if (FWINV(!(expires
>= sinfo
->expires_min
&& expires
<= sinfo
->expires_max
), XT_CONNTRACK_EXPIRES
))
202 #endif /* CONFIG_NF_IP_CONNTRACK */
204 static int check(const char *tablename
,
207 unsigned int matchsize
,
208 unsigned int hook_mask
)
210 if (matchsize
!= XT_ALIGN(sizeof(struct xt_conntrack_info
)))
216 static struct xt_match conntrack_match
= {
219 .checkentry
= &check
,
223 static int __init
init(void)
227 ret
= xt_register_match(AF_INET
, &conntrack_match
);
232 static void __exit
fini(void)
234 xt_unregister_match(AF_INET
, &conntrack_match
);