Skip to content

portmap plugin nftables backend intercepts non local traffic #1209

@champtar

Description

@champtar

Original messages by @agusdallalba:

This PR introduced a regression.

Let's say I want to forward incoming traffic to UDP port 53 to a pod with IP 2001:db8::53 on port 1053.

The cni_hostport table ends up looking like this:

table ip6 cni_hostport {
	comment "CNI portmap plugin"
	chain hostports {
		udp dport 53 dnat to [2001:db8::53]:1053 comment "d26f04dc7a080fb543e92051a5a5784923334f0713b72ae1c1349c1830a5e889"
	}

	chain hostip_hostports {
	}

	chain prerouting {
		type nat hook prerouting priority -100; policy accept;
		jump hostip_hostports
		jump hostports
	}

	chain output {
		type nat hook output priority -100; policy accept;
		jump hostip_hostports
		fib daddr type local jump hostports
	}

	chain masquerading {
		type nat hook postrouting priority 100; policy accept;
		ip6 saddr 2001:db8::53 ip6 daddr 2001:db8::53 masquerade comment "d26f04dc7a080fb543e92051a5a5784923334f0713b72ae1c1349c1830a5e889"
	}
}

The prerouting chain is not filtered in any way! All UDP 53 traffic passing through the node (including internal pod traffic) will be forwarded to 2001:db8::53:1053, not just traffic destined to the node.

In my case this broke DNS resolution inside the pods. If I had forwarded TCP port 8080 I would have broken internal services using that port.

I suspect all that's needed is to add the fib daddr type local condition to the prerouting chain.

@danwinship @squeed
Thinking about it a bit more, in the iptables version hostIP also only work for local IPs
https://www.cni.dev/plugins/current/meta/portmap/#dnat

// The basic setup (all operations are on the nat table) is:
//
// DNAT case (rewrite destination IP and port):
// PREROUTING, OUTPUT: --dst-type local -j CNI-HOSTPORT-DNAT
// CNI-HOSTPORT-DNAT: --destination-ports 8080,8081 -j CNI-DN-abcd123
// CNI-DN-abcd123: -p tcp --dport 8080 -j DNAT --to-destination 192.0.2.33:80

ie the fix here is to use fib daddr type local for hostPorts and hostPorts with hostIP

Is it ok with everyone to remove the hostip_hostports chain and cleanup the code ? For people using hostPorts with hostIPs AND the nftables backend this means they would need to restart their containers during upgrade, but this seems acceptable to me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions