📜 ⬆️ ⬇️

Overview of Nuclear NAT in FreeBSD

There are quite a few common variants of NAT under FreeBSD. This is also natd, ipnat, pfnat, ng_nat, or as an option “buy an ASA 5550 and don’t get it.”


Unfortunately, recently I came across very few good and most importantly accessible articles on ipfw nat which appeared, if my memory serves me as early as 7.0.
We will consider it under a magnifying glass today.

True adherents of pf under kat are recommended not to drop in, so as not to injure yourself with excessive knowledge.
')


First, explain why ipfw nat
First, because I am a supporter of simple and obvious solutions, the support of which is possible almost at a glance without long meditations and reflections on the topic “but how does it work? Ooh. Unfortunately, I can not attribute to these non-trivial hybrids of the form ipfw + pfnat.
Secondly, there are already quite a lot of documentation on ng_nat and pfnat (nat on intif from somenet to any -> extif - Y?).
Thirdly, I use ipfw, and I love it - for simplicity, clarity, predictability, dummynet and hybrids of the form ipfw + pf + altq ... in general, we look at “First”.

Materiel
We will consider ipfw nat on the example of a spherical horse-like network in vacuum depicted just above. Actually, according to the scheme, everything is pretty clear - we will immediately make a reservation that we will network 172.16.0.0/21, the address hangs on em1, say 8.8.8.8 and the internal resources of the network to which we do not need to broadcast addresses - such as, for example, corporate porn archives mail servers and other necessary things will live with addresses, say 8.8.8.9, 8.8.8.10
The ipfw nat functionality almost completely duplicates the libalias functionality, which is also used by natd, ng_nat.
If a very crude end in itself NAT server is reduced to replacing src-ip in packets that came to the internal interface (in our case em0) to the address of the outgoing interface (in our example em1) and entering data into its correspondence table for the inverse transformation upon the arrival of the necessary packets in reply. Further, all the appropriately aligned packages fly away either by default or wherever you need (if, say, a PBR is freaked out).

Total in the base case, we need the following

Enumerate the kernel with ipfw, ipfw nat, libalias support

# cd /sys/i386/conf/
# cp GENERIC NAT
# vim NAT


Then we insert something similar to this:

ident NAT
options IPFIREWALL
options IPFIREWALL_DEFAULT_TO_ACCEPT
options IPFIREWALL_FORWARD
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=50
options IPFIREWALL_NAT
options LIBALIAS
options ROUTETABLES=2
options DUMMYNET
options HZ="1000"


We assemble and install a new core as a precautionary one.

# cp -R /boot/kernel /boot/good
# config NAT
# cd ../compile/NAT
# make depend
# make
# make install


Add to /etc/rc.conf
firewall_enable="YES"
firewall_nat_enable="YES"
dummynet_enable="YES"
firewall_type="/etc/firewall"


As if it should hint that we will carry out the initialization of ipfw using the / etc / firewall that you want in the simplest case, to look like this:

#
table 2 add 172.16.0.0/21

# nat
table 9 add 8.8.8.8
table 9 add 8.8.8.9
table 9 add 8.8.8.10

# nat =)
nat 1 config log if em1 reset same_ports
add 1200 nat 1 ip from table\(2\) to not table\(9\) via em1
add 1300 nat 1 ip from any to 8.8.8.8 via em1


To calm your conscience you can do something else in /etc/sysctl.conf

net.inet.ip.fw.one_pass=1
net.inet.ip.fastforwarding=1
net.inet.tcp.maxtcptw=40960
kern.ipc.somaxconn=4096
kern.ipc.nmbclusters=65536
net.inet.tcp.nolocaltimewait=1
net.inet.ip.portrange.randomized=0


After the reboot everything should work. It checks the performance of this all very simple method

ipfw nat 1 show
nat 1: icmp=271, udp=45462, tcp=61534, sctp=0, pptp=0, proto=1, frag_id=2 frag_ptr=0 / tot=107270


This is the scant statistics compared to pfctl –sa, using the log parameter to collect ipfw nat.

Let's briefly run through the options with scant knowledge about which we can learn from man:

if - interface on which address translation will be performed
log - includes logging of “exhaustive” statistics on internal connections that we have already seen (ipfw nat1 show)
reset - hints that the interface should be cleared when the interface is changed
deny_in - prohibits passing packets from the outside for which no match was found in the internal table.
same_ports - if possible, keep the original ports in outgoing packets (it is recommended to enable)
unreg_only - to disguise only packets coming from "unreal" networks .
redirect_addr intip extip - instructs to wrap traffic coming to extip to the machine with intip. Similarly, the redirect_port and redirect_proto options work, which are useful for “pushing” some machines with necessary services for NAT.

Actually we can populate instances of nat as many as you like and on any interfaces / ip (ipfw nat 2 config log if em2 reset same_ports, for example) and wrap the traffic in them as we like.
The memory that ipfw nat uses in its work is the memory available to the kernel and looks with
# sysctl -a | grep kmem
vm.kmem_size_scale: 3
vm.kmem_size_max: 335544320
vm.kmem_size_min: 0
vm.kmem_size: 335544320


To spin it using the KVA_PAGES kernel option (maximum 512, which corresponds to 2GB for i386).

Somehow it is subjective, with a good load on the channel (I get out at> 350-400Mbit / s), a periodic restart of the nat instance may be required, in order to free up the memory that is eaten by its labels. I think the dog rummaged through the slow mechanism for shooting expired sessions. Restart can be done with an elementary script like:

#!/bin/sh
/sbin/ipfw nat 1 delete && /sbin/ipfw nat 1 config log if em1 reset same_ports


Also, as everyone comes around, they step on the rake with the fact that libalias itself is categorically not friendly with the hardware checksum readers as well as with tcp segmentation offload, we initially recommend configuring cards in a similar way:

cat /etc/rc.conf | grep ifconfig
ifconfig_em1="inet 8.8.8.8 netmask 255.255.255.0 -rxcsum -txcsum -tso"


That's all. Everything works transparently, does not initially have diseases with services such as pptp, ftp (pfnat) and does not suffer from depressing sluggishness due to switching to user space (natd). The only thing that can really be missed is the normal way to nat-it from under the address pool. The only thing that comes to mind in this case is to spawn many instances on aliases, but it looks like it is not as beautiful as, say, pfnat.

Somehow it turned out messy, but I hope visually.

On the topic of the next article, the question arises - would it be interesting for someone to see a step-by-step guide on installing billing with traffic distribution on remote NAS and netflow accounting? Well, actually, how are solutions freely scalable horizontally, unlike all that I described in previous articles? Or write about something less narrowly specific?

PS I was hinted that I had already used it in my examples under the guise of the “real” ipishki dns google. Yes, I know about RFC3330 where it says that "192.0.2.0/24 is assigned as" TEST-NET ", but somehow I don’t know, it’s clearer for myself that you can do something :)

Source: https://habr.com/ru/post/102739/


All Articles