예제 #1
0
        int OnExecute(CommandLineApplication app, IConsole console)
        {
            var configs = DomainConfigHelper.GetConfigs();

            WriteDomainConfigItemListToConsole(configs, console.Out);

            return(0);
        }
예제 #2
0
        int OnExecute(CommandLineApplication app, IConsole console)
        {
            if (!String.IsNullOrEmpty(Provider) && !ProviderHelper.CheckSupportability(Provider))
            {
                console.Error.WriteLine($"Provider '{Provider}' is not supported.");
                return(1);
            }

            var item = DomainConfigHelper.GetSingle(new DomainConfigItem
            {
                Domain   = Domain,
                Type     = Type ?? DomainRecordType.A,
                Provider = Provider
            });

            if (item == null)
            {
                console.Error.WriteLine("Failed to delete, because there is no such configuration.");
                return(1);
            }

            var confirmMessage = new StringBuilder("Please confirm that you want to delete this record:");

            confirmMessage.AppendLine();
            confirmMessage.AppendLine($"  Domain: {item.Domain}");
            confirmMessage.AppendLine($"  Type: {item.Type}");
            confirmMessage.AppendLine($"  Provider: {item.Provider}");

            if (!Prompt.GetYesNo(confirmMessage.ToString(), defaultAnswer: false))
            {
                console.Out.WriteLine("Operation cancelled.");
                return(1);
            }

            DomainConfigHelper.DeleteItem(item);
            console.Out.WriteLine($"Deleted successfully!");

            return(1);
        }
예제 #3
0
        public override void Sync(SyncContext context)
        {
            var config = DomainConfigHelper.GetProviderInfo <AliyunConfig>(context.DomainConfigItem);

            IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", config.Id, config.Secret);

            var client = new DefaultAcsClient(profile);

            client.SetConnectTimeoutInMilliSeconds(60000);
            client.SetReadTimeoutInMilliSeconds(60000);

            var item = context.DomainConfigItem;

            // 更新解析记录使用的请求,为了便于 catch 时获取相关数据,所以定义在 try 块外面
            UpdateDomainRecordRequest updateRequest = null;

            try
            {
                string recordId;
                string rr;
                string originalIP;

                var domainName       = item.Domain;
                var domainTypeString = item.Type.ToString();

                // 先用获取子域名的 API DescribeSubDomainRecordsRequest 进行尝试,如果查询不到该子域名,再尝试使用 DescribeDomainRecordsRequest 进行根域名查询
                Console.WriteLine($"Try use sub domain api to search. SubDomain = {domainName}, Type = {domainTypeString}");

                var subQueryRequest = new DescribeSubDomainRecordsRequest
                {
                    SubDomain = domainName,
                    Type      = domainTypeString
                };

                var subQueryResponse = client.GetAcsResponse(subQueryRequest);
                if (subQueryResponse.TotalCount > 0)
                {
                    Console.WriteLine("Is sub domain");

                    // 虽然 DescribeSubDomainRecordsRequest 没有问题,安全起见还是过滤一下(具体问题参见后面 DescribeDomainRecordsRequest 的注释)
                    var result = subQueryResponse.DomainRecords.SingleOrDefault(d => d.Type == domainTypeString);
                    recordId   = result?.RecordId;
                    rr         = result?.RR;
                    originalIP = result?._Value;
                }
                else
                {
                    Console.WriteLine($"Not sub domain. Try use root domain api to search. SearchMode = EXACT, KeyWord = @, DomainName = {domainName}, TypeKeyWord = {domainTypeString}, Type = {domainTypeString}");

                    // 由于 Type 和 TypeKeyWord 属性实测没有作用,过滤不了域名类型
                    // 所以得到查询结果后还需要再手动过滤一次
                    var rootQueryRequest = new DescribeDomainRecordsRequest
                    {
                        SearchMode  = "EXACT",
                        DomainName  = domainName,
                        KeyWord     = "@",
                        TypeKeyWord = domainTypeString,
                        Type        = domainTypeString
                    };

                    var rootQueryResponse = client.GetAcsResponse(rootQueryRequest);
                    var result            = rootQueryResponse.DomainRecords.SingleOrDefault(d => d.Type == domainTypeString);
                    recordId   = result?.RecordId;
                    rr         = result?.RR;
                    originalIP = result?._Value;
                }

                Console.WriteLine($"Search succeed: id = {recordId}, RR = {rr}, Value = {originalIP}");

                if (recordId == null)
                {
                    throw new KeyNotFoundException($"Update failed: cannot find a record for the domain name {item.Domain}.");
                }

                var address = IPHelper.GetAddress(item.Interface, item.AddressFamily);
                Console.WriteLine($"Interface {item.Interface} {item.AddressFamily} address is {address}");

                updateRequest = new UpdateDomainRecordRequest
                {
                    RecordId = recordId,
                    RR       = rr,
                    Type     = domainTypeString,
                    _Value   = address
                };

                var updateResponse = client.GetAcsResponse(updateRequest);

                Console.WriteLine($"{item.Domain} updated successfully: {originalIP} -> {address}");

                item.LastSyncStatus            = SyncStatus.Success;
                item.LastSyncSuccessOriginalIP = originalIP;
                item.LastSyncSuccessCurrentIP  = address;
                item.LastSyncSuccessTime       = DateTime.Now;
            }
            catch (ClientException ex)
            {
                // 如果更新时返回了 DomainRecordDuplicate 错误
                // 有可能是本地记录的 LastSyncSuccessCurrentIP 和机器实际的 IP 以及域名解析提供商一侧的地址不匹配
                // 例如有段时间里程序没有执行,但 IP 发生了改变,就会造成 LastSyncSuccessCurrentIP 和提供商处的 IP 地址,以及实际地址不匹配)
                if (ex.ErrorCode == "DomainRecordDuplicate")
                {
                    item.LastSyncStatus = SyncStatus.Ignore;

                    if (updateRequest._Value != item.LastSyncSuccessCurrentIP)
                    {
                        item.LastSyncSuccessCurrentIP = updateRequest?._Value;

                        App.Out.WriteLine($"Update failed because the IP address recorded in the cache does not match the actual IP address and the IP address stored by the provider. The cache record has been updated, you can ignore this prompt.");

                        return;
                    }

                    App.Out.WriteLine($"{ex.ErrorMessage} You can ignore this prompt.");
                }
                else
                {
                    throw;
                }
            }
        }
예제 #4
0
        public static int DoAdd(CommandLineApplication <AddCommandModel> addCmd, ProviderBase providerBase)
        {
            var newConfigItem = new DomainConfigItem
            {
                Domain = addCmd.Model.Domain,
                Type   = addCmd.Model.Type ?? DomainRecordType.A
                         // 为了便于下面 GetSingle() 模糊查询,这里先不对 Provider 赋值
            };

            // 根据 域名+类型 判断,是否有重复的
            var item = DomainConfigHelper.GetSingle(newConfigItem);

            if (item != null)
            {
                addCmd.Error.WriteLine("Failed to add, because the same configuration already exists: ");
                WriteConfigInfoToConsole(item, addCmd.Error);
                addCmd.Error.WriteLine("Only one record can be added for the same domain name and type, even if the provider is different.");

                return(1);
            }

            // 获取网卡信息
            // 如果只有一个网卡,并且用户没有设置 interface 选项,那么该域名就与该网卡绑定,使用该网卡的 IP 地址
            // 如果只有一个网卡,并且用户设置了 interface 选项,先判断可用网卡和用户设置的是否一致,如果一致则使用;不一致则报错
            // 如果有多个网卡,并且用户没有设置 interface 选项,报错
            // 如果有多个网卡,并且用户设置了 interface 选项,判断用户设置的网卡是否可用,如果不可用则报错
            NetworkInterface iface;
            var interfaces = GetAvailableNetworkInterfaces();

            if (!interfaces.Any())
            {
                return(FailedWithAvailableNetworkInterface(addCmd.Error));
            }

            if (!String.IsNullOrEmpty(addCmd.Model.Interface))
            {
                iface = interfaces.SingleOrDefault(i => i.Name == addCmd.Model.Interface);

                if (iface == null)
                {
                    return(FailedWithInterfaceNameNotFound(addCmd.Error));
                }
            }
            else if (interfaces.Count == 1)
            {
                iface = interfaces.Single();

                if (iface.Name != addCmd.Model.Interface)
                {
                    return(FailedWithInterfaceNameNotFound(addCmd.Error));
                }
            }
            else
            {
                return(FailedWithMultipleInterfaceNameFoundButNoSpecify(addCmd.Error));
            }

            // 准备保存数据了,为 Provider 等内容赋值
            newConfigItem.Provider  = addCmd.Model.Provider;
            newConfigItem.Interface = iface.Name;

            // 保存访问 DNS 提供商 API 时需要用到的参数信息
            var providerOptionNames = ProviderHelper.GetProviderOptions(providerBase.GetType()).Select(o => o.LongName);

            newConfigItem.ProviderInfo = addCmd.Options
                                         .Where(o => providerOptionNames.Contains(o.LongName))
                                         .ToDictionary(k => k.LongName, v => String.Join('|', v.Values));

            DomainConfigHelper.AddItem(newConfigItem);
            addCmd.Out.WriteLine($"Added successfully!");

            return(1);
        }