利用DNSPodAPI实现服务器DDNS解析

DDNS是将用户的动态IP地址映射到一个固定的域名解析服务上,用户每次连接网络的时候客户端程序就会通过信息传递把该主机的动态IP地址传送给位于服务商主机上的服务器程序,服务器程序负责提供DNS服务并实现动态域名解析。

一句话:把动态变化的IP地址绑定到固定不变的域名上,以不变应万变。

博主找了很多DNSPOD的API脚本,一部分已经是几年前开发的了,运行起来会出现各种问题,后面找到一个完美版本,分享给大家。

从实际上来说,为什么我们会需要DDNS服务?

现阶段的HKT和Hinet的NAT机器非常流行,一部分商家已经为我们做好了DDNS服务,我们只需要使用官方提供的域名即可,但是一部分商家不提供DDNS,而是为我们提供一个动态IP,当IP出现问题后, 商家更换IP也不会通知我们。需要去后台查看,所以解决这个问题,就需要我们自建DDNS。

DNSPodAPI安装:

#!/usr/bin/env python
# -*- coding:utf-8 -*-


import socket
import requests
import time
import logging

logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)


class DNSPod(object):
    """DNSPod ddns application."""

    def __init__(self, params):
        """Initialize with params."""
        self._params = params

    def run(self, params=None):
        if params is None:
            params = self._params
        public_ip = self.get_public_ip()
        # get record_id of sub_domain
        record_list = self.get_record_list(params)
        if record_list['code'] == '10':
            # create record for empty sub_domain
            record_id = self.create_record(params, public_ip)
            remote_ip = public_ip
        elif record_list['code'] == '1':
            # get record id
            record_id = record_list['record_id']
            remote_ip = record_list['ip_value']
        else:
            logger.error('!!!can not get record_id!!!')
            return -1
        params['record_id'] = record_id

        current_ip = remote_ip
        while True:
            try:
                public_ip = self.get_public_ip()
                if current_ip != public_ip:
                    logger.warning("update IP from %s to %s" % (current_ip, public_ip))
                    if self.ddns(params, public_ip):
                        current_ip = public_ip
                else:
                    logger.info("IP remains %s" % public_ip)
            except Exception as e:
                logger.error(e)
            exit()
            pass
            time.sleep(300)

    def get_public_ip(self):
        """Get public ip via dnspod."""
        sock = socket.create_connection(('ns1.dnspod.net', 6666), timeout=30)
        ip = sock.recv(16)
        sock.close()
        return ip.decode('utf-8')

    def get_record_list(self, params):
        """Get record list.

        https://www.dnspod.cn/docs/records.html#record-list
        :return: dict of code, record_id and IP value
        """
        record_list_url = 'https://dnsapi.cn/Record.List'
        r = requests.post(record_list_url, data=params)
        code = r.json()['status']['code']
        record_id = r.json()['records'][0]['id'] if code == '1' else ""
        ip_value = r.json()['records'][0]['value'] if code == '1' else ""
        return dict(code=code, record_id=record_id, ip_value=ip_value)

    def create_record(self, params, ip):
        """Create record if not created before.

        https://www.dnspod.cn/docs/records.html#record-create
        :return: record_id of new record
        """
        params['value'] = ip
        record_create_url = 'https://dnsapi.cn/Record.Create'
        r = requests.post(record_create_url, data=params)
        logger.warning('create new record %s.%s with IP %s' % (params['sub_domain'], params['domain'], ip))
        assert r.json()['status']['code'] == '1'
        record_id = r.json()['record']['id']
        return record_id

    def ddns(self, params, ip):
        """Update ddns ip.

        https://www.dnspod.cn/docs/records.html#dns
        """
        params['value'] = ip
        ddns_url = 'https://dnsapi.cn/Record.Ddns'
        r = requests.post(ddns_url, data=params)
        logger.info('status: %s, reason: %s' % (r.status_code, r.reason))
        return r.json()['status']['code'] == '1'


def main():
    # initialize params
    # Use Token, check https://support.dnspod.cn/Kb/showarticle/tsid/227
    ID = '请输入id'  # replace with your ID
    Token = '请输入token'  # replace with your Token
    params = dict(
        login_token=("%s,%s" % (ID, Token)),
        format='json',
        domain='请输入主域名',  # replace with your domain
        sub_domain='需要解析的二级域名名字',  # replace with your sub_domain
        record_type='A',
        record_line='默认'
    )

    dnspod = DNSPod(params)
    dnspod.run()


if __name__ == "__main__":
    main()

修改配置:

修改配置请替换文件中红色部分即可。举例子,我们有个域名叫 gov.cn,需要解析hinet.gov.cn到服务器中,所以后面这样填:

domain='gov.cn',  # replace with your domain
        sub_domain='hinet',  # replace with your sub_domain
        record_type='A',
        record_line='默认'

脚本在线下载:

wget https://cikeblog.com/e/ddns.py && chmod +x ddns.py

将文件存为ddns.py后,我们赋予执行权限:

chmod  +x ddns.py

然后手动执行一次:

./ddns.py

测试无问题后,将其加入放入/home、目录下,并加入crontab定时任务,推荐为20分钟执行一次:

crontab -e
*/20 * * * * /home/ddns.py

请注意,请先为域名做一个A记录,填写内容为任意IP,脚本只能进行修改记录,无法为您创建一个子域名记录。

DNSPodAPI申请:

https://www.dnspod.cn/console/user/security

申请后,请记录下ID和token,此信息只会出现一次,然后进行文件替换即可。

注意,DNSPOD有个好处,我们手动修改域名信息的话,最低TTL为600,用脚本执行的话,TTL可以最低到10,这样解析会更快生效。

《利用DNSPodAPI实现服务器DDNS解析》

文章来源: https://cikeblog.com/use-dnspodapi-to-achieve-server-ddns-resolution.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注