阿里云动态DNS解析脚本之最笨的开发

文末有现成的代码供下载,只需要简单的配置节课使用,伸手党快来吧

0x01 前言

之所以说我这么开发很笨,主要是因为,代码写的真的很low,还花了两三个小时来调试,由于代码上有注释,我就直接上代码了

0x02 DDNS核心代码

首先新建一个文件夹,取名叫Aliddns

ddns.py

import json
import time
import requests
import re
from datetime import datetime
import urllib
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
import logging
from config import *
import getip

class Aliddns:
    def __init__(self):
        self.clt = AcsClient(access_key_id, access_key_secret, 'default')

    def RequestDomainIP(self, rrkey, keyType):
        """ 查询domain_name中域名的ip地址

        """
        request = CommonRequest()
        request.set_accept_format(recv_format)
        request.set_domain(aliddns_api)
        request.set_method('POST')
        request.set_protocol_type('https')
        request.set_version('2015-01-09')
        request.set_action_name('DescribeDomainRecords')
        request.add_query_param('RRKeyWord', rrkey)
        request.add_query_param("TypeKeyWord", keyType)
        request.add_query_param('DomainName', domain_name)
        m = self.clt.do_action(request)
        response = json.loads(m.decode('utf-8'))
        try:
            result = response['DomainRecords']['Record']
        except:
            result  = False
        return result


    def UpdateDNS(self, dns_type, dns_rrKey, dns_record_id, dns_value):
        request = CommonRequest()
        request.set_accept_format(recv_format)
        request.set_domain(aliddns_api)
        request.set_method('POST')
        request.set_protocol_type('https')
        request.set_version('2015-01-09')
        request.set_action_name('UpdateDomainRecord')

        request.add_query_param('RecordId', dns_record_id)
        request.add_query_param('RR', dns_rrKey)
        request.add_query_param('Type', dns_type)
        request.add_query_param('Value', dns_value)

        response = json.loads(self.clt.do_action(request).decode('utf-8'))
        return response

    def AddDNS(self, rrKey, dns_type, dns_value, dns_ttl):
        request = CommonRequest()
        request.set_accept_format(recv_format)
        request.set_domain(aliddns_api)
        request.set_method('POST')
        request.set_protocol_type('https')
        request.set_version('2015-01-09')

        request.set_action_name('AddDomainRecord')

        request.add_query_param('DomainName', domain_name)
        request.add_query_param('RR', rrKey)
        request.add_query_param('Type', dns_type)
        request.add_query_param('Value', dns_value)

        response = json.loads(self.clt.do_action(request).decode('utf-8'))
        return response

    def DeleteDNS(self, record_id):
        request = CommonRequest()
        request.set_accept_format(recv_format)
        request.set_domain(aliddns_api)
        request.set_method('POST')
        request.set_protocol_type('httpps')
        request.set_version('2015-01-09')
        request.set_action_name('DeleteDomainRecord')
        request.add_query_param('RecordId', record_id)

        response = json.loads(self.clt.do_action(request).decode('utf-8'))
        return response

aliddns = Aliddns()


def updateV6(local_v6_domains):
    if not domain_rrkey:
        return False

    # 遍历所有的子域名
    for rrKey in domain_rrkey: 
        ddns_v6_address = aliddns.RequestDomainIP(rrKey, domain_type['ipv6'])

        # 有地址解析的情况
        if len(ddns_v6_address) > 0: 
            for index,v6 in enumerate(ddns_v6_address):
                # 已解析的地址过期的情况
                if v6['Value'] not in local_v6_domains:
                    # 获取不在ipv6地址的RecordID
                    recordId = v6['RecordId']
                    # 删除该记录
                    response = aliddns.DeleteDNS(recordId)
                    if recordId == response['RecordId']:
                        print("成功删除子域名:{}.{} 的过期v6地址{}".format(v6['RR'],v6['DomainName'],v6['Value']))
                        del(ddns_v6_address[index])
                    else:
                        print("失败删除子域名:{}.{} 的过期v6地址{}".format(v6['RR'],v6['DomainName'],v6['Value']))
        # 解析地址不存在或条数小于本地v6地址数
        if not ddns_v6_address or len(ddns_v6_address) < len(local_v6_domains): 
            ddns_list = map(lambda x: x['Value'], ddns_v6_address)
            for local_v6 in local_v6_domains:
                if (local_v6 in ddns_list):
                    continue
                aliddns.AddDNS(rrKey, domain_type['ipv6'], local_v6.strip(), domain_ttl)

def updateV4(local_v4_domain):

    for rrKey in domain_rrkey:
        ddns_v4_address = aliddns.RequestDomainIP(rrKey, domain_type['ipv4'])
        if len(ddns_v4_address) < 1:
            # 该子域名不存在v4地址
            aliddns.AddDNS(rrKey, domain_type['ipv4'], local_v4_domain, domain_ttl)
            continue

        if ddns_v4_address[0]['Value'] != local_v4_domain:
            # 本地外网地址与域名DNS解析地址不匹配
            aliddns.UpdateDNS(domain_type['ipv4'], rrKey, ddns_v4_address[0]['RecordId'], local_v4_domain)

def main():
    # ipv6 处理
    local_v6_domains = getip.ipv6()
    if local_v6_domains:  # local has ipv6 adrees
        updateV6(local_v6_domains)

    # ipv4 处理
    local_v4_domain = getip.ipv4()
    if local_v4_domain:
        updateV4(local_v4_domain)

if __name__ == "__main__":
    main()

其次是配置文件 config.py

# Aliddns config
domain_rrkey = ['demo1', 'demo2']
domain_name = "demo.com"
# 同时支持ipv4 和 ipv6
domain_type = { 'ipv4': 'A', 'ipv6': 'AAAA'}
domain_ttl = "600"
recv_format = 'json'

# 具体怎么申请,我忘了,不过阿里云官方文档有
access_key_id = "blablabla"
access_key_secret = "blablabla"

aliddns_api = "alidns.aliyuncs.com"

最后是获取需要解析的ip地址文件 getip.py

import sys
import urllib.request
import subprocess
import socket
import re
import requests 

# v6 地址一般都会在本地,所以直接从本地获取
def ipv6():
	if (sys.platform == "linux"):
		cmd="ifconfig"
	elif (sys.platform == "win32"):
		cmd = "ipconfig"
	else:
		return False

	child=subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE)
	out=child.communicate();#保存ipconfig中的所有信息
	 
	ipv6_pattern='(([a-f0-9]{1,4}:){7}[a-f0-9]{1,4})'
	address=re.findall(ipv6_pattern,str(out))
	return list(map(lambda x: x[0], address))

def ipv4():
    # this network ipv4 address
    try:
        opener = requests.get('http://getip.com/get_ip')
        # 显然这个借口你需要自己配置,不过我可以给你一段nginx配置
    except:
        return False
    strg = opener.text
    return strg.strip()

0x03 nginx获取IP的API配置

我server{
  listen 8080;
  server_name demo.com;
  
  location /get_ip {
    default_type text/plain;
    return 200 "$remote_addrn";
  }

}

0x04 设置systemd管理

不同的操作系统,systemd的目录有细微的差别,我是放在/lib/systemd/system/目录下的,因为我用户目录下没有systemd这个文件夹

Aliddns.service

[Unit]
Description=Aliyun DDNS Client.
Wants=network-online.target
After=network.target network-online.target

[Service]
Type=simple
WorkingDirectory=/path/Aliddns
ExecStart=python3 /path/Aliddns/ddns.py

然后通过 Aliddns.timer 来定时启动Aliddns.service,我设置的10分钟启动一次

Aliddns.timer

[Unit]
Description=Run Aliyun DDNS Client every 10 minutes.

[Timer]
OnBootSec=0s
OnUnitActiveSec=10min
Unit=Aliddns.service

[Install]
WantedBy=multi-user.target

最后将Aliddns.service 、Aliddns.timer 拷到systemd的文件夹下面

sudo systemctl reload
sudo systemctl start Aliddns
sudo systemctl start Aliddns.timer
sudo systemctl enable Aliddns.timer

0x05 源代码下载地址

链接:http://tank.zklighting.ltd:8888/share/detail/3df2b713-5ab2-40e3-4dcd-4ea6a52616e3 提取码:9kcr

暂无评论

发表评论

您的电子邮件地址不会被公开,必填项已用*标注。

相关推荐