#! /usr/bin/awk -f # FIAIF is an Intelligent firewall, version: $Revision: 1.17 $ # # description: Automates a packet filtering firewall with iptables. # # Script Author: Anders Fugmann # # FIAIF is an Intelligent firewall # Copyright (C) 2002-2003 Anders Peter Fugmann # # 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; either version 2 # of the License, or (at your option) any later version. # # 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 for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. BEGIN { FS = "NO SPLITTING" line = 0 errors = 0 } ## Test if a pattern covers the whole string ## Returns 1 on success, 0 othervice. function exact_match (string, pattern) { match(string, pattern) return ( RSTART == 1 && RLENGTH == length(string) ) } ## Trim a string starting spaces ## Returns a trimmed list. function trim (string) { if ( match(string, "[ ]+") == 1 ) return substr(string, RLENGTH+1) else return string } ## Expand a regular expression as found in the PATTERN array. ## Any elements enclosed in '#' is substituted by the corrosponding value ## as found in PATTERN[value]. ## Returns: The resulting string. function expand_pattern(pattern, expansion) { while ( match(pattern, "#[^#]*#" ) ) { expansion=substr(pattern,RSTART+1,RLENGTH-2) sub("#[^#]*#", PATTERN[expansion], pattern) } return pattern } ## Expand a rule as found in the RULE array. ## Any elements enclosed in '<' and '>' is substituted by the corrosponding value ## as found in RULE[value]. ## Returns: The resulting string. function expand_rule(rule, expansion) { while ( match(rule, "<[^#]*>" ) ) { expansion=substr(rule,RSTART+1,RLENGTH-2) sub("<[^#]*>", RULE[expansion], rule) } return rule } ## Generate an array of tokens from an string of tokens. ## Returns: number of tokens extracted. ## the 2. parameter contains an array of all found tokens. function split_tokens(token_list, token_arr, tok, token, tok_index) { tok=0 token_list=trim(token_list) while (length(token_list)) { if ( match(token_list, "[(][^)]*[)]") == 1 || match(token_list, "[^ ]*") == 1 ) { token_arr[tok++]=substr(token_list, 1, RLENGTH) token_list=trim(substr(token_list, RLENGTH+1)) } else { printf("Error in token_list"); break } } return tok } ## Eat tokens (as specified by the string 'tokens') from the given 'string'. ## Returns: 1 on success, 0 othervice. ## EMSG: A string containing the unmatched token. ## ELEN: The number of chars eaten. function eat(string, tokens, total_eaten, token, token_arr, eaten, expr, nr_tokens, compound, nr_compound, compound_arr) { error_msg = "" total_eaten=0 nr_tokens = split_tokens(tokens, token_arr) for ( token=0; token < nr_tokens; token++ ) { # printf("Next token: '%s'\n", token_arr[token]) # If expandable pattern if ( exact_match(token_arr[token], "<[^#]*>") ) { eaten = eat(string, expand_rule(token_arr[token])) if (!eaten) { ELEN+=total_eaten return 0 } eaten = ELEN } else { # If enclosed in paranthes if ( match(token_arr[token], "[(][^)]*[)]") == 1) { compound = substr(token_arr[token], 2, length(token_arr[token])-2) nr_compound = split(compound, compound_arr, "|") # List all compound tokens: for ( compound=1; compound <= nr_compound; compound++ ) { eaten = eat(string, compound_arr[compound], error_msg) # If something was eaten, then return an error. if (ELEN) { break } } if (!eaten) { ELEN+=total_eaten return 0 } eaten = ELEN } else { # just eat a standard pattern expr = expand_pattern(PATTERN[token_arr[token]]) if (DEBUG == 1) { printf(" Matching exp: %s (%s) to '%s'\n", expr, token_arr[token], string) } if ( match(string, expr) != 1 ) { EMSG = sprintf("<%s> expected.", token_arr[token]) ELEN = total_eaten return 0 } else { eaten=RLENGTH } } } string=substr(string, eaten+1) total_eaten+=eaten } ELEN = total_eaten EMSG = "" return 1 } ## Test values against rules for the paramter. ## Returns: 1 on success, 0 othervice. ## EMSG: A string containing the error message. ## ELEN: The number of chars eaten. function test_arguments(param_name, string, value, stripped) { ELEN=0 stripped=0 if ( ! exact_match(string, "([^ ]*|\".*\")[ #]*.*") ) { EMSG = "Value not enclosed in '\"'" return 0 } EMGS="" # Strip \". if ( match(string , "\".*\"") ) { string = substr(string, RSTART+1, RLENGTH-2) stripped=1 } value = eat(string, RULE[param_name]) # Test if extra chars exists (besides spaces): if ( value && ELEN < length(string) && ! (exact_match(substr(string, ELEN+1), "[ ]*([#].*)?") )) { EMSG="Unexpected character." value = 0 } ELEN+=stripped return value } ## Examine if a parametername is valid, and return ## the variable name on simple form function get_rule_name (string, name) { # First test that construction is ok. if ( ! (exact_match(string, "[A-Z]+[A-Z0-9_]*([[][0-9]+[]])?") || exact_match(string, "[A-Z]+[A-Z0-9_]*([[][$][{][#][A-Z]+[A-Z0-9_]*[[]@[]][}][]])?")) ) return "" # See if longname exists: if ( match(string, "[A-Z0-9_]+") == 1 ) { name=substr(string, 1, RLENGTH) if ( RULE[name] != "" ) { return name } } if ( match(string, "[A-Z]+") == 1 ) { name=substr(string, 1, RLENGTH) if ( RULE[name] != "" ) { return name } } return "" } ## Main functions (so to speak) ## Errors are printed to stdout. ## The total number of errors are stored in the var errors { if ( match($1, "=") ) { param=substr($1, 1, RSTART-1) value=substr($1, RSTART+1, length($1)) } else param=$1 line++ if ( match($1, "^[ ]*($|#)") == 0 ) { name = get_rule_name(param) if ( name == "" ) { errors++ printf("Line %d: Illegal parameter name <%s>\n", line, param) } else { if ( test_arguments(name, value) == 0 ) { errors++ printf("Line %d, pos %d: %s\n", line, ELEN+length(param)+2, EMSG) } } } } ## Give correct error value. ## If any erros was found, then exit with value if 1. ## Othervice exit with value 0. END { if (errors) { if (errors == 1) error_str="error" else error_str="errors" printf("%d lines scanned, %d %s found\n", line, errors, error_str) exit 1 } else { exit 0 } }