Firewalling 90% complete & tested, questions about writing tone

Dagmar d'Surreal dagmar.wants at
Wed Apr 28 14:59:32 PDT 2004

OKay.  I've written some stuff and done some stuff that I'm relatively
sure of.  Some of it's still ugly, and some of it burns CPU cycles
unnecessarily, but shouldn't slow down boot time more than 1/10th of a
second even on a slow machine.  That having been said...

I've got routines now called resolve_address() the utility of which
aren't exactly obvious.  In an effort to make configuring firewalling
rules really, _really_ automagical within init scripts, one may now
specify them as follows...  (this example should be entirely
self-explanatory, although somewhat stupid)

permit_inbound from INTRANET for ssh

What this one little line will do in the init script is call
resolve_address for both from and to.  The identifier INTRANET is one of
the automagical things... these are in all-caps because it's too much of
a pain in the ass to sort out possible collisions between entries in the
hostname database and these tokens.  The automagic entries are as
follows... I need to know if anyone sees anything wrong with the logic
in sorting these out...

ANYWHERE: obviously.
NOWHERE: not defined, not sure if there's a reason to, either.

These may be overridden in /etc/sysconfig/network:
INTRANET: If not set in esn, this will be auto-selected based on all
interfaces that exist (excepting lo obviously) which do not have a
default route to
EXTRANET: This will be all interfaces which have a default route to bound to them.
DMZNET: I can't for the life of me think of a good way to detect this
any differently than INTRANET without going into some bash math to
determine network "size" which doesn't appear to be a good solution. 
Setting it in esn is the only option at the moment.

INTERNAL: This is the interfaces which don't have the default route.
EXTERNAL: This is the interface which does have the default route.
DMZ: This is the interface for the DMZ.  (Again, set in esn)

INTERNALIP: Ip address bound to the interface...
EXTERNALIP: (obvious)
DMZIP: (obvious, esn)

Pretty much everything that uses these runs through a for loop, so
multiple entries should be space separated, although I'll probably go
and change that to allow comma separation if I can do it neatly.

Now, as to the arguments to permit_inbound and permit_outbound... 
anything that doesn't match a magic token will be passed through without
analysis, so yes you can make typos and error handling is more or less
nonexistant at the moment.  Most of these arguments are just as optional
to the bash function as they are to iptables.

over [protocol] - This will take TCP, UDP, and ICMP as rather dumb magic
tokens at the moment.  Numeric protocol support (for ipsec stuff) may or
may not work with this.

for [service] - This will either take a port number, or anything
alphanumeric passed to it will be searched through /etc/services for. 
HOWEVER, if it's gotten from /etc/services it's going to set 'over' to
whatever protocols are listed there.  You can override having rules for
both tcp and udp when only one is needed with the 'over' directive.

on [interface] - This will control what interface rules are applied to. 
You can use the appropriate automagic token, or you can specify an
interface name that ifconfig sees, so if you've named your interfaces
(let's not go into much detail, but you _can_ change eth0 to be named
external or fred if you like with a little work) this won't shatter.

from [address] - Heavily magical.  If you specify something external,
it's going to also set 'on' so the rule won't be applied to all
interfaces.  The same goes for internal and dmz.

to [address] - Just as magical as 'from'.

user [username or uid] - will translate usernames to uids because
iptables doesn't accept anything but numerics.

group [groupname or gid] - (obvious)

One last bit, I have no idea how to make this syntax encompass a simple
way to declare a masquerading rule.  I suspect the simpler way will be
to just make a new function to set those up.

Any comments at all?  I'll be posting the scripts to the list this
weekend for public testing if everything continues to not explode here.
What I've said before about these directives never being invoked if you
set FIREWALL_SCRIPT in esn still holds true.  At one point I had things
"wired" so that the commands would all silently do nothing if this was
set, and then realized how dimwitted that would be.  ;)

More examples:

(Allow a local caching mail server to deliver mail from local network
permit_inbound from ANYWHERE to INTERNALIP for smtp
permit_outbound from EXTERNALIP to ANYWHERE for smtp user smmta

(Allow access to the local webserver)
permit_inbound from ANYWHERE for http

Footnote: Having and using the user/group directives is good stuff. 
There's no sense in allowing shell users to go 'round spoofing mail if
you don't want them to.  One could also prevent shell users from running
eggdrops in a similar manner (making ircII sgid ircusers and so on).

I'll also add that anyone who doesn't like two-space tabs can bite me. 
The for loops wind up getting really, really deeply nested and there's
no way the support script will ever be formattable within 80 columns
unless two-space tabs are used (without making it unreadable, which is

Never again will I write anything like this in bash script.  Many times
I came very close to throwing the support code out and rewriting it in
perl (which would have taken about three hours total).  Anyone know of a
recipe for doing getopts style parsing for bash functions?

Last question, for the explanations of stuff, are these sections all
expected to be in one consistent style, using professional technical
language or is a conversational tone okay?  I would personally prefer to
use the latter since I've found you lose fewer people who are in over
their heads that way.
The email address above is phony because my penis is already large enough, kthx. 
              AIM: evilDagmar  Jabber: evilDagmar at

More information about the hlfs-dev mailing list