<?php
// IPplan v4.92a
// Aug 24, 2001
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// workaround for funky behaviour of nested includes with older
// versions of php
require_once(dirname(__FILE__)."/config.php");
// common class functions for forward and reverse zones
class DNSZone extends IPplanDbf {
// form variables
var $hname;
var $ttl;
var $refresh;
var $retry;
var $expire;
var $minimum;
var $responsiblemail;
var $slaveonly;
var $zonepath;
var $seczonepath;
var $info="";
var $serialdate=0;
var $serialnum=0;
// local class variables
var $grps;
var $errstr = "";
var $err = 1;
var $clone = 0;
function SetSOA($hname, $ttl, $refresh, $retry, $expire, $minimum,
$responsiblemail, $slaveonly, $zonepath, $seczonepath, $info="") {
$this->hname = $hname;
$this->ttl = $ttl;
$this->refresh = $refresh;
$this->retry = $retry;
$this->expire = $expire;
$this->minimum = $minimum;
$this->responsiblemail = $responsiblemail;
$this->slaveonly = $slaveonly;
$this->zonepath = $zonepath;
$this->seczonepath = $seczonepath;
$this->info = $info;
}
function SetSerial($serialdate, $serialnum) {
$this->serialdate=$serialdate;
$this->serialnum=$serialnum;
}
// work out the new serial number from a previous SetSerial
function Serial() {
$now = getdate();
$newserialdate = $now["year"] . str_pad($now["mon"], 2, '0', STR_PAD_LEFT) . str_pad( $now["mday"], 2, '0', STR_PAD_LEFT);
if ($this->serialdate==$newserialdate) {
$this->serialnum++;
}else{
$this->serialdate=$newserialdate;
$this->serialnum=0;
}
}
// remove domain name from FQDN, converts to lowercase
// if domain cannot be stripped, return FQDN with trailing .
function strip_domain($hname, $domain) {
$hname=strtolower($hname);
$domain=strtolower($domain);
// use ~ as sperator as this cannot appear in dns name
$temp = preg_replace("~\.$domain$~", "", $hname);
if ($hname===$temp) {
$temp=$hname.".";
}
return $temp;
}
function ZoneAXFR($domain, $server) {
require_once("Net/DNS.php");
$res = new Net_DNS_Resolver();
//$res->debug = 1;
$res->persistent_tcp=1;
$res->nameservers=array($server);
$answer = $res->axfr($domain);
/*
echo "<pre>";
var_dump($answer);
//var_dump($res);
//var_dump($answer[0]->header->rcode);
echo "</pre>";
exit;
*/
// check for errors
/*
if ($res->errorstring != "NOERROR") {
$this->err=70;
$this->errstr .= sprintf(my_("Zone transfer for domain %s failed with message %s"), $this->domain, $res->errorstring)."\n";
return "";
}
*/
if ($answer) {
$this->hname=array(); $i=1; // kill form information
foreach($answer as $rr) {
if ($rr->type == "SOA") {
//var_dump($rr);
$this->ttl=$rr->ttl;
$this->refresh=$rr->refresh;
$this->retry=$rr->retry;
$this->expire=$rr->expire;
$this->minimum=$rr->minimum;
$this->responsiblemail=$rr->rname;
}
if ($rr->type == "NS" and $rr->name == $this->domain) {
$this->hname[$i++]=$this->strip_domain($rr->nsdname, $this->domain);
}
}
$this->err = 0;
return $answer;
} else {
$this->errstr .= sprintf(my_("Zone transfer for domain %s failed - using defaults: %s"), $this->domain, $res->errorstring)."\n";
// could not do transfer, so use defaults from now on!
$this->err = -1;
return "";
}
}
} // end class DNSZone
// specific forward zone functions
class DNSfwdZone extends DNSZone {
var $cust;
var $dataid;
var $domain;
var $server;
var $createmod;
var $expiremod;
var $regmod;
function SetForm($cust, $dataid, $domain) {
$this->cust = $cust;
$this->dataid = $dataid;
$this->domain = $domain;
}
function SetDate($createmod, $expiremod, $regmod) {
$this->createmod = $createmod;
$this->expiremod = $expiremod;
$this->regmod = $regmod;
}
function FwdDelete($cust, $dataid, $domain) {
// use local function variables as they may change
$this->cust = $cust;
$this->rangeindex = $dataid;
$this->areaindex = $domain;
// check for records
$result = $this->ds->Execute("SELECT recidx
FROM fwdzonerec
WHERE customer=$cust AND data_id=$dataid");
$recs=$result->PO_RecordCount("fwdzonerec", "customer=$cust AND data_id=$dataid");
if ($recs) {
$this->err=50;
$this->errstr .= my_("Cannot delete domain zone - there are still DNS records\n");
return FALSE;
}
$result = $this->ds->Execute("DELETE FROM fwdzone
WHERE customer=$cust AND data_id=$dataid") and
$this->ds->Execute("DELETE FROM fwdzoneadd
WHERE customer=$cust AND data_id=$dataid") and
$this->ds->Execute("DELETE FROM fwddns
WHERE id=$dataid");
return $result;
}
function FwdZoneAddRR ($dataid, $answer) {
$i=5;
foreach($answer as $rr) {
if ($rr->type == "A") {
$recordtype=$rr->type;
$host=$this->strip_domain($rr->name, $this->domain);
$iphostname=$rr->address;
}
else if ($rr->type == "CNAME") {
$recordtype=$rr->type;
$host=$this->strip_domain($rr->name, $this->domain);
$iphostname=$this->strip_domain($rr->cname, $this->domain);
}
else if ($rr->type == "NS" and $rr->name != $this->domain) {
$recordtype=$rr->type;
$host=$this->strip_domain($rr->name, $this->domain);
$iphostname=$this->strip_domain($rr->nsdname, $this->domain);
}
else if ($rr->type == "MX") {
$recordtype=$rr->type;
$host=$this->strip_domain($rr->name, $this->domain);
$iphostname=$rr->preference." ".$this->strip_domain($rr->exchange, $this->domain);
}
else if ($rr->type == "TXT") {
$recordtype=$rr->type;
$host=$this->strip_domain($rr->name, $this->domain);
// truncate TXT field to 254 chars - can be much bigger
$iphostname=substr($rr->rdata, 1, $rr->rdlength > 254 ? 254 : $rr->rdlength);
}
else if ($rr->type == "SRV") {
$recordtype=$rr->type;
$host=$this->strip_domain($rr->name, $this->domain);
$iphostname=$rr->preference." ".$rr->weight." ".$rr->port." ".$this->strip_domain($rr->target, $this->domain);
}
else if ($rr->type == "AFSDB") {
$recordtype=$rr->type;
$host=$this->strip_domain($rr->name, $this->domain);
$iphostname=$rr->preference." ".$this->strip_domain($rr->exchange, $this->domain);
}
else {
continue;
}
$result = $this->ds->Execute("INSERT into fwdzonerec
(customer, data_id, sortorder, lastmod, host,
recordtype, userid, ip_hostname) ".
"VALUES ($this->cust, $dataid, ". $i.",".
$this->ds->DBTimeStamp(time()).",".
$this->ds->qstr($host).",".
$this->ds->qstr($recordtype).",".
$this->ds->qstr(getAuthUsername()).",".
$this->ds->qstr($iphostname).")" );
if (!$result) {
return FALSE;
}
$i=$i+5;
}
return TRUE;
}
function FwdAddNS($dataid) {
// add reverse DNS into fwddns table
for ($i = 1; $i < 11; $i++) {
if (isset($this->hname[$i]) and !empty($this->hname[$i])) {
$hnametemp=$this->hname[$i];
// add DNS records
$result=$this->ds->Execute("INSERT INTO fwddns
(id, hname, horder)
VALUES
($dataid,
".$this->ds->qstr($hnametemp).",
$i)");
if (!$result) {
return FALSE;
}
}
}
return TRUE;
}
// test if the zone exists and lock for update
function FwdZoneExists($cust, $dataid) {
// need to do select as mysql driver does not have RowLock
// mysqlt does have rowlock
$row = $this->ds->GetOne("SELECT data_id
FROM fwdzone
WHERE customer=$cust AND data_id=$dataid");
$this->ds->RowLock("fwdzone", "customer=$cust AND data_id=$dataid");
return !empty($row);
}
function FwdUpdateSOA($cust, $dataid) {
// use local function variables as they may change
$this->cust = $cust;
if (!$this->FwdZoneExists($cust, $dataid)) {
$this->err=90;
$this->errstr .= my_("Could not find the zone - possibly deleted by another user")."\n";
return FALSE;
}
// work out new serial numbers
$this->Serial();
// check and warn if there are zone records if slaveonly=Y
if ($this->slaveonly=="Y") {
$result = $this->ds->Execute("SELECT count(*) AS cnt
FROM fwdzonerec
WHERE customer=$cust AND data_id=$dataid");
// loop through each host record
$row = $result->FetchRow();
if($row["cnt"] > 0) {
$this->err=-50;
$this->errstr .= my_("You are changing this zone to a slave only zone, but there are zone records\n");
}
}
// Updated DB here.
$result = $this->ds->Execute("UPDATE fwdzone ".
"set serialdate=".$this->ds->qstr($this->serialdate).
", serialnum=$this->serialnum".
",ttl=".$this->ttl.
",refresh=".$this->refresh.
",retry=".$this->retry.
",expire=".$this->expire.
",minimum=".$this->minimum.
",error_message=".$this->ds->qstr("E").
",responsiblemail=".$this->ds->qstr($this->responsiblemail).
",userid=".$this->ds->qstr(getAuthUsername()).
",zonefilepath1=".$this->ds->qstr($this->zonepath).
",zonefilepath2=".$this->ds->qstr($this->seczonepath).
",createmod=".$this->ds->DBDate($this->createmod).
",lastmod=".$this->ds->DBTimeStamp(time()).
",expiremod=".$this->ds->DBDate($this->expiremod).
",regmod=".$this->ds->DBDate($this->regmod).
",slaveonly=".$this->ds->qstr($this->slaveonly).
" WHERE customer=$cust AND data_id=".$dataid );
if($this->ds->GetRow("SELECT info
FROM fwdzoneadd
WHERE customer=$cust AND
data_id=$dataid")) { // should have FOR UPDATE here!
$result = $this->ds->Execute("UPDATE fwdzoneadd ".
"set info=".$this->ds->qstr($this->info).
" WHERE customer=$cust AND data_id=".$dataid );
}
else { // no record, insert
if (!empty($this->info)) {
$result = $this->ds->Execute("INSERT into fwdzoneadd (customer, data_id, info) ".
"VALUES ($this->cust,".
$dataid.",".
$this->ds->qstr($this->info).")" );
}
}
// delete all the DNS records first to preserve correct order
$result=$this->ds->Execute("DELETE FROM fwddns
WHERE id=$dataid");
// add reverse DNS into fwdzone table
$this->FwdAddNS($dataid);
return $result;
}
function FwdAddSOA() {
// work out new serial numbers
$this->Serial();
// Add to DB here.
$result = $this->ds->Execute("INSERT into fwdzone (customer, domain, error_message,
createmod, lastmod, expiremod, regmod, serialdate, serialnum, ttl, refresh, retry,
expire, minimum, responsiblemail, userid, zonefilepath1, zonefilepath2, slaveonly) ".
"VALUES ($this->cust,".
$this->ds->qstr($this->domain).",".
$this->ds->qstr("E").",".
$this->ds->DBDate($this->createmod).",".
$this->ds->DBTimeStamp(time()).",".
$this->ds->DBDate($this->expiremod).",".
$this->ds->DBDate($this->regmod).",".
$this->ds->qstr($this->serialdate).", $this->serialnum,".
$this->ttl.",".
$this->refresh.",".
$this->retry.",".
$this->expire.",".
$this->minimum.",".
$this->ds->qstr($this->responsiblemail).",".
$this->ds->qstr(getAuthUsername()).",".
$this->ds->qstr($this->zonepath).",".
$this->ds->qstr($this->seczonepath).",".
$this->ds->qstr($this->slaveonly).")" );
// did not fail due to key error?
// should not fail as we checked this already!
if ($result) {
if (DBF_TYPE=="mysql" or DBF_TYPE=="maxsql") {
$dataid=$this->ds->Insert_ID();
}
else {
// emulate getting the last insert_id
$result=$this->ds->Execute("SELECT data_id
FROM fwdzone
WHERE customer=$this->cust AND
domain=".$this->ds->qstr($this->domain));
$temprow = $result->FetchRow();
$dataid=$temprow["data_id"];
}
if (!empty($info)) {
$result = $this->ds->Execute("INSERT into fwdzoneadd (customer, data_id, info) ".
"VALUES ($this->cust,".
$dataid.",".
$this->ds->qstr($this->info).")" );
}
return $dataid;
}
// key error?
return 0;
}
function FwdAdd($cust, $domain, $server) {
// use local function variables as they may change
$this->cust = $cust;
// is the server variable set? then do zone transfer
// should really only read SOA if slaveonly set
if (!empty($server)) {
$answer=$this->ZoneAXFR($this->domain, $server);
// fatal zone transfer error?
if ($this->err > 0) {
return $this->err;
}
}
// could use unique key on database to do check, but requires extra key
// just to add a new record
$restemp=$this->ds->Execute("SELECT domain FROM fwdzone
WHERE customer=$cust AND domain = ".$this->ds->qstr($this->domain));
if ($restemp->FetchRow()) {
// domain already exists, fail transaction
$this->err=-60;
$this->errstr .= sprintf(my_("DNS Domain %s could not be created - possibly duplicate zone"), $this->domain)."\n";
}
else {
// create the actual zone
$dataid=$this->FwdAddSOA();
$this->dataid=$dataid;
// did not fail due to key error?
if ($dataid) {
if(!$this->FwdAddNS($dataid)) {
$this->err = -60;
return $this->err;
}
// now load individual rr records if zone transfer requested
// only if not a slavezone and no previous error
if (!empty($server) and $this->slaveonly=="N" and !empty($answer)) {
if(!$this->FwdZoneAddRR($dataid, $answer)) {
$this->err = -60;
return $this->err;
}
}
// or clone zone if clone requested
else if (empty($server) and $this->slaveonly=="N" and $this->clone) {
// this SQL only works with MySql v >= 4.0.14
$result=$this->ds->Execute("INSERT INTO fwdzonerec
(data_id, host, recordtype, ip_hostname, sortorder, customer, userid, lastmod)
SELECT $dataid AS data_id, fwdzonerec.host, fwdzonerec.recordtype,
fwdzonerec.ip_hostname, fwdzonerec.sortorder, fwdzonerec.customer,
".$this->ds->qstr(getAuthUsername())." AS userid,
".$this->ds->DBTimeStamp(time())." AS lastmod
FROM fwdzonerec, fwdzone
WHERE fwdzonerec.data_id=fwdzone.data_id AND
fwdzone.domain=".$this->ds->qstr("template.com"));
}
$this->err = 0;
}
else {
$this->err = -60;
$this->errstr .= sprintf(my_("DNS Domain %s could not be created - possibly duplicate zone"), $this->domain)."\n";
}
}
return $this->err;
}
function FwdZoneExport($cust, $dataid) {
// use local function variables as they may change
$this->cust = $cust;
$this->Serial();
// Update DNS Database Serial Count. Update Serial Count only when we export.
$result = $this->ds->Execute("UPDATE fwdzone ".
"set serialdate=".$this->ds->qstr($this->serialdate).
", userid=".$this->ds->qstr(getAuthUsername()).
", error_message=".$this->ds->qstr("").
", lastexp=".$this->ds->DBTimeStamp(time()).
", serialnum=$this->serialnum".
" WHERE customer=$cust AND data_id=".$dataid);
if ($result) {
$sqllastmod = $this->ds->SQLDate("M d Y H:i:s", 'lastmod');
$result = $this->ds->Execute("SELECT data_id, domain, engineer, error_message,
responsiblemail, serialdate, serialnum, ttl, refresh, retry, expire,
minimum, zonefilepath1, zonefilepath2, customer, admingrp,
$sqllastmod AS lastmod, userid, slaveonly
FROM fwdzone
WHERE customer=$cust AND data_id=$dataid");
$row = $result->FetchRow();
$this->domain=$row["domain"];
$info = $this->ds->GetOne("SELECT info
FROM fwdzoneadd
WHERE customer=$cust AND data_id=$dataid");
$tmpfname = tempnam (DNSEXPORTPATH, "zone_".$this->domain."_");
if(!$tmpfname) {
$this->err=80;
$this->errstr .= my_("Could not create temporary file!");
return;
}
$fp = fopen ("$tmpfname", "w");
// header of document
$output='<?xml version="1.0" ?>';
fputs($fp, $output);
fputs($fp, "\n");
fputs($fp, sprintf('<zone domain="%s" slaveonly="%s">', $row["domain"],
(empty($row["slaveonly"]) ? "N" : $row["slaveonly"])));
fputs($fp, "\n");
fputs($fp, sprintf("<path>\n<primary>\n%s\n</primary>\n",
htmlspecialchars($row["zonefilepath1"])));
fputs($fp, sprintf("<primaryfile>\n%s\n</primaryfile>\n",
htmlspecialchars(basename($row["zonefilepath1"]))));
fputs($fp, sprintf("<primarydir>\n%s\n</primarydir>\n",
htmlspecialchars(dirname($row["zonefilepath1"]))));
fputs($fp, sprintf("<secondary>\n%s\n</secondary>\n",
htmlspecialchars($row["zonefilepath2"])));
fputs($fp, sprintf("<secondaryfile>\n%s\n</secondaryfile>\n",
htmlspecialchars(basename($row["zonefilepath2"]))));
fputs($fp, sprintf("<secondarydir>\n%s\n</secondarydir>\n",
htmlspecialchars(dirname($row["zonefilepath2"]))));
fputs($fp, "</path>\n");
// SOA portion
fputs($fp, sprintf('<soa serialdate="%s" serialnum="%02d" ttl="%s" retry="%s" refresh="%s" expire="%s" minimumttl="%s" email="%s" />',
$this->serialdate, $this->serialnum,
$row["ttl"],
$row["retry"],
$row["refresh"],
$row["expire"],
$row["minimum"],
$row["responsiblemail"]
));
fputs($fp, "\n");
// additional fields
if (!empty($info)) {
$template=new IPplanIPTemplate("fwdzonetemplate", $cust);
if ($template->is_error() == FALSE) {
$template->Merge($template->decode($info));
fputs($fp, "<additional>\n");
foreach($template->userfld as $field=>$val) {
fputs($fp, sprintf("\t<%s>%s</%s>\n",
htmlspecialchars($field),
htmlspecialchars($val["value"]),
htmlspecialchars($field)));
}
fputs($fp, "</additional>\n");
}
}
// nameservers
$result1 = $this->ds->Execute("SELECT hname
FROM fwddns
WHERE id=$dataid
ORDER BY horder");
$cnt=0;
while($row1 = $result1->FetchRow()) {
fputs($fp, '<record><NS>');
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row1["hname"]));
fputs($fp, '</NS></record>');
fputs($fp, "\n");
$cnt++;
}
if ($cnt < 2) {
fclose($fp);
unlink($tmpfname);
$this->err=70;
$this->errstr .= my_("Invalid zone - zone should have at least two name servers defined")."\n";
return;
}
$sqllastmod = $this->ds->SQLDate("M d Y H:i:s", 'lastmod');
$result = $this->ds->Execute("SELECT recidx, data_id, host, recordtype, ip_hostname,
error_message, sortorder, customer, $sqllastmod AS lastmod, userid
FROM fwdzonerec
WHERE customer=$cust AND data_id=$dataid
ORDER BY sortorder");
// loop through each host record
while($row = $result->FetchRow()) {
fputs($fp, sprintf('<record><%s>', $row["recordtype"]));
fputs($fp, sprintf('<host>%s</host>', $row["host"]));
// MX records are in format "10 hostname.com" in database field ip_hostname
if ($row["recordtype"]=="MX" or $row["recordtype"]=="AFSDB") {
list($preference, $iphost) = explode(" ", $row["ip_hostname"], 2);
if (is_numeric($preference) and $preference >= 0) {
fputs($fp, sprintf('<preference>%s</preference>', $preference));
fputs($fp, sprintf('<iphostname>%s</iphostname>', $iphost));
}
else {
fputs($fp, '<preference>10</preference>');
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row["ip_hostname"]));
}
}
else if ($row["recordtype"]=="SRV")
{
list($priority, $weight, $port, $iphost) = explode(" ", $row["ip_hostname"], 4);
if (is_numeric($priority) and is_numeric($weight) and is_numeric($port)
and $priority >= 0 and $weight >= 0 and $port >= 0 ) {
fputs($fp, sprintf('<preference>%s %s %s</preference>', $priority, $weight, $port));
fputs($fp, sprintf('<iphostname>%s</iphostname>', $iphost));
}
else {
fputs($fp, '<preference> Invalid SRV record </preference>');
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row["ip_hostname"]));
}
}
else {
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row["ip_hostname"]));
}
fputs($fp, sprintf('</%s></record>', $row["recordtype"]));
fputs($fp, "\n");
}
// close zone
fputs($fp, '</zone>');
fputs($fp, "\n");
fclose($fp);
// give file proper extension
rename($tmpfname, $tmpfname.".xml");
@chmod($tmpfname.".xml",0644);
$this->err=0;
return $tmpfname.".xml";
}
//return $tmpfname;
// database error?
}
} // end of class DNSFwdZone
// specific forward zone functions
class DNSrevZone extends DNSZone {
var $cust;
var $zoneid;
var $zone;
var $zoneip;
var $size;
var $server;
function SetForm($cust, $zoneid, $zone, $zoneip, $size) {
$this->cust = $cust;
$this->zoneid = $zoneid;
$this->zone = $zone;
$this->zoneip = $zoneip;
$this->size = $size;
}
function RevDelete($cust, $zoneid, $zone) {
// use local function variables as they may change
$this->cust = $cust;
$result = $this->ds->Execute("DELETE FROM zones
WHERE customer=$cust AND id=$zoneid") and
$this->ds->Execute("DELETE FROM zonedns
WHERE id=$zoneid");
return $result;
}
function RevZoneAddRR ($zoneid, $answer) {
global $grps;
// open a new database connection
$ds = new Base();
if(!$ds) {
$this->err=90;
$this->errstr .= my_("Could not connect to database");
}
$ds->SetGrps($grps);
$ds->SetSearchIn(1);
foreach($answer as $rr) {
if ($rr->type == "PTR") {
$recordtype=$rr->type;
$domain=$rr->ptrdname; // proper domain name
$host=$rr->name; // in format 46.61.110.147.in-addr.arpa
}
else {
continue;
}
// now split ip address
list($oc1, $oc2, $oc3, $oc4, $tail) = split("\.", $host, 5);
$ipaddr="$oc4.$oc3.$oc2.$oc1";
if (testIP($ipaddr)) {
$this->errstr .= sprintf(my_("Invalid address %s"), $ipaddr)."\n";
continue;
}
$ds->SetIPaddr($ipaddr);
$result = $ds->FetchBase($this->cust, 0, 0);
if (!$result) {
$this->err=70;
$this->errstr .= $ds->errstr;
}
// add records here - got a match for a subnet
if ($row = $result->FetchRow()) {
$baseindex=$row["baseindex"];
$affected=$ds->UpdateIP(inet_aton($ipaddr), $baseindex, "hname", $domain);
if (!$affected) {
$ds->AddIP(inet_aton($ipaddr), $baseindex, "", "", "", "",
"Reverse zone import", $domain, "");
}
}
// no subnet matched, add something to the error string
else {
$this->errstr .= sprintf(my_("No subnet found for address %s"), $ipaddr)."\n";
}
}
return TRUE;
}
function RevAddNS($zoneid) {
// add reverse DNS into fwddns table
for ($i = 1; $i < 11; $i++) {
if (isset($this->hname[$i]) and !empty($this->hname[$i])) {
$hnametemp=$this->hname[$i];
// add DNS records
$result=$this->ds->Execute("INSERT INTO zonedns
(id, hname, horder)
VALUES
($zoneid,
".$this->ds->qstr($hnametemp).",
$i)");
if (!$result) {
return FALSE;
}
}
}
return TRUE;
}
// test if the zone exists and lock for update
function RevZoneExists($cust, $zoneid) {
// need to do select as mysql driver does not have RowLock
// mysqlt does have rowlock
$row = $this->ds->GetOne("SELECT id
FROM zones
WHERE customer=$cust AND id=$zoneid");
$this->ds->RowLock("zones", "customer=$cust AND id=$zoneid");
return !empty($row);
}
// test if the zone has changed records - check the last serial for the zone
// against the ippaddr table for changed records i.e. records with a date equal or
// later than the serial date
function RevZoneChanged($cust, $zoneid) {
$sqlfn = $this->ds->SQLDate('Ymd','ipaddr.lastmod');
$row = $this->ds->GetOne("SELECT zones.id
FROM zones, base, ipaddr
WHERE zones.customer=base.customer AND
base.baseindex=ipaddr.baseindex AND
$sqlfn >= zones.serialdate AND
ipaddr.ipaddr >= zones.zoneip AND
ipaddr.ipaddr < zones.zoneip+zones.zonesize AND
zones.id=$zoneid");
return !empty($row);
}
function RevUpdateSOA($cust, $zoneid, $zone, $zoneip, $size) {
// use local function variables as they may change
$this->cust = $cust;
if (!$this->RevZoneExists($cust, $zoneid)) {
$this->err=90;
$this->errstr .= my_("Could not find the zone - possibly deleted by another user")."\n";
return FALSE;
}
// work out new serial numbers
$this->Serial();
// Updated DB here.
$result = $this->ds->Execute("UPDATE zones SET zoneip=$zoneip".
",zone=".$this->ds->qstr($this->zone).
",zonesize=$size".
",serialdate=".$this->ds->qstr($this->serialdate).
",serialnum=$this->serialnum".
",ttl=".$this->ttl.
",refresh=".$this->refresh.
",retry=".$this->retry.
",expire=".$this->expire.
",minimum=".$this->minimum.
",error_message=".$this->ds->qstr("E").
",responsiblemail=".$this->ds->qstr($this->responsiblemail).
",userid=".$this->ds->qstr(getAuthUsername()).
",zonefilepath1=".$this->ds->qstr($this->zonepath).
",zonefilepath2=".$this->ds->qstr($this->seczonepath).
",lastmod=".$this->ds->DBTimeStamp(time()).
",slaveonly=".$this->ds->qstr($this->slaveonly).
" WHERE customer=$cust AND id=".$zoneid );
// delete all the DNS records first to preserve correct order
$result=$this->ds->Execute("DELETE FROM zonedns
WHERE id=$zoneid");
// add reverse DNS into fwdzone table
$this->RevAddNS($zoneid);
return $result;
}
function RevAddSOA() {
// work out new serial numbers
$this->Serial();
// Add to DB here.
$result = $this->ds->Execute("INSERT into zones
(customer, zoneip, zone, zonesize, serialdate,
serialnum, error_message, ttl, refresh, retry, expire, minimum,
lastmod, responsiblemail, userid, zonefilepath1,
zonefilepath2, slaveonly) ".
"VALUES ($this->cust, $this->zoneip,".
$this->ds->qstr($this->zone).", $this->size,".
$this->ds->qstr($this->serialdate).", $this->serialnum,".
$this->ds->qstr("E").",".
$this->ttl.",".
$this->refresh.",".
$this->retry.",".
$this->expire.",".
$this->minimum.",".
$this->ds->DBTimeStamp(time()).",".
$this->ds->qstr($this->responsiblemail).",".
$this->ds->qstr(getAuthUsername()).",".
$this->ds->qstr($this->zonepath).",".
$this->ds->qstr($this->seczonepath).",".
$this->ds->qstr($this->slaveonly).")" );
// did not fail due to key error?
// should not fail as we checked this already!
if ($result) {
if (DBF_TYPE=="mysql" or DBF_TYPE=="maxsql") {
$zoneid=$this->ds->Insert_ID();
}
else {
// emulate getting the last insert_id
$result=$this->ds->Execute("SELECT id
FROM zones
WHERE customer=$this->cust AND
zoneip=$this->zoneip");
$temprow = $result->FetchRow();
$zoneid=$temprow["id"];
}
return $zoneid;
}
// key error?
return 0;
}
function RevAdd($cust, $zone, $server) {
// use local function variables as they may change
$this->cust = $cust;
// is the server variable set? then do zone transfer
// should really only read SOA if slaveonly set
if (!empty($server)) {
$answer=$this->ZoneAXFR($this->zone, $server);
// fatal zone transfer error?
if ($this->err > 0) {
return $this->err;
}
}
// could use unique key on database to do check, but requires extra key
// just to add a new record
$restemp=$this->ds->Execute("SELECT zone FROM zones
WHERE customer=$cust AND zone = ".$this->ds->qstr($this->zone));
if ($restemp->FetchRow()) {
// domain already exists, fail transaction
$this->err=-60;
$this->errstr .= sprintf(my_("DNS Domain %s could not be created - possibly duplicate zone"), $this->zone)."\n";
}
else {
// create the actual zone
$zoneid=$this->RevAddSOA();
$this->zoneid=$zoneid;
// did not fail due to key error?
if ($zoneid) {
if(!$this->RevAddNS($zoneid)) {
$this->err = -60;
return $this->err;
}
// now load individual rr records
// only if not a slavezone and no previous error
if (!empty($server) and $this->slaveonly=="N" and !empty($answer)) {
if(!$this->RevZoneAddRR($zoneid, $answer)) {
$this->err = -60;
return $this->err;
}
}
$this->err = 0;
}
else {
$this->err = -60;
$this->errstr .= sprintf(my_("DNS Domain %s could not be created - possibly duplicate zone"), $this->zone)."\n";
}
}
return $this->err;
}
function RevZoneExport($cust, $zoneid) {
// use local function variables as they may change
$this->cust = $cust;
$this->Serial();
$result = $this->ds->Execute("UPDATE zones ".
"set serialdate=".$this->ds->qstr($this->serialdate).
", userid=".$this->ds->qstr(getAuthUsername()).
", lastexp=".$this->ds->DBTimeStamp(time()).
", error_message=".$this->ds->qstr("").
", serialnum=$this->serialnum ".
" WHERE customer=$cust AND id=$zoneid");
if ($result) {
$sqllastmod = $this->ds->SQLDate("M d Y H:i:s", 'lastmod');
$result = $this->ds->Execute("SELECT id, zoneip, zonesize, zone, serialdate,
serialnum, ttl, refresh, retry, expire, minimum, zonefilepath1,
zonefilepath2, responsiblemail, customer, $sqllastmod AS lastmod,
userid, slaveonly
FROM zones
WHERE customer=$cust AND id=$zoneid");
$row = $result->FetchRow();
$this->zone=$row["zone"];
$this->zoneip=$row["zoneip"];
$this->size=$row["zonesize"];
$prefix=inet_bits($row["zonesize"]);
$tmpfname = tempnam (DNSEXPORTPATH, "revzone_".$this->zone."_");
if(!$tmpfname) {
$this->err=80;
$this->errstr .= my_("Could not create temporary file!");
return;
}
$fp = fopen ("$tmpfname", "w");
// header of document
$output='<?xml version="1.0" ?>';
fputs($fp, $output);
fputs($fp, "\n");
$ip=inet_ntoa($row["zoneip"]);
list($octet1,$octet2,$octet3,$octet4) = explode(".",$ip);
fputs($fp, sprintf('<zone domain="%s" zoneip="%s" zonesize="%s" prefix="%s" slaveonly="%s" octect1="%s" octect2="%s" octect3="%s" octect4="%s">',
$row["zone"], $ip, $row["zonesize"], $prefix,
(empty($row["slaveonly"]) ? "N" : $row["slaveonly"]),
$octet1, $octet2, $octet3, $octet4));
fputs($fp, "\n");
fputs($fp, sprintf("<path>\n<primary>\n%s\n</primary>\n",
htmlspecialchars($row["zonefilepath1"])));
fputs($fp, sprintf("<primaryfile>\n%s\n</primaryfile>\n",
htmlspecialchars(basename($row["zonefilepath1"]))));
fputs($fp, sprintf("<primarydir>\n%s\n</primarydir>\n",
htmlspecialchars(dirname($row["zonefilepath1"]))));
fputs($fp, sprintf("<secondary>\n%s\n</secondary>\n",
htmlspecialchars($row["zonefilepath2"])));
fputs($fp, sprintf("<secondaryfile>\n%s\n</secondaryfile>\n",
htmlspecialchars(basename($row["zonefilepath2"]))));
fputs($fp, sprintf("<secondarydir>\n%s\n</secondarydir>\n",
htmlspecialchars(dirname($row["zonefilepath2"]))));
fputs($fp, "</path>\n");
// SOA portion
fputs($fp, sprintf('<soa serialdate="%s" serialnum="%02d" ttl="%s" retry="%s" refresh="%s" expire="%s" minimumttl="%s" email="%s" />',
$this->serialdate, $this->serialnum,
$row["ttl"],
$row["retry"],
$row["refresh"],
$row["expire"],
$row["minimum"],
$row["responsiblemail"]
));
fputs($fp, "\n");
// nameservers
$result1 = $this->ds->Execute("SELECT hname FROM zonedns
WHERE id=$zoneid
ORDER BY horder");
$cnt=0;
while($row1 = $result1->FetchRow()) {
fputs($fp, '<record><NS>');
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row1["hname"]));
fputs($fp, '</NS></record>');
fputs($fp, "\n");
$cnt++;
}
if ($cnt < 2) {
fclose($fp);
unlink($tmpfname);
$this->err=90;
$this->errstr .= my_("Invalid zone - zone should have at least two name servers defined");
return;
}
// get records from main ipplan ipaddr tables
$result1 = $this->ds->Execute("SELECT ipaddr.ipaddr, ipaddr.hname
FROM base, ipaddr
WHERE base.customer = $cust AND
base.baseindex = ipaddr.baseindex AND
ipaddr.ipaddr >= ".$row["zoneip"]." AND
ipaddr.ipaddr <= ".($row["zoneip"]+$row["zonesize"])."
ORDER BY ipaddr.ipaddr");
while($row1 = $result1->FetchRow()) {
$ip=inet_ntoa($row1["ipaddr"]);
// ignore blank records
if (empty($row1["hname"])) {
continue;
}
// test for valid domain name
if (!preg_match('/^(([\w][\w\-\.]*)\.)?([\w][\w\-]+)(\.([\w][\w\.]*))?$/', $row1["hname"])) {
$this->errstr .= sprintf(my_("Invalid record - ignored: %s %s"), $ip, $row1["hname"]);
continue;
}
fputs($fp, '<record><PTR>');
fputs($fp, sprintf('<host>%s</host>', $row1["hname"]));
list($octet1,$octet2,$octet3,$octet4) = explode(".",$ip);
fputs($fp, sprintf('<octet1>%s</octet1>', $octet1));
fputs($fp, sprintf('<octet2>%s</octet2>', $octet2));
fputs($fp, sprintf('<octet3>%s</octet3>', $octet3));
fputs($fp, sprintf('<octet4>%s</octet4>', $octet4));
fputs($fp, "\n");
fputs($fp, sprintf('<iphostname>%s</iphostname>', $ip));
fputs($fp, '</PTR></record>');
fputs($fp, "\n");
}
// close zone
fputs($fp, '</zone>');
fputs($fp, "\n");
fclose($fp);
// give file proper extension
rename($tmpfname, $tmpfname.".xml");
@chmod($tmpfname.".xml",0644);
$this->err=0;
return $tmpfname.".xml";
}
//return $tmpfname;
// database error?
/*
// Update DNS Database Serial Count. Update Serial Count only when we export.
$result = $this->ds->Execute("UPDATE fwdzone ".
"set serialdate=".$this->ds->qstr($this->serialdate).
", userid=".$this->ds->qstr(getAuthUsername()).
", serialnum=$this->serialnum".
" WHERE customer=$cust AND data_id=".$zoneid);
if ($result) {
$result = $this->ds->Execute("SELECT * FROM fwdzone
WHERE customer=$cust AND data_id=$zoneid");
$row = $result->FetchRow();
$this->domain=$row["domain"];
$tmpfname = tempnam (DNSEXPORTPATH, "zone_") or
myError($w,$p, my_("Could not create temporary file!"));
$fp = fopen ("$tmpfname", "w");
// header of document
$output='<?xml version="1.0" ?>';
fputs($fp, $output);
fputs($fp, "\n");
fputs($fp, sprintf('<zone domain="%s" slaveonly="%s">', $row["domain"],
(empty($row["slaveonly"]) ? "N" : $row["slaveonly"])));
fputs($fp, "\n");
// SOA portion
fputs($fp, sprintf('<soa serialdate="%s" serialnum="%02d" ttl="%s" retry="%s" refresh="%s" expire="%s" minimumttl="%s" email="%s" />',
$this->serialdate, $this->serialnum,
$row["ttl"],
$row["retry"],
$row["refresh"],
$row["expire"],
$row["minimum"],
$row["responsiblemail"]
));
fputs($fp, "\n");
// nameservers
$result1 = $this->ds->Execute("SELECT hname
FROM fwddns
WHERE id=$zoneid
ORDER BY horder");
$cnt=0;
while($row1 = $result1->FetchRow()) {
fputs($fp, '<record><NS>');
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row1["hname"]));
fputs($fp, '</NS></record>');
fputs($fp, "\n");
$cnt++;
}
if ($cnt < 2) {
insert($w,textbr(my_("Invalid zone - zone should have at least two name servers defined")));
}
$result = $this->ds->Execute("SELECT * FROM fwdzonerec
WHERE customer=$cust AND data_id=$zoneid
ORDER BY sortorder");
// loop through each host record
while($row = $result->FetchRow()) {
fputs($fp, sprintf('<record><%s>', $row["recordtype"]));
fputs($fp, sprintf('<host>%s</host>', $row["host"]));
// MX records are in format "10 hostname.com" in database field ip_hostname
if ($row["recordtype"]=="MX") {
list($preference, $iphost) = explode(" ", $row["ip_hostname"], 2);
if (is_numeric($preference) and $preference >= 0) {
fputs($fp, sprintf('<preference>%s</preference>', $preference));
fputs($fp, sprintf('<iphostname>%s</iphostname>', $iphost));
}
else {
fputs($fp, '<preference>10</preference>');
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row["ip_hostname"]));
}
}
else {
fputs($fp, sprintf('<iphostname>%s</iphostname>', $row["ip_hostname"]));
}
fputs($fp, sprintf('</%s></record>', $row["recordtype"]));
fputs($fp, "\n");
}
// close zone
fputs($fp, '</zone>');
fputs($fp, "\n");
fclose($fp);
}
return $tmpfname;
*/
}
} // end of class DNSFwdZone
?>