I am currently writing a tree-based firewall library and close to wrapping up the core parts. I would like to ask for preference of naming conventions for NAT from potential users as I am working on the NAT module now.
If you spot any missing NAT types in the list, please do correct me as well so I don’t miss them in the implementation.
I mentioned the library briefly in another thread, you can see the development progress at the repo.
Context
The issue I have stems from the myriad names a type of NAT may have across different vendors (Cisco, Juniper, Linux, etc), and even a “type” of NAT is not very concretely defined in some instances.
Currently I have identified the following major types of NAT
Static one source IP to one source IP mapping
Aliases
Source NAT
Static NAT
Static one destination IP to one destination IP mapping
Aliases
Destination NAT
Static one destination IP+port to one destination IP+port mapping
Aliases
Destination NAT
Port forwarding
Dynamic source IP pool to source IP pool mapping
Pools may or may not be of the same size
Aliases
Source NAT
Dynamic destination IP pool to destination IP pool mapping
Pools may or may not be of the same size
Aliases
Destination NAT
Dynamic NAT
Load balancing
Dynamic source IP pool to one source IP mapping
Aliases
Masquerading (iptables)
Overloading NAT
Dynamic NAT with Port Address Translation (PAT) overloading
Naming convention of library
A NAT unit would be represented as a node in the firewall tree. The API providing NAT functionality would give you a function to create a NAT node.
Using one source IP to one source IP as an example, this may look like
val make_ipv4_nat_static_single_src_to_single_src :
(ipv4_addr * ipv4_addr) list -> selecting_modifier
where selecting_modifier is one of the basic node variant in the library.
Question
For each type of the NAT, is there a preferred way/direction that you’d like them to be named?
Directions may be like
Lean closer to a given vendor’s terminology
Lean closer to the nature of mapping (static one to one, dynamic many to many, dynamic many to one)
Lean closer to colloquial terminology (e.g. prefer port forwarding over DNAT)
If the firewall rules were written in OCaml, one could solve this with one or two constructors, which received a callback which made the choice, so I understand the reason to enumerate the various translations may be that it should be possible to load firewall rules from some data source?
I think one additional question to ask in the dynamic cases is what kind of algorithm will be used to decide the result, e.g.:
round robin or random choice for load balancing
destination based on the hash of the source for load balancing when the same clients use the same server
a stateful allocation scheme, e.g. to map source connections to source ports for masquerading
a deterministic mapping from address/port range to address/port range
Though this may be implied by the case-by-case analysis, as it allows for a different algorithm in each case.
You should probably review the relevant Best Current Practice documents in the IETF Request For Comments (RFC) series, e.g. RFC 7857 and its predecessors. See especially the Terminology section, for starters, but all the various documents introduce additional relevant terms and definitions in the normative text.
That’s partially the reason, yes. Ideally the library can emulate behaviour of either iptables and pf.
The text of yours about underlying algorithm used is a really good point which I didn’t consider, thanks! This reminds me maybe usage of (first class) module to package the algorithms used would be worth exploring later on.
I just wanted to second this as an excellent aspect to consider when designing the library. Having the algorithms and decision mechanisms implemented separately, and then combined to form the specific NAT would be useful. I could imagine having a very different NAT strategy for a home network vs a locked down enterprise network (or indeed, why aren’t our home networks locked down?).
One fun example of dynamic selection might be to use Irmin to do port allocations based on the application state that is requesting the NAT mapping. I wonder if you could combine some aspects of HTTP2 multiplexing with smart IP port reuse across multiple requests.
Sorry I’m a bit confused, could you elaborate on what you mean by application state?
I feel like I’ve missed something but I’ll ask anyway - doesn’t HTTP2 multiplexing use the same TCP connection for multiple requests? In that case there would not be need for a different port allocation strategy?