public void Add(FwData fwdata, UInt64 weight = 0, bool permit = false, bool persistent = false) { long expiration = fwdata.Expire; long currtime = DateTime.UtcNow.Ticks; // Adding filter with expiration time in past // doesn't really make any sense if (currtime >= expiration) { string tmp = Convert.ToString(expiration); try { DateTime tmpExp = new DateTime(expiration, DateTimeKind.Utc); tmp = tmpExp.ToLocalTime().ToString(); } catch (Exception) { } Log.Info("Skipping expired firewall rule (expired on " + tmp + ")"); return; } byte[] hash = fwdata.Hash; FirewallConditions conds = fwdata.Conditions(); // IPv4 filter layer if (conds.HasIPv4() || (!conds.HasIPv4() && !conds.HasIPv6())) { byte[] hash4 = new byte[hash.Length]; hash.CopyTo(hash4, 0); hash4[hash4.Length - 1] &= 0xfe; Add(fwdata.ToString(), expiration, hash4, conds, weight, permit, persistent, F2B.Firewall.Instance.AddIPv4); } // IPv6 filter layer if (conds.HasIPv6() || (!conds.HasIPv4() && !conds.HasIPv6())) { byte[] hash6 = new byte[hash.Length]; hash.CopyTo(hash6, 0); hash6[hash6.Length - 1] |= 0x01; Add(fwdata.ToString(), expiration, hash6, conds, weight, permit, persistent, F2B.Firewall.Instance.AddIPv6); } }
private void Add(string filter, long expiration, byte[] hash, FirewallConditions conds, UInt64 weight, bool permit, bool persistent, Func <string, FirewallConditions, UInt64, bool, bool, ulong> AddFilter) { long currtime = DateTime.UtcNow.Ticks; string filterName = FwData.EncodeName(expiration, hash); lock (dataLock) { // we need unique expiration time to keep all required // data in simple key/value hashmap structure (and we // really don't care about different expiration time in ns) while (cleanup.ContainsKey(expiration)) { expiration++; } // filter out requests with expiration within 10% time // range and treat them as duplicate requests UInt64 filterId = 0; long expirationOld; if (expire.TryGetValue(hash, out expirationOld)) { if (currtime > Math.Max(expirationOld, expiration)) { Log.Info("Skipping request with expiration in past"); } else if (expiration < expirationOld) { Log.Info("Skipping request with new expiration " + expiration + " < existing exipration " + expirationOld); } else if (expiration - expirationOld < (expiration - currtime) / 10) { Log.Info("Skipping request with expiration of new records within 10% of expiration of existing rule (c/o/e=" + currtime + "/" + expirationOld + "/" + expiration + ")"); } else { UInt64 filterIdOld = cleanup[expirationOld]; Log.Info("Replace old filter #" + filterIdOld + " with increased expiration time (c/o/e=" + currtime + "/" + expirationOld + "/" + expiration + ")"); try { filterId = AddFilter(filterName, conds, weight, permit, persistent); Log.Info("Added filter rule #" + filterId + ": " + filter); F2B.Firewall.Instance.Remove(filterIdOld); Log.Info("Removed filter rule #" + filterIdOld); } catch (FirewallException ex) { Log.Warn("Unable to replace filter rule #" + filterId + ": " + ex.Message); //fail++; } if (filterId != 0) // no exception during rule addition { data.Remove(filterIdOld); expire.Remove(hash); // not necessary cleanup.Remove(expirationOld); } } } else { if (MaxSize == 0 || MaxSize > data.Count) { try { filterId = AddFilter(filterName, conds, weight, permit, persistent); Log.Info("Added new filter #" + filterId + ": " + filter); } catch (FirewallException ex) { Log.Warn("Unable to add filter " + filter + ": " + ex.Message); //fail++; } } else { Log.Warn("Reached limit for number of active F2B filter rules, skipping new additions"); } } if (filterId != 0) { data[filterId] = hash; expire[hash] = expiration; cleanup[expiration] = filterId; if (!tCleanupExpired.Enabled) { Log.Info("Enabling cleanup timer (interval " + tCleanupExpired.Interval + " ms)"); tCleanupExpired.Enabled = true; } } } // dataLock }