From 9c5b933befcd7fbaa038dbaebfaa63f2f12d7bac Mon Sep 17 00:00:00 2001 From: Denis Akimkin Date: Mon, 9 Mar 2015 00:52:36 +0200 Subject: [PATCH] Add support for Yandex.Mail for Domain DNS service (domain.yandex.com) Yandex's DNS management API reference is located at: https://api.yandex.com/domain/doc/about.xml --- README.md | 1 + ddclient | 153 ++++++++++++++++++++++++++++++++++++++- sample-etc_ddclient.conf | 8 ++ 3 files changed, 160 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index edd0dc7..0a9ec16 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Dynamic DNS services currently supported include: nsupdate - See nsupdate(1) and ddns-confgen(8) for details CloudFlare - See https://www.cloudflare.com/ for details Google - See http://www.google.com/domains for details + Yandex - See https://domain.yandex.com/ for details DDclient now supports many of cable/dsl broadband routers. diff --git a/ddclient b/ddclient index b0550f6..adca562 100755 --- a/ddclient +++ b/ddclient @@ -451,6 +451,9 @@ my %variables = ( 'googledomains-common-defaults' => { 'server' => setv(T_FQDNP, 1, 0, 1, 'domains.google.com', undef), }, + 'yandex-common-defaults' => { + 'server' => setv(T_FQDNP, 1, 0, 1, 'pddimp.yandex.ru', undef), + }, ); my %services = ( 'dyndns1' => { @@ -625,6 +628,16 @@ my %services = ( $variables{'service-common-defaults'}, ), }, + 'yandex' => { + 'updateable' => undef, + 'update' => \&nic_yandex_update, + 'examples' => \&nic_yandex_examples, + 'variables' => merge( + { 'min-interval' => setv(T_DELAY, 0, 0, 1, interval('5m'), 0),}, + $variables{'yandex-common-defaults'}, + $variables{'service-common-defaults'}, + ), + }, ); $variables{'merged'} = merge($variables{'global-defaults'}, $variables{'service-common-defaults'}, @@ -1868,6 +1881,9 @@ sub geturl { my $url = shift || ''; my $login = shift || ''; my $password = shift || ''; + my $data = shift || ''; + my $headerref = shift || ''; + my %headers = $headerref ? %$headerref : (); my ($peer, $server, $port, $default_port, $use_ssl); my ($sd, $rq, $request, $reply); @@ -1908,17 +1924,36 @@ sub geturl { my $to = sprintf "%s%s", $server, $proxy ? " via proxy $peer:$port" : ""; verbose("CONNECT:", "%s", $to); - $request = "GET "; - $request .= "http://$server" if $proxy; + $request = $data ? "POST " : "GET "; + if (!$use_ssl) { + $request .= "http://$server" if $proxy; + } else { + $request .= "https://$server" if $proxy; + } $request .= "/$url HTTP/1.0\n"; $request .= "Host: $server\n"; + for my $header (keys %headers) { + $request .= "${header}: "; + $request .= "$headers{$header}\n"; + } my $auth = encode_base64("${login}:${password}", ""); $request .= "Authorization: Basic $auth\n" if $login || $password; $request .= "User-Agent: ${program}/${version}\n"; + if ($data) { + $request .= "Content-Type: application/x-www-form-urlencoded\n"; + $request .= "Content-Length: "; + $request .= length($data); + $request .= "\n"; + } $request .= "Connection: close\n"; $request .= "\n"; + if ($data) { + $request .= $data; + $request .= "\n"; + } + ## make sure newlines are for some pedantic proxy servers ($rq = $request) =~ s/\n/\r\n/g; @@ -4117,6 +4152,120 @@ sub nic_cloudflare_update { } } } +###################################################################### +## nic_yandex_examples +###################################################################### +sub nic_yandex_examples { + return < $config{$key}{'password'}); + + # FQDNs + for my $host (@hosts) { + delete $config{$host}{'wantip'}; + + info("setting IP address to %s for %s", $ip, $host); + verbose("UPDATE:","updating %s", $host); + + # Get record ID for host + my $url = "https://$config{$host}{'server'}/api2/admin/dns/list?"; + $url .= "domain="; + $url .= $config{$key}{'login'}; + my $reply = geturl(opt('proxy'), $url, '', '', '', \%headers); + unless ($reply) { + failed("updating %s: Could not connect to %s.", $host, $config{$key}{'server'}); + last; + } + last if !header_ok($host, $reply); + + # Strip header + $reply =~ s/^.*?\n\n//s; + my $response = JSON::Any->jsonToObj($reply); + if ($response->{success} eq 'error') { + failed ("%s", $response->{error}); + next; + } + + # Pull the ID out of the json + my ($id) = map { $_->{fqdn} eq $host ? $_->{record_id} : () } @{ $response->{records} }; + unless($id) { + failed("updating %s: DNS record ID not found.", $host); + next; + } + + # Update the DNS record + $url = "https://$config{$host}{'server'}/api2/admin/dns/edit"; + my $data = "domain="; + $data .= $config{$key}{'login'}; + $data .= "&record_id="; + $data .= $id; + $data .= "&content="; + $data .= $ip if $ip; + + $reply = geturl(opt('proxy'), $url, '', '', $data, \%headers); + unless ($reply) { + failed("updating %s: Could not connect to %s.", $host, $config{$host}{'server'}); + last; + } + last if !header_ok($host, $reply); + + # Strip header + $reply =~ s/^.*?\n\n//s; + $response = JSON::Any->jsonToObj($reply); + if ($response->{success} eq 'error') { + failed ("%s", $response->{error}); + } else { + success ("%s -- Updated Successfully to %s", $host, $ip); + } + + # Cache + $config{$host}{'ip'} = $ip; + $config{$host}{'mtime'} = $now; + $config{$host}{'status'} = 'good'; + } + } +} ###################################################################### diff --git a/sample-etc_ddclient.conf b/sample-etc_ddclient.conf index de8bfbc..da42bd5 100644 --- a/sample-etc_ddclient.conf +++ b/sample-etc_ddclient.conf @@ -214,3 +214,11 @@ ssl=yes # use ssl-support. Works with # login=my-auto-generated-username, # password=my-auto-generated-password # my.domain.tld, otherhost.domain.tld + +## +## Yandex.Mail for Domain (domain.yandex.com) +## +# protocol=yandex, \ +# login=domain.tld, \ +# password=yandex-pdd-token \ +# my.domain.tld,other.domain.tld \