V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
freetg
V2EX  ›  Python

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

  •  
  •   freetg ·
    bagel · 2016-05-01 19:00:18 +08:00 · 21359 次点击
    这是一个创建于 3160 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 = "[email protected]"
    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 调用有次数限制,不要频繁调用

    原文地址:http://greak.net/2016/05/01/shi-yong-dnspod-apishi-xian-yu-ming-dong-tai-jie-xi/

    11 条回复    2016-05-03 02:23:43 +08:00
    boboliu
        1
    boboliu  
       2016-05-01 19:06:47 +08:00
    。。。这种文章发来 V2 , B 格略不足的样子(以及论大内网的重要性)
    freetg
        2
    freetg  
    OP
       2016-05-01 19:14:10 +08:00
    @boboliu 求老司机指点
    clanned
        3
    clanned  
       2016-05-01 20:01:06 +08:00 via Android
    这里有 shell 脚本的,可以在 ddwrt 和 openwrt 里跑。 https://github.com/xdtianyu/scripts/tree/master/ddns
    Tink
        4
    Tink  
       2016-05-01 20:05:52 +08:00 via iPhone
    我觉得一句 curl 就搞定了啊
    am241
        5
    am241  
       2016-05-01 20:13:37 +08:00
    在网上找了一圈.py 和.sh 结果都以报错而告终后,昨天半夜刚搞了一个

    https://github.com/lijyigithub/ddnspod/blob/master/ddnspod.py
    LazyZhu
        6
    LazyZhu  
       2016-05-01 20:20:13 +08:00
    ETiV
        7
    ETiV  
       2016-05-01 20:22:00 +08:00 via iPhone
    dnspod 有 token 机制了,设置这种不需要密码了
    tSQghkfhTtQt9mtd
        8
    tSQghkfhTtQt9mtd  
       2016-05-01 21:19:52 +08:00 via Android
    对于 @CloudXNS 来说只需要

    #!/bin/sh
    API_KEY=""
    SECRET_KEY=""
    DATE=$(date)
    URL_U="https://www.cloudxns.net/api2/ddns"

    PARAM_BODY="{\"domain\":\"ddns.example.com\"}"
    HMAC_U=$(echo -n "$API_KEY$URL_U$PARAM_BODY$DATE$SECRET_KEY"|md5sum|cut -d" " -f1)

    RESULT=$(/opt/bin/curl -k -s $URL_U -X POST -d $PARAM_BODY -H "API-KEY: $API_KEY" -H "API-REQUEST-DATE: $DATE" -H "API-HMAC: $HMAC_U" -H 'Content-Type: application/json')

    echo $RESULT

    if [ $(echo -n "$RESULT"|grep -o "message\":\"success\""|wc -l) = 1 ];then
    echo "$(date) -- Update success"
    else
    echo "$(date) -- Update failed"
    fi
    qile1
        9
    qile1  
       2016-05-01 22:12:25 +08:00 via Android
    这个限制太多,一直没时间弄在自己服务器上基本时时更新的。
    ProfFan
        10
    ProfFan  
       2016-05-02 17:36:34 +08:00
    @qile1 ArDNSPod
    realpg
        11
    realpg  
       2016-05-03 02:23:43 +08:00
    我觉得 dnspod 这种弱爆了……
    提供一个动态 IP 独立 API 也就是几行代码的事儿
    当年 3322 那个接口多好
    http://username:[email protected]/update?domain=xxxx.xxxx.net&ip=119.119.119.119
    哪怕一个 wget 都能更新 IP
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   993 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 21:26 · PVG 05:26 · LAX 13:26 · JFK 16:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.