之前在腾讯云注册了域名,最近想让自己的一台主机(有公网IP,但不固定)也能通过域名访问。于是就想腾讯云有没有相关接口来实现域名解析记录的修改更新操作,这样的话,一旦本地主机的IP地址发生了变化,就可以了通过它自动完成记录的修改。结果确实有的,文档参见:https://cloud.tencent.com/document/api/302/4032。
但是这套API的使用却很复杂,估计这也就是为什么腾讯云现在搞了一套API 3.0
的东西。看了下,3.0版本的API直接提供了相关SDK,相对来说就很好使用了。但是!API 3.0
没有域名解析相关的API!所以还得用2.0。
1. 签名鉴权
API调用方面,其他部分倒也不是什么问题,关键在于请求参数中Signature
参数的计算。该参数用来验证调用者的身份合法性,但签名的过程却比较复杂,经常会出错。网上的教程包括官方文档都是从怎么生成这个签名的角度进行讲解,看了半天也是知其然不知其所以然。这里反向地看待这个问题,看看调用请求被腾讯云服务器接收后,它会怎么进行验证。
假设腾讯云收到了我们发出了一个请求:
https://cns.api.qcloud.com/v2/index.php?Bar=1111&Foo=222&Signature=xxxxxx&SignatureMethod=HmacSHA256
首先作为服务器,他可以知道请求的方式(GET/POST)
然后它先会把Signature的值(xxxxxx)记录下来
最后对除了Signature外的所有请求参数(key=value),按key的字典顺序进行排序
可以生成一个如下格式(忽略空格)的字符串(称为签名原文字符串):
请求方式 请求地址 ? 参数1=值1 & 参数2=值2 ……
如上述示例中为:
GETcns.api.qcloud.com/v2/index.php?Bar=1111&Foo=222&SignatureMethod=HmacSHA256
注意以下几点:
- 严格区分大小写
- 不能有任何其他无关符号
- 参数必须按照字典序排序
Signature
参数不在其中- 请求地址不包括协议(https://)
然后,腾讯服务器会将上述字符串进行加密,加密方式(HmacSHA256/HmacSHA1)由请求参数中的SignatureMethod
指定,加密使用的密钥为请求者的SecretKey
,然后对加密后的数据进行base64
编码。到此服务器可以得到一个签名,将这个签名与请求参数中的Signature
比较,如果一致,认证通过。
因为HmacSHA加密的不可逆性,不难知道为什么在生成上述签名原文字符串时为什么必须严格遵守那些约定,因为任何一个字节的错误都会导致加密所得结果完全不同。
2. 代码实现
2.1. API请求
假设已经申请了如下的API密钥:
SecretId: AKIDz8krbsJ5yKBZQpn74WFkmLPx3gnPhESA
SecreKey: Gu5t9xGARNpq86cd98joQYCN3Cozk1qA
import base64 |
参数:
- action根据腾讯云文档确定
- 对于域名解析相关API操作,region不用填写(毕竟又不像云主机在某个地区的机房)
- dict_arg已字典的形式传入接口请求参数(不需要公共请求参数)
- kw_arg作用与dict_arg等价,但是可以关键字参数的形式指定
返回:API返回数据中的data
字段
异常:当API返回的code不为0(调用失败)时
2.2. 获取本机IP
Python标准库没有直接的实现,不过可以利用Socket建立一个外部连接,间接获取本机的IP地址。
至于外部连接的目标可以任意,比如可以使用谷歌的DNS服务器:
import socket |
2.3. 修改记录值
假设你在腾讯云拥有域名yourdomain.com,然后已经添加了DNS解析记录home(记录值随便填,待会儿修改)。
# 获取原记录值列表 |
通过运行这段代码,home.yourdomain.com将被定向到代码中my_ip指定的地址,完成记录值修改操作。
最后,将上述程序设置成为每隔一定时间自动运行(linux的crontab),就可以实现域名到本地可变IP主机的绑定。