NICMx / Jool

SIIT and NAT64 for Linux
GNU General Public License v2.0
319 stars 66 forks source link

Add support for draft-ietf-sunset4-nat64-port-allocation #175

Open ydahhrk opened 8 years ago

ydahhrk commented 8 years ago

2018-11-25 Update

Hello. If you came here from the survey, you'll notice that this thread used to be a pretty lousy introduction to the feature. So I'll try again:

I think it's best explained through an example:

Suppose that your NAT64 has 5 IPv6 customers (Where "customer" is either an IPv6 address or a block of IPv6 addresses assigned to someone) and your pool4 has 1000 transport addresses.

Currently, Jool assigns those transport addresses on demand. For example, if customer A requests one transport address, Jool will give it one transport address. If customer B requests the remaining 999 addresses, Jool will give it the remaining 999 addresses. And customers C, D and E will get nothing.

Greedy customers can be currently addressed through the use of mark, but this loses convenience as your customer pool grows.

So the idea is that you will be able to tell your NAT64 something along the lines of "automatically divide the pool4 into 5 blocks, and assign them evenly to each of my customers."

Because this will also make your transport address assignments predictable, it will also free you from the need of BIB logging.

Progress: A first iteration of this feature has already been coded, and can be found in the issue175 branch. It's missing documentation, a (likely arduous) merge and some testing.

Original post

This is the draft as of now. It's mostly added flexibility to pool4.

Stuff I find particularly attractive:

Supporting these is valuable even if the draft doesn't reach RFC status.

This will take a while. It's definitely post-issue-140 material.

ydahhrk commented 8 years ago

This is assigned to both @frutos93 and @ddnov89. (Github doesn't support multiple assignees.)

toreanderson commented 8 years ago

I wasn't sure to leave this comment in this issue or in #114 but here goes...

Accessing IPv4 FTP servers through Jool generally works fine, provided that the server supports the EPSV command. However, there is one gotcha: Some (most?) FTP servers require that the data connection come from the same client source IP address as the control connection. That breaks if Jool is configured with an IPv4 pool containing more than a single address, as Jool may then pick a different IPv4 transport address for the client's FTP data connection, which will be rejected by the IPv4 FTP server.

Jool could help work around this problem by ensuring that individual sessions originating from a single IPv6 client address is always assigned the same IPv4 transport address (to the extent possible - it could of course be that the IPv4 transport address in question is fully utilised, in which case it is preferable to fall back on another available IPv4 transport address rather than failing to set up the binding/session).

ydahhrk commented 8 years ago

Jool could help work around this problem by ensuring that individual sessions originating from a single IPv6 client address is always assigned the same IPv4 transport address

BTW, Jool 3.3 tries very hard to do this. (If the newer features aren't an issue, maybe a downgrade isn't so bad.)

It's one of the RFC 6146 pool4 requirements I had to discard from Jool 3.4 because it's very anti-RFC6056-y:

Address preservation, as well as parity/range port preservation were not considered in this iteration (and there's uncertainty on whether they will return in the future) due to the potential performance impact and the newer RFCs' complete disregard of them.

(6056 is a lot friendlier to 7422 and draft-ietf-sunset4-nat64-port-allocation than original NAT64 (6146).)

("Address preservation" is when the NAT64 tries to mask all packets from the same IPv6 node using the same IPv4 address. I think I came up with that expression.)

That said, making the 6056 algorithm work as you want doesn't sound too hard. Maybe we could turn it into a configuration switch, even.

Here goes nothing:

RFC 6056 (or, more specifically, algorithm 3 of RFC 6056) defines a means to find a transport address which is reasonably random and dependant of several original packet fields. This transport address is then used as the source of the translated packet. The fields included in the equation are

The rationale, I think, is that all packets that share those values will yield adjacent translated source transport addresses (well, they will yield the same translated source transport address. But BIB will tweak the ports a little since they aren't allowed to collide). This is a form of "attempted" address preservation in that packets that share source address and destination do tend to be sourced similarly, but it doesn't guarantee the pool4 address completely runs out of ports before moving on to the next one. Still, it's clever and does what it wants well.

If "Destination port" wasn't part of that list, your EPSVs would work much more reliably, right?

So maybe we should let the operator decide which fields should be present in the equation. We could even throw Source port to that list for shits and giggles (and disable it by default).

So you would remove Destination port and cope with the increased binding collision due to internal nodes sometimes talking to the same external nodes.

It would be easy to implement. Would it be worth the performance hit, though?

toreanderson commented 8 years ago

If "Destination port" wasn't part of that list, your EPSVs would work much more reliably, right?

Exactly. The destination port of the FTP data connection is picked randomly by the server on-demand. Ensuring FTP to EPSV-capable servers works would be worth the performance hit for me.

pierky commented 8 years ago

I run some tests using an old server (2 x 3.00 Intel Xeon, 800 Mhz bus, 2 MB L2 cache) to evaluate the impact of a lot of ip6tables -t mangle ... --set-mark x and jool --pool4 --add ... --mark x statements.

The goal was to leverage the (great) feature introduced with #115 to obtain a deterministic mapping between IPv6 source addresses and IPv4 addresses and ports used in NAT64 (you know, to avoid heavy logging).

So, I used iperf in TCP single connection mode to send traffic from the IPv6 host (100 Mbps NIC) toward an IPv4-only host (100 Mbps NIC) via the Jool box.

I know these tests have rough edges (I'll continue to work on them), but do you think these numbers make sense? It seems that the bottleneck is in the Jool's lookup mechanism more than ip6tables. If so, do you think implementing RFC7422 deterministic algorithms may lower this bottleneck?

ydahhrk commented 8 years ago

Those results make sense.

Each translation involves pool4 lookups, which are implemented as an ugly sequential search. From what I can remember, this is because other requirements prevent pool4 from being stored sorted in any way. (But I should probably take another peek since it sounds quite unreasonable.)

You are correct; implementing RFC7422 deterministic algorithms will lower this bottleneck, because it converts a lot of the algorithm complexity to straightforward address arithmetic.

I forgot to mention this feature is being worked on here, but is rather far from completion still. RFC7422 is part of what draft-ietf-sunset4-nat64-port-allocation wants.