
#-----------------------------------------------------------------------
# Copyright (C) 2000-2001, Jean-Sebastien Morisset <jsmoriss@mvlan.net>
#-----------------------------------------------------------------------
# $Id: write_config.sh,v 1.14 2001/11/19 19:25:55 jsmoriss Exp $
#-----------------------------------------------------------------------
#  $RCSfile: write_config.sh,v $
#   $Author: jsmoriss $
# $Revision: 1.14 $
#     $Date: 2001/11/19 19:25:55 $
#   $Locker:  $ 
#     $Name:  $
#-----------------------------------------------------------------------
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by 
# the Free Software Foundation <http://www.gnu.org/copyleft/gpl.txt>.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License (LICENSE file in archive) for more details.
#
#-----------------------------------------------------------------------
# README
#-----------------------------------------------------------------------
#
# A bourne shell function used by rcf; a very secure, fast, and complete
# firewall for linux <http://jsmoriss.mvlan.net/linux/rcf.html>.
#
#-----------------------------------------------------------------------
# FUNCTION
#-----------------------------------------------------------------------

Write_Config () {
	if [ -s "$CONF" ]
	then
		echo "Copying `Sed_Basename ${CONF}` to `Sed_Basename ${CONF}.bak`..."
		cp "${CONF}" "${CONF}.bak"
		chmod 0600 "${CONF}.bak"
	fi
	
	touch "${CONF}.tmp"
	chmod 0600 "${CONF}.tmp"
	echo -n "Writing v${PKG_VERSION} Configuration..."

	Sed_Cat <<EOF > "${CONF}.tmp"

# ======================================================================
# Firewall v${PKG_VERSION} Configuration (Last Updated on `date '+%a %b %d %H:%M'`).
# ======================================================================


# ----------------------------------------------------------------------
# Interfaces
# ----------------------------------------------------------------------
# IF YOU ADD AND/OR REMOVE AN INTERFACE TO/FROM THESE VARIABLES, YOU
# SHOULD EXECUTE RCF WITH THE --UPDATE-CONFIG PARAMETER. This will 
# create/remove the configuration options for the interface. You will
# probably want to review any new options and re-run the firewall script
# to implement the new rules.
# ----------------------------------------------------------------------

# Public (Internet) network interfaces. If necessary, you can specify
# interfaces which are down and/or may not exist. This will maintain the
# necessary options in the configuration file, but the interfaces will 
# not be used until they are up.
#
# Example:
#   public-interfaces = eth2 ipsec0
#
public-interfaces = $PUBLIC_INTERFACES

# One or more private network interfaces. Seperate each interface name
# by a space. Leave this string empty if you don't have a private LAN -
# i.e. you're only connected to the Internet.
#
# See also the forward-{interface}-masq-networks option to allow
# masquerading on each interface (enabled by default).
#
# Example:
#   private-interfaces = eth0 eth1 eth1:1
#
# If you want to restrict access to/from servers on a private subnet,
# use the mz-interfaces option instead. You can then create clusters
# of servers and assign access rules for them.
#
private-interfaces = $PRIVATE_INTERFACES

# De-Militarized Zones (DMZs) are public network segments connected to
# the firewall. DMZ servers typically offer public services such as
# http, ftp, etc. IP addresses on these segments should be routable on
# the internet (no private IPs like 10.0.0.0, 192.168.0.0, etc.).
#
dmz-interfaces = $DMZ_INTERFACES

# Militarized-Zones (MZs) are private network segments which offer
# services (usually databases) to DMZ servers. Access to and from these
# servers can be controlled by defining "clusters" -- refer to the
# mz-{int}-clusters option (after executing rcf with the --update-config 
# parameter).
#
mz-interfaces = $MZ_INTERFACES


# ----------------------------------------------------------------------
# Security Levels
# ----------------------------------------------------------------------
# "open" mode allows all standard TCP traffic to pass. Broadcast based
# services (dhcp, etc.) will have to be given explicit access. This mode
# can only be used on private interfaces.
#
# "relaxed" mode allows outgoing TCP connections and incoming/outgoing
# UDP traffic on high ports. When used for public interfaces, this mode
# will allow port-scanning of remote hosts from your firewall. Access
# must be granted for each service offered (web and ftp servers, etc.).
#
# "strict" mode allows outgoing TCP connections except to known hacker-
# friendly service ports (sunrpc, rlogin, telnet, etc.). All UDP traffic
# is denied. Access must be given for each UDP based service and local
# TCP services offered to remote users (web and ftp servers, etc.). This
# is usually the prefered mode for public and dmz interfaces/clusters.
#
# "paranoid" mode denies all incoming/outgoing TCP and UDP traffic. Each
# service (local and remote) must be granted access.
#
# MAKE SURE YOU EXECUTE RCF WITH THE --update-config PARAMETER AFTER 
# SWITCHING MODES. This will add/remove several options to/from the
# configuration file.
# ----------------------------------------------------------------------

EOF

	[ "$PUBLIC_INTERFACES" ] && {
		echo "public-interfaces-security = ${PUBLIC_INTERFACES_SECURITY:=strict}"
		echo ""
	} >> "${CONF}.tmp"

	[ "$PRIVATE_INTERFACES" ] && {
		echo "private-interfaces-security = ${PRIVATE_INTERFACES_SECURITY:=strict}"
		echo ""
	} >> "${CONF}.tmp"

	[ "$DMZ_INTERFACES" ] && Sed_Cat <<EOF >> "${CONF}.tmp"
# Interface rules have precedence over cluster firewall rules. Using
# strict mode (for example) will give the interface access to all
# servers on that subnet. Leave the interface in paranoid mode unless
# you have a good reason for changing it.
#
dmz-interfaces-security = ${DMZ_INTERFACES_SECURITY:=paranoid}
  dmz-clusters-security = ${DMZ_CLUSTERS_SECURITY:=paranoid}

EOF

	[ "$MZ_INTERFACES" ] && Sed_Cat <<EOF >> "${CONF}.tmp"
# Interface rules have precedence over cluster firewall rules. Using
# strict mode (for example) will give the interface access to all
# servers on that subnet. Leave the interface in paranoid mode unless
# you have a good reason for changing it.
#
mz-interfaces-security = ${MZ_INTERFACES_SECURITY:=paranoid}
  mz-clusters-security = ${MZ_CLUSTERS_SECURITY:=paranoid}

EOF

	[ "$DMZ_INTERFACES" -a "$DMZ_CLUSTERS_MODE" ] \
		&& if [ "$DMZ_CLUSTERS_MODE" -gt "0" ]
	then
		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# DMZ Service Clusters
# ----------------------------------------------------------------------
# For each DMZ interface, you must specify one or more service clusters.
# These are groups of servers which offer the same service and share 
# the same access rules.
#
# Syntax:
#   dmz-{int}-clusters = {cluster-name} [ip|network|host]/{netmask} {...}, {...}
#
# Example:
#   dmz-eth3-clusters = allservers 24.1.2.0/24, webservers 24.1.2.0/28 24.1.2.170, ftpservers ftp.my.domain 24.1.2.131
#   dmz-eth4-clusters = allservers 24.2.0.0/16
#
# The cluster names you define will be used to create additional 
# configuration options for services such as http, ftp, etc. As an 
# example, the eth3 cluster names above would lead to the following
# http service options being added to the configuration file:
#
#   accept-eth3:allservers-http-clients = 
#   accept-eth3:webservers-http-clients = 
#   accept-eth3:ftpservers-http-clients = 
#
# When adding and/or removing cluster names, you should execute 
# rcf with the --update-config parameter. This will create/remove the
# configuration options which use these cluster names.
#
# Tip: The order in which you enter clusters in an option will determine
# their order in the firewall rules. Try to list heavily used clusters
# first, like http servers, etc. You can also give precedence to
# clusters with fewer services.
# ----------------------------------------------------------------------

EOF
		for INTERFACE in $DMZ_INTERFACES
		do
			DEVICE="`echo $INTERFACE|sed -n -e 's/^\([^\:]*\).*$/\1/p'`"
			[ "$DEVICE" != "$INTERFACE" ] && VIRTUAL="yes" || VIRTUAL="no"

			if [ "$VIRTUAL" = "no" ]
			then
				UCASE_INTERFACE="`echo ${INTERFACE}|To_Upper_Fix`"
				eval echo "dmz-${INTERFACE}-clusters = \$DMZ_${UCASE_INTERFACE}_CLUSTERS" >> "${CONF}.tmp"
			fi
		done
		unset INTERFACE UCASE_INTERFACE
		echo "" >> "${CONF}.tmp"
	fi

	[ "$MZ_INTERFACES" -a "$MZ_CLUSTERS_MODE" ] \
		&& if [ "$MZ_CLUSTERS_MODE" -gt "0" ]
	then
		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# MZ Service Clusters
# ----------------------------------------------------------------------
# For each militarized-zone (MZ) interface, you must specify one or more
# service clusters. These are groups of servers (on your private 
# network) which offer the same service and should have the same access 
# from your DMZs.
#
# Syntax:
#   mz-{int}-clusters = {cluster-name} [ip|network|host]/{netmask} {...}, {...}
#
# Example:
#   mz-eth0-clusters = lan 10.1.1.0/24, databases 10.1.1.34 10.1.1.35
#   mz-eth1-clusters = lan 10.1.2.0/24 172.16.0.0/16
#
# The cluster names you define will be used to create configuration 
# options for services such as oracle, sybase, etc. As an example, the
# eth0 cluster names above would lead to the following oracle service
# options being added to the configuration file:
#
#   accept-eth0:lan-oracle-clients = 
#   accept-eth0:databases-oracle-clients = 
#
# When adding and/or removing cluster names, you should execute 
# rcf with the --update-config parameter. This will create/remove the
# configuration options which use these cluster names.
#
# Tip: The order in which you enter clusters in an option will determine
# their order in the firewall rules. Try to list heavily used clusters
# first, like http servers, etc. You can also give precedence to
# clusters with fewer services.
# ----------------------------------------------------------------------

EOF
		for INTERFACE in $MZ_INTERFACES
		do
			DEVICE="`echo $INTERFACE|sed -n -e 's/^\([^\:]*\).*$/\1/p'`"
			[ "$DEVICE" != "$INTERFACE" ] && VIRTUAL="yes" || VIRTUAL="no"

			if [ "$VIRTUAL" = "no" ]
			then
				UCASE_INTERFACE="`echo ${INTERFACE}|To_Upper_Fix`"
				eval echo "mz-${INTERFACE}-clusters = \$MZ_${UCASE_INTERFACE}_CLUSTERS" >> "${CONF}.tmp"
			fi
		done
		unset INTERFACE UCASE_INTERFACE
		echo "" >> "${CONF}.tmp"
	fi

	if [ "$PUBLIC_INTERFACES" -o "$DMZ_INTERFACES" ]
	then
		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Public Service Modules
# ----------------------------------------------------------------------
# Separate each hostname (or filename) name with a space. Hostnames and
# IPs can be entered several ways. Example:
#
# zappa.dyndns.org      A fully qualified domain name (FQDN).
# 206.167.150.35/32     206.167.150.35 specifically. Some people prefer
#                       using IP addresses instead of FQDNs to protect
#                       themselves against DNS spoofing.
# 206.167.150.0/24      Any host in the 206.167.150.* network.
# any/0                 Anyone on the planet. This "wildcard" is often
#                       used for web and SMTP services.
# /path/filename        A text file which contains any of the above.
#                       Hosts within this file can be entered on
#                       multiple lines. The pound (#) character can be
#                       used for comments (after the hostname is ok).
# ./filename            Identical to above except the file is expected
#                       to reside under /etc/firewall/groups/.
# ----------------------------------------------------------------------

EOF
		Config_Modules "public" "services"
		
		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Misc. Public Interface Options
# ----------------------------------------------------------------------

# IANA Reserved Networks. These addresses should not be seen on the
# internet. You should update this list once or twice per year.
#
iana-reserved-networks = ${IANA_RESERVED_NETWORKS:="./iana-reserved-networks"}

# Some cable-modem providers send IGMP multicast packets as a "keep 
# alive". If you're not sure if you need to accept IGMP multicast, leave
# this option empty. If you notice messages like this:
#
#   ...input DENY eth# PROTO=2 24.x.x.x:65535 224.0.0.1:65535...
#
# in your syslog files, add the 24.x.x.x address to this option.
#
EOF
		Config_Options accept "public" mcastigmp servers

		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Online Games
# ----------------------------------------------------------------------

EOF
		Config_Modules "public" "online-games"
	fi

	if [ "$PRIVATE_INTERFACES" -o "$MZ_INTERFACES" ]
	then
		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Private Service Modules
# ----------------------------------------------------------------------

EOF
		Config_Modules "private" "services"
	
		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Online Games
# ----------------------------------------------------------------------

EOF
		Config_Modules "private" "online-games"
	fi

	if [ \( "$PUBLIC_INTERFACES" -o "$DMZ_INTERFACES" \) \
		-a \( "$PRIVATE_INTERFACES" -o "$MZ_INTERFACES" \) ]
	then
		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Port Forwarding
# ----------------------------------------------------------------------

EOF
		Config_Modules "public" "port-forwarding"

		Sed_Cat <<EOF >> "${CONF}.tmp"
# In some cases, you may want to forward a port from your firewall 
# directly to an internal (LAN) host. You can enter multiple hosts and 
# ports in these variables (seperated by commas). You'll also need to 
# install the ipmasqadm tool (available from 
# http://juanjox.kernelnotes.org/).
#
# Syntax:
#   forward-[int]-[prot]-hostports = [host/ip] [ports],[...]
#
# The [ports] field can be a simple port number (25), a port range 
# (3010:3020), or a local->remote port match (25->60 or 
# 3010:3020->4010:4020). Multiple [ports] can also be entered for
# each host/ip.
#
# Example:
#   forward-eth1-tcp-hostports = zaphod.localdomain 80 81
#   forward-eth1-tcp-hostports = zaphod.localdomain 80->8080
#   forward-eth1-tcp-hostports = zaphod.localdomain 6100:6200
#   forward-eth1-tcp-hostports = zaphod.localdomain 80, trillian.localdomain 23 25
#
EOF
		Config_Options forward "public private dmz mz" tcp hostports
		Config_Options forward "public private dmz mz" udp hostports

		Sed_Cat <<EOF >> "${CONF}.tmp"
# If you're forwarding ports which haven't been covered in the standard 
# accept options (or simply need to open additional ports), use the 
# following option(s). You can enter multiple hosts and ports in these
# variables (seperated by commas).
#
# Example:
#   accept-eth1-tcp-rhostlports = zappa.mvlan.net 44 82:88, omar.dyndns.org 44
#
EOF
		Config_Options accept "public private dmz mz" tcp rhostlports
		Config_Options accept "public private dmz mz" udp rhostlports

		Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Masquerading
# ----------------------------------------------------------------------

# Most TCP/IP-enabled applications work fine behind a Linux IP 
# masquerade server, but some applications need a special module to 
# get their traffic in and out properly.
#
# Example:
#   masq-modules = cuseeme ftp irc quake raudio vdolive
#
masq-modules = $MASQ_MODULES

# Timeout values used for TCP and UDP masquerading. This command always 
# takes 3 parameters, representing the timeout values (in seconds) for
# TCP sessions, TCP sessions after receiving a FIN packet, and UDP 
# packets, respectively.
#
# Example:
#   masq-timeouts = 7200 10 160
#
masq-timeouts = ${MASQ_TIMEOUTS:="7200 10 160"}

# Networks, hosts, etc. which are masqueraded when passing through
# these interfaces. WARNING: The public interface should only
# masquerade private interface networks. MZ NETWORKS SHOULD BE
# EXCLUDED AS AN EXTRA SECURITY MEASURE.
#
# Example:
#   forward-eth1-masq-networks = 10.1.1.0/24 10.1.2.0/24
#
EOF

		private_networks="`{
			for interface in $PRIVATE_INTERFACES
			do
				# virtual interfaces won't match any route
				netstat -nre 2>/dev/null | \
					grep \" U[G ].* ${interface}\$\" | \
					grep -v '^0.0.0.0' | \
					sed -n -e 's/^ *\([^ ]*\) *[^ ]* *\([^ ]*\) *.*$/\1\/\2/p'
			done
		} | sort | Sed_Uniq`"

		Config_Options forward "real_public real_private real_dmz real_mz" \
			masq networks "forward_public = $private_networks"

		unset private_networks
	fi

	Sed_Cat <<EOF >> "${CONF}.tmp"

# ----------------------------------------------------------------------
# Miscellaneous
# ----------------------------------------------------------------------

# Mark incoming packets with a 32-bit unsigned value. If the string 
# [markvalue] begins with a + or -, then this value will be added or 
# subtracted from the current marked value of the packet (which starts
# at zero). 
#
# Syntax:
#   mark-{int}-tcp-rhostlports = [markvalue] [hostname] [local ports...]
#
# Example:
#   mark-eth1-tcp-rhostlports = 10 any/0 80 443, +1 joe.bob.net 22
#   mark-ppp0-tcp-rhostlports = 20 any/0 80 443
#
EOF
		Config_Options mark "public private dmz mz" tcp rhostlports

	Sed_Cat <<EOF >> "${CONF}.tmp"
# Activate extra logging (accept, deny, forward, etc.) to debug the
# firewall rules (yes/no)? You can over-ride this option using the 
# --debug and --nodebug command line parameters.
#
debug = ${DEBUG:="no"}

# If you have IP Accounting installed, enter the path to your ipacset
# binary. If ipacset is found in this directory, it will be executed to 
# add your accounting rules.
#
# Example:
#   ipac-bindir = /usr/local/bin
#
ipac-bindir = $IPAC_BINDIR


EOF
	mv "${CONF}.tmp" "${CONF}"
	echo ""
	echo -n `grep "^ *[a-z]" $CONF|Sed_Wc`
	echo " Options ($TOTAL_MODULES Modules Processed)."
}

