#!/usr/bin/perl
# Simple firewalling script written & adopted only for TACIS organisation.
# May partly be usefull for others as a reference.
# Not yet fully finished though.. (some vars defined but their use is only
# planned in the future versions.)
# License is current GNU GPL.
# (c) Olli <olli@digger.org.ru>

# sanity checks.
use strict;

# user supplyed vars:
my ($fw); $fw="/sbin/ipchains";
# protocols that are base of most others.
my @proto_type=qw(tcp icmp udp);

my $any="0.0.0.0/0";
my (%names,%adr,%nms,%net,%m_fnet,$glob_debug,$verbose,$log,$logacc,$logdeny,%servers,@portlist);
my ($server,$logrej,$logmasq1,$logmasq2);
$glob_debug=1;
#$log=" -l ";
$log=" ";

# same management as $log.
$logacc=" ";
#$logacc=" -l ";

$logdeny=" -l ";
#$logdeny=" ";

$logrej=" -l ";
#$logrej=" ";

### masq logs for 192.168.1.0 
$logmasq1=" -l ";
#$logmasq=" ";

### masq logs for 192.168.6.0 
$logmasq2=" -l ";
#$logmasq=" ";


#replace w/ -v for more verbosity..
#$verbose=" -v ";
$verbose=" ";

# names of interfaces
$names{"lo"}="lo";
$names{"if0"}="eth0";
$names{"if1"}="eth1";
$names{"if2"}="eth2";
$names{"if3"}="eth3";
# alias names
$names{"if0:0"}="eth0:0";

# ip addresses for these interfaces
$adr{"lo"}="127.0.0.1";
$adr{"eth0:0"}="195.209.37.129";
$adr{"eth1"}="195.209.37.26";
$adr{"eth2"}="212.38.105.2";
$adr{"eth3"}="192.168.6.1";
$adr{"eth0"}="192.168.1.1";

# netmask masks for these interfaces
$nms{"lo"}="255.0.0.0";
$nms{"eth0:0"}="255.255.255.192";
$nms{"eth1"}="255.255.255.252";
$nms{"eth2"}="255.255.255.192";
$nms{"eth3"}="255.255.255.0";
$nms{"eth0"}="255.255.255.0";

# networks for these interfaces
$net{"lo"}="127.0.0.0";
$net{"eth0:0"}="195.209.37.128";
$net{"eth1"}="195.209.37.26";
$net{"eth2"}="212.38.105.0";
$net{"eth3"}="192.168.6.0";
$net{"eth0"}="192.168.1.0";

# networks for interfaces we do masquerade from
$m_fnet{"eth3"}="192.168.6.0";
$m_fnet{"eth0"}="192.168.1.0";
# test
$m_fnet{"eth0:0"}="195.209.37.128";

# external (internet) iface names
my @extif=qw( eth1 eth2);
# all existing interface names.
my @allif=qw( eth0 eth1 eth2 eth3 eth0:0 lo );
# local (LAN) iface names (we may calculate, but I'm too lazy)
my @locif=qw( eth0 eth3 lo );
#ifaces we do NAT from.
#my @m_iffrom=qw( eth0 eth3 );
my @m_iffrom=qw( eth0 eth3 eth0:0);
#ifaces we do NAT to.
my @m_ifto=qw( eth0:0 eth1 eth2 );
# adresses (w/ nmasks) that can't come from external ifaces:
my @reserved=qw (	127.0.0.0/8
		        10.0.0.0/8
			172.16.0.0/12
			192.18.0.0/16
			240.0.0.0/5
			224.0.0.0/4
);

# unpriveleged ports.
my $unpriv_ports="1024:65535";
my $priv_ports="0:1023";
# interface we have servers on.
my $servlan="eth0:0";

# open priveleged ports per server.
$servers{"195.209.37.132"}="80,25,465,20,21";
$servers{"195.209.37.133"}="80,25,465,20,21";
$servers{"195.209.37.134"}="80,25,465,20,21";
$servers{"195.209.37.135"}="80,25,465,20,21";
$servers{"195.209.37.136"}="80,25,465,20,21";
$servers{"195.209.37.137"}="80,25,465,20,21";
$servers{"195.209.37.138"}="80,25,465,20,21";
$servers{"195.209.37.139"}="80,25,465,20,21";
$servers{"195.209.37.140"}="80,25,465,20,21,4899";
$servers{"195.209.37.141"}="80,25,465,20,21,4899";
$servers{"195.209.37.144"}="80,25,465,20,21";
$servers{"195.209.37.145"}="80,25,443,465,20,21";
$servers{"195.209.37.146"}="80,25,465,20,21";
$servers{"195.209.37.148"}="80,25,465,20,21";
$servers{"195.209.37.150"}="80,25,465,20,21";
$servers{"195.209.37.151"}="80,25,465,20,21";
$servers{"195.209.37.152"}="80,25,465,20,21";
$servers{"195.209.37.153"}="80,25,465,20,21";
$servers{"195.209.37.154"}="80,25,465,20,21";
$servers{"195.209.37.155"}="80,25,465,20,21";
$servers{"195.209.37.156"}="80,25,465,20,21";
$servers{"195.209.37.157"}="80,25,465,20,21";
$servers{"195.209.37.158"}="80,25,465,20,21";
$servers{"195.209.37.159"}="80,25,465,20,21";
$servers{"195.209.37.160"}="80,25,465,20,21";
$servers{"195.209.37.161"}="80,25,465,20,21";
$servers{"195.209.37.162"}="80,25,465,20,21";
$servers{"195.209.37.163"}="80,25,465,20,21";
$servers{"195.209.37.164"}="80,25,465,20,21";
$servers{"195.209.37.165"}="80,25,465,20,21";
$servers{"195.209.37.166"}="80,25,465,20,21";
$servers{"195.209.37.167"}="80,25,465,20,21";
$servers{"195.209.37.168"}="80,25,465,20,21";
$servers{"195.209.37.169"}="80,25,465,20,21";
$servers{"195.209.37.170"}="80,25,465,20,21";
$servers{"195.209.37.171"}="80,25,465,20,21";
$servers{"195.209.37.172"}="80,25,465,20,21";
$servers{"195.209.37.173"}="80,25,465,20,21";
$servers{"195.209.37.174"}="80,25,465,20,21";
$servers{"195.209.37.176"}="80,25,465,20,21";
$servers{"195.209.37.178"}="80,25,465,20,21";
$servers{"195.209.37.179"}="80,25,465,20,21";
$servers{"195.209.37.180"}="80,25,465,20,21";
$servers{"195.209.37.181"}="80,25,465,20,21";
$servers{"195.209.37.182"}="80,25,465,20,21";
$servers{"195.209.37.183"}="80,25,465,20,21";
$servers{"195.209.37.184"}="80,25,465,20,21";
$servers{"195.209.37.185"}="80,25,465,20,21";
$servers{"195.209.37.186"}="80,25,465,20,21";
$servers{"195.209.37.187"}="80,25,465,20,21";
$servers{"195.209.37.188"}="80,25,465,20,21";
# our local ports 
$servers{"195.209.37.26"}="22,53";
$servers{"195.209.37.129"}="22,53";
$servers{"192.168.6.1"}="22,53";
$servers{"192.168.1.1"}="22,53";

# Addresses (w/ nmasks) defined as reserved by the IANA.
# Note:  this list includes the loopback, multicast, & reserved addresses,
# them are removed since we already have definitions for them.
# The following are based on reservations as listed by IANA as of 10/10/2000.
# Check http://www.iana.org/ for the latest status.
# 0.*.*.*           - Can't be blocked for DHCP users.
# 1.*.*.*, 2.*.*.*, 5.*.*.*, 7.*.*.*, 23.*.*.*, 27.*.*.*
# 31.*.*.*, 36.*.*.*, 37.*.*.*, 39.*.*.*, 41.*.*.*, 42.*.*.*
# 49-50.*.*.*, 58-60.*.*.*
# 67-127.*.*.*
# 169.254.*.*       - Link Local Networks
# 192.0.2.*         - TEST-NET
# 197.*.*.*, 217-255.*.*.*
my @iana_reserved=qw (	1.0.0.0/8
			2.0.0.0/8
			5.0.0.0/8
			7.0.0.0/8
			23.0.0.0/8
			27.0.0.0/8
			31.0.0.0/8
			36.0.0.0/8
			37.0.0.0/8
			39.0.0.0/8
			41.0.0.0/8
			42.0.0.0/8
			49.0.0.0/8
			50.0.0.0/8
			58.0.0.0/7
			60.0.0.0/8
			67.0.0.0/8
			68.0.0.0/6
			72.0.0.0/5
			80.0.0.0/4
			96.0.0.0/3
			169.254.0.0/16
			192.0.2.0/24
			197.0.0.0/8
			218.0.0.0/7
			220.0.0.0/6
			224.0.0.0/3
);

# 127.0.0.0/8		 reserved for loopback address range
# 10.0.0.0/8             reserved for LANs,Class A private networks
# 172.16.0.0/12          reserved for LANs,Class B private networks
# 192.18.0.0/16          reserved for LANs,Class C private networks
# 240.0.0.0/5            Class E reserved addresses
# 224.0.0.0/4        	 multicasting, Class D multicast addresses


# pogramm internal vars.
my ($subret);

#sub calc_locif
#{my ($sub_serial,$sub_debug);$sub_serial="00:00:00:00:00:05";
# my ($iface);
# # set to somth. not "undef" for debugging ON.
# $sub_debug=1; #$sub_debug=undef;
# if ($sub_debug) {print "running $sub_serial\n";}
# my (@temp,$iface1);
# ############# sub runs from here.
# @locif= [@allif]-[@extif];
# if ($sub_debug) 
# {local $"=" , "; print "\t$sub_serial: @locif\n";
# }
#}

#$servers{195.209.37.188}="80,25,465,20,21";
# get_ports
sub get_ports
{my ($sub_serial,$sub_debug);$sub_serial="get_ports";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=0; #$sub_debug=undef;
 if ($sub_debug) {print "running $sub_serial ..\n";}
 my (@ports,$string); @ports=undef;
 ############# sub runs from here.
 #put ports in parameter into $pol_in, $pol_out,$pol_forw
  if ($_[0]) {$string=$_[0];} 
   else {die "Err: no parameter in sub $sub_serial.";}
  @ports=split(/\,/,$string);
  return @ports;
}


# deny_spooffing
sub deny_spooffing
{my ($sub_serial,$sub_debug);$sub_serial="deny_spooffing";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=1; #$sub_debug=undef;
 if ($sub_debug) {print "running $sub_serial ..\n";}
 my ($intif,$extif_,$extif,$addr);
 ############# sub runs from here.

 foreach $intif (@locif)
  {foreach $extif_ (@extif)
    {# reject local spooffing:
     # reject all going out through $intif w/ src address of $extif.  
     ### After test-time should switch to deny.
     system ("$fw -A output -i $intif -s $adr{$extif_} -j REJECT$verbose$logrej")==0
      || die "'system' call error in sub $sub_serial: $!";
    }
  }
 foreach $extif (@extif)
  {foreach $addr (@reserved)
    {# Reject external spooffing:
     # Reject all going in through $extif w/ reserved src address.
     ### After test-time should switch to deny.
     system ("$fw -A input -i $extif -s $addr  -j REJECT$verbose$logrej")==0
          || die "'system' call error in sub $sub_serial: $!";
    }
  }


}

########### ipchains quick reference:
# Reserved chains:
#
#  input
#  output
#  forward
#
#TARGETS
#
# The target can be the name of a user-defined chain, or one of the special
# values: ACCEPT, DENY, REJECT, MASQ, REDIRECT, or RETURN.
#
# TARGET prefs:
#      MASQ  is  only  legal  for  the  forward  and user defined chains.
#      REDIRECT  is  only  legal  for  the input and user-defined
#      chains.
#      RETURN does nothing & used to skip some packets within a chain - after
#      reaching RETURN we're jumping to the next rule of the upper chains &
#      if no upper chains exist (for built-in chains) - chain POLICY acts.
#COMMANDS:
# [-A, --append]
#  Append one or more rules to the end of the selected
#  chain.   When  the  source and/or destination names
#  resolve to more than one address, a  rule  will  be
#  added for each possible address combination.
#
# [-D, --delete]
#  Delete  one  or more rules from the selected chain.
#  There are two versions of this  command:  the  rule
#  can be specified as a number in the chain (starting
#  at 1 for the first rule) or a rule to match.
#
# [-I, --insert]
#  Insert  one  or more rules in the selected chain as
#  the given rule number.  So, if the rule  number  is
#  1,  the  rule  or rules are inserted at the head of
#  the chain.
#
# [-P, --policy]
#  Set the policy for the chain to the  given  target.
#  See  the  section  TARGETS  for  the legal targets.
#  Only non-userdefined chains can have policies,  and
#  neither  built-in  nor  user-defined  chains can be
#  policy targets.
#
# [-L, --list] 
#  List all rules in the selected chain.  If no  chain
#  is selected, all chains are listed.  It is legal to
#   specify the -Z (zero) option with this.
#
# [-M, --masquerading]
#  This option allows viewing of  the  currently  mas­
#  queraded  connections  (in  conjuction  with the -L
#  option) or to set the kernel masqerading parameters
#  (with the -S option).
#
# 
# [-Z, --zero]               Zero  the  packet  and byte counters in all chains.
# [-N, --new-chain]          Create a new user-defined chain of the given  name.
# [-X, --delete-chain]       Delete  the  specified  user-defined  chain.
# [-S, --set tcp tcpfin udp] Change  the  timeout  values used for masquerading.
# [-C, --check]              Check the given packet against the selected  chain.
#
#PARAMETERS:
# [-p, --protocol[!] protocol]   Protocol of the rule or of the packet to check.
# [-s, --source [!] address[/mask] [!] [port[:port]]]                    Source.
# [--source-port [!] [port[:port]], --sport]             Source port/port range.
# [-d, --destination [!] address[/mask] [!] [port[:port]]]          Destination.
# [--icmp-type [!] typename]                     Specification of the ICMP type.
# [-j, --jump target]       What to do w/ the packet? (may be chain or TARGETS).
# [-i, --interface [!] name]         Name of an interface via which packet goes.
# [[!]  -f, --fragment] Only apply to 2 & higher fragments of fragmented packet.
# [-b, --bidirectional] Same as repeating the rule with the src & dest reversed.
# [-v, --verbose]                                                Verbose output.
# [-n, --numeric]                                                Numeric output.
# [-l, --log]                                        Log info about this packet.
# [-o, --output [maxsize]]              Copy matching packets to NETLINK device.
# [-t, --TOS andmask xormask]                 Modify the TOS field in IP header.
# [[!] -y, --syn] Match TCP packets w/ SYN bit set & the ACK and FIN bits unset.
# [--line-numbers]                             w/ [-L] shows rule nums in chain.
# 
#
#
##

# clear all rules & chains. remove user defined.
sub clear_all
{my ($sub_serial,$sub_debug);$sub_serial="clear_all";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=1; #$sub_debug=undef;
 if ($sub_debug) {print "running $sub_serial\n";}
 ############# sub runs from here.
 # Remove all existing rules belonging to this filter
 if ($sub_debug) {print "\t$sub_serial:\tRemoving all existing rules..\n";}
 system ("$fw -F $verbose")==0
      || die "'system' call error in sub $sub_serial: $!";
 if ($sub_debug) 
 {print 
 "\t$sub_serial:\t Clearing all current rules and user defined chains..\n";
 }
 system ("$fw -X$verbose")==0
      || die "'system' call error in sub $sub_serial: $!";
}

# set policy ; unfinished. 2do: change to accept policy as a parameter.
sub set_policy
{my ($sub_serial,$sub_debug);$sub_serial="set_policy";
 # set to somth. not "undef" for debugging ON.
 my ($pol_in,$pol_out,$pol_forw);
 #put policys in parameter into $pol_in, $pol_out,$pol_forw
  if ($_[0]) {$pol_in=$_[0];} 
   else {die "Err: no 1st parameter in sub $sub_serial.";}
  if ($_[1]) {$pol_out=$_[1];} 
   else {die "Err: no 2nd parameter in sub $sub_serial.";}
  if ($_[2]) {$pol_forw=$_[2];} 
   else {die "Err: no 3d parameter in sub $sub_serial.";}

 $sub_debug=1; #$sub_debug=undef;
 if ($sub_debug) {print "running $sub_serial..\n";}

 ############# sub runs from here.

 if ($sub_debug) {print "\t$sub_serial:\tsetting output policy to $pol_out..\n";}
 system ("$fw -P output $pol_out$verbose")==0
      || die "'system' call error in sub $sub_serial: $!";

 if ($sub_debug) {print "\t$sub_serial:\tsetting input policy to $pol_in..\n";}
 system ("$fw -P input $pol_in$verbose")==0
      || die "'system' call error in sub $sub_serial: $!";

 if ($sub_debug) {print "\t$sub_serial:\tsetting forward policy to $pol_forw..\n";}
 system ("$fw -P forward $pol_forw$verbose")==0
      || die "'system' call error in sub $sub_serial: $!";

}

# proceed w/ ouput chain.
sub set_output
{my ($sub_serial,$sub_debug);$sub_serial="set_output";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=1; #$sub_debug=undef;
 my ($if,$proto);
 if ($sub_debug) {print "running $sub_serial\n";}
 ############# sub runs from here.

 if ($sub_debug)
  {print "\t$sub_serial:\t output, src interface = loopback, ACCEPT..\n";}
 
 system ("$fw -A output -i $names{lo} -j ACCEPT $verbose$logacc")==0
    || die "'system' call error in sub $sub_serial: $!";

 if ($sub_debug) 
  {print "\t$sub_serial:\t output, accept all going to ssh & dns & smptp 
  ports..\n";
  }
 
 system ("$fw -A output -p tcp -s $any ssh -j ACCEPT $verbose$logacc")==0
    || die "'system' call error in sub $sub_serial: $!";

 system ("$fw -A output -p tcp -s $any 53 -j ACCEPT $verbose$logacc")==0
    || die "'system' call error in sub $sub_serial: $!";

 system ("$fw -A output -p tcp -s $any 25 -j ACCEPT $verbose$logacc")==0
    || die "'system' call error in sub $sub_serial: $!";


 if ($sub_debug) 
  {print "\t$sub_serial:\t output, per server individual rules..\n";
  }
 foreach $server (keys %servers)
 {@portlist=get_ports($servers{$server}); 
  foreach my $port (@portlist)
  {foreach $proto (@proto_type)
   {system ("$fw -A output -b -p $proto -d $server $port -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";
   }
  }
 }

 if ($sub_debug) 
  {print "\t$sub_serial:\t output: allowing all other ICMP..\n";
  }
  system ("$fw -A output -p icmp -j ACCEPT$logacc$verbose")==0
   || die "'system' call error in sub $sub_serial: $!";

 if ($sub_debug) 
  {print "\t$sub_serial:\t output on external ifaces: allow all, log.\n";
  }
 foreach $if (@extif)
 {system ("$fw -A output -i $if -p all -j ACCEPT$logacc$verbose")==0
   || die "'system' call error in sub $sub_serial: $!";
 }

###### Temporary removed.
# if ($sub_debug) 
#  {print "\t$sub_serial:\t output on $servlan: allow all to unpr-ports, nonSYN, log.\n";
#  }
# system ("$fw -A output -i $servlan -p tcp -d $any $unpriv_ports --syn -j REJECT $logrej $verbose")==0
#   || die "'system' call error in sub $sub_serial: $!";
# foreach $proto (@proto_type)
# {system ("$fw -A output -i $servlan -p $proto -d $any $unpriv_ports -j ACCEPT $logacc $verbose")==0
#    || die "'system' call error in sub $sub_serial: $!";
# }
#
# if ($sub_debug)
#  {print "\t$sub_serial:\t output on $servlan: reject anything not accepted yet, log.\n";
#  }
 foreach  $proto (@proto_type)
 {system ("$fw -A output -i $servlan -p $proto -d $any $priv_ports -j REJECT$logrej$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";
 }

### temporary removed.
# foreach $proto (@proto_type)
#  {system ("$fw -A output -i $servlan -p $proto -d $net{\"eth0:0\"}/$nms{\"eth0:0\"} -j REJECT $logrej $verbose")==0
#   || die "'system' call error in sub $sub_serial: $!";
#  }

## allow output for addresses from eth0:0 on eth1
if ($sub_debug) 
{print "\t$sub_serial:\t enabling output on eth1 w/ src addr on eth0:0 LAN..\n";
}
my $netmask=$nms{"eth0:0"}; my $network=$net{"eth0:0"};
system ("$fw -A output -b -i eth1 -s $network/$netmask -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";

if ($sub_debug) 
{print "\t$sub_serial:\t accept input for addr from eth0 on eth0:0..\n";
}
$netmask=$nms{"eth0:0"}; $network=$net{"eth0:0"};
system ("$fw -A output -b -i eth0:0 -d $network/$netmask -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";

#### Just allow all. For temp debugging.. Should be removed.
system ("$fw -A output -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";
} # sub 'set_output'

# proceed w/ input chain.
sub set_input
{my ($sub_serial,$sub_debug);$sub_serial="set_input";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=1;#$sub_debug=undef;
 my ($tmpaddr,$iface,$intif,);
 if ($sub_debug) {print "running $sub_serial..\n";}
 ############# sub runs from here.

 if ($sub_debug) 
  {print "\t$sub_serial:\t input,src interface = loopback, ACCEPT, $log ..\n";
  }
 system ("$fw -A input  -i $names{lo} -j ACCEPT$verbose$logacc")==0
          || die "'system' call error in sub $sub_serial: $!";

 if ($sub_debug) 
  {print "\t$sub_serial:\t input, refuse addresses reserved by the IANA..\n";
  }
 foreach $tmpaddr (@iana_reserved)
  {system ("$fw -A input -s $tmpaddr -j REJECT$verbose$logrej")==0
    || die "'system' call error in sub $sub_serial: $!";
   #system ("$fw -A input -s $tmpaddr -j DENY $logdeny $verbose")==0
   #    || die "'system' call error in sub $sub_serial: $!";
  }

 if ($sub_debug) 
  {print "\t$sub_serial:\t input, allow ssh & dns & smtp anywhere..\n";
  }
 system ("$fw -A input -p tcp -d $any ssh -j ACCEPT$verbose$logacc")==0
   || die "'system' call error in sub $sub_serial: $!";

 system ("$fw -A input -p tcp -d $any ssh -j ACCEPT$verbose$logacc")==0
   || die "'system' call error in sub $sub_serial: $!";


 if ($sub_debug) 
  {print "\t$sub_serial:\t output, per server individual rules..\n";
  }
 foreach $server (keys %servers)
 {@portlist=get_ports($servers{$server}); 
  foreach my $port (@portlist)
  {foreach my $proto (@proto_type)
   {system ("$fw -A input -b -p $proto -d $server $port -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";
   }
  }
 }

### Temporary removed.
# if ($sub_debug) 
#  {print "\t$sub_serial:\t input, disabling external ICMP redirects (type=5)..\n";
#  }
# foreach my $if (@extif)
# {system 
#   ("$fw -A input -p icmp -i $if --icmp-type 5 -j REJECT $logrej $verbose")==0
#    || die "'system' call error in sub $sub_serial: $!";
# }

 if ($sub_debug) 
  {print "\t$sub_serial:\t input, allowing all other ICMP..\n";
  }
 system ("$fw -A input -p icmp -j ACCEPT $logacc $verbose")==0
   || die "'system' call error in sub $sub_serial: $!";

 if ($sub_debug) 
  {print "\t$sub_serial:\t input, allowing LAN NETs to go to any iface..\n";
  }
 foreach $iface (@allif)
  {foreach $intif (@locif)
   {system ("$fw -A input -i $iface -s $net{$intif}/$nms{$intif} -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";
    }
  }

if ($sub_debug) 
{print "\t$sub_serial:\t enabling input on eth1 w/ dst addr on eth0:0 LAN..\n";
}
my $netmask=$nms{"eth0:0"}; my $network=$net{"eth0:0"};
system ("$fw -A input -b -i eth1 -d $network/$netmask -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";

$netmask=$nms{"eth0:0"}; $network=$net{"eth0:0"};
if ($sub_debug) 
{print "\t$sub_serial:\t accept input for addr from eth0 on eth0:0..\n";
}

system ("$fw -A input -b -i eth0:0 -d $network/$netmask -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";

### just allow all & log it.. for ttemp debug problems..
system ("$fw -A input -j ACCEPT$logacc$verbose")==0
    || die "'system' call error in sub $sub_serial: $!";

} # sub 'set_input'

# proceed w/ input chain.
sub set_NAT
{my ($sub_serial,$sub_debug);$sub_serial="set_NAT";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=1;#$sub_debug=undef;
 my ($counter,$if,$log1,$log2);
 ### two local debugging variables, just for easier logging.
 #$log1=" -l ";
 $log1=" -l ";
 #$log2=" -l ";
 $log2=" -l ";
 if ($sub_debug) {print "running $sub_serial..\n";}
 ############# sub runs from here.

# ip addresses for these interfaces
#$adr{"lo"}="127.0.0.1";
#$adr{"eth0:0"}="195.209.37.129";
#$adr{"eth1"}="195.209.37.26";
#$adr{"eth2"}="212.38.105.2";
#$adr{"eth3"}="192.168.6.1";
#$adr{"eth0"}="192.168.1.1";

# masquerade on 195.209.37.26 from 192.168.1.0/24 & 192.168.6.0/24
system ("$fw -A forward -i eth1 -s 192.168.1.0/24 -j MASQ$logmasq1$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";
system ("$fw -A forward -i eth1 -s 192.168.6.0/24 -j MASQ$logmasq2$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";

# masquerade on 212.38.105.2 from 192.168.1.0/24 & 192.168.6.0/24
system ("$fw -A forward -i eth2 -s 192.168.1.0/24 -j MASQ$logmasq1$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";
system ("$fw -A forward -i eth2 -s 192.168.6.0/24 -j MASQ$logmasq2$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";

# accept forwarding for 195.209.37.128/26 (in-out) if default gw is on eth2
system ("$fw -A forward -i eth2 -s 195.209.37.128/26 -j ACCEPT$logmasq1$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";
system ("$fw -A forward -i eth2 -d 195.209.37.128/26 -j ACCEPT$logmasq1$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";

# accept forwarding for 195.209.37.128/26 (in-out) if default gw is 
# on eth1
system ("$fw -A forward -i eth1 -s 195.209.37.128/26 -j ACCEPT$log2$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";
system ("$fw -A forward -i eth1 -d 195.209.37.128/26 -j ACCEPT$log2$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";


system ("$fw -A forward -d 195.209.37.128/26 -j ACCEPT$log1$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";
system ("$fw -A forward -d 192.168.6.0/24 -j ACCEPT$log1$verbose")==0
          || die "'system' call error in sub $sub_serial: $!";
} # sub 'set_NAT' 

sub show_usage
{my ($sub_serial,$sub_debug);$sub_serial="show_usage..";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=1;#$sub_debug=undef;
 if ($sub_debug) {print "running $sub_serial\n";}
 ############# sub runs from here.
 print 
"

 Simple firewalling script $0. 
 Adopt for your needs.
 License is curernt GNU GPL.
 Created by Olli <olli\@digger.org.ru> for TACIS company.
 Last changed at Sun 07 Oct 2001 04:10:13 PM EDT by /Olli.


This is your firewalling script. Usage is either:
    $0 start	- start firewalling.
    $0 stop	- stop firewalling (clear all & remove all\n\t\t\t\tuser chains).
    $0 clear	- clear all rules.
";
exit 0;
} # sub 'show_usage'

########### subs
sub how_called
{my ($sub_serial,$sub_debug); $sub_serial="how_called..";
 # set to somth. not "undef" for debugging ON.
 $sub_debug=1;#$sub_debug=undef;
 if ($sub_debug) {print "running $sub_serial\n";}
 ############# sub runs from here.
 if ("$ARGV[0]" eq "start")
  {print "\t$0:\tStarting..\n"; return 0;}
 if ("$ARGV[0]" eq "stop")
  {print "\t$0:\tStopping..\n"; return 1;}
if ("$ARGV[0]" eq "clear")
  {print "\t$0:\tStopping..\n"; return 2;}
 show_usage;
} # sub 'how_called'

########## programm vars

########## programm start working here.
$subret=how_called;

if ($subret == 0)
{#Start firewall rules.
 
 # enable IP forwarding.
 system ("echo 1 > /proc/sys/net/ipv4/ip_forward") == 0 || die 
 "'system' call error! $!";

 # disable autodropping of packets if the routing table entry 
 # for their source address doesn't match the network interface they're
 # arriving on. This is needed for asymmetric routing (packets from you 
 # to a host take a different path than packets from that host to you)
system ("echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter") == 0 || die
 "'system' call error! $!";

clear_all;
### set_policy(in,out,masq);
# the effective restricted.
#set_policy("REJECT","ACCEPT","REJECT");
set_policy("REJECT","ACCEPT","REJECT");
# the most restricted.
#set_policy("REJECT","REJECT","REJECT");
# set_policy("ACCEPT","ACCEPT","REJECT");
# set_policy("ACCEPT","ACCEPT","ACCEPT");

##### temporary removed.
# deny_spooffing;
 set_input;
 set_output;
 set_NAT;
}

if ($subret == 1)
{
 #Stop firewall rules.
 clear_all;
 if ($glob_debug)
 {print "\tsetting all policys to ACCEPT,disabling forwarding.. \n";
 }
 system ("$fw -P input ACCEPT$verbose")==0
          || die "'system' call error! $!";
 system ("$fw -P output ACCEPT$verbose")==0
          || die "'system' call error! $!";
 system ("$fw -P forward ACCEPT$verbose")==0
          || die "'system' call error! $!";
 system ("echo 0 > /proc/sys/net/ipv4/ip_forward") == 0 
          || die "'system' call error! $!";
 }

if ( $subret == 1 )
{#Stop firewall rules.
 clear_all;
}
