]> git.ipfire.org Git - thirdparty/xtables-addons.git/blame - extensions/xt_ipp2p.c
xt_ipp2p: use textsearch API for substring searching
[thirdparty/xtables-addons.git] / extensions / xt_ipp2p.c
CommitLineData
30ba7eb4 1#include <linux/gfp.h>
44d6f47a 2#include <linux/module.h>
30ba7eb4 3#include <linux/textsearch.h>
44d6f47a
JE
4#include <linux/version.h>
5#include <linux/netfilter_ipv4/ip_tables.h>
6#include <net/tcp.h>
7#include <net/udp.h>
0712d0fd 8#include <asm/unaligned.h>
44d6f47a
JE
9#include "xt_ipp2p.h"
10#include "compat_xtables.h"
11
c237fe24
JE
12//#define IPP2P_DEBUG_ARES
13//#define IPP2P_DEBUG_SOUL
14//#define IPP2P_DEBUG_WINMX
15
74e7eb28
JE
16#define get_u8(X, O) (*(const __u8 *)((X) + O))
17#define get_u16(X, O) get_unaligned((const __u16 *)((X) + O))
18#define get_u32(X, O) get_unaligned((const __u32 *)((X) + O))
44d6f47a
JE
19
20MODULE_AUTHOR("Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>");
21MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
22MODULE_LICENSE("GPL");
23
a6079ae9
JS
24#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0)
25static inline unsigned int
26ip_transport_len(const struct sk_buff *skb)
27{
28 return ntohs(ip_hdr(skb)->tot_len) - skb_network_header_len(skb);
29}
30static inline unsigned int
31ipv6_transport_len(const struct sk_buff *skb)
32{
33 return ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr) -
34 skb_network_header_len(skb);
35}
36#endif
37
ad554f10 38struct ipp2p_result_printer {
f144c2eb 39 const union nf_inet_addr *saddr, *daddr;
ad554f10 40 short sport, dport;
f144c2eb 41 void (*print)(const union nf_inet_addr *, short, const union nf_inet_addr *, short, bool, unsigned int);
ad554f10
JS
42};
43
ee1c4c72
JS
44static bool iscrlf(const unsigned char *str)
45{
46 return str[0] == '\r' && str[1] == '\n';
47}
48
ad554f10
JS
49static void
50print_result(const struct ipp2p_result_printer *rp, bool result,
51 unsigned int hlen)
52{
53 rp->print(rp->saddr, rp->sport,
54 rp->daddr, rp->dport,
55 result, hlen);
56}
57
c237fe24 58/* Search for UDP eDonkey/eMule/Kad commands */
569643ac 59static unsigned int
30ba7eb4
JS
60udp_search_edk(const unsigned char *t, const unsigned int packet_len,
61 const struct ipt_p2p_info *info)
44d6f47a 62{
17a03128
CB
63 if (packet_len < 4)
64 return 0;
65
44d6f47a 66 switch (t[0]) {
c237fe24 67 case 0xe3:
30ddb4f8 68 /* eDonkey */
c237fe24
JE
69 switch (t[1]) {
70 /* client -> server status request */
71 case 0x96:
c66d291e 72 if (packet_len == 6)
c237fe24 73 return IPP2P_EDK * 100 + 50;
44d6f47a 74 break;
c237fe24
JE
75
76 /* server -> client status request */
77 case 0x97:
c66d291e 78 if (packet_len == 34)
c237fe24
JE
79 return IPP2P_EDK * 100 + 51;
80 break;
81
82 /* server description request */
83 /* e3 2a ff f0 .. | size == 6 */
84 case 0xa2:
c66d291e 85 if (packet_len == 6 &&
c237fe24
JE
86 get_u16(t, 2) == __constant_htons(0xfff0))
87 return IPP2P_EDK * 100 + 52;
88 break;
89
90 /* server description response */
91 /* e3 a3 ff f0 .. | size > 40 && size < 200 */
92 /*
93 case 0xa3:
94 return IPP2P_EDK * 100 + 53;
95 break;
96 */
97
98 case 0x9a:
c66d291e 99 if (packet_len == 18)
c237fe24
JE
100 return IPP2P_EDK * 100 + 54;
101 break;
102
103 case 0x92:
c66d291e 104 if (packet_len == 10)
c237fe24 105 return IPP2P_EDK * 100 + 55;
44d6f47a
JE
106 break;
107 }
c237fe24
JE
108 break;
109
110 case 0xe4:
111 switch (t[1]) {
c66d291e 112 /* e4 20 .. | size == 35 */
c237fe24 113 case 0x20:
c66d291e 114 if (packet_len == 35 && t[2] != 0x00 && t[34] != 0x00)
c237fe24
JE
115 return IPP2P_EDK * 100 + 60;
116 break;
44d6f47a 117
c66d291e 118 /* e4 00 .. 00 | size == 27 ? */
c237fe24 119 case 0x00:
c66d291e 120 if (packet_len == 27 && t[26] == 0x00)
c237fe24 121 return IPP2P_EDK * 100 + 61;
44d6f47a 122 break;
c237fe24 123
c66d291e 124 /* e4 10 .. 00 | size == 27 ? */
c237fe24 125 case 0x10:
c66d291e 126 if (packet_len == 27 && t[26] == 0x00)
c237fe24 127 return IPP2P_EDK * 100 + 62;
44d6f47a 128 break;
c237fe24 129
c66d291e 130 /* e4 18 .. 00 | size == 27 ? */
c237fe24 131 case 0x18:
c66d291e 132 if (packet_len == 27 && t[26] == 0x00)
c237fe24 133 return IPP2P_EDK * 100 + 63;
44d6f47a 134 break;
c237fe24 135
c66d291e 136 /* e4 52 .. | size = 36 */
c237fe24 137 case 0x52:
c66d291e 138 if (packet_len == 36)
c237fe24 139 return IPP2P_EDK * 100 + 64;
44d6f47a 140 break;
c237fe24
JE
141
142 /* e4 58 .. | size == 6 */
143 case 0x58:
c66d291e 144 if (packet_len == 6)
c237fe24 145 return IPP2P_EDK * 100 + 65;
44d6f47a 146 break;
c237fe24
JE
147
148 /* e4 59 .. | size == 2 */
149 case 0x59:
c66d291e 150 if (packet_len == 2)
c237fe24 151 return IPP2P_EDK * 100 + 66;
44d6f47a 152 break;
c237fe24 153
c66d291e 154 /* e4 28 .. | packet_len == 49,69,94,119... */
c237fe24 155 case 0x28:
c66d291e 156 if ((packet_len - 44) % 25 == 0)
c237fe24 157 return IPP2P_EDK * 100 + 67;
44d6f47a 158 break;
c237fe24
JE
159
160 /* e4 50 xx xx | size == 4 */
161 case 0x50:
c66d291e 162 if (packet_len == 4)
c237fe24
JE
163 return IPP2P_EDK * 100 + 68;
164 break;
165
166 /* e4 40 xx xx | size == 48 */
167 case 0x40:
c66d291e 168 if (packet_len == 48)
c237fe24 169 return IPP2P_EDK * 100 + 69;
44d6f47a 170 break;
44d6f47a 171 }
c237fe24 172 break;
44d6f47a 173 }
c237fe24
JE
174 return 0;
175}
176
177/* Search for UDP Gnutella commands */
569643ac 178static unsigned int
30ba7eb4
JS
179udp_search_gnu(const unsigned char *t, const unsigned int packet_len,
180 const struct ipt_p2p_info *info)
c237fe24 181{
17a03128 182 if (packet_len >= 3 && memcmp(t, "GND", 3) == 0)
c237fe24 183 return IPP2P_GNU * 100 + 51;
17a03128 184 if (packet_len >= 9 && memcmp(t, "GNUTELLA ", 9) == 0)
c237fe24
JE
185 return IPP2P_GNU * 100 + 52;
186 return 0;
187}
188
189/* Search for UDP KaZaA commands */
569643ac 190static unsigned int
30ba7eb4
JS
191udp_search_kazaa(const unsigned char *t, const unsigned int packet_len,
192 const struct ipt_p2p_info *info)
c237fe24 193{
17a03128
CB
194 if (packet_len < 6)
195 return 0;
196 if (memcmp(t + packet_len - 6, "KaZaA\x00", 6) == 0)
197 return IPP2P_KAZAA * 100 + 50;
c237fe24
JE
198 return 0;
199}
200
201/* Search for UDP DirectConnect commands */
30ba7eb4
JS
202static unsigned int
203udp_search_directconnect(const unsigned char *t, const unsigned int packet_len,
204 const struct ipt_p2p_info *info)
c237fe24 205{
17a03128
CB
206 if (packet_len < 5)
207 return 0;
dc05fc62
JS
208 if (t[0] != 0x24)
209 return 0;
210 if (t[packet_len-1] != 0x7c)
211 return 0;
212 if (memcmp(&t[1], "SR ", 3) == 0)
213 return IPP2P_DC * 100 + 60;
214 if (packet_len >= 7 && memcmp(&t[1], "Ping ", 5) == 0)
215 return IPP2P_DC * 100 + 61;
c237fe24
JE
216 return 0;
217}
218
219/* Search for UDP BitTorrent commands */
569643ac 220static unsigned int
30ba7eb4
JS
221udp_search_bit(const unsigned char *haystack, const unsigned int packet_len,
222 const struct ipt_p2p_info *info)
c237fe24
JE
223{
224 switch (packet_len) {
c66d291e 225 case 16:
c237fe24 226 /* ^ 00 00 04 17 27 10 19 80 */
2c5d0956
JS
227 if (get_u32(haystack, 0) == __constant_htonl(0x00000417) &&
228 get_u32(haystack, 4) == __constant_htonl(0x27101980))
c237fe24
JE
229 return IPP2P_BIT * 100 + 50;
230 break;
c66d291e
CB
231 case 36:
232 if (get_u32(haystack, 8) == __constant_htonl(0x00000400) &&
233 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24 234 return IPP2P_BIT * 100 + 51;
c66d291e 235 if (get_u32(haystack, 8) == __constant_htonl(0x00000400))
c237fe24
JE
236 return IPP2P_BIT * 100 + 61;
237 break;
c66d291e
CB
238 case 57:
239 if (get_u32(haystack, 8) == __constant_htonl(0x00000404) &&
240 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24 241 return IPP2P_BIT * 100 + 52;
c66d291e 242 if (get_u32(haystack, 8) == __constant_htonl(0x00000404))
c237fe24
JE
243 return IPP2P_BIT * 100 + 62;
244 break;
c66d291e
CB
245 case 59:
246 if (get_u32(haystack, 8) == __constant_htonl(0x00000406) &&
247 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24 248 return (IPP2P_BIT * 100 + 53);
c66d291e 249 if (get_u32(haystack, 8) == __constant_htonl(0x00000406))
c237fe24
JE
250 return (IPP2P_BIT * 100 + 63);
251 break;
c66d291e
CB
252 case 203:
253 if (get_u32(haystack, 0) == __constant_htonl(0x00000405))
c237fe24
JE
254 return IPP2P_BIT * 100 + 54;
255 break;
c66d291e
CB
256 case 21:
257 if (get_u32(haystack, 0) == __constant_htonl(0x00000401))
c237fe24
JE
258 return IPP2P_BIT * 100 + 55;
259 break;
c66d291e
CB
260 case 44:
261 if (get_u32(haystack, 0) == __constant_htonl(0x00000827) &&
262 get_u32(haystack, 4) == __constant_htonl(0x37502950))
c237fe24
JE
263 return IPP2P_BIT * 100 + 80;
264 break;
265 default:
266 /* this packet does not have a constant size */
c66d291e
CB
267 if (packet_len >= 32 &&
268 get_u32(haystack, 8) == __constant_htonl(0x00000402) &&
269 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24
JE
270 return IPP2P_BIT * 100 + 56;
271 break;
272 }
273
274 /* some extra-bitcomet rules: "d1:" [a|r] "d2:id20:" */
dc05fc62
JS
275 if (packet_len > 22 &&
276 get_u8(haystack, 0) == 'd' &&
277 get_u8(haystack, 1) == '1' &&
278 get_u8(haystack, 2) == ':' &&
279 (get_u8(haystack, 3) == 'a' ||
280 get_u8(haystack, 3) == 'r') &&
281 memcmp(haystack + 4, "d2:id20:", 8) == 0)
282 return IPP2P_BIT * 100 + 57;
c237fe24 283
44d6f47a
JE
284#if 0
285 /* bitlord rules */
c66d291e 286 /* packetlen must be bigger than 32 */
44d6f47a 287 /* first 4 bytes are zero */
c66d291e 288 if (packet_len > 32 && get_u32(haystack, 0) == 0x00000000) {
30ddb4f8 289 /* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00 */
c66d291e
CB
290 if (get_u32(haystack, 4) == 0x00000000 &&
291 get_u32(haystack, 8) == 0x00010000 &&
292 get_u32(haystack, 16) == 0x00000000)
c237fe24
JE
293 return IPP2P_BIT * 100 + 71;
294
30ddb4f8 295 /* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00 */
c66d291e
CB
296 if (get_u32(haystack, 4) == 0x00000001 &&
297 get_u32(haystack, 8) == 0x000d0000 &&
298 get_u32(haystack, 16) == 0x00000000)
c237fe24 299 return IPP2P_BIT * 100 + 71;
44d6f47a
JE
300 }
301#endif
302
c237fe24
JE
303 return 0;
304}
44d6f47a 305
c237fe24 306/* Search for Ares commands */
569643ac 307static unsigned int
30ba7eb4
JS
308search_ares(const unsigned char *payload, const unsigned int plen,
309 const struct ipt_p2p_info *info)
44d6f47a 310{
17a03128
CB
311 if (plen < 3)
312 return 0;
44d6f47a 313 /* all ares packets start with */
c237fe24
JE
314 if (payload[1] == 0 && plen - payload[0] == 3) {
315 switch (payload[2]) {
316 case 0x5a:
317 /* ares connect */
318 if (plen == 6 && payload[5] == 0x05)
319 return IPP2P_ARES * 100 + 1;
320 break;
321 case 0x09:
322 /*
323 * ares search, min 3 chars --> 14 bytes
324 * lets define a search can be up to 30 chars
325 * --> max 34 bytes
326 */
327 if (plen >= 14 && plen <= 34)
328 return IPP2P_ARES * 100 + 1;
329 break;
44d6f47a 330#ifdef IPP2P_DEBUG_ARES
c237fe24
JE
331 default:
332 printk(KERN_DEBUG "Unknown Ares command %x "
333 "recognized, len: %u\n",
334 (unsigned int)payload[2], plen);
335#endif
44d6f47a
JE
336 }
337 }
338
c237fe24 339#if 0
44d6f47a
JE
340 /* found connect packet: 03 00 5a 04 03 05 */
341 /* new version ares 1.8: 03 00 5a xx xx 05 */
c237fe24
JE
342 if (plen == 6)
343 /* possible connect command */
344 if (payload[0] == 0x03 && payload[1] == 0x00 &&
345 payload[2] == 0x5a && payload[5] == 0x05)
346 return IPP2P_ARES * 100 + 1;
347
348 if (plen == 60)
30ddb4f8 349 /* possible download command */
c237fe24
JE
350 if (payload[59] == 0x0a && payload[58] == 0x0a)
351 if (memcmp(t, "PUSH SHA1:", 10) == 0)
352 /* found download command */
353 return IPP2P_ARES * 100 + 2;
44d6f47a
JE
354#endif
355
c237fe24
JE
356 return 0;
357}
44d6f47a 358
c237fe24 359/* Search for SoulSeek commands */
569643ac 360static unsigned int
30ba7eb4
JS
361search_soul(const unsigned char *payload, const unsigned int plen,
362 const struct ipt_p2p_info *info)
44d6f47a 363{
17a03128
CB
364 if (plen < 8)
365 return 0;
c237fe24
JE
366 /* match: xx xx xx xx | xx = sizeof(payload) - 4 */
367 if (get_u32(payload, 0) == plen - 4) {
569643ac
JE
368 const uint32_t m = get_u32(payload, 4);
369
c237fe24
JE
370 /* match 00 yy yy 00, yy can be everything */
371 if (get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00) {
44d6f47a 372#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
373 printk(KERN_DEBUG "0: Soulseek command 0x%x "
374 "recognized\n", get_u32(payload, 4));
375#endif
376 return IPP2P_SOUL * 100 + 1;
377 }
378
379 /* next match: 01 yy 00 00 | yy can be everything */
380 if (get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000) {
44d6f47a 381#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
382 printk(KERN_DEBUG "1: Soulseek command 0x%x "
383 "recognized\n", get_u16(payload, 4));
384#endif
385 return IPP2P_SOUL * 100 + 2;
386 }
387
388 /* other soulseek commandos are: 1-5,7,9,13-18,22,23,26,28,35-37,40-46,50,51,60,62-69,91,92,1001 */
389 /* try to do this in an intelligent way */
390 /* get all small commandos */
391 switch (m) {
44d6f47a
JE
392 case 7:
393 case 9:
394 case 22:
395 case 23:
396 case 26:
397 case 28:
398 case 50:
399 case 51:
400 case 60:
401 case 91:
402 case 92:
403 case 1001:
404#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
405 printk(KERN_DEBUG "2: Soulseek command 0x%x "
406 "recognized\n", get_u16(payload, 4));
407#endif
408 return IPP2P_SOUL * 100 + 3;
409 }
410
411 if (m > 0 && m < 6) {
44d6f47a 412#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
413 printk(KERN_DEBUG "3: Soulseek command 0x%x "
414 "recognized\n", get_u16(payload, 4));
415#endif
416 return IPP2P_SOUL * 100 + 4;
417 }
418
419 if (m > 12 && m < 19) {
44d6f47a 420#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
421 printk(KERN_DEBUG "4: Soulseek command 0x%x "
422 "recognized\n", get_u16(payload, 4));
423#endif
424 return IPP2P_SOUL * 100 + 5;
425 }
44d6f47a 426
c237fe24 427 if (m > 34 && m < 38) {
44d6f47a 428#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
429 printk(KERN_DEBUG "5: Soulseek command 0x%x "
430 "recognized\n", get_u16(payload, 4));
431#endif
432 return IPP2P_SOUL * 100 + 6;
433 }
44d6f47a 434
c237fe24 435 if (m > 39 && m < 47) {
44d6f47a 436#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
437 printk(KERN_DEBUG "6: Soulseek command 0x%x "
438 "recognized\n", get_u16(payload, 4));
439#endif
440 return IPP2P_SOUL * 100 + 7;
441 }
44d6f47a 442
c237fe24 443 if (m > 61 && m < 70) {
44d6f47a 444#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
445 printk(KERN_DEBUG "7: Soulseek command 0x%x "
446 "recognized\n", get_u16(payload, 4));
447#endif
448 return IPP2P_SOUL * 100 + 8;
449 }
44d6f47a
JE
450
451#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
452 printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first "
453 "16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",
454 get_u32(payload, 4), get_u16(payload, 4) >> 16,
455 get_u8(payload, 4) >> 24);
456#endif
457 }
458
44d6f47a 459 /* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */
30ddb4f8 460 /* without size at the beginning! */
c237fe24 461 if (get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01) {
569643ac 462 uint32_t y = get_u32(payload, 5);
dc05fc62 463 const unsigned char *w;
569643ac 464
44d6f47a 465 /* we need 19 chars + string */
dc05fc62
JS
466 if (plen < y + 19)
467 return 0;
468 w = payload + 9 + y;
469 if (get_u32(w, 0) == 0x01 &&
470 (get_u16(w, 4) == 0x4600 ||
471 get_u16(w, 4) == 0x5000) &&
472 get_u32(w, 6) == 0x00) {
44d6f47a 473#ifdef IPP2P_DEBUG_SOUL
dc05fc62 474 printk(KERN_DEBUG "Soulseek special client command recognized\n");
c237fe24 475#endif
dc05fc62 476 return IPP2P_SOUL * 100 + 9;
44d6f47a
JE
477 }
478 }
c237fe24 479 return 0;
44d6f47a
JE
480}
481
c237fe24 482/* Search for WinMX commands */
569643ac 483static unsigned int
30ba7eb4
JS
484search_winmx(const unsigned char *payload, const unsigned int plen,
485 const struct ipt_p2p_info *info)
44d6f47a 486{
30ba7eb4
JS
487 uint16_t start;
488
c237fe24
JE
489 if (plen == 4 && memcmp(payload, "SEND", 4) == 0)
490 return IPP2P_WINMX * 100 + 1;
491 if (plen == 3 && memcmp(payload, "GET", 3) == 0)
492 return IPP2P_WINMX * 100 + 2;
493 /*
494 if (packet_len < head_len + 10)
495 return 0;
496 */
497 if (plen < 10)
498 return 0;
499
30ba7eb4
JS
500 if (memcmp(payload, "SEND", 4) == 0)
501 start = 4;
502 else if (memcmp(payload, "GET", 3) == 0)
503 start = 3;
504 else
505 start = 0;
506
507 if (start) {
569643ac 508 uint8_t count = 0;
c237fe24 509
30ba7eb4
JS
510 do {
511 struct ts_state state;
512 unsigned int pos;
513
514 pos = textsearch_find_continuous(info->ts_conf_winmx,
515 &state,
516 &payload[start],
517 plen - start);
518 if (pos == UINT_MAX)
519 break;
520
521 count++;
522 if (count >= 2)
523 return IPP2P_WINMX * 100 + 3;
524
525 start = pos + 2;
526 } while (start < plen);
c237fe24
JE
527 }
528
529 if (plen == 149 && payload[0] == '8') {
44d6f47a 530#ifdef IPP2P_DEBUG_WINMX
c237fe24 531 printk(KERN_INFO "maybe WinMX\n");
44d6f47a 532#endif
c237fe24
JE
533 if (get_u32(payload, 17) == 0 && get_u32(payload, 21) == 0 &&
534 get_u32(payload, 25) == 0 &&
535// get_u32(payload, 33) == __constant_htonl(0x71182b1a) &&
536// get_u32(payload, 37) == __constant_htonl(0x05050000) &&
537// get_u32(payload, 133) == __constant_htonl(0x31097edf) &&
538// get_u32(payload, 145) == __constant_htonl(0xdcb8f792))
539 get_u16(payload, 39) == 0 &&
540 get_u16(payload, 135) == __constant_htons(0x7edf) &&
541 get_u16(payload,147) == __constant_htons(0xf792))
542 {
44d6f47a 543#ifdef IPP2P_DEBUG_WINMX
c237fe24 544 printk(KERN_INFO "got WinMX\n");
44d6f47a 545#endif
c237fe24
JE
546 return IPP2P_WINMX * 100 + 4;
547 }
548 }
549 return 0;
550}
551
552/* Search for appleJuice commands */
569643ac 553static unsigned int
30ba7eb4
JS
554search_apple(const unsigned char *payload, const unsigned int plen,
555 const struct ipt_p2p_info *info)
44d6f47a 556{
dc05fc62
JS
557 if (plen < 8)
558 return 0;
559 if (memcmp(payload, "ajprot\r\n", 8) == 0)
c237fe24 560 return IPP2P_APPLE * 100;
c237fe24 561 return 0;
44d6f47a
JE
562}
563
c237fe24 564/* Search for BitTorrent commands */
569643ac 565static unsigned int
30ba7eb4
JS
566search_bittorrent(const unsigned char *payload, const unsigned int plen,
567 const struct ipt_p2p_info *info)
44d6f47a 568{
30ba7eb4
JS
569 struct ts_state state;
570 unsigned int pos;
571
dc05fc62
JS
572 /*
573 * bitcomet encrypts the first packet, so we have to detect another one
574 * later in the flow.
575 */
576 if (plen == 17 &&
577 get_u32(payload, 0) == __constant_htonl(0x0d) &&
578 payload[4] == 0x06 &&
579 get_u32(payload,13) == __constant_htonl(0x4000))
580 return IPP2P_BIT * 100 + 3;
581 if (plen <= 20)
582 return 0;
c237fe24 583
dc05fc62
JS
584 /* test for match 0x13+"BitTorrent protocol" */
585 if (payload[0] == 0x13)
586 if (memcmp(payload + 1, "BitTorrent protocol", 19) == 0)
587 return IPP2P_BIT * 100;
588 /*
589 * Any tracker command starts with GET / then *may be* some file
590 * on web server (e.g. announce.php or dupa.pl or whatever.cgi
591 * or NOTHING for tracker on root dir) but *must have* one (or
592 * more) of strings listed below (true for scrape and announce)
593 */
594 if (memcmp(payload, "GET /", 5) != 0)
595 return 0;
30ba7eb4
JS
596
597 pos = textsearch_find_continuous(info->ts_conf_bt_info_hash,
598 &state, &payload[5], plen - 5);
599 if (pos != UINT_MAX)
dc05fc62 600 return IPP2P_BIT * 100 + 1;
30ba7eb4
JS
601
602 pos = textsearch_find_continuous(info->ts_conf_bt_peer_id,
603 &state, &payload[5], plen - 5);
604 if (pos != UINT_MAX)
dc05fc62 605 return IPP2P_BIT * 100 + 2;
30ba7eb4
JS
606
607 pos = textsearch_find_continuous(info->ts_conf_bt_passkey,
608 &state, &payload[5], plen - 5);
609 if (pos != UINT_MAX)
dc05fc62 610 return IPP2P_BIT * 100 + 4;
c237fe24 611 return 0;
44d6f47a
JE
612}
613
c237fe24 614/* check for Kazaa get command */
569643ac 615static unsigned int
30ba7eb4
JS
616search_kazaa(const unsigned char *payload, const unsigned int plen,
617 const struct ipt_p2p_info *info)
44d6f47a 618{
17a03128
CB
619 if (plen < 13)
620 return 0;
ee1c4c72 621 if (iscrlf(&payload[plen-2]) &&
c237fe24
JE
622 memcmp(payload, "GET /.hash=", 11) == 0)
623 return IPP2P_DATA_KAZAA * 100;
44d6f47a 624
c237fe24 625 return 0;
44d6f47a
JE
626}
627
30ddb4f8 628/* check for Gnutella get command */
569643ac 629static unsigned int
30ba7eb4
JS
630search_gnu(const unsigned char *payload, const unsigned int plen,
631 const struct ipt_p2p_info *info)
44d6f47a 632{
17a03128
CB
633 if (plen < 11)
634 return 0;
dc05fc62
JS
635 if (!iscrlf(&payload[plen-2]))
636 return 0;
637 if (memcmp(payload, "GET /get/", 9) == 0)
638 return IPP2P_DATA_GNU * 100 + 1;
639 if (plen >= 15 && memcmp(payload, "GET /uri-res/", 13) == 0)
640 return IPP2P_DATA_GNU * 100 + 2;
c237fe24 641 return 0;
44d6f47a
JE
642}
643
30ddb4f8 644/* check for Gnutella get commands and other typical data */
569643ac 645static unsigned int
30ba7eb4
JS
646search_all_gnu(const unsigned char *payload, const unsigned int plen,
647 const struct ipt_p2p_info *info)
44d6f47a 648{
30ba7eb4
JS
649 struct ts_state state;
650 unsigned int c, pos;
dc05fc62 651
17a03128
CB
652 if (plen < 11)
653 return 0;
dc05fc62
JS
654 if (!iscrlf(&payload[plen-2]))
655 return 0;
656 if (plen >= 19 && memcmp(payload, "GNUTELLA CONNECT/", 17) == 0)
657 return IPP2P_GNU * 100 + 1;
658 if (memcmp(payload, "GNUTELLA/", 9) == 0)
659 return IPP2P_GNU * 100 + 2;
660 if (plen < 22)
661 return 0;
30ba7eb4
JS
662 if (memcmp(payload, "GET /get/", 9) == 0)
663 c = 9;
664 else if (memcmp(payload, "GET /uri-res/", 13) == 0)
665 c = 13;
666 else
dc05fc62 667 return 0;
569643ac 668
30ba7eb4
JS
669 pos = textsearch_find_continuous(info->ts_conf_gnu_x_gnutella,
670 &state, &payload[c], plen - c);
671 if (pos != UINT_MAX)
672 return IPP2P_GNU * 100 + 3;
673
674 pos = textsearch_find_continuous(info->ts_conf_gnu_x_queue,
675 &state, &payload[c], plen - c);
676 if (pos != UINT_MAX)
677 return IPP2P_GNU * 100 + 3;
c237fe24 678 return 0;
44d6f47a
JE
679}
680
c237fe24 681/* check for KaZaA download commands and other typical data */
d01a5f3d 682/* plen is guaranteed to be >= 5 (see @matchlist) */
569643ac 683static unsigned int
30ba7eb4
JS
684search_all_kazaa(const unsigned char *payload, const unsigned int plen,
685 const struct ipt_p2p_info *info)
44d6f47a 686{
30ba7eb4
JS
687 struct ts_state state;
688 unsigned int pos;
d01a5f3d 689
17a03128 690 if (plen < 7)
879e964f
JE
691 /* too short for anything we test for - early bailout */
692 return 0;
ee1c4c72 693 if (!iscrlf(&payload[plen-2]))
22db3bcb 694 return 0;
c237fe24 695
22db3bcb
JE
696 if (memcmp(payload, "GIVE ", 5) == 0)
697 return IPP2P_KAZAA * 100 + 1;
698
d01a5f3d
JE
699 if (memcmp(payload, "GET /", 5) != 0)
700 return 0;
701
4cdfd496
JE
702 if (plen < 18)
703 /* The next tests would not succeed anyhow. */
704 return 0;
705
30ba7eb4
JS
706 pos = textsearch_find_continuous(info->ts_conf_kz_x_kazaa_username,
707 &state, &payload[5], plen - 5);
708 if (pos != UINT_MAX)
709 return IPP2P_KAZAA * 100 + 2;
710
711 pos = textsearch_find_continuous(info->ts_conf_kz_user_agent,
712 &state, &payload[5], plen - 5);
713 if (pos != UINT_MAX)
714 return IPP2P_KAZAA * 100 + 2;
22db3bcb 715
c237fe24 716 return 0;
44d6f47a
JE
717}
718
30ddb4f8 719/* fast check for eDonkey file segment transfer command */
569643ac 720static unsigned int
30ba7eb4
JS
721search_edk(const unsigned char *payload, const unsigned int plen,
722 const struct ipt_p2p_info *info)
44d6f47a 723{
17a03128
CB
724 if (plen < 6)
725 return 0;
dc05fc62 726 if (payload[0] != 0xe3)
c237fe24 727 return 0;
dc05fc62
JS
728 if (payload[5] == 0x47)
729 return IPP2P_DATA_EDK * 100;
730 return 0;
44d6f47a
JE
731}
732
30ddb4f8 733/* intensive but slower search for some eDonkey packets including size check */
569643ac 734static unsigned int
30ba7eb4
JS
735search_all_edk(const unsigned char *payload, const unsigned int plen,
736 const struct ipt_p2p_info *info)
44d6f47a 737{
dc05fc62
JS
738 unsigned int cmd;
739
17a03128
CB
740 if (plen < 6)
741 return 0;
dc05fc62 742 if (payload[0] != 0xe3)
c237fe24 743 return 0;
c237fe24 744
dc05fc62
JS
745 cmd = get_u16(payload, 1);
746 if (cmd == plen - 5) {
747 switch (payload[5]) {
748 case 0x01:
749 /* Client: hello or Server:hello */
c237fe24 750 return IPP2P_EDK * 100 + 1;
dc05fc62
JS
751 case 0x4c:
752 /* Client: Hello-Answer */
753 return IPP2P_EDK * 100 + 9;
c237fe24 754 }
44d6f47a 755 }
dc05fc62 756 return 0;
44d6f47a
JE
757}
758
c237fe24 759/* fast check for Direct Connect send command */
569643ac 760static unsigned int
30ba7eb4
JS
761search_dc(const unsigned char *payload, const unsigned int plen,
762 const struct ipt_p2p_info *info)
44d6f47a 763{
17a03128
CB
764 if (plen < 6)
765 return 0;
dc05fc62 766 if (payload[0] != 0x24)
c237fe24 767 return 0;
dc05fc62
JS
768 if (memcmp(&payload[1], "Send|", 5) == 0)
769 return IPP2P_DATA_DC * 100;
770 return 0;
44d6f47a
JE
771}
772
c237fe24 773/* intensive but slower check for all direct connect packets */
569643ac 774static unsigned int
30ba7eb4
JS
775search_all_dc(const unsigned char *payload, const unsigned int plen,
776 const struct ipt_p2p_info *info)
44d6f47a 777{
dc05fc62
JS
778 const unsigned char *t;
779
17a03128
CB
780 if (plen < 7)
781 return 0;
dc05fc62
JS
782 if (payload[0] != 0x24)
783 return 0;
784 if (payload[plen-1] != 0x7c)
785 return 0;
786 t = &payload[1];
787 /* Client-Hub-Protocol */
788 if (memcmp(t, "Lock ", 5) == 0)
789 return IPP2P_DC * 100 + 1;
790 /*
791 * Client-Client-Protocol, some are already recognized by client-hub
792 * (like lock)
793 */
794 if (plen >= 9 && memcmp(t, "MyNick ", 7) == 0)
795 return IPP2P_DC * 100 + 38;
c237fe24 796 return 0;
44d6f47a
JE
797}
798
c237fe24 799/* check for mute */
569643ac 800static unsigned int
30ba7eb4
JS
801search_mute(const unsigned char *payload, const unsigned int plen,
802 const struct ipt_p2p_info *info)
44d6f47a 803{
c237fe24
JE
804 if (plen == 209 || plen == 345 || plen == 473 || plen == 609 ||
805 plen == 1121) {
806 //printk(KERN_DEBUG "size hit: %u", size);
807 if (memcmp(payload,"PublicKey: ", 11) == 0) {
808 return IPP2P_MUTE * 100 + 0;
809 /*
810 if (memcmp(t + size - 14, "\x0aEndPublicKey\x0a", 14) == 0)
811 printk(KERN_DEBUG "end pubic key hit: %u", size);
812 */
44d6f47a
JE
813 }
814 }
815 return 0;
816}
817
44d6f47a 818/* check for xdcc */
569643ac 819static unsigned int
30ba7eb4
JS
820search_xdcc(const unsigned char *payload, const unsigned int plen,
821 const struct ipt_p2p_info *info)
44d6f47a 822{
30ba7eb4
JS
823 struct ts_state state;
824 unsigned int pos;
c237fe24 825
dc05fc62
JS
826 /* search in small packets only */
827 if (plen <= 20 || plen >= 200)
828 return 0;
829 if (memcmp(payload, "PRIVMSG ", 8) != 0 || !iscrlf(&payload[plen - 2]))
830 return 0;
831 /*
832 * It seems to be an IRC private message, check for xdcc command
833 */
30ba7eb4
JS
834 pos = textsearch_find_continuous(info->ts_conf_xdcc,
835 &state, &payload[8], plen - 8);
836 if (pos != UINT_MAX)
837 return IPP2P_XDCC * 100 + 0;
838
44d6f47a
JE
839 return 0;
840}
841
842/* search for waste */
569643ac 843static unsigned int
30ba7eb4
JS
844search_waste(const unsigned char *payload, const unsigned int plen,
845 const struct ipt_p2p_info *info)
44d6f47a 846{
38a85247 847 if (plen >= 9 && memcmp(payload, "GET.sha1:", 9) == 0)
c237fe24 848 return IPP2P_WASTE * 100 + 0;
44d6f47a
JE
849
850 return 0;
851}
852
569643ac
JE
853static const struct {
854 unsigned int command;
569643ac 855 unsigned int packet_len;
30ba7eb4
JS
856 unsigned int (*function_name)(const unsigned char *, const unsigned int,
857 const struct ipt_p2p_info *);
44d6f47a 858} matchlist[] = {
a1d307e3 859 {IPP2P_EDK, 20, search_all_edk},
01df89eb
JE
860 {IPP2P_DATA_KAZAA, 200, search_kazaa}, /* exp */
861 {IPP2P_DATA_EDK, 60, search_edk}, /* exp */
862 {IPP2P_DATA_DC, 26, search_dc}, /* exp */
a1d307e3 863 {IPP2P_DC, 5, search_all_dc},
01df89eb 864 {IPP2P_DATA_GNU, 40, search_gnu}, /* exp */
a1d307e3
JE
865 {IPP2P_GNU, 5, search_all_gnu},
866 {IPP2P_KAZAA, 5, search_all_kazaa},
867 {IPP2P_BIT, 20, search_bittorrent},
868 {IPP2P_APPLE, 5, search_apple},
869 {IPP2P_SOUL, 5, search_soul},
870 {IPP2P_WINMX, 2, search_winmx},
871 {IPP2P_ARES, 5, search_ares},
872 {IPP2P_MUTE, 200, search_mute},
873 {IPP2P_WASTE, 5, search_waste},
874 {IPP2P_XDCC, 5, search_xdcc},
c237fe24 875 {0},
44d6f47a
JE
876};
877
569643ac
JE
878static const struct {
879 unsigned int command;
569643ac 880 unsigned int packet_len;
30ba7eb4
JS
881 unsigned int (*function_name)(const unsigned char *, const unsigned int,
882 const struct ipt_p2p_info *);
44d6f47a 883} udp_list[] = {
a1d307e3
JE
884 {IPP2P_KAZAA, 14, udp_search_kazaa},
885 {IPP2P_BIT, 23, udp_search_bit},
886 {IPP2P_GNU, 11, udp_search_gnu},
887 {IPP2P_EDK, 9, udp_search_edk},
888 {IPP2P_DC, 12, udp_search_directconnect},
c237fe24 889 {0},
44d6f47a
JE
890};
891
ad554f10 892static void
f144c2eb
JE
893ipp2p_print_result_tcp4(const union nf_inet_addr *saddr, short sport,
894 const union nf_inet_addr *daddr, short dport,
baa9e72b 895 bool p2p_result, unsigned int hlen)
ad554f10
JS
896{
897 printk("IPP2P.debug:TCP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %u\n",
898 p2p_result, &saddr->ip, sport, &daddr->ip, dport, hlen);
899}
900
baa9e72b 901static void
f144c2eb
JE
902ipp2p_print_result_tcp6(const union nf_inet_addr *saddr, short sport,
903 const union nf_inet_addr *daddr, short dport,
baa9e72b
JE
904 bool p2p_result, unsigned int hlen)
905{
906 printk("IPP2P.debug:TCP-match: %d from: %pI6:%hu to: %pI6:%hu Length: %u\n",
907 p2p_result, &saddr->in6, sport, &daddr->in6, dport, hlen);
908}
909
f68c44f2
JS
910static bool
911ipp2p_mt_tcp(const struct ipt_p2p_info *info, const struct tcphdr *tcph,
912 const unsigned char *haystack, unsigned int hlen,
ad554f10 913 const struct ipp2p_result_printer *rp)
f68c44f2
JS
914{
915 size_t tcph_len = tcph->doff * 4;
dc05fc62 916 int i;
f68c44f2
JS
917
918 if (tcph->fin) return 0; /* if FIN bit is set bail out */
919 if (tcph->syn) return 0; /* if SYN bit is set bail out */
920 if (tcph->rst) return 0; /* if RST bit is set bail out */
921
922 if (hlen < tcph_len) {
923 if (info->debug)
924 pr_info("TCP header indicated packet larger than it is\n");
925 return 0;
926 }
927 if (hlen == tcph_len)
928 return 0;
929
930 haystack += tcph_len;
931 hlen -= tcph_len;
932
dc05fc62
JS
933 for (i = 0; matchlist[i].command; ++i) {
934 if ((info->cmd & matchlist[i].command) != matchlist[i].command)
935 continue;
936 if (hlen <= matchlist[i].packet_len)
937 continue;
30ba7eb4 938 if (matchlist[i].function_name(haystack, hlen, info)) {
dc05fc62
JS
939 if (info->debug)
940 print_result(rp, true, hlen);
941 return true;
f68c44f2 942 }
f68c44f2 943 }
dc05fc62 944 return false;
f68c44f2
JS
945}
946
ad554f10 947static void
f144c2eb
JE
948ipp2p_print_result_udp4(const union nf_inet_addr *saddr, short sport,
949 const union nf_inet_addr *daddr, short dport,
baa9e72b 950 bool p2p_result, unsigned int hlen)
ad554f10
JS
951{
952 printk("IPP2P.debug:UDP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %u\n",
953 p2p_result, &saddr->ip, sport, &daddr->ip, dport, hlen);
954}
955
baa9e72b 956static void
f144c2eb
JE
957ipp2p_print_result_udp6(const union nf_inet_addr *saddr, short sport,
958 const union nf_inet_addr *daddr, short dport,
baa9e72b
JE
959 bool p2p_result, unsigned int hlen)
960{
961 printk("IPP2P.debug:UDP-match: %d from: %pI6:%hu to: %pI6:%hu Length: %u\n",
962 p2p_result, &saddr->in6, sport, &daddr->in6, dport, hlen);
963}
964
f68c44f2
JS
965static bool
966ipp2p_mt_udp(const struct ipt_p2p_info *info, const struct udphdr *udph,
967 const unsigned char *haystack, unsigned int hlen,
ad554f10 968 const struct ipp2p_result_printer *rp)
f68c44f2
JS
969{
970 size_t udph_len = sizeof(*udph);
dc05fc62 971 int i;
f68c44f2
JS
972
973 if (hlen < udph_len) {
974 if (info->debug)
975 pr_info("UDP header indicated packet larger than it is\n");
976 return 0;
977 }
978 if (hlen == udph_len)
979 return 0;
980
981 haystack += udph_len;
982 hlen -= udph_len;
983
dc05fc62
JS
984 for (i = 0; udp_list[i].command; ++i) {
985 if ((info->cmd & udp_list[i].command) != udp_list[i].command)
986 continue;
987 if (hlen <= udp_list[i].packet_len)
988 continue;
30ba7eb4 989 if (udp_list[i].function_name(haystack, hlen, info)) {
dc05fc62
JS
990 if (info->debug)
991 print_result(rp, true, hlen);
992 return true;
f68c44f2 993 }
f68c44f2 994 }
dc05fc62 995 return false;
f68c44f2
JS
996}
997
cc23d0a2 998static bool
9a18a05d 999ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
44d6f47a 1000{
ee7e4f5a 1001 const struct ipt_p2p_info *info = par->matchinfo;
ad554f10 1002 struct ipp2p_result_printer printer;
f144c2eb 1003 union nf_inet_addr saddr, daddr;
f68c44f2
JS
1004 const unsigned char *haystack; /* packet data */
1005 unsigned int hlen; /* packet data length */
baa9e72b
JE
1006 uint8_t family = xt_family(par);
1007 int protocol;
c237fe24 1008
baa9e72b
JE
1009 /*
1010 * must not be a fragment
1011 *
1012 * NB, `par->fragoff` may be zero for a fragmented IPv6 packet.
1013 * However, in that case the later call to `ipv6_find_hdr` will not find
1014 * a transport protocol, and so we will return 0 there.
1015 */
ee7e4f5a 1016 if (par->fragoff != 0) {
c237fe24 1017 if (info->debug)
ee7e4f5a 1018 printk("IPP2P.match: offset found %d\n", par->fragoff);
c237fe24
JE
1019 return 0;
1020 }
1021
1022 /* make sure that skb is linear */
1023 if (skb_is_nonlinear(skb)) {
1024 if (info->debug)
1025 printk("IPP2P.match: nonlinear skb found\n");
1026 return 0;
1027 }
44d6f47a 1028
baa9e72b
JE
1029 if (family == NFPROTO_IPV4) {
1030 const struct iphdr *ip = ip_hdr(skb);
1031 saddr.ip = ip->saddr;
1032 daddr.ip = ip->daddr;
1033 protocol = ip->protocol;
1034 hlen = ip_transport_len(skb);
1035 } else {
1036 const struct ipv6hdr *ip = ipv6_hdr(skb);
1037 int thoff = 0;
44d6f47a 1038
baa9e72b
JE
1039 saddr.in6 = ip->saddr;
1040 daddr.in6 = ip->daddr;
1041 protocol = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
1042 if (protocol < 0)
1043 return 0;
1044 hlen = ipv6_transport_len(skb);
1045 }
ad554f10
JS
1046
1047 printer.saddr = &saddr;
1048 printer.daddr = &daddr;
baa9e72b 1049 haystack = skb_transport_header(skb);
ad554f10 1050
baa9e72b 1051 switch (protocol) {
c237fe24 1052 case IPPROTO_TCP: /* what to do with a TCP packet */
44d6f47a 1053 {
f68c44f2 1054 const struct tcphdr *tcph = tcp_hdr(skb);
90835b11 1055
ad554f10
JS
1056 printer.sport = ntohs(tcph->source);
1057 printer.dport = ntohs(tcph->dest);
baa9e72b
JE
1058 printer.print = family == NFPROTO_IPV6 ?
1059 ipp2p_print_result_tcp6 : ipp2p_print_result_tcp4;
ad554f10 1060 return ipp2p_mt_tcp(info, tcph, haystack, hlen, &printer);
44d6f47a 1061 }
f68c44f2 1062 case IPPROTO_UDP: /* what to do with a UDP packet */
939d3c8b 1063 case IPPROTO_UDPLITE:
44d6f47a 1064 {
f68c44f2 1065 const struct udphdr *udph = udp_hdr(skb);
c237fe24 1066
ad554f10
JS
1067 printer.sport = ntohs(udph->source);
1068 printer.dport = ntohs(udph->dest);
baa9e72b
JE
1069 printer.print = family == NFPROTO_IPV6 ?
1070 ipp2p_print_result_udp6 : ipp2p_print_result_udp4;
ad554f10 1071 return ipp2p_mt_udp(info, udph, haystack, hlen, &printer);
c237fe24 1072 }
c237fe24
JE
1073 default:
1074 return 0;
44d6f47a 1075 }
44d6f47a
JE
1076}
1077
30ba7eb4
JS
1078static int ipp2p_mt_check(const struct xt_mtchk_param *par)
1079{
1080 struct ipt_p2p_info *info = par->matchinfo;
1081 struct ts_config *ts_conf;
1082
1083 ts_conf = textsearch_prepare("bm", "\x20\x22", 2,
1084 GFP_KERNEL, TS_AUTOLOAD);
1085 if (IS_ERR(ts_conf))
1086 goto err_return;
1087 info->ts_conf_winmx = ts_conf;
1088
1089 ts_conf = textsearch_prepare("bm", "info_hash=", 10,
1090 GFP_KERNEL, TS_AUTOLOAD);
1091 if (IS_ERR(ts_conf))
1092 goto err_ts_destroy_winmx;
1093 info->ts_conf_bt_info_hash = ts_conf;
1094
1095 ts_conf = textsearch_prepare("bm", "peer_id=", 8,
1096 GFP_KERNEL, TS_AUTOLOAD);
1097 if (IS_ERR(ts_conf))
1098 goto err_ts_destroy_bt_info_hash;
1099 info->ts_conf_bt_peer_id = ts_conf;
1100
1101 ts_conf = textsearch_prepare("bm", "passkey", 8,
1102 GFP_KERNEL, TS_AUTOLOAD);
1103 if (IS_ERR(ts_conf))
1104 goto err_ts_destroy_bt_peer_id;
1105 info->ts_conf_bt_passkey = ts_conf;
1106
1107 ts_conf = textsearch_prepare("bm", "\r\nX-Gnutella-", 13,
1108 GFP_KERNEL, TS_AUTOLOAD);
1109 if (IS_ERR(ts_conf))
1110 goto err_ts_destroy_bt_passkey;
1111 info->ts_conf_gnu_x_gnutella = ts_conf;
1112
1113 ts_conf = textsearch_prepare("bm", "\r\nX-Queue-", 10,
1114 GFP_KERNEL, TS_AUTOLOAD);
1115 if (IS_ERR(ts_conf))
1116 goto err_ts_destroy_gnu_x_gnutella;
1117 info->ts_conf_gnu_x_queue = ts_conf;
1118
1119 ts_conf = textsearch_prepare("bm", "\r\nX-Kazaa-Username: ", 20,
1120 GFP_KERNEL, TS_AUTOLOAD);
1121 if (IS_ERR(ts_conf))
1122 goto err_ts_destroy_gnu_x_queue;
1123 info->ts_conf_kz_x_kazaa_username = ts_conf;
1124
1125 ts_conf = textsearch_prepare("bm", "\r\nUser-Agent: PeerEnabler/", 26,
1126 GFP_KERNEL, TS_AUTOLOAD);
1127 if (IS_ERR(ts_conf))
1128 goto err_ts_destroy_kazaa_x_kazaa_username;
1129 info->ts_conf_kz_user_agent = ts_conf;
1130
1131 ts_conf = textsearch_prepare("bm", ":xdcc send #", 12,
1132 GFP_KERNEL, TS_AUTOLOAD);
1133 if (IS_ERR(ts_conf))
1134 goto err_ts_destroy_kazaa_user_agent;
1135 info->ts_conf_xdcc = ts_conf;
1136
1137 return 0;
1138
1139err_ts_destroy_kazaa_user_agent:
1140 textsearch_destroy(info->ts_conf_kz_user_agent);
1141
1142err_ts_destroy_kazaa_x_kazaa_username:
1143 textsearch_destroy(info->ts_conf_kz_x_kazaa_username);
1144
1145err_ts_destroy_gnu_x_queue:
1146 textsearch_destroy(info->ts_conf_gnu_x_queue);
1147
1148err_ts_destroy_gnu_x_gnutella:
1149 textsearch_destroy(info->ts_conf_gnu_x_gnutella);
1150
1151err_ts_destroy_bt_passkey:
1152 textsearch_destroy(info->ts_conf_bt_passkey);
1153
1154err_ts_destroy_bt_peer_id:
1155 textsearch_destroy(info->ts_conf_bt_peer_id);
1156
1157err_ts_destroy_bt_info_hash:
1158 textsearch_destroy(info->ts_conf_bt_info_hash);
1159
1160err_ts_destroy_winmx:
1161 textsearch_destroy(info->ts_conf_winmx);
1162
1163err_return:
1164 return PTR_ERR(ts_conf);
1165}
1166
1167static void ipp2p_mt_destroy(const struct xt_mtdtor_param *par)
1168{
1169 struct ipt_p2p_info *info = (struct ipt_p2p_info *) par->matchinfo;
1170
1171 textsearch_destroy(info->ts_conf_winmx);
1172 textsearch_destroy(info->ts_conf_bt_info_hash);
1173 textsearch_destroy(info->ts_conf_bt_peer_id);
1174 textsearch_destroy(info->ts_conf_bt_passkey);
1175 textsearch_destroy(info->ts_conf_gnu_x_gnutella);
1176 textsearch_destroy(info->ts_conf_gnu_x_queue);
1177 textsearch_destroy(info->ts_conf_kz_x_kazaa_username);
1178 textsearch_destroy(info->ts_conf_kz_user_agent);
1179 textsearch_destroy(info->ts_conf_xdcc);
1180}
1181
baa9e72b
JE
1182static struct xt_match ipp2p_mt_reg[] __read_mostly = {
1183 {
1184 .name = "ipp2p",
1185 .revision = 1,
1186 .family = NFPROTO_IPV4,
30ba7eb4 1187 .checkentry = ipp2p_mt_check,
baa9e72b 1188 .match = ipp2p_mt,
30ba7eb4 1189 .destroy = ipp2p_mt_destroy,
baa9e72b
JE
1190 .matchsize = sizeof(struct ipt_p2p_info),
1191 .me = THIS_MODULE,
1192 },
1193 {
1194 .name = "ipp2p",
1195 .revision = 1,
1196 .family = NFPROTO_IPV6,
30ba7eb4 1197 .checkentry = ipp2p_mt_check,
baa9e72b 1198 .match = ipp2p_mt,
30ba7eb4 1199 .destroy = ipp2p_mt_destroy,
baa9e72b
JE
1200 .matchsize = sizeof(struct ipt_p2p_info),
1201 .me = THIS_MODULE,
1202 },
44d6f47a
JE
1203};
1204
cc23d0a2 1205static int __init ipp2p_mt_init(void)
44d6f47a 1206{
baa9e72b 1207 return xt_register_matches(ipp2p_mt_reg, ARRAY_SIZE(ipp2p_mt_reg));
44d6f47a 1208}
c237fe24 1209
cc23d0a2 1210static void __exit ipp2p_mt_exit(void)
44d6f47a 1211{
baa9e72b 1212 xt_unregister_matches(ipp2p_mt_reg, ARRAY_SIZE(ipp2p_mt_reg));
44d6f47a 1213}
c237fe24 1214
cc23d0a2
JE
1215module_init(ipp2p_mt_init);
1216module_exit(ipp2p_mt_exit);
29139c14 1217MODULE_ALIAS("ipt_ipp2p");
71599a0f 1218MODULE_ALIAS("ip6t_ipp2p");