]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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> | |
9fb9cbb1 YK |
13 | |
14 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | |
1da177e4 | 15 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
9fb9cbb1 YK |
16 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> |
17 | #else | |
18 | #include <net/netfilter/nf_conntrack.h> | |
19 | #endif | |
20 | ||
2e4e6a17 HW |
21 | #include <linux/netfilter/x_tables.h> |
22 | #include <linux/netfilter/xt_conntrack.h> | |
1da177e4 LT |
23 | |
24 | MODULE_LICENSE("GPL"); | |
25 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | |
26 | MODULE_DESCRIPTION("iptables connection tracking match module"); | |
2e4e6a17 | 27 | MODULE_ALIAS("ipt_conntrack"); |
1da177e4 | 28 | |
9fb9cbb1 YK |
29 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) |
30 | ||
1da177e4 LT |
31 | static int |
32 | match(const struct sk_buff *skb, | |
33 | const struct net_device *in, | |
34 | const struct net_device *out, | |
35 | const void *matchinfo, | |
36 | int offset, | |
2e4e6a17 | 37 | unsigned int protoff, |
1da177e4 LT |
38 | int *hotdrop) |
39 | { | |
2e4e6a17 | 40 | const struct xt_conntrack_info *sinfo = matchinfo; |
1da177e4 LT |
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) | |
2e4e6a17 | 50 | statebit = XT_CONNTRACK_STATE_UNTRACKED; |
1da177e4 | 51 | else if (ct) |
2e4e6a17 | 52 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); |
1da177e4 | 53 | else |
2e4e6a17 | 54 | statebit = XT_CONNTRACK_STATE_INVALID; |
1da177e4 | 55 | |
2e4e6a17 | 56 | if(sinfo->flags & XT_CONNTRACK_STATE) { |
1da177e4 LT |
57 | if (ct) { |
58 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != | |
59 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) | |
2e4e6a17 | 60 | statebit |= XT_CONNTRACK_STATE_SNAT; |
1da177e4 LT |
61 | |
62 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != | |
63 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) | |
2e4e6a17 | 64 | statebit |= XT_CONNTRACK_STATE_DNAT; |
1da177e4 LT |
65 | } |
66 | ||
2e4e6a17 | 67 | if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) |
1da177e4 LT |
68 | return 0; |
69 | } | |
70 | ||
2e4e6a17 HW |
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)) | |
1da177e4 LT |
73 | return 0; |
74 | } | |
75 | ||
2e4e6a17 HW |
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)) | |
1da177e4 LT |
78 | return 0; |
79 | } | |
80 | ||
2e4e6a17 HW |
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)) | |
1da177e4 LT |
83 | return 0; |
84 | } | |
85 | ||
2e4e6a17 HW |
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)) | |
1da177e4 LT |
88 | return 0; |
89 | } | |
90 | ||
2e4e6a17 HW |
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)) | |
1da177e4 LT |
93 | return 0; |
94 | } | |
95 | ||
2e4e6a17 HW |
96 | if(sinfo->flags & XT_CONNTRACK_STATUS) { |
97 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) | |
1da177e4 LT |
98 | return 0; |
99 | } | |
100 | ||
2e4e6a17 | 101 | if(sinfo->flags & XT_CONNTRACK_EXPIRES) { |
1da177e4 LT |
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 | ||
2e4e6a17 | 109 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) |
1da177e4 LT |
110 | return 0; |
111 | } | |
112 | ||
113 | return 1; | |
114 | } | |
115 | ||
9fb9cbb1 YK |
116 | #else /* CONFIG_IP_NF_CONNTRACK */ |
117 | static int | |
118 | match(const struct sk_buff *skb, | |
119 | const struct net_device *in, | |
120 | const struct net_device *out, | |
121 | const void *matchinfo, | |
122 | int offset, | |
2e4e6a17 | 123 | unsigned int protoff, |
9fb9cbb1 YK |
124 | int *hotdrop) |
125 | { | |
2e4e6a17 | 126 | const struct xt_conntrack_info *sinfo = matchinfo; |
9fb9cbb1 YK |
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) | |
2e4e6a17 | 136 | statebit = XT_CONNTRACK_STATE_UNTRACKED; |
9fb9cbb1 | 137 | else if (ct) |
2e4e6a17 | 138 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); |
9fb9cbb1 | 139 | else |
2e4e6a17 | 140 | statebit = XT_CONNTRACK_STATE_INVALID; |
9fb9cbb1 | 141 | |
2e4e6a17 | 142 | if(sinfo->flags & XT_CONNTRACK_STATE) { |
9fb9cbb1 YK |
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) | |
2e4e6a17 | 146 | statebit |= XT_CONNTRACK_STATE_SNAT; |
9fb9cbb1 YK |
147 | |
148 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip != | |
149 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) | |
2e4e6a17 | 150 | statebit |= XT_CONNTRACK_STATE_DNAT; |
9fb9cbb1 YK |
151 | } |
152 | ||
2e4e6a17 | 153 | if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) |
9fb9cbb1 YK |
154 | return 0; |
155 | } | |
156 | ||
2e4e6a17 HW |
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)) | |
9fb9cbb1 YK |
159 | return 0; |
160 | } | |
161 | ||
2e4e6a17 HW |
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)) | |
9fb9cbb1 YK |
164 | return 0; |
165 | } | |
166 | ||
2e4e6a17 HW |
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)) | |
9fb9cbb1 YK |
169 | return 0; |
170 | } | |
171 | ||
2e4e6a17 HW |
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)) | |
9fb9cbb1 YK |
174 | return 0; |
175 | } | |
176 | ||
2e4e6a17 HW |
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)) | |
9fb9cbb1 YK |
179 | return 0; |
180 | } | |
181 | ||
2e4e6a17 HW |
182 | if(sinfo->flags & XT_CONNTRACK_STATUS) { |
183 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) | |
9fb9cbb1 YK |
184 | return 0; |
185 | } | |
186 | ||
2e4e6a17 | 187 | if(sinfo->flags & XT_CONNTRACK_EXPIRES) { |
9fb9cbb1 YK |
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 | ||
2e4e6a17 | 195 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) |
9fb9cbb1 YK |
196 | return 0; |
197 | } | |
198 | ||
199 | return 1; | |
200 | } | |
201 | ||
202 | #endif /* CONFIG_NF_IP_CONNTRACK */ | |
203 | ||
1da177e4 | 204 | static int check(const char *tablename, |
2e4e6a17 | 205 | const void *ip, |
1da177e4 LT |
206 | void *matchinfo, |
207 | unsigned int matchsize, | |
208 | unsigned int hook_mask) | |
209 | { | |
2e4e6a17 | 210 | if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info))) |
1da177e4 LT |
211 | return 0; |
212 | ||
213 | return 1; | |
214 | } | |
215 | ||
2e4e6a17 | 216 | static struct xt_match conntrack_match = { |
1da177e4 LT |
217 | .name = "conntrack", |
218 | .match = &match, | |
219 | .checkentry = &check, | |
220 | .me = THIS_MODULE, | |
221 | }; | |
222 | ||
223 | static int __init init(void) | |
224 | { | |
2e4e6a17 HW |
225 | int ret; |
226 | need_conntrack(); | |
227 | ret = xt_register_match(AF_INET, &conntrack_match); | |
228 | ||
229 | return ret; | |
1da177e4 LT |
230 | } |
231 | ||
232 | static void __exit fini(void) | |
233 | { | |
2e4e6a17 | 234 | xt_unregister_match(AF_INET, &conntrack_match); |
1da177e4 LT |
235 | } |
236 | ||
237 | module_init(init); | |
238 | module_exit(fini); |