# ed2k_hello.rope - ROPE script to identify eDonkey 2000 "hello" packets for # IpTables and Netfilter. # # By : Chris Lowth - December 2005 # Support Forum : http://www.lowth.com/rope/HelpForum # ROPE Language Home : http://www.lowth.com/rope # Script Home : http://www.lowth.com/rope/BlockingEdonkey2000 # License : GPL (http://www.lowth.com/rope/GPL) # # Copyright (C) 2003,2004,2005 Chris Lowth - http://www.lowth.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # # Insert this script into an iptables chain (after compiling it) using a command # like # # iptables -A FORWARD -p tcp -m rope --rope-script ed2k_hello -j DROP # # If you want messages like "ED2K: User Kermit logging into 192.168.0.99" to # appear in your system log file when these packets are identified, then # uncomment the "println" line near the end of the script. # #================================================================================= # # This ROPE script identifies eDonkey 2000 (ED2K) "Hello" packets. These are used # to initiate the connection with an eDonkey 2000 server. # # The packet we are looking for looks something like this.. # # 00000000 45 00 00 70 e1 0d 40 00 80 06 5f b7 c0 a8 00 14 |E..p..@..._.....| # 00000010 8c 7b 6c 8b 04 65 1d e6 00 25 85 1c cc 6a 78 71 |.{l..e...%...jxq| # 00000020 50 18 22 38 6d 48 00 00 e3 43 00 00 00 01 2e 29 |P."8mH...C.....)| # 00000030 f1 55 70 0e 36 7b 64 24 8f 5a 6a ac 6f a8 a8 32 |.Up.6{d$.Zj.o..2| # 00000040 9f 00 36 12 05 00 00 00 02 01 00 01 02 00 63 6c |..6...........cl| # 00000050 03 01 00 11 3c 00 00 00 03 01 00 0f 36 12 00 00 |....<.......6...| # 00000060 03 01 00 20 19 00 00 00 03 01 00 fb 80 b1 00 00 |... ............| # First byte should be an E3 - this identifies the ED2K Protocol "\0xE3" expect_str # Next, the little endian counter indicating the packet length 4 expect le32_to_int 5 add $data_len eq assert # Now we check for a "HELLO" packet, denoted by packet type byte # with the value 01. "\0x01" expect_str # Then 22 bytes of fixed data that we dont try to interpret 22 move # 16 bytes of user hash # then 4 bytes of client ip # then 2 bytes of client port # Now the number of tags - store it in $n 4 expect le32_to_int $n put # Validate the range of $n $n 0 ge assert $n 10 le assert # Process the tags to verify their structure. We'll store the user name # if we find it (for checking and possible logging, later) "" $u put # blank the user name ($u) to start with 0 $g put # $g = have we GOT a user name? repeat($n { expect_one( { # String tag "\0x02" expect_str 2 expect le16_to_int $l put # tag description length $l 1 ge assert # bounds check $l expect $d put # store tag description in $d 2 expect le16_to_int $l put # tag value length $l 0 ge assert # bounds check $l expect $v put # store tag value in $v if( $d "\0x01" eq { # If this is user name, remember it $v $u put # name in $u 1 $g put # TRUE in $g } ) yes } { # integer tag "\0x03" expect_str 2 expect le16_to_int $l put # tag description lnegth $l 1 ge assert # bounds check $l move # tag description 4 move # tag value yes } ) dropall }) $eop assert # true if we are now at end of packet # check we've got a user name at all $g assert # Optionally write a message to syslog (uncomment the line below to enable logging) # println( "ED2K : User '" $u "' on " $ip_saddr ipv4_ntoa " logging in to " $ip_daddr ipv4_ntoa ) # If you are using this script to BLOCK ED2K, but you want to allow specific # users to connect, add lines below (one per user name) that look like this # (minus the leading '#' comment characters).. # $u "Kermit" ne assert # $u "MissPiggy" ne assert # The two lines above would (if uncommented) allow Kermit and MissPiggy to # log in by FAILING the match if the login name in the packet is either of # their names. # okay - we're prepared to admit that this is an ED2K login packet yes