Files
webmin/dnsadmin/dns-lib.pl
2017-11-08 16:43:37 +08:00

221 lines
5.2 KiB
Perl
Executable File

# dnsadmin common functions
BEGIN { push(@INC, ".."); };
use WebminCore;
&init_config();
&foreign_require("bind8", "bind8-lib.pl");
do "$bind8::module_root_directory/records-lib.pl";
# mapping between record types and names
%code_map = ("A", "Address", "NS", "Name Server", "CNAME", "Name Alias",
"MX", "Mail Server", "HINFO", "Host Information", "TXT", "Text",
"WKS", "Well Known Service", "RP", "Responsible Person",
"PTR", "Reverse Address");
# get_config()
# Returns the current bind4 configuration
sub get_config
{
if (!@get_config_cache) {
@get_config_cache = &read_config_file($config{'named_boot_file'});
}
return \@get_config_cache;
}
# read_config_file(filename, [don't expand includes])
# Read and parse a BIND4 format config file
sub read_config_file
{
# read primary config file
local $lnum = 0;
local $n = 0;
local($i, $j, @rv);
open(CONF, $_[0]);
while(<CONF>) {
s/\r|\n//g; # strip newline
s/;.*$//g; # strip comments
s/\s+$//g; # strip trailing spaces
if (/^(\S+)\s*(.*)$/) {
local(%dir);
$dir{'name'} = $1;
$dir{'value'} = $2;
$dir{'values'} = [ split(/\s+/, $2) ];
$dir{'line'} = $lnum;
$dir{'file'} = $_[0];
$dir{'index'} = $n++;
push(@rv, \%dir);
}
$lnum++;
}
close(CONF);
# expand include directives
for($i=0; $i<@rv; $i++) {
if ($rv[$i]->{'name'} eq "include" && !$_[1]) {
# replace this include directive
$inc = $rv[$i]->{'value'};
if ($inc !~ /^\//) {
$inc = &base_directory(\@rv)."/".$inc;
}
@inc = &read_config_file($inc, 1);
# update index of included structures
for($j=0; $j<@inc; $j++) {
$inc[$j]->{'index'} += $rv[$i]->{'index'};
}
# update index of directives after include
for($j=$i+1; $j<@rv; $j++) {
$rv[$j]->{'index'} += scalar(@inc) - 1;
}
splice(@rv, $i--, 1, @inc);
}
}
return @rv;
}
# find_config(name, &array)
sub find_config
{
local($c, @rv);
foreach $c (@{$_[1]}) {
if ($c->{'name'} eq $_[0]) {
push(@rv, $c);
}
}
return @rv ? wantarray ? @rv : $rv[0]
: wantarray ? () : undef;
}
# base_directory([&config])
# Returns the base directory for include and domain files
sub base_directory
{
$conf = @_ ? $_[0] : &get_config();
$dir = &find_config("directory", $conf);
if ($dir) { return $dir->{'values'}->[0]; }
$config{'named_boot_file'} =~ /^(.*)\/[^\/]+$/;
return $1;
}
# create_zone(&details)
sub create_zone
{
local(@v) = @{$_[0]->{'values'}};
open(ZONE, ">> $config{'named_boot_file'}");
print ZONE $_[0]->{'name'}.(@v ? " ".join(" ", @v) : "")."\n";
close(ZONE);
}
# modify_zone(&old, &details)
sub modify_zone
{
local(@v) = @{$_[1]->{'values'}};
&replace_file_line($_[0]->{'file'}, $_[0]->{'line'},
$_[1]->{'name'}.(@v ? " ".join(" ", @v) : "")."\n");
}
# delete_zone(&old)
sub delete_zone
{
&replace_file_line($_[0]->{'file'}, $_[0]->{'line'});
}
# find_reverse(address)
# Returns the zone and record structures for the PTR record for some address
sub find_reverse
{
local($conf, @zl, $rev, $z, $revconf, $revfile, $revrec, @revrecs, @octs, $rr);
# find reverse domain
$conf = &get_config();
@zl = &find_config("primary", $conf);
@octs = split(/\./, $_[0]);
for($i=2; $i>=0; $i--) {
$rev = &ip_to_arpa(join('.', @octs[0..$i]));
$rev =~ s/\.$//g;
foreach $z (@zl) {
if (lc($z->{'values'}->[0]) eq $rev) {
# found the reverse master domain
$revconf = $z;
last;
}
}
}
# find reverse record
if ($revconf) {
$revfile = $revconf->{'values'}->[1];
@revrecs = &read_zone_file($revfile, $revconf->{'values'}->[0]);
local $addr = &ip_to_arpa($_[0]);
foreach $rr (@revrecs) {
if ($rr->{'type'} eq "PTR" &&
lc($rr->{'name'}) eq lc($addr)) {
# found the reverse record
$revrec = $rr;
last;
}
}
}
return ($revconf, $revfile, $revrec);
}
# find_forward(address)
# Returns the zone and record structures for the A record for some address
sub find_forward
{
local($conf, @zl, $fwd, $z, $fwdconf, $fwdfile, $fwdrec, @fwdrecs, @octs, $rr);
# find reverse domain
local $host = $_[0]; $host =~ s/\.$//;
$conf = &get_config();
@zl = &find_config("primary", $conf);
local @parts = split(/\./, $host);
DOMAIN: for($i=1; $i<@parts; $i++) {
local $fwd = join(".", @parts[$i .. @parts-1]);
foreach $z (@zl) {
local $typed;
if (lc($z->{'values'}->[0]) eq $fwd) {
# Found the forward master!
$fwdconf = $z;
last DOMAIN;
}
}
}
# find forward record
if ($fwdconf) {
$fwdfile = $fwdconf->{'values'}->[1];
local @fwdrecs = &read_zone_file($fwdfile, $fwdconf->{'values'}->[0]);
foreach $fr (@fwdrecs) {
if ($fr->{'type'} eq 'A' &&
$fr->{'name'} eq $_[0]) {
# found the forward record
$fwdrec = $fr;
last;
}
}
}
return ($fwdconf, $fwdfile, $fwdrec);
}
# can_edit_zone(&access, zone)
sub can_edit_zone
{
local %zcan;
return 1 if ($access{'zones'} eq '*');
foreach (split(/\s+/, $access{'zones'})) {
return 1 if ($_ eq $_[1]);
}
return 0;
}
sub make_chroot
{
return $_[0];
}
1;