From 5a50e2bb632761b8ef11a7690c66c0db9eeed2d2 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Wed, 15 Apr 2026 17:34:00 -0500 Subject: [PATCH] Fix NAT-PMP struct format and renewal interval ProtonVPN returns 16-byte success responses (last field is uint32 lifetime, not uint16). The previous !BBHIHHH format expected 14 bytes causing unpack failure. Fixed to !BBHIHHI (16 bytes). ProtonVPN grants 60s leases; request 60s and renew every 45s instead of sleeping 240s which let leases expire between renewals. --- servers/legion/k8s/media/fornax-workers.yaml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/servers/legion/k8s/media/fornax-workers.yaml b/servers/legion/k8s/media/fornax-workers.yaml index bc84093..7371850 100644 --- a/servers/legion/k8s/media/fornax-workers.yaml +++ b/servers/legion/k8s/media/fornax-workers.yaml @@ -161,9 +161,10 @@ spec: # Install curl and python3 for NAT-PMP port forwarding until apk add -q curl python3 2>/dev/null; do sleep 5; done - # NAT-PMP: single-line Python to request TCP port mapping from ProtonVPN gateway + # NAT-PMP: request TCP port from ProtonVPN gateway (60s lease; renew every 45s) + # Response is 16 bytes: BB H I H H I (last field is uint32 lifetime, not uint16) get_natpmp_port() { - python3 -c "import socket,struct;s=socket.socket(2,2);s.settimeout(5);s.sendto(struct.pack('!BBHHHI',0,2,0,0,0,7776000),('10.2.0.1',5351));d=s.recvfrom(256)[0];r=struct.unpack('!BBHIHHH',d[:16]) if len(d)>=16 else None;print(r[5] if r and r[2]==0 else 0)" 2>/dev/null || echo 0 + python3 -c "import socket,struct;s=socket.socket(2,2);s.settimeout(5);s.sendto(struct.pack('!BBHHHI',0,2,0,0,0,60),('10.2.0.1',5351));d=s.recvfrom(256)[0];r=struct.unpack('!BBHIHHI',d) if len(d)==16 else None;print(r[5] if r and r[2]==0 else 0)" 2>/dev/null || echo 0 } echo "Requesting port via NAT-PMP..." @@ -193,7 +194,7 @@ spec: fi LAST_PORT="$PORT" fi - sleep 240 + sleep 45 done env: - name: COORDINATOR_URL @@ -415,9 +416,10 @@ spec: until apk add -q curl python3 2>/dev/null; do sleep 5; done - # NAT-PMP: single-line Python to request TCP port mapping from ProtonVPN gateway + # NAT-PMP: request TCP port from ProtonVPN gateway (60s lease; renew every 45s) + # Response is 16 bytes: BB H I H H I (last field is uint32 lifetime, not uint16) get_natpmp_port() { - python3 -c "import socket,struct;s=socket.socket(2,2);s.settimeout(5);s.sendto(struct.pack('!BBHHHI',0,2,0,0,0,7776000),('10.2.0.1',5351));d=s.recvfrom(256)[0];r=struct.unpack('!BBHIHHH',d[:16]) if len(d)>=16 else None;print(r[5] if r and r[2]==0 else 0)" 2>/dev/null || echo 0 + python3 -c "import socket,struct;s=socket.socket(2,2);s.settimeout(5);s.sendto(struct.pack('!BBHHHI',0,2,0,0,0,60),('10.2.0.1',5351));d=s.recvfrom(256)[0];r=struct.unpack('!BBHIHHI',d) if len(d)==16 else None;print(r[5] if r and r[2]==0 else 0)" 2>/dev/null || echo 0 } echo "Requesting port via NAT-PMP..." @@ -445,7 +447,7 @@ spec: fi LAST_PORT="$PORT" fi - sleep 240 + sleep 45 done env: - name: COORDINATOR_URL