中国石油大学 校内DDNS脚本

暑假回学校后惊艳的发觉学校的路由策略有所调整。原来宿舍清一色的180IP段改成121段,可惜依旧是没有设置入口路由,且DHCP池时间设置的非常短,有时重启下路由器IP可能就变了。这种情况下显然记住IP是不现实的,萌生了通过DDNS保持指向的想法,在DnsPod官方给出的脚本基础上简单修改很轻易实现,却懒于一直没整理文档,今晚特此整理一下。

有关DDNS,摘录一段来自Wikipedia的解释:

动态DNS(英语:Dynamic DNS,简称DDNS)是域名系统(DNS)中的一种自动更新名称服务器(Name server)内容的技术。根据互联网的域名订立规则,域名必须跟从固定的IP地址。但动态DNS系统为动态网域提供一个固定的名称服务器(Name server),透过即时更新,使外界用户能够连上动态用户的网址。

我的域名是在 DnsPod 注册的,下面的脚本也是在 DnsPod 官方 API 开放的基础上写成的,如果你不是在 DnsPod 注册的,可能需要将域名的 NS 记录改为DnsPod 才能使用下面的脚本。

一、获取你的登录用Token

在路由器等公共设备上保存用户名密码是一种相当愚蠢的方式,为此 DnsPod 官方也加入 Token 验证方式,获取 Token 的方法很简单,登录 DnsPod,在 “用户中心” > “安全设置” > “API Token” 中创建一个新的 API Token 就可以,注意记录其ID和Token,特别是Token,只会在创建时候显示一次!

中国石油大学 校内DDNS脚本

 

二、获取 domain_id 和 record_id (两者顺序不能颠倒)

1、获取 domain_id

通过向 Domain.List API 发送POST请求的方式获得,如果是 *nix 系统,可以通过 curl 执行下面的执行获得。返回的结果为JSON,从JSON中找出 domain_id 即可(使用JSON可视化工具处理后可以方便的一眼看出相应的值)。

注意:务必记得用 ID,Token 的形式替换掉下面的 <your_login_token>

curl 'https://dnsapi.cn/Domain.List' -d 'login_token=<your_login_token>&format=json'

2、获取 record_id

注意:务必记得用 ID,Token 的形式替换掉下面的 <your_login_token><your_domain_id> 取上面的结果值!

curl 'https://dnsapi.cn/Record.List' -d 'login_token=<your_login_token>&format=json&domain_id=<your_domain_id>'

 

三、将相关信息填写入下面的代码中并使用Python3 执行

几点说明:

  • 不知道为什么,最近(2018.12.13)使用会提示SSL证书认证错误,如果有此提示,可将相关的两行注释取消即可取消证书有效性的验证。
  • 请务必根据自己是有线网络还是无线网络选择性的注释掉 getip() 中的另一个address,否则一定会出错!
  • 初次使用请创建空白的config.txt文件(否则程序会异常),该文件会保存上次程序运行的结果,防止相同IP时重复提交!
#-*- coding:utf-8 -*-
import http.client
import urllib
import socket
import time
import requests
import json

# # 如果提示证书错误,那么取消掉这两行注释。
# import ssl
# ssl._create_default_https_context = ssl._create_unverified_context

# 请登录 DnsPod 后台获取自己的 ID 和 Token 填写在这里
ID = "Your Login ID"
Token = "Your Login Token"

# 请参考上面的方法获取自己的 domain_id 和 record_id 填写在下面,并将子域名的内容填写到 sub_domain 中。
params = dict(
    login_token=("%s,%s" % (ID, Token)),
    format="json",
    domain_id=Your Domain ID,
    record_id=Your Record ID,
    sub_domain="Your Sub Domain",
    record_line="默认",
)

# 从文件中读取当前上次DDNS执行的结果
try:
    configFile = open("config.txt")
    current_ip = configFile.readline()
    configFile.close()
    print ("Saved IP : " + current_ip)
except Exception as e:
    print (e)

# 将DDNS执行结果写入 config.txt 文件
def write(ip):
    config = open("config.txt","w")
    config.write(ip)
    config.close()

# DDNS 提交到 DnsPod
def ddns(ip):
    params.update(dict(value=ip))
    headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/json"}
    conn = http.client.HTTPSConnection("dnsapi.cn")
    conn.request("POST", "/Record.Ddns", urllib.parse.urlencode(params), headers)

    response = conn.getresponse()
    print (response.status, response.reason)
    data = response.read()
    print (data)
    conn.close()
    return response.status == 200

# 从中国石油大学(华东)认证网关获取IP地址
# 请根据自己的需要选择有线认证网关或无线认证网关
def getip():
    address = "http://lan.upc.edu.cn/eportal/InterFace.do?method=getOnlineUserInfo"   #有线
    # address = "http://wlan.upc.edu.cn/eportal/InterFace.do?method=getOnlineUserInfo"  #无线    
    getText = requests.get(address).text
    textJson = json.loads(getText)
    return (textJson['userIp'])

if __name__ == '__main__':
    try:
        ip = getip()
        print ("IP from ePortal: " + ip)
        if current_ip != ip:
            if ddns(ip):
                current_ip = ip
                write(current_ip)
    except Exception as e:
        print (e)

补充:刚开始我采取的方法是while Ture和sleep的方式让程序常驻后台,但发现系统在资源不足的时候可能会杀进程,所以后面改用程序执行后保存当前IP且采用计划任务的形式执行,从而更加保证了DDNS程序的稳定运行。

分享