动机
冠状病毒蔓延,为了响应国家号召在家宅,不能出去,又不能去办公室,找点事做没有那么枯燥;公司的开发环境及演示环境一直是在内网,疫情期间客户演示就有点不方便了,问题还不止这一点如兄弟们需要在家里开发等都很不方便;之前也做过一个方案就是搭建VPN也一直在用,但客户那边使用我们的VPN太麻烦,因此就做一个客户通过我们的域名访问内网的演示环境,既不需要于客户接触又简单,轻松+愉快岂不乐哉。
当然商业的动态域名解析提供商比较多了,之前也用过效果不太理想放弃了,我们本来就是干这行档的总想自己干的才是最爽的,别喷我,干过程序员的都懂。废话了一大段,说干就干。
思路
- 查询本机的公网IP地址并保存。
- 检查记录最后获取公网IP地址是否变更。
- 登录域名提供商的域名管理系统
- 把变更后的IP重新绑定到域名
我的域名提供商西部数码 以下的处理都是基于次提供商,其他提供商也可按次方法炮制。
前置条件
- 内网服务器一台
- 已经备案的域名一个
-
运营商给你分配的是真实的IP而不是局域网IP
注意了:为了节约IP资源电信运营商默认分配的大局域网IP,打客服电话可以修改
移动、联通都是大局域网IP好像不行。
开发环境
- 安装python(这个简单就不细说了)
- 安装网络请求处理包
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
大功告成!域名解析需要一点时间,等会儿试试你绑定的域名。