Merge pull request #4724 from mnin/master

[Netfilter] Fix creating endless SNAT rules for ipv4
This commit is contained in:
Niklas Meyer 2022-10-06 12:18:23 +02:00 committed by GitHub
commit 9fb346751c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -252,7 +252,7 @@ def permBan(net, unban=False):
if rule not in chain.rules and not unban: if rule not in chain.rules and not unban:
logCrit('Add host/network %s to blacklist' % net) logCrit('Add host/network %s to blacklist' % net)
chain.insert_rule(rule) chain.insert_rule(rule)
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
elif rule in chain.rules and unban: elif rule in chain.rules and unban:
logCrit('Remove host/network %s from blacklist' % net) logCrit('Remove host/network %s from blacklist' % net)
chain.delete_rule(rule) chain.delete_rule(rule)
@ -267,7 +267,7 @@ def permBan(net, unban=False):
if rule not in chain.rules and not unban: if rule not in chain.rules and not unban:
logCrit('Add host/network %s to blacklist' % net) logCrit('Add host/network %s to blacklist' % net)
chain.insert_rule(rule) chain.insert_rule(rule)
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
elif rule in chain.rules and unban: elif rule in chain.rules and unban:
logCrit('Remove host/network %s from blacklist' % net) logCrit('Remove host/network %s from blacklist' % net)
chain.delete_rule(rule) chain.delete_rule(rule)
@ -346,6 +346,8 @@ def snat4(snat_target):
rule.dst = '!' + rule.src rule.dst = '!' + rule.src
target = rule.create_target("SNAT") target = rule.create_target("SNAT")
target.to_source = snat_target target.to_source = snat_target
match = rule.create_match("comment")
match.comment = f'{int(round(time.time()))}'
return rule return rule
while not quit_now: while not quit_now:
@ -356,19 +358,26 @@ def snat4(snat_target):
table.refresh() table.refresh()
chain = iptc.Chain(table, 'POSTROUTING') chain = iptc.Chain(table, 'POSTROUTING')
table.autocommit = False table.autocommit = False
if get_snat4_rule() not in chain.rules: new_rule = get_snat4_rule()
logCrit('Added POSTROUTING rule for source network %s to SNAT target %s' % (get_snat4_rule().src, snat_target)) for position, rule in enumerate(chain.rules):
chain.insert_rule(get_snat4_rule()) match = all((
table.commit() new_rule.get_src() == rule.get_src(),
else: new_rule.get_dst() == rule.get_dst(),
for position, item in enumerate(chain.rules): new_rule.target.parameters == rule.target.parameters,
if item == get_snat4_rule(): new_rule.target.name == rule.target.name
if position != 0: ))
chain.delete_rule(get_snat4_rule()) if position == 0:
table.commit() if not match:
logInfo(f'Added POSTROUTING rule for source network {new_rule.src} to SNAT target {snat_target}')
chain.insert_rule(new_rule)
else:
if match:
logInfo(f'Remove rule for source network {new_rule.src} to SNAT target {snat_target} from POSTROUTING chain at position {position}')
chain.delete_rule(rule)
table.commit()
table.autocommit = True table.autocommit = True
except: except:
print('Error running SNAT4, retrying...') print('Error running SNAT4, retrying...')
def snat6(snat_target): def snat6(snat_target):
global lock global lock
@ -402,7 +411,7 @@ def snat6(snat_target):
table.commit() table.commit()
table.autocommit = True table.autocommit = True
except: except:
print('Error running SNAT6, retrying...') print('Error running SNAT6, retrying...')
def autopurge(): def autopurge():
while not quit_now: while not quit_now:
@ -468,7 +477,7 @@ def whitelistUpdate():
if Counter(new_whitelist) != Counter(WHITELIST): if Counter(new_whitelist) != Counter(WHITELIST):
WHITELIST = new_whitelist WHITELIST = new_whitelist
logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST)) logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
time.sleep(60.0 - ((time.time() - start_time) % 60.0)) time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def blacklistUpdate(): def blacklistUpdate():
global quit_now global quit_now
@ -479,7 +488,7 @@ def blacklistUpdate():
new_blacklist = [] new_blacklist = []
if list: if list:
new_blacklist = genNetworkList(list) new_blacklist = genNetworkList(list)
if Counter(new_blacklist) != Counter(BLACKLIST): if Counter(new_blacklist) != Counter(BLACKLIST):
addban = set(new_blacklist).difference(BLACKLIST) addban = set(new_blacklist).difference(BLACKLIST)
delban = set(BLACKLIST).difference(new_blacklist) delban = set(BLACKLIST).difference(new_blacklist)
BLACKLIST = new_blacklist BLACKLIST = new_blacklist
@ -490,7 +499,7 @@ def blacklistUpdate():
if delban: if delban:
for net in delban: for net in delban:
permBan(net=net, unban=True) permBan(net=net, unban=True)
time.sleep(60.0 - ((time.time() - start_time) % 60.0)) time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def initChain(): def initChain():
# Is called before threads start, no locking # Is called before threads start, no locking