#!/bin/bash #Copyright 2001 William Stearns #GPL'd. #This converts any input snort rules to iptables rules. #asterisks added in any content rules referenced in the code to avoid tripping snort... :-) Debug () { echo "$*" >/dev/stderr } Failed () { #Record fact that conversion failed because of a feature in snort missing in iptables. FailedReasons="$FailedReasons $1" } StripOptionName () { echo "$*" | sed -e 's/^[A-Za-z]*://' -e 's/^ //' } ToAscii () { Input="$1" Tail="$Input" Output='' Hex='' while [ -n "$Tail" ]; do if [ -z "$Hex" ]; then #Strip ascii character and glue onto output, or | to switch us to hex. Head=`echo "$Tail" | sed -e 's/^\(.\).*/\1/'` Tail=`echo "$Tail" | sed -e 's/^.//'` if [ "$Head" = "|" ]; then Hex="y" else Output="$Output$Head" fi else #Strip first hex digit, space, or | to switch us back to ascii Head=`echo "$Tail" | sed -e 's/^\(.\).*/\1/'` Tail=`echo "$Tail" | sed -e 's/^.//'` if [ "$Head" = "|" ]; then Hex='' elif [ "$Head" = " " ]; then : elif [ "$Head" = '"' ]; then #Test code to handle trailing " when | was misinterpreted : else #We already have the first hex digit, grab the second. Head2=`echo "$Tail" | sed -e 's/^\(.\).*/\1/'` Tail=`echo "$Tail" | sed -e 's/^.//'` while [ "$Head2" = " " ]; do #Debug "X space second char in X$Input" Head2=`echo "$Tail" | sed -e 's/^\(.\).*/\1/'` Tail=`echo "$Tail" | sed -e 's/^.//'` done #$, `, ", \, and are treated specially in double quotes. # #The reason for the \\\" is that we need to provide enough quoting that the string can be #reprocessed by the shell into the final iptables command. # \\\" is interpreted as \\ (a \) and \" (a "), resulting in a \" in the #iptables command line. When that command line is processed, it will see the \" #and (hopefully) stuff " into the string to be matched in the kernel. # *fingers crossed* Head=$Head$Head2 case $Head in 00) #Null Failed "0x00 in $Input" #Output="$Output"`echo -e "\x$Head"` #No output at all. ;; 01) Failed "0x01 in $Input" #Output="$Output"`echo -e "\x$Head"` #No output at all. ;; 0[2-9B-Fb-f]|1[0-9A-Fa-f]) #Low control characters Output="$Output"`echo -e "\x$Head"` ;; 0[Aa]) #Newline #Output="$Output"'\\'`echo -e "\x0A"` #We get the \, but no lf. Failed "0x0A in $Input" ;; 2[0356A-Fa-f]|3[0-9A-Fa-f]|4[0-9A-Fa-f]|5[0-9ABDEFabdef]|6[1-9A-Fa-f]|7[0-9A-Ea-e]) #Few if any problems in printing. Output="$Output"`echo -e "\x$Head"` ;; 21) # ! Failed "0x21 in $Input" #Output="$Output\\\!" #Gives extra \ #Output="$Output"'!' #when iptables run, bash interprets the ! ;; 22) # " Output="$Output\\\"" ;; 27) # ' #Output="$Output\\\'" #Gives extra \ #Output="$Output\'" #Gives extra \ Output="$Output'" #Fine ;; 28) # ( #Output="$Output\\(" #Gives extra \ Output="$Output(" #Fine ;; 29) # ) #Output="$Output\\\)" #Gives extra \ #Output="$Output\)" #Gives extra \ Output="$Output)" #Fine ;; 24) #$ Output="$Output"'\$' ;; 5[Cc]) #\ Output="$Output"'\\' ;; 60) # ` #Output="$Output"'\\\`' #Gives extra \ Output="$Output"'\`' #Fine ;; 7[Ff]) #Del Failed "0x7f in $Input" #Output="$Output"`echo -e "\x$Head"` ;; [89A-Fa-f][0-9A-Fa-f]) #High extended ascii (drawing, etc.) characters. Output="$Output"`echo -e "\x$Head"` ;; *) Debug "Unhandled character <$Head> in $Input" #Debug "Conv$Head" ;; esac fi fi done echo "$Output" # echo >/dev/stderr } #ToAscii regression test if /bin/false ; then error () { echo Test $1 failed } if [ ! "`ToAscii "Abc"`" = "Abc" ]; then error ToAscii-1 ; fi if [ ! "`ToAscii "|20|"`" = " " ]; then error ToAscii-2 ; fi if [ ! "`ToAscii "Abc|20|Def"`" = "Abc Def" ]; then error ToAscii-3 ; fi if [ ! "`ToAscii "|20|Abc|20|"`" = " Abc " ]; then error ToAscii-4 ; fi if [ ! "`ToAscii "| 20 |Abc| 20 |"`" = " Abc " ]; then error ToAscii-5 ; fi if [ ! "`ToAscii "| 2 0 2 0 |"`" = " " ]; then error ToAscii-6 ; fi if [ ! "`ToAscii "a||b||||c||||||d"`" = "abcd" ]; then error ToAscii-7 ; fi if [ ! "`ToAscii "a|||20|||b"`" = "a b" ]; then error ToAscii-8 ; fi if [ ! "`ToAscii "|6E 61 6D 65 20 3D 22 70 69 63 73 34 79 6F 75 2E 65 78 65 22|"`" = "name =\\\"pics4you.exe\\\"" ]; then error ToAscii-9 ; fi if [ ! "`ToAscii "|66 69 63 6B 65 6E|"`" = "ficken" ]; then error ToAscii-10 ; fi #if [ ! "`ToAscii ""`" = "" ]; then error ToAscii-x ; fi fi ProcessPrimaryFields () { PrimaryParams="" #$1: alert, config, include, preprocessor, var case "$1" in "") : #Ignore null line ;; alert) #Debug Primary: "$*" #$2: tcp, udp, icmp, ip, *.rules case "$2" in ip) if [ "$4" != "any" ] || [ "$7" != "any" ]; then Debug IP protocol with source port "$4" and dest port "$7" fi ;; tcp|TCP) PrimaryParams="$PrimaryParams -p tcp" ;; udp|UDP) PrimaryParams="$PrimaryParams -p udp" ;; icmp|ICMP) if [ "$4" != "any" ] || [ "$7" != "any" ]; then Debug ICMP protocol with source port "$4" and dest port "$7" fi PrimaryParams="$PrimaryParams -p icmp" ;; *) Debug unrecognized protocol "$2" ;; esac #$5: -> <- <> #calling routine handles '<>', this function handles '<-' or '->' case "$5" in -\>) LeftDir="s" RightDir="d" ;; \<-) LeftDir="d" RightDir="s" ;; *) Failed "Unhandled direction $5" ;; esac #$3: netvars, any if [ "$3" != "any" ]; then PrimaryParams="$PrimaryParams -$LeftDir $3" fi #$4: ports, any (port ranges a:b , a: ) #iptables takes a:, :b quite well. if [ "$4" != "any" ]; then PrimaryParams="$PrimaryParams --${LeftDir}port $(echo "$4" | sed 's/!/! /')" fi #$6: netvars, ips, any if [ "$6" != "any" ]; then PrimaryParams="$PrimaryParams -$RightDir $6" fi #$7: port a:b a: !a:b :b any if [ "$7" != "any" ]; then PrimaryParams="$PrimaryParams --${RightDir}port $(echo "$7" | sed 's/!/! /')" fi ;; config) : #Debug Skipping classification ;; include) Debug 'Um, why did I get an include line?' ;; preprocessor) Debug 'Um, why did I get a preprocessor line?' ;; var) Debug 'Um, why did I get a var line?' ;; *) Failed "Unknown line starting with $*" ;; esac #PrimaryParams is passed back as a global variable } ProcessSecondaryFields () { SecondaryParams="" Comment="" LogString="" DashMStringLoaded="" #Glue "itype: mmm; icode: nnn;" together into itype: mmm/nnn; AllSecondary=`echo "$*" | sed -e 's@\(itype:[ ]*[0-9]*\)[ ]*;[ ]*icode:[ ]*\([0-9]*;\)@\1/\2@'` HeadField=`echo "$AllSecondary" | sed -e 's/;.*//' -e 's/^ //'` AllSecondary=`echo "$AllSecondary" | sed -e 's/[^;]*;//'` while [ -n "$HeadField" ]; do HeadValue=$(StripOptionName $HeadField) case "$HeadField" in \)) #FIXME : Failed 'Stray right parentheses.' ;; ack:*) #ack: 0 #ack: 101058054 #ack:0 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/ack Failed "$HeadField" ;; classtype:*) #classtype: attempted-admin #classtype: attempted-dos #classtype: successful-admin #classtype:attempted-admin #classtype:attempted-dos #classtype:attempted-recon #classtype:attempted-user #classtype:bad-unknown #classtype:not-suspicious #classtype:unknown #classtype:unsuccessful-user #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/classtype Comment="$Comment $HeadField" ;; content:*) #FIXME #alert tcp any 110 -> any any (msg:"Virus - Possible PrettyPark Trojan"; content:"\\C*o*o*l*P*r*o*g*s\\";offset:300;depth:750; reference:MCAFEE,10175; sid:772; rev:1;) #gives #iptables -A SnortRules -p tcp --sport 110 -m string --string CoolProgs"' -j DROP #Try `iptables -h' or 'iptables --help' for more information. #Bad argument `-' #FIXME #alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS 80 (msg:"WEB-MISC http directory traversal"; flags: A+; content: ".*.*\*\";reference:arachnids,298; classtype:attempted-recon; sid:1112; rev:1;) #gives #iptables -A SnortRules -p tcp -s 0/0 -d 0/0 --dport 80 --tcp-flags ACK ACK -m string --string .."' -j DROP #Try `iptables -h' or 'iptables --help' for more information. #Bad argument `http' #FIXME #alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS 80 (msg:"WEB-MISC ads.cgi command execution attempt"; flags:A+; uricontent:"/a*d*s*.*c*g*i"; nocase; conten #t:"f*i*l*e*="; nocase; content:"../../"; content:"\*|"; reference:cve,CAN-2001-0025; reference:bugtraq,2103; classtype:web-application-attack; sid:1053 #; rev:3;) #gives #--string " #and #Unhandled character " #content: "..." #content:"..." # | toggles to and from hex. #Ignore embedded spaces in hex strings. #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/content if [ -z "$DashMStringLoaded" ]; then SecondaryParams="$SecondaryParams -m string" DashMStringLoaded="Yes" fi if `echo $HeadValue | grep -q '|'`; then #Failed "$HeadField" SecondaryParams="$SecondaryParams --string "`ToAscii "$HeadValue"` else #Ce n'est pas un pipe... :-) SecondaryParams="$SecondaryParams --string $HeadValue" fi ;; depth:*) #depth: nnn #depth:nnn #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/depth : #We won't care about depth on the assumption that this is an optimization. ;; dsize:*) #dsize: nnn or > nnn or < nnn #dsize:nnn or > nnn or < nnn #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/dsize #Failed "$HeadField" #Doesn't appear to be an iptables equivalent # #There's an iptables equivalent module; if it's not in the iptables #CVS at the time your read this (http://netfilter.samba.org), get it #at http://www.stearns.org/ipt_dsize/ case "$HeadValue" in \>65535|\>\ 65535) Failed "Illegal dsize >65535" ;; \>*) SecondaryParams="$SecondaryParams -m dsize --dsize $[ $(echo "$HeadValue" | sed -e 's/>//') + 1 ]:" ;; \<0|\<\ 0) Failed "Illegal dsize <0" ;; \<*) SecondaryParams="$SecondaryParams -m dsize --dsize :$[ $(echo "$HeadValue" | sed -e 's/>/usr/src/snort2iptables-work/fields/flags FlagA='' ; FlagF='' ; FlagP='' ; FlagS='' ; FlagR='' ; FlagU='' ; Flag1='' ; Flag2='' ; FlagPlus='' HeadByte=`echo "$HeadValue" | sed -e 's/^\(.\).*/\1/'` HeadValue=`echo "$HeadValue" | sed -e 's/^.//'` while [ -n "$HeadByte" ]; do case "$HeadByte" in 0) FlagA='' ; FlagF='' ; FlagP='' ; FlagS='' ; FlagR='' ; FlagU='' ; Flag1='' ; Flag2='' ; FlagPlus='' ;; A|a) FlagA="ACK" ;; F|f) FlagF="FIN" ;; P|p) FlagP="PSH" ;; S|s) FlagS="SYN" ;; R|r) FlagR="RST" ;; U|u) FlagU="URG" ;; 1) Failed Flag1 #Flag1="ZZ" ;; 2) Failed Flag2 #Flag2="ZZ" ;; +) FlagPlus="Yes" ;; *) Debug Invalid HeadByte in flags: "$HeadByte" ;; esac HeadByte=`echo "$HeadValue" | sed -e 's/^\(.\).*/\1/'` HeadValue=`echo "$HeadValue" | sed -e 's/^.//'` done #$FlagA $FlagF $FlagP $FlagS $FlagR $FlagU $Flag1 $Flag2 if [ -n "$FlagA$FlagF$FlagP$FlagS$FlagR$FlagU$Flag1$Flag2" ]; then AllFlags="" for OneFlag in $FlagA $FlagF $FlagP $FlagS $FlagR $FlagU $Flag1 $Flag2 ; do if [ -z "$AllFlags" ]; then AllFlags="$OneFlag" else AllFlags="$AllFlags,$OneFlag" fi done else AllFlags="NONE" fi if [ "$FlagPlus" = "Yes" ]; then SuperSet="$AllFlags" else SuperSet="ALL" fi if [ "$AllFlags" != "NONE" ] || [ "$SuperSet" != "NONE" ]; then SecondaryParams="$SecondaryParams --tcp-flags $SuperSet $AllFlags" fi ;; fragbits:*) #fragbits: M #fragbits: M+ #fragbits:M #fragbits:R #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/fragbits Failed "$HeadField" ;; icmp_id:*) #icmp_id: 0 #icmp_id: 1000 #icmp_id: 123 #icmp_id: 456 #icmp_id: 51201 #icmp_id: 666 #icmp_id: 666 #icmp_id: 667 #icmp_id: 668 #icmp_id: 669 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/icmp_id Failed "$HeadField" #There does not seem to be a netfilter equivalent. ;; icmp_seq:*) #icmp_seq: 0 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/icmp_seq Failed "$HeadField" ;; icode:*) #As iptables wants these glued together in a single field, the #sed at the top of this function should have glued #"itype: mmm; icode: nnn;" together into itype: mmm/nnn; #icode: 0 #icode: 1 #icode:0 #icode:1 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/icode Failed "$HeadField" ;; id:*) #id: 39426 #id: 413 #id: 666 #id: 678 #id:13170 #id:242 #id:3868 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/id Failed "$HeadField" ;; ip_proto:*) #ip_proto: 2 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/ip_proto SecondaryParams="$SecondaryParams --proto $HeadValue" ;; ipopts:*) #ipopts: rr #ipopts: ssrr #ipopts:lsrr #ipopts:lsrre #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/ipopts case "$HeadValue" in rr) SecondaryParams="$SecondaryParams -m ipv4options --rr" ;; ssrr) SecondaryParams="$SecondaryParams -m ipv4options --ssrr" ;; lsrr) SecondaryParams="$SecondaryParams -m ipv4options --lsrr" ;; lsrre) #What is this? Failed "$HeadField" ;; esac ;; itype:*) #itype:[ ]0-39 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/itype #FIXME #iptables -A SnortRules -p icmp -s 0/0 -d 0/0 -m ttl --ttl-eq 1 -m icmp --icmp-type 8 -j DROP #iptables v1.2.3: Can't specify TTL option twice #FIXME - -m icmp (incorrect removed) -p icmp _not_ put in, on the logic #that -p icmp is probably at the beginning of the line. SecondaryParams="$SecondaryParams --icmp-type $HeadValue" ;; msg:*) #msg:[ ]"..." text description #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/msg Comment="$Comment $HeadValue" ;; nocase) #nocase (verbatim) #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/nocase #FIXME - handle more gracefully if true ; then Comment="$Comment nocase-ignored" else Failed "$HeadField" fi ;; offset:*) #offset:[ ]0-300 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/offset : #We won't care about offset on the assumption that this is an optimization. ;; reference:*) #reference:[ ]ascii, no quotes #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/reference #case "$HeadValue" in #cve*) # if [ -z "$LogString" ]; then # LogString=`echo "$HeadValue" | sed -e 's/cve, /cve-/' -e 's/cve,/cve-/'` # else # LogString="$LogString,"`echo "$HeadValue" | sed -e 's/cve, /cve-/' -e 's/cve,/cve-/'` # fi # ;; #*) Comment="$Comment $HeadValue" # ;; #esac ;; rev:*) #rev:[ ]1-4 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/rev #Don't really care about the revision number. : ;; rpc:*) #rpc: 100000,*,* #rpc:100249,*,* #rpc:391029,*,* #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/rpc Failed "$HeadField" ;; sameip) #sameip (verbatim) #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/sameip Failed "$HeadField" ;; seq:*) #seq: 101058054 #seq: 1958810375 #seq: 3868 #seq: 6060842 #seq: 674711609 #seq:0 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/seq Failed "$HeadField" ;; sid:*) case $HeadValue in 152) Failed "Mishandled quotes" ;; #Possibly fixed; there may still be ordering requirements that #the icmp-type come before ttl. #385) # Failed "Can't specify TTL option twice" # ;; 661) Failed "Mishandled quotes" ;; 688) Failed "Mishandled quotes" ;; 772) Failed "Mishandled quotes" ;; 1112) Failed "Mishandled quotes" ;; #FIXME: sid 1053 has "*\*|*" for content, comes out as unhandled character " 1053) Failed "misconvert on quoted pipe: $HeadField" ;; 1333) Failed "misconvert in content semicolon: $HeadField" ;; #FIXME: sid 1368 has "*/*b*i*n*/*l*s*|*" for content, similar unhandled " 1368) Failed "misconvert in content pipe: $HeadField" ;; esac #sid:[ ]nnnn #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/sid if [ -z "$LogString" ]; then LogString="SID$HeadValue" else LogString="$LogString,SID$HeadValue" fi Comment="$Comment $HeadField" ;; ttl:*) #ttl: >220 #ttl:1 #echo "$HeadField" >>/usr/src/snort2iptables-work/fields/ttl case "$HeadValue" in \>*) SecondaryParams="$SecondaryParams -m ttl --ttl-gt $(echo "$HeadValue" | sed -e 's/>//')" ;; \<*) SecondaryParams="$SecondaryParams -m ttl --ttl-lt $(echo "$HeadValue" | sed -e 's/>/usr/src/snort2iptables-work/fields/uricontent if [ -z "$DashMStringLoaded" ]; then SecondaryParams="$SecondaryParams -m string" DashMStringLoaded="Yes" fi if `echo $HeadValue | grep -q '|'`; then #Failed "$HeadField" SecondaryParams="$SecondaryParams --string "`ToAscii "$HeadValue"` else #Ce n'est pas un pipe... :-) SecondaryParams="$SecondaryParams --string $HeadValue" fi ;; *) if [ -d /usr/src/snort2iptables-work/fields/ ]; then echo "$HeadField" >>/usr/src/snort2iptables-work/fields/newfields fi Failed "$HeadField" ;; esac HeadField=`echo "$AllSecondary" | sed -e 's/;.*//' -e 's/^ //'` AllSecondary=`echo "$AllSecondary" | sed -e 's/[^;]*;//'` done #SecondaryParams is passed back as a global variable } ProcessLine () { #Debug "$*" FailedReasons='' PrimaryFields=`echo "$*" | sed -e 's/ (.*//'` SecondaryFields=`echo "$*" | sed -e 's/[^(]* (//' -e 's/)$//'` PrimaryParams='' SecondaryParams='' ProcessPrimaryFields $PrimaryFields if [ -n "$PrimaryParams" ]; then ProcessSecondaryFields $SecondaryFields fi } OutputRule () { if [ -n "$1$2" ]; then if [ -n "$FailedReasons" ]; then if [ "$DoLog" = "yes" ]; then if [ -n "$LogString" ]; then echo "#iptables -A SnortRules$1$2 -j LOG --log-prefix \" $LogString \" #Cannot convert:$FailedReasons $Comment" else echo "#iptables -A SnortRules$1$2 -j LOG #Cannot convert:$FailedReasons $Comment" fi fi if [ -n "$DoAction" ]; then echo "#iptables -A SnortRules$1$2 -j $DoAction #Cannot convert:$FailedReasons $Comment" fi else if [ "$DoLog" = "yes" ]; then if [ -n "$LogString" ]; then echo "iptables -A SnortRules$1$2 -j LOG --log-prefix \" $LogString \" #$Comment" else echo "iptables -A SnortRules$1$2 -j LOG #$Comment" fi fi if [ -n "$DoAction" ]; then echo "iptables -A SnortRules$1$2 -j $DoAction #$Comment" fi fi fi } ProcessFile () { #FIXME - recursion: local variables and file descriptor (case passed incrementing parameter) #Don't use includes for the moment. #Params: #- RecursionLevel (0 for top level file, 1 for file included from 0, 2 for file included in 1, etc.) #- Filename to process local RecursionLevel="$1" shift local OneLine local Params if [ -z "$1" ]; then Debug Missing filename in ProcessFile return 1 fi if [ ! -r "$1" ]; then Debug File "$1" is not readable return 1 fi #Read kludge: #Redirect stdin to work around an f^@&ing annoying limitation in the read command. case "$RecursionLevel" in 0) exec 5<&0 < "$1" ;; 1) exec 6<&0 < "$1" ;; 2) exec 7<&0 < "$1" ;; 3) exec 8<&0 < "$1" ;; *) echo Recursion level too deep in ProcessFile, exiting. >/dev/stderr exit 1 ;; esac while read OneLine ; do case "$OneLine" in \#*) : #Ignore comment lines ;; include*) Debug Processing `echo "$OneLine" | sed -e 's/include //'` ProcessFile $[ $RecursionLevel + 1 ] `echo "$OneLine" | sed -e 's/include //'` ;; preprocessor*) : #FIXME #Debug Skipping preprocessor ;; var*) echo "$OneLine" | sed -e 's/var //' -e 's/ *$//' -e 's/ /=/' -e 's@any@0/0@' ;; alert\ ip\ *\ any\ -\>\ *\ :1023\ *) #Debug Special processing ip with port: "alert ip $EXTERNAL_NET any -> $HOME_NET :1023 ..." #call twice, once with tcp .... OneLine=`echo "$OneLine" | sed -e 's/ ip / tcp /'` ProcessLine "$OneLine" OutputRule "$PrimaryParams" "$SecondaryParams" #...and once with udp OneLine=`echo "$OneLine" | sed -e 's/ tcp / udp /'` ProcessLine "$OneLine" OutputRule "$PrimaryParams" "$SecondaryParams" ;; *\<\>*) #call twice, once with -> .... OneLine=`echo "$OneLine" | sed -e 's/<>/->/'` ProcessLine "$OneLine" OutputRule "$PrimaryParams" "$SecondaryParams" #...and once with <- OneLine=`echo "$OneLine" | sed -e 's/->/<-/'` ProcessLine "$OneLine" OutputRule "$PrimaryParams" "$SecondaryParams" ;; *) #-\>|\<-) ProcessLine "$OneLine" OutputRule "$PrimaryParams" "$SecondaryParams" ;; esac done case "$RecursionLevel" in 0) exec 0<&5 5<&- ;; 1) exec 0<&6 6<&- ;; 2) exec 0<&7 7<&- ;; 3) exec 0<&8 8<&- ;; *) echo Invalid recursion level in ProcessFile, exiting. >/dev/stderr exit 1 ;; esac } usage () { echo This script is designed to convert a snort ruleset to iptables rules. >/dev/stderr echo Since it can recurse into included files, simply give it the top-level >/dev/stderr echo ruleset, such as /etc/snort/snort.conf . >/dev/stderr echo >/dev/stderr echo Usage: >/dev/stderr echo -e '\t' "$0" ' [--log] [--drop|--reject] SnortRuleFile [SnortRuleFile...]' >/dev/stderr echo Example: >/dev/stderr echo -e '\t' "$0" ' --log /etc/snort/snort.conf' >/dev/stderr echo You should pick at least one of log, drop, or reject to get any output. >/dev/stderr echo Log can be mixed with drop or reject. >/dev/stderr } if [ -z "$1" ]; then usage exit 1 fi DoLog='' DoAction='' while [ -n "$1" ]; do case "$1" in --[Ll][Oo][Gg]) DoLog="yes" ;; --[Dd][Rr][Oo][Pp]) DoAction="DROP" ;; --[Rr][Ee][Jj][Ee][Cc][Tt]) DoAction="REJECT" ;; *) if [ -r "$1" ]; then if [ -z "$DoLog$DoAction" ]; then echo 'Note: No action has been selected! Without a "--log", "--drop"' >/dev/stderr echo 'or "--reject" command line option, this program will not produce' >/dev/stderr echo 'any useful output.' >/dev/stderr fi ProcessFile 0 "$1" else echo Unable to read "$1", skipping. >/dev/stderr fi ;; esac shift done