Ошибка nsupdate при вызове в php с функцией exec

Я использовал следующий скрипт 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();
?>

У меня проблема с PHP-скриптом, когда я выполняю nsupdate:

/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 скрипте?

0 ответов

У меня была такая же проблема (ret=2, обновление не удалось с php, выполнение того же самого из командной строки работало нормально). После нескольких часов отладки я просто перезапустил "именованную" службу, что решило проблему.

Другие вопросы по тегам