拾贝博客

——积累知识,胜于积累金银

Python实现动态域名解析

作者:晨檬 向 | 发表于  2020年2月9日 (2196)

动机

    冠状病毒蔓延,为了响应国家号召在家宅,不能出去,又不能去办公室,找点事做没有那么枯燥;公司的开发环境及演示环境一直是在内网,疫情期间客户演示就有点不方便了,问题还不止这一点如兄弟们需要在家里开发等都很不方便;之前也做过一个方案就是搭建VPN也一直在用,但客户那边使用我们的VPN太麻烦,因此就做一个客户通过我们的域名访问内网的演示环境,既不需要于客户接触又简单,轻松+愉快岂不乐哉。
    当然商业的动态域名解析提供商比较多了,之前也用过效果不太理想放弃了,我们本来就是干这行档的总想自己干的才是最爽的,别喷我,干过程序员的都懂。废话了一大段,说干就干。

思路

  1. 查询本机的公网IP地址并保存。
  2. 检查记录最后获取公网IP地址是否变更。
  3. 登录域名提供商的域名管理系统
  4. 把变更后的IP重新绑定到域名
    我的域名提供商西部数码 以下的处理都是基于次提供商,其他提供商也可按次方法炮制。

前置条件

  1. 内网服务器一台
  2. 已经备案的域名一个
  3. 运营商给你分配的是真实的IP而不是局域网IP
    注意了:

    为了节约IP资源电信运营商默认分配的大局域网IP,打客服电话可以修改
    移动、联通都是大局域网IP好像不行。

开发环境

  1. 安装python(这个简单就不细说了)
  2. 安装网络请求处理包
    pip install requests

代码实现

先上全部代码,后面再分部分说明,新建一个py文件,如:ipbinding.py,内容如下

\#!/usr/bin/python3  
import requests  
from urllib.parse import urljoin, quote  
from requests.packages import urllib3  
urllib3.disable_warnings()  
west = requests.Session()  

def get_out_ip():  
    '''  
    获取外网IP地址  
    '''  
    ip_svrs = ['http://icanhazip.com', 'http://ident.me', 'http://ip.42.pl/raw', 'http://ipecho.net/plain', 'http://tnx.nl/ip']  
    for url in ip_svrs:  
        res = requests.get(url)  
        if res.status_code == 200:  
            return res.text.rstrip()  
    return None  


def ip_changed(new_ip):  
    '''  
    检查IP是否有变更  
    '''  
    try:  
        with open('./outip.txt') as file_obj:  
            old_ip = file_obj.read()  
    except FileNotFoundError:  
        old_ip = ""  

    if new_ip != old_ip:  
        with open('./outip.txt', 'w') as file_obj:  
            file_obj.write(new_ip)  
        return True  
    return False  


def login(user, pwd):  
    '''  
    登录西部数码域名管理系统  
    '''  

    headers = {  
        'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3914.0 Safari/537.36"  
    }  
    # 登录方法一  
    # url = "https://www.west.cn/default.asp"  
    # res = west.get(url, verify=False, headers=headers)  
    # print(res.headers)  
    # data = "act=login&u_name=%s&u_password=%s&caplogin=&adds323sdsdsad=3546234134sadsa233" % (quote(user), quote(pwd))  
    # url = "https://www.west.cn/config/loadbox/loginbox2016.asp?"+data  
    # res = west.get(url, verify=False,)  

    # 登录方法二  
    url = "https://www.west.cn/login.asp"  
    res = west.get(url, verify=False, headers=headers)  
    print("Login Get:", res.status_code)  
    if res.status_code != 200:  
        return False  
    print("Login...")  
    data = {  
        'u_name': user,  
        'u_password': pwd,  
        'adds323sdsdsad': '3546234134sadsa233',  
        'back_path2': '',  
        'm': '',  
        'module': 'enterzone'  
    }  
    # print(data)  
    res = west.post(url, data=data, verify=False)  
    print("Login Result:", res.status_code)  

    if res.status_code != 200:  
        return False  
    return True  


def update_domain(ip):  
    '''  
    更新指定域名解析(指定域名是cid=65304462)  
    '''  
    url = "https://www.west.cn/Manager/domain/load.asp"  
    data = {  
            'act': 'rsalldomod',  
            'did': '10419488',  # 域名ID  
            'cid': '65304462',  # 子域名ID  
            'val': ip,  
            'ttl': '60',  
            'lng': ''  
            }  
    res = west.post(url, data=data, verify=False)  
    print("Update:", res.text)  
    if res.status_code != 200:  
        return False  
    return True  


if __name__ == "__main__":  
    newIp = get_out_ip()  
    if ip_changed(newIp) is True:  
        login("username", "password")  
        update_domain(newIp)  
        print("ip changed!")  
    else:  
        print("ip not changed!")  

1.头部

参考备注

\#!/usr/bin/python3  
import requests  
from urllib.parse import urljoin, quote  
from requests.packages import urllib3  
# 禁止https请求时发出的警告,因为后面的https请求没有验证。  
urllib3.disable_warnings()  
# 建立全局的http会话,让requests帮我们管理会话,否则Cookies得自己处理。  
west = requests.Session()  

2. 公网IP获取

网上又有很多查询公网ip的服务,随便选能成功就行。

def get_out_ip():  
    '''  
    获取外网IP地址  
    '''  
    # 下面得地址测试过,可直接返回公网IP,用多IP防止服务失效  
    ip_svrs = ['http://icanhazip.com', 'http://ident.me', 'http://ip.42.pl/raw', 'http://ipecho.net/plain', 'http://tnx.nl/ip']  
    for url in ip_svrs:  
        res = requests.get(url)  
        if res.status_code == 200:  
            return res.text.rstrip()  
    return None  

3. 判断IP是否存在更新

为了节约IP资源,宽带运营商会动态给你分配新的IP,我们得监测我们的IP有没有变化。

def ip_changed(new_ip):  
    '''  
    检查IP是否有变更  
    '''  
    try:  
        with open('./outip.txt') as file_obj:  
            old_ip = file_obj.read()  
    except FileNotFoundError:  
        old_ip = ""  

    if new_ip != old_ip:  
        with open('./outip.txt', 'w') as file_obj:  
            file_obj.write(new_ip)  
        return True  
    return False  

4.登录域名运营商

我的是西部数码,在浏览器中输入官网的登录页,在浏览器的开发模式获取相关参数。下面提供了2种方式都测试过可行。

def login(user, pwd):  
    '''  
    登录西部数码域名管理系统  
    '''  
    # 模拟浏览器  
    headers = {  
        'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3914.0 Safari/537.36"  
    }  
    # 登录方法一  
    # url = "https://www.west.cn/default.asp"  
    # res = west.get(url, verify=False, headers=headers)  
    # print(res.headers)  
    # data = "act=login&u_name=%s&u_password=%s&caplogin=&adds323sdsdsad=3546234134sadsa233" % (quote(user), quote(pwd))  
    # url = "https://www.west.cn/config/loadbox/loginbox2016.asp?"+data  
    # res = west.get(url, verify=False,)  

    # 登录方法二  
    url = "https://www.west.cn/login.asp"  
    res = west.get(url, verify=False, headers=headers)  
    print("Login Get:", res.status_code)  
    if res.status_code != 200:  
        return False  
    print("Login...")  
    data = {  
        'u_name': user,  
        'u_password': pwd,  
        'adds323sdsdsad': '3546234134sadsa233',  
        'back_path2': '',  
        'm': '',  
        'module': 'enterzone'  
    }  
    # print(data)  
    res = west.post(url, data=data, verify=False)  
    print("Login Result:", res.status_code)  

    if res.status_code != 200:  
        return False  
    return True  

5.更新域名

这个地方偷了懒,好点的做法是根据域名更新IP,但我的域名相对比较固定,不会变,所以直接用的域名对应的ID(浏览器的开发模式可以获取);有开发能力的小伙伴可以自行完善。

def update_domain(ip):  
    '''  
    更新指定域名解析(指定域名是cid=65304462)  
    '''  
    url = "https://www.west.cn/Manager/domain/load.asp"  
    data = {  
            'act': 'rsalldomod',  
            'did': '10419488',  # 域名ID  
            'cid': '65304462',  # 子域名ID  
            'val': ip,  
            'ttl': '60',  
            'lng': ''  
            }  
    res = west.post(url, data=data, verify=False)  
    print("Update:", res.text)  
    if res.status_code != 200:  
        return False  
    return True  

6.main函数

流程是:获取公网IP-检查IP是否变更-如果变更登录域名服务商并更新

if __name__ == "__main__":  
    newIp = get_out_ip()  
    if ip_changed(newIp) is True:  
        login("username", "password")  
        update_domain(newIp)  
        print("ip changed!")  
    else:  
        print("ip not changed!")  

自动跑起来

windows

python3 ipbinding.py

linux(我的是CentOS7)
把编好的程序放到你喜欢的目录。
然后建立Cron自动任务,每隔10分钟检查IP变更 ,编辑Cron任务 vim /etc/cron.d/ipbinding
内容:

*/1 * * * * root /usr/bin/python3 /home/root/ipbinding.py>>/home/root/bind.txt

重启cron

systemctl restart crond

大功告成!域名解析需要一点时间,等会儿试试你绑定的域名。


 

分类:技术分享

标签: Python 动态域名 网络

分享:

 我来说两句

评论列表

相关文章