使用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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章