使用DNSPOD API实现域名动态解析

0. 简单概述
在家里放一个NAS服务器,但是宽带的IP地址经常改变,一般路由器自带的花生壳域名解析可以解决,如果路由器没有类似功能或者想使用自己的域名,可以尝试使用DNSPOD API来实现域名动态解析。

1. 添加记录
在dnspod添加域名后并添加一个记录用来解析宽带的IP地址,如添加一个记录h

2. 获取信息
1) 域名信息 domain_id
接口文档:https://www.dnspod.cn/docs/domains.html#domain-info

def domain_info(domain):  
    url = "https://dnsapi.cn/Domain.Info"
    data = {
        "login_email": LOGIN_EMAIL,
        "login_password": LOGIN_PASSWORD,
        "format": FORMAT,
        "domain": domain
    }
    r = requests.post(url, data=data, timeout=5)
    return r.json()["domain"]

def domain_id(domain):  
    info = domain_info(domain)
    return info["id"]

# 获取domain_id
print domain_id("greak.net")  

2) 记录信息 record_idrecord_linevalue
接口文档:https://www.dnspod.cn/docs/records.html#record-list

def record_info(domain, sub_domain):  
    url = "https://dnsapi.cn/Record.List"
    data = {
        "login_email": LOGIN_EMAIL,
        "login_password": LOGIN_PASSWORD,
        "format": FORMAT,
        "domain": domain,
        "sub_domain": sub_domain
    }
    r = requests.post(url, data=data, timeout=5)
    return r.json()["records"][0]

def record_data(domain, sub_domain):  
    info = record_info(domain, sub_domain)
    return info["id"], info["line"], info["value"]

# 获取record_id, record_line, value
rid, line, oldip = record_data("greak.net", "h")  

3) 获取最新IP地址
接口:http://greak.net/ip

def get_newip():  
    url = "http://greak.net/ip"
    r = requests.get(url, timeout=5)
    return r.content.strip()

# 获取IP地址
print get_newip()  

3. 修改记录
接口文档:https://www.dnspod.cn/docs/records.html#dns

def record_update(domain, sub_domain):  
    newip = get_newip()
    rid, line, oldip = record_data(domain, sub_domain)
    if newip == oldip:  # 比较新IP和现有记录是否一致,如果一致则不需要更新
        return "not change"
    url = "https://dnsapi.cn/Record.Ddns"
    data = {
        "login_email": LOGIN_EMAIL,
        "login_password": LOGIN_PASSWORD,
        "format": FORMAT,
        "domain_id": domain_id(domain),
        "record_id": rid,
        "sub_domain": sub_domain,
        "record_line": line,
        "value": newip
    }
    r = requests.post(url, data=data, timeout=5)
    return r.json()

# 修改记录
print record_update("greak.net", "h")  

4. 定期执行
完整python脚本dns.py

#!/usr/bin/env python2

import sys  
import os  
import json  
import time  
import requests

LOGIN_EMAIL = "xxxxxx@example.com"  
LOGIN_PASSWORD = "xxxxxx"  
FORMAT = "json"

def domain_info(domain):  
    url = "https://dnsapi.cn/Domain.Info"
    data = {
        "login_email": LOGIN_EMAIL,
        "login_password": LOGIN_PASSWORD,
        "format": FORMAT,
        "domain": domain
    }
    r = requests.post(url, data=data, timeout=5)
    return r.json()["domain"]

def domain_id(domain):  
    info = domain_info(domain)
    return info["id"]

def record_info(domain, sub_domain):  
    url = "https://dnsapi.cn/Record.List"
    data = {
        "login_email": LOGIN_EMAIL,
        "login_password": LOGIN_PASSWORD,
        "format": FORMAT,
        "domain": domain,
        "sub_domain": sub_domain
    }
    r = requests.post(url, data=data, timeout=5)
    return r.json()["records"][0]

def record_id(domain, sub_domain):  
    info = record_info(domain, sub_domain)
    return info["id"]

def record_line(domain, sub_domain):  
    info = record_info(domain, sub_domain)
    return info["line"]

def record_value(domain, sub_domain):  
    info = record_info(domain, sub_domain)
    return info["value"]

def record_data(domain, sub_domain):  
    info = record_info(domain, sub_domain)
    return info["id"], info["line"], info["value"]

def get_newip():  
    url = "http://greak.net/ip"
    r = requests.get(url, timeout=5)
    return r.content.strip()

def record_update(domain, sub_domain):  
    newip = get_newip()
    rid, line, oldip = record_data(domain, sub_domain)
    if newip == oldip:
        return "not change"
    url = "https://dnsapi.cn/Record.Ddns"
    data = {
        "login_email": LOGIN_EMAIL,
        "login_password": LOGIN_PASSWORD,
        "format": FORMAT,
        "domain_id": domain_id(domain),
        "record_id": rid,
        "sub_domain": sub_domain,
        "record_line": line,
        "value": newip
    }
    r = requests.post(url, data=data, timeout=5)
    return r.json()

if __name__ == "__main__":  
    print time.strftime("%Y/%m/%d %H:%M:%S")
    print record_update("greak.net", "h")

添加cron计划任务执行

#dns record update
*/1 * * * * root /usr/bin/python /home/debian/dns.py >>/home/debian/dns.log 2>&1

日志输出

2016/05/01 18:17:02  
{u'status': {u'message': u'Action completed successful', u'code': u'1', u'created_at': u'2016-05-01 18:17:03'}, u'record': {u'id': 178422498, u'value': u'180.172.158.222', u'name': u'h'}}
# 更新成功

2016/05/01 18:18:02  
not change  
# 没有变化,无需改变

检查是否生效

$ curl greak.net/ip
180.172.158.222

$ dig h.greak.net | grep "^h.greak.net" | awk '{print $NF}'
180.172.158.222  

如果输出的IP地址一样就表示生效了,由于存在dns缓存,dns生效需要大概几分钟
注:dnspod的api调用有次数限制,不要频繁调用