1

I am trying to get my head around networking with docker. First I create a docker image (based on ubuntu22) with net cat installed:

FROM ubuntu:22.04
RUN apt-get update -y && apt-get upgrade -y
RUN apt-get install -y netcat-openbsd

Build using:

docker build -f foobar.Dockerfile -t foobar .

I then run this as a container with a static IP (on RHEL8) as follows:

docker network create --driver bridge --subnet 172.20.0.0/16 foobar-net &&
docker run -v /home:/home -it --name foobar --network foobar-net --ip 172.20.0.2 -p 1781:1781 foobar /bin/bash

Inside the docker image I get netcat to listen for UDP packets on port 1781 using:

nc -l -u -p 1781

From the host I can see the IP address:

>docker inspect foobar 

    "NetworkSettings": {
        "Bridge": "",
        "SandboxID": "b6019cec78bac4536f1ff66159dc5c724c9f5e205ef68f64fa23b41223a9e66c",
        "HairpinMode": false,
        "LinkLocalIPv6Address": "",
        "LinkLocalIPv6PrefixLen": 0,
        "Ports": {
            "1781/tcp": [
                {
                    "HostIp": "0.0.0.0",
                    "HostPort": "1781"
                },
                {
                    "HostIp": "::",
                    "HostPort": "1781"
                }
            ]
        },
        "SandboxKey": "/var/run/docker/netns/b6019cec78ba",
        "SecondaryIPAddresses": null,
        "SecondaryIPv6Addresses": null,
        "EndpointID": "",
        "Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "IPAddress": "",
        "IPPrefixLen": 0,
        "IPv6Gateway": "",
        "MacAddress": "",
        "Networks": {
            "dcs-net": {
                "IPAMConfig": {
                    "IPv4Address": "172.20.0.2"
                },
                "Links": null,
                "Aliases": [
                    "71efaf0b1ec4"
                ],
                "NetworkID": "84fc84937c72e2461751eb5edb74183c3ce9a5bad83c3310ba81847cd052327d",
                "EndpointID": "28f447f842036eb30e90574a4b6a4d94c826224afc42e2ffa68678c51f0d3331",
                "Gateway": "172.20.0.1",
                "IPAddress": "172.20.0.2",
                "IPPrefixLen": 16,
                "IPv6Gateway": "",
                "GlobalIPv6Address": "",
                "GlobalIPv6PrefixLen": 0,
                "MacAddress": "02:42:ac:14:00:02",
                "DriverOpts": null
            }
        }
    }

I want to expose this port to the network. To do this I am trying:

firewall-cmd --zone=external --add-port=1781/udp
firewall-cmd --zone=public --add-forward-port=port=1781:proto=udp:toport=1781:toaddr=172.20.0.2

But I am having trouble connecting to it from the local machine:

 >nc -u 127.0.0.1 -p 1781
 hello world!
 Ncat: Connection refused.

 >nc -u 127.0.0.20 -p 1781
 hello world!
 Ncat: Connection refused.

 >nc -u <local machines IP> -p 1781
 hello world!
 Ncat: Connection refused.

I can see the rules I think are relevant using iptables-save:

-A DOCKER -p udp -m udp --dport 1781 -j DNAT --to-destination 172.20.0.2:1781
-A DOCKER ! -i br-84fc84937c72 -p tcp -m tcp --dport 1781 -j DNAT --to-destination 172.20.0.2:1781
-A POSTROUTING -s 172.20.0.2/32 -d 172.20.0.2/32 -p tcp -m tcp --dport 1781 -j MASQUERADE

or:

>firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eno2np1
  sources: 
  services: cockpit dhcpv6-client ssh
  ports: 9200/tcp 1781/udp
  protocols: 
  forward: no
  masquerade: no
  forward-ports: 
    port=1781:proto=udp:toport=1781:toaddr=172.20.0.2
  source-ports: 
  icmp-blocks: 
  rich rules: 

I do not entirely grok what I am doing here. Either my firewalld or docker network or both are wrong. Please help me grok.

This is a very common use case and so likely a duplicate but I cannot find anything which helps me identify what I'm missing so far.

Bruce Adams
  • 4,953
  • 4
  • 48
  • 111

1 Answers1

1

By default when you use -p option in docker, it published TCP port. You should use -p 1781:1781/udp

docker run -v /home:/home -it --name foobar --network foobar-net --ip 172.20.0.2 -p 1781:1781 /udp foobar /bin/bash
Amin Imani
  • 26
  • 2
  • (I'd also suggest removing all of the IP addresses everywhere in this setup. You almost never need to know or manually specify them. `docker run -p` will have the service accessible via the host's IP address(es).) – David Maze Dec 07 '22 at 18:06
  • That has had an interesting effect I now get: nc -u 172.20.0.2 -p 1781 libnsock mksock_bind_addr(): Bind to 0.0.0.0:1781 failed (IOD #1): Address already in use (98) ^C and yet netstat -plnt does not show anything bound to 1781 – Bruce Adams Dec 07 '22 at 18:18
  • @DavidMaze I understand using the host network type, which I assumed that does, to be considered less safe. E.g. https://stackoverflow.com/questions/35230321/what-are-the-disadvantages-of-a-docker-container-using-the-host-network . Is that not the case? – Bruce Adams Dec 07 '22 at 18:24
  • I guess -p 1781:1781 binds the address for both incoming and outgoing traffic? I just want the docker image to listen so that I can use netcat from the machnie hosting the docker container. This works if you run nc and nc -l in different terminals for example. – Bruce Adams Dec 07 '22 at 19:01
  • The netstat issue is explained [here](https://stackoverflow.com/questions/62239618/netstat-does-not-show-ports-exposed-by-docker-windows-container?noredirect=1&lq=1) >sudo netstat -anp | grep 1781 udp 0 0 0.0.0.0:1781 0.0.0.0:* 1330278/docker-prox udp6 0 0 :::1781 :::* 1330287/docker-prox – Bruce Adams Dec 07 '22 at 19:01