예제 #1
0
        protected bool CreateOrUpdateRule(string ruleName, string action, string hashType, int maxCount, IEnumerable <PortRange> allowedPorts, CancellationToken cancelToken)
        {
            if (cancelToken.IsCancellationRequested)
            {
                throw new OperationCanceledException(cancelToken);
            }

            PortRange[] allowedPortsArray = allowedPorts?.ToArray();

            // create or update the rule in iptables
            RunProcess(IpTablesProcess, true, out IReadOnlyList <string> lines, "-L --line-numbers");
            string portString = " ";
            bool   replaced   = false;
            bool   block      = (action == "DROP");

            if (allowedPortsArray != null && allowedPortsArray.Length != 0)
            {
                string portList = (block ? IPBanFirewallUtility.GetBlockPortRangeString(allowedPorts) :
                                   IPBanFirewallUtility.GetPortRangeStringAllow(allowedPorts));
                portString = " -m multiport -p tcp --dports " + portList.Replace('-', ':') + " "; // iptables uses ':' instead of '-' for range
            }

            string ruleNameWithSpaces = " " + ruleName + " ";

            foreach (string line in lines)
            {
                if (line.Contains(ruleNameWithSpaces, StringComparison.OrdinalIgnoreCase))
                {
                    // rule number is first piece of the line
                    int index   = line.IndexOf(' ');
                    int ruleNum = int.Parse(line[..index]);
예제 #2
0
        protected bool CreateOrUpdateRule(string ruleName, string action, string hashType, int maxCount, IEnumerable <PortRange> allowedPorts, CancellationToken cancelToken)
        {
            if (cancelToken.IsCancellationRequested)
            {
                throw new OperationCanceledException(cancelToken);
            }

            PortRange[] allowedPortsArray = allowedPorts?.ToArray();

            // create or update the rule in iptables
            RunProcess(IpTablesProcess, true, out IReadOnlyList <string> lines, "-L --line-numbers");
            string portString = " ";
            bool   replaced   = false;
            bool   block      = (action == "DROP");

            if (allowedPortsArray != null && allowedPortsArray.Length != 0)
            {
                string portList = (block ? IPBanFirewallUtility.GetBlockPortRangeString(allowedPorts) :
                                   IPBanFirewallUtility.GetPortRangeStringAllow(allowedPorts));
                portString = " -m multiport -p tcp --dports " + portList.Replace('-', ':') + " "; // iptables uses ':' instead of '-' for range
            }

            string ruleNameWithSpaces = " " + ruleName + " ";

            foreach (string line in lines)
            {
                if (line.Contains(ruleNameWithSpaces, StringComparison.OrdinalIgnoreCase))
                {
                    // rule number is first piece of the line
                    int index   = line.IndexOf(' ');
                    int ruleNum = int.Parse(line.Substring(0, index));

                    // replace the rule with the new info
                    RunProcess(IpTablesProcess, true, $"-R INPUT {ruleNum} -m state --state NEW -m set{portString}--match-set \"{ruleName}\" src -j {action}");
                    replaced = true;
                    break;
                }
            }
            if (!replaced)
            {
                // add a new rule, for block add to end of list (lower priority) for allow add to begin of list (higher priority)
                string addCommand = (block ? "-A" : "-I");
                RunProcess(IpTablesProcess, true, $"{addCommand} INPUT -m state --state NEW -m set{portString}--match-set \"{ruleName}\" src -j {action}");
            }

            if (cancelToken.IsCancellationRequested)
            {
                throw new OperationCanceledException(cancelToken);
            }

            SaveTableToDisk();

            return(true);
        }
예제 #3
0
            public MemoryFirewallRuleRanges(IEnumerable <IPAddressRange> ipRanges, List <PortRange> allowedPorts, bool block, string name)
            {
                List <IPAddressRange> ipRangesSorted = new List <IPAddressRange>(ipRanges);

                ipRangesSorted.Sort();
                allowedPorts ??= emptyPortRanges;
                Block = block;
                Name  = name;
                foreach (IPAddressRange range in ipRangesSorted)
                {
                    // optimized storage, no pointers or other overhead
                    if (range.Begin.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        uint begin = range.Begin.ToUInt32();
                        uint end   = range.End.ToUInt32();
                        Debug.Assert(end >= begin);
                        ipv4.Add(new IPV4Range {
                            Begin = begin, End = end
                        });
                    }
                    else
                    {
                        UInt128 begin = range.Begin.ToUInt128();
                        UInt128 end   = range.End.ToUInt128();
                        Debug.Assert(end.CompareTo(begin) >= 0);
                        ipv6.Add(new IPV6Range {
                            Begin = begin, End = end
                        });
                    }
                }
                ipv4.TrimExcess();
                ipv6.TrimExcess();
                if (block)
                {
                    string portString = IPBanFirewallUtility.GetBlockPortRangeString(allowedPorts);
                    this.portRanges = (string.IsNullOrWhiteSpace(portString) ? new List <PortRange>(0) : portString.Split(',').Select(s => PortRange.Parse(s)).ToList());
                }
                else
                {
                    this.portRanges = allowedPorts;
                }
            }
예제 #4
0
        private bool GetOrCreateRule(string ruleName, string remoteIPAddresses, NET_FW_ACTION_ action, IEnumerable <PortRange> allowedPorts = null)
        {
            remoteIPAddresses = (remoteIPAddresses ?? string.Empty).Trim();
            bool emptyIPAddressString = string.IsNullOrWhiteSpace(remoteIPAddresses) || remoteIPAddresses == "*";
            bool ruleNeedsToBeAdded   = false;

            lock (policy)
            {
recreateRule:
                INetFwRule rule = null;
                try
                {
                    rule = policy.Rules.Item(ruleName);
                }
                catch
                {
                    // ignore exception, assume does not exist
                }
                if (rule is null)
                {
                    rule                = Activator.CreateInstance(ruleType) as INetFwRule;
                    rule.Name           = ruleName;
                    rule.Enabled        = true;
                    rule.Action         = action;
                    rule.Description    = "Automatically created by IPBan";
                    rule.Direction      = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
                    rule.EdgeTraversal  = false;
                    rule.Grouping       = "IPBan";
                    rule.LocalAddresses = "*";
                    rule.Profiles       = int.MaxValue; // all
                    ruleNeedsToBeAdded  = true;
                }

                // do not ever set an empty string, Windows treats this as * which means everything
                if (!emptyIPAddressString)
                {
                    try
                    {
                        PortRange[] allowedPortsArray = (allowedPorts?.ToArray());
                        if (allowedPortsArray != null && allowedPortsArray.Length != 0)
                        {
                            rule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
                            string localPorts;
                            if (action == NET_FW_ACTION_.NET_FW_ACTION_BLOCK)
                            {
                                localPorts = IPBanFirewallUtility.GetPortRangeStringBlockExcept(allowedPortsArray);
                            }
                            else
                            {
                                localPorts = IPBanFirewallUtility.GetPortRangeStringAllow(allowedPortsArray);
                            }
                            rule.LocalPorts = localPorts;
                        }
                        else
                        {
                            try
                            {
                                rule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_ANY;
                            }
                            catch
                            {
                                // failed to set protocol to any, we are switching from tcp back to any without ports, the only option is to
                                //  recreate the rule
                                if (!ruleNeedsToBeAdded)
                                {
                                    policy.Rules.Remove(ruleName);
                                    goto recreateRule;
                                }
                            }
                        }
                        rule.RemoteAddresses = (remoteIPAddresses == "0.0.0.0/0,::/0" ? "*" : remoteIPAddresses);
                    }
                    catch (Exception ex)
                    {
                        // if something failed, do not create the rule
                        emptyIPAddressString = true;
                        Logger.Error(ex);
                    }
                }

                if (emptyIPAddressString || string.IsNullOrWhiteSpace(rule.RemoteAddresses) || (rule.RemoteAddresses == "*" && remoteIPAddresses != "0.0.0.0/0,::/0"))
                {
                    // if no ip addresses, remove the rule as it will allow or block everything with an empty RemoteAddresses string
                    try
                    {
                        rule = null;
                        policy.Rules.Remove(ruleName);
                    }
                    catch
                    {
                    }
                }
                else if (ruleNeedsToBeAdded)
                {
                    policy.Rules.Add(rule);
                }
                return(rule != null);
            }
        }
예제 #5
0
 /// <inheritdoc />
 public IIPBanFirewall CreateFirewall(IPBanConfig config, IIPBanFirewall previousFirewall)
 {
     return(IPBanFirewallUtility.CreateFirewall(config.FirewallRulePrefix, previousFirewall));
 }
예제 #6
0
        private Task ProcessPendingLogEvents()
        {
            // get copy of pending log events quickly in a lock and clear list
            List <IPAddressLogEvent> events = null;

            lock (pendingLogEvents)
            {
                events = new List <IPAddressLogEvent>(pendingLogEvents);
                pendingLogEvents.Clear();
            }

            List <IPAddressLogEvent> bannedIPs = new List <IPAddressLogEvent>();
            object transaction = BeginTransaction();

            try
            {
                // loop through events, for failed and successful logins, we want to group / aggregate the same event from the
                // same remote ip address
                foreach (IPAddressLogEvent evt in events)
                {
                    if (!IPBanFirewallUtility.TryNormalizeIPAddress(evt.IPAddress, out string normalizedIPAddress))
                    {
                        continue;
                    }
                    evt.IPAddress = normalizedIPAddress;
                    switch (evt.Type)
                    {
                    case IPAddressEventType.FailedLogin:
                        // if we are not already banned...
                        if (!DB.TryGetIPAddressState(evt.IPAddress, out IPBanDB.IPAddressState? state, transaction) ||
                            state.Value == IPBanDB.IPAddressState.FailedLogin)
                        {
                            ProcessIPAddressEvent(evt, pendingFailedLogins, Config.MinimumTimeBetweenFailedLoginAttempts, "failed");
                        }
                        break;

                    case IPAddressEventType.SuccessfulLogin:
                        ProcessIPAddressEvent(evt, pendingSuccessfulLogins, Config.MinimumTimeBetweenSuccessfulLoginAttempts, "successful");
                        break;

                    case IPAddressEventType.Blocked:
                        // if we are not already banned...
                        if (!DB.TryGetIPAddressState(evt.IPAddress, out IPBanDB.IPAddressState? state2, transaction) ||
                            state2.Value == IPBanDB.IPAddressState.FailedLogin)
                        {
                            // make sure the ip address is ban pending
                            AddBannedIPAddress(evt.IPAddress, evt.Source, evt.UserName, bannedIPs,
                                               evt.Timestamp, false, evt.Count, string.Empty, transaction, evt.External);
                        }
                        break;

                    case IPAddressEventType.Unblocked:
                        DB.SetIPAddressesState(new string[] { evt.IPAddress }, IPBanDB.IPAddressState.RemovePending, transaction);
                        firewallNeedsBlockedIPAddressesUpdate = true;
                        break;
                    }
                }
                CommitTransaction(transaction);
            }
            catch (Exception ex)
            {
                RollbackTransaction(transaction);
                Logger.Error(ex);
            }
            ExecuteExternalProcessForBannedIPAddresses(bannedIPs);
            return(Task.CompletedTask);
        }
예제 #7
0
 /// <inheritdoc />
 public IIPBanFirewall CreateFirewall(System.Collections.Generic.IReadOnlyCollection <Type> allTypes,
                                      IPBanConfig config,
                                      IIPBanFirewall previousFirewall)
 {
     return(IPBanFirewallUtility.CreateFirewall(allTypes, config.FirewallRulePrefix, previousFirewall));
 }