4 HTTP client request match
5 Copyright (C) 2006 Jonathan Zarate
7 Licensed under GNU GPL v2 or later.
10 #include <linux/module.h>
11 #include <linux/skbuff.h>
12 #include <linux/version.h>
14 #include <linux/tcp.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");
25 #define LOG(...) do { } while (0);
28 static int find(const char *data
, const char *tail
, const char *text
)
34 while ((data
< tail
) && (*data
== ' ')) ++data
;
35 while ((tail
> data
) && (*(tail
- 1) == ' ')) --tail
;
44 if (z
> dlen
) z
= dlen
;
47 LOG(KERN_INFO
"find in '%s'\n", tmp
);
62 if (*(text
+ n
) == '$') {
65 if ((dlen
== n
) && (memcmp(data
, text
+ 1, n
) == 0)) {
66 LOG(KERN_INFO
"matched %s\n", text
);
72 if ((dlen
>= n
) && (memcmp(data
, text
+ 1, n
) == 0)) {
73 LOG(KERN_INFO
"matched %s\n", text
);
78 else if (*(text
+ n
- 1) == '$') {
81 if (memcmp(tail
- n
, text
, n
) == 0) {
82 LOG(KERN_INFO
"matched %s\n", text
);
91 if (memcmp(p
, text
, n
) == 0) {
92 LOG(KERN_INFO
"matched %s\n", text
);
104 static inline const char *findend(const char *data
, const char *tail
, int min
)
108 while (data
< tail
) {
109 if (*data
== '\r') return data
;
117 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
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
)
130 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
131 const struct ipt_web_info
*info
= matchinfo
;
133 const struct ipt_web_info
*info
= par
->matchinfo
;
134 const int offset
= par
->fragoff
;
136 const struct iphdr
*iph
= ip_hdr(skb
);
137 const struct tcphdr
*tcph
= (void *)iph
+ iph
->ihl
* 4;
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
);
151 printk(KERN_INFO
"dlen=%d doff=%d\n", dlen
, doff
);
153 memcpy(tmp
, data
, sizeof(tmp
));
154 tmp
[sizeof(tmp
) - 1] = 0;
155 printk(KERN_INFO
"[%s]\n", tmp
);
158 // POST / HTTP/1.0$$$$
159 // GET / HTTP/1.0$$$$
160 // 1234567890123456789
161 if (dlen
< 18) return info
->invert
;
164 sig
= *(__u32
*)data
;
165 if ((sig
!= __constant_htonl(0x47455420)) && (sig
!= __constant_htonl(0x504f5354))) {
176 // POST / HTTP/1.0$$$$
177 // GET / HTTP/1.0$$$$ -- minimum
178 // 0123456789012345678
180 if (((p
= findend(data
+ 14, tail
, 18)) == NULL
) || (memcmp(p
- 9, " HTTP/", 6) != 0))
185 const char *qq
= info
->text
;
187 printk(KERN_INFO
"text=%s\n", qq
);
188 qq
+= strlen(qq
) + 1;
193 switch (info
->mode
) {
195 return !info
->invert
;
197 // entire request line, else host line
198 if (find(data
+ 4, p
- 9, info
->text
)) return !info
->invert
;
201 // left side of '?' or entire line
204 while ((q
< p
) && (*q
!= '?')) ++q
;
205 return find(data
, q
, info
->text
) ^ info
->invert
;
207 // right side of '?' or none
210 while ((q
< p
) && (*q
!= '?')) ++q
;
211 if (q
>= p
) return info
->invert
;
212 return find(q
+ 1, p
, info
->text
) ^ info
->invert
;
214 // entire request line
215 return find(data
+ 4, p
- 9, info
->text
) ^ info
->invert
;
221 // else, IPT_WEB_HOST
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;
230 memcpy(tmp
, data
, 32);
232 printk(KERN_INFO
"data=[%s]\n", tmp
);
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)
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
)
251 checkentry(const struct xt_mtchk_param
*par
)
257 static struct xt_match web_match
= {
261 .matchsize
= sizeof(struct ipt_web_info
),
262 .checkentry
= &checkentry
,
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
);