summaryrefslogtreecommitdiff
path: root/ddns.php
blob: 31b8706f138d10e943eb9b0a4c0b595d6dd61155 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<?php

// $filter = array(v4, v6, file('/srv/http/vhosts/eckner.net/ddns/ip-filters'))
// $x \in array($token, $token.$filter foreach $filter with match):
// $x.ddns.eckner.net (all)

  function lifetime($addr) {
    $addrTeile = explode('.', $addr);
    if (($addrTeile[0] == '10') ||
       (($addrTeile[0] == '192') && ($addrTeile[1] == '168')) ||
       (($addrTeile[0] == '172') && ($addrTeile[1] >= 16) && ($addrTeile[1] < 32)))
      return '7200';
    return '120';
  };

  // 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[0] = '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";
    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";

  // actually do something
  $pin = popen('nsupdate -l', 'w');
  if ($pin === FALSE)
    die();

  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";