Exemplo n.º 1
0
 public Task <bool> AllowIPAddresses(string ruleNamePrefix, IEnumerable <IPAddressRange> ipAddresses, IEnumerable <PortRange> allowedPorts = null, CancellationToken cancelToken = default)
 {
     lock (this)
     {
         allowRuleRanges[ruleNamePrefix] = new MemoryFirewallRuleRanges(ipAddresses.Select(i => IPAddressRange.Parse(i)).ToList(), allowedPorts?.ToList(), false);
     }
     return(Task.FromResult <bool>(true));
 }
Exemplo n.º 2
0
        private void PopulateList(HashSet <System.Net.IPAddress> set, List <IPAddressRange> ranges, HashSet <string> others, ref Regex regex, string setValue, string regexValue)
        {
            setValue   = (setValue ?? string.Empty).Trim();
            regexValue = (regexValue ?? string.Empty).Replace("*", @"[0-9A-Fa-f:]+?").Trim();
            set.Clear();
            regex = null;

            if (!string.IsNullOrWhiteSpace(setValue))
            {
                foreach (string entry in setValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(e => e.Trim()))
                {
                    string entryWithoutComment = entry;
                    int    pos = entryWithoutComment.IndexOf('?');
                    if (pos >= 0)
                    {
                        entryWithoutComment = entryWithoutComment.Substring(0, pos);
                    }
                    entryWithoutComment = entryWithoutComment.Trim();
                    if (entryWithoutComment != "0.0.0.0" && entryWithoutComment != "::0" && entryWithoutComment != "127.0.0.1" && entryWithoutComment != "::1" && entryWithoutComment != "localhost")
                    {
                        try
                        {
                            if (IPAddressRange.TryParse(entryWithoutComment, out IPAddressRange range))
                            {
                                if (range.Begin.Equals(range.End))
                                {
                                    set.Add(range.Begin);
                                }
                                else if (!ranges.Contains(range))
                                {
                                    ranges.Add(range);
                                }
                            }
                            else
                            {
                                if (dns != null)
                                {
                                    try
                                    {
                                        // add entries for each ip address that matches the dns entry
                                        IPAddress[] addresses = dns.GetHostEntryAsync(entryWithoutComment).Sync().AddressList;
                                        if (addresses != null)
                                        {
                                            foreach (IPAddress adr in addresses)
                                            {
                                                set.Add(adr);
                                            }
                                        }
                                    }
                                    catch
                                    {
                                        // eat exception, nothing we can do
                                        others.Add(entryWithoutComment);
                                    }
                                }
                                else
                                {
                                    // add the entry itself
                                    others.Add(entryWithoutComment);
                                }
                            }
                        }
                        catch (System.Net.Sockets.SocketException)
                        {
                            // ignore, dns lookup fails
                        }
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(regexValue))
            {
                regex = ParseRegex(regexValue);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Check if an ip address range is whitelisted
        /// </summary>
        /// <param name="range">Range</param>
        /// <returns>True if whitelisted, false otherwise</returns>
        public bool IsWhitelisted(IPAddressRange range)
        {
            IPBanConfig config = Config;

            return(config != null && Config.IsWhitelisted(range));
        }
Exemplo n.º 4
0
        public override bool IsIPAddressBlocked(string ipAddress, out string ruleName, int port = -1)
        {
            ruleName = null;

            try
            {
                lock (policy)
                {
                    for (int i = 0; ; i += MaxIpAddressesPerRule)
                    {
                        string firewallRuleName = BlockRulePrefix + i.ToString(CultureInfo.InvariantCulture);
                        try
                        {
                            INetFwRule rule = policy.Rules.Item(firewallRuleName);
                            if (rule is null)
                            {
                                // no more rules to check
                                break;
                            }
                            else
                            {
                                HashSet <string> set = new(rule.RemoteAddresses.Split(',').Select(i2 => IPAddressRange.Parse(i2).Begin.ToString()));
                                if (set.Contains(ipAddress))
                                {
                                    ruleName = firewallRuleName;
                                    return(true);
                                }
                            }
                        }
                        catch
                        {
                            // no more rules to check
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    Logger.Error(ex);
                }
            }
            return(false);
        }
Exemplo n.º 5
0
        // deleteRule will drop the rule and matching set before creating the rule and set, use this is you don't care to update the rule and set in place
        protected bool UpdateRuleDelta(string ruleName, string action, IEnumerable <IPBanFirewallIPAddressDelta> deltas, string hashType,
                                       int maxCount, bool deleteRule, IEnumerable <PortRange> allowPorts, CancellationToken cancelToken)
        {
#if ENABLE_FIREWALL_PROFILING
            Stopwatch timer = Stopwatch.StartNew();
#endif

            string ipFileTemp = OSUtility.Instance.GetTempFileName();
            try
            {
                // add and remove the appropriate ip addresses from the set
                using (StreamWriter writer = File.CreateText(ipFileTemp))
                {
                    if (cancelToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException(cancelToken);
                    }
                    writer.WriteLine($"create {ruleName} hash:{hashType} family {INetFamily} hashsize {hashSize} maxelem {maxCount} -exist");
                    foreach (IPBanFirewallIPAddressDelta delta in deltas)
                    {
                        if (cancelToken.IsCancellationRequested)
                        {
                            throw new OperationCanceledException(cancelToken);
                        }

                        if (IPAddressRange.TryParse(delta.IPAddress, out IPAddressRange range) &&
                            range.Begin.AddressFamily == addressFamily && range.End.AddressFamily == addressFamily)
                        {
                            try
                            {
                                if (delta.Added)
                                {
                                    if (range.Begin.Equals(range.End))
                                    {
                                        writer.WriteLine($"add {ruleName} {range.Begin} -exist");
                                    }
                                    else
                                    {
                                        writer.WriteLine($"add {ruleName} {range.ToCidrString()} -exist");
                                    }
                                }
                                else
                                {
                                    if (range.Begin.Equals(range.End))
                                    {
                                        writer.WriteLine($"del {ruleName} {range.Begin} -exist");
                                    }
                                    else
                                    {
                                        writer.WriteLine($"del {ruleName} {range.ToCidrString()} -exist");
                                    }
                                }
                            }
                            catch
                            {
                                // ignore invalid cidr ranges
                            }
                        }
                    }
                }

                if (cancelToken.IsCancellationRequested)
                {
                    throw new OperationCanceledException(cancelToken);
                }
                else
                {
                    // restore the deltas into the existing set
                    bool result = (RunProcess("ipset", true, $"restore < \"{ipFileTemp}\"") == 0);
                    CreateOrUpdateRule(ruleName, action, hashType, maxCount, allowPorts, cancelToken);
                    return(result);
                }
            }
            finally
            {
                ExtensionMethods.FileDeleteWithRetry(ipFileTemp);

#if ENABLE_FIREWALL_PROFILING
                timer.Stop();
                Logger.Warn("BlockIPAddressesDelta rule '{0}' took {1:0.00}ms with {2} ips",
                            ruleName, timer.Elapsed.TotalMilliseconds, deltas.Count());
#endif
            }
        }
        private void PopulateList(HashSet <System.Net.IPAddress> set,
                                  HashSet <IPAddressRange> ranges,
                                  HashSet <string> others,
                                  ref Regex regex,
                                  string setValue,
                                  string regexValue)
        {
            setValue   = (setValue ?? string.Empty).Trim();
            regexValue = (regexValue ?? string.Empty).Replace("*", @"[0-9A-Fa-f]+?").Trim();
            set.Clear();
            regex = null;

            void AddIPAddressRange(IPAddressRange range)
            {
                if (range.Begin.Equals(range.End))
                {
                    lock (set)
                    {
                        set.Add(range.Begin);
                    }
                }
                else
                {
                    lock (ranges)
                    {
                        ranges.Add(range);
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(setValue))
            {
                List <string> entries = new List <string>();
                foreach (string entry in setValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(e => e.Trim()))
                {
                    string entryWithoutComment = entry;
                    int    pos = entryWithoutComment.IndexOf('?');
                    if (pos >= 0)
                    {
                        entryWithoutComment = entryWithoutComment.Substring(0, pos);
                    }
                    entryWithoutComment = entryWithoutComment.Trim();
                    entries.Add(entryWithoutComment);
                }
                List <Task> entryTasks = new List <Task>();

                // iterate in parallel for performance
                foreach (string entry in entries)
                {
                    string entryWithoutComment = entry;
                    entryTasks.Add(Task.Run(async() =>
                    {
                        bool isUserName;
                        if (entryWithoutComment.StartsWith("user:"******"user:"******"https://", StringComparison.OrdinalIgnoreCase) ||
                                      entryWithoutComment.StartsWith("http://", StringComparison.OrdinalIgnoreCase)))
                            {
                                try
                                {
                                    if (httpRequestMaker != null)
                                    {
                                        // assume url list of ips, newline delimited
                                        byte[] ipListBytes = null;
                                        Uri uri            = new Uri(entryWithoutComment);
                                        await ExtensionMethods.RetryAsync(async() => ipListBytes = await httpRequestMaker.MakeRequestAsync(uri, null, ipListHeaders));
                                        string ipList = Encoding.UTF8.GetString(ipListBytes);
                                        if (!string.IsNullOrWhiteSpace(ipList))
                                        {
                                            foreach (string item in ipList.Split('\n'))
                                            {
                                                if (IPAddressRange.TryParse(item.Trim(), out IPAddressRange ipRangeFromUrl))
                                                {
                                                    AddIPAddressRange(ipRangeFromUrl);
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Logger.Error(ex, "Failed to get ip list from url {0}", entryWithoutComment);
                                }
                            }
                            else if (!isUserName && Uri.CheckHostName(entryWithoutComment) != UriHostNameType.Unknown)
                            {
                                try
                                {
                                    // add entries for each ip address that matches the dns entry
                                    IPAddress[] addresses = null;
                                    await ExtensionMethods.RetryAsync(async() => addresses = await dns.GetHostAddressesAsync(entryWithoutComment),
                                                                      exceptionRetry: _ex =>
                                    {
                                        // ignore host not found errors
                                        return(!(_ex is System.Net.Sockets.SocketException socketEx) ||
                                               socketEx.SocketErrorCode != System.Net.Sockets.SocketError.HostNotFound);
                                    });

                                    lock (set)
                                    {
                                        foreach (IPAddress adr in addresses)
                                        {
                                            set.Add(adr);
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Logger.Debug("Unable to resolve dns for {0}: {1}", entryWithoutComment, ex.Message);

                                    lock (others)
                                    {
                                        // eat exception, nothing we can do
                                        others.Add(entryWithoutComment);
                                    }
                                }
                            }
                            else
                            {
                                lock (others)
                                {
                                    others.Add(entryWithoutComment);
                                }
                            }
                        }
Exemplo n.º 7
0
        /// <summary>
        /// Filter ip address ranges from ranges using filter
        /// </summary>
        /// <param name="ranges">Ip address ranges to filter</param>
        /// <param name="filter">Ip address ranges to filter out of ranges, null for no filtering</param>
        /// <returns>Filtered ip address ranges in sorted order</returns>
        public static IEnumerable <IPAddressRange> FilterRanges(this IEnumerable <IPAddressRange> ranges, IEnumerable <IPAddressRange> filter)
        {
            // if null ranges we are done
            if (ranges is null)
            {
                yield break;
            }

            // if null filter, return ranges as is
            else if (filter is null)
            {
                foreach (IPAddressRange range in ranges.OrderBy(r => r))
                {
                    yield return(range);
                }
                yield break;
            }

            using (IEnumerator <IPAddressRange> rangeEnum = ranges.OrderBy(r => r).GetEnumerator())
                using (IEnumerator <IPAddressRange> filterEnum = filter.OrderBy(r => r).GetEnumerator())
                {
                    // if no ranges left, we are done
                    if (!rangeEnum.MoveNext())
                    {
                        yield break;
                    }

                    IPAddressRange currentFilter = (filterEnum.MoveNext() ? filterEnum.Current : null);
                    IPAddressRange currentRange  = rangeEnum.Current;
                    while (true)
                    {
                        // if no more filter, just continue returning ranges as is
                        if (currentFilter is null)
                        {
                            yield return(currentRange);

                            if (!rangeEnum.MoveNext())
                            {
                                break;
                            }
                            continue;
                        }

                        int compare = currentFilter.Begin.CompareTo(currentRange.End);
                        if (compare > 0)
                        {
                            // current filter begin is after the range end, just return the range as is
                            yield return(currentRange);

                            if (!rangeEnum.MoveNext())
                            {
                                break;
                            }
                            currentRange = rangeEnum.Current;
                        }
                        else
                        {
                            compare = currentFilter.End.CompareTo(currentRange.Begin);

                            // check if the current filter end is before the range begin
                            if (compare < 0)
                            {
                                // current filter end is before the range begin, move to next filter
                                currentFilter = (filterEnum.MoveNext() ? filterEnum.Current : null);
                            }
                            else
                            {
                                // the current filter is inside the current range, filter
                                int compareBegin = currentFilter.Begin.CompareTo(currentRange.Begin);
                                int compareEnd   = currentFilter.End.CompareTo(currentRange.End);
                                if (compareBegin <= 0)
                                {
                                    // filter begin is less than or equal to the range begin
                                    if (compareEnd < 0 && currentFilter.End.TryIncrement(out IPAddress begin))
                                    {
                                        // set the range to have the filtered portion removed
                                        currentRange = new IPAddressRange(begin, currentRange.End);

                                        // move to next filter
                                        currentFilter = (filterEnum.MoveNext() ? filterEnum.Current : currentFilter);
                                    }
                                    else
                                    {
                                        // else the filter has blocked out this entire range, ignore it
                                        if (!rangeEnum.MoveNext())
                                        {
                                            break;
                                        }
                                        currentRange = rangeEnum.Current;
                                    }
                                }
                                else
                                {
                                    // if compareBegin was >= the ip address range begin, we won't get here
                                    // this means the current filter begin must be greater than 0
                                    if (!currentFilter.Begin.TryDecrement(out IPAddress end))
                                    {
                                        throw new InvalidOperationException("Current filter should have been able to decrement the begin ip address");
                                    }

                                    // filter begin is after the range begin, return the range begin and one before the filter begin
                                    yield return(new IPAddressRange(currentRange.Begin, end));

                                    if (!currentFilter.End.TryIncrement(out IPAddress newBegin))
                                    {
                                        newBegin = currentFilter.End;
                                    }

                                    if (newBegin.CompareTo(currentRange.End) > 0)
                                    {
                                        // end of range, get a new range
                                        if (!rangeEnum.MoveNext())
                                        {
                                            break;
                                        }
                                        currentRange = rangeEnum.Current;
                                    }
                                    else
                                    {
                                        currentRange = new IPAddressRange(newBegin, currentRange.End);
                                    }
                                }
                            }
                        }
                    }
                }
        }
Exemplo n.º 8
0
        // deleteRule will drop the rule and matching set before creating the rule and set, use this is you don't care to update the rule and set in place
        protected bool UpdateRule(string ruleName, string action, IEnumerable <string> ipAddresses, string hashType, int maxCount,
                                  IEnumerable <PortRange> allowPorts, CancellationToken cancelToken)
        {
            string ipFileTemp = OSUtility.GetTempFileName();

            try
            {
                // add and remove the appropriate ip addresses from the set
                using (StreamWriter writer = File.CreateText(ipFileTemp))
                {
                    if (cancelToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException(cancelToken);
                    }
                    RunProcess("ipset", true, out IReadOnlyList <string> sets, "-L -n");
                    if (sets.Contains(ruleName))
                    {
                        writer.WriteLine($"flush {ruleName}");// hash:{hashType} family {INetFamily} hashsize {hashSize} maxelem {maxCount} -exist");
                    }
                    writer.WriteLine($"create {ruleName} hash:{hashType} family {INetFamily} hashsize {hashSize} maxelem {maxCount} -exist");
                    foreach (string ipAddress in ipAddresses)
                    {
                        if (cancelToken.IsCancellationRequested)
                        {
                            throw new OperationCanceledException(cancelToken);
                        }

                        if (IPAddressRange.TryParse(ipAddress, out IPAddressRange range) &&
                            range.Begin.AddressFamily == addressFamily && range.End.AddressFamily == addressFamily)
                        {
                            try
                            {
                                if (hashType != hashTypeCidrMask || range.Begin.Equals(range.End))
                                {
                                    writer.WriteLine($"add {ruleName} {range.Begin} -exist");
                                }
                                else
                                {
                                    writer.WriteLine($"add {ruleName} {range.ToCidrString()} -exist");
                                }
                            }
                            catch
                            {
                                // ignore invalid cidr ranges
                            }
                        }
                    }
                }

                if (cancelToken.IsCancellationRequested)
                {
                    throw new OperationCanceledException(cancelToken);
                }
                else
                {
                    // restore the set
                    bool result = (RunProcess("ipset", true, $"restore < \"{ipFileTemp}\"") == 0);
                    CreateOrUpdateRule(ruleName, action, hashType, maxCount, allowPorts, cancelToken);
                    return(result);
                }
            }
            finally
            {
                ExtensionMethods.FileDeleteWithRetry(ipFileTemp);
            }
        }
Exemplo n.º 9
0
        // deleteRule will drop the rule and matching set before creating the rule and set, use this is you don't care to update the rule and set in place
        protected bool UpdateRuleDelta(string ruleName, string action, IEnumerable <IPBanFirewallIPAddressDelta> deltas, string hashType,
                                       int maxCount, bool deleteRule, IEnumerable <PortRange> allowPorts, CancellationToken cancelToken)
        {
            string ipFileTemp = IPBanOS.GetTempFileName();

            try
            {
                // add and remove the appropriate ip addresses from the set
                using (StreamWriter writer = File.CreateText(ipFileTemp))
                {
                    if (cancelToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException(cancelToken);
                    }
                    writer.WriteLine($"create {ruleName} hash:{hashType} family {INetFamily} hashsize {hashSize} maxelem {maxCount} -exist");
                    foreach (IPBanFirewallIPAddressDelta delta in deltas)
                    {
                        if (cancelToken.IsCancellationRequested)
                        {
                            throw new OperationCanceledException(cancelToken);
                        }

                        if (IPAddressRange.TryParse(delta.IPAddress, out IPAddressRange range) &&
                            range.Begin.AddressFamily == addressFamily && range.End.AddressFamily == addressFamily)
                        {
                            try
                            {
                                if (delta.Added)
                                {
                                    if (range.Begin.Equals(range.End))
                                    {
                                        writer.WriteLine($"add {ruleName} {range.Begin} -exist");
                                    }
                                    else
                                    {
                                        writer.WriteLine($"add {ruleName} {range.ToCidrString()} -exist");
                                    }
                                }
                                else
                                {
                                    if (range.Begin.Equals(range.End))
                                    {
                                        writer.WriteLine($"del {ruleName} {range.Begin} -exist");
                                    }
                                    else
                                    {
                                        writer.WriteLine($"del {ruleName} {range.ToCidrString()} -exist");
                                    }
                                }
                            }
                            catch
                            {
                                // ignore invalid cidr ranges
                            }
                        }
                    }
                }

                if (cancelToken.IsCancellationRequested)
                {
                    throw new OperationCanceledException(cancelToken);
                }
                else
                {
                    // restore the deltas into the existing set
                    bool result = (RunProcess("ipset", true, $"restore < \"{ipFileTemp}\"") == 0);
                    CreateOrUpdateRule(ruleName, action, hashType, maxCount, allowPorts, cancelToken);
                    return(result);
                }
            }
            finally
            {
                IPBanExtensionMethods.FileDeleteWithRetry(ipFileTemp);
            }
        }
Exemplo n.º 10
0
        private void PopulateList(HashSet <System.Net.IPAddress> set,
                                  HashSet <IPAddressRange> ranges,
                                  HashSet <string> others,
                                  ref Regex regex,
                                  string setValue,
                                  string regexValue)
        {
            setValue   = (setValue ?? string.Empty).Trim();
            regexValue = (regexValue ?? string.Empty).Replace("*", @"[0-9A-Fa-f:]+?").Trim();
            set.Clear();
            regex = null;

            if (!string.IsNullOrWhiteSpace(setValue))
            {
                foreach (string entry in setValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(e => e.Trim()))
                {
                    string entryWithoutComment = entry;
                    int    pos = entryWithoutComment.IndexOf('?');
                    if (pos >= 0)
                    {
                        entryWithoutComment = entryWithoutComment.Substring(0, pos);
                    }
                    entryWithoutComment = entryWithoutComment.Trim();
                    if (!ignoreListEntries.Contains(entryWithoutComment))
                    {
                        if (IPAddressRange.TryParse(entryWithoutComment, out IPAddressRange range))
                        {
                            if (range.Begin.Equals(range.End))
                            {
                                set.Add(range.Begin);
                            }
                            else
                            {
                                ranges.Add(range);
                            }
                        }
                        else if (Uri.CheckHostName(entryWithoutComment) != UriHostNameType.Unknown)
                        {
                            try
                            {
                                // add entries for each ip address that matches the dns entry
                                IPAddress[] addresses = null;
                                ExtensionMethods.Retry(() => addresses = dns.GetHostAddressesAsync(entryWithoutComment).Sync());
                                foreach (IPAddress adr in addresses)
                                {
                                    set.Add(adr);
                                }
                            }
                            catch (Exception ex)
                            {
                                Logger.Error(ex, "Unable to resolve dns for {0}", entryWithoutComment);

                                // eat exception, nothing we can do
                                others.Add(entryWithoutComment);
                            }
                        }
                        else
                        {
                            others.Add(entryWithoutComment);
                        }
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(regexValue))
            {
                regex = ParseRegex(regexValue);
            }
        }