% pfilter - packet filtering for GNU/Linux
%
% ruleset generation macro and other directives documentation

% Copyright 2003 Neil Gorsuch
%
% This file is part of pfilter.
%
% pfilter 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.
%
% pfilter 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

% The files in the rulesets directory are used to for two purposes:
%	to define unusual services before the configuration file is parsed,
%       and when generating the output ruleset commands files.
%
% The '%' character is used to trigger special actions such as defining
% macros, conditional output generation, etc.  The reason that the '#'
% character was not chosen for this was that the '#' character is heavily
% used in the output rulesets command file as a shell script comment delimiter.
% Every effort was made to allow faster initial parsing of the ruleset files,
% and to allow faster output generation of the ruleset command file.  
% Defining macros, conditional generation blocks, etc are only done with
% lines that have the '%' character in first column with a non-whitespace
% character in the next column.  Comment lines that are completely
% swallowed during ruleset generation need to have the '%' character first
% with a whitespace character next.  Portions of lines that are comments and
% are swallowed during ruleset generation are whitespace followed by the '%'
% character followed by any characters except the '%' character, or
% whitespace followed by the '%' character followed by at least one
% whitespace character and then any other characters.
%
% The possible things that can be done with this macro language are:
%
% -------------------------------------------------------------------------
% variable definition and substitution
%
% Variable substitution can be nested. Variables are defined like this:
%	|%constant NAME VALUE					|
% or like this:
%	|%define NAME VALUE					|
% where NAME only includes the [a-zA-Z_-0-9] characters,
% and VALUE includes any non-whitespace characters.
% The only difference between a constant and a define is
% that a constant, once assigned, cannot be redefined.
% To have a variable substitution in the generated ruleset output,
% embed the variable name with '%' characters on both sides, like this:
%	|about to include the variable %var1% in this line	|
% If the variable var1 had the value value1, that line would cause this output:
%	|about to include the variable value1 in this line	|
%
% These %constant values are pre-defined:
% action                           "restart" or "start" or "stop" or "status"
% all_interfaces                   all network interface names seperated by spaces
% config_file_path                 configuration file, default "/etc/pfilter.conf"
% date                             current date/time as returned by the date command
% debug                            non-zero if debug output wanted
% domainname                       domain name as returned by the domainname command
% exec                             non-zero if executing commands file
% filtered_interface_addressess    space seperated filtered interface addresses
% filtered_interface_names         space seperated filtered interface names
% forced_mode                      if forced, "iptables" or "ipchains"
% hostname                         machine name as returned by the hostname command
% mode                             "iptables" or "ipchains" or "ipfilter"
% output_file_path                 output commands, default "/usr/sbin/pfilter.cmds"
% pfilter_version                  version of pfilter, such as "1.25"
% protected_interface_addressess   protected interface addresses seperated by spaces
% protected_interface_names        protected interface names seperated by spaces
% source_file_path                 intermediate output, default "/usr/sbin/pfilter.src"
% uname                            output of the uname command
% unfiltered_interface_addressess  space seperated unfiltered interface addresses
% unfiltered_interface_names       space seperated unfiltered interface names
% unprotected_interface_addressess space seperated unprotected interface addresses
% unprotected_interface_names      space seperated unprotected interface names
% verbose                          non-zero if verbose output wanted
%
% These %define values are pre-defined:
% ifconfig_path	 	 full path for ifconfig binary
% ipchains_path	 	 full path for ipchains binary if found
% iptables_path	 	 full path for iptables binary if found
% log_burst		 logging burst limit, default "50"
% log_level		 logging level, default "DEBUG"
% log_rate		 logging maximum rate, default "2/m"
% nowayed		 how packets are blocked, "DROPPED" or "REJECTED"
% nowayit		 how to block packets, "DROP" or "REJECT"
% route_path		 full path for route binary
%
% -------------------------------------------------------------------------
% conditional rulesets generation
%
% Conditional generation can be nested as many levels deep as desired.
%
% At the end of a line, this:
%	|line to be conditionally generated %if STRING		|
% will cause the line to be generated if STRING is non-blank
% and string is not "0".
%
% At the beginning of a line, this:
%	|%ifdef VARIABLE	line to be possibly generated	|
% or at the end of a line, this:
%	|line to be possibly generated %ifdef %VARIABLE%	|
% will cause the line to be generated if the variable has been defined.
%
% At the beginning of a line, this:
%	|%ifndef VARIABLE	line to be possibly generated	|
% or at the end of a line, this:
%	|line to be possibly generated %ifndef %VARIABLE%	|
% will cause the line to be generated if the variable has not been defined.
%
% At the beginning of a line, this:
%	|%if STRING1=STRING2 line to be conditionally generated |
% or at the end of a line, this:
%	|line to be conditionally generated %if STRING1=STRING2 |
% will cause the line to be generated if STRING1 is the same as STRING2.
%
% At the beginning of a line, this:
%	|%if STRING1!=STRING2 line to be conditionally generated |
% or at the end of a line, this:
%	|line to be conditionally generated %if STRING1!=STRING2 |
% will cause the line to be generated if STRING1 is different than STRING2.
%
% This block of lines:
%	|%if STRING						|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if STRING is non-blank
% and string is not "0".
%
% This block of lines:
%	|%ifdef VARIABLE					|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if the variable has been defined.
%
% This block of lines:
%	|%ifndef VARIABLE					|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if the variable has not been defined.
%
% This block of lines:
%	|%if STRING1=STRING2					|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if STRING1 is the same as STRING2.
%
% This block of lines:
%	|%if STRING1!=STRING2					|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if STRING1 is different than STRING2.
%
% This block of lines:
%	|%if -r FILE						|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if there is a readable file FILE.
%
% This block of lines:
%	|%if -w FILE						|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if there is a writable file FILE.
%
% This block of lines:
%	|%if -x FILE						|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if FILE is executable.
%
% This block of lines:
%	|%if -d DIRECTORY					|
%	|line(s) to be conditionally generated			|
%	|%else		% else and following line(s) optional	|
%	|optional line(s) conditionally generated if false	|
%	|%endif							|
% will cause the line(s) to be generated if FILE is a directory.
%
% -------------------------------------------------------------------------
% file inclusion (not implemented yet)
%
% A line like this:
%	|%include FILE						|
% will cause the named file to be included. Included files can be nested.
%
% -------------------------------------------------------------------------
% internal array of lines inclusion (not implemented yet)
%
% A line like this:
%	|%array ARRAY						|
% will cause the the array of lines to be included.  This can be nested,
% but cannot be in a file, only used from another included array of lines.
%
% -------------------------------------------------------------------------
% looping (not implemented yet)
%
% A block of lines like this:
%	|%foreach VARIABLE VALUE1 VALUE2 VALUE3 ...		|
%	|lines(s) to be included in each loop, with 		|
%	|the variable VARIABLE defined as one of the		|
%	|values for each loop/invocation			|
%	|%endfor
% will cause the lines to be included as many times as there are values,
% with the variable VARIABLES being assigned each time to the current value.
%
% -------------------------------------------------------------------------
% macros
%
% A block of lines like this:
%	|%macro NAME [VAR1, ...]				|
%	|line(s) to be included when invoking macro		|
%	|%endmacro						|
% will cause the block of lines defined in the macro to be generated
% whenever the macro is encountered as the first fields of the line,
% with temporary variables values assigned to the variables listed
% in the macro definition.
%
% ------------------------------------------------------------------------
% mode definitions (not implemented yet)
%
% Modes are the packet filtering methods. These are currently supported:
%	iptables	(works well)
%	ipchains	(only placeholders)
% A mode is created by defining the following macros, where NAME is the 
% name of the mode:
%
% %macro mode_NAME_alias faked_address faked_ip real_address real_ip \
% faked_interface index
%	This macro will be invoked as the result of a compiled ALIAS 
%	directives. The address parameters can be either a numeric IP or
%	a gethostbyname resolvable NAME. The faked_ip is the resolved
%	numeric IP of the faked_address, and the real_ip is the resolved
%	numeric IP of the real_address. The index parameter starts at 
%	1 and is increased for every pseudo address on that interface.
%	This macro is optional for each mode.
%
% %macro mode_NAME_forward_protocol_port protocol port source_address \
% destination_address source_interface destination_interface \
% onto_address onto_ip onto_port
%	This macro will be invoked as the result of a compiled FORWARD
%	directives. The address parameters can be either a numeric IP or
%	a gethostbyname resolvable NAME. The faked_ip is the resolved
%	numeric IP of the faked_address, and the real_ip is the resolved
%	numeric IP of the real_address. The index parameter starts at 
%	1 and is increased for every pseudo address on that interface.
%	This macro is optional for each mode.
%
% %macro mode_NAME_nat inside_name inside_address_mask outside_name outside_ip
%	This is the macro used to enable and specify NAT (network address
%	translation) for connections/packets coming from a single inside
%	(protected) interface that are to be forwarded out to a single outside
%	(unprotected) interface, to look like they originated from the 
%	interface address on the outside (unprotected). This macro is optional
%	for each mode.
%
% %macro mode_NAME_open_close_protocol_port open_close source_address \
% destination_address source_interface destination_interface protocol port
%	This macro will be invoked as the result of compiled OPEN or CLOSE
%	directives. The open_close parameter will be either the string
%	"open" or "close". Addresses can be either a numeric IP or a numeric
%	IP/MASK_VALUE or a numeric IP/MASK_BITS or a gethostbyname resolvable
%	NAME or a gethostbyname resolvable NAME/MASK_VALUE or a gethostbyname
%	resolvable NAME/MASK_BITS or ANY to match any addresses. Interfaces 
%	should be either a valid interface name such as eth0 or ANY for no
%	specified interface. Protocol is one of these strings: "tcp" or "udp"
%	or "icmp". Port is either a numeric port number (or numeric icmp
%	type), or a named port that the main mode command understands.
%	This macro is required for each mode.
%
% %macro mode_NAME_start_restart_prefix
%	This macro will be invoked as part of the compiled output commands
%	during pfilter start and restart sections, in the prefix section 
%	(before the compiled OPEN/CLOSE/whatever compiled section. 
%	It should set up and start the packet filtering mode. This macro
%	is required for each mode.
%
% %macro mode_NAME_start_restart_suffix
%	This macro will be invoked as part of the compiled output commands
%	during pfilter start and restart sections, in the suffix section 
%	(after the compiled OPEN/CLOSE/whatever compiled section. 
%	It should finish doing default blocking rules and finish setting
%	up the packet filtering mode. This macro is required for each mode.
%
% %macro mode_NAME_stop
%	This macro will be invoked as part of the compiled output commands
%	during pfilter stop sections, It should turn off the packet filtering
%	and set everything back to unfiltered/pass all mode. This macro is
%	required for each mode.
%
% %macro mode_NAME_test
%	This macro will be invoked as a shell script to test if the packet
%	filtering mode is possible and allowed. It should exit with a
%	status of zero (success) if the mode can work, non-zero if the
%	mode will not work. If the macro has a single line only, it is
%	invoked as a single shell command line, with same exit status
%	requirements. This macro is required for each mode.
%
% %define mode_NAME_weight
%	This define sets the relative weight of each mode. If more than
%	one mode tests as being possible, the one with the highest weight
%	number will be used (unless a command line option is specified
%	that forces a particular mode). This definition is optional for
%	each mode, if not defined for a mode the weight is set to 5.
%
% ------------------------------------------------------------------------
% network service definitions
%
% By default, all service names listed in the system file /etc/services
% are converted to network service definitions.  These are very simple,
% since they are only listed with a name and the first tcp and/or udp
% port numbers for that service. Some services require opening or blocking
% more than one port, or require special shell commands to be executed
% when doing so. Defining a network service overrides the implicit 
% definition of that service created by entries in the /etc/services file.
%
% A special service is created by defining one or more of the following
% sets of definitions and/or macros, where NAME is the name of the service:
%
% %define service_NAME_protocols_ports PROTOCOLS/PORTS
%	When this constant/define is defined, it creates a network service
%	with a special set of protocols/ports to be opened and/or blocked.
%	A perfect example is the X server service, which needs to worry
%	about tcp and udp ports 6000 through 6063, to define it as 
% 	a special network service, there is a definition file that has:
%		|%define service_x_protocols_ports tcp udp/6000:6063       |
%		|%define service_x11_protocols_ports tcp udp/6000:6063     |
%		|%define service_xserver_protocols_ports tcp udp/6000:6063 |
%	Note that this allows x or x11 or xserver to correspond to the 
%	tcp and udp ports from 6000 through 6063.  For each service
%       defined this way, both variables must be defined, not just one.
%
% %macro service_NAME_open
%	When a macro like this is defined, a network service is created
% 	that doesn't just open or block ports. This macro is invoked when
%	a configuration line like this is compiled:
%		|OPEN NAME [from source_addresses] [to destination_addresses]	|
%	When the macro is invoked, the arguments passed are:
%		source address (if "ANY", any source address allowed)
%		destination address (if "ANY", to external ip addresses)
%		source interface name (if "ANY", any or unknown interface
%		destination interface name (if "ANY", any or unknown interface)
%		source interface broadcast address (or "UNKNOWN" if unknown)
%		destination interface broadcast address (or "UNKNOWN" if unknown)
%	For instance, allowing access to an nfs server requires a short
%	shell script fragment to determine which ports are currently being
%	used, as follows:
%	|%macro service_nfs_open source dest src_int dest_int scr_mask dest_mask|
%	|for prot in tcp udp ; do						|
%	|  for port in 111 635 ; do						|
%	|    %open_protocol_port% %source% %dest% %src_int% %dest_int% $prot $port|
%	|    %open_protocol_port% 127.0.0.1 127.0.0.1 lo0 lo0 $prot $port	|
%	|  done									|
%	|  for port in `rpcinfo -p | awk "\\$3==\"$prot\"{print \\$4}" | egrep -v '^111$' | sort -n | uniq` ; do	|
%	|    %open_protocol_port% %source% %dest% %src_int% %dest_int% $prot $port|
%	|    %open_protocol_port% 127.0.0.1 127.0.0.1 lo0 lo0 $prot $port	|
%	|  done									|
%	|done									|
%	|%endmacro								|
%       If there is a service open fragment, there should also be a close fragment.
%
% %macro service_NAME_close
%	When a macro like this is defined, a network service is created
% 	that doesn't just open or block ports. This macro is invoked when
%	a configuration line like this is compiled:
%		|CLOSE NAME [from source_addresses] [to destination_addresses]	|
%	When the macro is invoked, the arguments passed are:
%		source address (if "ANY", any source address allowed)
%		destination address (if "ANY", to external ip addresses)
%		source interface name (if "ANY", any or unknown interface
%		destination interface name (if "ANY", any or unknown interface)
%		source interface broadcast address (or "UNKNOWN" if unknown)
%		destination interface broadcast address (or "UNKNOWN" if unknown)
%	For instance, allowing access to an nfs server requires a short
%	shell script fragment to determine which ports are curretnly being
%	used, as follows:
%	|%macro service_nfs_close source dest src_int dest_int scr_mask dest_mask|
%	|for prot in tcp udp ; do						|
%	|  for port in 111 635 ; do						|
%	|    %close_protocol_port% %source% %dest% %src_int% %dest_int% $prot $port|
%	|    %close_protocol_port% 127.0.0.1 127.0.0.1 lo0 lo0 $prot $port	|
%	|  done									|
%	|  for port in `rpcinfo -p | awk "\\$3==\"$prot\"{print \\$4}" | egrep -v '^111$' | sort -n | uniq` ; do	|
%	|    %close_protocol_port% %source% %dest% %src_int% %dest_int% $prot $port|
%	|    %close_protocol_port% 127.0.0.1 127.0.0.1 lo0 lo0 $prot $port	|
%	|  done									|
%	|done									|
%	|%endmacro								|
%       If there is a service close fragment, there should also be an open fragment.
%








