自动检测更新域名绑定技术

一、背景介绍

当前网络处于校内网环境,登录外网需要学生账号,中间有小米路由。不同时间登录可能会出现ip地址更换。(当前路由下有两台电脑和一台nano)

要实现的目标:将个人路由下的设备用二级域名绑定,实现校内网远程使用域名访问路由下的设备。

需要的原料:域名,pycharm,联网主机。(当前使用腾讯云为案例)

二、操作流程

1)域名管理平台设置 (SecretId 和SecretKey)用来登录腾讯云账号

2)生成API密钥

3)进入API文档,进行构建代码更新DNS函数,其中要使用到,更新动态DNS记录,获取域名解析记录。

 这里是先添加了一条DNS记录,您也可以使用API进行添加。这里可自行研究。

在我的域名DNS解析中添加:

 4)模拟发送请求,获取RecordID

 填好域名和二级域名后代码生成后直接调试,弹出控制台,等待加载完毕回车执行py脚本。得到当前DNS记录的RecordID。新建记事本保存好生成的函数。

5)获取更新DNS记录的API函数

 可以使用界面方式就行调用。可以看见调用修改DNS

 

三、本地脚本构建

主要思想:①检测校园网登录状态,②登录校园网,③ 调用更新DNSAPI函数。

封装日志模块

# -*- coding: utf-8 -*
import sys
import os
import time
import logging
def get_loger():
    curPath = os.path.abspath(os.path.dirname(__file__))
    logger = logging.getLogger()
    logger.setLevel(logging.NOTSET)  # Log等级总开关
    # 创建一个handler,用于写入日志文件
    rq = time.strftime('%Y%m', time.localtime(time.time()))
    log_path = os.path.join(curPath,'Logs')
    os.makedirs(log_path,exist_ok=True)
    log_name = os.path.join(log_path , rq + '.log')
    logfile = log_name
    fh = logging.FileHandler(logfile, mode='a',encoding="utf-8")
    fh.setLevel(logging.INFO)  # 输出到file的log等级的开关
    # 定义handler的输出格式
    formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    fh.setFormatter(formatter)
    rf_handler = logging.StreamHandler(sys.stderr)
    rf_handler.setLevel(logging.INFO)
    rf_handler.setFormatter(formatter)
    logger.addHandler(fh)
    logger.addHandler(rf_handler)
    # 使用logger.XX来记录错误,这里的"error"可以根据所需要的级别进行修改
    return logger

if __name__ == '__main__':
    logger=get_loger()
    logger.info("logger init")

封装检测和登录模块

# Author: Kequanchen
# Date : 2022年3月8日08:58:42
# Des : 主要用来自动检测当前主机ip并绑定在自身域名上

# -*- coding:utf-8 -*
import os
import sys
sys.path.append(os.path.dirname(__file__))
import requests
import socket
import Logger
logger = Logger.get_loger()

#校园网账号
account = ""
password = ""


headers = {
        'Proxy-Connection': 'keep-alive',
        'Cache-Control': 'max-age=0',
        'Upgrade-Insecure-Requests': '1',
        'Origin': 'http://202.117.144.205:8602',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Referer': 'http://202.117.144.205:8602/snnuportal/login.jsp',
        'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8',
    }

def login_snnu():
    if not account or not password:
        logger.error("请在auto_login.py文件指定位置补充学号和密码")
        return False
    data = {
                'account': account,
                'password': password,
                'method': 'getUserInfo'
            }

    response = requests.post('http://202.117.144.205:8601/snnuportal/bind', headers=headers, data=data,
                             verify=False)
    data = {
        'sourceurl': 'null',
        'account': account,
        'password': password,
        'yys': '',
        'issave': ''
    }
    response=requests.post('http://202.117.144.205:8601/snnuportal/login', headers=headers, data=data,
                  verify=False)
    if response.text.find("登录失败")>=0:
        logger.error("账号或密码错误")
        return False

    elif response.text.find("当前登录账号")>=0:
        logger.error("登陆成功")
        return True
    logger.error("网络连接错误")
    return False
def islogin():
    def socketTest(url):
        socket.setdefaulttimeout(5)
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        try:
            resp=s.connect(("www.baidu.com",80))
            request_url = 'GET /s?wd=1 HTTP/1.0\r\nHost: {}\r\n\r\n'.format(url)
            s.send(request_url.encode())
            resp=s.recv(256)
            s.close()
            if resp.decode("utf8").find("10.196.0.242")>=0:#此ip为学校snnu服务器内网ip,若失效需更新
                return False
            return True
        except:
            s.close()
            return False
    urls=["www.baidu.com","www.sogou.com","www.weibo.com"]
    for url in urls:
        if socketTest(url):
            return True
    return False

if __name__ == '__main__':
    try:
        if not islogin():
            login_snnu()
    except:
        logger.error("发生错误", exc_info=True)

# -*- coding: utf-8 -*
import os
import sys
sys.path.append(os.path.dirname(__file__))
import requests
import re
import socket
import json
import pickle
import Logger
logger = Logger.get_loger()
###########在此补充用户名和密码###############################
account = "校园网账号"
password = "校园网密码"
##########################################################
accessKeyId = "密钥ID"
accessSecret = "密钥"
#########################################################
headers = {
        'Proxy-Connection': 'keep-alive',
        'Cache-Control': 'max-age=0',
        'Upgrade-Insecure-Requests': '1',
        'Origin': 'http://202.117.144.205:8602',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Referer': 'http://202.117.144.205:8602/snnuportal/login.jsp',
        'Accept-Language': 'zh-CN,zh;q=0.9,zh-TW;q=0.8',
    }
def login_snnu():
    if not account or not password:
        logger.error("请在auto_login.py文件指定位置补充学号和密码")
        return False
    data = {
                'account': account,
                'password': password,
                'method': 'getUserInfo'
            }

    response = requests.post('http://202.117.144.205:8601/snnuportal/bind', headers=headers, data=data,
                             verify=False)
    data = {
        'sourceurl': 'null',
        'account': account,
        'password': password,
        'yys': '',
        'issave': ''
    }
    response=requests.post('http://202.117.144.205:8601/snnuportal/login', headers=headers, data=data,
                  verify=False)
    if response.text.find("登录失败")>=0:
        logger.error("账号或密码错误")
        return False

    elif response.text.find("当前登录账号")>=0:
        logger.info("登陆成功")
        return True
    logger.error("网络连接错误")
    return False
def get_ip():
    try:
        response = requests.get('http://202.117.144.205:8601/snnuportal/login', headers=headers).text
        Pattern=re.compile("当前IP[::](.*?)[^0123456789.]")
        ip=Pattern.search(response).group(1)
        return ip
    except:
        return None
def islogin():
    def socketTest(url):
        socket.setdefaulttimeout(5)
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        try:
            resp=s.connect(("www.baidu.com",80))
            request_url = 'GET /s?wd=1 HTTP/1.0\r\nHost: {}\r\n\r\n'.format(url)
            s.send(request_url.encode())
            resp=s.recv(256)
            s.close()
            if resp.decode("utf8").find("10.196.0.242")>=0:#此ip为学校snnu服务器内网ip,若失效需更新
                return False
            return True
        except:
            s.close()
            return False
    urls=["www.baidu.com","www.sogou.com","www.weibo.com"]
    for url in urls:
        if socketTest(url):
            return True
    return False

#腾讯云获取RecordID
import json
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.dnspod.v20210323 import dnspod_client, models

def getRecordID(accessKeyId,accessSecret ):
    recordId = ''
    try:
        cred = credential.Credential(accessKeyId, accessSecret)
        httpProfile = HttpProfile()
        httpProfile.endpoint = "dnspod.tencentcloudapi.com"

        clientProfile = ClientProfile()
        clientProfile.httpProfile = httpProfile
        client = dnspod_client.DnspodClient(cred, "", clientProfile)

        req = models.DescribeRecordListRequest()
        params = {
            "Domain": "chenkequan.cn",
            "Subdomain": "nano"
        }
        req.from_json_string(json.dumps(params))

        resp = client.DescribeRecordList(req)
        recordId = resp.RecordList[0].RecordId
        print(resp.to_json_string())

    except TencentCloudSDKException as err:
        print(err)
    return recordId

def  updateDNS(accessKeyId,accessSecret,IP ):
    try:
        cred = credential.Credential(accessKeyId,accessSecret )
        httpProfile = HttpProfile()
        httpProfile.endpoint = "dnspod.tencentcloudapi.com"

        clientProfile = ClientProfile()
        clientProfile.httpProfile = httpProfile
        client = dnspod_client.DnspodClient(cred, "", clientProfile)

        req = models.ModifyDynamicDNSRequest()
        recordId = getRecordID(accessKeyId,accessSecret)
        params = {
            "Domain": "chenkequan.cn",
            "SubDomain": "nano",
            "RecordId": recordId,
            "RecordLine": "默认",
            "Value": IP
        }
        req.from_json_string(json.dumps(params))

        resp = client.ModifyDynamicDNS(req)
        print(resp.to_json_string())

    except TencentCloudSDKException as err:
        print(err)

def get_lastIP():
    if not os.path.exists("./last_ip.pt"):
        return "0.0.0.0"
    with open("./last_ip.pt","rb") as f:
        last_ip=pickle.load(f)
        return last_ip

def update_lastIp(current_ip):
    with open("./last_ip.pt","wb") as f:
        pickle.dump(current_ip,f)
        logger.info("更新LastIP:"+current_ip)


if __name__ == '__main__':
    try:
        logger.info("任务启动")
        login_flag=False
        if not islogin():
            login_flag=login_snnu()
        current_ip=get_ip()
        last_ip=get_lastIP()
        #测试
        # current_ip= '6.6.6.6'
        # last_ip = '6.6.6.5'
        # login_flag = True
        if current_ip!=last_ip and login_flag:
            updateDNS(accessKeyId,accessSecret,current_ip)
            logger.info("update chenkequan.cn:"+current_ip)
    except:
        logger.error("发生错误", exc_info=True)

使用测试数据,执行完毕后登录校园网查看DNS 是否更改为6.6.6.6

剩下工作就是运行在nano上

7) Jetson Nano (aarch64)搭建miniconda  (查看博客另一篇文章)

Jetson Nano (aarch64)搭建miniconda 和mmdetection环境_梦想是要有的,万一实现了呢!-CSDN博客一、安装minicondawget -c https://repo.anaconda.com/archive/Anaconda3-2021.05-Linux-aarch64.shbash Anaconda3-2021.05-Linux-aarch64.sh除了init选择no 其余确认全部选择yes编辑环境变量: vi ~/.bashrc#conda env export PATH="/home/chan/anaconda3/bin:"$PATH刷新bash文件:source ~https://blog.csdn.net/ckq707718837/article/details/123346043假设安装好环境后,当然如果不是aarch64位Linux系统就更好安装了。

创建一个执行脚本的python环境

conda create -n pureScript python=3.7 -y

激活环境,安装自动修改DNS的依赖

pip install requests
pip install tencentcloud_sdk_python

执行脚本

 基本上大功告成,最后一步,进行定时执行或者循环执行。

这里采用定时任务,详细知识查看

Crontab命令设置定时任务_梦想是要有的,万一实现了呢!-CSDN博客标准输出和错误输出command 1 > fielname 把把标准输出重定向到一个文件中command > filename 2>&1 把把标准输出和标准错误一起重定向到一个文件中常用命令ctrl-c: ( kill foreground process ) 发送 SIGINT 信号给前台进程组中的所有进程,强制终止程序的执行;ctrl-z: ( suspend foreground process ) 发送 SIGTSTP 信号给前台进程组中的所有进程,常..https://blog.csdn.net/ckq707718837/article/details/123361368主要工作:创建 autosnnu.cron文件

*/1 * * * * /home/chan/miniforge3/envs/pureScript/bin/python /home/chan/Project/scriptPro/autoSnnuForTencent/auto_snnu.py >>/home/chan/Project/scriptPro/autoSnnuForTencent/1.log 2>&1

 表示每分钟执行一次,并将日志输出到指定文件1.log中

这里直接使用环境中的python,也可以切换用户,激活环境的方式。不过编程不就是为了减少工作量吗,同样效果,哪种方便用哪种。这里还可以脚本中套脚本实现更详细的日志和效果。

总结:这篇文章主要介绍使用DNS API接口绑订内网IP,在局域网中实现远程连接或ssh。校内局域网中同样有效果。还差一步,将设备端口在路由上做下端口映射即可。

当前使用的是小米路由:

连接成功,而且校园内使用远程桌面再也不用担心向日葵限速啦

 

 喜欢这篇文章记得鼓励下作者~~~ 继续给大家更有价值的教程

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑾怀轩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值