Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wider_world_to_container not applying when external_network_interface is 'lo' #405

Open
xepa opened this issue Apr 6, 2021 · 2 comments

Comments

@xepa
Copy link

xepa commented Apr 6, 2021

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'  
@pitkley
Copy link
Owner

pitkley commented Apr 11, 2021

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:

  1. Keep the configuration as is and introduce a special case for when the external_network_interface contains/is lo, generating the matching output nat chain rules.
  2. Allow specifying a complex type for external_network_interface like { name = "lo", is_local_interface = true } for situations where a local interface is not called lo (while retaining backwards-compatibility to the simple string-type, of course).
  3. 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.
  4. 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.)

@xepa
Copy link
Author

xepa commented Apr 11, 2021

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:

  1. 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 the external_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.
  2. I do not know if there are loopback interfaces not called lo 🤷 I noticed that the rust code for pnet has the is_loopback maybe that can be useful, but I would not change this (maybe a future major version).
  3. this might also introduce more complexity and more edge cases (it would also prevent using them at the same time).
  4. 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 called lo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants