From 5cd5830ec59cfadb928167e46022f8c62c93d358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B8=E5=BE=92=E7=8E=9F=E7=90=85?= Date: Fri, 3 Jul 2020 15:34:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=80=9A=E8=BF=87=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E7=BD=91=E5=8D=A1=E8=8E=B7=E5=8F=96IP=E5=9C=B0?= =?UTF-8?q?=E5=9D=80=E3=80=82=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix #24 fix #21 --- .github/Dockerfile | 14 ++- ReadMe.md | 13 +++ aliyun-ddns/Common/Log.cs | 2 +- aliyun-ddns/DomainUpdater.cs | 8 +- aliyun-ddns/IPGetter/BaseLocalIPGetter.cs | 103 ++++++++++++++++++ .../IPGetter/IPv4Getter/IPv4GetterCreator.cs | 12 +- .../IPGetter/IPv4Getter/LocalIPv4Getter.cs | 26 +++++ .../IPGetter/IPv6Getter/IPv6GetterCreator.cs | 12 +- .../IPGetter/IPv6Getter/LocalIPv6Getter.cs | 64 ++--------- aliyun-ddns/Options.cs | 61 ++++++++--- aliyun-ddns/PublicIpGetter.cs | 2 +- aliyun-ddns/WebHook/WebHookAction.cs | 2 +- aliyun-ddns/aliyun-ddns.csproj | 7 +- 13 files changed, 239 insertions(+), 87 deletions(-) create mode 100644 aliyun-ddns/IPGetter/BaseLocalIPGetter.cs create mode 100644 aliyun-ddns/IPGetter/IPv4Getter/LocalIPv4Getter.cs diff --git a/.github/Dockerfile b/.github/Dockerfile index cad8a69..d7055a4 100644 --- a/.github/Dockerfile +++ b/.github/Dockerfile @@ -1,6 +1,18 @@ FROM mcr.microsoft.com/dotnet/core/runtime:3.1 AS final -MAINTAINER sanjusss +LABEL maintainer="sanjusss@qq.com" +ENV AKID="access key id" +ENV AKSCT="access key secret" +ENV DOMAIN="my.domain.com" +ENV REDO=300 +ENV TTL=600 +ENV TIMEZONE=8 +ENV TYPE=A,AAAA +ENV CNIPV4=false +ENV WEBHOOK= +ENV CHECKLOCAL=false +ENV IPV4NETS= +ENV IPV6NETS= WORKDIR /app COPY ./out . ENTRYPOINT ["dotnet", "aliyun-ddns.dll"] diff --git a/ReadMe.md b/ReadMe.md index 97c3ad6..bc7ad97 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -7,6 +7,13 @@ [![GitHub forks](https://img.shields.io/github/forks/sanjusss/aliyun-ddns.svg)](https://github.com/sanjusss/aliyun-ddns/network) [![GitHub stars](https://img.shields.io/github/stars/sanjusss/aliyun-ddns.svg)](https://github.com/sanjusss/aliyun-ddns/stargazers) +# 功能 +- 通过在线API获取公网IPv4地址 +- 通过在线API获取公网IPv6地址 +- 通过本地网卡获取公网或内网IPv4地址 +- 通过本地网卡获取公网或内网IPv6地址 +- Docker容器支持 +- IP发生变化时,使用WebHook通知 # 使用方法 @@ -33,6 +40,9 @@ docker run -d --restart=always --net=host \ |TYPE|需要更改的记录类型,可以用“,”隔开,只能是“A”、“AAAA”或“A,AAAA”。|A,AAAA| |CNIPV4|检查IPv4地址时,仅使用中国服务器。|false| |WEBHOOK|WEBHOOK推送地址。|无| +|CHECKLOCAL|是否检查本地网卡IP。此选项将禁用在线API的IP检查。
网络模式必须设置为host
(Windows版docker无法读取本机IP)|false| +|IPV4NETS|本地网卡的IPv4网段。格式示例:“192.168.1.0/24”。多个网段用“,”隔开。|无| +|IPV6NETS|本地网卡的IPv6网段。格式示例:“2001:0db8::/64”。多个网段用“,”隔开。|无| 以上环境变量均存在默认值,添加需要修改的环境变量即可。 @@ -69,5 +79,8 @@ dotnet aliyun-ddns.dll \ |type|需要更改的记录类型,可以用“,”隔开,只能是“A”、“AAAA”或“A,AAAA”。|A,AAAA| |cnipv4|检查IPv4地址时,仅使用中国服务器。|false| |webhook|WEBHOOK推送地址。|无| +|checklocal|是否检查本地网卡IP。此选项将禁用在线API的IP检查。|false| +|ipv4nets|本地网卡的IPv4网段。格式示例:“192.168.1.0/24”。多个网段用“,”隔开。|无| +|ipv6nets|本地网卡的IPv6网段。格式示例:“2001:0db8::/64”。多个网段用“,”隔开。|无| 以上参数均存在默认值,添加需要修改的参数即可。 diff --git a/aliyun-ddns/Common/Log.cs b/aliyun-ddns/Common/Log.cs index d777dfd..7b941f4 100644 --- a/aliyun-ddns/Common/Log.cs +++ b/aliyun-ddns/Common/Log.cs @@ -15,7 +15,7 @@ public static class Log /// 日志信息 public static void Print(string msg) { - Console.WriteLine($"[{ DateTime.UtcNow.AddHours(Options.Instance.TIMEZONE) }]{ msg }"); + Console.WriteLine($"[{ DateTime.UtcNow.AddHours(Options.Instance.Timezone) }]{ msg }"); } } } diff --git a/aliyun-ddns/DomainUpdater.cs b/aliyun-ddns/DomainUpdater.cs index d2f3dd1..70cd34d 100644 --- a/aliyun-ddns/DomainUpdater.cs +++ b/aliyun-ddns/DomainUpdater.cs @@ -50,8 +50,8 @@ private enum IpType /// public void Run() { - TimeSpan maxWait = new TimeSpan(0, 0, Options.Instance.REDO); - string[] domains = Options.Instance.DOMAIN.Split(',', StringSplitOptions.RemoveEmptyEntries); + TimeSpan maxWait = new TimeSpan(0, 0, Options.Instance.Redo); + string[] domains = Options.Instance.Domain.Split(',', StringSplitOptions.RemoveEmptyEntries); HashSet targetTypes = GetTargetTypes(); if (targetTypes.Count == 0) { @@ -154,7 +154,7 @@ private void Update(string[] domains, HashSet targetTypes) /// 目标记录类型的集合 private HashSet GetTargetTypes() { - HashSet inputTypes = new HashSet(Options.Instance.TYPE.Split(',', StringSplitOptions.RemoveEmptyEntries)); + HashSet inputTypes = new HashSet(Options.Instance.Type.Split(',', StringSplitOptions.RemoveEmptyEntries)); HashSet targetTypes = new HashSet(); if (inputTypes.Contains("A")) { @@ -242,7 +242,7 @@ private DefaultAcsClient GetNewClient() //var clientProfile = DefaultProfile.GetProfile(Options.Instance.ENDPOINT, Options.Instance.AKID, Options.Instance.AKSCT); //return new DefaultAcsClient(clientProfile); return new DefaultAcsClient(DefaultProfile.GetProfile(), - new Aliyun.Acs.Core.Auth.BasicCredentials(Options.Instance.AKID, Options.Instance.AKSCT)); + new Aliyun.Acs.Core.Auth.BasicCredentials(Options.Instance.Akid, Options.Instance.Aksct)); } /// diff --git a/aliyun-ddns/IPGetter/BaseLocalIPGetter.cs b/aliyun-ddns/IPGetter/BaseLocalIPGetter.cs new file mode 100644 index 0000000..d8d8483 --- /dev/null +++ b/aliyun-ddns/IPGetter/BaseLocalIPGetter.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace aliyun_ddns.IPGetter +{ + public abstract class BaseLocalIPGetter : IIPGetter + { + public abstract string Description { get; } + public abstract int Order { get; } + + /// + /// IP网段字符串。 + /// + protected abstract string IPNetworks { get; } + + /// + /// 检查IP信息是否符合要求。 + /// + /// IP信息 + /// 是否符合要求 + protected abstract bool CheckIPAddressInformation(IPAddressInformation info); + + public async Task GetIP() + { + return await Task.Run(() => + { + try + { + var nets = GetIPNetworks(); + string ip = null; + //获取所有网卡信息,返回最后一个地址。 + NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface adapter in nics) + { + try + { + //获取网络接口信息 + IPInterfaceProperties properties = adapter.GetIPProperties(); + //获取单播地址集 + UnicastIPAddressInformationCollection ips = properties.UnicastAddresses; + foreach (UnicastIPAddressInformation i in ips) + { + if (CheckIPAddressInformation(i) == false) + { + continue; + } + + bool success = false; + foreach (var net in nets) + { + if (net.Contains(i.Address)) + { + success = true; + break; + } + } + + if (success) + { + ip = i.Address.ToString(); + } + } + } + catch + { + continue; + } + } + + return ip; + } + catch + { + return null; + } + }); + } + + private IEnumerable GetIPNetworks() + { + List nets = new List(); + string text = IPNetworks; + if (string.IsNullOrEmpty(text) == false) + { + string[] subs = text.Split(',', StringSplitOptions.RemoveEmptyEntries); + foreach (var i in subs) + { + if (IPNetwork.TryParse(i, out IPNetwork net)) + { + nets.Add(net); + } + } + } + + return nets; + } + } +} diff --git a/aliyun-ddns/IPGetter/IPv4Getter/IPv4GetterCreator.cs b/aliyun-ddns/IPGetter/IPv4Getter/IPv4GetterCreator.cs index b679803..c86fce5 100644 --- a/aliyun-ddns/IPGetter/IPv4Getter/IPv4GetterCreator.cs +++ b/aliyun-ddns/IPGetter/IPv4Getter/IPv4GetterCreator.cs @@ -19,8 +19,16 @@ public static class IPv4GetterCreator public static IEnumerable Create() { List getters = new List(); - getters.AddRange(InstanceCreator.Create(Ignore.CheckType)); - getters.AddRange(_definedGetters); + if (Options.Instance.CheckLocalNetworkAdaptor) + { + getters.Add(new LocalIPv4Getter()); + } + else + { + getters.AddRange(InstanceCreator.Create(Ignore.CheckType)); + getters.AddRange(_definedGetters); + } + return getters; } } diff --git a/aliyun-ddns/IPGetter/IPv4Getter/LocalIPv4Getter.cs b/aliyun-ddns/IPGetter/IPv4Getter/LocalIPv4Getter.cs new file mode 100644 index 0000000..4a414da --- /dev/null +++ b/aliyun-ddns/IPGetter/IPv4Getter/LocalIPv4Getter.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Text; + +namespace aliyun_ddns.IPGetter.IPv4Getter +{ + /// + /// 获取所有网卡信息,返回最后一个IPv6地址。 + /// + [Ignore] + public sealed class LocalIPv4Getter : BaseLocalIPGetter, IIPv4Getter + { + public override string Description => "读取网卡IPv4设置"; + + public override int Order => 200; + + protected override string IPNetworks => Options.Instance.IPv4Networks; + + protected override bool CheckIPAddressInformation(IPAddressInformation info) + { + return info.Address.AddressFamily == AddressFamily.InterNetwork; + } + } +} diff --git a/aliyun-ddns/IPGetter/IPv6Getter/IPv6GetterCreator.cs b/aliyun-ddns/IPGetter/IPv6Getter/IPv6GetterCreator.cs index 58c5efc..da4fcb4 100644 --- a/aliyun-ddns/IPGetter/IPv6Getter/IPv6GetterCreator.cs +++ b/aliyun-ddns/IPGetter/IPv6Getter/IPv6GetterCreator.cs @@ -19,8 +19,16 @@ public static class IPv6GetterCreator public static IEnumerable Create() { List getters = new List(); - getters.AddRange(InstanceCreator.Create(Ignore.CheckType)); - getters.AddRange(_definedGetters); + if (Options.Instance.CheckLocalNetworkAdaptor) + { + getters.Add(new LocalIPv6Getter()); + } + else + { + getters.AddRange(InstanceCreator.Create(Ignore.CheckType)); + getters.AddRange(_definedGetters); + } + return getters; } } diff --git a/aliyun-ddns/IPGetter/IPv6Getter/LocalIPv6Getter.cs b/aliyun-ddns/IPGetter/IPv6Getter/LocalIPv6Getter.cs index 7941735..458cfa1 100644 --- a/aliyun-ddns/IPGetter/IPv6Getter/LocalIPv6Getter.cs +++ b/aliyun-ddns/IPGetter/IPv6Getter/LocalIPv6Getter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Text; @@ -11,65 +12,18 @@ namespace aliyun_ddns.IPGetter.IPv6Getter /// /// 获取所有网卡信息,返回最后一个IPv6地址。 /// - public sealed class LocalIPv6Getter : IIPv6Getter + [Ignore] + public sealed class LocalIPv6Getter : BaseLocalIPGetter, IIPv6Getter { - public string Description => "读取网卡设置"; + public override string Description => "读取网卡IPv6设置"; - public int Order => 200; + public override int Order => 200; - public async Task GetIP() - { - return await Task.Run(() => - { - Thread.Sleep(3000); - try - { - string ip = null; - //获取所有网卡信息,返回最后一个IPv6地址。 - NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); - foreach (NetworkInterface adapter in nics) - { - try - { - if (adapter.NetworkInterfaceType != NetworkInterfaceType.Ethernet && - adapter.NetworkInterfaceType != NetworkInterfaceType.Wireless80211 && - adapter.NetworkInterfaceType != NetworkInterfaceType.Ppp) - { - continue; - } - - //获取网络接口信息 - IPInterfaceProperties properties = adapter.GetIPProperties(); - //获取单播地址集 - UnicastIPAddressInformationCollection ips = properties.UnicastAddresses; - foreach (UnicastIPAddressInformation i in ips) - { - if (i.Address.AddressFamily != AddressFamily.InterNetworkV6 || - i.Address.IsIPv6LinkLocal || - i.Address.IsIPv6Multicast || - i.Address.IsIPv6SiteLocal || - i.Address.IsIPv4MappedToIPv6 || - i.Address.IsIPv6Teredo) - { - continue; - } + protected override string IPNetworks => Options.Instance.IPv6Networks; - ip = i.Address.ToString(); - } - } - catch - { - continue; - } - } - - return ip; - } - catch - { - return null; - } - }); + protected override bool CheckIPAddressInformation(IPAddressInformation info) + { + return info.Address.AddressFamily == AddressFamily.InterNetworkV6; } } } diff --git a/aliyun-ddns/Options.cs b/aliyun-ddns/Options.cs index a53a69a..4651d01 100644 --- a/aliyun-ddns/Options.cs +++ b/aliyun-ddns/Options.cs @@ -6,28 +6,47 @@ namespace aliyun_ddns public class Options { [Option('u', "access-key-id", Required = false, Default = "access key id", HelpText = "access key id")] - public string AKID { get; set; } = "access key id"; + public string Akid { get; set; } = "access key id"; + [Option('p', "access-key-secret", Required = false, Default = "access key secret", HelpText = "access key secret")] - public string AKSCT { get; set; } = "access key secret"; + public string Aksct { get; set; } = "access key secret"; + //[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 = "需要更新的域名,可以用“,”隔开。")] - public string DOMAIN { get; set; } = "my.domain.com"; + public string Domain { get; set; } = "my.domain.com"; + [Option('i', "interval", Required = false, Default = 300, HelpText = "执行域名更新的间隔,单位秒。")] - public int REDO { get; set; } = 300; + public int Redo { get; set; } = 300; + [Option('t', "ttl", Required = false, Default = 600, HelpText = "服务器缓存解析记录的时长,单位秒。")] public long TTL { get; set; } = 600; + [Option("timezone", Required = false, Default = 8.0, HelpText = "输出日志时的时区,单位小时。")] - public double TIMEZONE { get; set; } = 8; + public double Timezone { get; set; } = 8; + [Option("type", Required = false, Default = "A,AAAA", HelpText = "需要更改的记录类型,可以用“,”隔开,只能是“A”、“AAAA”或“A,AAAA”。")] - public string TYPE { get; set; } = "A,AAAA"; + public string Type { get; set; } = "A,AAAA"; + [Option("cnipv4", Required = false, Default = false, HelpText = "仅使用中国服务器检测公网IPv4地址。")] - public bool CNIPV4 { get; set; } = false; + public bool CNIPv4 { get; set; } = false; + [Option('h',"webhook", Required = false, Default = null, HelpText = "WEB HOOK推送地址。")] - public string WEBHOOK { get; set; } = null; + public string WebHook { get; set; } = null; + + [Option('c', "checklocal", Required = false, Default = false, HelpText = "是否检查本地网卡IP。此选项将禁用在线API的IP检查。")] + public bool CheckLocalNetworkAdaptor { get; set; } = false; + + [Option("ipv4nets", Required = false, Default = null, HelpText = "本地网卡的IPv4网段。格式示例:“192.168.1.0/24”。多个网段用“,”隔开。")] + public string IPv4Networks { get; set; } = null; + + [Option("ipv46nets", Required = false, Default = null, HelpText = "本地网卡的IPv6网段。格式示例:“2001:0db8::/64”。多个网段用“,”隔开。")] + public string IPv6Networks { get; set; } = null; private static Options _instance = null; private static object _instanceLocker = new object(); + public static Options Instance { get @@ -55,17 +74,19 @@ public static Options Instance private void InitOptionsFromEnvironment() { - AKID = GetEnvironmentVariable("AKID") ?? AKID; - AKSCT = GetEnvironmentVariable("AKSCT") ?? AKSCT; + Akid = GetEnvironmentVariable("AKID") ?? Akid; + Aksct = GetEnvironmentVariable("AKSCT") ?? Aksct; //ENDPOINT = GetEnvironmentVariable("ENDPOINT") ?? ENDPOINT; - DOMAIN = GetEnvironmentVariable("DOMAIN") ?? DOMAIN; - TYPE = GetEnvironmentVariable("TYPE") ?? TYPE; - WEBHOOK = GetEnvironmentVariable("WEBHOOK") ?? WEBHOOK; + Domain = GetEnvironmentVariable("DOMAIN") ?? Domain; + Type = GetEnvironmentVariable("TYPE") ?? Type; + WebHook = GetEnvironmentVariable("WEBHOOK") ?? WebHook; + IPv4Networks = GetEnvironmentVariable("IPV4NETS") ?? IPv4Networks; + IPv6Networks = GetEnvironmentVariable("IPV6NETS") ?? IPv6Networks; string redoText = GetEnvironmentVariable("REDO"); if (int.TryParse(redoText, out int redo)) { - REDO = redo; + Redo = redo; } string ttlText = GetEnvironmentVariable("TTL"); @@ -77,17 +98,23 @@ private void InitOptionsFromEnvironment() string tzText = GetEnvironmentVariable("TIMEZONE"); if (double.TryParse(tzText, out double tz)) { - TIMEZONE = tz; + Timezone = tz; } string cnipv4Text = GetEnvironmentVariable("CNIPV4"); if (bool.TryParse(cnipv4Text, out bool cnipv4)) { - CNIPV4 = cnipv4; + CNIPv4 = cnipv4; + } + + string checkLocalNetworkAdaptorText = GetEnvironmentVariable("CHECKLOCAL"); + if (bool.TryParse(checkLocalNetworkAdaptorText, out bool checkLocalNetworkAdaptor)) + { + CheckLocalNetworkAdaptor = checkLocalNetworkAdaptor; } } - private static string GetEnvironmentVariable(string variable) + private static string GetEnvironmentVariable(string variable) { string res = Environment.GetEnvironmentVariable(variable); if (string.IsNullOrEmpty(res)) diff --git a/aliyun-ddns/PublicIpGetter.cs b/aliyun-ddns/PublicIpGetter.cs index 460e4e4..c10fed6 100644 --- a/aliyun-ddns/PublicIpGetter.cs +++ b/aliyun-ddns/PublicIpGetter.cs @@ -21,7 +21,7 @@ public static async Task GetIpv4() try { var dics = IPv4GetterCreator.Create() - .Where(g => Options.Instance.CNIPV4 == false || g.Order < 100) + .Where(g => Options.Instance.CNIPv4 == false || g.Order < 100) .ToDictionary(g => g.GetIP(), g => g.Description); string result = await dics.Keys.WhenAny(task => { diff --git a/aliyun-ddns/WebHook/WebHookAction.cs b/aliyun-ddns/WebHook/WebHookAction.cs index d8562f7..ea13ba0 100644 --- a/aliyun-ddns/WebHook/WebHookAction.cs +++ b/aliyun-ddns/WebHook/WebHookAction.cs @@ -13,7 +13,7 @@ public static class WebHookAction { public static void Push(IEnumerable items) { - string url = Options.Instance.WEBHOOK; + string url = Options.Instance.WebHook; if (string.IsNullOrWhiteSpace(url)) { return; diff --git a/aliyun-ddns/aliyun-ddns.csproj b/aliyun-ddns/aliyun-ddns.csproj index f450552..8597c4d 100644 --- a/aliyun-ddns/aliyun-ddns.csproj +++ b/aliyun-ddns/aliyun-ddns.csproj @@ -83,7 +83,7 @@ Exe netcoreapp3.1 aliyun_ddns - 0.2.5 + 0.2.6 sanjusss https://github.com/sanjusss/aliyun-ddns @@ -91,14 +91,15 @@ git false BSD - 0.2.5.0 - 0.2.5.0 + 0.2.6.0 + 0.2.6.0 Linux +