搭建一个自己的DDNS服务器

DDNS,解决ADSL拨号,内网服务器无法提供稳定的互联网ip问题

前置条件

1 拥有公网地址,查看路由器wan口地址是否是公网地址

2 在godaddy上注册一个自己的域名

申请godaddy的api-key

https://developer.godaddy.com/keys

复制保存自己的密钥

godaddy API文档

https://developer.godaddy.com/doc/endpoint/domains

格式如下,这里的URL需要替换成你自己的域名

curl -X 'PUT' \
  'https://api.godaddy.com/v1/domains/darkghost.life/records/A/二级域名' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: sso-key key:secret' \
  -d '[
  {
    "data": "1.1.1.1",
    "port": 65535,
    "priority": 0,
    "protocol": "string",
    "service": "string",
    "ttl": 600,
    "weight": 0
  }
]'

使用python来改写下代码,设计思路如下

服务端使用一台拥有固定ip的主机做socket侦听客户机发送的数据和调用godaddy的api添加域名解析

客户端定期连接服务器的socket,发送要添加解析的域名

服务端验证客户端合法性和socket的源ip是否发生变动,变动后调用API更新解析记录

如果没有固定ip的服务器,也可以使用myip.ipip.net接口来检测公网ip是否发生变化,变动后客户端调用godaddy 的api更改域名解析记录

server端代码

#!/usr/bin env python
#-*-coding:utf-8-*-
import requests,socket,logging,os,sys,json
def logger():
    log_name = base_dir+'/ddns.log'
    logger = logging.getLogger()
    fh = logging.FileHandler(log_name)
    formater = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    fh.setFormatter(formater)
    logger.setLevel(logging.WARNING)
    logger.addHandler(fh)
    return logger
def sock():
    host = '0.0.0.0'
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    address = ('address',port)
    s.bind(address)
    s.listen(200)
    while True:
        try:
            conn,addr = s.accept()
            client_data = conn.recv(1024)
            data = json.loads(client_data.decode('utf-8'))
            key,domain = data['key'],data['domain']
            print(key,domain)
        except Exception as e:
            log.warning(e)
            continue
        finally:
            conn.close()
        if key=='验证客户端合法性自定义key':
            newhost,port = addr
            if newhost != host:
                host = newhost
                ddns(host,domain)
        else:
            pass
def ddns(host,domain):
    try:
        url = 'https://api.godaddy.com/v1/domains/darkghost.life/records/A/{}'.format(domain)
        headers = {
            'accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'sso-key yourkey:yoursecret'
        }
        data = [
            {
                "data": host,
                "port": 65535,
                "priority": 0,
                "ttl": 600,
                "weight": 0
            }
        ]
        response = requests.put(url, json=data, headers=headers)
        log.warning(response)
    except Exception as e:
        log.warning(str(e))

if __name__ == '__main__':
    base_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
    log = logger()
    sock()

客户端代码

#!/usr/bin env python
#-*-coding:utf-8-*-
import socket,time,logging,os,sys
def logger():
    log_name = base_dir+'/ddns.log'
    logger = logging.getLogger()
    fh = logging.FileHandler(log_name)
    formater = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    fh.setFormatter(formater)
    logger.setLevel(logging.WARNING)
    logger.addHandler(fh)
    return logger
def client(data):
    while True:
        try:
            s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            s.settimeout(3)
            s.connect(('serveraddress',port))
            s.sendall(data.encode())
        except Exception as e:
            log.warning(str(e))
        time.sleep(10)
if __name__ == '__main__':
    base_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
    data = '{"key":"自定义合法客户端key","domain":"二级域名"}'
    log = logger()
    client(data)

X