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 == 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; } catch (Exception ex) { // if something failed, do not create the rule emptyIPAddressString = true; IPBanLog.Error(ex); } } if (emptyIPAddressString || string.IsNullOrWhiteSpace(rule.RemoteAddresses) || rule.RemoteAddresses == "*") { // 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); } }
private bool CreateOrUpdateRule(string ruleName, string action, string hashType, int maxCount, IEnumerable <PortRange> allowedPorts, CancellationToken cancelToken) { // ensure that a set exists for the iptables rule in the event that this is the first run RunProcess("ipset", false, $"create {ruleName} hash:{hashType} family {inetFamily} hashsize {hashSize} maxelem {maxCount} -exist"); if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } string setFileName = GetSetFileName(ruleName); if (!File.Exists(setFileName)) { RunProcess("ipset", true, $"save {ruleName} > \"{setFileName}\""); } if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } PortRange[] allowedPortsArray = allowedPorts?.ToArray(); // create or update the rule in iptables RunProcess("iptables", true, out IReadOnlyList <string> lines, "-L --line-numbers"); string portString = " "; bool replaced = false; if (allowedPortsArray != null && allowedPortsArray.Length != 0) { string portList = (action == "DROP" ? IPBanFirewallUtility.GetPortRangeStringBlockExcept(allowedPorts) : IPBanFirewallUtility.GetPortRangeStringAllow(allowedPorts)); portString = " -m multiport --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("iptables", true, $"-R INPUT {ruleNum} -m set{portString}--match-set \"{ruleName}\" src -j {action}"); replaced = true; break; } } if (!replaced) { // add a new rule RunProcess("iptables", true, $"-A INPUT -m set{portString}--match-set \"{ruleName}\" src -j {action}"); } if (cancelToken.IsCancellationRequested) { throw new OperationCanceledException(cancelToken); } SaveTableToDisk(); return(true); }