ipchains2iptables Rule Converter

Tagged:  

雖然 Linux 的 kernel 2.4.x 已經推出多年, 但慣用 ipchains 作防火牆的系統管理員仍未升級伺服器到 kernel 2.4.x, 在考慮升級時發現要把長篇的 ipchains scripts 翻譯到 iptables 便頭痛。


其實, 系統管理員可以使用以下程式把 ipchains 自動轉為 iptables。


http://www.stearns.org/i2i/ipchains2iptables


為方便大家, 現把整篇 script 例出來。


#!/bin/bash
#Copyright (c) 1999-2002, William L. Stearns 
#Released under the GPL.
#Home page is at http://www.stearns.org/i2i/
##Version 0.6.1, cleanup release, May 9, 2002

#FIXME - finish keeping track of needed modules and listing them.
#FIXME - icmp needs icmp-type, not --sport/--dport
#NATSPEC and the IPNATCTLBIN are no loner used as masquerading is
#done right in the iptables ommand line again, as it was in ipchains.
#NATBANGWARNING also no longer used as iptables should take the negated
#arguments ipnatctl had trouble with.


echo "------------------------------------------------------------------" >/dev/stderr
echo "---- ipchains2iptables rule converter                         ----" >/dev/stderr
echo "---- See http://www.stearns.org for more info on              ----" >/dev/stderr
echo "---- this and Mason, the automatic firewall creator.          ----" >/dev/stderr
echo "---- Copyright (c) 1999 William Stearns   ----" >/dev/stderr
echo "---- Released under the GNU GPL.                              ----" >/dev/stderr
echo "------------------------------------------------------------------" >/dev/stderr

Fshift () {
	F1=$F2 ;	F2=$F3 ;	F3=$F4 ;	F4=$F5 ;	F5=$F6
	F6=$F7 ;	F7=$F8 ;	F8=$F9 ;	F9=$F10 ;	F10=$F11
	F11=$F12 ;	F12=$F13 ;	F13=$F14 ;	F14=$F15 ;	F15=$F16
	F16=$F17 ;	F17=$F18 ;	F18=$F19 ;	F19=$F20 ;	F20=$F21
	F21=$F22 ;	F22=$F23 ;	F23=$F24 ;	F24=$F25 ;	F25=$F26
	F26=$F27 ;	F27=$F28 ;	F28=$F29 ;	F29=$F30 ;	F30=$F31
	F31=$F32 ;	F32=$F33 ;	F33=$F34 ;	F34=$F35 ;	F35=$F36
	F36=$F37 ;	F37=$F38 ;	F38=$F39 ;	F39=$F40 ;	F40=$F41
	F41=$F42 ;	F42=$F43 ;	F43=$F44 ;	F44=$F45 ;	F45=$F46
	F46=$F47 ;	F47=$F48 ;	F48=$F49 ;	F49=$F50 ;	F50=$F51
	F51=$F52 ;	F52=$F53 ;	F53=$F54 ;	F54=$F55 ;	F55=$F56
	F56=$F57 ;	F57=$F58 ;	F58=$F59 ;	F59=$F60 ;				F60=''
}

islocalip () {
#Returns true if the $1 IP address is an ip address on this box.
#This is used to identify which packets are destined to/coming from
#local processes.
#param: ip address to check
	for ONEIP in $LOCALNAMES ; do
		if [ "z$1" = "z$ONEIP" ] || [ "z$1" = "z$ONEIP/32" ]; then
			return 0 #True
		fi
	done
	return 1 #False
}

suggestif () {
#Add a note in the comment that the user might want to add in
#an additional interface specification.
#params: -i/-o, srcaddr, optional actual interface to suggest
	if [ -n "$2" ]; then
		if [ -n "$3" ]; then
			COMMENT="$COMMENT Suggestion: \"$1 $3\"."
		else
			COMMENT="$COMMENT Suggestion: \"$1 IF-of-$2\"."
		fi
	fi
}

addprotoholder () {
#This adds a placeholder for "-p protocol", if it's not already there,
#to CHAINRULE.  This is used to make sure that "-p proto"
#always comes before any other specifications that depend on the 
#protocol module (ipt_TCP, etc) being loaded.
	if [ -z "`echo $CHAINRULE | grep ' -p '`" ]; then
		CHAINRULE="$CHAINRULE -p ZZPROTOZZ"
	fi
	#if [ -n "`echo $NATSPEC | grep ' -p '`" ] || [ -n "`echo $NATSPEC | grep '^-p '`" ]; then
	#	:
	#else
	#	NATSPEC="$NATSPEC -p ZZPROTOZZ"
	#fi
}


if [ "$1" = '--help' ] || [ "$1" = '-h' ]; then
	echo Usage: $0 [--help] >/dev/stderr
	echo This program converts ipchains rules to iptables rules. >/dev/stderr
	echo Example of use: >/dev/stderr
	echo >/dev/stderr
	echo cat ipchains_rulefile \| ipchains2iptables \>iptables_rulefile >/dev/stderr
	#echo echo if [ -f /proc/net/ip_fwchains ]\; then \>\>new_rules >/dev/stderr
	#echo cat ipchains_rulefile \>\>new_rules >/dev/stderr
	#echo echo elif [ -f /proc/net/ip_input ]\; then \>\>new_rules >/dev/stderr
	#echo cat ipfwadm_rulefile \>\>new_rules >/dev/stderr
	#echo echo fi \>\>new_rules >/dev/stderr
	#echo >/dev/stderr
	#echo The new_rules file will now work on ipchains and ipfwadm kernels. >/dev/stderr
	exit
fi


#Global settings:
NEEDEDMODULES=''

#if which ipnatctl >/dev/null ; then
#	IPNATCTLBIN=`which ipnatctl | head -1`
#elif [ -x /usr/local/bin/ipnatctl ]; then
#	IPNATCTLBIN='/usr/local/bin/ipnatctl'
#else
#	IPNATCTLBIN='ipnatctl'
#	echo '#ipnatctl was not found in your path or in /usr/local/bin.  You may need'
#	echo '#to copy it or add an explicit path to it in the following commands.'
#fi

if which iptables >/dev/null ; then
	IPTABLESBIN=`which iptables | head -1`
elif [ -x /sbin/iptables ]; then
	IPTABLESBIN='/sbin/iptables'
elif [ -x /usr/local/bin/iptables ]; then
	IPTABLESBIN='/usr/local/bin/iptables'
else
	IPTABLESBIN='iptables'
	echo '#iptables was not found in your path or in /usr/local/bin.  You may need'
	echo '#to copy it or add an explicit path to it in the following commands.'
fi

#NATBANGWARNING=''

#For me...
#export LOCALIPS="`ifconfig | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'` 172.20.0.253 \${ppp0ADDR}"

if [ -z "$LOCALNAMES" ]; then
	LOCALIPS="${LOCALIPS:-`ifconfig | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`}"

	for ONEIP in $LOCALIPS ; do
		LOCALNAMES="$LOCALNAMES $ONEIP $ONEIP/32"
		for ONENAME in `egrep "^$ONEIP[^0-9]" /etc/hosts | tail --lines=1 | sed -e "s/^$ONEIP//"` ; do
			LOCALNAMES="$LOCALNAMES $ONENAME $ONENAME/32"
		done
	done
fi
#echo $LOCALNAMES

#Variables that need to be reset for each line:
COMMENT='' DISABLELINE=''
BIDIRECTIONAL=''
CHAINRULE='' ; NEXT=''
REDIR='' ; REDIRPORT=''
NEGATE=''
CHAIN=''
LOGME=''
MASQME=''
#NATSPEC=''
SRCIP='' ; DESTIP=''
IFSPEC=''
PROTOCOL=''
SOURCEPARAM='' ; SOURCESPEC='' ; DESTPARAM='' ; DESTSPEC=''

#Start of main loop.  Read one iptables rule for processing.
while read  F1  F2  F3  F4  F5  F6  F7  F8  F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 \
           F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 F32 F33 F34 F35 F36 F37 F38 F39 F40 \
           F41 F42 F43 F44 F45 F46 F47 F48 F49 F50 F51 F52 F53 F54 F55 F56 F57 F58 F59 F60 ; do	 #While there is another line of input
	while [ -n "$F1" ]; do		#While there is another field to process in this line
		case "$F1" in
		/sbin/ipchains|ipchains|*/ipchains)
			CHAINRULE="$CHAINRULE $IPTABLESBIN"
			NEEDEDMODULES="$NEEDEDMODULES iptables"
			NEXT='' ; NEGATE=''											;;
		#*/ipchains)	#We're not guaranteed iptables will be in the same dir.
		#	CHAINRULE="$CHAINRULE `echo $F1 | sed -e 's@/ipchains$@/iptables@'`"
		#	NEEDEDMODULES="$NEEDEDMODULES iptables"
		#	NEXT='' ; NEGATE=''											;;

#"!" always applies to the _following_ object.  As the -x and --x try to handle ! in _their_ 
#parameters, this could be either "-s 192.168.0.1 ! www" or "! -f".  Just remember it for the 
#moment and let individual choices handle it in a minute.
		!)							#Negate the following object.  "NEXT" stays as is.
			NEGATE=" !"												;;

#---------- Single uppercase character options, alphabetically ----------
#ipchains -[ADC] chain rule-specification [options]
#Append  one  or  more rules to the end of the selected chain.  When the source and/or destination names
#resolve to more than one address, a rule will be added for each possible address combination.
		-A|--append)				#Append this rule (1 param, handled here)
			CHAIN="$F2"
			CHAINRULE="$CHAINRULE $F1 ZZCHAINZZ" ; Fshift
			NEXT='' ; NEGATE=''											;;

#ipchains -[ADC] chain rule-specification [options]
#Check  the  given packet against the selected chain.  This is extremely useful for testing, as the same
#kernel routines used to check "real" network packets are used to check this packet.  It can be used  to
#check  user-defined  chains  as  well as the builtin ones.  The same arguments used to specify firewall
#rules are used to construct the packet to be tested.  In particular, the -s (source), -d (destination),
#-p (protocol), and -i (interface) flags are compulsory.
		-C|--check)							#Check if packet would be accepted or not (1 param, handled here)
			CHAIN="$F2"
			CHAINRULE="$CHAINRULE $F1 ZZCHAINZZ" ; Fshift
			NEXT='' ; NEGATE=''											;;

#ipchains -[ADC] chain rule-specification [options]
#ipchains -D chain rulenum [options]
#Delete one or more rules from the selected chain.  There are two versions of this command: the rule can
#be specified as a number in the chain (starting at 1 for the first rule) or a rule to match.
		-D|--delete)				#Delete this rule (1 or 2 params, needs NEXT support)
			CHAIN="$F2"
			CHAINRULE="$CHAINRULE $F1 ZZCHAINZZ" ; Fshift
			NEXT='APPEND' ; NEGATE=''									;;

#ipchains -[LFZNX] [chain] [options]
#Flush the selected chain.  This is equivalent to deleting all the rules one by one.
		-F|--flush)					#Flush the rules in this chain (0 or 1 params, needs NEXT support)
			CHAINRULE="$CHAINRULE $F1"
			NEXT='CHAIN' ; NEGATE=''									;;

#ipchains -[RI] chain rulenum rule-specification [options]
#Insert one or more rules in the selected chain as the given rule number.  So, if the rule number is  1,
#the rule or rules are inserted at the head of the chain.
		-I|--insert)				#Insert this rule (1 or 2 params, needs NEXT support)
			CHAIN="$F2"
			CHAINRULE="$CHAINRULE $F1 ZZCHAINZZ" ; Fshift
			NEXT='APPEND' ; NEGATE=''									;;

#ipchains -[LFZNX] [chain] [options]
#List  all rules in the selected chain.  If no chain is selected, all chains are listed.  It is legal to
#specify the -Z (zero) option as well, in which case no chain may be specified.   The  exact  output  is
#effected by the other arguments given.
		-L|--list)					#List the rules in this chain (0 or 1 params, needs NEXT support)
			CHAINRULE="$CHAINRULE $F1"
			NEXT='CHAIN' ; NEGATE=''									;;

#ipchains -M [ -L | -S ] [options]
#This  option allows viewing of the currently masqueraded connections (in conjuction with the -L option)
#or to set the kernel masqerading parameters (with the -S option).
		-M|--masquerading)			#Masquerading administration (used for -L and -S, 0 params, handled here)
			COMMENT="$COMMENT Remove -M."
			DISABLELINE='# '
			NEXT='' ; NEGATE=''											;;

#ipchains -[LFZNX] [chain] [options]
#Create a new user-defined chain of the given name.  There must be no target of that name already.
#No need to adjust the chain name as it's never a builtin.
		-N|--new-chain)				#Create a new chain (1 param, handled here)
			CHAINRULE="$CHAINRULE $F1 $F2" ; Fshift
			NEXT='' ; NEGATE=''											;;

#ipchains -P chain target [options]
#Set the policy for the chain to the given target.  See the section TARGETS for the legal targets.  Only
#non-userdefined chains can have policies, and neither built-in nor user-defined chains  can  be  policy
#targets.
		-P|--policy) 				#Default policy for the chain (2 params, handled here)
			CHAIN="$F2"
			CHAINRULE="$CHAINRULE $F1 ZZCHAINZZ $F3" ; Fshift ; Fshift
			NEXT='' ; NEGATE=''											;;

#ipchains -[RI] chain rulenum rule-specification [options]
#Replace  a  rule  in  the  selected  chain.  If the source and/or destination names resolve to multiple
#addresses, the command will fail.  Rules are numbered starting at 1.
		-R|--replace)				#Replace a rule (2 params, handled here)
			CHAIN="$F2"
			CHAINRULE="$CHAINRULE $F1 ZZCHAINZZ $F3" ; Fshift ; Fshift
			NEXT='' ; NEGATE=''											;;

#-S, --set tcp tcpfin udp
#Change the timeout values used for 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.  A timeout value 0 means that the current timeout  value  of  the  corresponding
#entry is preserved.  This option is only allowed in combination with the -M flag.
		-S|--set)	#Set timeouts for masquerading
			COMMENT="$COMMENT Remove -S $F2 $F3 $F4."
			Fshift ; Fshift ; Fshift
			DISABLELINE='# '
			NEXT='' ; NEGATE=''											;;

#ipchains -[LFZNX] [chain] [options]
#Delete  the  specified  user-defined chain.  There must be no references to the chain (if there are you
#must delete or replace the referring rules before the chain can be deleted).  If no argument is  given,
#it will attempt to delete every non-builtin chain.
#No need to adjust the chain name as it's never a builtin.
		-X|--delete-chain)			# (1 param, handled here)
			CHAINRULE="$CHAINRULE $F1 $F2" ; Fshift
			NEXT='' ; NEGATE=''											;;

#ipchains -[LFZNX] [chain] [options]
#Zero  the  packet and byte counters in all chains.  It is legal to specify the -L, --list (list) option
#as well, to see the counters immediately before they are cleared; if this is  done,  then  no  specific
#chain can be specified (they will all be displayed and cleared.
		-Z|--zero) 					#Zero out the counters (0 params)
			CHAINRULE="$CHAINRULE $F1"
			NEXT='' ; NEGATE=''											;;

#---------- Single lowercase character options, alphabetically ----------
#Bidirectional mode.  The rule will match with IP packets in both directions; this has the  same  effect
#as repeating the rule with the source & destination reversed.
		-b|--bidirectional) 		#bidirectional mode
			BIDIRECTIONAL='YES'
			NEXT='' ; NEGATE=''											;;

#-d, --destination [!] address[/mask] [!] [port[:port]]
#Destination specification.  See the desciption of the -s (source) flag for a  detailed  description  of
#the syntax.  For ICMP, which does not have ports, a "destination port" refers to the numeric ICMP code.
#The flag --dst is a convenience alias for this option.
		-d|--destination|--dst)		#Specify packet destination (1 - 4 params, portspec must be stripped off, needs NEXT support)
			if [ "z$F2" = "z!" ]; then
				CHAINRULE="$CHAINRULE $F1 $F2 $F3"
				#NATSPEC="$NATSPEC -d $F2 $F3"
				#NATBANGWARNING='YES'
				Fshift ; Fshift
			#elif [ "z$F2" = "z0/0" ]; then	#No need to add -d 0/0 anymore, but it doesn't hurt to leave it there
			#	Fshift
			else
				CHAINRULE="$CHAINRULE $F1 $F2"
				#NATSPEC="$NATSPEC -d $F2"
				DESTIP="$F2"
				Fshift
			fi
			NEXT='dport' ; NEGATE=''									;;

#[!]  -f, --fragment
#This  means  that  the  rule  only refers to second and furthur fragments of fragmented packets.  Since
#there is no way to tell the source or destination ports of such a packet (or ICMP type), such a  packet
#will  not  match any rules which specify them.  When the "!" argument precedes the "-f" flag, the sense
#is inverted.
		-f|--fragment)				#Match second or further fragments (0 params, NEGATABLE)
			CHAINRULE="$CHAINRULE$NEGATE $F1"
			NEXT='' ; NEGATE=''											;;

#-h     Help.  Give a (currently very brief) description of the command syntax.
		-h)							#Show help (0 or 1 params)
			if [ "z$F2" = "zicmp" ]; then
				CHAINRULE="$CHAINRULE -p $F2 $F1" ; Fshift
			else
				CHAINRULE="$CHAINRULE $F1"
			fi
			NEXT='' ; NEGATE=''											;;

#-i, --interface [!] name
#Optional  name  of  an  interface via which a packet is received, or via which is packet is going to be
#sent.  When this option is omitted, the empty string is assumed, which has a special meaning  and  will
#match  with  any interface name.  When the "!" argument is used before the interface name, the sense is
#inverted.  If the interface name ends in a "+", then any interface which begins  with  this  name  will
#match.
		-i|--interface)				#Use this interface (1 or 2 params, handled here)
			CHAINRULE="$CHAINRULE ZZIFSPECZZ"
			if [ "z$F2" = "z!" ]; then
				IFSPEC="$F2 $F3"
				Fshift ; Fshift
			else
				IFSPEC="$F2"
				Fshift
			fi
			NEXT='' ; NEGATE=''											;;

#-j, --jump target
#This specifies the target of the rule; ie. what to do if the packet matches it.  The target  can  be  a
#user-defined chain (not the one this rule is in) or one of the special targets which decide the fate of
#the packet immediately.  If this option is omitted in a rule, then  matching  the  rule  will  have  no
#effect on the packets fate, but the counters on the rule will be incremented.
#5.1.1.1.  iptables takes away...
#o  -j MASQ: Masquerading packets
#o  -j REDIRECT: Redirecting packets to the local machine
#o  -j REJECT: ICMP repies for dropped packets*
		-j|--jump)					#Jump to this chain or target (1 param, handled here)
			case "$F2" in
			DENY)
				CHAINRULE="$CHAINRULE $F1 DROP" ; Fshift
				NEXT='' ; NEGATE=''											;;
			MASQ)
				MASQME='YES'
				CHAINRULE="$CHAINRULE $F1 MASQUERADE" ; Fshift
				NEXT='' ; NEGATE=''											;;
			REJECT)
				CHAINRULE="$CHAINRULE $F1 REJECT" ; Fshift
				NEEDEDMODULES="$NEEDEDMODULES ipt_REJECT"
				NEXT='' ; NEGATE=''											;;
#FIXME ?
			REDIRECT)
				COMMENT="$COMMENT Unable to convert -j REDIRECT "
				DISABLELINE='# '
				CHAINRULE="$CHAINRULE $F1 REDIRECT" ; Fshift
				NEXT='REDIRPORT' ; NEGATE=''								;;
			*)	#Including ACCEPT and all user-defined chains
				CHAINRULE="$CHAINRULE $F1 $F2" ; Fshift
				NEXT='' ; NEGATE=''											;;
			esac
																		;;

#Turn  on kernel logging of matching packets.  When this option is set for a rule, the Linux kernel will
#print some information of all matching packets (like most IP header fields) via printk().
		-l|--log)					#log these packets
			LOGME='YES'
			NEEDEDMODULES="$NEEDEDMODULES ipt_LOG"
			NEXT='' ; NEGATE=''											;;

#-m, --mark markvalue
#Mark  matching  packets.  Packets can be marked with a 32-bit unsigned value which may (one day) change
#how they are handled internally.  If you are not a kernel hacker you are unlikely to care  about  this.
#If the string markvalue begins with a + or -, then this value will be added or subtracted from the cur-
#rent marked value of the packet (which starts at zero).
#FIXME - check to see if the MARK extension is simply a planned but currently unimmplemented feature.
		-m|--mark)					#
			#CHAINRULE="$CHAINRULE "
			COMMENT="$COMMENT $F1 $F2 Removed."
			Fshift
			NEXT='' ; NEGATE=''											;;

#Numeric output.  IP addresses and port numbers will be printed in numeric format.  By default, the pro-
#gram will try to display them as host names, network names, or services (whenever applicable).
		-n|--numeric)				#Numeric output
			CHAINRULE="$CHAINRULE $F1"
			#NATSPEC="$NATSPEC -n"
			NEXT='' ; NEGATE=''											;;

#-o, --output [maxsize]
#Copy matching packets to the userspace device.  This is currently mainly for  developers  who  want  to
#play  with  firewalling  effects  in userspace.  The optional maxsize argument can be used to limit the
#maximum number of bytes from the packet which are to be copied.  This option is only valid if the  ker-
#nel has been compiled with CONFIG_IP_FIREWALL_NETLINK set.
#FIXME - can this be replaced with -j QUEUE somehow?
		-o|--output)				#Copy packets to userspace device
			#CHAINRULE="$CHAINRULE "
			COMMENT="$COMMENT Removed $F1 "
			#DISABLELINE='# '
			NEXT='MAXSIZE' ; NEGATE=''										;;

#-p, --protocol[!] protocol
#The protocol of the rule or of the packet to check.  The specified protocol can be  one  of  tcp,  udp,
#icmp,  or  all,  or  it can be a numeric value, representing one of these protocols or a different one.
#Also a protocol name from /etc/protocols is allowed.  A "!" argument before the  protocol  inverts  the
#test.   The  number zero is equivalent to all.  Protocol all will match with all protocols and is taken
#as default when this option is omitted.  All may not be used in in combination with the check  command.
		-p|--protocol)				#Protocol (1 or 2 params, handled here)
			addprotoholder
			if [ "z$F1" = "z--protocol" ]; then F1="--proto" ; fi
			case "$F2" in
			"!")	
					#CHAINRULE="$CHAINRULE $F1 $F2 $F3"
					#NATSPEC="$NATSPEC $F1 $F2 $F3"
					PROTOCOL="$F2 $F3"
					#NATBANGWARNING='YES'
					Fshift ; Fshift											;;	#Implicitly handles the case of "! all".  If it's technically possible, _some_ bozo is going to do it.
			0|all)
					Fshift													;;
			[Tt][Cc][Pp])
					#CHAINRULE="$CHAINRULE $F1 $F2"
					#NATSPEC="$NATSPEC $F1 $F2"
					NEEDEDMODULES="$NEEDEDMODULES ipt_tcp"
					PROTOCOL="tcp"
					Fshift													;;
			[Uu][Dd][Pp])
					#CHAINRULE="$CHAINRULE $F1 $F2"
					#NATSPEC="$NATSPEC $F1 $F2"
					NEEDEDMODULES="$NEEDEDMODULES ipt_udp"
					PROTOCOL="udp"
					Fshift													;;
			[Ii][Cc][Mm][Pp])
					#CHAINRULE="$CHAINRULE $F1 $F2"
					#NATSPEC="$NATSPEC $F1 $F2"
					NEEDEDMODULES="$NEEDEDMODULES ipt_icmp"
					PROTOCOL="icmp"
					Fshift													;;
			*)
					#CHAINRULE="$CHAINRULE $F1 $F2"
					#NATSPEC="$NATSPEC $F1 $F2"
					PROTOCOL="$F2"
					Fshift													;;
			esac
			NEXT='' ; NEGATE=''											;;

#-s, --source [!] address[/mask] [!] [port[:port]]
#Source  specification.   Address  can be either a hostname, a network name, or a plain IP address.  The
#mask can be either a network mask or a plain number, specifying the number of 1s at the left  side  of
#the  network  mask.   Thus,  a  mask  of  24 is equivalent to 255.255.255.0.  A "!" argument before the
#address specification inverts the sense of the address.
#The source may include a port specification or ICMP type.  This can either be a service  name,  a  port
#number, a numeric ICMP type, or one of the ICMP type names shown by the command
#ipchains -h icmp Note that many of these ICMP names refer to both a type and code, meaning that an ICMP
#code after the -d flag is illegal.  In the rest of this paragraph, a port means either a port  specifi-
#cation  or  an ICMP type.  An inclusive range is can also be specified, using the format port:port.  If
#the first port is omitted, "0" is assumed; if the last is omitted, "65535" is assumed.
#Ports may only be specified in combination with the tcp, udp, or icmp protocols.  A "!" before the port
#specification  inverts  the  sense.  When the check command is specified, exactly one port is required,
#and if the -f (fragment) flag is specified, no ports are allowed.  The  flag  --src  is  a  convenience
#alias for this option.
		-s|--source|--src)			#Specify packet source (1 - 4 params, portspec must be stripped off, needs NEXT support)
			if [ "z$F2" = "z!" ]; then
				CHAINRULE="$CHAINRULE $F1 $F2 $F3"
				#NATSPEC="$NATSPEC -s $F2 $F3"
				#NATBANGWARNING='YES'
				Fshift ; Fshift
			#elif [ "z$F2" = "z0/0" ]; then	#No need to add -s 0/0 anymore, but it doesn't hurt to leave it there
			#	Fshift
			else
				CHAINRULE="$CHAINRULE $F1 $F2"
				#NATSPEC="$NATSPEC -s $F2"
				SRCIP='' ; DESTIP=''
				SRCIP="$F2"
				Fshift
			fi
			NEXT='sport' ; NEGATE=''								;;

#-t, --TOS andmask xormask
#Masks used for modifying the TOS field in the IP header.  When a packet matches a rule, its  TOS  field
#is  first  bitwise anded with first mask and the result of this will be bitwise xored with the second
#mask.  The masks should be specified as hexadecimal 8-bit values.  As the LSB of the TOS field must  be
#unaltered  (RFC  1349),  TOS  values  which would cause it to be altered are rejected, as are any rules
#which always set more than TOS bit.  Rules which might set multiple TOS bits for certain packets result
#in  warnings  (sent to stdout) which can be ignored if you know that packets with those TOS values will
#never reach that rule.   Obviously, manipulating the TOS is a meaningless gesture if the rules  target
#is DENY or REJECT.
		-t|--TOS)					#Set TOS masks
			COMMENT="$COMMENT $F1 $F2 $F3 Removed."
			Fshift ; Fshift
			NEXT='' ; NEGATE=''											;;

#Verbose  output.   This  option makes the list command show the interface address, the rule options (if
#any), and the TOS masks.  The packet and byte counters are also listed, with the suffix 'K', 'M' or 'G'
#for  1000,  1,000,000  and 1,000,000,000 multipliers respectively (but see the -x flag to change this).
#When used in combination with -M, information related to delta sequence numbers will  also  be  listed.
#For  appending,  insertion,  deletion  and replacement, this causes detailed information on the rule or
#rules to be printed.
		-v|--verbose)				#Extended/verbose output (0 params)
			CHAINRULE="$CHAINRULE $F1"
			NEXT='' ; NEGATE=''											;;

#Expand  numbers.   Display the exact value of the packet and byte counters, instead of only the rounded
#number in Ks (multiples of 1000) Ms (multiples of 1000K) or Gs (multiples of 1000M).  This option is
#only relevent for the -L command.
		-x|--exact)							#Expand numbers
			CHAINRULE="$CHAINRULE $F1"
			NEXT='' ; NEGATE=''											;;

#[!] -y, --syn
#Only match TCP packets with the SYN bit set and the ACK and FIN bits cleared.  Such packets are used to
#request TCP connection initiation; for example, blocking such packets coming in an interface will  pre-
#vent  incoming  TCP  connections, but outgoing TCP connections will be unaffected.  This option is only
#meaningful when the protocol type is set to TCP.  If the "!" flag precedes the "-y", the sense  of  the
#option is inverted.
		-y|--syn)					#Syn flag set and ack cleared (0 params, NEGATABLE)
			addprotoholder
			CHAINRULE="$CHAINRULE$NEGATE --syn"
			NEEDEDMODULES="$NEEDEDMODULES ipt_tcp"
			NEXT='' ; NEGATE=''											;;

#--destination-port [!] [port[:port]]
#This allows separate specifiction of the ports.  See the description of the -s flag for  details.   The
#flag --dport is an alias for this option.
		--destination-port|--dport)	#Destination port (1-2 params, all handled here)
			addprotoholder
			DESTPARAM="$F1"
			CHAINRULE="$CHAINRULE ZZDESTPARAMZZ ZZDESTSPECZZ"
			#NATSPEC="$NATSPEC ZZDESTPARAMZZ ZZDESTSPECZZ"
			if [ "z$F2" = "z!" ]; then
				DESTSPEC="$F2 $F3"
				#NATBANGWARNING='YES'
				Fshift ; Fshift
			else
				DESTSPEC="$F2"
				Fshift
			fi
			NEXT='' ; NEGATE=''											;;

#--icmp-type [!] typename
#This allows specification of the ICMP type (use the -h icmp option to see valid ICMP type names).  This
#is often more convenient to appending it to the destination specification.
		--icmp-type)				#icmp type
			addprotoholder
			if [ "z$F2" = "z!" ]; then
				CHAINRULE="$CHAINRULE $F1 $F2 $F3" ; Fshift ; Fshift
			else
				CHAINRULE="$CHAINRULE $F1 $F2" ; Fshift
			fi
			NEEDEDMODULES="$NEEDEDMODULES ipt_icmp"
			NEXT='' ; NEGATE=''											;;

#--source-port [!] [port[:port]]
#This allows separate specifiction of the source port or port range.  See the description of the -s flag
#above for details.The flag --sport is an alias for this option.
		--source-port|--sport)		#Source port (1-2 params, all handled here)
			addprotoholder
			SOURCEPARAM="$F1"
			CHAINRULE="$CHAINRULE ZZSOURCEPARAMZZ ZZSOURCESPECZZ"
			#NATSPEC="$NATSPEC ZZSOURCEPARAMZZ ZZSOURCESPECZZ"
			if [ "z$F2" = "z!" ]; then
				SOURCESPEC="$F2 $F3"
				#NATBANGWARNING='YES'
				Fshift ; Fshift
			else
				SOURCESPEC="$F2"
				Fshift
			fi
			NEXT='' ; NEGATE=''											;;

		\#*)	#Append comments verbatim.
			while [ -n "$F1" ]; do
				CHAINRULE="$CHAINRULE $F1"
				Fshift
			done														;;
		*)
			case "$NEXT" in		#FIXME - should we be clearing NEXT below, especially on APPEND?
			'APPEND')	#Just a generic parameter that needs to be appended.
				CHAINRULE="$CHAINRULE$NEGATE $F1"
				NEXT='' ; NEGATE=''											;;
			'CHAIN')
				CHAIN="$F2"
				CHAINRULE="$CHAINRULE ZZCHAINZZ" ; NEXT='' ; NEGATE=''		;;
			'MAXSIZE')	#-o's maxsize.
				COMMENT="$COMMENT $F1."
				NEXT='' ; NEGATE=''											;;
			'REDIRPORT')
				REDIRPORT="$F1"
				COMMENT="$COMMENT $F1."
				NEXT='' ; NEGATE=''											;;
#ipfwadm->ipchains needed support for expanding multiple port specifications into multiple rules; ipchains->iptables doesn't.
			dport)
				addprotoholder
				DESTPARAM="--dport"
				CHAINRULE="$CHAINRULE ZZDESTPARAMZZ ZZDESTSPECZZ"
				#NATSPEC="$NATSPEC ZZDESTPARAMZZ ZZDESTSPECZZ"
				if [ -n "$NEGATE" ]; then
					DESTSPEC="$NEGATE $F1"
					#NATBANGWARNING='YES'
				else
					DESTSPEC="$F1"
				fi
				NEXT='' ; NEGATE=''											;;
			sport)
				addprotoholder
				SOURCEPARAM="--sport"
				CHAINRULE="$CHAINRULE ZZSOURCEPARAMZZ ZZSOURCESPECZZ"
				#NATSPEC="$NATSPEC ZZSOURCEPARAMZZ ZZSOURCESPECZZ"
				if [ -n "$NEGATE" ]; then
					SOURCESPEC="$NEGATE $F1"
					#NATBANGWARNING='YES'
				else
					SOURCESPEC="$F1"
				fi
				NEXT='' ; NEGATE=''											;;
			*)	#Just return the field - we don't know what to do.
				CHAINRULE="$CHAINRULE$NEGATE $F1"
				NEXT='' ; NEGATE=''											;;
			esac
		esac
		Fshift
	done

#---------- Chain and interface conversion logic ----------
#If IFSPEC unset, do not set it but suggest.
#If CHAIN unset, no problem; there will be no ZZCHAINZZ placeholder so the variable will be ignored
#Missing src or destip handled by islocalip / suggest.

#Hmmm... This is my best read on the way to convert the rules:
#   --------Given--------,  ----------Set---------------- 
#   |                   |   |                           |
#	SRCIP	DESTIP	CHAIN	NEW CHAIN		NEW INTERFACE
#	(any)	(any)	forward	FORWARD			-o $IFSPEC (suggest -i if-of-src-ip) (never a local src or local dest ip)
#	local	local	input	INPUT			-i $IFSPEC (probably lo)
#	local	local	output	OUTPUT			-o $IFSPEC (probably lo)
#	local	local	user	(leave as is)		-i $IFSPEC or -o $IFSPEC (probably lo)
#	local	not	(any)	OUTPUT			-o $IFSPEC (never an ipchains input rule, just output or user)
#	not	local	(any)	INPUT			-i $IFSPEC (never an ipchains output rule, just input or user)
#	not	not	input	FORWARD			-i $IFSPEC (suggest -o if-of-dest-ip)
#	not	not	output	FORWARD			-o $IFSPEC (suggest -i if-of-src-ip)
#	not	not	user	FORWARD			(suggest -i if-of-src-ip -o if-of-dest-ip)
#	$SRCIP	$DESTIP	$CHAIN	CHAIN=			IFSPEC=


	case $CHAIN in
	input)		CHAIN='INPUT'	;;
	output)		CHAIN='OUTPUT'	;;
	forward)	CHAIN='FORWARD'	;;
	esac

	if [ "z$CHAIN" = "zFORWARD" ]; then #----Rule is already a forward rule----
		if [ -n "$IFSPEC" ]; then IFSPEC="-o $IFSPEC" ; else suggestif "-o" "$DESTIP" ; fi
		suggestif "-i" "$SRCIP"
	elif islocalip $SRCIP ; then
		if islocalip $DESTIP ; then #----Both SRCIP and DESTIP local----
			case $CHAIN in
			INPUT)
				CHAIN="INPUT"
				if [ -n "$IFSPEC" ]; then IFSPEC="-i $IFSPEC" ; else suggestif "-i" "$SRCIP" "lo" ; fi		;;
			OUTPUT)
				CHAIN="OUTPUT"
				if [ -n "$IFSPEC" ]; then IFSPEC="-o $IFSPEC" ; else suggestif "-o" "$DESTIP" "lo" ; fi		;;
			*)
				if [ -n "$IFSPEC" ]; then
					IFSPEC="-i $IFSPEC"
					COMMENT="$COMMENT \"-i $IFSPEC\" may need to be \"-o $IFSPEC\"."
				else
					suggestif "-i" "$SRCIP" ; suggestif "-o" "$DESTIP"
				fi																							;;
			esac
		else #----Only SRCIP local----
			CHAIN="OUTPUT"
			if [ -n "$IFSPEC" ]; then IFSPEC="-o $IFSPEC" ; else suggestif "-o" "$DESTIP" ; fi
		fi
	else #----SRCIP is not local----
		if islocalip $DESTIP ; then #Only DESTIP local
			CHAIN="INPUT"
			if [ -n "$IFSPEC" ]; then IFSPEC="-i $IFSPEC" ; else suggestif "-i" "$SRCIP" ; fi
		else #----Neither SRCIP nor DESTIP local----
			case $CHAIN in
			INPUT)
				CHAIN="FORWARD"
				if [ -n "$IFSPEC" ]; then IFSPEC="-i $IFSPEC" ; else suggestif "-i" "$SRCIP" ; fi
				suggestif "-o" "$DESTIP"																	;;
			OUTPUT)
				CHAIN="FORWARD"
				if [ -n "$IFSPEC" ]; then IFSPEC="-o $IFSPEC" ; else suggestif "-o" "$DESTIP" ; fi
				suggestif "-i" "$SRCIP"																		;;
			*)
				CHAIN="FORWARD"
				suggestif "-i" "$SRCIP" ; suggestif "-o" "$DESTIP"
				if [ -n "$IFSPEC" ]; then
					COMMENT="$COMMENT Originally \"-i $IFSPEC\"."
					IFSPEC=""
				fi																							;;
			esac
		fi
	fi

	case $PROTOCOL in				#iptables can't use --sport for icmp.
	[Ii][Cc][Mm][Pp])
		SOURCEPARAM="--icmp-type"
		DESTPARAM=""
		if [ -n "$DESTSPEC" ]; then
			SOURCESPEC="$SOURCESPEC/$DESTSPEC"
			DESTSPEC=""
		fi									;;
	esac


#echo 1 $CHAIN 2 $IFSPEC 3 $PROTOCOL 4 $SOURCEPARAM 5 $SOURCESPEC 6 $DESTPARAM 7 $DESTSPEC

	CHAINRULE=`echo $CHAINRULE | sed -e "s@ZZCHAINZZ@$CHAIN@g" \
					 -e "s@ZZIFSPECZZ@$IFSPEC@g" \
					 -e "s@ZZPROTOZZ@$PROTOCOL@g" \
					 -e "s@ZZSOURCEPARAMZZ@$SOURCEPARAM@g" \
					 -e "s@ZZSOURCESPECZZ@$SOURCESPEC@g" \
					 -e "s@ZZDESTPARAMZZ@$DESTPARAM@g" \
					 -e "s@ZZDESTSPECZZ@$DESTSPEC@g" `
	#NATSPEC=`echo $NATSPEC | sed -e "s@ZZPROTOZZ@$PROTOCOL@g" \
	#				 -e "s@ZZSOURCEPARAMZZ@$SOURCEPARAM@g" \
	#				 -e "s@ZZSOURCESPECZZ@$SOURCESPEC@g" \
	#				 -e "s@ZZDESTPARAMZZ@$DESTPARAM@g" \
	#				 -e "s@ZZDESTSPECZZ@$DESTSPEC@g" `

	if [ -n "$COMMENT" ]; then CHAINRULE="$CHAINRULE ###$COMMENT" ; fi

#Output the rule.  ipchains only allows a single portspec so we don't need to handle looping through multiple source and dest ports.

	if [ "z$LOGME" = "zYES" ]; then
		if [ -z "`echo $CHAINRULE | grep ' -j '`" ]; then
			echo "$DISABLELINE$CHAINRULE -j LOG"
		else
			echo "$DISABLELINE$CHAINRULE" | sed -e 's/ -j [^ ]*/ -j LOG/'
		fi
	fi
	if [ "z$MASQME" = "zYES" ]; then
		#echo $IPNATCTLBIN -I $NATSPEC -b source -m masquerade
		echo "$DISABLELINE$CHAINRULE" | sed -e "s@$IPTABLESBIN @$IPTABLESBIN -A POSTROUTING -t nat @"
	else
		echo "$DISABLELINE$CHAINRULE"
	fi

	if [ "z$BIDIRECTIONAL" = "zYES" ]; then	#Probably not a good choice with --syn, but hey, if it worked for them in ipchains...
#-d|--destination|--dst		<-> -s|--source|--src
#--destination-port|--dport	<-> --source-port|--sport
#-i|--interface			<-> -o, --out-interface
		CHAINRULE=`echo "$CHAINRULE" | \
		sed \
			-e 's/ -d / ZZHOLDZZ /'			-e 's/ -s / -d /'				-e 's/ ZZHOLDZZ / -s /' \
			-e 's/ --destination / ZZHOLDZZ /'	-e 's/ --source / --destination /'		-e 's/ ZZHOLDZZ / --source /' \
			-e 's/ --dst / ZZHOLDZZ /'		-e 's/ --src / --dst /'				-e 's/ ZZHOLDZZ / --src /' \
			-e 's/ --destination-port / ZZHOLDZZ /'	-e 's/ --source-port / --destination-port /'	-e 's/ ZZHOLDZZ / --source-port /' \
			-e 's/ --dport / ZZHOLDZZ /'		-e 's/ --sport / --dport /'			-e 's/ ZZHOLDZZ / --sport /' \
			-e 's/ -i / ZZHOLDZZ /'			-e 's/ -o / -i /'				-e 's/ ZZHOLDZZ / -o /' \
			-e 's/ --interface / ZZHOLDZZ /'	-e 's/ --out-interface / --interface /'		-e 's/ ZZHOLDZZ / --out-interface /'`
		#NATSPEC=`echo "$NATSPEC" | \
		#sed \
		#	-e 's/ -d / ZZHOLDZZ /'			-e 's/ -s / -d /'				-e 's/ ZZHOLDZZ / -s /' \
		#	-e 's/ --destination / ZZHOLDZZ /'	-e 's/ --source / --destination /'		-e 's/ ZZHOLDZZ / --source /' \
		#	-e 's/ --dst / ZZHOLDZZ /'		-e 's/ --src / --dst /'				-e 's/ ZZHOLDZZ / --src /' \
		#	-e 's/ --destination-port / ZZHOLDZZ /'	-e 's/ --source-port / --destination-port /'	-e 's/ ZZHOLDZZ / --source-port /' \
		#	-e 's/ --dport / ZZHOLDZZ /'		-e 's/ --sport / --dport /'			-e 's/ ZZHOLDZZ / --sport /'`
		if [ "z$LOGME" = "zYES" ]; then
			if [ -z "`echo $CHAINRULE | grep ' -j '`" ]; then
				echo "$DISABLELINE$CHAINRULE -j LOG"
			else
				echo "$DISABLELINE$CHAINRULE" | sed -e 's/ -j [^ ]*/ -j LOG/'
			fi
		fi
		if [ "z$MASQME" = "zYES" ]; then		#Bidirectional masq?  Aughhhhhhhhh!
			#echo $IPNATCTLBIN -I $NATSPEC -b source -m masquerade
			echo "$DISABLELINE$CHAINRULE" | sed -e "s@$IPTABLESBIN @$IPTABLESBIN -A POSTROUTING -t nat @"
		else
			echo "$DISABLELINE$CHAINRULE"
		fi
	fi

	COMMENT='' DISABLELINE=''
	BIDIRECTIONAL=''
	CHAINRULE='' ; NEXT=''
	REDIR='' ; REDIRPORT=''
	NEGATE=''
	CHAIN=''
	LOGME=''
	MASQME=''
	#NATSPEC=''
	SRCIP='' ; DESTIP=''
	IFSPEC=''
	PROTOCOL=''
	SOURCEPARAM='' ; SOURCESPEC='' ; DESTPARAM='' ; DESTSPEC=''
done

if [ -n "$NEEDEDMODULES" ]; then
	echo '#The following modules may be needed - insert by hand if not autoloaded:'
	echo "$NEEDEDMODULES" | tr ' ' '\012' | sort | uniq | grep -v '^$' | sed -e 's/^/#/'
fi

#if [ "z$NATBANGWARNING" = "zYES" ]; then
#	echo '#One or more of the above ipnatctl rules has an exclamation point in it'
#	echo '#which, in iptables, negates the specification.  At this time, though,'
#	echo '#ipnatctl does not support negated specifications.  Please fix.'
#fi



#---------- Graveyard: ----------

#Global Initialize:
#ACCOUNTINGPREPARED=''

#Function:
#SetupAccounting () {
#	if [ "z$ACCOUNTINGPREPARED" != 'zYES' ]; then
#		echo \#The following block may be used to initialize the 
#		echo \#Accounting chains that must be explicitly prepared 
#		echo \#in ipchains.  The lines starting with \"/sbin/ipchains\" 
#		echo \#should be uncommented and a single
#		echo \#copy of the block placed at the top of your firewall.
#		echo \#/sbin/ipchains -N acctin
#		echo \#/sbin/ipchains -N acctout
#		echo \#/sbin/ipchains -N acctio
#		echo \#/sbin/ipchains -I input 1 -j acctio
#		echo \#/sbin/ipchains -I input 1 -j acctin
#		echo \#/sbin/ipchains -I output 1 -j acctio
#		echo \#/sbin/ipchains -I output 1 -j acctout
#		ACCOUNTINGPREPARED='YES'
#	fi
#}

#Per line initialize:
#ACCTDIR='both'
#SOURCEPORT='' ; DESTPORT=''
#MASQ=''

#ipfwadm options:
#		-A)	#Create an accounting rule
#			SetupAccounting
#			CHAINRULE="$CHAINRULE -A ZZACCTDIRZZ"
#			NEXT='ACCTDIR'												;;
#		-F)	#Forwarding rule
#			CHAIN='forward'
#			NEXT=''														;;
#		-I)	#Input rule
#			CHAIN='input'
#			NEXT=''														;;
#		-O)	#Output rule
#			CHAIN='output'
#			NEXT=''														;;
#		-V)	#Use this IP address; convert to an IF name.
#			HOSTIP="$F2"
#			IFNAME=`ifconfig | grep -B 1 "inet addr:$HOSTIP" | head -1 | awk '{print $1}'`
#			if [ -z "$IFNAME" ]; then
#				HOSTIP=`host -t a $F2 2>/dev/null | grep 'has address' | head -1 | awk '{print $4}'`
#				if [ -n "$HOSTIP" ]; then
#					IFNAME=`ifconfig | grep -B 1 "inet addr:$HOSTIP" | head -1 | awk '{print $1}'`
#				else
#					echo Unable to find the interface name for $F2 . >/dev/stderr
#					echo Please convert it by hand. >/dev/stderr
#					IFNAME="interface_name_for_${F2}"
#				fi
#			fi
#			CHAINRULE="$CHAINRULE -i $IFNAME" ; Fshift
#			NEXT='' ; IFNAME='' ; HOSTIP=''								;;
#		-m)	#Masquerade this traffic
#			MASQ='YES' ; NEXT=''										;;

#Next fields:
#			case "$NEXT" in
#			'ACCTDIR')
#				ACCTDIR="$F1" ; NEXT=''										;;
#			"POLICY")
#				POLICY=`echo $F1 | tr a-z A-Z`
#				case "$POLICY" in
#				A*)		POLICY="ACCEPT"											;;
#				D*)		POLICY="DENY"											;;
#				M*)		POLICY="MASQ"											;;
#				R*)		POLICY="REJECT"											;;
#				esac
#				NEXT='' ; NEGATE=''											;;

#Pre-output processing:
#Replace Policy and Chain placeholders
#	if [ "z$REDIR" = "zYES" ]; then
#		if [ -n "$REDIRPORT" ]; then
#			POLICY="REDIRECT $REDIRPORT"
#		else
#			POLICY="REDIRECT"
#		fi
#	fi
#	CHAINRULE=`echo $CHAINRULE | sed -e "s/ZZPOLICYZZ/$POLICY/g" \
#	 -e "s/ZZCHAINZZ/$CHAIN/g"`
#	case "$ACCTDIR" in
#	'in')
#		CHAINRULE=`echo $CHAINRULE | sed -e "s/ZZACCTDIRZZ/acctin/g"`	;;
#	'out')
#		CHAINRULE=`echo $CHAINRULE | sed -e "s/ZZACCTDIRZZ/acctout/g"`	;;
#	'both'|''|*)
#		CHAINRULE=`echo $CHAINRULE | sed -e "s/ZZACCTDIRZZ/acctio/g"`	;;
#	esac
#	if [ "z$MASQ" = "zYES" ]; then
#		POLICY="MASQ"
#	fi

#Output with looping through portspecs:
#	if [ -z "$SOURCEPORT" ] && [ -z "$DESTPORT" ]; then	#No src/dest ports specified
#		echo $CHAINRULE
#	elif [ -n "$SOURCEPORT" ] && [ -z "$DESTPORT" ]; then #>=1 src port, no dest ports
#		for ONESOURCE in $SOURCEPORT ; do
#			echo $CHAINRULE | sed -e "s/ZZSOURCEPORTZZ/$ONESOURCE/g"
#		done
#	elif [ -z "$SOURCEPORT" ] && [ -n "$DESTPORT" ]; then #no src ports, >=1 dest port
#		for ONEDEST in $DESTPORT ; do
#			echo $CHAINRULE | sed -e "s/ZZDESTPORTZZ/$ONEDEST/g"
#		done
#	else	#>=1 src port and >=1 dest port
#		for ONESOURCE in $SOURCEPORT ; do
#			for ONEDEST in $DESTPORT ; do
#				echo $CHAINRULE | sed -e "s/ZZSOURCEPORTZZ/$ONESOURCE/g" -e "s/ZZDESTPORTZZ/$ONEDEST/g"
#			done
#		done
#	fi