0

I would like to remap outbound traffic from within a docker container to a different port. Eg: I would like to curl 1.2.3.4:8080 from within the container and have the request actually be made to curl 1.2.3.4:8181. (this is similar to what kube-proxy does for kubernetes).

I understand that within a docker container I can run:

iptables -t nat -A OUTPUT -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to-destination 1.2.3.4:8181

And then requests will behave as desired. However, I'd like to only edit the iptables rules on the host to get the same functionality.

I have a docker network with id 8e8799c36e69, if I run iptables-save | grep 8e8799c36e69 on the host I get the following rules:

-A POSTROUTING -s 172.18.0.0/16 ! -o br-8e8799c36e69 -j MASQUERADE
-A DOCKER -i br-8e8799c36e69 -j RETURN
-A FORWARD -o br-8e8799c36e69 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-8e8799c36e69 -j DOCKER
-A FORWARD -i br-8e8799c36e69 ! -o br-8e8799c36e69 -j ACCEPT
-A FORWARD -i br-8e8799c36e69 -o br-8e8799c36e69 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-8e8799c36e69 ! -o br-8e8799c36e69 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o br-8e8799c36e69 -j DROP

Is it possible to hook into these rules so that I can set up my port rewrite just within that network? (is this event the correct approach?).

Maybe just something like this?

iptables -t nat -I OUTPUT -o br-8e8799c36ec9  --src 0/0 --dst 1.2.3.4 -p tcp --dport 8080 -j REDIRECT --to-ports 8181

Or maybe I don't need the docker bridge network and I can somehow filter on traffic coming from within the container?

edit:

When I start a docker container it creates these rules:

-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8080 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8080
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -j ACCEPT

The container has ip addr 172.17.0.2 on my machine. So I've added this rule:

sudo iptables -t nat -A OUTPUT -s 172.17.0.2/32 -p tcp -d 172.217.3.110 --dport 8080 -j DNAT --to-destination 172.217.3.110:80

To try and get a test request to 172.217.3.110:8080 to request 172.217.3.110:80, but it doesn't seem to work.

edit 2:

If I'm trying to rewrite a port for a service that is listening locally I got it working with this:

LOCAL_IP=192.168.86.30
REQUESTED_PORT=80
DESTINATION_PORT=8080
CONTAINER_IP=172.17.0.2
sudo iptables -t nat -A OUTPUT -p tcp -d $LOCAL_IP --dport $REQUESTED_PORT -j DNAT --to-destination :$DESTINATIO_PORT
sudo iptables -t nat -I PREROUTING -s $CONTAINER_IP -d $LOCAL_IP -p tcp --dport $REQUESTED_PORT -j REDIRECT --to-ports $DESTINATION_PORT

that seems to just work with local ips

edit 3: kube-proxy source has some more information about their approach and various gotcha's:

https://github.com/kubernetes/kubernetes/blob/84dc704/pkg/proxy/userspace/proxier.go#L1133-L1165

https://github.com/kubernetes/kubernetes/blob/84dc7046797aad80f258b6740a98e79199c8bb4d/pkg/proxy/userspace/proxier.go#L1180-L1200

2
  • Docker adds a ton of of iptables rules (a lot more than you've seen). Inserting your own rules there without breaking anything will be quite difficult. Trying to figure out what docker is doing and how your own rules can fit in there will probably be quite time consuming.
    – dirkt
    Mar 14 '20 at 20:28
  • For sure. I'm exploring building something like kube-proxy for hashicorp's nomad. The service will have to manage many iptables rules alonside docker just like kube-proxy does.
    – maxm
    Mar 14 '20 at 20:29
0

Ok, figured it out.

If I would like to redirect traffic from 192.168.86.30:80 to 192.168.86.30:8084 for a container with an ip address 172.17.0.2 then you can add the following rule:

sudo iptables -t nat -A PREROUTING --protocol tcp --destination 192.168.86.30 \
    --dport 80 --source 172.17.0.2 \
    --jump DNAT --to-destination 192.168.86.30:8084

This also seems to work with public external ip addrs.

REDIRECT doesn't seem to work because [source]:

It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface (locally-generated packets are mapped to the 127.0.0.1 address).

Still not entirely sure what was going on, but I think that's why REDIRECT was working with some things served locally (especially anything listening on 0.0.0.0), but not external ips.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.