使用he.net的动态域名服务

我的ipv6动态域名(DDNS)服务之前托管在dynv6上。dynv6是一家专注于ipv6 DDNS的网站,它有一个别家不具备的优点:即可以手动配置ipv6地址的后64位。在局域网内,诸如NAS、软路由等,默认情况下,会将自己的Mac地址作为ipv6地址的后64位,而Windows出于安全原因会默认会关闭这项功能。这样一来,局域网内的N台设备,只需要其中1台向dynv6“汇报”ipv6地址,dynv6即可取得前64位前缀,与手动设置的后64位(实际上是设备的Mac地址)拼合成其他设备的ipv6。

原先的方案中,我使用openwrt自动汇报公网ipv6,其余设备均采用这种方式“半指定”ipv6地址,其中Windows设备关闭隐藏硬件地址功能。一开始运行不错,但过了一段时间发现,dynv6似乎对免费用户不太友好,如果一段时间不用,ipv6 DDNS就会失效,需要登陆上去,手动删除并重新添加。

这怎么行?只能更换服务。

一直听说鼎鼎大名的HE(HERRICANE ELECTRIC),之前曾经研究过它家的IPv6 Tunnel Broker,而它也具备ipv4、ipv6的DDNS功能。它上古设计的网站风格让人望而却步,但不妨碍它是业内最老牌的网络服务商之一。

由于它过分“精简”的页面设计,在使用它的DDNS过程中不免有一番探索和折腾。记录一下以备忘。

一、在你的域名托管商处设置NS(NameServer)解析

假设我们的域名是domain.sample.com。在托管域名的DNS解析管理页面,将之前domain.sample.com的DNS解析全部删除,并添加5个NS:ns1.he.net、ns2.he.net……ns5.he.net。

NS(NameServer)解析的意思是,对这个域名具体解析到哪里,你别管了,交给我设置的这些(nsx.he.net)来负责吧。添加5个原因是为了DNS解析的健壮性,确保全球不同地区均可以稳定地解析domain.sample.com的NS设置。注意,5个NS无法写到同一行中,这是由DNS规范确定的。

此外,经测试发现,阿里云的DNS解析,不支持将NS设置为he.net,设置之后始终无效。猜测是因为国内的DNS解析如果使用CNAME,它会首先检测你CNAME的指向域名有没有备案,如果没有备案,直接就不让你使用这条CNAME。而NS设定可能可以绕过这一点,因此当阿里云检测到NS的目标是一个“境外网站”时,它就不生效,急死你。

实测在cloudflare上对域名DNS进行操作就没有这些猫腻。添加之后,可能需要5分钟左右时间令它生效。

二、在dns.he.net上添加域名解析

首先注册dns.he.net。这个页面既包括手动的静态DNS,也包括动态DNS,每个免费用户可以设置50个域名。

第一步,添加域名,点击左侧“Add a new domain”。属于domain.sample.com。它会对这个域名进行一番检查,确保它已经正确设置了NS,除了NS之外的其他设置已经清空。

添加成功后,domain.sample.com就出现在了Active domains for this account表格中。点击域名前面编辑图标(Edit zone),进入Managing zone页面,可以看到,之前添加过的5个NS已经罗列在其中。除此之外,还有一个SOA,它标记了5个NS中具体哪一个是主域名解析器。这些都不用管它。

点击表格顶部的“New AAAA”(添加的是ipv6解析,如果是ipv4则为New A),在弹出的窗口中,Name可以再次输入域名,IPv6 Address留空(因为我们想要的是动态域名),TTL默认,然后勾选最下方的“Enable entry for dynamic dns”,这时候IPv6中可能会自动填上::1,或者上一个设置的ipv6地址,不用在意(因为它会被动态域名机制自动更新)。点击Submit提交。

之后可以看到DNS解析表格的最后一行是刚刚添加的AAAA记录。蓝色的四个AAAA表示这是一个动态域名。注意,后面有一个DDNS列,其中有一个类似“刷新”的图标,它不是刷新!它的功能鼠标移上去可以发现:“Generate a DDNS key.”

这个KEY对于DDNS来说至关重要,DDNS的原理就是任意一台设备,只要能报出域名和对应的KEY,就可以更新域名对应的IP为当前设备的IP。点击这个“Generate a DDNS key”,单击“Generate”,它会生成一个密码(DDNS key),妥善保存它,然后务必记得,再次点击Submit,让这个刚刚生成的key生效。

好了,dns.he.net这边的设置已经完成,下面的问题就是,如何让你的设备们,向dns.he.net报告自己的IP了。

dns.he.net没有像dynv6那样的手动设置Mac地址作为ipv6后缀的功能,所以只好在每台设备上进行客户端设置。

三、Openwrt的DDNS客户端设置

对于Openwrt,相对简单,在任务计划中添加一行即可:

*/5 * * * * curl -6 "https://domain.sample.com:DDNS_KEY@dyn.dns.he.net/nic/update?hostname=domain.sample.com"

四、Windows的DDNS客户端设置

有两个方法,推荐第二种。

1、使用Newfuture同志的DDNS工具(注意,该方法于2024.4发现已经失效)

项目地址:https://github.com/NewFuture/DDNS,在release中下载DDNS.exe和create-task.bat。

将DDNS.exe保存在某个文件夹内,双击运行一下DDNS热热身,它会自动创建一个config.json文件。对该文件的配置方法详见Github项目主页的readme。一个典型的配置如下:

{
  "$schema": "https://ddns.newfuture.cc/schema/v2.8.json",
  "debug": true,
  "dns": "he",
  "id": "YOUR ID or EMAIL for DNS Provider",
  "index4": "default",
  "index6": "public",
  "ipv4": [],
  "ipv6": [
    "domain.sample.com"
  ],
  "proxy": null,
  "token": "DDNS_KEY",
  "ttl": null
}

其中,DNS设置为“he”,表示采用的是dns.he.net的DDNS服务。index6设置为“public”,表示使用公网ipv6地址。本例中ipv4没有设置。ipv6项即为域名,token即为DDNS_KEY。

将create-task.bat与DDNS.exe放在同一个文件夹下,双击它,即可在系统中创建一个任务计划“DDNS”,每隔5分钟执行一次,以不断更新自己的ipv6地址。

2、使用powershell手动配置任务计划

实际上DDNS只需要向一个特定地址报告域名和密码,对于dns.he.net同样如此。这个地址和linux系统里curl的地址是一样的:

https://domain.sample.com:DDNS_KEY@dyn.dns.he.net/nic/update?hostname=domain.sample.com

如果Windows当前处于ipv6环境,那么,直接用浏览器访问上述地址,就可以看到返回结果,如果显示good [ipv6-address]说明DNS已经成功刷新;如果显示nochg [ipv6-address]说明成功握手,但DNS解析没变。

但是仍然有几个问题需要解决。

a)如果Windows当前环境下既有ipv4,又有ipv6,而因为某种原因,ipv6没有设置为优先时,上述网址可能就会返回“noipv4”。这是因为域名设置为AAAA,它只接受ipv6地址,如果本机报告的是ipv4地址,就会失败。

这种情况下,我们可以强行先对dyn.dns.he.net域名进行AAAA解析,将解析结果塞到一个变量中,然后用这个ipv6地址变量来构建后面的地址,这样,浏览器就明确知道“这是一个ipv6地址”,就不会傻乎乎地还用ipv4网络去访问它了。

b)powershell的Invoke-WebRequest方法,并不直接支持基本认证(也就是在URL地址中嵌入用户名、密码),因此,我们还需要手动构造。

c)Windows 10经过更新之后,默认禁止powershell执行任何脚本,因此,需要在powershell的执行参数中加上-ExecutionPolicy Bypass,以在“本次执行中”绕过执行权限限制。

d)我们希望执行的结果可以保存到一个log文件中。

创建一个后缀名为ps1的文本文件,例如dns-update.ps1,假设该文件位于c:\ddns。内容如下:

#首先获得dyn.dns.he.net的ipv6地址
$ipv6Address = (Resolve-DnsName -Name "dyn.dns.he.net" -Type AAAA).IPAddress;
#构造http头部,加入验证信息
$creds = [System.Text.Encoding]::ASCII.GetBytes("DOMAIN:DNS_KEY");
$base64Creds = [System.Convert]::ToBase64String($creds);
$headers = @{ Authorization = "Basic $base64Creds" };
#发起一个完整url请求以完成更新dns动作
try {
$response = Invoke-WebRequest -Uri "http://[$ipv6Address]/nic/update?hostname=DOMAIN" -Headers $headers;
# 记录响应到日志文件
$logPath = "c:\ddns\dns_update.log"
$response.Content | Out-File -Append -FilePath $logPath
} catch {
# 如果发生错误,记录错误信息
"Error: $($_.Exception.Message)" | Out-File -Append -FilePath $logPath
}
# 记录时间戳和状态码
"$(Get-Date) - Status Code: $($response.StatusCode)" | Out-File -Append -FilePath $logPath
#注意,上面的DOMAIN和DNS_KEY换成你自己的

如果在单网卡环境下,只要dyn.dns.he.net可以被正常解析,也可以简化:

$creds = [System.Text.Encoding]::ASCII.GetBytes("DOMAIN:DNS_KEY");
$base64Creds = [System.Convert]::ToBase64String($creds);
$headers = @{ Authorization = "Basic $base64Creds" }; 
try {
$response = Invoke-WebRequest -Uri "https://dyn.dns.he.net/nic/update?hostname=DOMAIN" -Headers $headers;
$logPath = "c:\ddns\dns_update.log"
$response.Content | Out-File -Append -FilePath $logPath
} catch {
"Error: $($_.Exception.Message)" | Out-File -Append -FilePath $logPath
}
"$(Get-Date) - Status Code: $($response.StatusCode)" | Out-File -Append -FilePath $logPath

注意,直接使用域名url时,前面http改成https。

接下来,只需要手动创建一个任务计划,设定5分钟或者10分钟的时间间隔,程序选择powershell.exe(注意它一般在这里:C:\Windows\System32\WindowsPowerShell\v1.0),参数如下(路径修改为实际路径):

-ExecutionPolicy Bypass -File "c:\ddns\dns-update.ps1"

五、NAS的DDNS客户端设置

对于群晖,也比较简单,群晖无论是DSM6.2还是DSM7.2,控制面板中均自带任务计划功能,创建一个任务计划,配置为5分钟运行一次,脚本为:

curl -6 "https://domain.sample.com:DDNS_KEY@dyn.dns.he.net/nic/update?hostname=domain.sample.com"

注意这里不需要在脚本中添加定时设定,因为任务计划本身已经包含了定时执行的设置了。

对于西数NAS,这个恶心的设备,自带的DDNS功能只支持两家(不包含he.net),虽然可以SSH进去,但用户无法自定义cron任务,必须手动修改其系统级的cron任务,非常麻烦,不推荐。