前几天刚换了电信宽带,终于有了公网IP,摆脱了移动的大内网,打通家里网络的方案又多几种选择。以前用过花生壳之类的免费DDNS,是挺方便的,但得用服务商的二级域名,没自己的域名用起来自由。家里的路由用的pfSense有DDNS服务,但不支持腾讯云。想着pfSense是开源的,之前申请Let’s encrypt泛域名证书的时候又调试过腾讯云的API了,改造改造难度应该不大,虽然没研究过pfSense的代码,但还是有信心约估个半天可以完成的。于是乎开工:读代码、定位功能模块还算顺利,但调试还是掉坑了,为了把php的调试日志调出来昨晚研究到近2点,最后不得不放弃。今天早上单独调试好模块后,再三确认嵌入的代码,运行后还好能正常工作了,哪天有空再回头研究调试的事情吧。
1.准备
1)工作流程分析
配置DDNS服务->pfSense监测WANIP变化->调用API修改”A”记录->最后通过域名解析服务器获取最新IP
2)需要改造内容
- 前台的编辑页面:增加腾讯云类型的选项、显示相关的输入选项
- 后台的处理逻辑:增加腾讯云类型的处理分支、相关的更新记录方法
3)复用之前的腾讯云云解析接口
2.过程
2.1. 前端页面
- 修改/usr/local/www/services_dyndns_edit.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21# 增加qcloud类型客户端的需要显示的选项
function setVisible(service) {
switch (service) {
# ……省略……
case "qcloud":
hideGroupInput('domainname', false); # 域名
hideInput('resultmatch', true);
hideInput('updateurl', true);
hideInput('requestif', true);
hideCheckbox('curl_ipresolve_v4', true);
hideCheckbox('curl_ssl_verifypeer', true);
hideInput('host', false); # 主机名
hideInput('mx', false); # mx值
hideCheckbox('wildcard', true);
hideCheckbox('proxied', true);
hideInput('zoneid', true);
hideInput('ttl', false); # ttl值
break;
# ……省略……
}
}Tips
该功能函数作用是根据不同类型的客户端,在页面显示不同的配置选项。另外用户名、密码选项默认显示,不需要设置。
2.2. 后端处理
修改/etc/inc/services.inc
1
2
3
4
5# DYNDNS_PROVIDER_VALUES、DYNDNS_PROVIDER_DESCRIPTIONS两个字符串常量的定义中,加入qcloud。注意要加入分隔符,并且保证位置序号一致。
# ……省略……
define('DYNDNS_PROVIDER_VALUES', 'all-inkl azure azurev6 citynetwork cloudflare cloudflare-v6 cloudns custom custom-v6 digitalocean dnsexit dnsimple dnsmadeeasy dnsomatic dreamhost dreamhost-v6 duiadns duiadns-v6 dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns freedns-v6 glesys godaddy godaddy-v6 googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker hover loopia namecheap noip noip-free ods opendns ovh-dynhost qcloud route53 route53-v6 selfhost spdyn spdyn-v6 zoneedit');
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'All-Inkl.com,Azure DNS,Azure DNS (v6),City Network,Cloudflare,Cloudflare (v6),ClouDNS,Custom,Custom (v6),DigitalOcean,DNSexit,DNSimple,DNS Made Easy,DNS-O-Matic,DreamHost,Dreamhost (v6),DuiaDns.net,DuiaDns.net (v6),DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,freeDNS (v6),GleSYS,GoDaddy,GoDaddy (v6),Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Hover,Loopia,Namecheap,No-IP,No-IP (free),ODS.org,OpenDNS,OVH DynHOST,qcloud,Route 53,Route 53 (v6),SelfHost,SPDYN,SPDYN (v6),ZoneEdit');
# ……省略……Tips
services_dyndns_edit.php页面的根据这两个常量生成的类型列表。
修改/etc/inc/dyndns.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21# 第一个switch ($this->_dnsService),在'azurev6'分支前加入'qcloud'分支
function updatedns{
# ……省略……
switch ($this->_dnsService){
# ……省略……
case 'qcloud': # 增加这个即可,会执行$this->_update();
case 'azurev6':
$this->_update();
if ($this->_dnsDummyUpdateDone == true) {
// If a dummy update was needed, then sleep a while and do the update again to put the proper address back.
// Some providers (e.g. No-IP free accounts) need to have at least 1 address change every month.
// If the address has not changed recently, or the user did "Force Update", then the code does
// a dummy address change for providers like this.
sleep(10);
$this->_update();
}
break;
# ……省略……
}
# ……省略……
}Tips
该处判断服务并出发更新操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43# 第二个switch ($this->_dnsService),加入'qcloud'分支,位置在'default'之前即可。
function _update() {
# ……省略……
switch ($this->_dnsService){
# ……省略……
case 'qcloud':
/* tencent cloud dyndns */
$secretId = $this->_dnsUser; #
$secretKey = $this->_dnsPass; #
$domain = $this->_dnsDomain; #
$subDomain = $this->_dnsHost; #
$recordType = 'A';
$ip = $this->_dnsIP;
$ttl = $this->_dnsTTL;
$mx = $this->_dnsMX;
$obj = new QcloudDns($secretId, $secretKey);
$data = $obj->ListRecords($domain);
$is_newRecord = true;
if($data["code"] == 0){
$data = $data["data"]["records"];
if (is_array($data)) {
foreach ($data as $v) {
if ($v["name"] == $subDomain) {
$recordId = $v["id"];
$result = $obj->UpdateRecord($domain, $recordId, $subDomain, $recordType, $recordLine = '默认', $ip, $ttl = 600, $mx = 0);
$is_newRecord = false;
}
}
if($is_newRecord){
$result = $obj->CreateRecord($domain, $subDomain, $recordType, $recordLine = '默认', $ip, $ttl = 600, $mx = 0);
}
$this->_checkStatus(0, $result, null);
}
}else{
$this->_checkStatus(0, $data,null);
}
break;
default:
break;
}
# ……省略……
}
# ……省略……Tips
该处实现获取腾讯云API配置信息、更新IP操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 第三个switch ($this->_dnsService),加入'qcloud'分支,位置在'default'之前即可。
function _checkStatus($ch, $data, $header) {
# ……省略……
switch ($this->_dnsService){
# ……省略……
case 'qcloud':
$data = json_encode($data);
if (preg_match("/Success/i", $data)) {
$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
$successful_update = true;
} else {
$status = $status_intro . "(" . gettext("Unknown Response") . ")";
log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
$this->_debug($data);
}
break;
# ……省略……
}
# ……省略……
}Tips
该处根据腾讯云返回的信息判断是否更新成功并输出日志。为了简单点,这里不对错误原因一一分析。
1
2
3
4
5
6# 将所有的if($this->_dnsService != 'ods')判断语句,加入'qcloud'类型
# ……省略……
if (!in_array($this->_dnsService, array('ods','qcloud'))){
# ……省略……
}
# ……省略……Tips
原来代码'ods'类型的服务使用特殊的处理流程,跳过通用的curl构造处理流程。新加的'qcloud'直接使用QcloudDns类方法,也不需要用到原来的curl处理流程,所以也加进忽略列表。
1
2
3
4# 最后加入QcloudDns类定义代码
class QcloudDns {
# ……省略……
}补充
也可以做个文件引用。
3.小结
- php的配置文件php.ini由/etc/rc.php_ini_setup脚本生成,每次重启会覆盖。
- sshd的配置文件sshd_config由/etc/sshd脚本生成,每次重启会覆盖;secureCRT7版本不支持默认的钥匙交换协议,可以在配置文件增加旧方法,简单点就升级secureCRT版本。