0.简要介绍 0.1 思路说明
AliDDNSNet 是基于 .NET Core 开发的动态 DNS 解析工具,借助于阿里云的 DNS API 来实现域名与动态 IP 的绑定功能。工具核心就是调用了阿里云 DNS 的两个 API ,一个 API 获取指定域名的所有解析记录,然后通过比对与当前公网 IP 是否一致,一致则不进行更改,不一致则通过另外一个修改 API 来修改指定子域名的修改记录。
0.2 使用说明使用时请更改同目录下的 settings.json.example 为 settings.json 文件,同时也可以显示通过 -f 参数来制定配置文件路径。例如:
dotnet ./AliDDNSNet.dll -f ./settings.json2 ./AliDDNSNet -f ./settings.json3NAS 运行效果图:
0.3.配置说明:通过更改 settings.json/settings.json.example 的内容来实现 DDNS 更新。
{ // 阿里云的 Access Id "access_id": "", // 阿里云的 Access Key "access_key": "", // TTL 时间 "interval": 600, // 主域名 "domain": "example.com", // 子域名前缀 "sub_domain": "test", // 记录类型 "type": "A" }其中 Access Id 与 Access Key 可以登录阿里云之后在右上角可以得到。
2.代码说明 2.1 主程序流程主要流程代码在 Program.cs 文件当中编写,这里依次讲解一下。
首先加载配置文件,如果用户传入了 -f 参数,则使用用户传入的配置文件路径,否则的话直接使用当前目录的默认 settings.json 配置文件,读取成功之后存放到 Utils.config 属性当中以便 Utils 使用。
// 加载配置文件: var filePath = attachments.HasValue() ? attachments.Value() : $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}settings.json"; if (!File.Exists(filePath)) { Console.WriteLine("当前目录没有配置文件,或者配置文件位置不正确。"); return -1; } var config = await Utils.ReadConfigFile(filePath); Utils.config = config;之后通过 Utils.GetCurentPublicIP() 方法获取到当前设备的公网 IP,再判断指定的二级域名解析是否存在,如果不存在的话,则直接返回,这里并没有做新增解析操作,后续版本可能会加上。
// 获得当前 IP var currentIP = (await Utils.GetCurentPublicIP()).Replace("\n", ""); var subDomains = JObject.Parse(await Utils.SendGetRequest(new DescribeDomainRecordsRequest(config.domain))); if (subDomains.SelectToken($"$.DomainRecords.Record[?(@.RR == '{config.sub_domain}')]") == null) { Console.WriteLine("指定的子域名不存在,请新建一个子域名解析。"); return 0; }如果找到了对应二级域名的解析,则输出当前解析的记录值,然后进行比较,如果当前主机的公网 IP 与记录值一样则无需进行变更。
Console.WriteLine("已经找到对应的域名与解析"); Console.WriteLine("======================"); Console.WriteLine($"子域名:{config.sub_domain}{config.domain}"); var dnsIp = subDomains.SelectToken($"$.DomainRecords.Record[?(@.RR == '{config.sub_domain}')].Value").Value<string>(); Console.WriteLine($"目前的 A 记录解析 IP 地址:{dnsIp}"); if (currentIP == dnsIp) { Console.WriteLine("解析地址与当前主机 IP 地址一致,无需更改."); return 0; }当阿里云 DNS 解析记录与当前主机公网 IP 不一致的时候调用更新 API,传入之前的域名的 rrId 去进行变更,完成即退出。
Console.WriteLine("检测到 IP 地址不一致,正在更改中......"); var rrId = subDomains.SelectToken($"$.DomainRecords.Record[?(@.RR == '{config.sub_domain}')].RecordId").Value<string>(); var response = await Utils.SendGetRequest(new UpdateDomainRecordRequest(rrId, config.sub_domain, config.type, currentIP, config.interval.ToString())); var resultRRId = JObject.Parse(response).SelectToken("$.RecordId").Value<string>(); if (resultRRId == null || resultRRId != rrId) { Console.WriteLine("更改记录失败,请稍后再试。"); } else { Console.WriteLine("更改记录成功。"); } return 0; 2.1 Utils 详解Utils.cs 主要存放一些功能性方法,比如说将 SortedDictionary 字典转为请求字符串,还有就是加密方法,请求方法等。
2.2.1 生成通用参数字典因为 API 请求的时候有很多共有参数,所以这里单独用了一个静态方法来生成这个公有请求参数的字典。
/// <summary> /// 生成通用参数字典 /// </summary> public static SortedDictionary<string, string> GenerateGenericParameters() { var dict = new SortedDictionary<string, string>(StringComparer.Ordinal) { {"Format", "json"}, {"AccessKeyId", config.access_id}, {"SignatureMethod", "HMAC-SHA1"}, {"SignatureNonce", Guid.NewGuid().ToString()}, {"Version", "2015-01-09"}, {"SignatureVersion", "1.0"}, {"Timestamp", DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")} }; return dict; }可以看到这里使用了 SortedDictionary<string,string> 来处理,这是因为阿里云 API 必须要求按大小写敏感来排序请求参数,所以这里直接使用了 ```SortedDictionary 来处理这种情况。
2.2.2 根据字典构建请求字符串