Tomato 1.28
[tomato.git] / release / src / linux / linux / net / ipv4 / netfilter / ipt_web.c
blobc32a860ad90c736782add6f2f4512a862e890422
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 <net/sock.h>
13 #include <linux/netfilter_ipv4/ip_tables.h>
14 #include <linux/netfilter_ipv4/ipt_web.h>
16 MODULE_AUTHOR("Jonathan Zarate");
17 MODULE_DESCRIPTION("HTTP client request match (experimental)");
18 MODULE_LICENSE("GPL");
21 // #define LOG printk
22 #define LOG(...) do { } while (0);
25 static int find(const char *data, const char *tail, const char *text)
27 int n, o;
28 int dlen;
29 const char *p, *e;
31 while ((data < tail) && (*data == ' ')) ++data;
32 while ((tail > data) && (*(tail - 1) == ' ')) --tail;
34 dlen = tail - data;
36 #if 0
38 char tmp[128];
39 int z;
40 z = sizeof(tmp) - 1;
41 if (z > dlen) z = dlen;
42 memcpy(tmp, data, z);
43 tmp[z] = 0;
44 LOG(KERN_INFO "find in '%s'\n", tmp);
46 #endif
48 // 012345
49 // text
50 // ^text
51 // text$
52 // ^text$
53 // 012345
55 while (*text) {
56 n = o = strlen(text);
57 if (*text == '^') {
58 --n;
59 if (*(text + n) == '$') {
60 // exact
61 --n;
62 if ((dlen == n) && (memcmp(data, text + 1, n) == 0)) {
63 LOG(KERN_INFO "matched %s\n", text);
64 return 1;
67 else {
68 // begins with
69 if ((dlen >= n) && (memcmp(data, text + 1, n) == 0)) {
70 LOG(KERN_INFO "matched %s\n", text);
71 return 1;
75 else if (*(text + n - 1) == '$') {
76 // ends with
77 --n;
78 if (memcmp(tail - n, text, n) == 0) {
79 LOG(KERN_INFO "matched %s\n", text);
80 return 1;
83 else {
84 // contains
85 p = data;
86 e = tail - n;
87 while (p <= e) {
88 if (memcmp(p, text, n) == 0) {
89 LOG(KERN_INFO "matched %s\n", text);
90 return 1;
92 ++p;
96 text += o + 1;
98 return 0;
101 static inline const char *findend(const char *data, const char *tail, int min)
103 int n = tail - data;
104 if (n >= min) {
105 while (data < tail) {
106 if (*data == '\r') return data;
107 ++data;
110 return NULL;
113 static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
114 const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
116 const struct ipt_web_info *info;
117 const struct tcphdr *tcph;
118 const char *data;
119 const char *tail;
120 const char *p, *q;
121 int doff, dlen;
123 info = matchinfo;
125 if (offset != 0) return info->invert;
127 tcph = hdr;
128 doff = (tcph->doff * 4);
129 data = (char *)tcph + doff;
130 dlen = datalen - doff;
132 #if 0
133 printk(KERN_INFO "datalen=%u dlen=%d doff=%d\n", datalen, dlen, doff);
134 char tmp[16];
135 memcpy(tmp, data, sizeof(tmp));
136 tmp[sizeof(tmp) - 1] = 0;
137 printk(KERN_INFO "[%s]\n", tmp);
138 #endif
140 // POST / HTTP/1.0$$$$
141 // GET / HTTP/1.0$$$$
142 // 1234567890123456789
143 if (dlen < 18) return info->invert;
145 // "GET " or "POST"
146 __u32 sig = *(__u32 *)data;
147 if ((sig != __constant_htonl(0x47455420)) && (sig != __constant_htonl(0x504f5354))) {
148 return info->invert;
151 tail = data + dlen;
152 if (dlen > 1024) {
153 dlen = 1024;
154 tail = data + 1024;
158 // POST / HTTP/1.0$$$$
159 // GET / HTTP/1.0$$$$ -- minimum
160 // 0123456789012345678
161 // 9876543210
162 if (((p = findend(data + 14, tail, 18)) == NULL) || (memcmp(p - 9, " HTTP/", 6) != 0))
163 return info->invert;
165 #if 0
167 const char *qq = info->text;
168 while (*qq) {
169 printk(KERN_INFO "text=%s\n", qq);
170 qq += strlen(qq) + 1;
173 #endif
175 switch (info->mode) {
176 case IPT_WEB_HTTP:
177 return !info->invert;
178 case IPT_WEB_HORE:
179 // entire request line, else host line
180 if (find(data + 4, p - 9, info->text)) return !info->invert;
181 break;
182 case IPT_WEB_PATH:
183 // left side of '?' or entire line
184 q = data += 4;
185 p -= 9;
186 while ((q < p) && (*q != '?')) ++q;
187 return find(data, q, info->text) ^ info->invert;
188 case IPT_WEB_QUERY:
189 // right side of '?' or none
190 q = data + 4;
191 p -= 9;
192 while ((q < p) && (*q != '?')) ++q;
193 if (q >= p) return info->invert;
194 return find(q + 1, p, info->text) ^ info->invert;
195 case IPT_WEB_RURI:
196 // entire request line
197 return find(data + 4, p - 9, info->text) ^ info->invert;
198 default:
199 // shutup compiler
200 break;
203 // else, IPT_WEB_HOST
205 while (1) {
206 data = p + 2; // skip previous \r\n
207 p = findend(data, tail, 8); // p = current line's \r
208 if (p == NULL) return 0;
210 #if 0
211 char tmp[64];
212 memcpy(tmp, data, 32);
213 tmp[32] = 0;
214 printk(KERN_INFO "data=[%s]\n", tmp);
215 #endif
217 if (memcmp(data, "Host: ", 6) == 0)
218 return find(data + 6, p, info->text) ^ info->invert;
221 return !info->invert;
224 static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo,
225 unsigned int matchsize, unsigned int hook_mask)
227 return (matchsize == IPT_ALIGN(sizeof(struct ipt_web_info)));
231 static struct ipt_match web_match
232 = { { NULL, NULL }, "web", &match, &checkentry, NULL, THIS_MODULE };
234 static int __init init(void)
236 // LOG(KERN_INFO "ipt_web <" __DATE__ " " __TIME__ "> loaded\n");
237 return ipt_register_match(&web_match);
240 static void __exit fini(void)
242 ipt_unregister_match(&web_match);
245 module_init(init);
246 module_exit(fini);