电信宽带一般能申请到公网IP,但是是动态的,基本上每天都要变,所以想到做一个定时任务,随系统启动,网上看了不少博文很多都支持IPv4,自己动手写了一个。
(私信可全程指导)
部署步骤:
1、下载软件包,修改配置文件
下载地址:私信获取
下载压缩包,解压后修改配置文件AliDDNS.exe.config中的阿里云帐号和自己的域名。
2、修改脚本,并运行脚本
将"安装服务.bat"和"卸载服务.bat"脚本中的可执行文件路径,改为自己的软件包所在路径,然后右键"安装服务.bat"进行安装服务。
执行脚本后会将定时服务添加到系统服务中。
3、启动服务
右键"此电脑",点击"管理"进入计算机管理窗口,在服务列表中找到上一步新增的服务,然后启动。即可定时更新阿里云解析记录,实现动态IP的DDNS。
源代码:
cs
/// <summary>
/// 刷新阿里云域名解析记录
/// </summary>
private void RefreshAliRecord()
{
string recordTypes = ConfigurationManager.AppSettings["RecordTypes"];
if (string.IsNullOrWhiteSpace(recordTypes))
{
NLogHelper.WriteLog(typeof(AliDDNS), "配置文件中的"待解析的协议类型"不能为空。", NLogLevel.Warn);
return;
}
string regionId = ConfigurationManager.AppSettings["RegionId"];
string accessKeyID = ConfigurationManager.AppSettings["AccessKeyID"];
string accessKeySecret = ConfigurationManager.AppSettings["AccessKeySecret"];
string domainName = ConfigurationManager.AppSettings["DomainName"];
string rR = ConfigurationManager.AppSettings["RR"];
string[] rRTypes = rR.Split('|');
// regionId:地区节点
// accessKeyID:阿里云Key
// accessKeySecret:阿里云密钥
AlibabaCloudCredentialsProvider provider = new AccessKeyCredentialProvider(accessKeyID, accessKeySecret);
IClientProfile profile = DefaultProfile.GetProfile(regionId);
DefaultAcsClient client = new DefaultAcsClient(profile, provider);
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> recordList = DescribeDomainRecords(client, domainName);
string[] recordTypeArray = recordTypes.Split('|');
foreach (string recordType in recordTypeArray)
{
if (recordType == "A")
{
#region IPv4解析记录
try
{
string urls = ConfigurationManager.AppSettings["GetIPFromUrl"];
string ipv4 = CommonHelper.GetExtranetIP(urls.Split('|').ToList());
if (string.IsNullOrWhiteSpace(ipv4))
{
NLogHelper.WriteLog(typeof(AliDDNS), "未获取到外网IPv4地址!", NLogLevel.Warn);
return;
}
if (IsAddSuccessLog)
{
NLogHelper.WriteLog(typeof(AliDDNS), "获取到的外网IPv4地址为:" + ipv4, NLogLevel.Info);
}
foreach (string rRItem in rRTypes)
{
if (string.IsNullOrWhiteSpace(rRItem))
{
continue;
}
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> ipv4Records = recordList.Where(r => r.Type == recordType && r.RR == rRItem).ToList();
if (ipv4Records == null || ipv4Records.Count() == 0)
{
AddDNSRecord(client, domainName, rRItem, recordType, ipv4);
}
else
{
#region 更新解析记录
// 非ipv4记录
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> otherRecords = ipv4Records.Where(r => r._Value != ipv4).ToList();
// ipv4记录
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> tempList = ipv4Records.Where(r => r._Value == ipv4).ToList();
if (tempList == null || tempList.Count == 0)
{
// 如果不存在该IPv4的记录,则删除所有记录ipv4Records,并新增记录
AddDNSRecord(client, domainName, rRItem, recordType, ipv4);
DeleteDNSRecord(client, ipv4Records);
}
else if (tempList.Count == 1) // 如果只存在一条该IPv4记录,则记录日志,如果有其他记录则删除
{
NLogHelper.WriteLog(typeof(AliDDNS), string.Format("同类型("{0}"类型)的解析记录(IPv4:{1})已存在,无需更新!", rRItem, ipv4), NLogLevel.Info);
if (ipv4Records.Count != tempList.Count)
{
// 存在其他记录,则删除其他记录otherRecords
DeleteDNSRecord(client, otherRecords);
}
}
else
{
// 如果存在多条该IPv4记录,则取第一条,其他的记录都删除
tempList.RemoveRange(0, 1);
otherRecords.AddRange(tempList);
DeleteDNSRecord(client, otherRecords);
}
#endregion
}
}
}
catch (Exception ex)
{
NLogHelper.WriteLog(typeof(AliDDNS), "查询并更新IPv4解析记录时异常:" + ex.ToString(), NLogLevel.Warn);
}
#endregion
}
else if (recordType == "AAAA")
{
#region IPv6解析记录
try
{
List<string> ipv6List = CommonHelper.GetLocalIPv6();
if (ipv6List == null || ipv6List.Count() == 0)
{
NLogHelper.WriteLog(typeof(AliDDNS), "未获取到本机IPv6地址!", NLogLevel.Warn);
return;
}
if (IsAddSuccessLog)
{
NLogHelper.WriteLog(typeof(AliDDNS), "获取到的本地IPv6地址为:" + string.Join(",", ipv6List), NLogLevel.Info);
}
string defaultIPv6 = ipv6List[0]; // 默认只添加第一个IPv6地址
foreach (string rRItem in rRTypes)
{
if (string.IsNullOrWhiteSpace(rRItem))
{
continue;
}
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> ipv6Records = recordList.Where(r => r.Type == recordType && r.RR == rRItem).ToList();
if (ipv6Records == null || ipv6Records.Count() == 0)
{
AddDNSRecord(client, domainName, rRItem, recordType, defaultIPv6);
}
else
{
#region 更新解析记录
// 非ipv6记录
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> otherRecords = ipv6Records.Where(r => r._Value != defaultIPv6).ToList();
// ipv6记录
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> tempList = ipv6Records.Where(r => r._Value == defaultIPv6).ToList();
if (tempList == null || tempList.Count == 0)
{
// 如果不存在该IPv6的记录,则删除所有记录ipv6Records,并新增记录
AddDNSRecord(client, domainName, rRItem, recordType, defaultIPv6);
DeleteDNSRecord(client, ipv6Records);
}
else if (tempList.Count == 1) // 如果只存在一条该IPv6记录,则记录日志,如果有其他记录则删除
{
NLogHelper.WriteLog(typeof(AliDDNS), string.Format("同类型("{0}"类型)的解析记录(IPv6:{1})已存在,无需更新!", rRItem, defaultIPv6), NLogLevel.Info);
if (ipv6Records.Count != tempList.Count)
{
// 存在其他记录,则删除其他记录otherRecords
DeleteDNSRecord(client, otherRecords);
}
}
else
{
// 如果存在多条该IPv6记录,则取第一条,其他的记录都删除
tempList.RemoveRange(0, 1);
otherRecords.AddRange(tempList);
DeleteDNSRecord(client, otherRecords);
}
#endregion
}
}
}
catch (Exception ex)
{
NLogHelper.WriteLog(typeof(AliDDNS), "查询并更新IPv6解析记录时异常:" + ex.ToString(), NLogLevel.Warn);
}
#endregion
}
}
}
// 获取指定主域名的所有解析记录列表
public List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> DescribeDomainRecords(DefaultAcsClient client, string domainName)
{
List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> records = new List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record>();
try
{
DescribeDomainRecordsRequest request = new DescribeDomainRecordsRequest();
request.DomainName = domainName;
记录类型 官网支持A/CNAME/MX/AAA/TXT/NS/SRV/CAA/URL隐性(显性)转发如果有需要可将该值配置为参数传入
//request.Type = recordType;
try
{
DescribeDomainRecordsResponse response = client.GetAcsResponse(request);
if (IsAddSuccessLog)
{
NLogHelper.WriteLog(typeof(AliDDNS), "查询到的解析记录:" + System.Text.Encoding.Default.GetString(response.HttpResponse.Content), NLogLevel.Info);
}
if (response.DomainRecords != null)
{
records = response.DomainRecords;
}
}
catch (Exception ex)
{
NLogHelper.WriteLog(typeof(AliDDNS), "调用DescribeDomainRecords接口时发生异常:" + ex.ToString(), NLogLevel.Error);
}
}
catch (Exception ex)
{
NLogHelper.WriteLog(typeof(AliDDNS), "创建DescribeDomainRecords接口调用对象时发生异常:" + ex.ToString(), NLogLevel.Error);
}
return records;
}
// 新增解析记录
public void AddDNSRecord(DefaultAcsClient client, string domainName, string rRItem, string recordType, string ipValue)
{
#region 新增解析记录
string recordStr = string.Format("(RR:{0},Type:{1},Value:{2})", rRItem, recordType, ipValue);
try
{
var request = new AddDomainRecordRequest();
request.DomainName = domainName;
request.RR = rRItem;
request.Type = recordType;
request._Value = ipValue;
request.TTL = 600; // 免费版,默认600秒,10分钟
var response = client.GetAcsResponse(request);
if (IsAddSuccessLog)
{
NLogHelper.WriteLog(typeof(AliDDNS), string.Format("新增解析记录{0}时接口返回内容:{1}", recordStr, Encoding.Default.GetString(response.HttpResponse.Content)), NLogLevel.Info);
}
}
catch (Exception ex)
{
NLogHelper.WriteLog(typeof(AliDDNS), string.Format("新增解析记录{0}时发生异常:{1}", recordStr, ex.ToString()), NLogLevel.Error);
}
#endregion
}
// 删除解析记录
public void DeleteDNSRecord(DefaultAcsClient client, List<DescribeDomainRecordsResponse.DescribeDomainRecords_Record> deleteList)
{
#region 删除解析记录
foreach (DescribeDomainRecordsResponse.DescribeDomainRecords_Record record in deleteList)
{
string recordStr = string.Format("(RR:{0},Type:{1},Value:{2})", record.RR, record.Type, record._Value);
try
{
DeleteDomainRecordRequest request = new DeleteDomainRecordRequest();
request.RecordId = record.RecordId;
DeleteDomainRecordResponse response = client.GetAcsResponse(request);
if (IsAddSuccessLog)
{
NLogHelper.WriteLog(typeof(AliDDNS), string.Format("删除解析记录{0}时接口返回内容:{1}", recordStr, Encoding.Default.GetString(response.HttpResponse.Content)), NLogLevel.Info);
}
}
catch (Exception ex)
{
NLogHelper.WriteLog(typeof(AliDDNS), string.Format("删除解析记录{0}时发生异常:{1}", recordStr, ex.ToString()), NLogLevel.Error);
}
}
#endregion
}