]> git.ipfire.org Git - thirdparty/xtables-addons.git/blame - extensions/xt_ipp2p.c
xt_SYSRQ: fix UDPLITE header lookup in IPv6
[thirdparty/xtables-addons.git] / extensions / xt_ipp2p.c
CommitLineData
44d6f47a
JE
1#include <linux/module.h>
2#include <linux/version.h>
3#include <linux/netfilter_ipv4/ip_tables.h>
4#include <net/tcp.h>
5#include <net/udp.h>
0712d0fd 6#include <asm/unaligned.h>
44d6f47a
JE
7#include "xt_ipp2p.h"
8#include "compat_xtables.h"
9
c237fe24
JE
10//#define IPP2P_DEBUG_ARES
11//#define IPP2P_DEBUG_SOUL
12//#define IPP2P_DEBUG_WINMX
13
74e7eb28
JE
14#define get_u8(X, O) (*(const __u8 *)((X) + O))
15#define get_u16(X, O) get_unaligned((const __u16 *)((X) + O))
16#define get_u32(X, O) get_unaligned((const __u32 *)((X) + O))
44d6f47a
JE
17
18MODULE_AUTHOR("Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>");
19MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
20MODULE_LICENSE("GPL");
21
c237fe24 22/* Search for UDP eDonkey/eMule/Kad commands */
569643ac 23static unsigned int
cb407ce7 24udp_search_edk(const unsigned char *t, const unsigned int packet_len)
44d6f47a 25{
17a03128
CB
26 if (packet_len < 4)
27 return 0;
28
44d6f47a 29 switch (t[0]) {
c237fe24
JE
30 case 0xe3:
31 /* edonkey */
32 switch (t[1]) {
33 /* client -> server status request */
34 case 0x96:
c66d291e 35 if (packet_len == 6)
c237fe24 36 return IPP2P_EDK * 100 + 50;
44d6f47a 37 break;
c237fe24
JE
38
39 /* server -> client status request */
40 case 0x97:
c66d291e 41 if (packet_len == 34)
c237fe24
JE
42 return IPP2P_EDK * 100 + 51;
43 break;
44
45 /* server description request */
46 /* e3 2a ff f0 .. | size == 6 */
47 case 0xa2:
c66d291e 48 if (packet_len == 6 &&
c237fe24
JE
49 get_u16(t, 2) == __constant_htons(0xfff0))
50 return IPP2P_EDK * 100 + 52;
51 break;
52
53 /* server description response */
54 /* e3 a3 ff f0 .. | size > 40 && size < 200 */
55 /*
56 case 0xa3:
57 return IPP2P_EDK * 100 + 53;
58 break;
59 */
60
61 case 0x9a:
c66d291e 62 if (packet_len == 18)
c237fe24
JE
63 return IPP2P_EDK * 100 + 54;
64 break;
65
66 case 0x92:
c66d291e 67 if (packet_len == 10)
c237fe24 68 return IPP2P_EDK * 100 + 55;
44d6f47a
JE
69 break;
70 }
c237fe24
JE
71 break;
72
73 case 0xe4:
74 switch (t[1]) {
c66d291e 75 /* e4 20 .. | size == 35 */
c237fe24 76 case 0x20:
c66d291e 77 if (packet_len == 35 && t[2] != 0x00 && t[34] != 0x00)
c237fe24
JE
78 return IPP2P_EDK * 100 + 60;
79 break;
44d6f47a 80
c66d291e 81 /* e4 00 .. 00 | size == 27 ? */
c237fe24 82 case 0x00:
c66d291e 83 if (packet_len == 27 && t[26] == 0x00)
c237fe24 84 return IPP2P_EDK * 100 + 61;
44d6f47a 85 break;
c237fe24 86
c66d291e 87 /* e4 10 .. 00 | size == 27 ? */
c237fe24 88 case 0x10:
c66d291e 89 if (packet_len == 27 && t[26] == 0x00)
c237fe24 90 return IPP2P_EDK * 100 + 62;
44d6f47a 91 break;
c237fe24 92
c66d291e 93 /* e4 18 .. 00 | size == 27 ? */
c237fe24 94 case 0x18:
c66d291e 95 if (packet_len == 27 && t[26] == 0x00)
c237fe24 96 return IPP2P_EDK * 100 + 63;
44d6f47a 97 break;
c237fe24 98
c66d291e 99 /* e4 52 .. | size = 36 */
c237fe24 100 case 0x52:
c66d291e 101 if (packet_len == 36)
c237fe24 102 return IPP2P_EDK * 100 + 64;
44d6f47a 103 break;
c237fe24
JE
104
105 /* e4 58 .. | size == 6 */
106 case 0x58:
c66d291e 107 if (packet_len == 6)
c237fe24 108 return IPP2P_EDK * 100 + 65;
44d6f47a 109 break;
c237fe24
JE
110
111 /* e4 59 .. | size == 2 */
112 case 0x59:
c66d291e 113 if (packet_len == 2)
c237fe24 114 return IPP2P_EDK * 100 + 66;
44d6f47a 115 break;
c237fe24 116
c66d291e 117 /* e4 28 .. | packet_len == 49,69,94,119... */
c237fe24 118 case 0x28:
c66d291e 119 if ((packet_len - 44) % 25 == 0)
c237fe24 120 return IPP2P_EDK * 100 + 67;
44d6f47a 121 break;
c237fe24
JE
122
123 /* e4 50 xx xx | size == 4 */
124 case 0x50:
c66d291e 125 if (packet_len == 4)
c237fe24
JE
126 return IPP2P_EDK * 100 + 68;
127 break;
128
129 /* e4 40 xx xx | size == 48 */
130 case 0x40:
c66d291e 131 if (packet_len == 48)
c237fe24 132 return IPP2P_EDK * 100 + 69;
44d6f47a 133 break;
44d6f47a 134 }
c237fe24 135 break;
44d6f47a 136 }
c237fe24
JE
137 return 0;
138}
139
140/* Search for UDP Gnutella commands */
569643ac 141static unsigned int
cb407ce7 142udp_search_gnu(const unsigned char *t, const unsigned int packet_len)
c237fe24 143{
17a03128 144 if (packet_len >= 3 && memcmp(t, "GND", 3) == 0)
c237fe24 145 return IPP2P_GNU * 100 + 51;
17a03128 146 if (packet_len >= 9 && memcmp(t, "GNUTELLA ", 9) == 0)
c237fe24
JE
147 return IPP2P_GNU * 100 + 52;
148 return 0;
149}
150
151/* Search for UDP KaZaA commands */
569643ac 152static unsigned int
cb407ce7 153udp_search_kazaa(const unsigned char *t, const unsigned int packet_len)
c237fe24 154{
17a03128
CB
155 if (packet_len < 6)
156 return 0;
157 if (memcmp(t + packet_len - 6, "KaZaA\x00", 6) == 0)
158 return IPP2P_KAZAA * 100 + 50;
c237fe24
JE
159 return 0;
160}
161
162/* Search for UDP DirectConnect commands */
cb407ce7 163static unsigned int udp_search_directconnect(const unsigned char *t,
569643ac 164 const unsigned int packet_len)
c237fe24 165{
17a03128
CB
166 if (packet_len < 5)
167 return 0;
168 if (t[0] == 0x24 && t[packet_len-1] == 0x7c) {
169 if (memcmp(&t[1], "SR ", 3) == 0)
c237fe24 170 return IPP2P_DC * 100 + 60;
17a03128 171 if (packet_len >= 7 && memcmp(&t[1], "Ping ", 5) == 0)
c237fe24
JE
172 return IPP2P_DC * 100 + 61;
173 }
174 return 0;
175}
176
177/* Search for UDP BitTorrent commands */
569643ac
JE
178static unsigned int
179udp_search_bit(const unsigned char *haystack, const unsigned int packet_len)
c237fe24
JE
180{
181 switch (packet_len) {
c66d291e 182 case 16:
c237fe24 183 /* ^ 00 00 04 17 27 10 19 80 */
c66d291e
CB
184 if (ntohl(get_u32(haystack, 0)) == 0x00000417 &&
185 ntohl(get_u32(haystack, 4)) == 0x27101980)
c237fe24
JE
186 return IPP2P_BIT * 100 + 50;
187 break;
c66d291e
CB
188 case 36:
189 if (get_u32(haystack, 8) == __constant_htonl(0x00000400) &&
190 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24 191 return IPP2P_BIT * 100 + 51;
c66d291e 192 if (get_u32(haystack, 8) == __constant_htonl(0x00000400))
c237fe24
JE
193 return IPP2P_BIT * 100 + 61;
194 break;
c66d291e
CB
195 case 57:
196 if (get_u32(haystack, 8) == __constant_htonl(0x00000404) &&
197 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24 198 return IPP2P_BIT * 100 + 52;
c66d291e 199 if (get_u32(haystack, 8) == __constant_htonl(0x00000404))
c237fe24
JE
200 return IPP2P_BIT * 100 + 62;
201 break;
c66d291e
CB
202 case 59:
203 if (get_u32(haystack, 8) == __constant_htonl(0x00000406) &&
204 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24 205 return (IPP2P_BIT * 100 + 53);
c66d291e 206 if (get_u32(haystack, 8) == __constant_htonl(0x00000406))
c237fe24
JE
207 return (IPP2P_BIT * 100 + 63);
208 break;
c66d291e
CB
209 case 203:
210 if (get_u32(haystack, 0) == __constant_htonl(0x00000405))
c237fe24
JE
211 return IPP2P_BIT * 100 + 54;
212 break;
c66d291e
CB
213 case 21:
214 if (get_u32(haystack, 0) == __constant_htonl(0x00000401))
c237fe24
JE
215 return IPP2P_BIT * 100 + 55;
216 break;
c66d291e
CB
217 case 44:
218 if (get_u32(haystack, 0) == __constant_htonl(0x00000827) &&
219 get_u32(haystack, 4) == __constant_htonl(0x37502950))
c237fe24
JE
220 return IPP2P_BIT * 100 + 80;
221 break;
222 default:
223 /* this packet does not have a constant size */
c66d291e
CB
224 if (packet_len >= 32 &&
225 get_u32(haystack, 8) == __constant_htonl(0x00000402) &&
226 get_u32(haystack, 28) == __constant_htonl(0x00000104))
c237fe24
JE
227 return IPP2P_BIT * 100 + 56;
228 break;
229 }
230
231 /* some extra-bitcomet rules: "d1:" [a|r] "d2:id20:" */
c66d291e
CB
232 if (packet_len > 22 && get_u8(haystack, 0) == 'd' &&
233 get_u8(haystack, 1) == '1' && get_u8(haystack, 2) == ':')
234 if (get_u8(haystack, 3) == 'a' ||
235 get_u8(haystack, 3) == 'r')
236 if (memcmp(haystack + 4, "d2:id20:", 8) == 0)
c237fe24
JE
237 return IPP2P_BIT * 100 + 57;
238
44d6f47a
JE
239#if 0
240 /* bitlord rules */
c66d291e 241 /* packetlen must be bigger than 32 */
44d6f47a 242 /* first 4 bytes are zero */
c66d291e 243 if (packet_len > 32 && get_u32(haystack, 0) == 0x00000000) {
44d6f47a 244 /* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00*/
c66d291e
CB
245 if (get_u32(haystack, 4) == 0x00000000 &&
246 get_u32(haystack, 8) == 0x00010000 &&
247 get_u32(haystack, 16) == 0x00000000)
c237fe24
JE
248 return IPP2P_BIT * 100 + 71;
249
44d6f47a 250 /* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00*/
c66d291e
CB
251 if (get_u32(haystack, 4) == 0x00000001 &&
252 get_u32(haystack, 8) == 0x000d0000 &&
253 get_u32(haystack, 16) == 0x00000000)
c237fe24 254 return IPP2P_BIT * 100 + 71;
44d6f47a
JE
255 }
256#endif
257
c237fe24
JE
258 return 0;
259}
44d6f47a 260
c237fe24 261/* Search for Ares commands */
569643ac
JE
262static unsigned int
263search_ares(const unsigned char *payload, const unsigned int plen)
44d6f47a 264{
17a03128
CB
265 if (plen < 3)
266 return 0;
44d6f47a 267 /* all ares packets start with */
c237fe24
JE
268 if (payload[1] == 0 && plen - payload[0] == 3) {
269 switch (payload[2]) {
270 case 0x5a:
271 /* ares connect */
272 if (plen == 6 && payload[5] == 0x05)
273 return IPP2P_ARES * 100 + 1;
274 break;
275 case 0x09:
276 /*
277 * ares search, min 3 chars --> 14 bytes
278 * lets define a search can be up to 30 chars
279 * --> max 34 bytes
280 */
281 if (plen >= 14 && plen <= 34)
282 return IPP2P_ARES * 100 + 1;
283 break;
44d6f47a 284#ifdef IPP2P_DEBUG_ARES
c237fe24
JE
285 default:
286 printk(KERN_DEBUG "Unknown Ares command %x "
287 "recognized, len: %u\n",
288 (unsigned int)payload[2], plen);
289#endif
44d6f47a
JE
290 }
291 }
292
c237fe24 293#if 0
44d6f47a
JE
294 /* found connect packet: 03 00 5a 04 03 05 */
295 /* new version ares 1.8: 03 00 5a xx xx 05 */
c237fe24
JE
296 if (plen == 6)
297 /* possible connect command */
298 if (payload[0] == 0x03 && payload[1] == 0x00 &&
299 payload[2] == 0x5a && payload[5] == 0x05)
300 return IPP2P_ARES * 100 + 1;
301
302 if (plen == 60)
303 /* possible download command*/
304 if (payload[59] == 0x0a && payload[58] == 0x0a)
305 if (memcmp(t, "PUSH SHA1:", 10) == 0)
306 /* found download command */
307 return IPP2P_ARES * 100 + 2;
44d6f47a
JE
308#endif
309
c237fe24
JE
310 return 0;
311}
44d6f47a 312
c237fe24 313/* Search for SoulSeek commands */
569643ac
JE
314static unsigned int
315search_soul(const unsigned char *payload, const unsigned int plen)
44d6f47a 316{
17a03128
CB
317 if (plen < 8)
318 return 0;
c237fe24
JE
319 /* match: xx xx xx xx | xx = sizeof(payload) - 4 */
320 if (get_u32(payload, 0) == plen - 4) {
569643ac
JE
321 const uint32_t m = get_u32(payload, 4);
322
c237fe24
JE
323 /* match 00 yy yy 00, yy can be everything */
324 if (get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00) {
44d6f47a 325#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
326 printk(KERN_DEBUG "0: Soulseek command 0x%x "
327 "recognized\n", get_u32(payload, 4));
328#endif
329 return IPP2P_SOUL * 100 + 1;
330 }
331
332 /* next match: 01 yy 00 00 | yy can be everything */
333 if (get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000) {
44d6f47a 334#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
335 printk(KERN_DEBUG "1: Soulseek command 0x%x "
336 "recognized\n", get_u16(payload, 4));
337#endif
338 return IPP2P_SOUL * 100 + 2;
339 }
340
341 /* 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 */
342 /* try to do this in an intelligent way */
343 /* get all small commandos */
344 switch (m) {
44d6f47a
JE
345 case 7:
346 case 9:
347 case 22:
348 case 23:
349 case 26:
350 case 28:
351 case 50:
352 case 51:
353 case 60:
354 case 91:
355 case 92:
356 case 1001:
357#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
358 printk(KERN_DEBUG "2: Soulseek command 0x%x "
359 "recognized\n", get_u16(payload, 4));
360#endif
361 return IPP2P_SOUL * 100 + 3;
362 }
363
364 if (m > 0 && m < 6) {
44d6f47a 365#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
366 printk(KERN_DEBUG "3: Soulseek command 0x%x "
367 "recognized\n", get_u16(payload, 4));
368#endif
369 return IPP2P_SOUL * 100 + 4;
370 }
371
372 if (m > 12 && m < 19) {
44d6f47a 373#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
374 printk(KERN_DEBUG "4: Soulseek command 0x%x "
375 "recognized\n", get_u16(payload, 4));
376#endif
377 return IPP2P_SOUL * 100 + 5;
378 }
44d6f47a 379
c237fe24 380 if (m > 34 && m < 38) {
44d6f47a 381#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
382 printk(KERN_DEBUG "5: Soulseek command 0x%x "
383 "recognized\n", get_u16(payload, 4));
384#endif
385 return IPP2P_SOUL * 100 + 6;
386 }
44d6f47a 387
c237fe24 388 if (m > 39 && m < 47) {
44d6f47a 389#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
390 printk(KERN_DEBUG "6: Soulseek command 0x%x "
391 "recognized\n", get_u16(payload, 4));
392#endif
393 return IPP2P_SOUL * 100 + 7;
394 }
44d6f47a 395
c237fe24 396 if (m > 61 && m < 70) {
44d6f47a 397#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
398 printk(KERN_DEBUG "7: Soulseek command 0x%x "
399 "recognized\n", get_u16(payload, 4));
400#endif
401 return IPP2P_SOUL * 100 + 8;
402 }
44d6f47a
JE
403
404#ifdef IPP2P_DEBUG_SOUL
c237fe24
JE
405 printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first "
406 "16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",
407 get_u32(payload, 4), get_u16(payload, 4) >> 16,
408 get_u8(payload, 4) >> 24);
409#endif
410 }
411
44d6f47a
JE
412 /* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */
413 /* without size at the beginning !!! */
c237fe24 414 if (get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01) {
569643ac
JE
415 uint32_t y = get_u32(payload, 5);
416
44d6f47a 417 /* we need 19 chars + string */
c237fe24
JE
418 if (y + 19 <= plen) {
419 const unsigned char *w = payload + 9 + y;
420 if (get_u32(w, 0) == 0x01 &&
421 (get_u16(w, 4) == 0x4600 ||
422 get_u16(w, 4) == 0x5000) &&
423 get_u32(w, 6) == 0x00)
424 ;
44d6f47a
JE
425#ifdef IPP2P_DEBUG_SOUL
426 printk(KERN_DEBUG "Soulssek special client command recognized\n");
c237fe24
JE
427#endif
428 return IPP2P_SOUL * 100 + 9;
44d6f47a
JE
429 }
430 }
c237fe24 431 return 0;
44d6f47a
JE
432}
433
c237fe24 434/* Search for WinMX commands */
569643ac
JE
435static unsigned int
436search_winmx(const unsigned char *payload, const unsigned int plen)
44d6f47a 437{
c237fe24
JE
438 if (plen == 4 && memcmp(payload, "SEND", 4) == 0)
439 return IPP2P_WINMX * 100 + 1;
440 if (plen == 3 && memcmp(payload, "GET", 3) == 0)
441 return IPP2P_WINMX * 100 + 2;
442 /*
443 if (packet_len < head_len + 10)
444 return 0;
445 */
446 if (plen < 10)
447 return 0;
448
449 if (memcmp(payload, "SEND", 4) == 0 || memcmp(payload, "GET", 3) == 0) {
569643ac
JE
450 uint16_t c = 4;
451 const uint16_t end = plen - 2;
452 uint8_t count = 0;
c237fe24
JE
453
454 while (c < end) {
455 if (payload[c] == 0x20 && payload[c+1] == 0x22) {
456 c++;
457 count++;
458 if (count >= 2)
459 return IPP2P_WINMX * 100 + 3;
460 }
461 c++;
462 }
463 }
464
465 if (plen == 149 && payload[0] == '8') {
44d6f47a 466#ifdef IPP2P_DEBUG_WINMX
c237fe24 467 printk(KERN_INFO "maybe WinMX\n");
44d6f47a 468#endif
c237fe24
JE
469 if (get_u32(payload, 17) == 0 && get_u32(payload, 21) == 0 &&
470 get_u32(payload, 25) == 0 &&
471// get_u32(payload, 33) == __constant_htonl(0x71182b1a) &&
472// get_u32(payload, 37) == __constant_htonl(0x05050000) &&
473// get_u32(payload, 133) == __constant_htonl(0x31097edf) &&
474// get_u32(payload, 145) == __constant_htonl(0xdcb8f792))
475 get_u16(payload, 39) == 0 &&
476 get_u16(payload, 135) == __constant_htons(0x7edf) &&
477 get_u16(payload,147) == __constant_htons(0xf792))
478 {
44d6f47a 479#ifdef IPP2P_DEBUG_WINMX
c237fe24 480 printk(KERN_INFO "got WinMX\n");
44d6f47a 481#endif
c237fe24
JE
482 return IPP2P_WINMX * 100 + 4;
483 }
484 }
485 return 0;
486}
487
488/* Search for appleJuice commands */
569643ac
JE
489static unsigned int
490search_apple(const unsigned char *payload, const unsigned int plen)
44d6f47a 491{
c237fe24
JE
492 if (plen > 7 && payload[6] == 0x0d && payload[7] == 0x0a &&
493 memcmp(payload, "ajprot", 6) == 0)
494 return IPP2P_APPLE * 100;
495
496 return 0;
44d6f47a
JE
497}
498
c237fe24 499/* Search for BitTorrent commands */
569643ac
JE
500static unsigned int
501search_bittorrent(const unsigned char *payload, const unsigned int plen)
44d6f47a 502{
c237fe24
JE
503 if (plen > 20) {
504 /* test for match 0x13+"BitTorrent protocol" */
505 if (payload[0] == 0x13)
506 if (memcmp(payload + 1, "BitTorrent protocol", 19) == 0)
507 return IPP2P_BIT * 100;
c237fe24 508 /*
43864ac6
TT
509 * Any tracker command starts with GET / then *may be* some file on web server
510 * (e.g. announce.php or dupa.pl or whatever.cgi or NOTHING for tracker on root dir)
511 * but *must have* one (or more) of strings listed below (true for scrape and announce)
c237fe24
JE
512 */
513 if (memcmp(payload, "GET /", 5) == 0) {
43864ac6 514 if (HX_memmem(payload, plen, "info_hash=", 9) != NULL)
c237fe24 515 return IPP2P_BIT * 100 + 1;
43864ac6 516 if (HX_memmem(payload, plen, "peer_id=", 8) != NULL)
c237fe24 517 return IPP2P_BIT * 100 + 2;
43864ac6
TT
518 if (HX_memmem(payload, plen, "passkey=", 8) != NULL)
519 return IPP2P_BIT * 100 + 4;
c237fe24
JE
520 }
521 } else {
522 /* bitcomet encryptes the first packet, so we have to detect another
523 * one later in the flow */
304e5e52 524 /* first try failed, too many false positives */
c237fe24
JE
525 /*
526 if (size == 5 && get_u32(t, 0) == __constant_htonl(1) &&
527 t[4] < 3)
528 return IPP2P_BIT * 100 + 3;
529 */
530
531 /* second try: block request packets */
532 if (plen == 17 &&
533 get_u32(payload, 0) == __constant_htonl(0x0d) &&
534 payload[4] == 0x06 &&
535 get_u32(payload,13) == __constant_htonl(0x4000))
536 return IPP2P_BIT * 100 + 3;
44d6f47a 537 }
c237fe24
JE
538
539 return 0;
44d6f47a
JE
540}
541
c237fe24 542/* check for Kazaa get command */
569643ac
JE
543static unsigned int
544search_kazaa(const unsigned char *payload, const unsigned int plen)
44d6f47a 545{
17a03128
CB
546 if (plen < 13)
547 return 0;
c237fe24
JE
548 if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a &&
549 memcmp(payload, "GET /.hash=", 11) == 0)
550 return IPP2P_DATA_KAZAA * 100;
44d6f47a 551
c237fe24 552 return 0;
44d6f47a
JE
553}
554
c237fe24 555/* check for gnutella get command */
569643ac
JE
556static unsigned int
557search_gnu(const unsigned char *payload, const unsigned int plen)
44d6f47a 558{
17a03128
CB
559 if (plen < 11)
560 return 0;
c237fe24
JE
561 if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a) {
562 if (memcmp(payload, "GET /get/", 9) == 0)
563 return IPP2P_DATA_GNU * 100 + 1;
304e5e52 564 if (plen >= 15 && memcmp(payload, "GET /uri-res/", 13) == 0)
c237fe24
JE
565 return IPP2P_DATA_GNU * 100 + 2;
566 }
567 return 0;
44d6f47a
JE
568}
569
c237fe24 570/* check for gnutella get commands and other typical data */
569643ac
JE
571static unsigned int
572search_all_gnu(const unsigned char *payload, const unsigned int plen)
44d6f47a 573{
17a03128
CB
574 if (plen < 11)
575 return 0;
c237fe24 576 if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a) {
304e5e52 577 if (plen >= 19 && memcmp(payload, "GNUTELLA CONNECT/", 17) == 0)
c237fe24 578 return IPP2P_GNU * 100 + 1;
304e5e52 579 if (memcmp(payload, "GNUTELLA/", 9) == 0)
c237fe24
JE
580 return IPP2P_GNU * 100 + 2;
581
17a03128
CB
582 if (plen >= 22 && (memcmp(payload, "GET /get/", 9) == 0 ||
583 memcmp(payload, "GET /uri-res/", 13) == 0))
c237fe24 584 {
17a03128 585 unsigned int c;
569643ac 586
17a03128 587 for (c = 0; c < plen - 22; ++c)
3f7288ab
CB
588 if (payload[c] == 0x0d &&
589 payload[c+1] == 0x0a &&
c237fe24
JE
590 (memcmp(&payload[c+2], "X-Gnutella-", 11) == 0 ||
591 memcmp(&payload[c+2], "X-Queue:", 8) == 0))
592 return IPP2P_GNU * 100 + 3;
44d6f47a
JE
593 }
594 }
c237fe24 595 return 0;
44d6f47a
JE
596}
597
c237fe24 598/* check for KaZaA download commands and other typical data */
d01a5f3d 599/* plen is guaranteed to be >= 5 (see @matchlist) */
569643ac
JE
600static unsigned int
601search_all_kazaa(const unsigned char *payload, const unsigned int plen)
44d6f47a 602{
d01a5f3d
JE
603 uint16_t c, end, rem;
604
17a03128 605 if (plen < 7)
879e964f
JE
606 /* too short for anything we test for - early bailout */
607 return 0;
608
22db3bcb
JE
609 if (payload[plen-2] != 0x0d || payload[plen-1] != 0x0a)
610 return 0;
c237fe24 611
22db3bcb
JE
612 if (memcmp(payload, "GIVE ", 5) == 0)
613 return IPP2P_KAZAA * 100 + 1;
614
d01a5f3d
JE
615 if (memcmp(payload, "GET /", 5) != 0)
616 return 0;
617
4cdfd496
JE
618 if (plen < 18)
619 /* The next tests would not succeed anyhow. */
620 return 0;
621
d01a5f3d
JE
622 end = plen - 18;
623 rem = plen - 5;
624 for (c = 5; c < end; ++c, --rem) {
625 if (payload[c] != 0x0d)
626 continue;
627 if (payload[c+1] != 0x0a)
628 continue;
629 if (rem >= 18 &&
630 memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0)
631 return IPP2P_KAZAA * 100 + 2;
632 if (rem >= 24 &&
633 memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0)
634 return IPP2P_KAZAA * 100 + 2;
44d6f47a 635 }
22db3bcb 636
c237fe24 637 return 0;
44d6f47a
JE
638}
639
c237fe24 640/* fast check for edonkey file segment transfer command */
569643ac
JE
641static unsigned int
642search_edk(const unsigned char *payload, const unsigned int plen)
44d6f47a 643{
17a03128
CB
644 if (plen < 6)
645 return 0;
c237fe24
JE
646 if (payload[0] != 0xe3) {
647 return 0;
648 } else {
649 if (payload[5] == 0x47)
650 return IPP2P_DATA_EDK * 100;
651 else
652 return 0;
653 }
44d6f47a
JE
654}
655
c237fe24 656/* intensive but slower search for some edonkey packets including size-check */
569643ac
JE
657static unsigned int
658search_all_edk(const unsigned char *payload, const unsigned int plen)
44d6f47a 659{
17a03128
CB
660 if (plen < 6)
661 return 0;
c237fe24
JE
662 if (payload[0] != 0xe3) {
663 return 0;
664 } else {
17a03128 665 unsigned int cmd = get_u16(payload, 1);
c237fe24
JE
666
667 if (cmd == plen - 5) {
668 switch (payload[5]) {
669 case 0x01:
670 /* Client: hello or Server:hello */
671 return IPP2P_EDK * 100 + 1;
672 case 0x4c:
673 /* Client: Hello-Answer */
674 return IPP2P_EDK * 100 + 9;
675 }
676 }
677 return 0;
44d6f47a 678 }
44d6f47a
JE
679}
680
c237fe24 681/* fast check for Direct Connect send command */
569643ac
JE
682static unsigned int
683search_dc(const unsigned char *payload, const unsigned int plen)
44d6f47a 684{
17a03128
CB
685 if (plen < 6)
686 return 0;
c237fe24
JE
687 if (payload[0] != 0x24) {
688 return 0;
689 } else {
690 if (memcmp(&payload[1], "Send|", 5) == 0)
691 return IPP2P_DATA_DC * 100;
692 else
693 return 0;
694 }
44d6f47a
JE
695}
696
c237fe24 697/* intensive but slower check for all direct connect packets */
569643ac
JE
698static unsigned int
699search_all_dc(const unsigned char *payload, const unsigned int plen)
44d6f47a 700{
17a03128
CB
701 if (plen < 7)
702 return 0;
c237fe24
JE
703 if (payload[0] == 0x24 && payload[plen-1] == 0x7c) {
704 const unsigned char *t = &payload[1];
705
706 /* Client-Hub-Protocol */
707 if (memcmp(t, "Lock ", 5) == 0)
708 return IPP2P_DC * 100 + 1;
709
710 /*
711 * Client-Client-Protocol, some are already recognized by
712 * client-hub (like lock)
713 */
17a03128 714 if (plen >= 9 && memcmp(t, "MyNick ", 7) == 0)
c237fe24
JE
715 return IPP2P_DC * 100 + 38;
716 }
717 return 0;
44d6f47a
JE
718}
719
c237fe24 720/* check for mute */
569643ac
JE
721static unsigned int
722search_mute(const unsigned char *payload, const unsigned int plen)
44d6f47a 723{
c237fe24
JE
724 if (plen == 209 || plen == 345 || plen == 473 || plen == 609 ||
725 plen == 1121) {
726 //printk(KERN_DEBUG "size hit: %u", size);
727 if (memcmp(payload,"PublicKey: ", 11) == 0) {
728 return IPP2P_MUTE * 100 + 0;
729 /*
730 if (memcmp(t + size - 14, "\x0aEndPublicKey\x0a", 14) == 0)
731 printk(KERN_DEBUG "end pubic key hit: %u", size);
732 */
44d6f47a
JE
733 }
734 }
735 return 0;
736}
737
44d6f47a 738/* check for xdcc */
569643ac
JE
739static unsigned int
740search_xdcc(const unsigned char *payload, const unsigned int plen)
44d6f47a
JE
741{
742 /* search in small packets only */
c237fe24
JE
743 if (plen > 20 && plen < 200 && payload[plen-1] == 0x0a &&
744 payload[plen-2] == 0x0d && memcmp(payload, "PRIVMSG ", 8) == 0)
44d6f47a 745 {
569643ac
JE
746 uint16_t x = 10;
747 const uint16_t end = plen - 13;
c237fe24
JE
748
749 /*
750 * is seems to be a irc private massage, chedck for
751 * xdcc command
752 */
753 while (x < end) {
44d6f47a 754 if (payload[x] == ':')
c237fe24
JE
755 if (memcmp(&payload[x+1], "xdcc send #", 11) == 0)
756 return IPP2P_XDCC * 100 + 0;
44d6f47a
JE
757 x++;
758 }
759 }
760 return 0;
761}
762
763/* search for waste */
569643ac
JE
764static unsigned int
765search_waste(const unsigned char *payload, const unsigned int plen)
44d6f47a 766{
c237fe24
JE
767 if (plen >= 8 && memcmp(payload, "GET.sha1:", 9) == 0)
768 return IPP2P_WASTE * 100 + 0;
44d6f47a
JE
769
770 return 0;
771}
772
569643ac
JE
773static const struct {
774 unsigned int command;
569643ac
JE
775 unsigned int packet_len;
776 unsigned int (*function_name)(const unsigned char *, const unsigned int);
44d6f47a 777} matchlist[] = {
a1d307e3 778 {IPP2P_EDK, 20, search_all_edk},
01df89eb
JE
779 {IPP2P_DATA_KAZAA, 200, search_kazaa}, /* exp */
780 {IPP2P_DATA_EDK, 60, search_edk}, /* exp */
781 {IPP2P_DATA_DC, 26, search_dc}, /* exp */
a1d307e3 782 {IPP2P_DC, 5, search_all_dc},
01df89eb 783 {IPP2P_DATA_GNU, 40, search_gnu}, /* exp */
a1d307e3
JE
784 {IPP2P_GNU, 5, search_all_gnu},
785 {IPP2P_KAZAA, 5, search_all_kazaa},
786 {IPP2P_BIT, 20, search_bittorrent},
787 {IPP2P_APPLE, 5, search_apple},
788 {IPP2P_SOUL, 5, search_soul},
789 {IPP2P_WINMX, 2, search_winmx},
790 {IPP2P_ARES, 5, search_ares},
791 {IPP2P_MUTE, 200, search_mute},
792 {IPP2P_WASTE, 5, search_waste},
793 {IPP2P_XDCC, 5, search_xdcc},
c237fe24 794 {0},
44d6f47a
JE
795};
796
569643ac
JE
797static const struct {
798 unsigned int command;
569643ac
JE
799 unsigned int packet_len;
800 unsigned int (*function_name)(const unsigned char *, const unsigned int);
44d6f47a 801} udp_list[] = {
a1d307e3
JE
802 {IPP2P_KAZAA, 14, udp_search_kazaa},
803 {IPP2P_BIT, 23, udp_search_bit},
804 {IPP2P_GNU, 11, udp_search_gnu},
805 {IPP2P_EDK, 9, udp_search_edk},
806 {IPP2P_DC, 12, udp_search_directconnect},
c237fe24 807 {0},
44d6f47a
JE
808};
809
cc23d0a2 810static bool
9a18a05d 811ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
44d6f47a 812{
ee7e4f5a 813 const struct ipt_p2p_info *info = par->matchinfo;
569643ac
JE
814 const unsigned char *haystack;
815 const struct iphdr *ip = ip_hdr(skb);
816 bool p2p_result = false;
817 int i = 0;
3c8131b9 818 unsigned int hlen = ntohs(ip->tot_len) - ip_hdrlen(skb); /* hlen = packet-data length */
c237fe24
JE
819
820 /* must not be a fragment */
ee7e4f5a 821 if (par->fragoff != 0) {
c237fe24 822 if (info->debug)
ee7e4f5a 823 printk("IPP2P.match: offset found %d\n", par->fragoff);
c237fe24
JE
824 return 0;
825 }
826
827 /* make sure that skb is linear */
828 if (skb_is_nonlinear(skb)) {
829 if (info->debug)
830 printk("IPP2P.match: nonlinear skb found\n");
831 return 0;
832 }
44d6f47a 833
3c8131b9 834 haystack = skb_network_header(skb) + ip_hdrlen(skb);
44d6f47a 835
c237fe24
JE
836 switch (ip->protocol) {
837 case IPPROTO_TCP: /* what to do with a TCP packet */
44d6f47a 838 {
fbbca687 839 const struct tcphdr *tcph = (const void *)ip + ip_hdrlen(skb);
c237fe24
JE
840
841 if (tcph->fin) return 0; /* if FIN bit is set bail out */
842 if (tcph->syn) return 0; /* if SYN bit is set bail out */
843 if (tcph->rst) return 0; /* if RST bit is set bail out */
844
845 haystack += tcph->doff * 4; /* get TCP-Header-Size */
430723ec
JE
846 if (tcph->doff * 4 > hlen) {
847 if (info->debug)
848 pr_info("TCP header indicated packet larger than it is\n");
849 hlen = 0;
850 } else {
851 hlen -= tcph->doff * 4;
852 }
c237fe24 853 while (matchlist[i].command) {
a1d307e3 854 if ((info->cmd & matchlist[i].command) == matchlist[i].command &&
c237fe24
JE
855 hlen > matchlist[i].packet_len)
856 {
857 p2p_result = matchlist[i].function_name(haystack, hlen);
858 if (p2p_result) {
859 if (info->debug)
860 printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
861 p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
862 return p2p_result;
863 }
864 }
865 i++;
866 }
867 return p2p_result;
44d6f47a 868 }
c237fe24
JE
869
870 case IPPROTO_UDP: /* what to do with an UDP packet */
44d6f47a 871 {
fbbca687 872 const struct udphdr *udph = (const void *)ip + ip_hdrlen(skb);
c237fe24 873
c66d291e
CB
874 haystack += sizeof(*udph);
875 if (sizeof(*udph) > hlen) {
876 if (info->debug)
877 pr_info("UDP header indicated packet larger than it is\n");
878 hlen = 0;
879 } else {
880 hlen -= sizeof(*udph);
881 }
882
c237fe24 883 while (udp_list[i].command) {
a1d307e3 884 if ((info->cmd & udp_list[i].command) == udp_list[i].command &&
c237fe24
JE
885 hlen > udp_list[i].packet_len)
886 {
887 p2p_result = udp_list[i].function_name(haystack, hlen);
888 if (p2p_result) {
889 if (info->debug)
890 printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
891 p2p_result, NIPQUAD(ip->saddr), ntohs(udph->source), NIPQUAD(ip->daddr), ntohs(udph->dest), hlen);
892 return p2p_result;
893 }
894 }
895 i++;
44d6f47a 896 }
c237fe24
JE
897 return p2p_result;
898 }
899
900 default:
901 return 0;
44d6f47a 902 }
44d6f47a
JE
903}
904
cc23d0a2 905static struct xt_match ipp2p_mt_reg __read_mostly = {
c237fe24 906 .name = "ipp2p",
137ecb98 907 .revision = 1,
be6fbee5 908 .family = NFPROTO_IPV4,
cc23d0a2 909 .match = ipp2p_mt,
c237fe24
JE
910 .matchsize = sizeof(struct ipt_p2p_info),
911 .me = THIS_MODULE,
44d6f47a
JE
912};
913
cc23d0a2 914static int __init ipp2p_mt_init(void)
44d6f47a 915{
cc23d0a2 916 return xt_register_match(&ipp2p_mt_reg);
44d6f47a 917}
c237fe24 918
cc23d0a2 919static void __exit ipp2p_mt_exit(void)
44d6f47a 920{
cc23d0a2 921 xt_unregister_match(&ipp2p_mt_reg);
44d6f47a 922}
c237fe24 923
cc23d0a2
JE
924module_init(ipp2p_mt_init);
925module_exit(ipp2p_mt_exit);
29139c14 926MODULE_ALIAS("ipt_ipp2p");