在带有exec函数的php中调用时,nsupdate失败

时间:2017-10-06 11:05:29

标签: php linux apache dyndns

我已使用以下php脚本通过我的网络服务器更新动态DNS记录,如此链接所述own-ddns

<?php
  // configuration of user and domain
  $user_domain = array( 'user' => array('subdomain','sub2'), 'user2' => array('sub4') );
  // main domain for dynamic DNS
  $dyndns = "dyndns.example.org";
  // DNS server to send update to
  $dnsserver = "localhost";
  // port of DNS server
  $dnsport = "";

  // short sanity check for given IP
  function checkip($ip)
  {
    $iptupel = explode(".", $ip);
    foreach ($iptupel as $value)
    {
      if ($value < 0 || $value > 255)
        return false;
      }
    return true;
  }

  // retrieve IP
  $ip = $_SERVER['REMOTE_ADDR'];
  // retrieve user
  if ( isset($_SERVER['REMOTE_USER']) )
  {
    $user = $_SERVER['REMOTE_USER'];
  }
  else if ( isset($_SERVER['PHP_AUTH_USER']) )
  {
    $user = $_SERVER['PHP_AUTH_USER'];
  }
  else
  {
    syslog(LOG_WARN, "No user given by connection from $ip");
    exit(0);
  }

  // open log session
  openlog("DDNS-Provider", LOG_PID | LOG_PERROR, LOG_LOCAL0);

  // check for given domain
  if ( isset($_POST['DOMAIN']) )
  {
    $subdomain = $_POST['DOMAIN'];
  }
  else if ( isset($_GET['DOMAIN']) )
  {
    $subdomain = $_GET['DOMAIN'];
  }
  else
  {
    syslog(LOG_WARN, "User $user from $ip didn't provide any domain");
    exit(0);
  }

  // check for needed variables
  if ( isset($subdomain) && isset($ip) && isset($user) )
  {
    // short sanity check for given IP
    if ( preg_match("/^(\d{1,3}\.){3}\d{1,3}$/", $ip) && checkip($ip) && $ip != "0.0.0.0" && $ip != "255.255.255.255" )
    {
      // short sanity check for given domain
      if ( preg_match("/^[\w\d-_\*\.]+$/", $subdomain) )
      {
        // check whether user is allowed to change domain
        if ( in_array("*", $user_domain[$user]) or in_array($subdomain, $user_domain[$user]) )
        {
          if ( $subdomain != "-" )
            $subdomain = $subdomain . '.';
          else
            $subdomain = '';

          // shell escape all values
          $subdomain = escapeshellcmd($subdomain);
          $user = escapeshellcmd($user);
          $ip = escapeshellcmd($ip);

          // prepare command
          $data = "<<EOF
server $dnsserver $dnsport
zone $dyndns
update delete $subdomain$user.$dyndns A
update add $subdomain$user.$dyndns 300 A $ip
send
EOF";
          // run DNS update
          exec("/usr/bin/nsupdate -k /etc/named/K$dyndns*.private $data", $cmdout, $ret);
          // check whether DNS update was successful
          if ($ret != 0)
          {
            syslog(LOG_INFO, "Changing DNS for $subdomain$user.$dyndns to $ip failed with code $ret");
          }
        }
        else
        {
          syslog(LOG_INFO, "Domain $subdomain is not allowed for $user from $ip");
        }
      }
      else
      {
        syslog(LOG_INFO, "Domain $subdomain for $user from $ip with $subdomain was wrong");
      }
    }
    else
    {
      syslog(LOG_INFO, "IP $ip for $user from $ip with $subdomain was wrong");
    }
  }
  else
  {
    syslog(LOG_INFO, "DDNS change for $user from $ip with $subdomain failed because of missing values");
  }
  // close log session
  closelog();
?>

执行nsupdate时,我遇到了php脚本的问题:

/usr/bin/nsupdate -k /etc/named/Kdyndns.example.com*.private <<EOF
server ns.example.com
zone dyndns.example.com
update delete subdomain.user.dyndns.example.com A
update add subdomain.user.dyndns.example.com 300 A W.X.Y.Z
send
show
answer
debug
EOF

结果$cmdout

Array
(
    [0] => Outgoing update query:
    [1] => ;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 0
    [2] => ;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
    [3] => ;; ZONE SECTION:
    [4] => ;dyndns.example.com. IN  SOA
    [5] =>
    [6] => Answer:
    [7] => ;; ->>HEADER<<- opcode: UPDATE, status: REFUSED, id: 17305
    [8] => ;; flags: qr ra; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
    [9] => ;; ZONE SECTION:
    [10] => ;dyndns.example.com.    IN  SOA
    [11] =>
)
$ret=2 // update failed

但是当我手动执行相同的命令时它工作正常(我使用了php脚本生成的命令,由echo函数显示):

[root@server ~]# /usr/bin/nsupdate -k /etc/named/Kdyndns.example.com*.private <<EOF
server ns.example.com
zone dyndns.example.com
update delete subdomain.user.dyndns.example.com A
update add subdomain.user.dyndns.example.com 300 A W.X.Y.Z
send
show
answer
debug
EOF
echo ret=$?
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;dyndns.example.com.    IN  SOA

Answer:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 17305
;; flags: qr ra; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; ZONE SECTION:
;dyndns.example.com.    IN  SOA

ret=0 //successful update

我已经检查了预设一切正常,我已经在已命名的组中添加了apache用户但仍无法正常工作:

[root@server ~]# usermod -a apache -G named

php脚本中的错误是什么?

1 个答案:

答案 0 :(得分:-2)

我遇到了完全相同的问题(ret = 2,从php更新失败,从命令行执行完全相同的操作也很好)。经过几个小时的调试,我只是重新启动了“命名”服务即可解决问题。