天空 Blond - ddns
type: channel
link: https://skyblond.info/tag/ddns/
items: 【歪门邪道】使用Cloudflare作为ddns更新IPv6域名DNS

【歪门邪道】使用Cloudflare作为ddns更新IPv6域名DNS
type: item
date: 2024-11-01T08:19:00+08:00
description: 上一篇文章无意中发现了我的公网IPv6地址是能够联通的，并且实际联机体验较为不错。但由于没钱买商宽，所以没有静态IP，而每次IP变动都会带来麻烦，因此本篇将探索如何使用Cloudflare API来更新域名DNS，四舍五入成为一个dDNS。IPv6公网地址虽然好，但毕竟是动态的。虽然Minecraft本身对于服务器的地址没什么要求，但一些mod，例如小地图，它使用服务器的地址来区分数据。也就是说，当IP变动时，即便服务器还是原来的服务器，但对于小地图mod来说，这就是一个新的服务器，因此之前加载的地图缓存和路经点也就全没了。前些日子刚好想起来我还有个域名托管在Cloudflare，主要是利用它的tunnel服务来将内网或一些临时性的服务分享到公网上（一方面是懒得更新DNS，另一方面是懒得搞SSL证书）。我原本也想用tunnel服务将Minecraft服务器映射出去，但简单测试后发现延迟波动比较大，而且延迟普遍有点高，不适合联机。这时我突然意识到，Cloudflare提供了完备的API，即便官方没有提供ddns客户端，我也可以通过调用API的方式更新域名的DNS记录。想来想去，由于我用的是Linux系统，因此实现的最佳方式便是bash，恰好Cloudflare的API文档也提供了多种多样的调用例子，其中就包含了Shell/curl：https://developers.cloudflare.com/api/operations/zones-get要访问Cloudflare API，第一步就是要获取访问密钥，也就是所谓的API Token，这一步在账户设置里就可以找到。关键点在于创建的Token不光要能Edit Zone设置，还要能Read，不然后面第一步获取id就失败了。我一开始以为Edit蕴含了Read权限，所以是我调用的方式不对，结果发现是我token的权限没给。api_email="your login email address" api_key="your api token"在Cloudflare中，网页中显示的website，实际上是DNS Zone。要操作一个DNS Zone，我们不能直接用名字，我们要用它的ID。根据文档，我们可以直接按照Zone的名字（也就是域名）进行筛选：zone_name="example.com" zone_id=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" \ -H "X-Auth-Email: $api_email" \ -H "Authorization: Bearer $api_key" \ -H "Content-Type: application/json" | jq -r .result[0].id ) echo Zone $zone_name id is: $zone_id这里我们用jq这个工具从返回的Json中获取我们想要的结果。拿到Zone ID之后，若要修改一个记录（Record），我们同样需要ID。根据文档，我们使用记录的完整域名和zone id进行查询：record_name="ddns.example.com" record_id=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records?type=AAAA&name=$record_name" \ -H "X-Auth-Email: $api_email" \ -H "Authorization: Bearer $api_key" \ -H "Content-Type: application/json" | jq -r .result[0].id ) echo Record $record_name id is: $record_id同样地，使用jq来解析Json。拿到了这两个ID我们就可以更新DNS记录了。这里要先在网页面板上创建好一个AAAA记录（用于IPv6），至于实际地址可以随便写，比如::1。关于TTL，因为IP可能会随时变动，因此直接设置为最小值，以便IP更新后朋友那边可以直接获取到最新的记录。那么，IPv6怎么获取呢？经过一番awk的现学现卖，我得到了如下命令：v6Addr=$(ip -6 addr show scope global | grep /128 | awk -F '[ \t]+|/' '{print $3}' | grep -v ^fd7a)在上一篇文章中可以得知，我的NUC是能够获得一个/128的公网IP。我先通过ip addr命令的变体找出所有公网IPv6地址，然…