Fix race condition in ensure_forward_stateful: add threading.Lock
Concurrent callers (health monitor + startup) could both pass the delete-all loop and each insert a copy, producing duplicate ESTABLISHED,RELATED rules. Lock serialises all calls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+17
-13
@@ -8,10 +8,13 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import threading
|
||||||
from typing import Dict, List, Any, Optional
|
from typing import Dict, List, Any, Optional
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_forward_stateful_lock = threading.Lock()
|
||||||
|
|
||||||
# Virtual IPs assigned to Caddy per service — must match Caddyfile listeners.
|
# Virtual IPs assigned to Caddy per service — must match Caddyfile listeners.
|
||||||
# Populated at import time from the default subnet; call update_service_ips()
|
# Populated at import time from the default subnet; call update_service_ips()
|
||||||
# whenever ip_range changes so all downstream callers see the new values.
|
# whenever ip_range changes so all downstream callers see the new values.
|
||||||
@@ -459,19 +462,20 @@ def ensure_forward_stateful() -> bool:
|
|||||||
which pushes this rule down every time wg0 restarts — causing ICMP to hit the
|
which pushes this rule down every time wg0 restarts — causing ICMP to hit the
|
||||||
per-peer DROP rule before reaching the stateful ACCEPT.
|
per-peer DROP rule before reaching the stateful ACCEPT.
|
||||||
"""
|
"""
|
||||||
try:
|
with _forward_stateful_lock:
|
||||||
# Remove all existing instances so we can re-anchor at position 1.
|
try:
|
||||||
# PostUp -I FORWARD rules drift this rule down on every wg0 restart.
|
# Remove all existing instances so we can re-anchor at position 1.
|
||||||
while _wg_exec(['iptables', '-D', 'FORWARD', '-m', 'state',
|
# PostUp -I FORWARD rules drift this rule down on every wg0 restart.
|
||||||
'--state', 'ESTABLISHED,RELATED', '-j', 'ACCEPT']).returncode == 0:
|
while _wg_exec(['iptables', '-D', 'FORWARD', '-m', 'state',
|
||||||
pass
|
'--state', 'ESTABLISHED,RELATED', '-j', 'ACCEPT']).returncode == 0:
|
||||||
_wg_exec(['iptables', '-I', 'FORWARD', '1', '-m', 'state',
|
pass
|
||||||
'--state', 'ESTABLISHED,RELATED', '-j', 'ACCEPT'])
|
_wg_exec(['iptables', '-I', 'FORWARD', '1', '-m', 'state',
|
||||||
logger.info('ensure_forward_stateful: ESTABLISHED,RELATED anchored at FORWARD position 1')
|
'--state', 'ESTABLISHED,RELATED', '-j', 'ACCEPT'])
|
||||||
return True
|
logger.info('ensure_forward_stateful: ESTABLISHED,RELATED anchored at FORWARD position 1')
|
||||||
except Exception as e:
|
return True
|
||||||
logger.error(f'ensure_forward_stateful: {e}')
|
except Exception as e:
|
||||||
return False
|
logger.error(f'ensure_forward_stateful: {e}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def ensure_cell_api_dnat() -> bool:
|
def ensure_cell_api_dnat() -> bool:
|
||||||
|
|||||||
Reference in New Issue
Block a user