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