Here at the University of Delaware we were looking for a way to lock-down our campus license server to off-campus IPs. The particular way that we run FlexLM leaves all of the vendor sub-daemons registered on random TCP ports, making a strict and static software firewall setup inaccessible.
Trying to get a large population of end users to install and begin using our VPN from off-campus presented quite a challenge. Since VPN funnels all of the user's traffic through the University via the user's ISP, it also seems excessive to increase the VPN load strictly for the sake of passing a couple of packets to the license server.
In looking for another solution I came across the address pool and “auth” features in IPF. The address pool would allow us to manage a dynamic list of off-campus IPs we've authorized to communicate with the license server. Two drawbacks to using the pool feature would be
Both of these properties would be handled quite easily by a transactional database: the address list can be arbitrarily large and the database itself would handle the locking/sequencing. Considering the fact that whatever application we created to allow our end users to authorize specific off-campus IPs would store its data in a database anyway, it would be wonderful to be able to interface IPF to that very same database. That's exactly what the “auth” IPF feature is meant to do: provide a means for a userland program to programmatically block/pass packets!
The IPF firewall software has a little-used feature that allows one to write rules that will attempt to build a packet disposition by passing the packet (headers only or headers and payload) to a program running outside the kernel. The userland program must open the
/dev/ipauth device and perform
ioctl() calls to wait for a packet and to pass back the disposition. An example program exists in the official IPF source distributions; this program holds lists of authorized IPs in memory. The goal of
pgipfauth is to use a Postgres database to hold a persistent, possibly large list of authorized IP addresses and consult that list as needed. Authorizations are cached by
pgipfauth to attempt to decrease the number of database queries which must be performed.
Combined with the connection state table of IPF, the typical TCP connection profile is handled quite efficiently:
pgipfauthqueries the database with the orginating IP, decides to BLOCK or PASS, caches the IP + disposition
For the lifetime of the cache record added in step 2, the primary difference in the connection profile is that the database is never queried:
pgipfauth merely returns the cached disposition.