예제 #1
0
        public void TestComplexRule()
        {
            RulesChecker.RulesCheckerResult result;
            NetworkInfo networkInfo;
            AutoProxySwitcherLib.NetworkChangeDetector ncd = new NetworkChangeDetector();
            ncd.LoadConfigurations("Samples/ComplexRule.xml");

            NetworkInfo ni = new NetworkInfo();
            ni.Description = "Test Network";
            ni.DNS = new List<string> { "192.168.1.252" };
            ni.IP = new List<string> { "192.168.1.254" };
            ni.NetworkIP = new List<string> { "192.168.0.0/16" };
            ni.Type = "Wi-Fi";
            ni.IfName = "Test1";

            List<NetworkInfo> networks = new List<NetworkInfo> { ni };

            NetworkConfiguration configuration = ncd.FindMatchingConfiguration(networks, out result, out networkInfo);

            if (result != null)
            {
                Console.WriteLine(result.ReasonString);
            }
            Console.WriteLine("Test");
            Assert.AreSame(configuration, ncd.Configurations[0]);
            //Assert.IsTrue(result.ReasonString.Equals("network DNS matches 192.168.1.252"));
        }
예제 #2
0
        public void TestManyConfigs()
        {
            AutoProxySwitcherLib.NetworkChangeDetector ncd = new NetworkChangeDetector();
            RulesChecker.RulesCheckerResult result;
            NetworkInfo networkInfo;
            ncd.LoadConfigurations("Samples/ManyConfigs.xml");

            NetworkInfo ni = new NetworkInfo();
            ni.Description = "Test Network";
            ni.DNS = new List<string> { "172.17.4.80", "172.17.4.81" };
            ni.IP = new List<string> { "172.17.4.145" };
            ni.NetworkIP = new List<string> { "172.17.4.0/24" };
            ni.Type = "Local Area Connection";
            ni.IfName = "test";

            List<NetworkInfo> networks;
            NetworkConfiguration configuration;

            networks = new List<NetworkInfo> { ni };
            configuration = ncd.FindMatchingConfiguration(networks, out result, out networkInfo);

            Console.WriteLine(result.ReasonString);
            Console.WriteLine(configuration.ProxySettings);
            Assert.AreEqual(configuration.Name, "Config 1");
            Assert.IsTrue(result.ReasonString.Equals("network subnet matches 172.17.4.0/24"));

            ni.Description = "Test Network";
            ni.DNS = new List<string> { "172.17.80.80", "172.17.80.81" };
            ni.IP = new List<string> { "172.17.80.15" };
            ni.NetworkIP = new List<string> { "172.17.80.0/24" };
            ni.Type = "Local Area Connection";
            ni.IfName = "test";

            networks = new List<NetworkInfo> { ni };
            configuration = ncd.FindMatchingConfiguration(networks, out result, out networkInfo);

            Console.WriteLine(result.ReasonString);
            Console.WriteLine(configuration.ProxySettings);
            Assert.AreEqual(configuration.Name, "Config 4");
            Assert.IsTrue(result.ReasonString.Equals("network subnet matches 172.17.80.0/24"));

            ni.Description = "Test Network";
            ni.DNS = new List<string> { "172.16.0.5" };
            ni.IP = new List<string> { "172.16.0.78" };
            ni.NetworkIP = new List<string> { "172.16.2/24" };
            ni.Type = "Local Area Connection";
            ni.IfName = "test";

            networks = new List<NetworkInfo> { ni };
            configuration = ncd.FindMatchingConfiguration(networks, out result, out networkInfo);

            Console.WriteLine(result.ReasonString);
            Console.WriteLine(configuration.ProxySettings);
            Assert.AreEqual(configuration.Name, "Default Config");
            Assert.IsTrue(result.ReasonString.Equals("default rule match"));
        }
예제 #3
0
        /// <summary>
        /// Default constructor, only for design mode
        /// </summary>
        public MainViewModel()
        {
            if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                // Generate some configurations
                _configurationsList = new List<NetworkConfiguration>();

                NetworkRulesSet rulesSet = new NetworkRulesSet();
                rulesSet.Rules.Add(new AutoProxySwitcherLib.Rules.NetworkRuleDNS("10.0.0.1"));

                for (int i = 0; i < 5; i++)
                {
                    _configurationsList.Add(new NetworkConfiguration("Config #" + i, rulesSet, new StandardProxySettings("http://test:8080", null, null)));
                }

                _activeConfiguration = _configurationsList[2];

                // Generate some networks
                for(int i = 0; i < 10; i++)
                {
                    _currentNetworks.Add(new NetworkInfo() { IfName = "Sample Network #" + i, IP = { "10.0.0.1" }, DNS = { "10.0.0.5" }, NetworkIP = { "10.0.0.0/24" } });
                }

                _currentNetwork = _currentNetworks[3];
                _currentProxySettings = _activeConfiguration.ProxySettings;

                //
                reason = "Network matching IP x.y.z.t";
            }
            else
            {
                string rulesFile = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData)
                    + "\\AutoProxySwitcher\\"
                    + Environment.ExpandEnvironmentVariables(System.Configuration.ConfigurationManager.AppSettings["RulesFile"]);

                // Create default rules files if it doesn't exists
                if (!System.IO.File.Exists(rulesFile))
                {
                    System.IO.File.Copy("Examples/rules.xml", rulesFile);
                }

                // Load configurations
                _networkChangeDetector = new NetworkChangeDetector();
                _networkChangeDetector.ProxyChanged += _networkChangeDetector_ProxyChanged;
                _networkChangeDetector.LoadConfigurations(rulesFile);

                _configurationsList = _networkChangeDetector.Configurations;

                // Init commands relay
                DebugCommand = new RelayCommand<string>(m => MessageBox.Show("toto: " + m));
                SetConfigurationCommand = new RelayCommand<string>((conf) => _networkChangeDetector.SetConfiguration(conf));
                AutoDetectCommand = new RelayCommand(() => _networkChangeDetector.SetConfiguration(null));
                ExitCommand = new RelayCommand(() => { Messenger.Default.Send<ExitMessage>(new ExitMessage()); });
            }
        }
예제 #4
0
        /// <summary>
        /// Find rule matching the given network informations
        /// </summary>
        /// <param name="net">Network information</param>
        /// <returns>Result containing reason of match</returns>
        public RulesCheckerResult CheckRulesAgainstNetwork(NetworkInfo net)
        {
            // Si aucune règle, alors ça matche automatiquement
            if (m_NetworkRulesSet.Rules.Count == 0)
            {
                return new RulesCheckerResult(Reasons.DEFAULT, "default rule match");
            }

            // Parcourir les règles de détection
            RulesCheckerResult res = new RulesCheckerResult(Reasons.NOMATCH, "");
            bool result = CheckRuleAgainstNetwork(m_NetworkRulesSet, net, ref res);
            return res;
        }
예제 #5
0
        /// <summary>
        /// Find rule matching the given network informations
        /// </summary>
        /// <param name="net">Network information</param>
        /// <returns>Result containing reason of match</returns>
        public RulesCheckerResult CheckRulesAgainstNetwork(NetworkInfo net)
        {
            // Si aucune règle, alors ça matche automatiquement
            if (m_NetworkRulesSet.Rules.Count == 0)
            {
                return(new RulesCheckerResult(Reasons.DEFAULT, "default rule match"));
            }

            // Parcourir les règles de détection
            RulesCheckerResult res = new RulesCheckerResult(Reasons.NOMATCH, "");
            bool result            = CheckRuleAgainstNetwork(m_NetworkRulesSet, net, ref res);

            return(res);
        }
예제 #6
0
        /// <summary>
        /// Returns a list of available connected networks. The network address is given in text format: "a.b.c.d/bits"
        /// This list is build from the list of main IPs of each network interface
        /// </summary>
        /// <returns></returns>
        public static IList <NetworkInfo> ListAvailableNetworks()
        {
            List <NetworkInfo> networks = new List <NetworkInfo>();

            NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();

            foreach (NetworkInterface n in adapters)
            {
                NetworkInfo net = new NetworkInfo();

                if (n.OperationalStatus == OperationalStatus.Up)
                {
                    // Stores basic attributes
                    net.IfName      = n.Name;
                    net.Description = n.Description;
                    net.Type        = n.NetworkInterfaceType.ToString();

                    // Stores interface address and network address
                    // Sometimes, it lacks masks (ex: loopback)
                    foreach (UnicastIPAddressInformation uipai in n.GetIPProperties().UnicastAddresses)
                    {
                        // Adds IP address
                        net.IP.Add(uipai.Address.ToString());

                        // Adds network IP adress with netmask
                        if (uipai.IPv4Mask != null && uipai.IPv4Mask.ToString() != "0.0.0.0")
                        {
                            net.NetworkIP.Add(GetNetworkAddressAsString(uipai.Address, uipai.IPv4Mask));
                        }
                    }

                    // Order addresses by length (shortest first)
                    net.IP = net.IP.OrderBy((s) => s.Length).ToList();

                    foreach (System.Net.IPAddress ipAddress in n.GetIPProperties().DnsAddresses)
                    {
                        net.DNS.Add(ipAddress.ToString());
                    }

                    networks.Add(net);
                }
            }

            return(networks);
        }
예제 #7
0
        /// <summary>
        /// Sets proxy according to current available networks and configurations rules
        /// </summary>
        private void SetProxyAccordingToNetwork(string configName)
        {
            if (configName != null)
            {
                log.Info("Set configuration " + configName);

                NetworkConfiguration configuration = m_configurations.Find((c) => c.Name == configName);
                configuration.ProxySettings.Configure();

                // Evénement
                if (ProxyChanged != null)
                {
                    ProxyChanged(configName, null, configuration.ProxySettings, "Setting forced");
                }
            }
            else
            {
                NetworkInfo                     matchingNetwork       = null;
                NetworkConfiguration            matchingConfiguration = null;
                RulesChecker.RulesCheckerResult result = new RulesChecker.RulesCheckerResult();

                // Get current networks
                IList <NetworkInfo> currentNetworks = NetworkManager.ListAvailableNetworks();
                _currentNetworks = currentNetworks;
                foreach (var networkInfo in currentNetworks)
                {
                    log.Debug("Network " + networkInfo);
                }

                // Find matching configuration
                matchingConfiguration = FindMatchingConfiguration(currentNetworks, out result, out matchingNetwork);

                // Configurer le configuration en conséquence
                if (matchingConfiguration != null)
                {
                    matchingConfiguration.ProxySettings.Configure();
                }

                // Evénement
                if (ProxyChanged != null)
                {
                    ProxyChanged(matchingConfiguration.Name, result.Reason != Reasons.DEFAULT ? matchingNetwork : null, matchingConfiguration.ProxySettings, result.ReasonString);
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Returns a list of available connected networks. The network address is given in text format: "a.b.c.d/bits"
        /// This list is build from the list of main IPs of each network interface
        /// </summary>
        /// <returns></returns>
        public static IList<NetworkInfo> ListAvailableNetworks()
        {
            List<NetworkInfo> networks = new List<NetworkInfo>();
            NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();

            foreach (NetworkInterface n in adapters)
            {
                NetworkInfo net = new NetworkInfo();

                if (n.OperationalStatus == OperationalStatus.Up)
                {
                    // Stores basic attributes
                    net.IfName = n.Name;
                    net.Description = n.Description;
                    net.Type = n.NetworkInterfaceType.ToString();

                    // Stores interface address and network address
                    // Sometimes, it lacks masks (ex: loopback)
                    foreach (UnicastIPAddressInformation uipai in n.GetIPProperties().UnicastAddresses)
                    {
                        // Adds IP address
                        net.IP.Add(uipai.Address.ToString());

                        // Adds network IP adress with netmask
                        if (uipai.IPv4Mask != null && uipai.IPv4Mask.ToString() != "0.0.0.0")
                        {
                            net.NetworkIP.Add(GetNetworkAddressAsString(uipai.Address, uipai.IPv4Mask));
                        }
                    }

                    // Order addresses by length (shortest first)
                    net.IP = net.IP.OrderBy((s) => s.Length).ToList();

                    foreach (System.Net.IPAddress ipAddress in n.GetIPProperties().DnsAddresses)
                    {
                        net.DNS.Add(ipAddress.ToString());
                    }

                    networks.Add(net);
                }
            }

            return networks;
        }
        /// <summary>
        /// Returns the configuration that matches the given network
        /// </summary>
        /// <param name="configurations"></param>
        public NetworkConfiguration FindMatchingConfiguration(IList<NetworkInfo> networks, out RulesChecker.RulesCheckerResult result, out NetworkInfo matchingNetwork)
        {
            int countMatches = 0;
            NetworkConfiguration matchingConfiguration = null;
            result = null;
            matchingNetwork = null;

            // Check each configuration
            foreach (NetworkConfiguration configuration in m_configurations)
            {
                using (log4net.ThreadContext.Stacks["NDC"].Push(String.Format("config {0}", configuration.Name)))
                {
                    log.InfoFormat("Checking config {0}", configuration.Name);

                    // Check each network
                    foreach (NetworkInfo net in networks)
                    {
                        log.InfoFormat("Checking network: {0} (IP: {1}, DNS: {2})", net.IfName, string.Join(",", net.NetworkIP), string.Join(",", net.DNS));

                        RulesChecker rc = new RulesChecker(configuration.NetworkRulesSet);

                        RulesChecker.RulesCheckerResult tempResult = rc.CheckRulesAgainstNetwork(net);
                        if (tempResult.Match)
                        {
                            log.InfoFormat("Match #{1}: config {0}", configuration.Name, countMatches + 1);

                            if (countMatches == 0)
                            {
                                result = tempResult;
                                matchingConfiguration = configuration;
                                matchingNetwork = net;
                            }

                            countMatches++;
                        }
                    }
                }
            }

            return matchingConfiguration;
        }
예제 #10
0
        /// <summary>
        /// Checks (recursively) if a rule matches a given network information
        /// </summary>
        /// <param name="rule">Rule to check</param>
        /// <param name="net">Network information</param>
        /// <param name="res">Detailed result if match</param>
        /// <returns>true if rule matches</returns>
        private bool CheckRuleAgainstNetwork(NetworkRule rule, NetworkInfo net, ref RulesCheckerResult res)
        {
            if (rule is NetworkRulesSet)
            {
                bool thisRes = false;
                foreach (var rule2 in (rule as NetworkRulesSet).Rules)
                {
                    thisRes = CheckRuleAgainstNetwork(rule2, net, ref res);
                    if ((rule as NetworkRulesSet).Op == Operator.And && !thisRes)
                    {
                        thisRes = false; break;
                    }
                    if ((rule as NetworkRulesSet).Op == Operator.Or && thisRes)
                    {
                        thisRes = true; break;
                    }
                    if ((rule as NetworkRulesSet).Op == Operator.Not)
                    {
                        thisRes = !thisRes; break;
                    }
                }

                res = new RulesCheckerResult(thisRes ? Reasons.MATCH : Reasons.NOMATCH, res != null ? res.ReasonString : "complex rule used");
                return(thisRes);
            }
            else if (rule is NetworkRuleDNS)
            {
                foreach (string dns in net.DNS)
                {
                    if ((rule as NetworkRuleDNS).DNS == dns)
                    {
                        res = new RulesCheckerResult(Reasons.MATCH, "network DNS matches " + dns);
                        return(true);
                    }
                }
            }
            else if (rule is NetworkRuleSubnet)
            {
                foreach (string ip in net.NetworkIP)
                {
                    if ((rule as NetworkRuleSubnet).Subnet == ip)
                    {
                        res = new RulesCheckerResult(Reasons.MATCH, "network subnet matches " + ip);
                        return(true);
                    }
                }
            }
            else if (rule is NetworkRuleIfName)
            {
                string regex = (rule as NetworkRuleIfName).InterfaceName;

                if (Regex.IsMatch(net.IfName, regex))
                {
                    res = new RulesCheckerResult(Reasons.MATCH, "interface name matches " + regex);
                    return(true);
                }
            }
            else if (rule is NetworkRulePingable)
            {
                string ip = (rule as NetworkRulePingable).IP;

                log.Debug("Pinging " + ip);
                System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
                var reply = ping.Send(ip, 5000);
                log.Info("Ping status: " + reply.Status);
                if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
                {
                    res = new RulesCheckerResult(Reasons.MATCH, "machine " + ip + " is pingable");
                    return(true);
                }
            }
            return(false);
        }
예제 #11
0
        /// <summary>
        /// Returns the configuration that matches the given network
        /// </summary>
        /// <param name="configurations"></param>
        public NetworkConfiguration FindMatchingConfiguration(IList <NetworkInfo> networks, out RulesChecker.RulesCheckerResult result, out NetworkInfo matchingNetwork)
        {
            int countMatches = 0;
            NetworkConfiguration matchingConfiguration = null;

            result          = null;
            matchingNetwork = null;

            // Check each configuration
            foreach (NetworkConfiguration configuration in m_configurations)
            {
                using (log4net.ThreadContext.Stacks["NDC"].Push(String.Format("config {0}", configuration.Name)))
                {
                    log.InfoFormat("Checking config {0}", configuration.Name);

                    // Check each network
                    foreach (NetworkInfo net in networks)
                    {
                        log.InfoFormat("Checking network: {0} (IP: {1}, DNS: {2})", net.IfName, string.Join(",", net.NetworkIP), string.Join(",", net.DNS));

                        RulesChecker rc = new RulesChecker(configuration.NetworkRulesSet);

                        RulesChecker.RulesCheckerResult tempResult = rc.CheckRulesAgainstNetwork(net);
                        if (tempResult.Match)
                        {
                            log.InfoFormat("Match #{1}: config {0}", configuration.Name, countMatches + 1);

                            if (countMatches == 0)
                            {
                                result = tempResult;
                                matchingConfiguration = configuration;
                                matchingNetwork       = net;
                            }

                            countMatches++;
                        }
                    }
                }
            }

            return(matchingConfiguration);
        }
예제 #12
0
        void _networkChangeDetector_ProxyChanged(string name, NetworkInfo networkInfo, ProxySettings proxySettings, string reason)
        {
            try
            {
                log.DebugFormat("ProxyChanged event: {0}, network {1}, proxy {2}, reason", name, networkInfo, proxySettings, reason);

                lastUpdateTime = DateTime.Now;
                _activeConfiguration = _configurationsList.First((c) => c.Name == name);
                this.interfaceName = networkInfo != null ? networkInfo.IfName : "N/A";
                this.addresses = networkInfo != null ? String.Join(", ", networkInfo.IP) : "";
                this.reason = reason;
                _currentNetworks = _networkChangeDetector.CurrentNetworks;
                _currentNetwork = networkInfo != null ? _currentNetworks.FirstOrDefault((n) => networkInfo.IfName == n.IfName) : null;
                _currentProxySettings = proxySettings;

                RaisePropertyChanged("LastUpdateTime");
                RaisePropertyChanged("ActiveConfiguration");
                RaisePropertyChanged("InterfaceName");
                RaisePropertyChanged("Addresses");
                RaisePropertyChanged("Reason");
                RaisePropertyChanged("CurrentNetworks");
                RaisePropertyChanged("CurrentNetwork");
                RaisePropertyChanged("CurrentProxySettings");

                log.Debug("Sending ChangeMessage");
                ChangeMessage msg = new ChangeMessage() { ConfName = name, Network = networkInfo, ProxySettings = proxySettings, Reason = reason };
                Messenger.Default.Send<ChangeMessage>(msg);
            }
            catch (Exception ex)
            {
                log.Error("Failure", ex);
            }
        }
예제 #13
0
        private void m_networkChangeDetector_ProxyChanged(string name, NetworkInfo networkInfo, ProxySettings proxySettings, string reason)
        {
            string info;
            string detailedInfo;

            log.Info("Proxy Changed");

            // Afficher tooltip indiquant disponibilité
            if (networkInfo != null && proxySettings != null)
            {
                info = String.Format("Configuration \"{0}\" available\nInterface name: {1}\nReason: {2}", name, networkInfo.IfName, reason);
                m_notifyIcon.BalloonTipIcon = ToolTipIcon.Info;
            }
            else if (networkInfo == null)
            {
                info = String.Format("Configuration \"{0}\" available\nReason: {1}", name, reason);
                m_notifyIcon.BalloonTipIcon = ToolTipIcon.Info;
            }
            else
            {
                info = String.Format("No rule found, no change");
                m_notifyIcon.BalloonTipIcon = ToolTipIcon.Warning;
            }

            m_notifyIcon.BalloonTipText = info;

            Assembly assembly = Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            string version = fvi.FileVersion;

            detailedInfo = "V" + fvi.FileVersion;
            detailedInfo += "\n\nUpdate date: " + System.DateTime.Now;
            detailedInfo += "\n\n" + info;

            if (networkInfo != null)
            {
                detailedInfo += "\n\nNetwork details: ";
                detailedInfo += "\n  Interface name: " + networkInfo.IfName;
                detailedInfo += "\n  Type: " + networkInfo.Type;
                detailedInfo += "\n  Description: " + networkInfo.Description;
                detailedInfo += "\n  IP(s): " + String.Join(", ", networkInfo.IP);
                detailedInfo += "\n  Network(s): " + String.Join(", ", networkInfo.NetworkIP);
                detailedInfo += "\n  DNS: " + String.Join(", ", networkInfo.DNS);
            }

            if (proxySettings != null)
            {
                detailedInfo += "\n\nProxy details: ";
                detailedInfo += "\n  " + proxySettings;
            }

            if (InvokeRequired)
            {
                UIA(() => m_statusForm.Status = detailedInfo);
            }
            else
            {
                m_statusForm.Status = detailedInfo;
            }

            m_notifyIcon.ShowBalloonTip(3000);
        }
예제 #14
0
        /// <summary>
        /// Checks (recursively) if a rule matches a given network information
        /// </summary>
        /// <param name="rule">Rule to check</param>
        /// <param name="net">Network information</param>
        /// <param name="res">Detailed result if match</param>
        /// <returns>true if rule matches</returns>
        private bool CheckRuleAgainstNetwork(NetworkRule rule, NetworkInfo net, ref RulesCheckerResult res)
        {
            if (rule is NetworkRulesSet)
            {
                bool thisRes = false;
                foreach (var rule2 in (rule as NetworkRulesSet).Rules)
                {
                    thisRes = CheckRuleAgainstNetwork(rule2, net, ref res);
                    if ((rule as NetworkRulesSet).Op == Operator.And && !thisRes) { thisRes = false; break; }
                    if ((rule as NetworkRulesSet).Op == Operator.Or && thisRes) { thisRes = true; break; }
                    if ((rule as NetworkRulesSet).Op == Operator.Not) { thisRes = !thisRes; break; }
                }

                res = new RulesCheckerResult(thisRes ? Reasons.MATCH : Reasons.NOMATCH, res != null ? res.ReasonString : "complex rule used");
                return thisRes;
            }
            else if (rule is NetworkRuleDNS)
            {
                foreach (string dns in net.DNS)
                {
                    if ((rule as NetworkRuleDNS).DNS == dns)
                    {
                        res = new RulesCheckerResult(Reasons.MATCH, "network DNS matches " + dns);
                        return true;
                    }
                }
            }
            else if (rule is NetworkRuleSubnet)
            {
                foreach (string ip in net.NetworkIP)
                {
                    if ((rule as NetworkRuleSubnet).Subnet == ip)
                    {
                        res = new RulesCheckerResult(Reasons.MATCH, "network subnet matches " + ip);
                        return true;
                    }
                }
            }
            else if (rule is NetworkRuleIfName)
            {
                string regex = (rule as NetworkRuleIfName).InterfaceName;

                if (Regex.IsMatch(net.IfName, regex))
                {
                    res = new RulesCheckerResult(Reasons.MATCH, "interface name matches " + regex);
                    return true;
                }
            }
            else if (rule is NetworkRulePingable)
            {
                string ip = (rule as NetworkRulePingable).IP;

                log.Debug("Pinging " + ip);
                System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
                var reply = ping.Send(ip, 5000);
                log.Info("Ping status: " + reply.Status);
                if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
                {
                    res = new RulesCheckerResult(Reasons.MATCH, "machine " + ip + " is pingable");
                    return true;
                }
            }
            return false;
        }