建议使用以下浏览器,以获得最佳体验。 IE 9.0+以上版本 Chrome 31+ 谷歌浏览器 Firefox 30+ 火狐浏览器
请选择 进入手机版 | 继续访问电脑版
设置昵称

在此一键设置昵称,即可参与社区互动!

确定
我再想想
选择版块
092713ie8gnff9tx2p8m72.jpg

qshujun

发帖: 5粉丝: 1

级别 : 注册会员

发消息 + 关注

发表于2017-11-25 15:27:16 27222 35
直达本楼层的链接
楼主
显示全部楼层
[云解析] 利用云解析API将域名动态解析到家庭路由器上

一、背景     前些年各种免费网盘如雨后春笋、铺天盖地,年轻的小伙伴纷纷将珍藏多年的学(稀)习(缺)材(资)料(源)拿出来上云,可是好景不长,各大网盘纷纷关闭,某度也对教育视屏痛下杀手。老师们飘逸的身姿、优雅的背影随着时间一点一点在小伙伴的记忆中慢慢褪去,消香玉损。     作为掌握先进科学知识的互联网从(屌)业(丝)者,自然要发扬“艰苦创业,自力更生”的革命精神,在家里打造属于自己的私有网盘。当然我们不必自己去开发一个完整功能的网盘,目前已经有好几个十分成熟的私有网盘项目,比如资格较老的OwnCloud,由上述原班人马打造的NextCloud,功能和插件都非常丰富的FileRun。你可以让它们运行在家里的电脑上、树莓派上、甚至是路由器上,但是接下来的问题是家庭使用宽带拨号上网的IP总是变化的,总不能每次在家里查好了IP再去访问网盘,所以本文重点是使用python脚本利用华为云解析服务的API实现动态域名解析 二、准备     1、域名一个,建议买一个,通常一年的费用也就60左右,却能给你带来巨大的品牌价值(逼格),当然免费的也有很多,详情Google。     2、在域名注册商将此域名解析到华为权威服务器,参考:http://support.huaweicloud.com/u ... pic_0035467702.html     3、在家里的服务器(PC、树莓派、路由器,有啥都行)上安装python执行环境 三、Code     1、一个对三方库requests封装的类,实现一些简单的HTTP方法请求及响应处理

  1. #!/usr/bin/python
  2. # coding: utf-8
  3. # HttpRequest.py
  4. # author : qshujun
  5. # version : 1.0.0
  6. # date : 2017/11/25
  7. import requests
  8. class HttpRequests():
  9.     ´´´
  10.         对requests库封装的GET、POST、PUT等方法调用类
  11.     ´´´
  12.     def __init__(self, url, data=None, type=´GET´, cookie=None, headers=None):
  13.         self.url = url
  14.         self.data = data
  15.         self.type = type
  16.         self.cookie = cookie
  17.         self.headers = headers
  18.         self.send_request()
  19.     def send_request(self):
  20.         ´´´´´
  21.             setup a request
  22.         ´´´
  23.         if self.url == None or self.url == ´´:
  24.             raise ´The url should not empty!´
  25.         if self.type == ´POST´:
  26.             self.req = requests.post(self.url, data=self.data, headers=self.headers)
  27.         elif self.type == ´GET´:
  28.             if self.data == None:
  29.                 self.req = requests.get(self.url, headers=self.headers)
  30.             else:
  31.                 self.req = requests.get(self.url, params=self.data, headers=self.headers)
  32.         elif self.type == ´PUT´:
  33.             self.req = requests.put(self.url, data=self.data, headers=self.headers)
  34.         else:
  35.             self.req = None
  36.             raise ´The http request type NOT support now!´
  37.     def get_code(self):
  38.         try:
  39.             return self.req.status_code
  40.         except Exception,e:
  41.             raise str(e)
  42.     def get_url(self):
  43.         try:
  44.             return self.req.url
  45.         except Exception,e:
  46.             raise str(e)
  47.     def get_text(self):
  48.         try:
  49.             return self.req.text
  50.         except Exception,e:
  51.             raise str(e)
  52.     def get_headers(self):
  53.         try:
  54.             return self.req.headers
  55.         except Exception,e:
  56.             raise str(e)
  57.     def get_cookie(self):
  58.         headers = self.get_headers()
  59.         if ´set-cookie´ in headers:
  60.             return headers[´set-cookie´]
  61.         else:
  62.             return None
复制代码
  1. #!/usr/bin/python
  2. # coding: utf-8
  3. # hwcloud-ddns.py
  4. # author : qshujun
  5. # version : 1.0.0
  6. # date : 2017/11/25
  7. import json
  8. import socket
  9. from HttpRequest import HttpRequests
  10. ´´´
  11.     定义全局变量
  12. ´´´
  13. #需要解析的域名及主机名
  14. domain = ´shujun.com´
  15. host = ´www´
  16. #认证信息
  17. domainname = ´domainname ´
  18. username = ´username ´
  19. password = ´password ´
  20. regionId = ´cn-north-1´
  21. iam_endpoint = ´https://iam.{regionId}.myhwclouds.com´
  22. get_token_uri = ´/v3/auth/tokens´
  23. #DNS接口信息
  24. nds_endpoint = ´https://dns.myhwclouds.com´
  25. query_zones_uri = ´/v2/zones?type=public&limit=50´
  26. create_zone_uri = ´/v2/zones´
  27. query_recordsets_uri = ´/v2/zones/{zone_id}/recordsets?limit=500´
  28. modify_recordset_uri = ´/v2/zones/{zone_id}/recordsets/{recordset_id}´
  29. create_recordset_uri = ´/v2/zones/{zone_id}/recordsets´
  30. #默认请求头
  31. headers = {´content-type´: ´application/json´}
  32. def get_iam_token():
  33.     ´´´
  34.     以用户名、密码从IAN换取token并加入headers
  35.     :return:
  36.     ´´´
  37.     iam_token_url = iam_endpoint.replace(´{regionId}´, regionId) + get_token_uri
  38.     data = {
  39.         "auth": {
  40.             "identity": {
  41.                 "methods": [
  42.                     "password"
  43.                 ],
  44.                 "password": {
  45.                     "user": {
  46.                         "name": username,
  47.                         "password": password,
  48.                         "domain": {
  49.                             "name": domainname
  50.                         }
  51.                     }
  52.                 }
  53.             },
  54.             "scope": {
  55.                 "project": {
  56.                     "name": regionId
  57.                 }
  58.             }
  59.         }
  60.     }
  61.     req = HttpRequests(iam_token_url, data=json.dumps(data),type=´POST´, headers=headers)
  62.     if ´X-Subject-Token´ in req.get_headers():
  63.         headers[´X-Auth-Token´] = req.get_headers()[´X-Subject-Token´]
  64.     else:
  65.         print ´Get IAM token failed, http code: %s, %s´ % (str(req.get_code()),req.get_text())
  66.         exit(1)
  67. def query_zone():
  68.     ´´´
  69.     查询zone(即domain:shujun.net)的id
  70.     :return:zone_id
  71.     ´´´
  72.     query_zones_url = nds_endpoint + query_zones_uri
  73.     req = HttpRequests(query_zones_url, headers=headers)
  74.     if req.get_code() == 200:
  75.         zones = json.loads(req.get_text())[´zones´]
  76.         for zone in zones:
  77.             if zone[´name´] == domain + ´.´:
  78.                 return zone[´id´]
  79.         return None
  80.     else:
  81.         print ´Query zone list failed, http code: %s, %s´ % (str(req.get_code()),req.get_text())
  82.         exit(1)
  83. def create_zone():
  84.     ´´´
  85.     创建zone(即domain:shujun.net)的,并返回新zone的id
  86.     :return: zone_id
  87.     ´´´
  88.     create_zone_url = nds_endpoint + create_zone_uri
  89.     data = {
  90.         "name": domain + ´.´,
  91.         "description": "This is an example zone.",
  92.         "zone_type": "public",
  93.         "email": "xx@example.org"
  94.     }
  95.     req = HttpRequests(create_zone_url, type=´POST´, data=json.dumps(data), headers=headers)
  96.     if req.get_code() == 202:
  97.         zone = json.loads(req.get_text())
  98.         return zone[´id´]
  99.     else:
  100.         print ´Create zone failed, http code: %s, %s´ % (str(req.get_code()),req.get_text())
  101.         exit(1)
  102. def query_recordset(zone_id):
  103.     ´´´
  104.     查询主机A记录,并返回记录链接及其值
  105.     :param zone_id:
  106.     :return: recordset_url,old_ip
  107.     ´´´
  108.     query_recordset_url = nds_endpoint + query_recordsets_uri.replace(´{zone_id}´,zone_id)
  109.     req = HttpRequests(query_recordset_url, headers=headers)
  110.     if req.get_code() == 200:
  111.         recordsets = json.loads(req.get_text())[´recordsets´]
  112.         for recordset in recordsets:
  113.             if recordset[´name´] == host + ´.´ + domain + ´.´:
  114.                 return recordset[´links´][´self´], recordset[´records´][0]
  115.         return None, None
  116.     else:
  117.         print ´Query recordset list failed, http code: %s, %s´ % (str(req.get_code()),req.get_text())
  118.         exit(1)
  119. def modify_recordset(recordset_url,new_ip):
  120.     ´´´
  121.     修改host.domain对应的A记录为新ip
  122.     :param recordset_url:
  123.     :param new_ip:
  124.     :return:
  125.     ´´´
  126.     data = {
  127.         "description": "This is an example record set.",
  128.         "ttl": 300,
  129.         "records": [new_ip]
  130.     }
  131.     req = HttpRequests(recordset_url, type=´PUT´, data=json.dumps(data), headers=headers)
  132.     if req.get_code() == 202:
  133.         return True
  134.     else:
  135.         print ´Modify recordset failed, http code: %s, %s´ % (str(req.get_code()),req.get_text())
  136. def create_recordset(zone_id,new_ip):
  137.     ´´´
  138.     创建新的主机记录
  139.     :param zone_id:
  140.     :param new_ip:
  141.     :return:
  142.     ´´´
  143.     create_recordset_url = nds_endpoint + create_recordset_uri.replace(´{zone_id}´, zone_id)
  144.     date = {
  145.         "name": host + ´.´ + domain + ´.´,
  146.         "description": "This is an example record set.",
  147.         "type": "A",
  148.         "ttl": 300,
  149.         "records": [new_ip]
  150.     }
  151.     req = HttpRequests(create_recordset_url, type=´POST´, data=json.dumps(date), headers=headers)
  152.     if req.get_code() == 202:
  153.         return True
  154.     else:
  155.         print ´Create recordset failed, http code: %s, %s´ % (str(req.get_code()),req.get_text())
  156.         exit(1)
  157. def get_public_ip():
  158.     ´´´
  159.     查询当前正在连接的公网ip
  160.     :return:
  161.     ´´´
  162.     get_ip_url = ´http://www.3322.org/dyndns/getip´
  163.     try:
  164.         req = HttpRequests(get_ip_url)
  165.         if req.get_code() == 200:
  166.             return req.get_text()
  167.     except Exception:
  168.         pass
  169.     try:
  170.         sock = socket.create_connection((´ns1.dnspod.net´,6666))
  171.         ip = sock.recv(16)
  172.         sock.close()
  173.         return ip
  174.     except Exception:
  175.         pass
  176.     print ´Get Public IP failed, http code: %s, %s´ % (str(req.get_code()),req.get_text())
  177.     exit(1)
  178. if __name__ == ´__main__´:
  179.     new_ip = get_public_ip()
  180.     get_iam_token()
  181.     zone_id = query_zone()
  182.     if zone_id == None:
  183.         zone_id = create_zone()
  184.     recordset_url, old_ip = query_recordset(zone_id)
  185.     if recordset_url == None:
  186.         create_recordset(zone_id,new_ip)
  187.     else:
  188.         if old_ip != new_ip:
  189.             modify_recordset(recordset_url,new_ip)
复制代码
举报
分享

分享文章到朋友圈

分享文章到微博

风吹宝宝PP凉

发帖: 6粉丝: 1

级别 : 注册会员

发消息 + 关注

发表于2017-11-25 15:32:08
直达本楼层的链接
沙发
显示全部楼层

沙发。。。。感觉好高端的样子,回头试下~

点赞1 评论 引用 举报

anna

发帖: 12粉丝: 1

级别 : 新手上路

发消息 + 关注

发表于2017-11-25 15:34:44
直达本楼层的链接
板凳
显示全部楼层

学习了,改天实践下

点赞 评论 引用 举报

qshujun

发帖: 5粉丝: 1

级别 : 注册会员

发消息 + 关注

发表于2017-11-25 15:38:46
直达本楼层的链接
地板
显示全部楼层

还有一些异常场景没有处理,另外考虑到要定时执行的没有加重试,后续再改进,大家多多指正

点赞 评论 引用 举报

yd_16082003

发帖: 6粉丝: 0

级别 : 注册会员

发消息 + 关注

发表于2017-11-25 15:42:29
直达本楼层的链接
5#
显示全部楼层

非常棒···后面把DFX特性考虑进去就更好了··

点赞 评论 引用 举报

kehaar

发帖: 2粉丝: 2

级别 : 新手上路

发消息 + 关注

发表于2017-11-25 15:55:52
直达本楼层的链接
6#
显示全部楼层

厉害,大牛

点赞 评论 引用 举报

追风猎手

发帖: 3粉丝: 0

级别 : 新手上路

发消息 + 关注

发表于2017-11-25 16:02:24
直达本楼层的链接
7#
显示全部楼层

点赞 评论 引用 举报

royal_lzj

发帖: 6粉丝: 0

级别 : 注册会员

发消息 + 关注

发表于2017-11-25 16:19:57
直达本楼层的链接
8#
显示全部楼层

这个使用

点赞 评论 引用 举报

yd_86191895

发帖: 5粉丝: 0

级别 : 注册会员

发消息 + 关注

发表于2017-11-28 09:22:25
直达本楼层的链接
9#
显示全部楼层

好厉害

点赞 评论 引用 举报

行风

发帖: 0粉丝: 0

级别 : 新手上路

发消息 + 关注

发表于2017-11-28 11:17:07
直达本楼层的链接
10#
显示全部楼层

现在运营商太机智,都不给分配公网IP,都是内部IP+nat, 大家要注意下自己拨号的IP是不是公网IP~

点赞 评论 引用 举报

qshujun

发帖: 5粉丝: 1

级别 : 注册会员

发消息 + 关注

发表于2017-11-28 11:38:51
直达本楼层的链接
11#
显示全部楼层

行风 发表于 2017-11-28 11:17 现在运营商太机智,都不给分配公网IP,都是内部IP+nat, 大家要注意下自己拨号的IP是不是公网IP~ ...
是的,以前用电信20M 给的是公网,后来给升了100M,IP变成了100.x.x.x ,直接打10000号投诉,半小时后重新拨号,公网ip拿到了 也有地方运营商是随机给的,可以在路由器上写个脚本判断下,没有分到公网ip就重拨,直到拿到为止
点赞 评论 引用 举报

游客

富文本
Markdown
您需要登录后才可以回帖 登录 | 立即注册