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