wider_world_to_container not applying when external_network_interface is 'lo'
Opened this issue · 2 comments
I am currently using wider_world_to_container rules
to "bind" containers to localhost. If there is another way of doing this please let me know.
[[wider_world_to_container.rules]]
network = "network"
dst_container = "container"
expose_port = [9999]
external_network_interface = "lo"
With the above config I would expect a connection from the host running the dockers to 127.0.0.1 port 9999
to be routed to the container container
on the docker network network
I notice that the dnat rules this config creates are placed in the following (other rules are removed)
table ip dfw {
chain prerouting {
type nat hook prerouting priority dstnat - 5; policy accept;
tcp dport 9999 iifname "lo" meta mark set 0x000000df dnat to 172.29.0.3:9999
}
}
table inet dfw {
chain forward {
type filter hook forward priority filter - 5; policy accept;
....
tcp dport 9999 ip daddr 172.29.0.3 iifname "lo" oifname "br-network" meta mark set 0x000000df accept
}
}
this might work for external traffic but localhost traffic does not pass the prerouting nat chain
but instead uses the output nat chain
with the following I can allow this.
nft 'add chain inet dfw output { type nat hook output priority -5; }'
nft 'insert rule inet dfw output meta mark set 0x000000df oifname "lo" tcp dport 9999 dnat ip to 172.29.0.3:9999'
nft 'insert rule ip dfw postrouting ip saddr 127.0.0.1 oifname "br-network" tcp dport 9999 masquerade'
Hi @xepa, thank you for reaching out. I had never really thought about the use case of NATting traffic from the host itself to a container, mostly because I probably always used port-publishing for this, but I understand how NATting it could still be preferable.
I have not thought a potential solution for this through entirely, so I'd like to get input on what you think would be a good solution from a usability standpoint:
- Keep the configuration as is and introduce a special case for when the
external_network_interface
contains/islo
, generating the matchingoutput nat chain
rules. - Allow specifying a complex type for
external_network_interface
like{ name = "lo", is_local_interface = true }
for situations where a local interface is not calledlo
(while retaining backwards-compatibility to the simple string-type, of course). - Extend the
container_dnat
implementation to not only allow cross-Docker-network NATting, but allow the source (and maybe destination) network to be a non-Docker network, too. - Add a new
host_to_container
configuration category that supports this use-case.
I personally think that the last one would probably be the most consistent, although I also don't dislike the other options. WDYT?
(Please note that I can't give you any kind of timeline on when I would get around to implementing this feature, although I'm of course happy to receive and review PRs.)
Hi @pitkley thanks for the response, I am glad that this is listed as an enhancement and I might be able to take a look some implementation myself, hopefully I can brush up my rust knowledge, and find some time somewhere to actually dive in.
Please see my thoughts on the following:
- Some change will have to be done if (4) is implemented a warning (or a documentation gotcha) will have to be added as adding
lo
for theexternal_network_interface
will not lead to expected results (but this would be documented). I have not tested this but this might also trigger if using a non loopback device. - I do not know if there are loopback interfaces not called
lo
🤷 I noticed that the rust code forpnet
has theis_loopback
maybe that can be useful, but I would not change this (maybe a future major version). - this might also introduce more complexity and more edge cases (it would also prevent using them at the same time).
host_to_container
is also my personal best fit, although I would optionally supply the interface, this would then also cover none loopback interfaces and loopback interfaces not calledlo