Can't "UDP hole punch" from containers

I’m probably doing something wrong because I thought I had tested this months ago, but maybe I am mistaken.

I have this little python script that performs UDP hole punching so that two machines can send messages to each other directly over the web. It’s pretty neat and works really well, but I tried to run it from inside a docker container and fail to receive the other machine’s messages. I think it might have something to do with the Docker NAT but idk. Hoping someone on here can help me.

I’ve tried everything I could think of, first of all, as far as docker configuration. The script works great outside the container, does not work from within the container no matter what I do.

You can try it too, if you have two machines over the web (you could have two local machines, but put one on a vpn). I’ll paste the script here, then I’ll show you everything I’ve tried.

# how to use:
#   on one machine run:
#       python3 udp.py <other ip address> 5002 5003 True
#   on another machine across the internet run:
#       python3 udp.py <other ip address> 5003 5002 True
#   at the same time.
# now they can talk to each other directly.

# to test within a container:
# docker run --rm -it --privileged -p 5002:5002/udp -p 5003:5003/udp -v .:/udp python:slim bash
# python /udp/udp.py <remoteIp> 5003 5002 True

# how to get the public ip address:
# docker run --rm -it --privileged --net=host --cap-add NET_ADMIN -v .:/udp python:slim bash
# apt-get update; apt-get install curl -y; curl https://satorinet.io/ip/

import sys
import socket
import threading


def listen(sock: socket.socket):
    while True:
        # data = sock.recv(1024)
        data, addr = sock.recvfrom(1024)
        print(f'\rpeer ({addr}): {data.decode()}\n> ', end='')


def run(remoteIp, remotePort=5002, localPort=5001, myLocalIsTheirRemote=False):
    localPort = int(localPort)
    remotePort = int(remotePort)
    print('\ngot peer')
    print(f'  remoteip:   {remoteIp}')
    print(f'  repotePort: {remotePort}')
    print(f'  localPort:  {localPort}')
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('0.0.0.0', localPort))
    sock.sendto(b'0', (remoteIp, remotePort))
    listener = threading.Thread(target=listen, args=[sock], daemon=True)
    listener.start()
    if not myLocalIsTheirRemote:
        sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock2.bind(('0.0.0.0', remotePort))
    while True:
        msg = input('> ')
        if not myLocalIsTheirRemote:
            sock2.sendto(msg.encode(), (remoteIp, localPort))
        else:
            sock.sendto(msg.encode(), (remoteIp, remotePort))


if __name__ == '__main__' and len(sys.argv) > 4:
    run(
        remoteIp=sys.argv[1],
        remotePort=sys.argv[2],
        localPort=sys.argv[3],
        myLocalIsTheirRemote=sys.argv[4],  # reversed?
    )
else:
    print('usage: python3 manual.py <remoteIp> <remotePort> <localPort> <myLocalIsTheirRemote>')

Ok, so to recreate this, map the ports, at least 2, or try it with --net=host, also map the folder this script is saved in, then just try to run the script with the other person’s public IP and make sure to reverse the ports.

Here’s the various ways I’ve tried running the docker container (choose any container, I’ve been testing with python:slim since this is a python script), but nothing has worked.

docker configuration for testing udp hole punching:

example:
on first machine with ip 123.123.123.123:

docker run --rm -it --net=host -v <path to folder containing udp.py>:/udp python:slim bash
python udp/udp.py 231.231.231.231 5002 5003 True

on second machine with ip 231.231.231.231:

docker run --rm -it --net=host -v <path to folder containing udp.py>:/udp python:slim bash
python udp/udp.py 123.123.123.123 5003 5002 True

see if they can talk.
I can’t get it to work. I’ve tried:

docker run --rm -it --net=host...
docker run --rm -it --net host...
docker run --rm -it --net="host"...
docker run --rm -it --net "host"...
docker run --rm -it --network=host...
docker run --rm -it --network host...
docker run --rm -it --network="host"...
docker run --rm -it --network "host"...
docker run --rm -it --net=host --privileged...
docker run --rm -it --net=host --privileged --cap-add NET_ADMIN...
docker run --rm -it -p 5002:5002/udp -p 5002:5003/udp ...
docker run --rm -it -p 5002:5002/udp -p 5002:5003/udp --privileged...
docker run --rm -it -p 5002:5002/udp -p 5002:5003/udp --privileged --cap-add NET_ADMIN...
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 my_macvlan_net
docker run --rm -it --network=my_macvlan_net --ip=192.168.1.10...
and others...

nothying seems to make any difference whatsoever.
the script works outside the container, but not from within it.

I’m no expert in any of this, docker, networking, udp or anything. So I don’t really know how to track the traffic and troubleshoot it, either. All I know is the script works really well outside the containers on machines across the internet, but in the containers it doesn’t work at all (I get no message from the other machine).

I’ve been trying to fix this for days so I’ve seen that people seem to think if you just use --net=host it’ll work because it’ll be on the same network as the host machine. I’ve tested that extensively.

Please help. Thanks!