Skip to content

Commit b744b41

Browse files
committed
fix: use runtime API for ipset updates to avoid network outages
`fds cron` was causing brief DNS/network connectivity outages because it called firewalld reload after updating ipset entries. The reload flushes iptables rules and causes packet loss. Changed update_ipsets() to use the runtime API (self.fw.setEntries) which applies changes immediately without reload. The permanent config created by initial `fds block` commands remains unchanged for persistence across firewalld restarts.
1 parent 707058c commit b744b41

File tree

3 files changed

+26
-12
lines changed

3 files changed

+26
-12
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4+
## [0.0.44] - 2026-02-20
5+
### Fixed
6+
* `fds cron` no longer causes network connectivity outages by using runtime API for ipset updates instead of firewalld reload
7+
48
## [0.0.30] - 2021-08-03
59
### Added
610
* Optionally uses aggregation to overcome FirewallD bugs #22

fds.spec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
%endif
2020

2121
Name: fds
22-
Version: 0.0.43
22+
Version: 0.0.44
2323
Release: 1%{?dist}
2424
Summary: The go-to FirewallD CLI companion app
2525
License: BSD

fds/FirewallWrapper.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -247,26 +247,36 @@ def get_blocked_countries(self):
247247
return blocked_countries
248248

249249
def update_ipsets(self):
250-
need_reload = False
250+
"""Update existing ipsets with fresh data using runtime API.
251+
252+
Uses the runtime API (self.fw.setEntries) which applies changes
253+
immediately without requiring a firewalld reload. This avoids
254+
brief network connectivity outages that occur during reload.
255+
"""
251256
all_ipsets = self.fw.getIPSets()
252257
from .Countries import Countries
253258
countries = Countries()
254-
is_tor_blocked = False
259+
w = WebClient()
260+
255261
for ipset_name in all_ipsets:
256-
if ipset_name.startswith('fds-tor-'):
257-
is_tor_blocked = True
262+
if ipset_name == 'fds-tor-4':
263+
log.info('Updating Tor IPv4 exit nodes')
264+
entries = w.get_tor_exits(family=4)
265+
self.fw.setEntries(ipset_name, entries)
266+
elif ipset_name == 'fds-tor-6':
267+
log.info('Updating Tor IPv6 exit nodes')
268+
entries = w.get_tor_exits(family=6)
269+
self.fw.setEntries(ipset_name, entries)
258270
elif ipset_name.startswith('fds-'):
259271
country_code = ipset_name.split('-')[1]
260272
if country_code in countries.names_by_code:
261273
country_name = countries.names_by_code[country_code]
262274
country = countries.get_by_name(country_name)
263-
self.block_country(country, reload=False)
264-
need_reload = True
265-
if is_tor_blocked:
266-
self.block_tor(reload=False)
267-
need_reload = True
268-
if need_reload:
269-
self.fw.reload()
275+
log.info('Updating {} {}'.format(country.name, country.getFlag()))
276+
entries = w.get_country_networks(country=country)
277+
self.fw.setEntries(ipset_name, entries)
278+
279+
# No reload needed - runtime API applies immediately
270280
return True
271281

272282
def reset(self):

0 commit comments

Comments
 (0)