summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatarWilliam Heimbigner <william.heimbigner@gmail.com>2013-03-07 10:35:43 +0000
committerLibravatarWilliam Heimbigner <william.heimbigner@gmail.com>2013-03-07 10:35:43 +0000
commitfdb1d6257cb9871c687e13b1ac1ec038ed2529e4 (patch)
tree94b21da667654e56d20b3ba0e194a6a846226d61
parent28e8eda8a99d2ea148741b2783b4f6110a8927d8 (diff)
Added logging of kicks/bans/quiets/removes/klines/kills to a special SQL table and corresponding text files
Enabled SQL debugging Bugfix: Only attempt to determine a host's IP if it doesn't contain a '/' Updates to channels.xml and users.xml Adjusted ;userx add and ;userx flags such that A cannot give B a flag that A doesn't already have Tweaked the ;help command Fixed ;mship such that it will respond even if it can't see the nick provided. Tweaked ;status to give output in format like 7d22h18m3s instead of 9814798712 seconds Added a ;teredo helper command to give info on IPv6 teredo-tunneled connections Added a nick blacklist file (to counter bot nicklists). Added a english wordlist file, for "garbage" detection. Added ;investigate and ;investigate2 commands Added a way to not throttle info-risk threats Added special detection for a cycling botnet Added special detection for bots that join, say something, and immediately quit Added detection for ascii art Added detection for "garbage" text Added fuzzy-matching against a set of nicks Added "real IP" to state tracking and logging, which "decrypts" gateway/web and teredo IPs Moved sigalarm code into meta.pl Improved statsp tracking, and logs it to a file Ping-pong every 30 seconds, auto-reconnect on persistent lag. Ensure inspector routine is always called AFTER log-handling routines Fixed a state-tracking bug in topic change handling Fixed a state-tracking bug with nick changes Fixed some state-tracking bugs with mode changes Determine who is impacted when a quiet/ban mask is placed Fixed handling of CTCP SOURCE requests Added feature where it keeps a 30 line "backlog" of each channel in memory. Added the reason for parts and quits to text logging
-rw-r--r--config-default/channels.xml187
-rw-r--r--config-default/commands.xml157
-rw-r--r--config-default/mysql.xml1
-rw-r--r--config-default/settings.xml1
-rw-r--r--config-default/users.xml26
-rwxr-xr-xmeta.pl31
-rw-r--r--modules/classes.pl75
-rw-r--r--modules/command.pl1
-rw-r--r--modules/event.pl244
-rw-r--r--modules/inspect.pl8
-rw-r--r--modules/log.pl47
-rw-r--r--modules/mysql.pl121
-rw-r--r--modules/util.pl41
13 files changed, 762 insertions, 178 deletions
diff --git a/config-default/channels.xml b/config-default/channels.xml
index 178a0bb..830a0eb 100644
--- a/config-default/channels.xml
+++ b/config-default/channels.xml
@@ -41,10 +41,17 @@
<debug>##hamradio-ops</debug>
</msgs>
</channel>
+ <channel id="##hamradio-banappeal">
+ <hilights></hilights>
+ </channel>
<channel id="##hamradio-ops">
<hilights></hilights>
<msgs></msgs>
</channel>
+ <channel id="##hardware">
+ <hilights></hilights>
+ <msgs></msgs>
+ </channel>
<channel id="##linux" silence="yes">
<hilights>
<info>Dominian</info>
@@ -106,6 +113,7 @@
<channel id="##wikia">
<hilights>
<info>vegadark</info>
+ <info>Furry</info>
</hilights>
<msgs></msgs>
</channel>
@@ -117,6 +125,7 @@
<disable>Thehelpfulone</disable>
<high>werdan7</high>
<info>njan</info>
+ <info>PZt</info>
<low>numist</low>
<low>HentaiXP</low>
<low>TechSalvager</low>
@@ -138,8 +147,15 @@
<hilights></hilights>
<msgs></msgs>
</channel>
- <channel id="#antispammeta-debug" />
- <channel id="#baadf00d" />
+ <channel id="#antispammeta-debug">
+ <hilights></hilights>
+ </channel>
+ <channel id="#baadf00d">
+ <hilights></hilights>
+ </channel>
+ <channel id="#chromium-support">
+ <hilights></hilights>
+ </channel>
<channel id="#cisco">
<hilights></hilights>
<msgs></msgs>
@@ -196,7 +212,9 @@
<hilights></hilights>
</channel>
<channel id="#frikipedia">
- <hilights></hilights>
+ <hilights>
+ <info>Nietzsche</info>
+ </hilights>
<msgs></msgs>
</channel>
<channel id="#gentoo" silence="yes">
@@ -233,12 +251,10 @@
</channel>
<channel id="#mediawiki" silence="yes">
<hilights>
- <debug>flyingparchment</debug>
- <debug>roberthl</debug>
<debug>Snowolf</debug>
- <disable>seanw</disable>
+ <debug>techman224</debug>
<info>charitwo</info>
- <low>vvv</low>
+ <medium>Jasper_Deng</medium>
</hilights>
<msgs>
<debug>#wikimedia-ops</debug>
@@ -255,14 +271,13 @@
</channel>
<channel id="#persian">
<hilights></hilights>
+ <msgs></msgs>
</channel>
<channel id="#persians">
<hilights></hilights>
</channel>
<channel id="#reddit">
<hilights>
- <debug>KyleXY</debug>
- <debug>kylexy</debug>
<debug>TheMoonMaster</debug>
<debug>Paradox</debug>
<debug>Mortvert</debug>
@@ -333,20 +348,20 @@
</channel>
<channel id="#wikimedia" silence="yes">
<hilights>
- <debug>Martinp23</debug>
<debug>PeterSymonds</debug>
- <debug>vvv</debug>
<debug>AfterDeath</debug>
- <debug>DeltaQuad</debug>
<debug>Snowolf</debug>
<debug>Thehelpfulone</debug>
<debug>Tanvir</debug>
<debug>jeremyb</debug>
<debug>Logan_</debug>
+ <debug>Rjd0060</debug>
<info>charitwo</info>
<info>Rjd0060</info>
<info>Fluffernutter</info>
<info>TBloemink</info>
+ <info>Steven_Zhang</info>
+ <low>DeltaQuad</low>
</hilights>
<msgs>
<debug>#wikimedia-ops</debug>
@@ -360,12 +375,29 @@
<debug>Thehelpfulone</debug>
<debug>Snowolf</debug>
<debug>Logan_</debug>
- <low>Kanonkas</low>
+ <debug>Rjd0060</debug>
+ <info>James_F</info>
</hilights>
<msgs>
<debug>#wikimedia-ops</debug>
</msgs>
</channel>
+ <channel id="#wikimedia-irc">
+ <hilights>
+ <info>seanw</info>
+ <info>martinp23</info>
+ <info>Rjd0060</info>
+ <info>Cbrown1023</info>
+ <info>dungodung</info>
+ <info>PeterSymonds</info>
+ <info>Barras</info>
+ <info>Thehelpfulone</info>
+ </hilights>
+ <msgs>
+ <debug>#wikimedia-ops</debug>
+ <low>#wikimedia-ops</low>
+ </msgs>
+ </channel>
<channel id="#wikimedia-office">
<hilights>
<info>mbimmler</info>
@@ -378,21 +410,17 @@
<info>Theo10011</info>
<info>Ironholds</info>
</hilights>
- <msgs>
- <debug>#wikimedia-ops</debug>
- </msgs>
+ <msgs></msgs>
</channel>
<channel id="#wikimedia-ops">
<hilights>
<debug>Cbrown1023</debug>
<debug>Thehelpfulone</debug>
- <debug>Not_the_NSA</debug>
- <debug>Kanonkas</debug>
<debug>PeterSymonds</debug>
- <debug>AfterDeath</debug>
<debug>Logan_</debug>
<debug>jeremyb</debug>
<debug>AfterDeath</debug>
+ <debug>Snowolf</debug>
<info>charitwo</info>
<info>TBloemink</info>
<info>Mh7kJ</info>
@@ -427,9 +455,7 @@
<debug>fschulenburg</debug>
<debug>Bastique</debug>
</hilights>
- <msgs>
- <debug>#wikimedia-ops</debug>
- </msgs>
+ <msgs></msgs>
</channel>
<channel id="#wikimedia-overflow">
<hilights>
@@ -445,6 +471,7 @@
<debug>PeterSymonds</debug>
<debug>Snowolf</debug>
<debug>Thehelpfulone</debug>
+ <debug>Rjd0060</debug>
<info>Snowolf</info>
<info>Rjd0060</info>
<info>TBloemink</info>
@@ -464,11 +491,19 @@
<debug>Thehelpfulone</debug>
<debug>Snowolf</debug>
<debug>Rjd0060</debug>
+ <debug>techman224</debug>
+ <medium>Jasper_Deng</medium>
</hilights>
<msgs>
<low>#wikimedia-ops</low>
</msgs>
</channel>
+ <channel id="#wikimedia-techJasper_Deng">
+ <hilights></hilights>
+ </channel>
+ <channel id="#wikimedia-techjasper_deng">
+ <hilights></hilights>
+ </channel>
<channel id="#wikimedia-toolserver">
<hilights>
<info>Austin</info>
@@ -481,53 +516,36 @@
<info>Simetrical</info>
<info>Werdna</info>
</hilights>
- <msgs>
- <debug>#wikimedia-ops</debug>
- </msgs>
+ <msgs></msgs>
</channel>
<channel id="#wikipedia" silence="yes">
<hilights>
- <debug>Golbez</debug>
<debug>Prodego</debug>
<debug>Snowolf</debug>
<debug>AfterDeath</debug>
<debug>Thehelpfulone</debug>
<debug>werdan7</debug>
- <debug>wimt</debug>
- <debug>Jake_Wartenberg</debug>
<debug>shimgray</debug>
- <debug>kibble</debug>
<debug>PeterSymonds</debug>
<debug>Jamesofur</debug>
<debug>killiondude</debug>
<debug>SpitfireWP</debug>
<debug>jeremyb</debug>
- <debug>Maximillion</debug>
<debug>stwalkerster</debug>
- <debug>DeltaQuad</debug>
<debug>Gfoley4</debug>
<debug>Logan_</debug>
- <debug>Theo10011</debug>
<debug>Snowolf</debug>
<debug>Tanvir</debug>
<debug>TBloemink</debug>
<debug>Rjd0060</debug>
<debug>Shirik</debug>
- <low>bumm13_</low>
- <low>Cyrius</low>
+ <info>Steven_Zhang</info>
<low>DanielB</low>
<low>FastLizard4</low>
<low>James_F</low>
<low>JohnReaves</low>
- <low>Lucifer_Cat</low>
- <low>Luna-San</low>
- <low>Mike42</low>
- <low>Mike_H</low>
- <low>skenmy</low>
- <low>ST47</low>
- <low>tawker</low>
<low>slakr</low>
- <low>Courcelles</low>
+ <low>DeltaQuad</low>
<medium>closedmouth</medium>
<medium>Fluffernutter</medium>
</hilights>
@@ -555,8 +573,6 @@
<debug>Jamesofur</debug>
<debug>SpitfireWP</debug>
<debug>jeremyb</debug>
- <debug>DeltaQuad</debug>
- <debug>Theo10011</debug>
<debug>Gfoley4</debug>
<debug>Logan_</debug>
<debug>Snowolf</debug>
@@ -564,12 +580,10 @@
<debug>Shirik</debug>
<debug>TBloemink</debug>
<debug>Rjd0060</debug>
- <low>Cobi</low>
- <low>Golbez</low>
+ <info>DeltaQuad</info>
<low>agkwiki</low>
<low>KFP</low>
<low>slakr</low>
- <low>Courcelles</low>
<medium>closedmouth</medium>
<medium>Fluffernutter</medium>
</hilights>
@@ -581,41 +595,21 @@
<hilights>
<info>Thehelpfulone</info>
<info>jamesofur</info>
- <info>Nixeagle</info>
<info>DeltaQuad</info>
- <info>Netalarm</info>
- <info>JoeGazz84</info>
- <info>MacMed</info>
<info>Snowolf</info>
</hilights>
- <msgs>
- <debug>#wikimedia-ops</debug>
- <low>#wikimedia-ops</low>
- </msgs>
+ <msgs></msgs>
</channel>
<channel id="#wikipedia-en-ambassadors">
<hilights>
- <info>anowlin</info>
- <info>ragesoss</info>
<info>stwalkerster</info>
- <info>chzz</info>
<info>Prodego</info>
- <info>Deskana</info>
- <info>Pathoschild</info>
- <info>fetchcomms</info>
- <info>BarkingFish</info>
- <info>Cbrown1023</info>
- <info>Earwig</info>
- <info>ldavis</info>
- <info>annielin</info>
<info>PeterSymonds</info>
<info>Shirik</info>
<info>Fluffernutter</info>
<info>Thehelpfulone</info>
</hilights>
- <msgs>
- <debug>#wikimedia-ops</debug>
- </msgs>
+ <msgs></msgs>
</channel>
<channel id="#wikipedia-en-classroom">
<hilights></hilights>
@@ -623,25 +617,13 @@
<channel id="#wikipedia-en-help" silence="yes">
<hilights>
<debug>werdan7</debug>
- <debug>GDonato</debug>
<debug>Thehelpfulone</debug>
- <debug>Mike42</debug>
- <debug>bjelleklang</debug>
- <debug>JohnReaves</debug>
- <debug>After-Midnight</debug>
- <debug>Srikeit</debug>
- <debug>Deon555</debug>
- <debug>Luna-San</debug>
- <debug>Golbez</debug>
<debug>stwalkerster</debug>
<debug>PeterSymonds</debug>
- <debug>Hersfold</debug>
<debug>killiondude</debug>
- <debug>DeltaQuad</debug>
<debug>Logan_</debug>
<debug>Shirik</debug>
<debug>slakr</debug>
- <debug>JoeGazz84</debug>
<debug>Steven_Zhang</debug>
<debug>SteveMobile</debug>
<debug>TBloemink</debug>
@@ -649,11 +631,13 @@
<debug>Tanvir</debug>
<debug>TBloemink</debug>
<debug>Ocaasi</debug>
+ <debug>Rjd0060</debug>
<info>mabdul</info>
+ <info>gwickwire</info>
<low>KFP</low>
<low>Gfoley4</low>
- <low>sonia</low>
<low>Pine</low>
+ <low>DeltaQuad</low>
</hilights>
<msgs>
<debug>#wikimedia-ops</debug>
@@ -672,12 +656,35 @@
<info>PeterSymonds</info>
<info>Shirik</info>
</hilights>
+ <msgs></msgs>
+ </channel>
+ <channel id="#wikipedia-media">
+ <hilights></hilights>
+ </channel>
+ <channel id="#wikipedia-otrs">
+ <hilights></hilights>
+ </channel>
+ <channel id="#wikipedia-social" silence="yes">
+ <hilights></hilights>
+ <msgs>
+ <low>#wikimedia-ops</low>
+ </msgs>
+ </channel>
+ <channel id="#wikitravel">
+ <hilights></hilights>
+ </channel>
+ <channel id="#wikivoyage">
+ <hilights>
+ <debug>Snowolf</debug>
+ <debug>Rschen7754</debug>
+ <info>Thehelpfulone</info>
+ <info>Logan_</info>
+ </hilights>
<msgs>
<debug>#wikimedia-ops</debug>
- <low>#wikimedia-ops</low>
</msgs>
</channel>
- <channel id="#wikipedia-social" silence="yes">
+ <channel id="#wikivoyage-es">
<hilights></hilights>
<msgs>
<low>#wikimedia-ops</low>
@@ -698,11 +705,14 @@
<info>Wytukaze</info>
<info>Tawker</info>
</hilights>
- <msgs>
- <debug>#wikimedia-ops</debug>
- </msgs>
+ <msgs></msgs>
+ </channel>
+ <channel id="antispammeta">
+ <hilights></hilights>
+ </channel>
+ <channel id="antispammetabeta">
+ <hilights></hilights>
</channel>
- <channel id="antispammetabeta" />
<channel id="default">
<hilights></hilights>
</channel>
@@ -714,7 +724,6 @@
<medium>dave2</medium>
</hilights>
<msgs>
- <debug>##asb-nexus</debug>
<debug>#antispammeta</debug>
</msgs>
</channel>
diff --git a/config-default/commands.xml b/config-default/commands.xml
index a3a1695..8154271 100644
--- a/config-default/commands.xml
+++ b/config-default/commands.xml
@@ -1,19 +1,69 @@
<commands>
- <command cmd="^;status$" flag="o">
+ <command cmd="^;makemelunch">
+ <![CDATA[
+ $conn->me($event->replyto, "makes " . $event->{nick} . " a sandwich");
+ ]]>
+ </command>
+ <command cmd="^;teredo (\S+)">
+ <![CDATA[
+ my $arg1 = $1;
+ my @splitip = split(/:/, $arg1);
+ if ( (int($splitip[0]) != 2001) || (int($splitip[1]) != 0) ) {
+ $conn->privmsg($event->replyto, "This is not a teredo-tunnelled IP.");
+ return;
+ }
+ print Dumper(\@splitip);
+ my $server = join('.', unpack('C4', pack('N', hex($splitip[2] . $splitip[3]))));
+ my $host = join('.', unpack('C4', pack('N', (hex($splitip[6] . $splitip[7])^hex('ffffffff')))));
+ my $port = hex($splitip[5]) ^ hex('ffff');
+ $conn->privmsg($event->replyto, "Source is $host:$port; teredo server in use is $server.");
+#hex('41379e76') ^ hex('ffffffff'); print join ('.', unpack('C4', pack('N', $ip))) . "\n"
+#join '.', unpack "C*", pack "H*", $ip;
+ #2001:0:4137:9e76:3094:127d:51a2:6952
+ #2001:0 - teredo marker
+ #4137:9e76 - teredo server
+ #3094 - teredo flags
+ #127d - xor 0xff - UDP port in use
+ #51a2:6952 - xor 0xff - source IP
+ ]]>
+ </command>
+ <command cmd="^;status$">
<![CDATA[
my $size = `ps -p $$ h -o size`;
my $cputime = `ps -p $$ h -o time`;
chomp $size; chomp $cputime;
- $conn->privmsg($event->replyto, "This bot has been running for " . (time - $::starttime) . " seconds" .
+ my $upstr = '';
+ my $up = (time - $::starttime);
+ if (int($up/86400) != 0) { #days
+ $upstr = $upstr . int($up/86400) . 'd';
+ $up = $up % 86400;
+ }
+ if (int($up/3600) != 0) { #hours
+ $upstr = $upstr . int($up/3600) . 'h';
+ $up = $up % 3600;
+ }
+ if (int($up/60) != 0) { #minutes
+ $upstr = $upstr . int($up/60) . 'm';
+ $up = $up % 60;
+ }
+ if (int($up/1) != 0) { #seconds
+ $upstr = $upstr . int($up/1) . 's';
+ $up = $up % 1;
+ }
+ $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.");
]]>
</command>
- <command cmd="^;mship (\S+)$" flag="c">
+ <command cmd="^;mship (\S+)$" flag="s">
<![CDATA[
- $conn->privmsg($event->replyto, $1 . " is on: " . ASM::Util->commaAndify(sort @{$::sn{lc $1}->{mship}}));
+ if (defined($::sn{lc $1}->{mship})) {
+ $conn->privmsg($event->replyto, $1 . " is on: " . ASM::Util->commaAndify(sort @{$::sn{lc $1}->{mship}}));
+ } else {
+ $conn->privmsg($event->replyto, "I don't see $1.");
+ }
]]>
</command>
<command cmd="^;source$">
@@ -46,8 +96,8 @@
</command>
<command cmd="^;help$">
<![CDATA[
- $conn->privmsg($event->replyto, "help is at http://meta.wikimedia.org/wiki/User:WHeimbigner/AntiSpamMeta");
- $conn->privmsg($event->replyto, "You can also get faster help by emailing william dot heimbigner at ttu dot edu - or bug ErrantEgo or tomaw");
+ $conn->privmsg($event->replyto, "command list is at http://antispammeta.net/syntax.txt ; see also http://meta.wikimedia.org/wiki/User:WHeimbigner/AntiSpamMeta (not as up to date but contains some additonal info)");
+ $conn->privmsg($event->replyto, "You can also get faster help by bugging ow, DLa\x02\x02nge, tom\x02\x02aw, or mari\x02\x02enz");
]]>
</command>
<command cmd="^;db$">
@@ -63,10 +113,95 @@
$conn->privmsg($event->replyto, "$result results found.");
]]>
</command>
+ <command cmd="^;investigate (\S+) *$">
+ <![CDATA[
+ my $nick = lc $1;
+ unless (defined($::sn{$nick})) {
+ $conn->privmsg($event->replyto, "I don't see $nick in my state tracking database, so I can't run any queries on their info, sorry :(" .
+ " You can try https://antispammeta.net/cgi-bin/secret/investigate.pl?nick=$nick instead!");
+ return;
+ }
+ my $person = $::sn{$nick};
+ my $dbh = $::db->{DBH};
+
+ my $mnicks = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE nick like " . $dbh->quote($nick) . ';');
+ my $musers = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE user like " . $dbh->quote($person->{user}) . ';');
+ my $mhosts = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE host like " . $dbh->quote($person->{host}) . ';');
+ my $maccts = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE account like " . $dbh->quote($person->{account}) . ';');
+ my $mgecos = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE gecos like " . $dbh->quote($person->{gecos}) . ';');
+
+ my $ip = ASM::Util->getNickIP($nick);
+ my $matchedip = 0;
+ $matchedip = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE ip = " . $dbh->quote($ip) . ';') if defined($ip);
+ $conn->privmsg($event->replyto, "I found $mnicks matches by nick, $musers user matches, $mhosts by hostname, " .
+ "$maccts by NickServ account, $mgecos by gecos field, and $matchedip by real IP.");
+ ]]>
+ </command>
+ <command cmd="^;investigate2 (\S+) ?(\d*)$" flag="s">
+ <![CDATA[
+ my $nick = lc $1;
+ my $skip = 0;
+ $skip = $2 if (defined($2) and ($2 ne ""));
+ unless (defined($::sn{$nick})) {
+ $conn->privmsg($event->replyto, "I don't see $nick in my state tracking database, so I can't run any queries on their info, sorry :(" .
+ " You can try https://antispammeta.net/cgi-bin/secret/investigate.pl?nick=$nick instead!");
+ return;
+ }
+ my $person = $::sn{$nick};
+ my $dbh = $::db->{DBH};
+
+ my $query = "SELECT * from $::db->{ACTIONTABLE} WHERE nick like " . $dbh->quote($nick) .
+ ' or user like ' . $dbh->quote($person->{user}) .
+ ' or host like ' . $dbh->quote($person->{host}) .
+ ' or account like ' . $dbh->quote($person->{account}) .
+ ' or gecos like ' . $dbh->quote($person->{gecos});
+ my $ip = ASM::Util->getNickIP($nick);
+ if (defined($ip)) {
+ $query = $query . ' or ip = ' . $dbh->quote($ip);
+ }
+ $query = $query . " order by time desc limit $skip,5;";
+ print Dumper($query);
+ my $query_handle = $dbh->prepare($query);
+ $query_handle->execute();
+ my @data = @{$query_handle->fetchall_arrayref()};
+# reverse @data;
+#$data will be an array of arrays,
+ my ($xindex, $xtime, $xaction, $xreason, $xchannel, $xnick, $xuser, $xhost, $xip, $xgecos, $xaccount, $xbynick, $xbyuser, $xbyhost, $xbygecos, $xbyaccount ) =
+ ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+ $conn->privmsg($event->replyto, "PM'ing you the list of results");
+ foreach my $line (@data) {
+ my $reason = '';
+ $reason = $line->[$xreason] if defined($line->[$xreason]);
+ $conn->privmsg($event->nick, '#' . $line->[$xindex] . ': ' . $line->[$xtime] . ' ' .
+ $line->[$xnick] . '!' . $line->[$xuser] . '@' . $line->[$xhost] . ' (' . $line->[$xgecos] . ') ' .
+ $line->[$xaction] . ' (' . $reason . ')' .
+ ' on ' . $line->[$xchannel] . ' by ' . $line->[$xbynick]); # . "\n";
+ }
+ my $dq = '';
+ if (defined($ip)) {
+ $dq = '&realip=' . join '.', unpack 'C4', pack 'N', $ip;
+ }
+ $conn->privmsg($event->nick, "Only 5 results are shown at a time. For more, do ;investigate2 $nick " . ($skip+5) .
+ ' or better yet, check out https://antispammeta.net/cgi-bin/secret/investigate.pl?nick=' . uri_escape($nick) .
+ '&user=' . uri_escape($person->{user}) . '&host=' . uri_escape($person->{host}) . '&account=' . uri_escape($person->{account}) .
+ '&gecos=' . uri_escape($person->{gecos}) . $dq );
+# print Dumper($data);
+ ]]>
+ </command>
<command cmd="^;userx add (\S+) (\S+)$" flag="a">
<![CDATA[
my $acct = lc $1;
my $flags = $2;
+ my %hasflagshash = ();
+ foreach my $item (split(//, $::users->{person}->{lc $::sn{lc $event->{nick}}->{account}}->{flags})) {
+ $hasflagshash{$item} = 1;
+ }
+ foreach my $flag (split(//, $flags)) {
+ if (!defined($hasflagshash{$flag})) {
+ $conn->privmsg($event->replyto, "You can't give a flag you don't already have.");
+ return;
+ }
+ }
if ($flags =~ /d/i) {
$conn->privmsg($event->replyto, "The d flag may not be assigned over IRC. Edit the configuration manually.");
return;
@@ -95,6 +230,16 @@
<![CDATA[
my $nick = lc $1;
my $flags = $2;
+ my %hasflagshash = ();
+ foreach my $item (split(//, $::users->{person}->{lc $::sn{lc $event->{nick}}->{account}}->{flags})) {
+ $hasflagshash{$item} = 1;
+ }
+ foreach my $flag (split(//, $flags)) {
+ if (!defined($hasflagshash{$flag})) {
+ $conn->privmsg($event->replyto, "You can't give a flag you don't already have.");
+ return;
+ }
+ }
if ($flags =~ /d/i) {
$conn->privmsg($event->replyto, "The d flag may not be assigned over IRC. Edit the configuration manually.");
return;
diff --git a/config-default/mysql.xml b/config-default/mysql.xml
index 3f66147..10aca77 100644
--- a/config-default/mysql.xml
+++ b/config-default/mysql.xml
@@ -3,6 +3,7 @@
<pass>PASS</pass>
<db>asm_main</db>
<table>alertlog</table>
+ <actiontable>actionlog</actiontable>
<host>localhost</host>
<port>3307</port>
</mysql>
diff --git a/config-default/settings.xml b/config-default/settings.xml
index 66eab42..b128cac 100644
--- a/config-default/settings.xml
+++ b/config-default/settings.xml
@@ -21,6 +21,7 @@
</autojoins>
<log>
<dir>logs/</dir>
+ <actiondir>actionlogs/</actiondir>
<filefmt>-%m-%d-%Y.log</filefmt>
<timefmt>%B %d %T </timefmt>
<zone>GMT</zone>
diff --git a/config-default/users.xml b/config-default/users.xml
index 7902bcc..ecf8de3 100644
--- a/config-default/users.xml
+++ b/config-default/users.xml
@@ -1,14 +1,18 @@
<people>
- <person id="afterdeath" flags="hocdatp" />
+ <person id="afterdeath" flags="hocdatps" />
+ <person id="antispammeta" />
<person id="cbrown1023" flags="oath" />
<person id="dave2" flags="oath" />
<person id="denny" flags="ha" />
- <person id="dlange" flags="coathd" />
+ <person id="dlange" flags="coathds" />
<person id="dmcdevit" flags="oath" />
<person id="dominian" flags="oath" />
<person id="dungodung" flags="oath" />
<person id="errantego" flags="doath" />
<person id="gary" flags="oath" />
+ <person id="gry" />
+ <person id="gryllida" flags="ahsto" />
+ <person id="gwickwire" flags="s" />
<person id="idleone" flags="o" />
<person id="jeremyb" flags="oth" />
<person id="jonathand" flags="oath" />
@@ -18,28 +22,28 @@
<person id="logan_" flags="oath" />
<person id="lstarnes" flags="oath" />
<person id="marienz" flags="doath" />
- <person id="mrmist" flags="doath" />
<person id="martinp23" flags="oath" />
<person id="mquin" flags="hota" />
+ <person id="mrmist" flags="doath" />
<person id="myrtti" flags="htoa" />
<person id="nhandler" flags="oath" />
<person id="njan" flags="oath" />
<person id="o_o" flags="oath" />
<person id="paradox" flags="h" />
- <person id="petersymonds" flags="oath" />
+ <person id="petersymonds" flags="oaths" />
+ <person id="pine" flags="ths" />
<person id="pricechild" flags="oath" />
<person id="richih" flags="oath" />
<person id="rjd0060" flags="th" />
- <person id="sauvin" flags="oath" />
+ <person id="sauvin" flags="oaths" />
<person id="seanw" flags="oath" />
<person id="shiibot" flags="p" />
- <person id="snowolf" flags="oath" />
+ <person id="snowolf" flags="oaths" />
+ <person id="tbloemink" flags="ths" />
<person id="th1" flags="th" />
<person id="thehelpfulone" flags="oath" />
<person id="tomaw" flags="oathd" />
- <person id="troubled" flags="oath" />
- <person id="ttuttle" flags="oath" />
- <person id="werdan7" flags="oath" />
- <person id="wildpikachu" flags="doath" />
- <person id="windowshasyou" flags="oath" />
+ <person id="ttuttle" flags="oaths" />
+ <person id="werdan7" flags="oth" />
+ <person id="wildpikachu" flags="doaths" />
</people>
diff --git a/meta.pl b/meta.pl
index 47c9d9b..7586b23 100755
--- a/meta.pl
+++ b/meta.pl
@@ -18,10 +18,13 @@ $Data::Dumper::Useqq=1;
%::eline=();
$::pass = '';
+@::nick_blacklist=();
@::string_blacklist=();
$::netsplit = 0;
$::debug = 0;
$::cset = '';
+$::pacealerts = 1;
+%::wordlist = ();
## debug variables. 0 to turn off debugging, else set it to a Term::ANSIColor constant.
%::debugx = (
@@ -32,14 +35,16 @@ $::cset = '';
"chanstate" => MAGENTA,
"restrictions" => BLUE,
"startup" => YELLOW,
- "mysql" => 0,
+ "mysql" => CYAN,
"inspector" => 0,
"commander" => GREEN,
"msg" => GREEN,
"dcc" => RED,
- "misc" => 0, #RED
+ "misc" => 0, #RED,
"latency" => RED,
- "statsp" => 0 #MAGENTA
+ "statsp" => MAGENTA,
+ "ctcp" => 0, #RED,
+ "logger" => 0
);
%::dsock = ();
%::spy = ();
@@ -54,6 +59,13 @@ $SIG{__WARN__} = sub {
print STDERR strftime("%F %T", gmtime), RED, ' WARNING: ', RESET, $_[0];
};
+sub alarmdeath
+{
+ die "SIG ALARM!!!\n";
+}
+$SIG{ALRM} = \&alarmdeath;
+alarm 300;
+
BEGIN {
my @modules = qw/Util Xml Inspect Event Services Log Command Classes Mysql/;
require 'modules/' . lc $_ . '.pl' foreach @modules;
@@ -75,9 +87,12 @@ sub init {
$host = ${$::settings->{server}}[rand @{$::settings->{server}}];
ASM::Util->dprint( "Connecting to $host", "startup");
$irc->debug($::debug);
- $::db = ASM::DB->new($::mysql->{db}, $::mysql->{host}, $::mysql->{port}, $::mysql->{user}, $::mysql->{pass}, $::mysql->{table}, $::mysql->{dblog});
+ $::db = ASM::DB->new($::mysql->{db}, $::mysql->{host}, $::mysql->{port},
+ $::mysql->{user}, $::mysql->{pass}, $::mysql->{table},
+ $::mysql->{actiontable}, $::mysql->{dblog});
$conn = $irc->newconn( Server => $host,
Port => $::settings->{port} || '6667',
+ SSL => defined($::settings->{ssl}),
Nick => $::settings->{nick},
Ircname => $::settings->{realname},
Username => $::settings->{username},
@@ -97,6 +112,9 @@ sub init {
my @strbl = io('string_blacklist.txt')->getlines;
chomp @strbl;
@::string_blacklist = @strbl;
+ my @nickbl = io('nick_blacklist.txt')->getlines;
+ chomp @nickbl;
+ @::nick_blacklist = @nickbl;
%::proxies = ();
my @proxy = io('proxy.txt')->getlines;
chomp @proxy;
@@ -105,6 +123,11 @@ sub init {
$::proxies{$1} = 1;
}
}
+ my @wl=io('wordlist.txt')->getlines;
+ chomp @wl;
+ foreach my $item (@wl) {
+ $::wordlist{lc $item} = 1;
+ }
$irc->start();
}
diff --git a/modules/classes.pl b/modules/classes.pl
index f943976..fc8e9e7 100644
--- a/modules/classes.pl
+++ b/modules/classes.pl
@@ -26,13 +26,53 @@ sub new
"nuhg" => \&nuhg,
"levenflood" => \&levenflood,
"proxy" => \&proxy,
- "nickbl" => \&nickbl
+ "nickbl" => \&nickbl,
+ "nickfuzzy" => \&nickfuzzy,
+ "asciiflood" => \&asciiflood,
+ "joinmsgquit" => \&joinmsgquit,
+ "garbagemeter" => \&garbagemeter,
+ "cyclebotnet" => \&cyclebotnet
};
$self->{ftbl} = $tbl;
bless($self);
return $self;
}
+sub garbagemeter {
+ my ($chk, $id, $event, $chan, $rev) = @_;
+ my @cut = split(/:/, $chk->{content});
+ my $limit = int($cut[0]);
+ my $timeout = int($cut[1]);
+ my $threshold = int($cut[2]);
+ my $threshold2 = int($cut[3]);
+ my $wordcount = 0;
+ my $line = $event->{args}->[0];
+ return 0 unless ($line =~ /^[A-Za-z: ]+$/);
+ my @words = split(/ /, $line);
+ return 0 unless ((scalar @words) >= $threshold2);
+ foreach my $word (@words) {
+ if (defined($::wordlist{lc $word})) {
+ $wordcount += 1;
+ }
+ return 0 if ($wordcount >= $threshold);
+ }
+ return 1 if ( flood_add( $chan, $id, 0, $timeout ) == $limit );
+ return 0;
+}
+
+sub joinmsgquit
+{
+ my ($chk, $id, $event, $chan, $rev) = @_;
+ my $time = $chk->{content};
+##STATE
+ $chan = lc $chan; #don't know if this is necessary but I'm trying to track down some mysterious state tracking corruption
+ return 0 unless defined($::sc{$chan}{users}{lc $event->{nick}}{jointime});
+ return 0 unless defined($::sc{$chan}{users}{lc $event->{nick}}{msgtime});
+ return 0 if ((time - $::sc{$chan}{users}{lc $event->{nick}}{jointime}) > $time);
+ return 0 if ((time - $::sc{$chan}{users}{lc $event->{nick}}{msgtime}) > $time);
+ return 1;
+}
+
sub check
{
my $self = shift;
@@ -40,6 +80,17 @@ sub check
return $self->{ftbl}->{$item}->(@_);
}
+sub nickbl
+{
+ my ($chk, $id, $event, $chan, $rev) = @_;
+ my $match = lc $event->{nick};
+ foreach my $line (@::nick_blacklist) {
+ if ($line eq $match) {
+ return 1;
+ }
+ }
+ return 0;
+}
sub proxy
{
my ($chk, $id, $event, $chan, $rev) = @_;
@@ -85,7 +136,7 @@ sub levenflood
return $ret;
}
-sub nickbl
+sub nickfuzzy
{
my ($chk, $id, $event, $chan) = @_;
my $nick = $event->{nick};
@@ -136,6 +187,26 @@ sub floodqueue {
return 0;
}
+sub asciiflood {
+ my ($chk, $id, $event, $chan, $rev) = @_;
+ my @cut = split(/:/, $chk->{content});
+ return 0 if (length($event->{args}->[0]) < $cut[0]);
+ return 0 if ($event->{args}->[0] =~ /[A-Za-z0-9]/);
+ return 1 if ( flood_add( $chan, $id, $event->{host}, int($cut[2]) ) == int($cut[1]) );
+ return 0;
+}
+
+sub cyclebotnet
+{
+ my ($chk, $id, $event, $chan, $rev) = @_;
+ my ($cycletime, $queueamt, $queuetime) = split(/:/, $chk->{content});
+ $chan = lc $chan; #don't know if this is necessary but I'm trying to track down some mysterious state tracking corruption
+ return 0 unless defined($::sc{$chan}{users}{lc $event->{nick}}{jointime});
+ return 0 if ((time - $::sc{$chan}{users}{lc $event->{nick}}{jointime}) > int($cycletime));
+ return 1 if ( flood_add( $chan, $id, "cycle", int($queuetime)) == int($queueamt) );
+ return 0;
+}
+
sub nickspam {
my ($chk, $id, $event, $chan) = @_;
my @cut = split(/:/, $chk->{content});
diff --git a/modules/command.pl b/modules/command.pl
index 3acaedd..7576850 100644
--- a/modules/command.pl
+++ b/modules/command.pl
@@ -5,6 +5,7 @@ use strict;
use IO::All;
use POSIX qw(strftime);
use Data::Dumper;
+use URI::Escape;
sub new
{
diff --git a/modules/event.pl b/modules/event.pl
index 3ed711c..bd76fb1 100644
--- a/modules/event.pl
+++ b/modules/event.pl
@@ -6,6 +6,7 @@ use Data::Dumper;
use Text::LevenshteinXS qw(distance);
use IO::All;
use POSIX qw(strftime);
+use Regexp::Wildcards;
sub cs {
my ($chan) = @_;
@@ -21,12 +22,6 @@ sub maxlen {
return $lb;
}
-sub alarmdeath
-{
- die "SIG ALARM!!!\n";
-}
-$SIG{ALRM} = \&alarmdeath;
-
sub new
{
my $module = shift;
@@ -82,22 +77,24 @@ sub new
my $clearstatsp = 1;
my %statsp = ();
+my %oldstatsp = ();
sub on_statsdebug
{
my ($conn, $event) = @_;
my ($char, $line) = ($event->{args}->[1], $event->{args}->[2]);
if ($char eq 'p') {
+ if ($clearstatsp) {
+ $clearstatsp = 0;
+ %oldstatsp = %statsp;
+ %statsp = ();
+ }
if ($line =~ /^(\d+) staff members$/) {
#this is the end of the report
} else {
my ($nick, $userhost) = split(" ", $line);
$userhost =~ s/\((.*)\)/$1/;
my ($user, $host) = split("@", $userhost);
- if ($clearstatsp) {
- $clearstatsp = 0;
- %statsp = ();
- }
$statsp{$nick}= [$user, $host];
}
}
@@ -109,24 +106,55 @@ sub on_endofstats
if ($event->{args}->[1] eq 'p') {
$clearstatsp=1;
my $tmp = Dumper(\%statsp); chomp $tmp;
- ASM::Util->dprint($tmp, 'statsp');
+ if ( join(",", sort(keys %oldstatsp)) ne join(",", sort(keys %statsp)) ) {
+ open(FH, '>>', 'statsplog.txt');
+ print FH strftime("%F %T ", gmtime) . join(",", sort(keys %statsp)) . "\n";
+ close(FH);
+ ASM::Util->dprint(join(",", keys %statsp), 'statsp');
+ }
# $event->{args}->[2] == "End of /STATS report"
#end of /stats p
}
}
+my $lagcycles = 0;
+my $pongcount = 0;
+
sub on_pong
{
my ($conn, $event) = @_;
- alarm 90;
- $conn->schedule( 60, sub { $conn->sl("PING :" . time); } );
+ alarm 120;
+ $conn->schedule( 30, sub { $conn->sl("PING :" . time); } );
ASM::Util->dprint('Pong? ... Ping!', 'pingpong');
-# ASM::Util->dprint(Dumper($event), 'pingpong');
- $conn->sl("STATS p");
my $lag = time - $event->{args}->[0];
if ($lag > 1) {
ASM::Util->dprint("Latency: $lag", 'latency');
}
+ if (($pongcount % 3) == 0) { #easiest way to do something roughly every 90 seconds
+ $conn->sl('STATS p');
+ }
+ if ((time - $::starttime) < 60 ) {
+ return; #we don't worry about lag if we've just started up and are still syncing etc.
+ }
+ if (($lag > 2) && ($lag < 5)) {
+ $conn->privmsg( $::settings->{masterchan}, "Warning: I'm currently lagging by $lag seconds.");
+ }
+ if ($lag >= 5) {
+ $lagcycles++;
+ if ($lagcycles >= 3) {
+ $conn->quit("Automatic restart triggered due to persistent lag. Freenode staff: If this is happening too frequently, please " .
+ "set a nickserv freeze on my account, and once my connection is stable, unfreeze the account and /kill me to tri" .
+ "gger a reconnect.");
+ } elsif ($lagcycles >=2) {
+ $conn->privmsg( $::settings->{masterchan}, "Warning: I'm currently lagging by $lag seconds. This marks heavy lag cycle " .
+ "$lagcycles - automatic restart will be triggered after 3 lag cycles." );
+ }
+ }
+ if (($lag <= 2) && ($lagcycles > 0)) {
+ $lagcycles--;
+# $conn->privmsg( $::settings->{masterchan}, "Warning: Heavy lag cycle count has been reduced to $lagcycles" );
+ ASM::Util->dprint('$lag = ' . $lag . '; $lagcycles = ' . $lagcycles, 'latency');
+ }
}
sub on_dchat
@@ -202,6 +230,8 @@ sub on_join {
$::sc{$chan}{users}{$nick}{hostmask} = $event->{userhost};
$::sc{$chan}{users}{$nick}{op} = 0;
$::sc{$chan}{users}{$nick}{voice} = 0;
+ $::sc{$chan}{users}{$nick}{jointime} = time;
+ $::sc{$chan}{users}{$nick}{msgtime} = 0;
if (defined($::sn{$nick})) {
my @mship = ();
if (defined($::sn{$nick}->{mship})) {
@@ -219,35 +249,43 @@ sub on_join {
$::sn{$nick}->{user} = $event->{user};
$::sn{$nick}->{host} = $event->{host};
$::sn{$nick}->{account} = lc $event->{args}->[0];
- $::inspector->inspect( $conn, $event ) unless $::netsplit;
$::db->logg($event);
$::log->logg( $event );
+ $::inspector->inspect( $conn, $event ) unless $::netsplit;
}
sub on_part
{
my ($conn, $event) = @_;
- $::inspector->inspect( $conn, $event );
my $nick = lc $event->{nick};
+ my $chan = lc $event->{to}->[0];
$::log->logg( $event );
$::db->logg( $event );
+ if ($event->{args}->[0] =~ /^requested by/) {
+ my $idx = $::db->actionlog( $event);
+ $::log->sqlIncident($chan, $idx) if $idx;
+ }
+# "to" => [ "#antispammeta" ],
+# "args" => [ "requested by ow (test)" ],
+# "nick" => "aoregcdu",
+ $::inspector->inspect( $conn, $event );
if (defined($::sn{$nick}) && defined($::sn{$nick}->{mship})) {
my @mship = @{$::sn{$nick}->{mship}};
- @mship = grep { lc $_ ne lc $event->{to}->[0] } @mship;
+ @mship = grep { lc $_ ne $chan } @mship;
if ( @mship ) {
$::sn{$nick}->{mship} = \@mship;
} else {
delete($::sn{$nick});
}
}
- if ( lc $conn->{_nick} eq lc $nick )
+ if ( lc $conn->{_nick} eq $nick )
{
- delete( $::sc{lc $event->{to}->[0]} );
- on_byechan(lc $event->{to}->[0]);
+ delete( $::sc{$chan} );
+ on_byechan($chan);
}
else
{
- delete( $::sc{lc $event->{to}->[0]}{users}{$nick} );
+ delete( $::sc{$chan}{users}{$nick} );
}
}
@@ -265,19 +303,20 @@ sub on_public
{
my ($conn, $event) = @_;
# alarm 200;
- $::inspector->inspect( $conn, $event );
+ $::sc{lc $event->{to}->[0]}{users}{lc $event->{nick}}{msgtime} = time;
$::log->logg( $event );
$::db->logg( $event );
+ $::inspector->inspect( $conn, $event );
$::commander->command( $conn, $event );
}
sub on_notice
{
my ($conn, $event) = @_;
- return if ( $event->{to}->[0] eq '$*' );
- $::inspector->inspect( $conn, $event );
+ return if ( $event->{to}->[0] eq '$*' ); # if this is a global notice FUCK THAT SHIT
$::log->logg( $event );
$::db->logg( $event );
+ $::inspector->inspect( $conn, $event );
$::services->doServices($conn, $event);
}
@@ -302,17 +341,24 @@ sub on_quit
my ($conn, $event) = @_;
my @channels=();
for ( keys %::sc ) {
- push ( @channels, $_ ) if delete $::sc{lc $_}{users}{lc $event->{nick}};
+ push ( @channels, lc $_ ) if delete $::sc{lc $_}{users}{lc $event->{nick}};
}
$event->{to} = \@channels;
+ my $idx = $::db->actionlog($event);
+ $::log->sqlIncident( join(',', @channels), $idx ) if $idx;
$::db->logg( $event );
+ $::log->logg( $event );
+
if (($::netsplit == 0) && ($event->{args}->[0] eq "*.net *.split") && (lc $event->{nick} ne 'chanserv')) { #special, netsplit situation
$conn->privmsg($::settings->{masterchan}, "Entering netsplit mode - JOIN and QUIT inspection will be disabled for 60 minutes");
$::netsplit = 1;
$conn->schedule(60*60, sub { $::netsplit = 0; $conn->privmsg($::settings->{masterchan}, 'Returning to regular operation'); });
}
$::inspector->inspect( $conn, $event ) unless $::netsplit;
- $::log->logg( $event );
+ #ugh. Repurge some shit, hopefully this will fix some stuff where things are going wrong
+ foreach my $chan ( keys %::sc ) {
+ delete $::sc{$chan}{users}{lc $event->{nick}};
+ }
delete($::sn{lc $event->{nick}});
}
@@ -335,6 +381,7 @@ sub irc_users
$::sc{lc $channel}{users}{lc $_} = {};
$::sc{lc $channel}{users}{lc $_}{op} = $op;
$::sc{lc $channel}{users}{lc $_}{voice} = $voice;
+ $::sc{lc $channel}{users}{lc $_}{jointime} = 0;
}
}
@@ -345,7 +392,6 @@ sub on_names {
sub irc_topic {
my ($conn, $event) = @_;
- $::inspector->inspect($conn, $event) if ($event->{format} ne 'server');
if ($event->{format} eq 'server')
{
my $chan = lc $event->{args}->[1];
@@ -363,34 +409,42 @@ sub irc_topic {
{
if ($event->{type} eq 'topic')
{
- my $chan = lc $event->{args}->[1];
+ my $chan = lc $event->{to}->[0];
$::sc{$chan}{topic}{text} = $event->{args}->[0];
$::sc{$chan}{topic}{time} = time;
$::sc{$chan}{topic}{by} = $event->{from};
}
$::log->logg($event);
$::db->logg( $event );
+ $::inspector->inspect($conn, $event);
}
}
sub on_nick {
my ($conn, $event) = @_;
my @channels=();
- for ( keys %::sc )
+ my $oldnick = lc $event->{nick};
+ my $newnick = lc $event->{args}->[0];
+ foreach my $chan ( keys %::sc )
{
- if ( defined $::sc{lc $_}{users}{lc $event->{nick}} )
+ $chan = lc $chan;
+ if ( defined $::sc{$chan}{users}{$oldnick} )
{
- $::sc{lc $_}{users}{lc $event->{args}->[0]} = $::sc{lc $_}{users}{lc $event->{nick}};
- delete( $::sc{lc $_}{users}{lc $event->{nick}} );
- push ( @channels, lc $_ );
+ if ($oldnick ne $newnick) { #otherwise a nick change where they're only
+ #changing the case of their nick means that
+ #ASM forgets about them.
+ $::sc{$chan}{users}{$newnick} = $::sc{$chan}{users}{$oldnick};
+ delete( $::sc{$chan}{users}{$oldnick} );
+ }
+ push ( @channels, $chan );
}
}
- $::sn{lc $event->{args}->[0]} = $::sn{lc $event->{nick}};
+ $::sn{$newnick} = $::sn{$oldnick} if ($oldnick ne $newnick);
$::db->logg( $event );
- delete( $::sn{lc $event->{nick}});
+ delete( $::sn{$oldnick}) if ($oldnick ne $newnick);
$event->{to} = \@channels;
- $::inspector->inspect($conn, $event);
$::log->logg($event);
+ $::inspector->inspect($conn, $event);
}
sub on_kick {
@@ -399,18 +453,21 @@ sub on_kick {
$conn->join($event->{args}->[0]);
}
my $nick = lc $event->{to}->[0];
+ my $chan = lc $event->{args}->[0];
$::log->logg( $event );
$::db->logg( $event );
+ my $idx = $::db->actionlog($event);
+ $::log->sqlIncident($chan, $idx) if $idx;
if (defined($::sn{$nick}) && defined($::sn{$nick}->{mship})) {
my @mship = @{$::sn{$nick}->{mship}};
- @mship = grep { lc $_ ne lc $event->{to}->[0] } @mship;
+ @mship = grep { lc $_ ne $chan } @mship;
if ( @mship ) {
$::sn{$nick}->{mship} = \@mship;
} else {
delete($::sn{$nick});
}
}
- if ( lc $conn->{_nick} eq lc $nick )
+ if ( lc $conn->{_nick} eq $nick )
{
delete( $::sc{lc $event->{args}->[0]} );
on_byechan(lc $event->{to}->[0]);
@@ -433,14 +490,26 @@ sub parse_modes
$t=$c;
}
else { #eIbq,k,flj,CFLMPQcgimnprstz
- if ( grep( /[eIbqkfljov]/,($c) ) ) { #modes that take args
- push (@new_modes, [$t.$c, shift @args]);
- }
- elsif ( grep( /[CFLMPQcgimnprstz]/, ($c) ) ) {
- push (@new_modes, [$t.$c]);
- }
- else {
- die "Unknown mode $c !\n";
+ if ($t eq '+') {
+ if ( grep( /[eIbqkfljov]/,($c) ) ) { #modes that take args WHEN BEING ADDED
+ push (@new_modes, [$t.$c, shift @args]);
+ }
+ elsif ( grep( /[CFLMPQcgimnprstz]/, ($c) ) ) {
+ push (@new_modes, [$t.$c]);
+ }
+ else {
+ die "Unknown mode $c !\n";
+ }
+ } else {
+ if ( grep( /[eIbqov]/,($c) ) ) { #modes that take args WHEN BEING REMOVED
+ push (@new_modes, [$t.$c, shift @args]);
+ }
+ elsif ( grep( /[CFLMPQcgimnprstzkflj]/, ($c) ) ) {
+ push (@new_modes, [$t.$c]);
+ }
+ else {
+ die "Unknown mode $c !\n";
+ }
}
}
}
@@ -470,12 +539,45 @@ sub on_channelmodeis
}
}
+sub whoGotHit
+{
+ my ($chan, $mask) = @_;
+ my $cvt = Regexp::Wildcards->new(type => 'jokers');
+ my @affected = ();
+ if ($mask !~ /^\$/) {
+ my @div = split(/\$/, $mask);
+ my $regex = $cvt->convert($div[0]);
+ foreach my $nick (keys %::sn) {
+ next unless defined($::sn{$nick}{user});
+ if (lc ($nick.'!'.$::sn{$nick}{user}.'@'.$::sn{$nick}{host}) =~ lc $regex) {
+ push @affected, $nick if defined($::sc{$chan}{users}{$nick});
+ }
+ }
+ } elsif ($mask =~ /^\$a:(.*)/) {
+ my @div = split(/\$/, $1);
+ my $regex = $cvt->convert($div[0]);
+ foreach my $nick (keys %::sn) {
+ next unless defined($::sn{$nick}{account});
+ if (lc ($::sn{$nick}{account}) =~ lc $regex) {
+ push @affected, $nick if defined($::sc{$chan}{users}{$nick});
+ }
+ }
+ }
+ return @affected;
+}
+
sub on_mode
{
my ($conn, $event) = @_;
my $chan = lc $event->{to}->[0];
+# holy shit, I feel so bad doing this
+# I have no idea how or why Net::IRC fucks up modes if they've got a ':' in one of the args
+# but you do what you must...
+ my @splitted = split(/ /, $::lastline); shift @splitted; shift @splitted; shift @splitted;
+ $event->{args}=\@splitted;
if ($chan =~ /^#/) {
my @modes = @{parse_modes($event->{args})};
+ ASM::Util->dprint(Dumper(\@modes), 'misc');
foreach my $line ( @modes ) {
my @ex = @{$line};
@@ -484,23 +586,39 @@ sub on_mode
elsif ( $ex[0] eq '+v' ) { $::sc{$chan}{users}{lc $ex[1]}{voice} = 1; }
elsif ( $ex[0] eq '-v' ) { $::sc{$chan}{users}{lc $ex[1]}{voice} = 0; }
- elsif ( $ex[0] eq '+b') {
+ elsif ( $ex[0] eq '+b' ) {
$::sc{$chan}{bans}{$ex[1]} = { bannedBy => $event->{from}, bannedOn => time };
+ if (lc $event->{nick} !~ /^(floodbot)/) { #ignore the ubuntu floodbots 'cause they quiet people a lot
+ my @affected = whoGotHit($chan, $ex[1]);
+ if ( (@affected) && (scalar @affected <= 4) ) {
+ foreach my $victim (@affected) {
+ my $idx = $::db->actionlog($event, 'ban', $victim);
+ $::log->sqlIncident( $chan, $idx ) if $idx;
+ }
+ }
+ }
}
- elsif ( $ex[0] eq '-b') {
- delete $::sc{$chan}{bans}{$ex[1]};
- }
- elsif ( $ex[0] eq '+q') {
+ elsif ( $ex[0] eq '-b' ) { delete $::sc{$chan}{bans}{$ex[1]}; }
+
+ elsif ( $ex[0] eq '+q' ) {
$::sc{$chan}{quiets}{$ex[1]} = { bannedBy => $event->{from}, bannedOn => time };
+ if (lc $event->{nick} !~ /^(floodbot)/) {
+ my @affected = whoGotHit($chan, $ex[1]);
+ if ( (@affected) && (scalar @affected <= 4) ) {
+ foreach my $victim (@affected) {
+ my $idx = $::db->actionlog($event, 'quiet', $victim);
+ $::log->sqlIncident( $chan, $idx ) if $idx;
+ }
+ }
+ }
}
- elsif ( $ex[0] eq '-q') {
- delete $::sc{$chan}{quiets}{$ex[1]};
- }
+ elsif ( $ex[0] eq '-q' ) { delete $::sc{$chan}{quiets}{$ex[1]}; }
+
else {
my ($what, $mode) = split (//, $ex[0]);
if ($what eq '+') {
if (defined($ex[1])) { push @{$::sc{$chan}{modes}}, $mode . ' ' . $ex[1]; }
- else { push @{$::sc{$chan}{modes}}, $mode; }
+ else { push @{$::sc{$chan}{modes}}, $mode; }
} else {
my @modes = grep {!/^$mode/} @{$::sc{$chan}{modes}};
$::sc{$chan}{modes} = \@modes;
@@ -518,7 +636,7 @@ sub on_mode
sub checkRegged
{
my ($conn, $chan) = @_;
- if (grep {/r/} @{$::sc{$chan}{modes}}) {
+ if (grep {/^r/} @{$::sc{$chan}{modes}}) {
my $tgt = $chan;
my $risk = "debug";
my $hilite=ASM::Util->commaAndify(ASM::Util->getAlert($tgt, $risk, 'hilights'));
@@ -553,6 +671,7 @@ sub on_ctcp
{
my ($conn, $event) = @_;
my $acct = lc $::sn{lc $event->{nick}}->{account};
+ ASM::Util->dprint(Dumper($event), 'ctcp');
if (($event->{type} eq 'cdcc') &&
(defined($::users->{person}->{$acct})) &&
(defined($::users->{person}->{$acct}->{flags})) &&
@@ -576,9 +695,7 @@ sub dcc_open
sub on_ctcp_source
{
my ($conn, $event) = @_;
- if (lc $event->{args}->[0] eq lc $conn->{_nick}) {
- $conn->ctcp_reply($event->{nick}, 'SOURCE http://svn.linuxrulz.org/repos/antispammeta/trunk/');
- }
+ $conn->ctcp_reply($event->{nick}, 'SOURCE http://svn.linuxrulz.org/repos/antispammeta/trunk/');
}
sub on_whoxreply
@@ -631,6 +748,13 @@ sub on_whofuckedup
{
my ($conn, $event) = @_;
ASM::Util->dprint('on_whofuckedup called!', 'sync');
+ if ($event->{args}->[1] eq "STATS") {
+#most likely this is getting called because we did stats p too often.
+#unfortunately the server doesn't let us know what exactly we called stats for.
+#anyways, we don't need to do anything for this
+ } else { #dunno why it got called, print the data and I'll add a handler for it.
+ ASM::Util->dprint(Dumper($event), 'sync');
+ }
}
sub on_bannedfromchan {
diff --git a/modules/inspect.pl b/modules/inspect.pl
index 24d93d8..4466d69 100644
--- a/modules/inspect.pl
+++ b/modules/inspect.pl
@@ -31,7 +31,7 @@ sub inspect {
}
}
else {
- $iaddr = gethostbyname($event->{host});
+ $iaddr = gethostbyname($event->{host}) if ($event->{host} !~ /\//);
$rev = join('.', reverse(unpack('C4', $iaddr))).'.' if (defined $iaddr);
}
## NB: isn't there a better way to do this with grep, somehow?
@@ -74,12 +74,16 @@ sub inspect {
if ($id eq 'last_measure_regex') { #TODO: Note that this is another example of things that shouldn't be hardcoded, but are.
}
- unless (defined($::ignored{$chan}) && ($::ignored{$chan} >= $::RISKS{$dct{$id}{risk}})) {
+ if (
+ (!(defined($::ignored{$chan}) && ($::ignored{$chan} >= $::RISKS{$dct{$id}{risk}}))) ||
+ (($::pacealerts == 0) && ($dct{$id}{risk} eq 'info'))
+ ) {
my @tgts = ASM::Util->getAlert($chan, $dct{$id}{risk}, 'msgs');
ASM::Util->sendLongMsg($conn, \@tgts, $txtz);
$::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");
delete $dct{$id}{xresult};
}
}
diff --git a/modules/log.pl b/modules/log.pl
index 8b30eab..bdf4821 100644
--- a/modules/log.pl
+++ b/modules/log.pl
@@ -12,10 +12,43 @@ sub new
my $config = shift;
my $self = {};
$self->{CONFIG} = $config;
+ $self->{backlog} = {};
bless($self);
return $self;
}
+sub incident
+{
+ my $self = shift;
+ my ($chan, $header) = @_;
+ $chan = lc $chan;
+ open(FH, '>>', 'dctlog.txt');
+ print FH $header;
+ if (defined($self->{backlog}->{$chan})) {
+ print FH join('', @{$self->{backlog}->{$chan}});
+ }
+ print FH "\n\n";
+ close(FH);
+}
+
+#writes out the backlog to a file which correlates to ASM's SQL actionlog table
+sub sqlIncident
+{
+ my $self = shift;
+ my ($channel, $index) = @_;
+ $channel = lc $channel;
+ my @chans = split(/,/, $channel);
+ open(FH, '>', $self->{CONFIG}->{actiondir} . $index . '.txt');
+ foreach my $chan (@chans) {
+ if (defined($self->{backlog}->{$chan})) {
+ print FH "$chan\n";
+ print FH join('', @{$self->{backlog}->{$chan}});
+ print FH "\n";
+ }
+ }
+ close(FH);
+}
+
sub logg
{
my $self = shift;
@@ -35,10 +68,10 @@ sub logg
$_ = '';
$_ = "<$event->{nick}> $event->{args}->[0]" if $event->{type} eq 'public';
$_ = "*** $event->{nick} has joined $chan" if $event->{type} eq 'join';
- $_ = "*** $event->{nick} has left $chan" if $event->{type} eq 'part';
+ $_ = "*** $event->{nick} has left $chan ($event->{args}->[0])" if $event->{type} eq 'part';
$_ = "* $event->{nick} $event->{args}->[0]" if $event->{type} eq 'caction';
$_ = "*** $event->{nick} is now known as $event->{args}->[0]" if $event->{type} eq 'nick';
- $_ = "*** $event->{nick} has quit IRC" if $event->{type} eq 'quit';
+ $_ = "*** $event->{nick} has quit ($event->{args}->[0])" if $event->{type} eq 'quit';
$_ = "*** $event->{to}->[0] was kicked by $event->{nick}" if $event->{type} eq 'kick';
$_ = "-$event->{nick}- $event->{args}->[0]" if $event->{type} eq 'notice';
$_ = "*** $event->{nick} sets mode: " . join(" ",@{$event->{args}}) if $event->{type} eq 'mode';
@@ -46,8 +79,18 @@ sub logg
my $nostamp = $_;
$_ = strftime($cfg->{timefmt}, @time) . $_ . "\n";
my $line = $_;
+ my @backlog = ();
+ if (defined($self->{backlog}->{$chan})) {
+ @backlog = @{$self->{backlog}->{$chan}};
+ if (scalar @backlog >= 30) {
+ shift @backlog;
+ }
+ }
+ push @backlog, $line;
+ $self->{backlog}->{$chan} = \@backlog;
if (open(FH, $path)) { # or die "Can't open $path: $!";
print FH $line;
+ ASM::Util->dprint($line, 'logger');
close(FH);
} else {
print "COULDN'T PRINT TO $path - $line";
diff --git a/modules/mysql.pl b/modules/mysql.pl
index d0cee00..7484ca3 100644
--- a/modules/mysql.pl
+++ b/modules/mysql.pl
@@ -6,13 +6,14 @@ use DBI;
sub new {
my $module = shift;
- my ($db, $host, $port, $user, $pass, $table, $dblog) = @_;
+ my ($db, $host, $port, $user, $pass, $table, $actiontable, $dblog) = @_;
my $self = {};
$self->{DBH} = DBI->connect("DBI:mysql:database=$db;host=$host;port=$port", $user, $pass);
$self->{DBH_LOG} = DBI->connect("DBI:mysql:database=$dblog;host=$host;port=$port", $user, $pass);
$self->{DBH}->{mysql_auto_reconnect} = 1;
$self->{DBH_LOG}->{mysql_auto_reconnect} = 1;
$self->{TABLE} = $table;
+ $self->{ACTIONTABLE} = $actiontable;
bless($self);
return $self;
}
@@ -60,6 +61,122 @@ sub record
$dbh->quote($id) . ", " . $dbh->quote($reason) . ");");
}
+sub actionlog
+{
+ my ($self, $event, $modedata1, $modedata2) = @_;
+ my $dbh = $self->{DBH};
+ my ($action, $reason, $channel,
+ $nick, $user, $host, $gecos, $account, $ip,
+ $bynick, $byuser, $byhost, $bygecos, $byaccount);
+
+ if ($event->{type} eq 'mode') {
+ $action = $modedata1;
+ $nick = $modedata2;
+ $channel = lc $event->{to}->[0];
+ $bynick = $event->{nick};
+ $byuser = $event->{user};
+ $byhost = $event->{host};
+ } elsif ($event->{type} eq 'quit') {
+ my $quitmsg = $event->{args}->[0];
+ if ($quitmsg =~ /^Killed \((\S+) \((.*)\)\)$/) {
+ $bynick = $1;
+ $reason = $2 unless ($2 eq '<No reason given>');
+ return if ($reason =~ /Nickname regained by services/);
+ $action = 'kill';
+ } elsif ($quitmsg =~ /^K-Lined$/) {
+ $action = 'k-line';
+ } else {
+ return; #quit not forced/tracked
+ }
+ $nick = $event->{nick};
+ $user = $event->{user};
+ $host = $event->{host};
+ } elsif (($event->{type} eq 'part') && ($event->{args}->[0] =~ /^requested by (\S+) \((.*)\)/)) {
+ $bynick = $1;
+ $reason = $2 unless (lc $reason eq lc $event->{nick});
+ $action = 'remove';
+ $nick = $event->{nick};
+ $user = $event->{user};
+ $host = $event->{host};
+ $channel = $event->{to}->[0];
+ } elsif ($event->{type} eq 'kick') {
+ $action = 'kick';
+ $bynick = $event->{nick};
+ $byuser = $event->{user};
+ $byhost = $event->{host};
+ $reason = $event->{args}->[1] unless ($event->{args}->[1] eq $event->{to}->[0]);
+ $nick = $event->{to}->[0];
+ $channel = $event->{args}->[0];
+ }
+ return unless defined($action);
+# $bynick = lc $bynick if defined $bynick; #we will lowercase the NUHGA info later.
+ if ( (defined($bynick)) && (defined($::sn{lc $bynick})) ) { #we have the nick taking the action available, fill in missing NUHGA info
+ $byuser = $::sn{lc $bynick}{user} unless defined($byuser);
+ $byhost = $::sn{lc $bynick}{host} unless defined($byhost);
+ $bygecos = $::sn{lc $bynick}{gecos} unless defined($bygecos);
+ $byaccount = $::sn{lc $bynick}{account} unless defined($byaccount);
+ if (($byaccount eq '0') or ($byaccount eq '*')) {
+ $byaccount = undef;
+ }
+ }
+# $nick = lc $nick if defined $nick;
+ if ( (defined($nick)) && (defined($::sn{lc $nick})) ) { #this should always be true, else something has gone FUBAR
+ $user = $::sn{lc $nick}{user} unless defined($user);
+ $host = $::sn{lc $nick}{host} unless defined($host);
+ $gecos = $::sn{lc $nick}{gecos} unless defined($gecos);
+ $account = $::sn{lc $nick}{account} unless defined($account);
+ if (($account eq '0') or ($account eq '*')) {
+ $account = undef;
+ }
+ $ip = ASM::Util->getNickIP(lc $nick);
+ }
+# my ($action, $reason, $channel,
+# $nick, $user, $host, $gecos, $account, $ip
+# $bynick, $byuser, $byhost, $bygecos, $byaccount);
+#Now, time to escape/NULLify everything
+ $action = $dbh->quote($action);
+ if (defined($reason)) { $reason = $dbh->quote($reason); } else { $reason = 'NULL'; }
+## removed lc's from everything except IP
+ if (defined($channel)) { $channel = $dbh->quote($channel); } else { $channel = 'NULL'; }
+
+ if (defined($nick)) { $nick = $dbh->quote($nick); } else { $nick = 'NULL'; }
+ if (defined($user)) { $user = $dbh->quote($user); } else { $user = 'NULL'; }
+ if (defined($host)) { $host = $dbh->quote($host); } else { $host = 'NULL'; }
+ if (defined($gecos)) { $gecos = $dbh->quote($gecos); } else { $gecos = 'NULL'; }
+ if (defined($account)) { $account = $dbh->quote($account); } else { $account = 'NULL'; }
+ if (defined($ip)) { $ip = $dbh->quote($ip); } else { $ip = 'NULL'; }
+
+ if (defined($bynick)) { $bynick = $dbh->quote($bynick); } else { $bynick = 'NULL'; }
+ if (defined($byuser)) { $byuser = $dbh->quote($byuser); } else { $byuser = 'NULL'; }
+ if (defined($byhost)) { $byhost = $dbh->quote($byhost); } else { $byhost = 'NULL'; }
+ if (defined($bygecos)) { $bygecos = $dbh->quote($bygecos); } else { $bygecos = 'NULL'; }
+ if (defined($byaccount)) { $byaccount = $dbh->quote($byaccount); } else { $byaccount = 'NULL'; }
+ my $sqlstr = "INSERT INTO $self->{ACTIONTABLE} " .
+ "(action, reason, channel, " .
+ "nick, user, host, gecos, account, ip, " .
+ "bynick, byuser, byhost, bygecos, byaccount)" .
+ " VALUES " .
+ "($action, $reason, $channel, " .
+ "$nick, $user, $host, $gecos, $account, $ip, " .
+ "$bynick, $byuser, $byhost, $bygecos, $byaccount);";
+ ASM::Util->dprint( $sqlstr, 'mysql' );
+ $dbh->do( $sqlstr );
+ return $dbh->last_insert_id(undef, undef, $self->{ACTIONTABLE}, undef);
+# $::sn{ow} looks like:
+#$VAR1 = {
+# "account" => "afterdeath",
+# "gecos" => "William Athanasius Heimbigner",
+# "user" => "icxcnika",
+# "mship" => [
+# "#baadf00d",
+# "#antispammeta-debug",
+# "#antispammeta"
+# ],
+# "host" => "freenode/weird-exception/network-troll/afterdeath"
+# };
+
+}
+
#FIXME: This function is shit. Also, it doesn't work like I want it to with mode.
sub logg
{
@@ -110,7 +227,7 @@ sub logg
$string = $string . ', ' . $dbh->quote($event->{args}->[1]);
}
$string = $string . ');';
- ASM::Util->dprint($string, "mysql");
+# ASM::Util->dprint($string, "mysql");
$dbh->do($string);
}
diff --git a/modules/util.pl b/modules/util.pl
index dc3f285..54e25a6 100644
--- a/modules/util.pl
+++ b/modules/util.pl
@@ -183,6 +183,47 @@ sub dprint {
print STDERR $text, "\n";
}
+sub dottedQuadToInt
+{
+ my ($module, $dottedquad) = @_;
+ my $ip_number = 0;
+ my @octets = split(/\./, $dottedquad);
+ foreach my $octet (@octets) {
+ $ip_number <<= 8;
+ $ip_number |= $octet;
+ }
+ return $ip_number;
+}
+
+sub getNickIP
+{
+ my ($module, $nick) = @_;
+ $nick = lc $nick;
+ return unless defined($::sn{$nick});
+ if (defined($::sn{$nick}{ip})) {
+ return $::sn{$nick}{ip};
+ }
+ my $host = $::sn{$nick}{host};
+ if ( ($host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) or
+ ($host =~ /^gateway\/web\/freenode\/ip\.(\d+)\.(\d+)\.(\d+)\.(\d+)$/) ) {
+ #yay, easy IP!
+ $::sn{$nick}{ip} = dottedQuadToInt(undef, "$1.$2.$3.$4");
+ return $::sn{$nick}{ip};
+ } elsif (index($host, '/') != -1) {
+ return;
+ } elsif ($host =~ /^2001:0:/) {
+ my @splitip = split(/:/, $host);
+ #I think I can just do (hex($splitip[6] . $splitip[7]) ^ hex('ffffffff')) here but meh
+ my $host = join('.', unpack('C4', pack('N', (hex($splitip[6] . $splitip[7])^hex('ffffffff')))));
+ $::sn{$nick}{ip} = dottedQuadToInt(undef, $host);
+ return $::sn{$nick}{ip};
+ }
+ my @resolve = gethostbyname($::sn{$nick}{host});
+ return unless @resolve;
+ $::sn{$nick}{ip} = dottedQuadToInt(undef, join('.', unpack('C4', $resolve[4])));
+ return $::sn{$nick}{ip};
+}
+
sub notRestricted {
my ($module, $nick, $restriction) = @_;
$nick = lc $nick;