Summer of Code 2005: Improve Libalias
Libalias is the library used to do masquerading and IP address translation (NAT) in many areas of FreeBSD. Unfortunately libalias has many weakness limiting its usage i.e:
- Libalias was not meant to be part of the system firewall ipfw, so it's not directly integrated with it, forcing the user to use an userland demon for the address translation, operation that results in a waste of cpu cycles and in a loss of ipfw's flexibility. To fix this problem i'll integrate libalias straight into ipfw.
- Libalias didn't natively work in kernel mode, so it couldn't be used in any network operations inside the network stack, pushing the developer to write its own routines when needed. Right now there's a version of libalias running in kernel mode for 6.x branch, my goal will be to port it in 5.x and 4.x branches too.
- Libalias has a monolitic design, therefore implementing the support for a new protocol reveals to be an hard task for the developer. One of the major improvement to the design of libalias will be to create a mechanism that will let people add support for new protocols dinamically.
Moreover, during the work I'll explore the use of new data structures and algorithms to reduce the impact of translation operations on system resources.
Libalias is largely used in FreeBSD userland (from natd to ppp), and I truly believe that fixing the existing issues will greatly enhance the usability of this library, reducing the number of code duplication across the entire code base and permitting the creation of a new number of features based on it.
- add libalias hooks to ipfw2 in 6.x, 5.x and 4.x
- port libalias-as-a-kernel-module to 5.x and 4.x (these two points before end of July)
- define and implement a mechanism to ease adding new protocol handlers to libalias
- implement at least one new protocol handler to prove the effectiveness of the above mechanism
- cleanup libalias code, locate weak points (e.g. inefficient data structures, etc.) and replace with more efficient ones
Work in progress
First status update and first milestone!
Ok, i've to report that ng_nat and libalias, right now, seem to work well on 4.x, 5.x and, of course, 6.x. I spent the beginning of SoC setting up a decent environment to work and test all the stuff on 3 different versions (4.x, 5.x and 6.x), and i've to admit that my pet project (miniBSD) was not up to the task...
In the mean time, i've developed even the first patchset that add nat (through libalias) support in ipfw2: right now it compiles and works (more or less) on 6.x, but i've still some problems; hope to fix it VERY soon.
Second status update and second milestone!
I'm happy to announce that my first experimental patchset that adds nat support (trough 'nat' action) to ipfw2, seems to work! Unfortunately, me and Luigi didn't decide yet how to manage different aspects of the ipfw2+nat integration, so there's still some work to do, but the basic nat mechanism works!
Yuuuupppiiii.... Just in time for the FreeBSD Status Update...
Me and Luigi settled on a new syntax for nat support into ipfw, that tries to resemble pipe&queue:
- ipfw add 100 nat N ... - add a new rule to firewall ruleset with nat action where N is
- nat identifier (number/string)
- ipfw nat N config ... - configure nat address, mode, etcetc
- ipfw nat N delete - delete nat instance N
- ipfw nat N show config - show nat instance N configuration
- ipfw nat N show - show nat instance N sessions
In the mean time, while i'm working on this synatx, you can test libalias and ng_nat in 4.x and 5.x using the following patches:
these one fix m_move_pkthdr in 4.x and 5.x, and make it cluster safe: it's mandatory to apply this patch if you want to use libalias as kld or ng_nat.
these contain libalias and ng_nat kld and add a couple of functions to libkern (strspn in 5.x, strspn and strsep in 4.x). Or if you prefer the all-in-one approach:
just grab one of them.
Whatever you choose, after you applied the correct patches, you have to rebuild kernel (due to m_move_pkthdr and libkern modifications), then go to libalias dir (sys/modules/libalias), make && make install, then go to ng_nat dir (sys/modules/netgraph/nat), make && make install and you are done.
Libalias works like userland counterpart, so if you want to know more about it, man libalias. For ng_nat there's no man page in the previuos patches, but i put a copy of 6.x ng_nat man page here, so copy it to /usr/share/man/man4/, and man ng_nat if you want to know how to use it.
If you want to easily test ng_nat with netgraph, use this script.
The entire work is based on Glebius Smirnoff efforts made in 6.x, and there's no differences in funcionatilies, so credits go where they are due, i just backported it...
Integration of nat in ipfw is going well, everything seems working. Right now i'm adding log support to libalias kld via sysctl: actually there're still some problems and i don't think using a sysctl is the best solution but for now i can live with it. When log support will work, i'll release another set of patches to test it: hope to do it VERY SOON...
Ok, ipfw and nat integration is officialy finished, and i'm heading toward modularizing libalias.
So far i've added log support to libalias trough syslog and to a char * buffer added instead of the regular FILE * entry in struct libalias. Luigi is reviewing my work right now, when i'll get an ok i'll post another set of patches.
Next step consists of refactorying libalias, giving it a better and more logical shape. Probably i'll add a fingerprint function to every supported protocol, and i'll load all the protocols module into a list. Then, for every packet entering libalias, the protocol list will be scanned, and for every loaded module the fingerprint function will be called: first one to match the packet, will get/translate it.
That's all for now, see u later.
Actually i achieved this a couple of days ago, but i was too lazy to update my wiki back then... :P Libalias is modularized now (at least in kld world), that means that it's finally possible to load/unload support for new protocols at runtime, without rebooting the system.
Now i'm trying to do the same in userland, but i didn't yet decide what to use to do it... :P
Hope to finish this part soon too...
Here we are, Summer of Code 2005 has gone and i can finally deliver my work: all the deliverables were met, so you can try ipfw with nat, libalias modules and so on.
You can find a tarball with all the necessary stuff here There's a readme inside that explains how to compile/install it and how to use it.
Enjoy and fell free to report any problem that you may encounter.
Made a second release of libalias, with little cosmetic and usability fixes. You can find it in the same place of the previous one: here.
While there, i updated my work to FreeBSD's perforce repository, so you can check it out from there too.
I'm working on redirect support but while here, i decided to pack a new release with fixes to make it compile/work with RELENG_6 (back then it was current and a couple of things changed - enough to breake my stuff of course... ) Find it here.
I finally decided to release a new version of libalias+ipfw with the following changes:
- dinamyc address support via interface name (ipfw nat 111 config if tun0)
- redirect and LSNAT support in ipfw following closely the natd syntax. The only difference with natd is that i changed the syntax from redirect_[addr|port|proto] to redir_[addr|port|proto]. See natd man page for details about redirect and LSNAT.
- patches for ppp and natd to use libalias modules (see libalias/patch/)
- many bugfixes and improvements here and there
It was tested on 6.x, it compiles fine on 4.x, 6.x and 7.x, for 5.x i just made the diffs. Download it here and enjoy.
For some unknown reason, my old host has problems serving the libalias archive, so i moved it here.
Released a new version of this work as a patchset for 6.x, get it here:
fixed the checksum corruption occurring to redirected/generated traffic to/by a local interface on the nat box.
To apply/insall it:
cp libalias_ipfw.patch /usr/src
patch -p3 < libalias_ipfw.patch
then recompile & install:
kernel, sbin/ipfw, sbin/natd, sbin/ppp, lib/libalias, sys/modules/ipfw, sys/modules/libalias
and copy /usr/src/etc/libalias.conf to /etc.
With this patch you get:
- ipfw nat + redirect + LSNAT support
- libalias modules (both in user and kernel land)
- for kernel land, all the libalias modules are installed
- in /boot/kernel as alias_*.ko.
for user land (natd & ppp), modules are shared lib
- loaded according to /etc/libalias.conf. To reload modules for a known process, 'kill -HUP $PID' it.
- for kernel land, all the libalias modules are installed
natd & ppp patched to use libalias modules
If natd/ppp/ipfw behaves strangely after you applied this patch (i.e. active ftp stops working), check libalias modules.
Some ipfw examples:
ipfw add nat 666 all from any to any via $IF
ipfw nat 666 confg ip 192.168.0.1 # nat with a fixed address
ipfw nat 666 confg if $IF log # dynamic if addr nat and logging
ipfw nat 666 confg if $IF redir_port ... # redirect support with
ipfw nat 666 confg if $IF redir_addr ... # linkspec natd syntax,
ipfw nat 666 confg if $IF redir_proto ... # LSNAT works too.
# different ipfw rules can be redirected to use the same nat instance
ipfw add nat 666 all from $IP1 to any via $IF1
ipfw add nat 666 all from any to any via $IF2 out
ipfw add nat 666 all from $IP2 to $IP3
ipfw nat show # see logs
ipfw nat show config # nat configuration
To load/unload a libalias module (kernel):
kldload alias_ftp # active ftp work ok now
To load/unload a libalias module (user):
[edit /etc/libalias.conf and add/cut needed modules] and kill -HUP $PID
For more info see the readme inside the archive.