使用Perl来对dnspod进行记录自动更新


在家外想访问家中主机上的资源,这就需要至少能访问到家中的网络设备。但adsl拨号得到的公网ip会隔一段时间发生变化,因此我还需要得到在我的adsl的公网ip发生变化知道。
当然,你还要要adsl上开启nat转发,这样才可能访问内部的服务,这里有一篇文章:如何在adsl得到最高权限来开启此类设置。
在我进行不定时更新dns记录前,我了解到一种动态dns解析的网络服务,也了解到一些服务提供商(一般的adsl上就支持自动更新到相应的dns服务商),但我最终还是放弃了这种方式。在老牌的动态dns服务商dyndns的网站上,可能是英语差,没有找到免费的功能块;国内的就更离谱了,邮箱还不够,还要手机和身份证。
求人不求己,我有域名,完全可以分配一个主机名,及时更新指向就行。但需要dns服务商支持这种自我更新的操作接口(api),还好本站的域名虽注册地在国外,但解析是停靠在国内,放在dnspod.cn上。
在起先转入时,曾经注意到他们可以提供api进行域名的操作。在其官方主页发仔细发现确实有详细的api文档,还提供了一些语言的sdk,不过没有关于Perl的只言片语,不过提供的是标准的http请求,Perl表示毫无鸭梨。
本脚本要实现下面的目的:找出本机的公网ip,并与上一次所得到的公网ip相比较,若发生改变则需要更新到dnspod,更新后通知我,需要定期执行。代码如下(该代码已经过时,请直接参考后面的代码):
use feature qw(:5.18);
use Mojo::UserAgent;
use Storable;
use Encode;
use Mojo::JSON qw(decode_json encode_json);
use Data::Dumper;
use Net::SMTP_auth;
binmode(STDOUT,':encoding(utf8)');
#Storable database iphs means storable db hash
my ($sdb,$iphs)=('/tmp/dns.sdb',());
$iphs=retrieve($sdb) if(-e $sdb);
my $ua = Mojo::UserAgent->new();
my $json = Mojo::JSON->new;
$ua->cookie_jar(0);
#get my public ip address(从ip.cn上取得公网ip地址)
my $cip=$ua->get('http://ip.cn')->res->dom->find('code')->text;
chomp($cip);
#define dns modify post hash(提交到dnspod api的语句块,这些信息可以通过其它的api来取得,当然你得有登录信息和真实的域名才行)
my $padata={login_email=>'freeoa@freeoa.net',login_password=>'mypasswd',format=>'json',lang=>'cn','domain_id'=>1256763,record_id=>54725811,record_ty
pe=>'A',ttl=>200,record_line=>decode("utf8",'默认'),sub_domain=>'iamhere',value=>"$cip"};
sub change_dns_ip{
my $tx=$ua->post('https://dnsapi.cn/Record.Modify'=>form=>$padata);
if(my $res=$tx->success){
my $rc=$json->decode($res->body);
say Dumper($rc);
#say $rc->{status}->{message};
}else{
my ($err, $code) = $tx->error;
say $code ? "$code response: $err" : "Connection error: $err";
}
}
#handle result and update dns
if(-e $sdb){
if($cip ne $iphs->{ip}){
say "public ip is changed to:$cip";
$iphs->{ip}=$cip;
change_dns_ip;
mail_sender('Home public ip chaned',"The new ip is:$cip");
}else{
say "ip not change:$cip";
}
}else{
#for first time run,must update dns record
$iphs->{ip}=$cip;
change_dns_ip;
mail_sender('Home public ip discover',"The ip is:$cip");
}
#邮件发送函数
sub mail_sender{
my ($subject,$mesg)=(@_);
my $smtp=Net::SMTP_auth->new('mail.fmail.com',Hello => 'mail.fmail.com',Debug=>1);
$smtp->auth('LOGIN','monitor@fmail.com','mpaswd');
#mail from
$smtp->mail('monitor@fmail.com');
#mail to
$smtp->to('zheng@xd-tech.cn');
$smtp->send_and_mail('monitor@fmail.com');
#####
$smtp->data();
$smtp->datasend("From: monitor\@fmail.com\n");
$smtp->datasend("To: zheng\@fmail.com\n");
$smtp->datasend("Subject:$subject \n");
#mail_to
#$smtp->datasend("monitor\@fmail.com");
#注意这里要两个换行,不然不会显示邮件正文内容。。。
$smtp->datasend("\n");
$smtp->datasend("\n");
$smtp->datasend("$mesg \n");
$smtp->dataend();
$smtp->quit;
}## mail send fun end
END{
#save to storage db
store $iphs,$sdb;
}
本文是采用Mojolicious的Mojo::UserAgent模块来实现http访问和提交,个人感觉简单的http应用还是HTTP::Tiny 模块好用些。
脚本使用系统的crontab来五分钟调用一次,在dnspod上可以将该记录ttl时间设定的小一些,这样不同的地方缓存该记录的时间更短。
############### 更新于2018年10月 ###############
更新于2018年10月,最新的dnspod主机名的更新办法。有如下一些改进:
1、dnspod.cn启用的新的login_token方式,取代了之前的登录名及密码,生成此种登录方式需要自行进行后台设置生成。
2、官方提供了一个通过socket方式取得客户机公网ip地址的接口,客户不需要从第三方或其它渠道获取其公网地址。
3、Mojo::UserAgent的api调用方式有所改变。
use v5.16;
use Encode;
use Storable;
use Data::Dumper;
use Net::SMTP_auth;
use Mojo::UserAgent;
use IO::Socket::INET;
use Mojo::JSON qw(decode_json encode_json);
binmode(STDOUT,':encoding(utf8)');
my $ua = Mojo::UserAgent->new;
#Storable database iphs means storable db hash
my ($sdb,$iphs,$cip)=('/tmp/dns.sdb');
$iphs=retrieve($sdb) if(-e $sdb);
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::INET(PeerHost => 'ns1.dnspod.net',PeerPort => '6666',Proto => 'tcp');
exit && warn "cannot connect to the server $!" unless $socket;
# data to send to a server
my $size = $socket->send('hello dnspod.');
#print "sent data of length $size\n";
# notify server that request has been sent
shutdown($socket, 1);
# receive a response of up to 1024 characters from server
my $res;
$socket->recv($res, 1024);
$cip=$res;
$socket->close();#关闭连接
#say "My public ip is:$cip" if(length($cip)>6);
#define dns modify post hash(提交到dnspod api的语句块,这些信息可以通过其它的api来取得,当然你得有登录信息和真实的域名才行)
my $padata={login_token=>'709nn,39493b4d1bce485f646240fd9bdabcdef',format=>'json',lang=>'cn','domain_id'=>69318880,record_id=>387354261,
record_type=>'A',ttl=>600,record_line_id=>0,sub_domain=>'mysite',value=>"$cip"};
#handle result and update dns
if(-e $sdb){
if($cip ne $iphs->{ip}){
#say "public ip is changed to:$cip";
$iphs->{ip}=$cip;
change_dns_ip();
}else{
#say "ip not change:$cip";
}
}else{
#for first time run,must update dns record
$iphs->{ip}=$cip;
change_dns_ip();
}
sub change_dns_ip{
my $tx=$ua->post('https://dnsapi.cn/Record.Modify'=>form=>$padata);
my $srs=decode_json($tx->res->body);
if($srs->{status}->{code} != 1){
#修改失败
mail_sender('dnspod modify failed!',$srs->{status}->{message});
}else{
#修改成功
mail_sender('office public ip changed',$cip);
}
}
#邮件发送函数
sub mail_sender{
#同上
}
END{
#save to storage db
store $iphs,$sdb;
}
当然,你还要要adsl上开启nat转发,这样才可能访问内部的服务,这里有一篇文章:如何在adsl得到最高权限来开启此类设置。
在我进行不定时更新dns记录前,我了解到一种动态dns解析的网络服务,也了解到一些服务提供商(一般的adsl上就支持自动更新到相应的dns服务商),但我最终还是放弃了这种方式。在老牌的动态dns服务商dyndns的网站上,可能是英语差,没有找到免费的功能块;国内的就更离谱了,邮箱还不够,还要手机和身份证。
求人不求己,我有域名,完全可以分配一个主机名,及时更新指向就行。但需要dns服务商支持这种自我更新的操作接口(api),还好本站的域名虽注册地在国外,但解析是停靠在国内,放在dnspod.cn上。
在起先转入时,曾经注意到他们可以提供api进行域名的操作。在其官方主页发仔细发现确实有详细的api文档,还提供了一些语言的sdk,不过没有关于Perl的只言片语,不过提供的是标准的http请求,Perl表示毫无鸭梨。
本脚本要实现下面的目的:找出本机的公网ip,并与上一次所得到的公网ip相比较,若发生改变则需要更新到dnspod,更新后通知我,需要定期执行。代码如下(该代码已经过时,请直接参考后面的代码):
use Mojo::UserAgent;
use Storable;
use Encode;
use Mojo::JSON qw(decode_json encode_json);
use Data::Dumper;
use Net::SMTP_auth;
binmode(STDOUT,':encoding(utf8)');
#Storable database iphs means storable db hash
my ($sdb,$iphs)=('/tmp/dns.sdb',());
$iphs=retrieve($sdb) if(-e $sdb);
my $ua = Mojo::UserAgent->new();
my $json = Mojo::JSON->new;
$ua->cookie_jar(0);
#get my public ip address(从ip.cn上取得公网ip地址)
my $cip=$ua->get('http://ip.cn')->res->dom->find('code')->text;
chomp($cip);
#define dns modify post hash(提交到dnspod api的语句块,这些信息可以通过其它的api来取得,当然你得有登录信息和真实的域名才行)
my $padata={login_email=>'freeoa@freeoa.net',login_password=>'mypasswd',format=>'json',lang=>'cn','domain_id'=>1256763,record_id=>54725811,record_ty
pe=>'A',ttl=>200,record_line=>decode("utf8",'默认'),sub_domain=>'iamhere',value=>"$cip"};
sub change_dns_ip{
my $tx=$ua->post('https://dnsapi.cn/Record.Modify'=>form=>$padata);
if(my $res=$tx->success){
my $rc=$json->decode($res->body);
say Dumper($rc);
#say $rc->{status}->{message};
}else{
my ($err, $code) = $tx->error;
say $code ? "$code response: $err" : "Connection error: $err";
}
}
#handle result and update dns
if(-e $sdb){
if($cip ne $iphs->{ip}){
say "public ip is changed to:$cip";
$iphs->{ip}=$cip;
change_dns_ip;
mail_sender('Home public ip chaned',"The new ip is:$cip");
}else{
say "ip not change:$cip";
}
}else{
#for first time run,must update dns record
$iphs->{ip}=$cip;
change_dns_ip;
mail_sender('Home public ip discover',"The ip is:$cip");
}
#邮件发送函数
sub mail_sender{
my ($subject,$mesg)=(@_);
my $smtp=Net::SMTP_auth->new('mail.fmail.com',Hello => 'mail.fmail.com',Debug=>1);
$smtp->auth('LOGIN','monitor@fmail.com','mpaswd');
#mail from
$smtp->mail('monitor@fmail.com');
#mail to
$smtp->to('zheng@xd-tech.cn');
$smtp->send_and_mail('monitor@fmail.com');
#####
$smtp->data();
$smtp->datasend("From: monitor\@fmail.com\n");
$smtp->datasend("To: zheng\@fmail.com\n");
$smtp->datasend("Subject:$subject \n");
#mail_to
#$smtp->datasend("monitor\@fmail.com");
#注意这里要两个换行,不然不会显示邮件正文内容。。。
$smtp->datasend("\n");
$smtp->datasend("\n");
$smtp->datasend("$mesg \n");
$smtp->dataend();
$smtp->quit;
}## mail send fun end
END{
#save to storage db
store $iphs,$sdb;
}
本文是采用Mojolicious的Mojo::UserAgent模块来实现http访问和提交,个人感觉简单的http应用还是HTTP::Tiny 模块好用些。
脚本使用系统的crontab来五分钟调用一次,在dnspod上可以将该记录ttl时间设定的小一些,这样不同的地方缓存该记录的时间更短。
############### 更新于2018年10月 ###############
更新于2018年10月,最新的dnspod主机名的更新办法。有如下一些改进:
1、dnspod.cn启用的新的login_token方式,取代了之前的登录名及密码,生成此种登录方式需要自行进行后台设置生成。
2、官方提供了一个通过socket方式取得客户机公网ip地址的接口,客户不需要从第三方或其它渠道获取其公网地址。
3、Mojo::UserAgent的api调用方式有所改变。
use v5.16;
use Encode;
use Storable;
use Data::Dumper;
use Net::SMTP_auth;
use Mojo::UserAgent;
use IO::Socket::INET;
use Mojo::JSON qw(decode_json encode_json);
binmode(STDOUT,':encoding(utf8)');
my $ua = Mojo::UserAgent->new;
#Storable database iphs means storable db hash
my ($sdb,$iphs,$cip)=('/tmp/dns.sdb');
$iphs=retrieve($sdb) if(-e $sdb);
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::INET(PeerHost => 'ns1.dnspod.net',PeerPort => '6666',Proto => 'tcp');
exit && warn "cannot connect to the server $!" unless $socket;
# data to send to a server
my $size = $socket->send('hello dnspod.');
#print "sent data of length $size\n";
# notify server that request has been sent
shutdown($socket, 1);
# receive a response of up to 1024 characters from server
my $res;
$socket->recv($res, 1024);
$cip=$res;
$socket->close();#关闭连接
#say "My public ip is:$cip" if(length($cip)>6);
#define dns modify post hash(提交到dnspod api的语句块,这些信息可以通过其它的api来取得,当然你得有登录信息和真实的域名才行)
my $padata={login_token=>'709nn,39493b4d1bce485f646240fd9bdabcdef',format=>'json',lang=>'cn','domain_id'=>69318880,record_id=>387354261,
record_type=>'A',ttl=>600,record_line_id=>0,sub_domain=>'mysite',value=>"$cip"};
#handle result and update dns
if(-e $sdb){
if($cip ne $iphs->{ip}){
#say "public ip is changed to:$cip";
$iphs->{ip}=$cip;
change_dns_ip();
}else{
#say "ip not change:$cip";
}
}else{
#for first time run,must update dns record
$iphs->{ip}=$cip;
change_dns_ip();
}
sub change_dns_ip{
my $tx=$ua->post('https://dnsapi.cn/Record.Modify'=>form=>$padata);
my $srs=decode_json($tx->res->body);
if($srs->{status}->{code} != 1){
#修改失败
mail_sender('dnspod modify failed!',$srs->{status}->{message});
}else{
#修改成功
mail_sender('office public ip changed',$cip);
}
}
#邮件发送函数
sub mail_sender{
#同上
}
END{
#save to storage db
store $iphs,$sdb;
}
该文章最后由 阿炯 于 2018-10-29 20:42:16 更新,目前是第 2 版。