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

FROM=/etc/firewall-easy-lib	# Configuration file of firewall-easy
TO=/etc/firewall-ipchains	# Script to be created/overwritted


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

#POR HACER: Generar errores de sintaxis?, Debug

#---------------PARTE FIJA---------------------------------------------
#---------------FIX PART (independent of ipchains, iptables...)--------

#VAR CONFIG	Explicacin				Detalles

#TESTFW		hacer test cortafuegos en arranque	-> valor en archivo
#NOLOG		NO hacer NINGUN LOG			-> to_log = $L
#LOGALLDENY	hacer log de toda regla DENY (debug)	-> solo al "generar"
#DEBUG		Descomentar para hacer debug		-> export DEBUG=


# AL PRINCIPIO
    BEGIN{
	header()			#Pongo cabecera de script

	hi = "1024:65535"		#Inicializo valores por defecto
	interface = "*"
	iplocal = "*"
	ipremote = "*"

	logalldeny = ""			#Inicializo variables de configuracin
	debug = ""

	    # Patrn para detectar si hay varios valores para usar bucles
	    # en los valores de INTERFACE, IPLOCAL, e IPREMOTE
	    #	Por ejemplo:
	    # "$IP1" no tiene varios valores, las $VAR1 no generan bucle
	    # "$IP" si puede tenerlos (variable que no acaba en nmero)
	    # "1.1.1.1 $IP1" tambin, son dos valores
	SEVERAL_VALUES = "(^\$.*[^0-9]+$)|([^ ]+[ ]+[^ ]+)"
    }

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

# GRUPO (empiezan con ####)
# imprimir lineas en blanco, quitar nombre y escribir como comentario
    $1 ~ "^####" {
	print ""
	print ""
	print ""
	print "#"$0
	next
    }

# VARIABLES DE CONFIGURACION (INCLUSO COMENTADAS)
    $0 ~ "^[ \t#]*TESTFW[ \t]*=" {		# TESTFW
	if ( $0 ~ "^[ \t]*#" ) comentar = "#"	# Esta comentado? -> Si
	else comentar = ""
	print ""
	print "#" $0				# Pongo linea comentada
	print "#...create /etc/testfw only if it does not exist (for tripwire)"
	print comentar "if test ! -f testfw; then echo 1 > /etc/testfw; fi"
	print ""
	next
    }
    $0 ~ "^[ \t#]*NOLOG[ \t]*=" {		# NOLOG
	if ( $0 ~ "^[ \t]*#" ) comentar = "#"	# Esta comentado? -> Si
	else comentar = ""
	print ""
	print "#" $0				# Pongo linea comentada
	print comentar "L=\"\""    		# Vacio var de log (o no)
	print ""
	next
    }
    $0 ~ "^[ \t#]*LOGALLDENY[ \t]*=" {		# LOGALLDENY
	print ""
	print "#" $0				# Pongo linea comentada
	if ($0 ~ "^[ \t]*#" ) {			# Esta comentado?
	    logalldeny = ""			# Si-> desactivo
	    print "# Script generado _sin_ LOGALLDENY activo"
	    print "# Script generated _without_ LOG ALL DENY rules active"
	}
	else {
	    logalldeny = "on"			# Activo el modo "log all deny"
	    print "# Script generado _con_ LOGALLDENY activo"
	    print "# Script generated _with_ LOG ALL DENY rules active"
	}
	print ""
	next
    }
    $0 ~ "^[ \t#]*DEBUG[ \t]*=" {		# DEBUG
	if ( $0 ~ "^[ \t]*#" ) comentar = "#"	# Esta comentado? -> Si
	else{
	    comentar = ""
	    debug = "on"			# Activar debug
	}
	print ""
	print "#" $0				# Pongo linea comentada
	print comentar "export DEBUG=on"
	print ""
	next
    }

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

# VARIABLES
    $0 ~ "=" {
	split( $0, parts, "[ \t]*[=][ \t]*" )	# Separo/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


    # VARIABLES ESPECIALES (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]
    # 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
	else if ( parts[2] ~ "\".*\"" ) {
	    print parts[1] "=" parts[2]		# Ya hay comillas
	}
	else {
	    print parts[1] "=\"" parts[2] "\""	# Pongo valores entre comillas
	}
	next
    }

# IMPORT: Importamos variables bash de un archivo de configuracin
    $1 ~ "^import$" {
	print ""
	print "# IMPORTING VARS FROM CONFIG FILE: " $2
	print ". " $2
	print ""
	next
    }

# SI LLEGA AQUI ES UNA LINEA DE REGLA
    {
    # $1 = action + to_log + prio, p.ej: >>!-- = ">>" + "!" + "--"
    # $2 = proto, varios separados por comas, p.ej: tcp,udp
    # $3 = local (ip:port:port)
    # $4 = dir (<, >, <>)
    # $5 = remote (ip:port:port)
    # $6 y resto = Descripcin de la regla 
    # $6 *POR HACER* puerto de REDIReccin

    
# IMPRIMIR LINEAS DE REGLAS COMO COMENTARIO (o como echo si es modo debug)
	print ""
	if ( debug ) {
	    print "echo"
	    print "echo \"" $0 "\""
	}
	else print "#"$0


    # SEPARAR ACCION EN: action, to_log, prio
	action = $1
	gsub( "[!+-]+", "", action )		#Quito ! y +, ++, -, --

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

	prio = $1
	gsub( "[^+-]+", "", prio )		#Quito todo menos +, ++, -, --

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

    # LOGALLDENY
	if ( logalldeny && action == "NO" ) to_log = "!"

    # SEPARAR IP LOCAL DE PUERTO/RANGO
	split ( $3, parts, ":" )
	if ( parts[1] ~ "(^\$)|(\.)" ) {	#Hay IP? ($VAR o x.x.x.x)
	    local = parts[1]			#Si
	    local_port = "" parts[2]		#Puerto, fuerzo cero como letra
	    if ( parts[3] ) local_port = local_port ":" parts[3]  # Es 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			#Fuerzo el cero como letra
	}

    # SEPARAR IP REMOTA DE PUERTO/RANGO
	split ( $5, parts, ":" )
	if ( parts[1] ~ "(^\$)|(\.)" ) {	#Hay IP? ($VAR o x.x.x.x)
	    remote = parts[1]			#Si
	    remote_port = "" parts[2]		#Puerto, fuerzo cero como letra
	    if ( parts[3] ) remote_port = remote_port ":" parts[3]  # Es 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			#Fuerzo el cero como letra
	}

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

    # PROCESO "REDIR"
	if ( action == "REDIR" ){
	    redir = $6
	    gsub ( "[->]*", "", redir )		#Ignorar "-" y ">" ("->")
	}
	else redir = ""

    # BUCLE PARA VARIABLE IPREMOTAS
	if ( remote ~ SEVERAL_VALUES ) {
	    print "for IP_R in " remote "; do"
	    remote = "$IP_R"
	}
    # BUCLE PARA VARIABLE IPLOCALES
	if ( local ~ SEVERAL_VALUES ) {
	    print "for IP_L in " local "; do"
	    local = "$IP_L"
	}
    # VARIOS PROTOS (separados por comas)
	split ( $2, proto, "," )		#Crear una tabla de protocolos
	for ( n in proto ) {
    # MONTAR REGLA
	    put_rule( action, to_log, prio, interface_tmp, proto[n], \
		local, local_port, $4, remote, remote_port, redir )
	}
    # FINAL BUCLES PARA VARIABLES...
	if ( local ~ SEVERAL_VALUES ) print "done"
	if ( remote ~ SEVERAL_VALUES ) print "done"
    }


# FUNCIONES

    # ERROR: Los errores de sintaxis vienen aqui
    # Pongo echos en el script de manera que muestre errores al lanzarlo

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


#---------------PARTE VARIABLE-----------------------------------------
#---------------VARIABLE PART (depends on ipchains, iptables...)-------

    # HEADER OF FIREWALL SHELL SCRIPT

    function header( ){
	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 ""
	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 "# PROHIBIR FRAGMENTOS / DENY FRAGMENTS"
	print "echorun ipchains -A input -f -j DENY"
	print ""
	print ""
	print "# VAR PARA HACER LOG / VAR TO DO LOG"
	print "L=\"-l\""
	print ""
	print ""
	
	
	print "##### firewall-easy-lib ####################################"
    }


    # PUT_RULE: genera reglas coherentes con los parmetros que se le dan
    # No admite varios valores de from, proto, etc... Sino solo uno
    #
    # Variable:	Debe ser uno entre:
    # action 	NO, >, >>, *, RST, MASQUERADE, REDIR
    # to_log	"", !
    # prio	"", ++, +, -, --
    # iface	"", *, eth0, ppp0
    # proto	*, tcp, udp, icmp, o cualquier otro vlido (/etc/protocols)
    # local		*, $DNS, 1.2.3.4
    # local_port	"", *, domain, 53, 1:1024
    # dir		>, <, <>
    # remote		= local
    # remote_port	= local_port
    # redir		= local_port (parametro opcional, solo para REDIR)

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

	# 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 ( redir == "*")	 redir = ""


	# SI SE USA MASQ O REDIR activar forward (solo una vez)

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


	# TRADUCCION A ipchains
	# ATENCION: Acuerdate de dejar un espacio al final de cada traduccin

	input = "echorun ipchains -A input "
	output = "echorun ipchains -A output "
	forward = "echorun ipchains -A forward "	# Para enmascaramiento

	t["NO"] = "-j DENY "		# t es un array de traduccin
	t[">"] = "-j ACCEPT "
	t[">>"] = "-j ACCEPT "
	t["*"] = "-j ACCEPT "
	t["RST"] = "-j REJECT "
	t["MASQUERADE"] = "-j MASQ "
	t["REDIR"] = "-j REDIRECT "	# precisa kernel con "transparent proxy"

	t["!"] = "$L "			# var para poder eliminar log en script
	
	t["++"] = "-t 0x01 0x10 "	# IPTOS_LOWDELAY
	t["+"] = "-t 0x01 0x18 "	# LOWDELAY + THROUGHPUT
	t["-"] = "-t 0x01 0x08 "	# IPTOS_THROUGHPUT
	t["--"] = "-t 0x01 0x02 "	# IPTOS_MINCOST


	# ERRORES DE SINTAXIS
	# todos los errores que empiezan 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 != >") 


	# PROCESAR ">" Y ">>" PARA ipchains
	# Solo podemos impedir paquetes SYN de entrada en tcp
	
	if (( action == ">" || action == ">>" ) && proto == "tcp" ) {
	    established = "! -y "
	}
	else { established = "" }


	# NO PUEDE HABER PUERTO SIN IP, PONER 0/0 (cualquier IP)

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


	# GENERO PARAMETROS (con espacio al final)

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


	# LADO LOCAL
	# TO PARA REGLA INPUT: input_to Y FROM PARA REGLA OUTPUT: output_from
	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 " "
	}

	# LADO REMOTO
	# TO PARA OUTPUT: output_to Y FROM PARA REGLA INPUT: input_from
	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 " "
	}

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

	# SI HAY ENMASCARAMIENTO en ipchains debe ser regla forward
	if ( action == "MASQUERADE" ) output = forward

	# 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
	}
    }

# AL FINAL
    END{
    # FIN DE BUCLE INTERFACES ANTERIOR (si lo hubo)
	if ( interface ~ SEVERAL_VALUES ) {
	    print "done		# End of last INTERFACE for loop"
	}
	print
	print "# LOG ALL OTHER FORWARD TRIALS"
	print "echorun ipchains -A forward -j DENY -l"
    }
    
' > $TO 

chmod ugo+x $TO		#Doy permisos de ejecucin a todo el mundo al archivo

