Pull to refresh

Делаем dDNS-клиент для DNS Яндекса

Reading time 2 min
Views 11K
Залез зачем-то в справку почты для домена яндекса и заметил там Его — долгожданный API DNS.
И захотелось сделать более нативный клиент dDNS, чем всего лишь 2-х месячной давности решение через эмуляцию пользователя.


Поскольку на С делать моими силами долго получилось бы, а ни Python ни Perl я не знаю, делать будем на перле.

Итого дано:
  • динамический внешний IP
  • домен, делегированный на яндекс
  • роутер под управлением Debian

Хочется их всех передружить.

Для начала определим IP, на который будем заменять запись:
sub getip {
    (my $interface,my $ipconf) = @_;
    $ipconf = defined($ipconf) ? $ipconf : '/sbin/ip';
    my $res = `ip a s $interface | grep «inet »` or die(«Can't get info from ip: ».$!);
    if ($res =~ /([\d]{1,3}.[\d]{1,3}.[\d]{1,3}.[\d]{1,3})/) {
        return $1;
        }
    die(«Can't find ip»);
    }

Берём первый попавшийся IP указанного интерфейса.

И выкинем в функцию выполнение запроса к API и общие проверки ответа:
sub yapi {
    my $url = $_[0];
    die 'Not URL in params yapi func'
        unless defined($url);
    my $cont = $ua->get($url);
        die 'HTTP Error: ', $cont->status_line
            unless $cont->is_success;
        die 'Not XML, given ', $cont->content_type
            unless $cont->content_type eq 'text/xml';
    my $resp = XML::Simple
                    ->new()
                    ->XMLin( $cont->content );
        die 'API error: ',$resp->{domains}->{error}
            unless $resp->{domains}->{error} eq 'ok';
    return ($resp->{domains}->{domain});
    }

В частности, удостоверимся, что есть ответ сервера, распарсим XML и проверим, Яндекс не вернул ли API ошибку.

Теперь и основная часть:
#!/usr/bin/perl
# доменное имя
my $domain = 'example.org';
#токен авторизационный
my $token = '1bdf72e04d6b50c82a48c7e4dd38cc6920116dfd6774a9e7b32eddfe'; 
# новый IP, определяем по переданному первым аргументом имени интерфейса
# т.е., например, ./yaddns.pl ppp0
my $currentip = getip($ARGV[0]); 
 
use strict;
use LWP::UserAgent;
use XML::Simple;
#use Data::Dumper; #for debug!
my $ua = LWP::UserAgent->new;
$ua->agent(«dDNS client for pdd.yandex.ru.»);
 
 
my $domainlist = yapi('https://pddimp.yandex.ru/nsapi/get_domain_records.xml?token='.$token.'&domain='.$domain)->{response}->{record};
while ( my ($record_id, $record) = each(%$domainlist) ) {
    #print Dumper($record);
    if ($record->{type} eq 'A' && $currentip ne $record->{content} ) {
        my $update = 'https://pddimp.yandex.ru/nsapi/edit_a_record.xml?token='.$token
                    .'&domain='.$domain.'&subdomain='.$record->{subdomain}
                    .'&record_id='.$record_id.'&content='.$currentip;
        print 'Обновление записи '.$record_id.' (хост '.$record->{subdomain}.")\n";
        yapi($update);
        }
    }

Сим получаем список записей этого домена и обновляем все A-записи, у которых IP не тот, что мы хотим.

Вот и всё, в общем-то. Теперь осталось прописать запуск скрипта при поднятии интерфейса и можно спокойно жить дальше.

PS: под debian'ом нужно доставить, если не стоят, пакеты libcrypt-ssleay-perl, libxml-simple-perl и libwww-perl.

Обратите внимание, что API устарело в декабре 2014г.
Tags:
Hubs:
+18
Comments 25
Comments Comments 25

Articles