• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/net/ipv4/netfilter/
1/*
2
3	web (experimental)
4	HTTP client request match
5	Copyright (C) 2006 Jonathan Zarate
6
7	Licensed under GNU GPL v2 or later.
8
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>
18
19MODULE_AUTHOR("Jonathan Zarate");
20MODULE_DESCRIPTION("HTTP client request match (experimental)");
21MODULE_LICENSE("GPL");
22
23#define LOG(...)	do { } while (0);
24
25static int find(const char *data, const char *tail, const char *text)
26{
27	int n, o;
28	int dlen;
29	const char *p, *e;
30
31	while ((data < tail) && (*data == ' ')) ++data;
32	while ((tail > data) && (*(tail - 1) == ' ')) --tail;
33
34	dlen = tail - data;
35
36	// 012345
37	// text
38	// ^text
39	// text$
40	// ^text$
41	// 012345
42
43	while (*text) {
44		n = o = strlen(text);
45		if (*text == '^') {
46			--n;
47			if (*(text + n) == '$') {
48				// exact
49				--n;
50				if ((dlen == n) && (memcmp(data, text + 1, n) == 0)) {
51					LOG(KERN_INFO "matched %s\n", text);
52					return 1;
53				}
54			}
55			else {
56				// begins with
57				if ((dlen >= n) && (memcmp(data, text + 1, n) == 0)) {
58					LOG(KERN_INFO "matched %s\n", text);
59					return 1;
60				}
61			}
62		}
63		else if (*(text + n - 1) == '$') {
64			// ends with
65			--n;
66			if (memcmp(tail - n, text, n) == 0) {
67				LOG(KERN_INFO "matched %s\n", text);
68				return 1;
69			}
70		}
71		else {
72			// contains
73			p = data;
74			e = tail - n;
75			while (p <= e) {
76				if (memcmp(p, text, n) == 0) {
77					LOG(KERN_INFO "matched %s\n", text);
78					return 1;
79				}
80				++p;
81			}
82		}
83
84		text += o + 1;
85	}
86	return 0;
87}
88
89static inline const char *findend(const char *data, const char *tail, int min)
90{
91	int n = tail - data;
92	if (n >= min) {
93		while (data < tail) {
94			if (*data == '\r') return data;
95			++data;
96		}
97	}
98	return NULL;
99}
100
101
102static bool
103match(const struct sk_buff *skb, struct xt_action_param *par)
104{
105	const struct ipt_web_info *info = par->matchinfo;
106	const int offset = par->fragoff;
107	const struct iphdr *iph = ip_hdr(skb);
108	const struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
109	const char *data;
110	const char *tail;
111	const char *p, *q;
112	int doff, dlen;
113	__u32 sig;
114
115	if (offset != 0) return info->invert;
116
117	doff = (tcph->doff * 4);
118 	data = (void *)tcph + doff;
119	dlen = ntohs(ip_hdr(skb)->tot_len);
120
121	// POST / HTTP/1.0$$$$
122	// GET / HTTP/1.0$$$$
123	// 1234567890123456789
124	if (dlen < 18) return info->invert;
125
126	// "GET " or "POST"
127	sig = *(__u32 *)data;
128	if ((sig != __constant_htonl(0x47455420)) && (sig != __constant_htonl(0x504f5354))) {
129		return info->invert;
130	}
131
132	tail = data + dlen;
133	if (dlen > 1024) {
134		dlen = 1024;
135		tail = data + 1024;
136	}
137
138	// POST / HTTP/1.0$$$$
139	// GET / HTTP/1.0$$$$	-- minimum
140	// 0123456789012345678
141	//      9876543210
142	if (((p = findend(data + 14, tail, 18)) == NULL) || (memcmp(p - 9, " HTTP/", 6) != 0))
143		return info->invert;
144
145	switch (info->mode) {
146	case IPT_WEB_HTTP:
147		return !info->invert;
148	case IPT_WEB_HORE:
149		// entire request line, else host line
150		if (find(data + 4, p - 9, info->text)) return !info->invert;
151		break;
152	case IPT_WEB_PATH:
153		// left side of '?' or entire line
154		q = data += 4;
155		p -= 9;
156		while ((q < p) && (*q != '?')) ++q;
157		return find(data, q, info->text) ^ info->invert;
158	case IPT_WEB_QUERY:
159		// right side of '?' or none
160		q = data + 4;
161		p -= 9;
162		while ((q < p) && (*q != '?')) ++q;
163		if (q >= p) return info->invert;
164		return find(q + 1, p, info->text) ^ info->invert;
165	case IPT_WEB_RURI:
166		// entire request line
167		return find(data + 4, p - 9, info->text) ^ info->invert;
168	default:
169		// shutup compiler
170		break;
171	}
172
173	// else, IPT_WEB_HOST
174
175	while (1) {
176		data = p + 2;				// skip previous \r\n
177		p = findend(data, tail, 8);	// p = current line's \r
178		if (p == NULL) return 0;
179
180		if (memcmp(data, "Host: ", 6) == 0)
181			return find(data + 6, p, info->text) ^ info->invert;
182	}
183
184	return !info->invert;
185}
186
187static int
188checkentry(const struct xt_mtchk_param *par)
189{
190	return 0;
191}
192
193static struct xt_match web_match = {
194	.name		= "web",
195	.family		= AF_INET,
196	.match		= &match,
197	.matchsize	= sizeof(struct ipt_web_info),
198	.checkentry	= &checkentry,
199	.destroy	= NULL,
200	.me		= THIS_MODULE
201};
202
203static int __init init(void)
204{
205	return xt_register_match(&web_match);
206}
207
208static void __exit fini(void)
209{
210	xt_unregister_match(&web_match);
211}
212
213module_init(init);
214module_exit(fini);
215