udp-holepunch - Python script for UDP holepunching using a webserver. With an example of SSH using this and sctp-echo.

git clone https://benconnors.ca/git-repos/udp-holepunch

About | Log | Files | Refs

commit 6778edcce27c74631f2d48a100a7fc34be1130fb
parent ddc495b53a04f3e41be1668be2f1e8fd093ef71e
Author: Ben Connors <benconnors@outlook.com>
Date:   Wed,  9 Sep 2026 12:11:16 -0400

Add timeout to holepunch loop

Diffstat:
Mudp_holepunch.py | 15++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/udp_holepunch.py b/udp_holepunch.py @@ -61,7 +61,7 @@ def ssh_verify(message, signature, allowed_keys, namespace="udp-holepunch"): return True -def udp_holepunch_loop(sock, other_addr, no_ack=False): +def udp_holepunch_loop(sock, other_addr, no_ack=False, timeout=60): """Finalize the UDP holepunching. The general idea here is to blast them with "hello!" packets; once they receive one from us, @@ -74,12 +74,18 @@ def udp_holepunch_loop(sock, other_addr, no_ack=False): sock.sendto(b"hello!", other_addr) else: found = False + + start = time.monotonic() + sock.settimeout(0.5) while True: sock.sendto(b"hello!" if not found else b"done!", other_addr) try: resp = sock.recvfrom(100) except TimeoutError: + if time.monotonic() - start > timeout: + return False + continue if resp[1] != other_addr: @@ -101,7 +107,9 @@ def udp_holepunch_loop(sock, other_addr, no_ack=False): except TimeoutError: break -def udp_holepunch_server(local_port, server_port, server_path, no_ack=False, allowed_keys=None): + return True + +def udp_holepunch_server(local_port, server_port, server_path, no_ack=False, allowed_keys=None, timeout=60): """Serve as the UDP holepunching "server". Poll the given `server_path`; if a message is found from `udp_holepunch_client`, begin the @@ -153,7 +161,8 @@ def udp_holepunch_server(local_port, server_port, server_path, no_ack=False, all ## Send to the client directly other_addr = (other_ip, other_port) - udp_holepunch_loop(c, other_addr, no_ack=no_ack) + if not udp_holepunch_loop(c, other_addr, no_ack=no_ack, timeout=timeout): + raise Exception("Holepunching timeout") c.close()