[BACK]Return to DNS.pm CVS log [TXT][DIR] Up to [local] / botnow

Annotation of botnow/DNS.pm, Revision 1.1

1.1     ! bountyht    1: #!/usr/bin/perl
        !             2:
        !             3: package DNS;
        !             4:
        !             5: use strict;
        !             6: use warnings;
        !             7: use OpenBSD::Pledge;
        !             8: use OpenBSD::Unveil;
        !             9: use Data::Dumper;
        !            10: use File::Copy qw(copy);
        !            11:
        !            12: my %conf = %main::conf;
        !            13: my $chans = $conf{chans};
        !            14: my $staff = $conf{staff};
        !            15: my $key = $conf{key};
        !            16: my $hash = $conf{hash};
        !            17: my $hostname = $conf{hostname};
        !            18: my $verbose = $conf{verbose};
        !            19: my $ipv4 = $conf{ipv4};
        !            20: my $zonedir = $conf{zonedir};
        !            21: my $ipv6path = $conf{ipv6path};
        !            22: my $hostnameif = $conf{hostnameif};
        !            23: # Validate ipv6s if it exists, otherwise load addresses from /etc/hostname.if
        !            24: my @ipv6s;
        !            25: if (!(-s "$ipv6path")) {
        !            26:        print "No IPv6 addresses in $ipv6path, loading from $hostnameif...\n";
        !            27:        @ipv6s = readipv6s($hostnameif);
        !            28: } else {
        !            29:        @ipv6s = readipv6s($ipv6path);
        !            30: }
        !            31: if (!@ipv6s) { die "No IPv6 addresses in $ipv6path or $hostnameif!"; }
        !            32: if (host($hostname) =~ /(\d+\.){3,}\d+/) {
        !            33:        $ipv4 = $&;
        !            34: }
        !            35: main::cbind("msg", "-", "setrdns", \&msetrdns);
        !            36: main::cbind("msg", "-", "delrdns", \&mdelrdns);
        !            37: main::cbind("msg", "-", "setdns", \&msetdns);
        !            38: main::cbind("msg", "-", "deldns", \&mdeldns);
        !            39: main::cbind("msg", "-", "host", \&mhost);
        !            40: main::cbind("msg", "-", "nextdns", \&mnextdns);
        !            41:
        !            42: sub init {
        !            43:        unveil("$ipv6path", "rwc") or die "Unable to unveil $!";
        !            44:        unveil("$zonedir", "rwc") or die "Unable to unveil $!";
        !            45:        #dependencies for doas
        !            46:        unveil("/usr/bin/doas", "rx") or die "Unable to unveil $!";
        !            47:        #dependencies for host
        !            48:        unveil("/usr/bin/host", "rx") or die "Unable to unveil $!";
        !            49: }
        !            50:
        !            51: sub msetrdns {
        !            52:        my ($bot, $nick, $host, $hand, $text) = @_;
        !            53:        if (! (main::isstaff($bot, $nick))) { return; }
        !            54:        if ($text =~ /^([0-9A-Fa-f:\.]{3,})\s+([-0-9A-Za-z\.]+)/) {
        !            55:                my ($ip, $hostname) = ($1, $2);
        !            56:                if (setrdns($ip, $hostname)) {
        !            57:                        main::putserv($bot, "PRIVMSG $nick :$hostname set to $ip");
        !            58:                } else {
        !            59:                        main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set rDNS");
        !            60:                }
        !            61:        }
        !            62: }
        !            63: sub mdelrdns {
        !            64:        my ($bot, $nick, $host, $hand, $text) = @_;
        !            65:        if (! (main::isstaff($bot, $nick))) { return; }
        !            66:        if ($text =~ /^([0-9A-Fa-f:\.]{3,})$/) {
        !            67:                my $ip = $1;
        !            68:                my $hostname = "notset";
        !            69:                if (setrdns($ip, $hostname)) {
        !            70:                        main::putserv($bot, "PRIVMSG $nick :$ip rDNS deleted");
        !            71:                } else {
        !            72:                        main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set rDNS");
        !            73:                }
        !            74:        }
        !            75: }
        !            76: sub msetdns {
        !            77:        my ($bot, $nick, $host, $hand, $text) = @_;
        !            78:        if (! (main::isstaff($bot, $nick))) { return; }
        !            79:        if ($text =~ /^([-0-9A-Za-z\.]+)\s+([0-9A-Fa-f:\.]+)/) {
        !            80:                my ($hostname, $ip) = ($1, $2);
        !            81:                if (setdns($hostname, $ip)) {
        !            82:                        main::putserv($bot, "PRIVMSG $nick :$hostname set to $ip");
        !            83:                } else {
        !            84:                        main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set DNS");
        !            85:                }
        !            86:        }
        !            87: }
        !            88: sub mdeldns {
        !            89:        my ($bot, $nick, $host, $hand, $text) = @_;
        !            90:        if (! (main::isstaff($bot, $nick))) { return; }
        !            91:        if ($text =~ /^([-0-9A-Za-z\.]+)/) {
        !            92:                if (setdns($text)) {
        !            93:                        main::putserv($bot, "PRIVMSG $nick :$text deleted");
        !            94:                } else {
        !            95:                        main::putserv($bot, "PRIVMSG $nick :ERROR: failed to delete DNS records");
        !            96:                }
        !            97:        }
        !            98: }
        !            99: sub mhost {
        !           100:        my ($bot, $nick, $host, $hand, $text) = @_;
        !           101:        if (! (main::isstaff($bot, $nick))) { return; }
        !           102:        if ($text =~ /^([-0-9A-Za-z:\.]{3,})/) {
        !           103:                my ($hostname, $version) = ($1, $2);
        !           104:                main::putserv($bot, "PRIVMSG $nick :".host($hostname));
        !           105:        }
        !           106: }
        !           107:
        !           108: sub mnextdns {
        !           109:        my ($bot, $nick, $host, $hand, $text) = @_;
        !           110:        if (! (main::isstaff($bot, $nick))) { return; }
        !           111:        if ($text =~ /^([-0-9a-zA-Z]+)/) {
        !           112:                main::putserv($bot, "PRIVMSG $nick :$text set to ".nextdns($text));
        !           113:        }
        !           114: }
        !           115:
        !           116: # Given filename, return a list of ipv6 addresses
        !           117: sub readipv6s {
        !           118:        my ($filename) = @_;
        !           119:        my @lines = main::readarray($filename);
        !           120:        my @ipv6s;
        !           121:        foreach my $line (@lines) {
        !           122:                if ($line =~ /^\s*inet6 (alias )?([0-9a-f:]{4,}) [0-9]+\s*$/i) {
        !           123:                        push(@ipv6s, $2);
        !           124:                } elsif ($line =~ /^\s*([0-9a-f:]{4,})\s*$/i) {
        !           125:                        push(@ipv6s, $1);
        !           126:                }
        !           127:        }
        !           128:        return @ipv6s;
        !           129: }
        !           130:
        !           131: # TODO: fix rdns request with buyvm's api, the ips must not skip 0s
        !           132: # returns true upon success, false upon failure
        !           133: sub setrdns {
        !           134:        my ($ip, $hostname) = @_;
        !           135:        my $stdout = `curl -d \"key=$key&hash=$hash&action=rdns&ip=$ip&rdns=$hostname\" https://manage.buyvm.net/api/client/command.php`;
        !           136:        if ($stdout !~ /success/) {
        !           137:                return 0;
        !           138:        }
        !           139:         return 1;
        !           140: }
        !           141: # set $domain to $ip if provided; otherwise, delete $domain
        !           142: # returns true upon success, false upon failure
        !           143: sub setdns {
        !           144:        my ($domain, $ip) = @_;
        !           145:        my $filename = "$zonedir/$hostname";
        !           146:        my $subdomain;
        !           147:        if ($domain =~ /^([a-zA-Z][-\.a-zA-Z0-9]+)\.$hostname$/) {
        !           148:                $subdomain = $1;
        !           149:        } else {
        !           150:                return 0;
        !           151:        }
        !           152:        my @lines = main::readarray($filename);
        !           153:        foreach my $line (@lines) {
        !           154:                # increment the zone's serial number
        !           155:                if ($line =~ /(\d{8})(\d{2})((\s+\d+){4}\s*\))/) {
        !           156:                        my $date = main::date();
        !           157:                        my $serial = 0;
        !           158:                        if ($date <= $1) { $serial = $2+1; }
        !           159:                        $line = $`.$date.sprintf("%02d",$serial).$3.$';
        !           160:                }
        !           161:        }
        !           162:        if ($ip =~ /^([0-9\.]+)$/) { # if IPv4
        !           163:                push(@lines, "$subdomain        3600    IN      A       $ip");
        !           164:        } elsif ($ip =~ /:/) { # if IPv6
        !           165:                push(@lines, "$subdomain        3600    IN      AAAA    $ip");
        !           166:        } elsif (!defined($ip)) { # delete records
        !           167:                @lines = grep !/\b$subdomain\s*3600\s*IN/, @lines;
        !           168:        }
        !           169:        # trailing newline necessary
        !           170:        main::writefile("$filename.bak", join("\n", @lines)."\n");
        !           171:        copy "$filename.bak", $filename;
        !           172:        if (system("doas -u _nsd nsd-control reload")) {
        !           173:                return 0;
        !           174:        } else {
        !           175:                return 1;
        !           176:        }
        !           177: }
        !           178:
        !           179: # given hostname, return IP addresses; or given IP address, return hostname
        !           180: sub host {
        !           181:        my ($name) = @_;
        !           182:        my @matches;
        !           183:        my @lines = split /\n/m, `host $name`;
        !           184:        if ($name =~ /^[0-9\.]+$/ or $name =~ /:/) { # IP address
        !           185:                foreach my $line (@lines) {
        !           186:                        if ($line =~ /([\d\.]+).(in-addr|ip6).arpa domain name pointer (.*)/) {
        !           187:                                push(@matches, $3);
        !           188:                        }
        !           189:                }
        !           190:        } else { # hostname
        !           191:                foreach my $line (@lines) {
        !           192:                        if ($line =~ /$name has (IPv6 )?address ([0-9a-fA-F\.:]+)/) {
        !           193:                                push(@matches, $2);
        !           194:                        }
        !           195:                }
        !           196:        }
        !           197:        return join(' ', @matches);
        !           198: }
        !           199:
        !           200: # create A and AAAA records for subdomain, set the rDNS,
        !           201: # and return the new ipv6 address
        !           202: sub nextdns {
        !           203:        my ($subdomain) = @_;
        !           204:        my $ipv6 = shift(@ipv6s);
        !           205:        my $fqdn = "$subdomain.$hostname";
        !           206:        main::writefile($ipv6path, join("\n", @ipv6s));
        !           207:        if (setdns($fqdn, $ipv4) && setdns($fqdn, $ipv6) && setrdns($ipv6, $fqdn)) {
        !           208:                return "$ipv6";
        !           209:        }
        !           210:        return "false";
        !           211: }
        !           212:
        !           213: 1; # MUST BE LAST STATEMENT IN FILE

CVSweb