Skip to content

Commit

Permalink
增加只更新指定线路的DNS解析记录的功能。 (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
sanjusss authored Aug 16, 2020
1 parent 46fc6c3 commit cb5f534
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 54 deletions.
11 changes: 5 additions & 6 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
[![GitHub stars](https://img.shields.io/github/stars/sanjusss/aliyun-ddns.svg)](https://github.com/sanjusss/aliyun-ddns/stargazers)

# 功能
- 通过在线API获取公网IPv4地址,更新到域名A记录。
- 通过在线API获取公网IPv6地址,更新到域名AAAA记录。
- 通过本地网卡获取公网或内网IPv4地址,更新到域名A记录。
- 通过本地网卡获取公网或内网IPv6地址,更新到域名AAAA记录。
- 通过在线API获取公网IPv4/v6地址,更新到域名A/AAAA记录。
- 通过本地网卡获取公网或内网IPv4/v6地址,更新到域名A/AAAA记录。
- 支持更新多个域名的记录。
- 支持更新指定线路的记录。
- 支持Docker容器,支持x64、ARMv7和ARMv8。
- IP发生变化时,使用WebHook通知。

Expand All @@ -34,7 +33,7 @@ docker run -d --restart=always --net=host \
| :---- | :----- | :--- |
|AKID|阿里云的Access Key ID。[获取阿里云AccessToken](https://usercenter.console.aliyun.com/)|access key id|
|AKSCT|阿里云的Access Key Secret。|access key secret|
|DOMAIN|需要更新的域名,多个域名需要“,”分隔|my.domain.com|
|DOMAIN|需要更新的域名,可以用“,”隔开。<br>可以指定线路,用“:”分隔线路和域名([线路名说明](https://help.aliyun.com/document_detail/29807.html?spm=a2c4g.11186623.2.14.42405eb4boCsnd))。<br>例如:“baidu.com,telecom:dianxin.baidu.com”|my.domain.com|
|REDO|更新间隔,单位秒。建议大于等于TTL/2。|300|
|TTL|服务器缓存解析记录的时长,单位秒,普通用户最小为600。|600|
|TIMEZONE|输出日志时的时区,单位小时。|8|
Expand Down Expand Up @@ -73,7 +72,7 @@ dotnet aliyun-ddns.dll \
| :---- | :----- | :--- |
|u|阿里云的Access Key ID。[获取阿里云AccessToken](https://usercenter.console.aliyun.com/)|access key id|
|p|阿里云的Access Key Secret。|access key secret|
|d|需要更新的域名,多个域名需要“,”分隔|my.domain.com|
|d|需要更新的域名,可以用“,”隔开。<br>可以指定线路,用“:”分隔线路和域名([线路名说明](https://help.aliyun.com/document_detail/29807.html?spm=a2c4g.11186623.2.14.42405eb4boCsnd))。<br>例如:“baidu.com,telecom:dianxin.baidu.com”|my.domain.com|
|i|更新间隔,单位秒。建议大于等于TTL/2。|300|
|t|服务器缓存解析记录的时长,单位秒,普通用户最小为600。|600|
|timezone|输出日志时的时区,单位小时。|8|
Expand Down
150 changes: 103 additions & 47 deletions aliyun-ddns/DomainUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private void Update(string[] domains, HashSet<IpType> targetTypes)
{
if (typedRecords.Count > 1)
{
DeleteRecords(typedRecords[0].DomainName, typedRecords[0].RR, type);
DeleteRecords(typedRecords);
}

success = AddRecord(j.Key, i, j.Value);
Expand Down Expand Up @@ -257,13 +257,15 @@ private IList<Record> GetRecords(string domain)
{
var client = GetNewClient();
long pageNumber = 1;
ParseSubDomainAndLine(domain, out string subDomain, out string line);
do
{
DescribeSubDomainRecordsRequest request = new DescribeSubDomainRecordsRequest
{
SubDomain = domain,
SubDomain = subDomain,
PageSize = _pageSize,
PageNumber = pageNumber
PageNumber = pageNumber,
Line = line
};

var response = client.GetAcsResponse(request);
Expand All @@ -288,41 +290,78 @@ private IList<Record> GetRecords(string domain)
return records;
}

///// <summary>
///// 删除所有指定类型的记录。
///// </summary>
///// <param name="domain">域名</param>
///// <param name="rr">主机记录</param>
///// <param name="type">解析记录类型</param>
///// <returns>是否删除成功。</returns>
//private bool DeleteRecordsByType(string domain, string rr, string type)
//{
// try
// {
// var client = GetNewClient();
// DeleteSubDomainRecordsRequest request = new DeleteSubDomainRecordsRequest
// {
// DomainName = domain,
// RR = rr,
// Type = type,
// };
// var response = client.GetAcsResponse(request);
// if (response.HttpResponse.isSuccess())
// {
// Log.Print($"成功清理{ type }记录{ rr }.{ domain }。");
// return true;
// }
// else
// {
// Log.Print($"清理{ type }记录{ rr }.{ domain }失败。");
// return false;
// }
// }
// catch (Exception e)
// {
// Log.Print($"删除{ type }记录{ rr }.{ domain }记录时出现异常:{ e }");
// return false;
// }
//}

/// <summary>
/// 删除所有指定类型的记录
/// 删除所有记录
/// </summary>
/// <param name="domain">域名</param>
/// <param name="rr">主机记录</param>
/// <param name="type">解析记录类型</param>
/// <returns>是否删除成功。</returns>
private bool DeleteRecords(string domain, string rr, string type)
/// <param name="records">记录</param>
/// <returns>是否成功删除</returns>
private bool DeleteRecords(IEnumerable<Record> records)
{
try
foreach (var rd in records)
{
var client = GetNewClient();
DeleteSubDomainRecordsRequest request = new DeleteSubDomainRecordsRequest
{
DomainName = domain,
RR = rr,
Type = type
};
var response = client.GetAcsResponse(request);
if (response.HttpResponse.isSuccess())
try
{
Log.Print($"成功清理{ type }记录{ rr }.{ domain }。");
return true;
var client = GetNewClient();
DeleteDomainRecordRequest request = new DeleteDomainRecordRequest
{
RecordId = rd.RecordId
};
var response = client.GetAcsResponse(request);
if (response.HttpResponse.isSuccess())
{
Log.Print($"成功清理{ rd.Type }记录{ rd.RR }.{ rd.DomainName }({ rd.Line })记录{ rd.RecordId }。");
}
else
{
Log.Print($"清理{ rd.Type }记录{ rd.RR }.{ rd.DomainName }({ rd.Line })记录{ rd.RecordId }失败。");
return false;
}
}
else
catch (Exception e)
{
Log.Print($"清理{ type }记录{ rr }.{ domain }失败。");
Log.Print($"删除{ rd.Type }记录{ rd.RR }.{ rd.DomainName }({ rd.Line })记录{ rd.RecordId }时出现异常:{ e }");
return false;
}
}
catch (Exception e)
{
Log.Print($"删除{ type }记录{ rr }.{ domain }记录时出现异常:{ e }");
return false;
}

return true;
}

/// <summary>
Expand All @@ -332,25 +371,17 @@ private bool DeleteRecords(string domain, string rr, string type)
/// <returns>是否完全删除成功。</returns>
private bool ClearCName(ref IList<Record> rds)
{
bool found = false;
string domain = null;
string rr = null;
List<Record> cnameRecords = new List<Record>();
for (int i = rds.Count - 1; i >= 0; --i)
{
if (rds[i].Type == "CNAME")
{
if (found == false)
{
found = true;
domain = rds[i].DomainName;
rr = rds[i].RR;
}

cnameRecords.Add(rds[i]);
rds.RemoveAt(i);
}
}

return found == false || DeleteRecords(domain, rr, "CNAME");
return cnameRecords.Count == 0 || DeleteRecords(cnameRecords);
}

/// <summary>
Expand All @@ -364,9 +395,10 @@ private bool AddRecord(IpType type, string domain, string ip)
{
try
{
ParseSubDomainAndLine(domain, out string subDomain, out string line);
string pattern = @"^(\S*)\.(\S+)\.(\S+)$";
Regex regex = new Regex(pattern);
var match = regex.Match(domain);
var match = regex.Match(subDomain);
string domainName;
string rr;
if (match.Success)
Expand All @@ -377,7 +409,7 @@ private bool AddRecord(IpType type, string domain, string ip)
else
{
rr = "@";
domainName = domain;
domainName = subDomain;
}

var client = GetNewClient();
Expand All @@ -387,7 +419,8 @@ private bool AddRecord(IpType type, string domain, string ip)
RR = rr,
Type = type.ToString(),
_Value = ip,
TTL = Options.Instance.TTL
TTL = Options.Instance.TTL,
Line = line
};
var response = client.GetAcsResponse(request);
if (response.HttpResponse.isSuccess())
Expand Down Expand Up @@ -422,7 +455,7 @@ private bool UpdateRecord(Record rd, string ip)
}
else if (ip == rd._Value)
{
Log.Print($"{ rd.Type }记录{ rd.RR }.{ rd.DomainName }不需要更新。");
Log.Print($"{ rd.Type }记录{ rd.RR }.{ rd.DomainName }({ rd.Line })不需要更新。");
return false;
}

Expand All @@ -435,25 +468,48 @@ private bool UpdateRecord(Record rd, string ip)
RR = rd.RR,
Type = rd.Type,
_Value = ip,
TTL = Options.Instance.TTL
TTL = Options.Instance.TTL,
Line = rd.Line
};
var response = client.GetAcsResponse(request);
if (response.HttpResponse.isSuccess())
{
Log.Print($"成功更新{ rd.Type }记录{ rd.RR }.{ rd.DomainName }{ ip }。");
Log.Print($"成功更新{ rd.Type }记录{ rd.RR }.{ rd.DomainName }({ rd.Line }){ ip }。");
return true;
}
else
{
Log.Print($"更新{ rd.Type }记录{ rd.RR }.{ rd.DomainName }失败。");
Log.Print($"更新{ rd.Type }记录{ rd.RR }.{ rd.DomainName }({ rd.Line })失败。");
return false;
}
}
catch (Exception e)
{
Log.Print($"更新{ rd.Type }记录{ rd.RR }.{ rd.DomainName }时出现异常:{ e }。");
Log.Print($"更新{ rd.Type }记录{ rd.RR }.{ rd.DomainName }({ rd.Line })时出现异常:{ e }。");
return false;
}
}

private static void ParseSubDomainAndLine(string domain, out string subDomain, out string line)
{
var words = domain.Split(':', StringSplitOptions.RemoveEmptyEntries);
if (words.Length > 2 || words.Length == 0)
{
line = "default";
subDomain = domain;
return;
}

if (words.Length == 2)
{
line = words[0];
subDomain = words[1];
}
else
{
line = "default";
subDomain = words[0];
}
}
}
}
2 changes: 1 addition & 1 deletion aliyun-ddns/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class Options
//[Option('e', "endpoint", Required = false, Default = "cn-hangzhou", HelpText = "Region Id,详见https://help.aliyun.com/document_detail/40654.html?spm=a2c4e.11153987.0.0.6d85366aUfTWbG")]
//public string ENDPOINT { get; set; } = "cn-hangzhou";

[Option('d', "domain", Required = false, Default = "my.domain.com", HelpText = "需要更新的域名,可以用“,”隔开。")]
[Option('d', "domain", Required = false, Default = "my.domain.com", HelpText = "需要更新的域名,可以用“,”隔开。可以指定线路,用“:”分隔线路和域名(线路名说明见https://help.aliyun.com/document_detail/29807.html?spm=a2c4g.11186623.2.14.42405eb4boCsnd)。例如:“baidu.com,telecom:dianxin.baidu.com”。")]
public string Domain { get; set; } = "my.domain.com";

[Option('i', "interval", Required = false, Default = 300, HelpText = "执行域名更新的间隔,单位秒。")]
Expand Down

0 comments on commit cb5f534

Please sign in to comment.