diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | config-default/commands.xml | 66 | ||||
| -rwxr-xr-x | meta.pl | 7 | ||||
| -rw-r--r-- | modules/classes.pl | 40 | ||||
| -rw-r--r-- | modules/event.pl | 57 | ||||
| -rw-r--r-- | modules/inspect.pl | 15 | ||||
| -rw-r--r-- | modules/log.pl | 4 | ||||
| -rw-r--r-- | modules/mysql.pl | 8 | ||||
| -rw-r--r-- | modules/services.pl | 10 | ||||
| -rw-r--r-- | modules/util.pl | 5 | ||||
| -rw-r--r-- | modules/xml.pl | 7 |
11 files changed, 195 insertions, 26 deletions
@@ -1,5 +1,7 @@ /config /config-main /config-backup +/actionlogs +HTTP_ACCESS* *.stor *~ diff --git a/config-default/commands.xml b/config-default/commands.xml index 9cffe50..83a583f 100644 --- a/config-default/commands.xml +++ b/config-default/commands.xml @@ -68,11 +68,23 @@ $upstr = $upstr . int($up/1) . 's'; $up = $up % 1; } + my ($tx, $rx); + if ($conn->{_tx}/1024 > 1024) { + $tx = sprintf("%.2fMB", $conn->{_tx}/(1024*1024)); + } else { + $tx = sprintf("%.2fKB", $conn->{_tx}/1024); + } + if ($conn->{_rx}/1024 > 1024) { + $rx = sprintf("%.2fMB", $conn->{_rx}/(1024*1024)); + } else { + $rx = sprintf("%.2fKB", $conn->{_rx}/1024); + } $conn->privmsg($event->replyto, "This bot has been running for " . $upstr . ", is tracking " . (scalar (keys %::sn)) . " nicks" . " across " . (scalar (keys %::sc)) . " tracked channels." . " It is using " . $size . "KB of RAM" . - " and has used " . $cputime . " of CPU time."); + ", has used $cputime of CPU time" . + ", has sent $tx of data, and received $rx of data."); ]]> </command> <command cmd="^;mship (\S+)$" flag="s"> @@ -462,6 +474,11 @@ $conn->quit($1); ]]> </command> + <command cmd="^;exit ?(.*)" flag="a"> + <![CDATA[ + $conn->quit($1); + ]]> + </command> <command cmd="^;ev (.*)" flag="d"> <![CDATA[ eval $1; warn $@ if $@; @@ -561,7 +578,7 @@ my $txtz = "[\x02$tgt\x02] - $event->{nick} wants op attention"; if ((time-$::sc{$tgt}{users}{lc $event->{nick}}{jointime}) > 90) { # return; #they've been on the channel for less than 90 seconds, probably nuisance botspam - $txtz = $txtz . " ($msg) " . $hilite; + $txtz = "$txtz ($msg) $hilite !att-$tgt-opalert"; } my @tgts = ASM::Util->getAlert($tgt, 'opalert', 'msgs'); ASM::Util->sendLongMsg($conn, \@tgts, $txtz); @@ -586,7 +603,7 @@ else { my @tgts = ASM::Util->getAlert($tgt, 'opalert', 'msgs'); foreach my $chan (@tgts) { - $conn->privmsg($chan, $event->{nick} . " tried to use the ops trigger but is restricted from doing so."); + $conn->privmsg($chan, $event->{nick} . " tried to use the ops trigger for $tgt but is restricted from doing so."); } } ]]> @@ -594,9 +611,23 @@ <command cmd="^;blacklist (.*)" flag="o"> <![CDATA[ my $str = lc $1; - push(@::string_blacklist, $str); - "$str\n" >> io 'string_blacklist.txt'; - $conn->privmsg($event->replyto, "$str blacklisted"); +# push(@::string_blacklist, $str); +# "$str\n" >> io 'string_blacklist.txt'; + use String::CRC32; + my $id = sprintf("%08x", crc32($str)); + $::blacklist->{string}->{$id} = { "content" => $str, "setby" => $event->nick }; + ASM::XML->writeBlacklist(); + $conn->privmsg($event->replyto, "$str blacklisted with id $id, please use ;blreason $id reasonGoesHere to set a reason"); + ]]> + </command> + <command cmd="^;unblacklist ([0-9a-f]+)$" flag="o"> + <![CDATA[ + my $id = $1; + if (defined($::blacklist->{string}->{$id})) { + delete $::blacklist->{string}->{$id}; + $conn->privmsg($event->replyto, "blacklist id $id removed"); + ASM::XML->writeBlacklist(); + } else { $conn->privmsg($event->replyto, "invalid id"); } ]]> </command> <command cmd="^;plugin (\S+) (\S+) (.*)" flag="p"> @@ -618,4 +649,27 @@ } ]]> </command> + <command cmd="^;sync (\S+)" flag="a"> + <![CDATA[ + my $chan = $1; + $conn->sl("MODE $chan bq"); + $conn->sl("MODE $chan"); + $conn->sl("WHO $chan %tcnuhra,314"); + ]]> + </command> + <command cmd="^;ping$"> + <![CDATA[ + $conn->privmsg($event->replyto, "pong"); + ]]> + </command> + <command cmd="^;blreason ([0-9a-f]+) (.*)" flag="o"> + <![CDATA[ + my $id = $1; my $reason = $2; + if (defined($::blacklist->{string}->{$id})) { + $::blacklist->{string}->{$id}->{reason} = $reason; + $conn->privmsg($event->replyto, "Reason set"); + ASM::XML->writeBlacklist(); + } else { $conn->privmsg($event->replyto, "ID is invalid"); } + ]]> + </command> </commands> @@ -15,6 +15,7 @@ use POSIX qw(strftime); use Term::ANSIColor qw(:constants); use File::Monitor; use feature qw(say); +use HTTP::Async; $Data::Dumper::Useqq=1; @@ -28,12 +29,13 @@ $::cset = ''; $::pacealerts = 1; $::settingschanged = 0; %::wordlist = (); +%::httpRequests = (); ## debug variables. 0 to turn off debugging, else set it to a Term::ANSIColor constant. %::debugx = ( "dnsbl" => 0, "pingpong" => 0, #BLUE, - "services" => YELLOW, + "snotice" => YELLOW, "sync" => CYAN, "chanstate" => MAGENTA, "restrictions" => BLUE, @@ -87,6 +89,7 @@ sub init { mkdir($::settings->{log}->{dir}); $::log = ASM::Log->new($::settings->{log}); $::pass = $::settings->{pass} if $::pass eq ''; + $::async = HTTP::Async->new(); $host = ${$::settings->{server}}[rand @{$::settings->{server}}]; ASM::Util->dprint( "Connecting to $host", "startup"); $irc->debug($::debug); @@ -132,7 +135,7 @@ sub init { $::wordlist{lc $item} = 1; } $::fm = File::Monitor->new(); - foreach my $file ("channels", "commands", "dnsbl", "mysql", "restrictions", "rules", "settings", "users") { + foreach my $file ("channels", "commands", "dnsbl", "mysql", "restrictions", "rules", "settings", "users", "blacklist") { $::fm->watch("./" . $::cset . '/' . $file . ".xml"); } $::fm->watch("string_blacklist.txt"); diff --git a/modules/classes.pl b/modules/classes.pl index 4fbfb94..5cafdbd 100644 --- a/modules/classes.pl +++ b/modules/classes.pl @@ -14,6 +14,7 @@ sub new my $self = {}; my $tbl = { "strbl" => \&strbl, + "strblnew" => \&strblnew, "dnsbl" => \&dnsbl, "floodqueue" => \&floodqueue, "floodqueue2" => \&floodqueue2, @@ -34,7 +35,8 @@ sub new "joinmsgquit" => \&joinmsgquit, "garbagemeter" => \&garbagemeter, "cyclebotnet" => \&cyclebotnet, - "banevade" => \&banevade + "banevade" => \&banevade, + "urlcrunch" => \&urlcrunch }; $self->{ftbl} = $tbl; bless($self); @@ -76,6 +78,20 @@ sub joinmsgquit return 1; } +sub urlcrunch +{ + my ($chk, $id, $event, $chan, $response) = @_; + return 0 unless defined($response); + return 0 unless ref($response); + return 0 unless defined($response->{_previous}); + return 0 unless defined($response->{_previous}->{_headers}); + return 0 unless defined($response->{_previous}->{_headers}->{location}); + if ($response->{_previous}->{_headers}->{location} =~ /$chk->{content}/i) { + return 1; + } + return 0; +} + sub check { my $self = shift; @@ -367,6 +383,23 @@ sub strbl { return 0; } +sub strblnew { + my ($chk, $xid, $event, $chan) = @_; + my $match = lc $event->{args}->[0]; + foreach my $id (keys %{$::blacklist->{string}}) { + my $line = lc $::blacklist->{string}->{$id}->{content}; + my $idx = index $match, $line; + if ( $idx != -1 ) { + my $setby = $::blacklist->{string}->{$id}->{setby}; + $setby = substr($setby, 0, 1) . "\x02\x02" . substr($setby, 1); + return defined($::blacklist->{string}->{$id}->{reason}) ? + "id $id added by $setby because $::blacklist->{string}->{$id}->{reason}" : + "id $id added by $setby for no reason"; + } + } + return 0; +} + sub nick { my ($chk, $id, $event, $chan) = @_; if ( lc $event->{nick} eq lc $chk->{content} ) { @@ -407,6 +440,11 @@ sub nuhg { return 0; } +sub invite { + my ( $chk, $id, $event, $chan) = @_; + return 1; +} + my $sfc = 0; sub flood_add diff --git a/modules/event.pl b/modules/event.pl index 3c41df4..d3e3fa5 100644 --- a/modules/event.pl +++ b/modules/event.pl @@ -7,6 +7,7 @@ use Text::LevenshteinXS qw(distance); use IO::All; use POSIX qw(strftime); use Regexp::Wildcards; +use HTTP::Request; sub cs { my ($chan) = @_; @@ -71,6 +72,8 @@ sub new $conn->add_handler('statsdebug', \&on_statsdebug); $conn->add_handler('endofstats', \&on_endofstats); $conn->add_handler('channelurlis', \&on_channelurlis); + $conn->add_handler('480', \&on_jointhrottled); + $conn->add_handler('invite', \&blah); # This doesn't need to be fancy; I just need it to go through inspect bless($self); return $self; } @@ -79,6 +82,16 @@ my $clearstatsp = 1; my %statsp = (); my %oldstatsp = (); +sub on_jointhrottled +{ + my ($conn, $event) = @_; + my $chan = $event->{args}->[1]; + ASM::Util->dprint("$event->{nick}: $chan: $event->{args}->[2]", 'snotice'); + if ($event->{args}->[2] =~ /throttle exceeded, try again later/) { + $conn->schedule(5, sub { $conn->join($chan); }); + } +} + sub on_statsdebug { my ($conn, $event) = @_; @@ -222,7 +235,7 @@ sub on_connect { $conn->sl("MODE $event->{args}->[0] +Q-i"); if (lc $event->{args}->[0] ne lc $::settings->{nick}) { ASM::Util->dprint('Attempting to regain my main nick', 'startup'); - $conn->privmsg( 'NickServ', "regain $::settings->{nick} $::settings->{pass}" ); + $conn->privmsg( 'NickServ@services.', "regain $::settings->{nick} $::settings->{pass}" ); } $conn->sl('CAP REQ :extended-join multi-prefix account-notify'); #god help you if you try to use this bot off freenode } @@ -325,10 +338,38 @@ sub on_public $::sc{lc $event->{to}->[0]}{users}{lc $event->{nick}}{msgtime} = time; $::log->logg( $event ); $::db->logg( $event ); +# if ($event->{args}->[0] =~ /(https?:\/\/bitly.com\/\w+)|(https?:\/\/bit.ly\/\w+)|(https?:\/\/j.mp\/\w+)/i) { +# my $reqid = $::async->add( HTTP::Request->new( GET => $1 ) ); +# $::httpRequests{$reqid} = $event; +# my ($response, $id) = $::async->wait_for_next_response( 1 ); +# if (defined($response)) { +# on_httpResponse($conn, $id, $response); +# } +# else { $conn->schedule( 1, sub { checkHTTP($conn); } ); } +# } $::inspector->inspect( $conn, $event ); $::commander->command( $conn, $event ); } +sub checkHTTP +{ + my ($conn) = @_; + my ($response, $id) = $::async->next_response(); + if (defined ($response)) { + on_httpResponse($conn, $id, $response); + } + $conn->schedule( 1, sub { checkHTTP($conn); } ); +} + +sub on_httpResponse +{ + my ($conn, $id, $response) = @_; + my $event = $::httpRequests{$id}; + delete $::httpRequests{$id}; + $::inspector->inspect( $conn, $event, $response ); +} +# if ($response->{_previous}->{_headers}->{location} =~ /^https?:\/\/bitly.com\/a\/warning/) + sub on_notice { my ($conn, $event) = @_; @@ -778,11 +819,23 @@ sub on_whoxover my $size = `ps -p $$ h -o size`; my $cputime = `ps -p $$ h -o time`; chomp $size; chomp $cputime; + my ($tx, $rx); + if ($conn->{_tx}/1024 > 1024) { + $tx = sprintf("%.2fMB", $conn->{_tx}/(1024*1024)); + } else { + $tx = sprintf("%.2fKB", $conn->{_tx}/1024); + } + if ($conn->{_rx}/1024 > 1024) { + $rx = sprintf("%.2fMB", $conn->{_rx}/(1024*1024)); + } else { + $rx = sprintf("%.2fKB", $conn->{_rx}/1024); + } $conn->privmsg($::settings->{masterchan}, "Finished syncing after " . (time - $::starttime) . " seconds. " . "I'm tracking " . (scalar (keys %::sn)) . " nicks" . " across " . (scalar (keys %::sc)) . " tracked channels." . " I'm using " . $size . "KB of RAM" . - " and have used " . $cputime . " of CPU time."); + ", have used " . $cputime . " of CPU time" . + ", have sent $tx of data, and received $rx of data."); my %x = (); foreach my $c (@{$::settings->{autojoins}}) { $x{$c} = 1; } foreach my $cx (keys %::sc) { delete $x{$cx}; } diff --git a/modules/inspect.pl b/modules/inspect.pl index 3b72a3a..f5914cb 100644 --- a/modules/inspect.pl +++ b/modules/inspect.pl @@ -17,7 +17,7 @@ sub new } sub inspect { - our ($self, $conn, $event) = @_; + our ($self, $conn, $event, $response) = @_; my (%aonx, %dct, $rev, $chan, $id); %aonx=(); %dct=(); $chan=""; $id=""; my (@dnsbl, @uniq); @@ -43,7 +43,14 @@ sub inspect { foreach $id (keys %aonx) { next unless ( grep { $event->{type} eq $_ } split(/[,:; ]+/, $aonx{$id}{type}) ); next if ($aonx{$id}{class} eq 'dnsbl') && ($event->{host} =~ /(fastwebnet\.it|fastres\.net)$/); #this is a bad hack - $xresult = $::classes->check($aonx{$id}{class}, $aonx{$id}, $id, $event, $chan, $rev); # this is another bad hack done for dnsbl-related stuff + if (defined($response)) { + print Dumper($response); + if ($aonx{$id}{class} ne 'urlcrunch') { next; } #don't run our regular checks if this is being called from a URL checking function + else { $xresult = $::classes->check($aonx{$id}{class}, $aonx{$id}, $id, $event, $chan, $response); } + } + else { + $xresult = $::classes->check($aonx{$id}{class}, $aonx{$id}, $id, $event, $chan, $rev); # this is another bad hack done for dnsbl-related stuff + } next unless (defined($xresult)) && ($xresult ne 0); ASM::Util->dprint(Dumper($xresult), 'inspector'); $dct{$id} = $aonx{$id}; @@ -81,10 +88,10 @@ sub inspect { ) { my @tgts = ASM::Util->getAlert($chan, $dct{$id}{risk}, 'msgs'); ASM::Util->sendLongMsg($conn, \@tgts, $txtz); + $conn->schedule(45, sub { delete($::ignored{$chan})}) unless defined($::ignored{$chan}); $::ignored{$chan} = $::RISKS{$dct{$id}{risk}}; - $conn->schedule(45, sub { delete($::ignored{$chan})}); } - $::log->incident($chan, "$chan: $dct{$id}{risk} risk: $event->{nick} - $nicereason\n"); +# $::log->incident($chan, "$chan: $dct{$id}{risk} risk: $event->{nick} - $nicereason\n"); delete $dct{$id}{xresult}; } } diff --git a/modules/log.pl b/modules/log.pl index fe92159..72e0972 100644 --- a/modules/log.pl +++ b/modules/log.pl @@ -63,6 +63,10 @@ sub logg if (substr($chan, 0, 1) eq '@') { $chan = substr($chan, 1); } + if ($chan eq '*') { + ASM::Util->dprint("$event->{nick}: $event->{args}->[0]", 'snotice'); + next; + } my $path = ">>$cfg->{dir}${chan}/${chan}" . strftime($cfg->{filefmt}, @time); $_ = ''; $_ = "<$event->{nick}> $event->{args}->[0]" if $event->{type} eq 'public'; diff --git a/modules/mysql.pl b/modules/mysql.pl index 4ff4441..85e0c6f 100644 --- a/modules/mysql.pl +++ b/modules/mysql.pl @@ -196,10 +196,10 @@ sub logg $string = 'INSERT INTO `quit` (nick, user, host, geco, ip, account, content1) VALUES (' . $dbh->quote($event->{nick}) . ',' . $dbh->quote($event->{user}) . ',' . $dbh->quote($event->{host}) . ',' . $dbh->quote($::sn{lc $event->{nick}}->{gecos}) . ','; - my $ip = ASM::Util->getNickIP(lc $event->{nick}); + my $ip = ASM::Util->getNickIP(lc $event->{nick}, $event->{host}); if (defined($ip)) { $ip = $dbh->quote($ip); } else { $ip = 'NULL'; } my $account = $::sn{lc $event->{nick}}->{account}; - if (($account eq '0') or ($account eq '*')) { + if (!defined($account) or ($account eq '0') or ($account eq '*')) { $account = 'NULL'; } else { $account = $dbh->quote($account); @@ -213,10 +213,10 @@ sub logg $dbh->quote($event->{to}->[0]) . ',' . $dbh->quote($event->{nick}) . ',' . $dbh->quote($event->{user}) . ',' . $dbh->quote($event->{host}) . ',' . $dbh->quote($::sn{lc $event->{nick}}->{gecos}) . ','; - my $ip = ASM::Util->getNickIP(lc $event->{nick}); + my $ip = ASM::Util->getNickIP(lc $event->{nick}, $event->{host}); if (defined($ip)) { $ip = $dbh->quote($ip); } else { $ip = 'NULL'; } my $account = $::sn{lc $event->{nick}}->{account}; - if (($account eq '0') or ($account eq '*')) { + if (!defined($account) or ($account eq '0') or ($account eq '*')) { $account = 'NULL'; } else { $account = $dbh->quote($account); diff --git a/modules/services.pl b/modules/services.pl index 4783d2b..528901d 100644 --- a/modules/services.pl +++ b/modules/services.pl @@ -17,10 +17,10 @@ sub doServices { my $i = 1; if ($event->{from} eq 'NickServ!NickServ@services.') { - ASM::Util->dprint("NickServ: $event->{args}->[0]", 'services'); + ASM::Util->dprint("NickServ: $event->{args}->[0]", 'snotice'); if ( $event->{args}->[0] =~ /^This nickname is registered/ ) { - $conn->privmsg( 'NickServ', "identify $::settings->{nick} $::settings->{pass}" ); + $conn->privmsg( 'NickServ@services.', "identify $::settings->{nick} $::settings->{pass}" ); } elsif ( $event->{args}->[0] =~ /^You are now identified/ ) { @@ -41,12 +41,12 @@ sub doServices { } elsif ($event->{args}->[0] =~ /has been (killed|released)/ ) { - ASM::Util->dprint('Got kill/release successful from NickServ!', 'services'); +# ASM::Util->dprint('Got kill/release successful from NickServ!', 'snotice'); $conn->nick( $::settings->{nick} ); } elsif ($event->{args}->[0] =~ /has been regained/ ) { - ASM::Util->dprint('Got regain successful from nickserv!', 'services'); +# ASM::Util->dprint('Got regain successful from nickserv!', 'snotice'); } elsif ($event->{args}->[0] =~ /Password Incorrect/ ) { @@ -58,7 +58,7 @@ sub doServices { if ( $event->{args}->[0] =~ /^\[#/ ) { return; } - ASM::Util->dprint('ChanServ: '. Dumper($event->{args}->[0]), 'services'); + ASM::Util->dprint("ChanServ: $event->{args}->[0]", 'snotice'); if ( $event->{args}->[0] =~ /^All.*bans matching.*have been cleared on(.*)/) { $conn->join($1); diff --git a/modules/util.pl b/modules/util.pl index 35a66ae..375d2e5 100644 --- a/modules/util.pl +++ b/modules/util.pl @@ -5,6 +5,7 @@ use warnings; use strict; use Term::ANSIColor qw (:constants); use Socket qw( inet_aton inet_ntoa ); +use Data::Dumper; %::RISKS = ( @@ -225,13 +226,13 @@ sub getHostIP sub getNickIP { - my ($module, $nick) = @_; + my ($module, $nick, $host) = @_; $nick = lc $nick; return unless defined($::sn{$nick}); if (defined($::sn{$nick}{ip})) { return $::sn{$nick}{ip}; } - my $host = $::sn{$nick}{host}; + $host = $::sn{$nick}{host} if (!defined($host)); my $ip = getHostIP(undef, $host); if (defined($ip)) { $::sn{$nick}{ip} = $ip; diff --git a/modules/xml.pl b/modules/xml.pl index 551dc3f..a3c6e85 100644 --- a/modules/xml.pl +++ b/modules/xml.pl @@ -20,6 +20,7 @@ sub readXML { $::dnsbl = $::xs1->XMLin( "$p/dnsbl.xml", ForceArray => []); $::rules = $::xs1->XMLin( "$p/rules.xml", ForceArray => []); $::restrictions = $::xs1->XMLin( "$p/restrictions.xml", ForceArray => ['host', 'nick', 'account']); + $::blacklist = $::xs1->XMLin( "$p/blacklist.xml", ForceArray => 'string'); } sub writeXML { @@ -27,6 +28,7 @@ sub writeXML { writeChannels(); writeUsers(); writeRestrictions(); + writeBlacklist(); # $::xs1->XMLout($::commands, RootName => 'commands', KeyAttr => ['id']) > io("$::cset/commands.xml"); } @@ -52,4 +54,9 @@ sub writeRestrictions { GroupTags => { hosts => "host", nicks => "nick", accounts => "account"}) > io("$::cset/restrictions.xml"); } +sub writeBlacklist { + $::settingschanged=1; + $::xs1->XMLout($::blacklist, RootName => 'blacklist', KeyAttr => ['id']) > io("$::cset/blacklist.xml"); +} + return 1; |
