Perl IRC Bot (Goki) + ChanOp plugin

Goki is an IRC Bot written in perl, very easy to install, use and develop. One of the best things about Goki is it doesn’t require any additional modules, just give it a try http://goki.sf.net.

Since Goki has no authentication yet, I did a small plugin which will handle a very primitive user’s access list and a few basic channel operator’s commands, nothing more but what you are reading 😉

Follow the instructions:

– Create a file plugin/chanop.pm (or whatever you want)
– Paste the following code:

package chanop; 
#use warnings; # we don't need warnings, we know it's dirty code ;) 
 
# Module wide variables 
 
# add as many nicks as you want, and remember, in order to authenticate  
# you need to have the same nick name (not case sensitive) 
my %chanops = ( 
'xUx' => '12345', 
'demonick' => 'demopass', 
'nick2' => 'somethinghere' 
); 
 
# careful, moving things here could make the bot crash :) 
my %chdata = (); # hash that will hold all data 
 
foreach $key (sort keys %chanops) { 
%{$chdata{lc($key)}} = ('nick' => lc($key), 'pass' => $chanops{$key}); 
} 
 
# Module load functions. Set default values here. 
BEGIN { 
our $VERSION = 0.4; 
$irc = main::IRC; 
# private events 
$irc->add_handler('privcmd auth','do_auth'); 
$irc->add_handler('privcmd who','do_who'); 
$irc->add_handler('privcmd join','do_join'); 
$irc->add_handler('privcmd part','do_part'); 
$irc->add_handler('privcmd kick','do_kick'); 
$irc->add_handler('privcmd ban','do_ban'); 
$irc->add_handler('privcmd voice','do_voice'); 
$irc->add_handler('privcmd devoice','do_devoice'); 
$irc->add_handler('privcmd op','do_op'); 
$irc->add_handler('privcmd deop','do_deop'); 
$irc->add_handler('privcmd sh','do_sh'); 
$irc->add_handler('privcmd say','do_say'); 
} 
 
sub do_say { 
my ( $nick, $hostmask, $text ) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
my $msg = join(" ",@args[1 .. scalar(@args)-1]); 
main::plog "Message sent from $nick to $args[0]\n"; 
$irc->say($args[0],$msg); 
} 
 
sub do_sh { 
my ( $nick, $hostmask, $text ) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
main::plog "Exec attempt by $nick\n"; 
my @output = `$text`; 
my $line; 
foreach $line (@output) { 
$irc->say($nick, $line); 
} 
} 
 
sub do_deop { 
# deop #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Deop on $args[0] to $args[1] by $nick\n"; 
$irc->deop($args[0],$args[1]); 
} 
 
sub do_op { 
# op #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Op on $args[0] to $args[1] by $nick\n"; 
$irc->op($args[0],$args[1]); 
} 
 
sub do_devoice { 
# devoice #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
$irc->devoice($args[0],$args[1]); 
} 
 
sub do_voice { 
# voice #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Voice on $args[0] to $args[1] by $nick\n"; 
$irc->voice($args[0],$args[1]); 
} 
 
sub do_ban { 
# ban #channel nick|hostmask 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Ban on $args[0] to $args[1] by $nick\n"; 
$irc->mode($args[0],"+b",$args[1]); 
} 
 
sub do_kick { 
# kick #channel nick reason 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
my $reason = join(" ",@args[2 .. scalar(@args)-1]) || $args[1]; 
main::plog "Kick on $args[0] to $args[1] ($reason) by $nick\n"; 
$irc->kick($args[0],$args[1],$reason); 
} 
 
sub do_part { 
# part #channel 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Parting $args[0] by $nick\n"; 
$irc->part($args[0]); 
} 
 
sub do_join { 
# join #channel 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Joining $args[0] by $nick\n"; 
$irc->join($args[0]); 
} 
 
sub do_who { 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
foreach my $key (sort keys %chdata) { 
if (exists($chdata{$key}{'hostmask'})) { 
$irc->say($nick, $chdata{$key}{'nick'} . " (". $chdata{$key}{'hostmask'}.")"); 
} 
} 
return; 
} 
 
sub do_auth_check { 
my ($nick,$hostmask) = @_; 
my $tmphostmask = (split("\!",$hostmask))[1]; 
if (!exists($chdata{lc($nick)}{'hostmask'})) { 
main::plog "Unauthorized access from $hostmask\n"; 
return 0; 
} 
if ($chdata{lc($nick)}{'hostmask'} eq $tmphostmask) { return 1; } 
return 0; 
} 
 
sub do_auth { 
my ($nick,$hostmask,$text) = @_; 
my $tmphostmask = (split("\!",$hostmask))[1]; 
if (!exists($chdata{lc($nick)})) { 
main::plog "Invalid user tried to AUTH: $nick ($tmphostmask)\n"; 
return; 
} 
my @args = split(" ",$text); 
if ($chdata{lc($nick)}{'pass'} ne $args[0]) { 
main::plog "Invalid Login attemp from $nick ($tmphostmask)\n"; 
$irc->notice($nick,"Invalid Password, attemp logged!"); 
return; 
} 
if (exists($chdata{lc($nick)}{'hostmask'})) { 
main::plog "RE-AUTH from $nick from ".$chdata{lc($nick)}{'hostmask'}." to $tmphostmask\n"; 
} 
else { main::plog "AUTH from $nick from $tmphostmask\n"; } 
$chdata{lc($nick)}{'hostmask'} = $tmphostmask; 
$irc->notice($nick, "Authentication Succesful!"); 
} 
 
return 1; 
 
# Module unload functions, free memory and close open filehandles here 
END { 
# Does not currently work, but is here for future compatibility 
# $irc->del_handler( '', '' ); 
} 

– Edit file conf/plugin.conf and make it load your plugin by adding a line with the word “chanop” (or the first part of your thanemayoupicked.pm)
– Start your bot and have fun 😉

For future reference and user’s comments go to http://sourceforge.net/forum/forum.php?thread_id=2185241&forum_id=621728

IP updater for EditDNS.net

As anyone know (and should know) EditDNS it’s the best alternative for DNS Management and the best of all it is FREE 😉

Here I wrote/adapted some code which will allow you to update your dynamic IP through EditDNS’s API.

Requirements:

  • You need to register first! (duh)
  • Donations are optional, but if it makes your life easier you should consider it and you’ll also get more services.
  • Perl!

File: editdns.pl

#!/usr/bin/perl

use strict;

## Configure ONLY this 2 variables
my $editdns_pass   = "a"; # put your password
my $editdns_record = "b"; # put the record you wish to update

## ###############
## Nothing else should be changed unless you know what to do
## ###############

my $host = "DynDNS.EditDNS.net";
my $port = 80;
my $editdns_post = "p=$editdns_pass&r=$editdns_record";

my $editdns_req = join("",
  "POST /api/dynLinux.php HTTP/1.0\r\n",
  "Host: $host:$port\r\n",
  "User-Agent: EditDNS Browser 0.1\r\n",
  "Referer: http://www.editdns.net\r\n",
  "Content-Type: application/x-www-form-urlencoded\r\n",
  "Content-Length: ".length($editdns_post)."\r\n\r\n",
  "$editdns_post\n"
);

my $hostaddr = (gethostbyname($host))[4] || &error("Couldn't get IP for $host");
my $remotehost= pack('S n a4 x8',2,$port,$hostaddr);
socket(S,2,1,6) || &error("Couldn't create socket");
connect(S,$remotehost) || &error("Couldn't connect to $host:$port");
select((select(S),$|=1)[0]);
print S $editdns_req;
vec(my $rin='',fileno(S),1)= 1 ;
select($rin,undef,undef,60) || &error("No response from $host:$port");
undef($/);
close(S);
print "[DONE]\n";
exit;

sub error {
        print "[ERROR] $_[0]\n";
        exit;
}

Next and once you have configured the script:

chmod +x editdns.pl
pico /etc/crontab
# Add editdns.pl to execute every 15 minutes
*/15 * * * * root /path/editdns.pl > /dev/null 2>&1

Do not set intervals lower than 15 minutes, since it can be considered as an abuse and you’ll get banned.

Part of this code was taken from James Marshal, happy coding!

*** If you are looking for SSL support and multiple records you might want to check http://xux.in/blog/post/php-editdns-updater-for-linux/