天天看點

使用python實作阿裡雲動态域名解析DDNS

前言

前置條件

1、域名是在阿裡雲購買的

2、位址必須是公網位址,不然加了解析也沒有用

簡介

通過阿裡雲提供的SDK,然後自己編寫程式新增或者修改域名的解析,達到動态解析域名的目的;主要應用于pppoe撥号的環境,比如家裡設定了伺服器,但是外網位址經常變化的場景;再比如公司的pppoe網關,需要建立vpn的場景。

安裝阿裡雲SDK

需要安裝兩個SDK庫,一個是阿裡雲核心SDK庫,一個是阿裡雲域名SDK庫;

阿裡雲核心SDK庫:pip install aliyun-python-sdk-core

阿裡雲域名SDK庫:pip install aliyun-python-sdk-domain

阿裡雲SDK幫助

關于調試

阿裡雲提供一個線上調試,支援線上調試好之後,再複制回來本地即可。使用調試平台需要先登入。

線上調試平台

API的子產品名稱都可以通過

幫助文檔

查詢

設計思路

一、擷取阿裡雲的accessKeyId和accessSecret

二、擷取外網ip

三、判斷外網ip是否與之前一緻

四、外網ip不一緻時,新增或者更新域名解析記錄

詳細步驟

擷取accessKeyId和accessSecret

可以在阿裡雲控制台個人中心直接擷取,但是一般建議使用RAM角色來進行權限控制,這樣這個accessKey和accessSecret就隻能操作域名,不能操作其他的資源,相對會比較安全。關于RAM快速入門,請

點選連結

擷取到accessKeyId和accessSecret之後,填入相對應的函數中即可:

from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from hwx_function import *
import os
import time

client = AcsClient('<accessKeyId>', '<accessSecret>', 'cn-hangzhou')           

擷取外網IP

通過網絡上面的外網ip的API擷取,可以使用多個,我這裡隻是列舉了一個,具體代碼如下:

def get_internet_ip():
    with urllib.request.urlopen('http://www.3322.org/dyndns/getip') as response:
        html = response.read()
        ip = str(html, encoding='utf-8').replace("\n", "")
    return ip           

判斷IP是否一緻

因為阿裡雲不允許修改相同的解析,是以需要比對IP是否一緻;因為把上一次解析的IP寫入檔案,是以隻需要讀取出來,跟本次得到的外網IP相比較,一緻則不修改解析記錄,不一緻則修改解析記錄。關于域名解析操作的代碼,下面會有解釋。

with open("./ip", 'r') as f:
        old_ip = f.read()
    if ip == old_ip:
        print("noupdate"+"\nnew_ip:"+ip+"\nold_ip:"+old_ip)
    else:
        #print("update"+"\nnew_ip:"+ip+"\nold_ip:"+old_ip)
        wirte_to_file("./ip",ip)
        des_relsult = Describe_SubDomain_Records(client,"A","sz.huangwx.cn")
        #判斷子域名解析記錄查詢結果,TotalCount為0表示不存在這個子域名的解析記錄,需要新增一個
        if des_relsult["TotalCount"] == 0:
            add_relsult = add_record(client,"5","600","A",ip,"sz","huangwx.cn")
            record_id = add_relsult["RecordId"]
            print("域名解析新增成功!")
        #判斷子域名解析記錄查詢結果,TotalCount為1表示存在這個子域名的解析記錄,需要更新解析記錄,更新記錄需要用到RecordId,這個在查詢函數中有傳回des_relsult["DomainRecords"]["Record"][0]["RecordId"]
        elif des_relsult["TotalCount"] == 1:
            record_id = des_relsult["DomainRecords"]["Record"][0]["RecordId"]
            update_record(client,"5","600","A",ip,"sz",record_id)
            print("域名解析更新成功!")
        else:
            record_id = 0
            print("存在兩個子域名解析記錄值,請核查删除後再操作!")
        path = './RecordId'
        wirte_to_file(path,record_id)           

域名解析記錄操作

域名解析記錄不存在時,就新增解析記錄,如果已經存在,則修改解析記錄;是以這裡還需要用到查詢子域名解析記錄的API;

子域名解析記錄查詢

Describe_SubDomain_Records(client,"A","sz.huangwx.cn")

這個函數會傳回一大堆東西,但是目前我們需要使用的就兩個,一個是解析記錄的數量,一個就是RecordId,RecordId修改域名解析時需要用到;

#這個是函數
def Describe_SubDomain_Records(client,record_type,subdomain):
    request = DescribeSubDomainRecordsRequest()
    request.set_accept_format('json')

    request.set_Type(record_type)
    request.set_SubDomain(subdomain)

    response = client.do_action_with_exception(request)
    response = str(response, encoding='utf-8')
    relsult = json.loads(response)
    return relsult
    
#以下是函數調用以及說明
des_relsult = Describe_SubDomain_Records(client,"A","sz.huangwx.cn")
des_relsult["TotalCount"]:解析記錄的數量,0表示解析記錄不存在,1表示有一條解析記錄
des_relsult["DomainRecords"]["Record"][0]["RecordId"]:當des_relsult["TotalCount"]為1時,會傳回這個RecordId,後續的修改域名解析記錄中需要用到           

新增域名解析記錄

如果域名解析記錄不存在時,就需要新增域名解析記錄,新增域名解析記錄比較簡單,直接填寫參數即可

def add_record(client,priority,ttl,record_type,value,rr,domainname):
    request = AddDomainRecordRequest()
    request.set_accept_format('json')

    request.set_Priority(priority)
    request.set_TTL(ttl)
    request.set_Value(value)
    request.set_Type(record_type)
    request.set_RR(rr)
    request.set_DomainName(domainname)

    response = client.do_action_with_exception(request)
    response = str(response, encoding='utf-8')
    relsult = json.loads(response)
    return relsult

#函數調用
add_relsult = add_record(client,"5","600","A",ip,"sz","huangwx.cn")
record_id = add_relsult["RecordId"]#同樣會傳回一個RecordId,修改的時候也可以直接調用           

更新域名解析記錄

如果域名解析記錄已存在,則不能使用新增,而是更新域名解析記錄。更新的時候需要用到RecordId,這個一般查詢的時候就會有傳回,直接使用即可

def update_record(client,priority,ttl,record_type,value,rr,record_id):
    request = UpdateDomainRecordRequest()
    request.set_accept_format('json')

    request.set_Priority(priority)
    request.set_TTL(ttl)
    request.set_Value(value)
    request.set_Type(record_type)
    request.set_RR(rr)
    request.set_RecordId(record_id)

    response = client.do_action_with_exception(request)
    response = str(response, encoding='utf-8')
    return response

#函數調用
record_id = des_relsult["DomainRecords"]["Record"][0]["RecordId"]
update_record(client,"5","600","A",ip,"sz",record_id)           

再加個循環或者定時任務即可定時更新域名解析記錄了

總結

1、阿裡雲函數的使用依賴于阿裡雲的SDK庫,是以這個一定要安裝好

2、新增解析記錄的時候,可以把RecordId存儲在本地檔案,下次直接判斷檔案是否存在即可,不用每次都調用查詢API