автономный DynDNS
Иногда есть необходимость обращаться по имени клиента, а не по адресу (адреса динамические). Сейчас это частично реализовано — есть локальный домен mydomain.local удаленные точки регистрируются в локальном домене и доступны по имени из локальной сети офиса.
Тестировалось на:
сервере freebsd 7.2 и freebsd 8.0, софт: apache 2.2, php, php-extensions (возможно не нужен), bind9;
клиентах Windows XP, софт: curl, bind9.
Настройка сервера.
В /usr/local/etc/apache22/http.conf добавим следующую секцию:
1 2 3 4 5 6 7 8 9 10 11 12 | Alias /ipaddress "/usr/local/www/ipaddress/" <directory "="" usr="" local="" www="" ipaddress"=""> Options Indexes AllowOverride All DirectoryIndex index.php Order allow,deny Allow from All AuthName "Who are you?" AuthType Basic AuthUserFile /usr/local/www/ipaddress/.htpasswd Require valid-user </directory> |
Далее создадим каталог:
1 | mkdir /usr/local/www/ipaddress |
И положим файл index.php следующего содержания (взял на http://www.phpfaq.ru/ip):
1 2 3 4 | <!--?php $ip=$_SERVER['REMOTE_ADDR']; echo $ip; ?--> |
При обращении к этой страничке клиенты узнают свой «белый адрес» с помощью curl. Далее определим тех пользователей, которым необходимо получать свой адрес:
1 | htpasswd -cb /usr/local/www/ipaddress/.htpasswd firstsuser userpassword |
Для проверки в браузере введем: http://ip-address/ipaddress/. В результате должны увидеть приглашение ввести имя пользователя и пароль, вводим и любуемся своим внешним адресом. Если нет — проверяем логи apache.
С апачем покончено, далее сервер имен. С помощью rndc-confgen генерируем ключ.
В /etc/namedb/named.conf добавим следующую запись:
1 2 3 4 5 6 7 8 9 10 | key "rndc-key" { algorithm hmac-md5; secret "только_что_сгенерированный_ключ=="; }; zone "mydomain.local" { type master; file "dynamic/mydomain.local"; allow-update { key "rndc-key"; }; }; |
И создадим файл зоны dynamic/mydomain.local. Я просто скопировал файл для локалхост и подправил.
Для проверки попробуем nsupdate обновить запись в зоне mydomain.local, я для этого использовал файл nsupdate.conf:
1 2 3 4 5 6 | server 192.168.0.1 key rndc-key только_что_сгенерированный_ключ== zone mydomain.local. update delete test.mydomain.local. A update add test.mydomain.local. 600 A 192.168.0.182 send |
Выполним:
1 | nsupdate nsupdate.conf |
И проверим:
1 | nslookup test.mydomain.local 192.168.0.1 |
Должен вернуть адрес тестовой машины, если нет, включаем и смотрим логи сервера имен.
С сервером закончили.
Для клиентской части нужен curl (распространяется с поддержкой ssl и без) и bind9. Из пакета bind9 нам понадобится только nsupdate, его библиотеки и vcredist_x86.exe. На стороне клиента выполняется следующий скрипт, там все понятно, описывать нечего:
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 | var WshShell = new ActiveXObject("WScript.Shell"); var fso = new ActiveXObject("Scripting.FileSystemObject"); var workdir = "d:\\nsupdate\"; var lastaddrr = "lastaddrr.txt"; var lastip = "127.0.0.1"; if (fso.FileExists(lastaddrr)) { var fileObj = fso.GetFile(workdir + lastaddrr); var ts = fileObj.OpenAsTextStream(1, -2); // если файл создался два и более часов назад затираем его var x=new Date(fileObj.DateLastModified); var y=new Date(); if (Math.floor((y-x)/(1000*60)) >= 10) { ts.Close(); fso.DeleteFile(workdir + lastaddrr, true); } // иначе читаем из него адрес else { var lastip = ts.ReadLine(); ts.Close(); } } var stdout = WScript.StdOut; var stdin = WScript.StdIn; // определим программы и их аргументы var curl = workdir + "curl.exe -u firstuser:userpassword http://192.168.0.1/ipaddress/index.php"; var nsupdate = workdir + "nsupdate.exe"; // если наш ДНС пингается, пытаемся получить свой адрес и обновить зону // иначе молча выходим var objLocalWMI = GetObject("Winmgmts:"); var enumPingStatus = new Enumerator(objLocalWMI.ExecQuery("Select StatusCode from Win32_PingStatus Where Address='192.168.0.1'")); if(enumPingStatus.item().StatusCode == 0) { // определяем внешний IP-address var oExec = WshShell.Exec(curl); // проинициализируем переменные var currentip = oExec.stdout.ReadLine(); if (lastip !== currentip) { var server = "server 192.168.0.1"; var key = "key rndc-key только_что_сгенерированный_ключ=="; var zone = "zone mydomain.local."; var update_del = "update delete mydomain.local. A"; var update_add = "update add mydomain.local. 600 A" + "\ " + currentip; var send = "send"; // отправим данные серверу oExec = WshShell.Exec(nsupdate); oExec.StdIn.Write(server + "\n"); oExec.StdIn.Write(key + "\n"); oExec.StdIn.Write(zone + "\n"); oExec.StdIn.Write(update_del + "\n"); oExec.StdIn.Write(update_add + "\n"); oExec.StdIn.Write(send + "\n"); // save current ip to file ts = fso.CreateTextFile(workdir + lastaddrr, true); ts.WriteLine(currentip); ts.Close(); } } |
Этот jscript запускаем на выполнение каждые 5 минут в планировщике. Если сервер не пингуется — молча выходим, если адрес не менялся — ничего обновлять не будем, если в течение 10 минут адрес не менялся (определим по времени создания файла) адрес все равно обновим, а файл удалим, последний полученный адрес сохраним в файл и на него будем ориентироваться в течение следующих 10 минут.