webmon [K26]: remove handling of source IP filter, fix some compile warnings.
[tomato.git] / release / src-rt / linux / linux-2.6 / net / ipv4 / netfilter / ipt_web.c
blob406206eab924f5638effe9dffa8112a68d197f0f
1 /*
3 web (experimental)
4 HTTP client request match
5 Copyright (C) 2006 Jonathan Zarate
7 Licensed under GNU GPL v2 or later.
9 */
10 #include <linux/module.h>
11 #include <linux/skbuff.h>
12 #include <linux/version.h>
13 #include <linux/ip.h>
14 #include <linux/tcp.h>
15 #include <net/sock.h>
16 #include <linux/netfilter_ipv4/ip_tables.h>
17 #include <linux/netfilter_ipv4/ipt_web.h>
19 MODULE_AUTHOR("Jonathan Zarate");
20 MODULE_DESCRIPTION("HTTP client request match (experimental)");
21 MODULE_LICENSE("GPL");
24 // #define LOG printk
25 #define LOG(...) do { } while (0);
28 static int find(const char *data, const char *tail, const char *text)
30 int n, o;
31 int dlen;
32 const char *p, *e;
34 while ((data < tail) && (*data == ' ')) ++data;
35 while ((tail > data) && (*(tail - 1) == ' ')) --tail;
37 dlen = tail - data;
39 #if 0
41 char tmp[128];
42 int z;
43 z = sizeof(tmp) - 1;
44 if (z > dlen) z = dlen;
45 memcpy(tmp, data, z);
46 tmp[z] = 0;
47 LOG(KERN_INFO "find in '%s'\n", tmp);
49 #endif
51 // 012345
52 // text
53 // ^text
54 // text$
55 // ^text$
56 // 012345
58 while (*text) {
59 n = o = strlen(text);
60 if (*text == '^') {
61 --n;
62 if (*(text + n) == '$') {
63 // exact
64 --n;
65 if ((dlen == n) && (memcmp(data, text + 1, n) == 0)) {
66 LOG(KERN_INFO "matched %s\n", text);
67 return 1;
70 else {
71 // begins with
72 if ((dlen >= n) && (memcmp(data, text + 1, n) == 0)) {
73 LOG(KERN_INFO "matched %s\n", text);
74 return 1;
78 else if (*(text + n - 1) == '$') {
79 // ends with
80 --n;
81 if (memcmp(tail - n, text, n) == 0) {
82 LOG(KERN_INFO "matched %s\n", text);
83 return 1;
86 else {
87 // contains
88 p = data;
89 e = tail - n;
90 while (p <= e) {
91 if (memcmp(p, text, n) == 0) {
92 LOG(KERN_INFO "matched %s\n", text);
93 return 1;
95 ++p;
99 text += o + 1;
101 return 0;
104 static inline const char *findend(const char *data, const char *tail, int min)
106 int n = tail - data;
107 if (n >= min) {
108 while (data < tail) {
109 if (*data == '\r') return data;
110 ++data;
113 return NULL;
117 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
118 static int
119 #else
120 static bool
121 #endif
122 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
123 match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
124 const struct xt_match *match, const void *matchinfo, int offset,
125 unsigned int protoff, int *hotdrop)
126 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
127 match(const struct sk_buff *skb, const struct xt_match_param *par)
128 #endif
130 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
131 const struct ipt_web_info *info = matchinfo;
132 #else
133 const struct ipt_web_info *info = par->matchinfo;
134 const int offset = par->fragoff;
135 #endif
136 const struct iphdr *iph = ip_hdr(skb);
137 const struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
138 const char *data;
139 const char *tail;
140 const char *p, *q;
141 int doff, dlen;
142 __u32 sig;
144 if (offset != 0) return info->invert;
146 doff = (tcph->doff * 4);
147 data = (void *)tcph + doff;
148 dlen = ntohs(ip_hdr(skb)->tot_len);
150 #if 0
151 printk(KERN_INFO "dlen=%d doff=%d\n", dlen, doff);
152 char tmp[16];
153 memcpy(tmp, data, sizeof(tmp));
154 tmp[sizeof(tmp) - 1] = 0;
155 printk(KERN_INFO "[%s]\n", tmp);
156 #endif
158 // POST / HTTP/1.0$$$$
159 // GET / HTTP/1.0$$$$
160 // 1234567890123456789
161 if (dlen < 18) return info->invert;
163 // "GET " or "POST"
164 sig = *(__u32 *)data;
165 if ((sig != __constant_htonl(0x47455420)) && (sig != __constant_htonl(0x504f5354))) {
166 return info->invert;
169 tail = data + dlen;
170 if (dlen > 1024) {
171 dlen = 1024;
172 tail = data + 1024;
176 // POST / HTTP/1.0$$$$
177 // GET / HTTP/1.0$$$$ -- minimum
178 // 0123456789012345678
179 // 9876543210
180 if (((p = findend(data + 14, tail, 18)) == NULL) || (memcmp(p - 9, " HTTP/", 6) != 0))
181 return info->invert;
183 #if 0
185 const char *qq = info->text;
186 while (*qq) {
187 printk(KERN_INFO "text=%s\n", qq);
188 qq += strlen(qq) + 1;
191 #endif
193 switch (info->mode) {
194 case IPT_WEB_HTTP:
195 return !info->invert;
196 case IPT_WEB_HORE:
197 // entire request line, else host line
198 if (find(data + 4, p - 9, info->text)) return !info->invert;
199 break;
200 case IPT_WEB_PATH:
201 // left side of '?' or entire line
202 q = data += 4;
203 p -= 9;
204 while ((q < p) && (*q != '?')) ++q;
205 return find(data, q, info->text) ^ info->invert;
206 case IPT_WEB_QUERY:
207 // right side of '?' or none
208 q = data + 4;
209 p -= 9;
210 while ((q < p) && (*q != '?')) ++q;
211 if (q >= p) return info->invert;
212 return find(q + 1, p, info->text) ^ info->invert;
213 case IPT_WEB_RURI:
214 // entire request line
215 return find(data + 4, p - 9, info->text) ^ info->invert;
216 default:
217 // shutup compiler
218 break;
221 // else, IPT_WEB_HOST
223 while (1) {
224 data = p + 2; // skip previous \r\n
225 p = findend(data, tail, 8); // p = current line's \r
226 if (p == NULL) return 0;
228 #if 0
229 char tmp[64];
230 memcpy(tmp, data, 32);
231 tmp[32] = 0;
232 printk(KERN_INFO "data=[%s]\n", tmp);
233 #endif
235 if (memcmp(data, "Host: ", 6) == 0)
236 return find(data + 6, p, info->text) ^ info->invert;
239 return !info->invert;
242 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
243 static int
244 #else
245 static bool
246 #endif
247 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
248 checkentry(const char *tablename, const void *inf, const struct xt_match *match,
249 void *matchinfo, unsigned int hook_mask)
250 #else
251 checkentry(const struct xt_mtchk_param *par)
252 #endif
254 return 1;
257 static struct xt_match web_match = {
258 .name = "web",
259 .family = AF_INET,
260 .match = &match,
261 .matchsize = sizeof(struct ipt_web_info),
262 .checkentry = &checkentry,
263 .destroy = NULL,
264 .me = THIS_MODULE
267 static int __init init(void)
269 // LOG(KERN_INFO "ipt_web <" __DATE__ " " __TIME__ "> loaded\n");
270 return xt_register_match(&web_match);
273 static void __exit fini(void)
275 xt_unregister_match(&web_match);
278 module_init(init);
279 module_exit(fini);