= 16) && ($addrTeile[1] < 32))) return '7200'; }; return '120'; }; function convert_ipv6_address_part_to_reverse_record_part(&$part) { while (strlen($part)<4) $part = '0' . $part; $part = str_split($part); $part = array_reverse($part); $part = implode('.', $part); }; function reverse_ipv6_address($addr) { $addr_Teile = array(); while (count($addr_Teile) < 8) { $addr_Teile = explode(':', $addr); $addr = str_replace('::',':0::',$addr); } array_walk($addr_Teile, 'convert_ipv6_address_part_to_reverse_record_part'); $addr_Teile = array_reverse($addr_Teile); return implode('.', $addr_Teile); }; function reverse_entry($addr) { if (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { $addrTeile = explode('.', $addr); $lp = array_pop($addrTeile); $subNet = implode('.', $addrTeile); array_push($addrTeile, $lp); $addrTeile = array_reverse($addrTeile); if (($subNet == '10.0.2') || ($subNet == '192.168.0') || ($subNet == '192.168.1')) return implode('.',$addrTeile).'.in-addr.arpa.'; } elseif (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $reversed_address = reverse_ipv6_address($addr); if (stripos(implode('.',array_reverse(explode('.',$reversed_address))),'2.a.0.1.0.0.d.0.f.6.c.e.')===0) return $reversed_address.'.ip6.arpa.'; }; return NULL; }; function reverse_zone($addr) { if (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { $addrTeile = explode('.', $addr); array_pop($addrTeile); $addrTeile = array_reverse($addrTeile); return implode('.',$addrTeile).'.in-addr.arpa.'; } elseif (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $reversed_address = reverse_ipv6_address($addr); if (stripos(implode('.',array_reverse(explode('.',$reversed_address))),'2.a.0.1.0.0.d.0.f.6.c.e.')===0) return 'e.c.6.f.0.d.0.0.1.0.a.2.ip6.arpa.'; }; return NULL; }; // invalid syntax? if ((!array_key_exists('i', $_GET)) || (strlen($_GET['i']) != 64) || (preg_match('@^[0-9A-Za-z]{64}$@', $_GET['i']) != 1)) die(); $line = preg_grep('@^' . $_GET['i'] . ' @', file('/srv/http/vhosts/eckner.net/ddns/tokens')); // unknown token? if (count($line) != 1) die(); $domain = substr(explode(' ', implode('', $line))[1], 0, -1); if (array_key_exists('address', $_GET)) $ips = explode(',', $_GET['address']); else $ips = array('auto'); foreach ($ips as $i => $ip) if ($ip == 'auto') $ips[$i] = $_SERVER['REMOTE_ADDR']; $ips = array_unique($ips); $hasRrType = array(); $rrTypes = array(); $filterMatches = array(); $filters = array(); foreach (file('/srv/http/vhosts/eckner.net/ddns/ip-filters') as $filterLine) { if (substr($filterLine, 0, 1) == '#') continue; $filter = explode(' ', $filterLine); if (count($filter) < 2) continue; $filters[] = array( 'name' => $filter[0], 'regex' => substr($filter[1], 0, -1) ); } foreach ($ips as $i => $ip) { $filterMatches[$i] = array(); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { $rrTypes[$i] = 'A'; $hasRrType['A'] = 1; $filterMatches[$i][] = 'v4'; } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $rrTypes[$i] = 'AAAA'; $hasRrType['AAAA'] = 1; $filterMatches[$i][] = 'v6'; } else die(); foreach ($filters as $filter) { if (preg_match('@' . $filter['regex'] . '@', $ip) == 1) $filterMatches[$i][] = $filter['name']; else $filterMatches[$i][] = 'non-' . $filter['name']; } $filterMatches[$i] = array_unique($filterMatches[$i]); } $updateCommand = "zone ddns.eckner.net.\n"; $logContent = ''; foreach ($hasRrType as $rrType => $dummy) { // delete old record if existing $updateCommand .= "prereq yxrrset " . $domain . ".ddns.eckner.net IN " . $rrType . "\n" . "update delete " . $domain . ".ddns.eckner.net IN " . $rrType . "\n" . "send\n"; if ($rrType == 'A') $updateCommand .= "prereq yxrrset " . $domain . ".v4.ddns.eckner.net IN " . $rrType . "\n" . "update delete " . $domain . ".v4.ddns.eckner.net IN " . $rrType . "\n" . "send\n"; else $updateCommand .= "prereq yxrrset " . $domain . ".v6.ddns.eckner.net IN " . $rrType . "\n" . "update delete " . $domain . ".v6.ddns.eckner.net IN " . $rrType . "\n" . "send\n"; foreach ($filters as $filter) { foreach (array('', 'non-') as $filter_prefix) { $updateCommand .= "prereq yxrrset " . $domain . "." . $filter_prefix . $filter['name'] . ".ddns.eckner.net IN " . $rrType . "\n" . "update delete " . $domain . "." . $filter_prefix . $filter['name'] . ".ddns.eckner.net IN " . $rrType . "\n" . "send\n"; } } } // set new records no matter what foreach ($ips as $i => $ip) { $updateCommand .= "update add " . $domain . ".ddns.eckner.net. " . lifetime($ip) . " IN " . $rrTypes[$i] . " " . $ip . "\n"; $logContent .= date('Y-m-d H:i:s') . ' ' . $domain . ' ' . $ip . "\n"; foreach ($filterMatches[$i] as $filter) { $updateCommand .= "update add " . $domain . "." . $filter . ".ddns.eckner.net. " . lifetime($ip) . " IN " . $rrTypes[$i] . " " . $ip . "\n"; $logContent .= date('Y-m-d H:i:s') . ' ' . $domain . '.' . $filter . ' ' . $ip . "\n"; } } $updateCommand .= "send\n"; foreach ($ips as $i => $ip) { $reverse_entry = reverse_entry($ip); if (!$reverse_entry) continue; $updateCommand .= "zone ".reverse_zone($ip)."\n"; // delete old record if existing $updateCommand .= "prereq yxrrset " . $reverse_entry . " IN PTR\n" . "update delete " . $reverse_entry . " IN PTR\n" . "send\n"; // set new records no matter what $updateCommand .= "update add " . $reverse_entry . " " . lifetime($ip) . " IN PTR " . $domain . ".ddns.eckner.net.\n" . "send\n"; } $aliasess = preg_grep('@ ' . $domain . '\b@', file('/srv/http/vhosts/eckner.net/ddns/aliases')); if (count($aliasess)) { $pin = popen( 'dig @127.0.0.1 ddns.eckner.net AXFR' . ' | sed "s/^\([^;.[:space:]]\+\)\.ddns\.eckner\.net\.\s\+\([0-9]\+\)\s\+IN\s\+\(AAAA\|A\)\s\+\(\S\+\)$/\1 \2 \3 \4/;t;d"', 'r'); if ($pin === FALSE) die_http(500, 'Internal Server Error', 'Failed to get Zone.'); while (!feof($pin)) $zone_file .= fread($pin, 1024); $zone_file = explode("\n", trim($zone_file)); pclose($pin); $updateCommand .= "zone ddns.eckner.net.\n"; foreach($aliasess as $aliases) { $aliases = explode(' ', trim($aliases)); $alias = array_shift($aliases); foreach ($hasRrType as $rrType => $dummy) { $updateCommand .= "prereq yxrrset " . $alias . ".ddns.eckner.net. IN " . $rrType . "\n" . "update delete " . $alias . ".ddns.eckner.net. IN " . $rrType . "\n" . "send\n"; foreach($aliases as $representative) { foreach($zone_file as $zone_file_entry) { if (preg_match('/^'.$representative.' ([0-9]+) (' . $rrType . ') (\S+)$/', $zone_file_entry, $match)) { $updateCommand .= "update add " . $alias . ".ddns.eckner.net. " . $match[1] . " IN " . $match[2] . " " . $match[3] . "\n"; } } } $updateCommand .= "send\n"; } } } // actually do something $pin = popen('nsupdate -l', 'w'); if ($pin === FALSE) die_http(500, 'Internal Server Error', 'Failed to update Zone.'); fwrite($pin, $updateCommand); pclose($pin); file_put_contents('/srv/http/vhosts/eckner.net/ddns/log', $logContent, FILE_APPEND | LOCK_EX); print "updated ips for domain \"" . $domain . ".ddns.eckner.net\": " . implode(", ", $ips) . "\n"; $handle = fopen('https://colocation.eckner.net/update.php?key=' . trim(file_get_contents('/srv/http/vhosts/eckner.net/ddns/colocation-token')) . '&running=1&machine=' . $domain, 'r'); fclose($handle);