skip to Main Content

I have a containerized application that needs to connect to a remote tcp server as a tcp client. When the app starts, it goes and grabs a random port to use for the connection. I would expect I need to expose this port through docker’s --port flag when I run the container. To test this out I used netcat.

# On the host
user@host:~$ nc -l 0.0.0.0 42069
abc123 # <<< received some stuff from container netcat
def456 # <<< send some stuff to container netcat

# In the container
user@host:~$ docker run -it --rm rockylinux:9 bash
[root@4498d21136f3 /]# nc host.docker.internal 42069
abc123 # <<< send some stuff to host netcat
def456 # <<< received some stuff from host netcat

As you can see, I did not need to expose the port. Looking at tcpdump below I can see that the container was using port 36956 which I did not expose. What’s going on here?

user@host:~$ sudo tcpdump -i any port 42069 -v
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
13:18:34.587654 lo    In  IP (tos 0x0, ttl 64, id 35827, offset 0, flags [DF], proto TCP (6), length 60)
    localhost.36956 > localhost.42069: Flags [S], cksum 0xfe30 (incorrect -> 0x4aad), seq 81689982, win 65495, options [mss 65495,sackOK,TS val 3926025283 ecr 0,nop,wscale 7], length 0
13:18:34.587665 lo    In  IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    localhost.42069 > localhost.36956: Flags [S.], cksum 0xfe30 (incorrect -> 0xc160), seq 3472256010, ack 81689983, win 65483, options [mss 65495,sackOK,TS val 3926025283 ecr 3926025283,nop,wscale 7], length 0
13:18:34.587675 lo    In  IP (tos 0x0, ttl 64, id 35828, offset 0, flags [DF], proto TCP (6), length 52)
    localhost.36956 > localhost.42069: Flags [.], cksum 0xfe28 (incorrect -> 0xe81c), ack 1, win 512, options [nop,nop,TS val 3926025283 ecr 3926025283], length 0
13:18:36.977633 lo    In  IP (tos 0x0, ttl 64, id 35829, offset 0, flags [DF], proto TCP (6), length 59)
    localhost.36956 > localhost.42069: Flags [P.], cksum 0xfe2f (incorrect -> 0xdded), seq 1:8, ack 1, win 512, options [nop,nop,TS val 3926027676 ecr 3926025283], length 7
13:18:36.977680 lo    In  IP (tos 0x0, ttl 64, id 6768, offset 0, flags [DF], proto TCP (6), length 52)
    localhost.42069 > localhost.36956: Flags [.], cksum 0xfe28 (incorrect -> 0xd563), ack 8, win 512, options [nop,nop,TS val 3926027676 ecr 3926027676], length 0
13:18:40.932413 lo    In  IP (tos 0x0, ttl 64, id 6769, offset 0, flags [DF], proto TCP (6), length 59)
    localhost.42069 > localhost.36956: Flags [P.], cksum 0xfe2f (incorrect -> 0xbc12), seq 1:8, ack 8, win 512, options [nop,nop,TS val 3926031630 ecr 3926027676], length 7
13:18:40.932446 lo    In  IP (tos 0x0, ttl 64, id 35830, offset 0, flags [DF], proto TCP (6), length 52)
    localhost.36956 > localhost.42069: Flags [.], cksum 0xfe28 (incorrect -> 0xb678), ack 8, win 512, options [nop,nop,TS val 3926031630 ecr 3926031630], length 0
^C
7 packets captured
14 packets received by filter
0 packets dropped by kernel

2

Answers


  1. Docker published ports – the docker run -p option – are only used from connections from outside of Docker into the container. Connections from inside the container to elsewhere are allowed by default, and there are not Docker options to limit and/or allow these.

    That is, if you had said docker run -p 12345:42069 ..., it would forward the host’s port 12345 to the container’s port 42069. You don’t need particular setup to make connections to host.docker.internal when that exists, or to external systems. If you’re just connecting between containers on the same docker run --net, published ports aren’t required or considered at all.

    In the question title you say "expose". This is a technical Docker term: there is a docker run --expose option and a Dockerfile EXPOSE directive. With modern Docker networking, though, "exposing" a port does almost nothing. More specifically, if you have a docker run --expose option or a Compose expose: directive, it is almost certainly safe to just delete that option.

    Login or Signup to reply.
  2. As you can see, I did not need to expose the port. Looking at tcpdump below I can see that the container was using port 36956 which I did not expose. What’s going on here?

    Docker allows bidirectional traffic as long as the connection comes from the container. This is because Docker uses a NAT to map the container’s ports to the host’s ports. This way it eliminates the need for the host to expose any ports in order for the container to communicate with the outside world.

    Furthermore I would like to highlight that Docker doesn’t block any ports by default. It means that if your container is vulnerable to attack, an attacker may use a weakness in the container to access the host.

    P.s.
    You can use a firewall to impose access restrictions on the exposed ports in order to mitigate the security risks of bidirectional traffic. You can also use a network monitoring tool to monitor the exposed ports for suspicious activity.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search