#!/bin/sh
#	fwgen-ipchains ver 0.36
#	Process firewall-easy-lib	# Procesa firewall-easy-lib
#
#	Generates a firewall script	# Genera un script de cortafuegos
#	in "/etc/firewall-ipchains"	# en "/etc/firewall-ipchains"
#
#	Copyright (C) 2000:	Manel Marin <manel3@wanadoo.es>
#	Licence:		GNU GPL version >= 2
#
#

	# Rules file of firewall-easy	# Archivo de reglas de firewall-easy
FROM=/etc/firewall-easy-lib

	# Script to create/overwritte	# Script a crear/sobreescribir
TO=/etc/firewall-ipchains



echo "-> Generating firewall script $TO (fwgen-ipchains)"
cat $FROM |  awk '

# We are going to parse the rules file	# Vamos a procesar el archivo de reglas
# line by line generating a bash script # linea a linea generando un script
# printing or echoing lines		# bash haciendo print o echo con lineas


# BE CAREFULL:				# CUIDADO:
# "" 0 = ASCII 0  comment		# Comentario  "" 0 = ASCII 0
# letter zero can be interpreted as	# la letra cero puede ser interpretada
# number zero not returning letter	# como nmero cero no devolviendo letra



#---------------FIX PART----------------#---------------PARTE FIJA-------------
#--independent of ipchains, iptables----#--independiente de ipchains, iptables-


# CONFIG VARS DETAILS			# DETALLES DE VARIABLES CONFIGURACION

#TESTFW					#TESTFW
#---to do firewall test in boot---	#---hacer test cortafuegos en arranque-

#NOLOG					#NOLOG
#---No to do any log---			#---NO hacer NINGUN LOG---
# log paramenter is $L in script	# el parametro para hacer log es $L
# So $L="" is enough to not log		# en el script, de modo que $L=""
# without regenerating firewall script	# basta para no hacer log

#LOGALLDENY				#LOGALLDENY
#---log all NO rule (for debuging)---	#---hacer log de toda regla NO (debug)-

#RSTALLDENY (ONLY 2.4)			#RSTALLDENY (SOLO 2.4)
#---return RST to all NO rule (debug)--	#---devolver RST a toda regla NO (debug)

#DEBUG					#DEBUG
#---If exists show rules---		#---Muestra reglas si existe---
# DEBUG shell var is checked in echorun	# La variable shell DEBUG es comprobada
# so export DEBUG=yes is enough	to	# en echorun, export DEBUG=si basta
# show rules when running the fwscript	# para mostrar las reglas al lanzar
#					# el script de firewall


#############################################################################
# BEFORE PROCESS THE FIRST LINE		# ANTES DE PROCESAR LA PRIMERA LINEA
# OF THE RULES FILE			# DEL ARCHIVO DE REGLAS
#############################################################################
    BEGIN{
	    # Put script begining	#Pongo principio del script

	begining()

	    # Initialize vars		#Inicializo valores por defecto

	hi = "1024:65535"
	interface = "*"
	iplocal = "*"
	ipremote = "*"


	    # Pattern to detect if there are	# Patrn para detectar si hay
	    # more than one value to use loops	# ms de un valor para usar
	    # in INTERFACE, IPLOCAL, and	# bucles en INTERFACE, IPLOCAL,
	    # IPREMOTE				# e IPREMOTE
	    #    For example:			#    Por ejemplo:
	    # $IP can hold several values	# $IP puede tener varios valores
	    # $IP1 has only one value		# $IP1 tiene un solo valor
	    # (var name ended in number		# (variable terminada en nmero
	    # do not generate while loops)	#  no genera bucle while)
	    # "1.1.1.1 $IP1" are two values	# "1.1.1.1 $IP1" son dos valores

	SEVERAL_VALUES = "(^\$.*[^0-9]+$)|([^ ]+[ ]+[^ ]+)"

	    # Pattern of IP ($VAR o x.x.x.x)	# Patrn de IP ($VAR o x.x.x.x)

	IS_IP = "(^\$)|(\.)"
	
	    # Pattern of commented var line	# Linea de variable comentada

	COMMENTED = "^[ \t]*#"

    }

#############################################################################
# IN EVERY LINE OF RULES FILE		# EN CADA LINEA DEL ARCHIVO DE REGLAS
#############################################################################

# SKIP EMPTY LINES			# SALTAR LINEAS VACIAS
    $1 ~ "^[ \t]*$" { next }

# GROUP (starting with ####)		# GRUPO (empiezan con ####)
# add as a comment to the script	# escribir como comentario al script
    $1 ~ "^####" {
	print ""
	print ""
	print ""
	print "#"$0
	next
    }


# SKIP OTHER COMMENTS			# SALTAR OTROS COMENTARIOS
    $1 ~ "^#" { next }


# VARIABLES				# VARIABLES
# To allow VAR=VALUE and VAR = VALUE	# Para permitir VAR=VALUE y VAR = VALUE
# I split the whole line in:		# Divido la linea completa en:
# parts[1] (the VARIABLE_NAME) and	# parts[1] (el NOMBRE_DE_LA_VARIABLE) y
# parts[2] (the VALUE)			# parts[2] (el VALOR)

    $0 ~ "=" {
	split( $0, parts, "[ \t]*[=][ \t]*" )	# Separo y quito espacios
	gsub( "[ \t\$]+", "", parts[1] )	# Quito espacios del nombre
	gsub( "[ \t]*#.*", "", parts[2] )	# Quito comentario
	gsub( "[ \t]+", " ", parts[2] )		# Sustituyo TAB por espacios

##	print "#" $0					#DEBUG
##	print "#" parts[1] " / " parts[2]		#DEBUG


    # SPECIAL VARS			# VARIABLES ESPECIALES
    # (We use them internally)		# (Las usamos internamente)
	if ( parts[1] == "INTERFACE" ) {

    # FIN DE BUCLE INTERFACES ANTERIOR (si lo hubo)
	    if ( interface ~ SEVERAL_VALUES ) {
		print "done		# End of last INTERFACE for loop"
	    }
	    print "#" $0	# Poner linea de INTERFACE tras fin bucle
	    interface = parts[2]

    # INTERFACE VARIABLE LOOP 		# BUCLE PARA VARIABLE DE INTERFACES
	    interface_tmp = interface			#No modif var global
	    if ( interface ~ SEVERAL_VALUES ) {
		print "for IFACE in " interface "; do"
		interface_tmp = "$IFACE"
	    }
	}
	else if ( parts[1] == "IPLOCAL" )  { print "#" $0; iplocal = parts[2] }
	else if ( parts[1] == "IPREMOTE" ) { print "#" $0; ipremote = parts[2] }
	else if ( parts[1] == "HI" )       { print "#" $0; hi = parts[2] }

    # RESTO DE VARIABLES		# OTHER VARS
    	else if ( parts[2] ~ "\".*\"" ) {
	    print parts[1] "=" parts[2]		# already "...", ya es "..."
	}
	else {
	    print parts[1] "=\"" parts[2] "\""	# put "..."
	}
	next
    }

# IMPORT: Importing bash variables	# IMPORT: Importamos variables bash
# from a config file			# de un archivo de configuracin
    $1 ~ "^import$" {
	put_import( $2 )
	next
    }

# ARRIVING HERE IT IS A RULE LINE	# SI LLEGA AQUI ES UNA LINEA DE REGLA
    {
    # $1 = action + to_log + prio :	>>!--   =   ">>" + "!" + "--"
    # $2 = proto (tcp   udp   tcp,udp)
    # $3 = local (ip:port:port)
    # $4 = dir (<, >, <>)
    # $5 = remote (ip:port:port)
    # $6 = [nat (ip:port)]
    # $6... = Description 

    
# PRINT RULES LINES AS COMMENTS		# IMPRIMIR LINEAS DE REGLAS COMO
# or echo them if debug			# COMENTARIOS o echo si es modo debug
	print " debug \"#" $0 "\""


    # EXTRACT $1: action, to_log, prio	# SEPARAR $1 EN: action, to_log, prio
	action = $1
	gsub( "[!+-]+", "", action )		# Supr.  !, +, ++, -, --

	if ( $1 ~ "!" ) { to_log = "!" }
	else { to_log = "" }

	prio = $1
	gsub( "[^+-]+", "", prio )		# Only/solo  +, ++, -, --

##	print action " / " to_log " / " prio		#DEBUG

    # SPLIT LOCAL IP FROM PORT/RANGE	# SEPARAR IP LOCAL DE PUERTO/RANGO
	split ( $3, parts, ":" )
	if ( parts[1] ~ IS_IP ) {
	    local = parts[1]
	    local_port = "" parts[2]		# "" 0 = ASCII 0
	    if ( parts[3] ) local_port = local_port ":" parts[3]  # Rango
	}
	else{					# No hay IP
	    if ( action == "NO" || action == "RST" ) {
		local = "*"		# NO/RST sin IP prohibir todas las IP
	    }
	    else local = iplocal		# */> sin IP usar IPLOCAL
	    local_port = "" $3			# "" 0 = ASCII 0
	}

    # SPLIT REMOTE IP FROM PORT/RANGE	# SEPARAR IP REMOTA DE PUERTO/RANGO
	split ( $5, parts, ":" )
	if ( parts[1] ~ IS_IP ) {
	    remote = parts[1]
	    remote_port = "" parts[2]		# "" 0 = ASCII 0
	    if ( parts[3] ) remote_port = remote_port ":" parts[3]  # Rango
	}
	else{					# No hay IP
	    if ( action == "NO" || action == "RST" ) {
		remote = "*"		# NO/RST sin IP prohibir todas las IP
	    }
	    else remote = ipremote		# */> sin IP usar IPREMOTE
	    remote_port = "" $5			# "" 0 = ASCII 0
	}

    # PROCESS PROXY/FORWARD		# PROCESO PROXY/FORWARD
    # Ignore "-" and ">" ("->")		# Ignorar "-" y ">" ("->")
	if ( action == "PROXY" || action == "FORWARD" ){
	    nat = $6
	    gsub ( "[->]*", "", nat )
	# SPLIT REMOTE IP FROM PORT	# SEPARAR IP REMOTA DE PUERTO
	    split ( nat, parts, ":" )
	    if ( parts[1] ~ IS_IP ) {
		nat_ip = parts[1]
		nat_port = "" parts[2]		# "" 0 = ASCII 0
	    }
	    else{				# No hay IP
		nat_ip = ""
		nat_port = "" nat		# "" 0 = ASCII 0
	    }
	}
	else nat = ""

    # REPLACING "HI" o "$HI"		# SUSTITUYO "HI" o "$HI"
	if ( local_port ~ "^[\$]?HI$" ) local_port = hi
	if ( remote_port ~ "^[\$]?HI$" ) remote_port = hi

    # LOOP FOR REMOTE IP		# BUCLE PARA VARIAS IP REMOTAS
	if ( remote ~ SEVERAL_VALUES ) {
	    print "for IP_R in " remote "; do"
	    remote = "$IP_R"
	}
    # LOOP FOR LOCAL IP			# BUCLE PARA VARIAS IP LOCALES
	if ( local ~ SEVERAL_VALUES ) {
	    print "for IP_L in " local "; do"
	    local = "$IP_L"
	}
    # SEVERAL PROTO ("," separated)	# VARIOS PROTOS (separados por comas)
	split ( $2, proto, "," )
	for ( n in proto ) {
    # MOUNT RULE			# MONTAR REGLA
	    put_rule( action, to_log, prio, interface_tmp, proto[n], \
		local, local_port, $4, remote, remote_port, nat_ip, nat_port )
	}
    # END OF LOOPS			# FINAL DE BUCLES
	if ( local ~ SEVERAL_VALUES ) print "done"
	if ( remote ~ SEVERAL_VALUES ) print "done"
    }


#############################################################################
# AFTER PROCESSING THE LAST LINE	# DESPUES DE PROCESAR LA ULTIMA LINEA
# OF THE RULES FILE			# DEL ARCHIVO DE REGLAS
#############################################################################

    END{
    # END OF PREVIOUS INTERFACE LOOP	# FIN DE BUCLE INTERFACES ANTERIOR
	if ( interface ~ SEVERAL_VALUES ) {
	    print "done		# End of last INTERFACE for loop"
	}
	print ""

    # LAST RULES AT THE END		# ULTIMAS REGLAS AL FINAL
	ending()
    }


#############################################################################
# FUNCTIONS				# FUNCIONES
#############################################################################

    # ERROR: Syntax errors arrive here	# ERROR: Los errores de sintaxis vienen
    #					# aqui
    # I put echo in the script so	# Pongo echos en el script de manera
    # errors are shown when run		# que muestre errores al lanzarlo

    function error( err ){
	print "echo"
	print "echo \"	SYNTAX ERROR IN: " err "\""
	print "echo \"	" $0 "\""
	print "echo"
    }


#---------------VARIABLE PART-----------#---------------PARTE VARIABLE---------
#--dependent of ipchains, iptables------#--dependiente de ipchains, iptables---


# BEGINING OF FIREWALL SHELL SCRIPT	# PRINCIPIO DEL SCRIPT SHELL

    function begining( ){
	print "#!/bin/sh"
	print "#	firewall-ipchains"
	print "#"
	print "#	GENERADO POR / FILE GENERATED BY: fwgen-ipchains"
	print "#"
	print "#	Este script monta un cortafuegos con ipchains"
	print "#	This script mounts firewall with ipchains"
	print "#"
	print "# DEFAULTS"
	print "PATH=/usr/lib/firewall-easy:/sbin:/usr/sbin:/bin:/usr/bin"
	print ""
	print "# VARS PARA HACER LOG / VARS TO DO LOG"
	print "L=\"-l\""
	print "N=\"\""
	print ""
	print ""
	print "# LOAD DEFAULT CONFIG FILE"
	print ". /etc/firewall-easy.conf"
	print ""
	print "# DEBUG"
	print "if [ \"$DEBUG\" != \"\" ]; then export DEBUG; fi"
	print ""
	print "# NOLOG"
	print "if [ \"$NOLOG\" != \"\" ]; then L=\"\"; N=\"\"; fi"
	print ""
	print "# LOGALLDENY"
	print "if [ \"$LOGALLDENY\" != \"\" ]; then L=\"-l\"; N=\"-l\"; fi"
	print ""
	print ""
	print "# ASEGURANDO EL KERNEL / SECURING KERNEL"
	print "secure-kernel-22"
	print ""
	print "echo \"-> Setting up firewall (firewall-ipchains)\""
	print ""
	print "# ESTABLECER POLITICA DEL CORTAFUEGOS / FW POLICY DENY"
	print "echorun ipchains -P input DENY"
	print "echorun ipchains -P forward DENY"
	print "echorun ipchains -P output DENY"
	print ""
	print "# BORRAR REGLAS ANTERIORES / DELETE PREVIOUS RULES"
	print "echorun ipchains -F input"
	print "echorun ipchains -F forward"
	print "echorun ipchains -F output"
	print ""
	print "ipmasqadm portfw -f > /dev/null 2>&1	# Port forwarding"
	print ""
	print ""
	print "# PROHIBIR FRAGMENTOS / DENY FRAGMENTS"
	print "echorun ipchains -A input -f -j DENY"
	print ""
	print ""
	
	
	print "##### firewall-easy-lib ####################################"
    }


    function put_import ( file ){
	print ""
	print "# IMPORTING VARS FROM CONFIG FILE: " file
	print ". " file
	print ""
	print "# DEBUG"
	print "if [ \"$DEBUG\" != \"\" ]; then export DEBUG; fi"
	print ""
	print "# NOLOG"
	print "if [ \"$NOLOG\" != \"\" ]; then L=\"\"; N=\"\"; fi"
	print ""
	print "# LOGALLDENY"
	print "if [ \"$LOGALLDENY\" != \"\" ]; then L=\"-l\"; N=\"-l\"; fi"
	print ""
    }


# PUT_RULE: generate valid rules	# PUT_RULE: genera reglas coherentes
# with paramenters given		# con los parmetros que se le dan
# Not allowed several values of		# No admite varios valores de from,
# from, proto, etc... just one		# proto, etc... Sino solo uno
#
# action 	NO, >, >>, *, RST, MASQUERADE, PROXY, FORWARD
# to_log	"", !
# prio		"", ++, +, -, --
# iface		"", *, eth0, ppp0
# proto		*, tcp, udp, icmp, ... (/etc/protocols)
# local		*, $DNS, 1.2.3.4
# local_port	"", *, domain, 53, 1:1024
# dir		>, <, <>
# remote	= local
# remote_port	= local_port
# nat_ip	= local (optional)
# nat_port	= local_port (optional)

    function put_rule ( action, to_log, prio, iface, proto, \
	local, local_port, dir, remote, remote_port, nat_ip, nat_port ){

    # CONVERT "*" TO ""			# NORMALIZO "*" A ""

	if ( iface == "*" )	 iface = ""
	if ( proto == "*")	 proto = ""
	if ( local == "*")	 local = ""
	if ( local_port == "*")	 local_port = ""
	if ( remote == "*")	 remote = ""
	if ( remote_port == "*") remote_port = ""
	if ( nat_ip == "*")	 nat_ip = ""
	if ( nat_port == "*")	 nat_port = ""


    # CHOOSE PROPER FUNCTION		# ELEGIR LA FUNCION ADECUADA
    # put_filter, put_redir, put_port_forward

	if ( action == "FORWARD" ) {
	    put_port_forward( action, to_log, prio, iface, proto, \
	      local, local_port, dir, remote, remote_port, nat_ip, nat_port )
	}
	else {
	    put_filter( action, to_log, prio, iface, proto, \
	      local, local_port, dir, remote, remote_port, nat_ip, nat_port )
	}
    }


# FILTER + PROXY: ipchains		# FILTER + PROXY: ipchains

    function put_filter ( action, to_log, prio, iface, proto, \
	local, local_port, dir, remote, remote_port, nat_ip, nat_port ){

    # IF USING MASQ OR PROXY		# SI SE USA MASQ O PROXY activar
    # activate forward (only once)	# forward (solo una vez)

	if ( action == "MASQUERADE" || action == "PROXY" ){
	    if ( forward_enabled != "yes" ){
		print ""
		print "# ENABLING FORWARD (needed by MASQUERADE and PROXY)"
		print "# ACTIVANDO FORWARD (necesario para MASQUERADE y PROXY)"
		print " debug \"echo 1 > /proc/sys/net/ipv4/ip_forward\""
		print "echo 1 > /proc/sys/net/ipv4/ip_forward"
		print ""
		forward_enabled = "yes"
	    }
	}


    # TRANSLATING TO ipchains		# TRADUCCION A ipchains
    # REMEMBER: add	space at end	# RECUERDA: dejar un espacio al final
    # of every string			# de cada cadena
    # t is a traslating array		# t es un array de traduccin

	input = "echorun ipchains -A input "
	output = "echorun ipchains -A output "
	forward = "echorun ipchains -A forward "

	t["NO"] = "-j DENY "		
	t[">"] = "-j ACCEPT "
	t[">>"] = "-j ACCEPT "		# >> = * in 2.2 
	t["*"] = "-j ACCEPT "
	t["RST"] = "-j REJECT "
	t["MASQUERADE"] = "-j MASQ "
	t["PROXY"] = "-j REDIRECT "


    # I use parameter $L/$N in firewall	# Uso los parmetros $L/$N en el
    # script, setting them in the	# script firewall, declarandolos
    # begining() function to allow to	# en la funcin begining() para
    # control log without regenerating	# permitir control el log sin regenerar

	if ( to_log == "!" ){
	    t["!"] = "$L "		# Log (by default)
	}
	else if ( action == "NO" ){
	    t["!"] = "$N "		# Not to log (by default)
	    to_log = "!"		# Force to put $N in NO rules w. no log
	}

	t["++"] = "-t 0x01 0x10 "	# IPTOS_LOWDELAY
	t["+"] = "-t 0x01 0x18 "	# LOWDELAY + THROUGHPUT
	t["-"] = "-t 0x01 0x08 "	# IPTOS_THROUGHPUT
	t["--"] = "-t 0x01 0x02 "	# IPTOS_MINCOST


    # SYNTAX ERRORS			# ERRORES DE SINTAXIS
    # all errors begining with		# todos los errores que empiezan
    # "/" are from variable part	# con "/" son de la parte variable

	if ( t[action] == "" ) error( "/action unknown" )
	if ( to_log != "" && t[to_log] == "" ) error( "/to_log unknown" )
	if ( prio != "" && t[prio] == "" ) error( "/prio unknown" )
	if ( dir != "<" && dir != ">" && dir != "<>" ) error( "/dir invalid" )
	if ( action == "MASQUERADE" && dir != ">" ) error( "/dir != >") 
	if ( action == "PROXY" && nat_ip != "" ) error( "/IP in PROXY" ) 


    # PROCESS ">" FOR ipchains		# PROCESAR ">" PARA ipchains
    # we can only deny input SYN	# Solo podemos impedir paquetes SYN
    # packets in tcp			# de entrada en tcp
	
	if ( action == ">" && proto == "tcp" ) {
	    established = "! -y "
	}
	else { established = "" }


    # NO PORT WITHOUT IP ALLOWED	# NO PUEDE HABER PUERTO SIN IP
    # PUT 0/0 (any IP)			# PONER 0/0 (cualquier IP)

	if ( local == "" && local_port ) local = "0/0"
	if ( remote == "" && remote_port ) remote = "0/0"


    # GENERATING PARAMETERS		# GENERO PARAMETROS

	if ( iface ) iface = "-i " iface " "
	if ( proto ) proto = "-p " proto " "
	if ( nat_port ) nat_port = nat_port " "


    # LOCAL SIDE			# LADO LOCAL
	input_to = ""; 	output_from = ""
	input_to_port = ""; output_from_port = ""

	if ( local ) {
	    input_to = "-d " local " "
	    output_from = "-s " local " "
	}
	if ( local_port ) {
	    input_to_port = local_port " "
	    output_from_port = local_port " "
	}

    # REMOTE SIDE			# LADO REMOTO
	output_to = ""; input_from = ""
	output_to_port = ""; input_from_port = ""

	if ( remote ) {
	    output_to = "-d " remote " "
	    input_from = "-s " remote " "
	}
	if ( remote_port ) {
	    output_to_port = remote_port " "
	    input_from_port = remote_port " "
	}

    # ASSEMBLING INPUT RULE		# ENSAMBLO REGLA DE ENTRADA
	if ( dir ~ "<" ) {
	    print input t[action] nat_port t[to_log] t[prio] iface proto \
		established input_to input_to_port input_from input_from_port
	}

    # IF MASQUERADING in ipchains	# SI HAY ENMASCARAMIENTO en ipchains
    # must be forward rule		# debe ser regla forward
	if ( action == "MASQUERADE" ) output = forward

    # ASSEMBLING OUTPUT RULE		# ENSAMBLO REGLA DE SALIDA
	if ( dir ~ ">" ) {
	    print output t[action] t[to_log] t[prio] iface proto \
		output_from output_from_port output_to output_to_port
	}
    }


# PORT FORWARDING: ipmasqadm portfw	# PORT FORWARDING: ipmasqadm portfw

    function put_port_forward ( action, to_log, prio, iface, proto, \
	local, local_port, dir, remote, remote_port, nat_ip, nat_port ){

    # SYNTAX ERRORS			# ERRORES DE SINTAXIS
    # all errors begining with		# todos los errores que empiezan
    # "/" are from variable part	# con "/" son de la parte variable

	if ( iface ) error( "/iface in FORWARD not supported" )
	if ( dir != "<" ) error ( "/dir != < in FORWARD" ) 
	if ( local == "" ) error ( "/IPlocal == * not supported" ) 


    # NO PORT WITHOUT IP ALLOWED	# NO PUEDE HABER PUERTO SIN IP
    # PUT 0/0 (any IP)			# PONER 0/0 (cualquier IP)

	if ( local == "" && local_port ) local = "0/0"
	if ( nat_ip == "" && nat_port ) nat_ip = "0/0"


    # GENERATING PARAMETERS		# GENERO PARAMETROS

	if ( proto ) proto = "-P " proto " "
	if ( local ) local = "-L " local " " local_port " "
	nat = "-R " nat_ip " " nat_port " "


    # ASSEMBLING RULE			# ENSAMBLO REGLA

	print "echorun ipmasqadm portfw -a " proto local nat
    }



# ENDING OF FIREWALL SHELL SCRIPT	# FINAL DEL SCRIPT SHELL

    function ending( ){
	print ""
	print "# LOG ALL OTHER FORWARD TRIALS"
	print "# avoiding to show a warning when forward is not active"
	print "ipchains -A forward -j DENY -l > /dev/null 2>&1"
	print ""
	print "# TEST FIREWALL"
	print "if [ \"$TESTFW\" != \"\" ]; then testfw; fi"
    }


' > $TO 

chmod ugo+x $TO		# Exec perms 	# Permisos de ejecucin

