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]);
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); }
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; } }
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); } }
/// <inheritdoc /> public IIPBanFirewall CreateFirewall(IPBanConfig config, IIPBanFirewall previousFirewall) { return(IPBanFirewallUtility.CreateFirewall(config.FirewallRulePrefix, previousFirewall)); }
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); }
/// <inheritdoc /> public IIPBanFirewall CreateFirewall(System.Collections.Generic.IReadOnlyCollection <Type> allTypes, IPBanConfig config, IIPBanFirewall previousFirewall) { return(IPBanFirewallUtility.CreateFirewall(allTypes, config.FirewallRulePrefix, previousFirewall)); }