автономный 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 добавим следующую секцию:
[cc lang=»apache»]Alias /ipaddress «/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
Далее создадим каталог:
[cc lang=»bash»]mkdir /usr/local/www/ipaddress[/cc]
И положим файл index.php следующего содержания (взял на http://www.phpfaq.ru/ip):
[cc lang=»php»][/cc]
При обращении к этой страничке клиенты узнают свой «белый адрес» с помощью curl. Далее определим тех пользователей, которым необходимо получать свой адрес:
[cc lang=»bash»]htpasswd -cb /usr/local/www/ipaddress/.htpasswd firstsuser userpassword[/cc]
Для проверки в браузере введем: http://ip-address/ipaddress/. В результате должны увидеть приглашение ввести имя пользователя и пароль, вводим и любуемся своим внешним адресом. Если нет — проверяем логи apache.
С апачем покончено, далее сервер имен. С помощью rndc-confgen генерируем ключ.
В /etc/namedb/named.conf добавим следующую запись:
[cc lang=»bash»]key «rndc-key» {
algorithm hmac-md5;
secret «только_что_сгенерированный_ключ==»;
};
zone «mydomain.local» {
type master;
file «dynamic/mydomain.local»;
allow-update { key «rndc-key»; };
};[/cc]
И создадим файл зоны dynamic/mydomain.local. Я просто скопировал файл для локалхост и подправил.
Для проверки попробуем nsupdate обновить запись в зоне mydomain.local, я для этого использовал файл nsupdate.conf:
[cc lang=»bash»]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[/cc]
Выполним:
[cc lang=»bash»]nsupdate nsupdate.conf[/cc]
И проверим:
[cc lang=»bash»]nslookup test.mydomain.local 192.168.0.1[/cc]
Должен вернуть адрес тестовой машины, если нет, включаем и смотрим логи сервера имен.
С сервером закончили.
Для клиентской части нужен curl (распространяется с поддержкой ssl и без) и bind9. Из пакета bind9 нам понадобится только nsupdate, его библиотеки и vcredist_x86.exe. На стороне клиента выполняется следующий скрипт, там все понятно, описывать нечего:
[cc lang=»javascript»]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();
}
}[/cc]
Этот jscript запускаем на выполнение каждые 5 минут в планировщике. Если сервер не пингуется — молча выходим, если адрес не менялся — ничего обновлять не будем, если в течение 10 минут адрес не менялся (определим по времени создания файла) адрес все равно обновим, а файл удалим, последний полученный адрес сохраним в файл и на него будем ориентироваться в течение следующих 10 минут.