OpenWrt Forum Archive

Topic: Updated firewall.sh

The content of this topic has been archived on 6 May 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

This is a total rewrite of the firewall.sh.  This was done in order to support dynamic addition/deletions of interfaces (both LAN and WAN) without resorting to grep/-I <line> guessing.

Few notes:
1) There now is a -A INPUT -i lo -j ACCEPT line.  This is to allow loopback
2) All -t filter (INPUT/OUTPUT/FORWARD) will DROP any packets not accepted.
3) Addition of -A FORWARD -j TCPMSS --clamp-mss-to-pmtu line.  I found that using PPPoE, I could not connect to certain sites (probably because they disable ICMP and therefore cannot PMTU properly).  This is a HACK (or so the author of TCPMSS claims), but it works (and is also in the stock Linksys firmware - but in a different manner), and will support PPPoE very nicely.
4) Addition of LAN-IN/WAN-IN.  This is packet terminating ON the router.  If you want to provide services on the router itself, do it on WAN-SVC instead. 
5) Addition of LAN-FWD/WAN-FWD.  If you want to disable forwarding of certain packets (NAT'ed or not), insert additional rules here.  If you want to provide Port Forwarding, do it on LAN-SVC instead.
6) Addition of LAN-SVC/WAN-SVC.  LAN-SVC is kind of misleading, its what's commonly known as port forwarding.  Note, there are TWO LAN-SVC, one for -t filter and one for -t nat, and the arguments are different.  WAN-SVC is for services that the router is providing.  Please look at the examples provided.
7) I've made it so that both ppp0 and vlan1 are covered.  However, it should be that firewall.sh be called to add/delete interface by the correct script (ie. ip-up/default.renew), which is why the ONLY place there is a -i/-o <iface> is on the builtin chain.  But since that would require rewriting the support script (networking.sh), it's the way it is.
8) This is currently a drop-in replacement for the existing firewall.sh.

#!/bin/sh
# OpenWRT Extended Firewall script
# Copyright (C) 2004, Kevin "Starfox" Arima, All rights reserved.
# This code is licensed under the terms of the GNU General Public License Version 2

PATH=/usr/bin:/bin:/usr/sbin:/sbin

ipt="$DEBUG iptables"
ipv4opt="$DEBUG ipv4opt"
inif="br0"
exif="vlan1 ppp0"

ipv4opt () {
  echo $2 > /proc/sys/net/ipv4/$1
}

# Flush everything
tables=`cat /proc/net/ip_tables_names 2>/dev/null`
for table in $tables; do {
  $ipt -t $table -F
  $ipt -t $table -X
  $ipt -t $table -Z
}; done

# Allow loopback
$ipt -t filter -A INPUT -i lo -j ACCEPT

# Create chains
for chain in LAN-IN WAN-IN LAN-FWD WAN-FWD LAN-SVC WAN-SVC; do {
  $ipt -t filter -N $chain
}; done
for chain in LAN-SVC; do {
  $ipt -t nat -N $chain
}; done

# Set default for chains
for chain in INPUT FORWARD OUTPUT; do {
  $ipt -t filter -A $chain -m state --state INVALID -j DROP
  $ipt -t filter -A $chain -m state --state RELATED,ESTABLISHED -j ACCEPT
  $ipt -t filter -P $chain DROP
}; done

# INPUT
# Call LAN-IN/WAN-IN depending on interface

# LAN Input
$ipt -t filter -A LAN-IN -j ACCEPT

# WAN Input
$ipt -t filter -A WAN-IN -j WAN-SVC
$ipt -t filter -A WAN-IN -p tcp -j REJECT --reject-with tcp-reset
$ipt -t filter -A WAN-IN -j REJECT --reject-with icmp-port-unreachable
$ipt -t filter -A WAN-IN -j DROP

# FORWARD
$ipt -t filter -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
# Call LAN-FWD/WAN-FWD depending on interface

# LAN Forward
$ipt -t filter -A LAN-FWD -j ACCEPT

# WAN Forward
$ipt -t filter -A WAN-FWD -j LAN-SVC
$ipt -t filter -A WAN-FWD -j DROP

# OUTPUT
$ipt -t filter -A OUTPUT -j ACCEPT

# PREROUTING
# Call LAN-SVC (Port-forwarding) from WAN interface

# POSTROUTING
# Call MASQUERADE from WAN interface

# LAN Services
# Example: Forward TCP Port 25 (SMTP) to 192.168.1.2
# $ipt -t filter -A LAN-SVC -p tcp --dport 25 -j DACCEPT
# $ipt -t nat -A LAN-SVC -p tcp --dport 25 -j DNAT --to 192.168.1.2

# WAN Services
$ipt -t filter -A WAN-SVC -p icmp -j ACCEPT
# Example: Accept TCP Port 22 (SSH) on the router
# $ipt -t filter -A WAN-SVC -p udp --dport 53 -j ACCEPT

# Internal interface
for if in $inif; do {
  $ipt -t filter -A INPUT -i $if -j LAN-IN
  $ipt -t filter -A FORWARD -i $if -j LAN-FWD
}; done

# External interface
for if in $exif; do {
  $ipt -t filter -A INPUT -i $if -j WAN-IN
  $ipt -t filter -A FORWARD -i $if -j WAN-FWD
  $ipt -t nat -A PREROUTING -i $if -j LAN-SVC
  $ipt -t nat -A POSTROUTING -o $if -j MASQUERADE
}; done

$ipv4opt ip_forward                1
$ipv4opt icmp_echo_ignore_broadcasts        1
$ipv4opt icmp_ignore_bogus_error_responses    1
$ipv4opt tcp_fin_timeout            30
$ipv4opt tcp_keepalive_time            120
$ipv4opt tcp_timestamps                0

I can see where you're going with the idea of providing chains that can be hooked by external scripts but the implementation could be better.

This is a total rewrite of the firewall.sh.  This was done in order to support dynamic addition/deletions of interfaces (both LAN and WAN) without resorting to grep/-I <line> guessing.

Great, since individual setups tend to be so diverse... If you like you could also look at some of the filtering ideas IPCop uses. They categorise interfaces into red (outside wild), orange (pin holed DMZ), blue (untrusted (wireless) with vpn to green), and green (inside trusted to certain extent).

Few notes:
1) There now is a -A INPUT -i lo -j ACCEPT line.  This is to allow loopback
2) All -t filter (INPUT/OUTPUT/FORWARD) will DROP any packets not accepted.

For internal networks I'd prefer to do REJECT, DROP does IMO only make sense for outside interfaces *if* no services/servers are exposed at all. The script might decide about the policy upon wether servers are defined or not.



6) Addition of LAN-SVC/WAN-SVC.  LAN-SVC is kind of misleading, its what's commonly known as port forwarding.  Note, there are TWO LAN-SVC, one for -t filter and one for -t nat, and the arguments are different.  WAN-SVC is for services that the router is providing.

So by SVC you are refering to services? Why not calling it SRV (or server), it might be less ambigous to distinguish LAN-Servers, DMZ-Servers and Router-WAN/LAN-Servers. And be somehow more intuitive that you'd need to inform your firewall about the Servers behind it  that you want to be accessible.

Regards,
-Chris

Looked some more for prior art on firewall scipts today. At the moment I'd tend to suggest  leaving the basic boot firewall.sh script to a bare secure minimum. And then add a configurable (ipackaged) setup script. I found the FireHOL shell scipts seemed best.

It takes a config file like the following simple example to generate iptable rules.

    interface eth0 mylan
        policy reject

                # only allow access to allowed router's server
                 server ssh

    
    interface ppp+ internet
        server ssh  accept src trusted.example.com

        
    router mylan2internet inface eth0 outface ppp+
        masquerade
        route all  accept

The sript consists of (uncompressed plain text)
24K     /sbin/firehol
112K    /lib/firehol

Interesting...

Chris, FireHOL looks like having an easier interface for normal users.
However IPCop's implementation seems more straight forward for developers and less weighted?

Chris, FireHOL looks like having an easier interface for normal users.
However IPCop's implementation seems more straight forward for developers and less weighted?

I'm not sure if it is always that easy to insert correct customizing rules into a iptables rules set you didn't build all by yourself, consider doing this from an install script with the possibity that the rules might have been changed by other packages before yours.

I found the "debug" and "explain" features of FireHOL are very helpfull to audit the generated rules, and give you a commented iptables sricpt.

For OpenWRT I was picturing the FireHOL interface definitions and standard routing definitions could maybe be split up into separate files. That way if you install a sshd it could add a line like "server ssh accept" to say /etc/firehol/lan.interface.


Onother thing is the wheigt of firehol you mentioned. Of course it takes more space than a mostly hardcoded firewall script. Firehol would strictly only be needed to *re*configure the iptables with it. (saying it could be an ipgk) It is planed that the output of firehols "debug" feature can also be directly used as a startup script.

OTOH iptables-save and -resotre take up over 100k on my machine, and they are regular i386 striped binaries, not (commented) plain text shell scripts that could possibly be compressed.


In the FAQ the author writes his personal  FireHOL config has 50 lines and:

These 50 lines produce about 900 iptables statements. For BASH these 900 iptables statements are also followed by another statement to check if the command succeded or failed, which totals to about 1800 BASH statements to be executed.

So flash memory requirements may not be that unequal if you compare 50 lines of config plus firehol compressed in cramfs vs. an equally sofisticated but harder to administer firewall startup script.

-Chris

I played around with firehol for a bit, and found it extremely interesting. However, it appears to be very bash specific, and in fact the firehol site refers to a lot of bash features. When I tried to play around with it on my 54g, I got a lot of errors (can't recall most off the top of my head), including an error with some of the main functions (does bb's ash support functions?). I haven't scripted much outside of bash for a long time, so maybe I'm just missing something simple (and I admit I didn't spend a ton of time on it).

Ultimately, I think we need a solution that can at least allow NAT port forwarding rules via a web interface (but maybe that's just me).

Here are the commands firehol uses according to the FAQ it should check for all of them:

which_cmd CAT_CMD cat
which_cmd CUT_CMD cut
which_cmd CHOWN_CMD chown
which_cmd CHMOD_CMD chmod
which_cmd DATE_CMD date
which_cmd EGREP_CMD egrep
which_cmd GAWK_CMD gawk
which_cmd GREP_CMD grep
which_cmd HOSTNAME_CMD hostname
which_cmd IP_CMD ip
which_cmd IPTABLES_CMD iptables
which_cmd IPTABLES_SAVE_CMD iptables-save
which_cmd LESS_CMD less
#which_cmd LSMOD_CMD lsmod
LSMOD_CMD=`which lsmod | head -n 1`
which_cmd MKDIR_CMD mkdir
which_cmd MV_CMD mv
#which_cmd MODPROBE_CMD modprobe
MODPROBE_CMD=`which modprobe | head -n 1`
which_cmd NETSTAT_CMD netstat
which_cmd RENICE_CMD renice
which_cmd RM_CMD rm
which_cmd SED_CMD sed
which_cmd SORT_CMD sort
which_cmd SYSCTL_CMD sysctl
which_cmd TOUCH_CMD touch
which_cmd TR_CMD tr
which_cmd UNAME_CMD uname
which_cmd UNIQ_CMD uniq


Regarding ash if found:

> Does anyone know if ash supports functions ??? 

Don't worry.  I figured it out.  I was testing under bash and using the
"function" keyword.  Under ash or bourne shells, the function keyword
must be removed.  Bash also allows the parenthesis to be absent where as
ash requires them (to detect a function definition I assume).

Cheers,
Brendan Simon.

Post #10
ballyn wrote:

does bb's ash support functions?

FYI, I posted a request here:

http://sourceforge.net/tracker/index.ph … tid=487695

that FireHOL be ported to run under any POSIX compliant shell.

-Tom

The discussion might have continued from here.