diff --git a/Shorewall/compiler b/Shorewall/compiler index 61a4d0c33..2dae9ab2d 100755 --- a/Shorewall/compiler +++ b/Shorewall/compiler @@ -165,13 +165,6 @@ qt_iptables() { save_command qt \$IPTABLES $@ } -# -# Generate a command to run tc -# -run_tc() { - save_command run_tc $@ -} - # # Add the implicit ACCEPT rules at the end of a rules file section # @@ -518,6 +511,7 @@ determine_zones() ipsec|IPSEC|ipsec4|IPSEC4) list_search $zone $ZONES $FW && fatal_error "Zone $zone is defined more than once" [ -n "$POLICY_MATCH" ] || fatal_error "Your kernel and/or iptables does not support policy match" + [ -n "$CLIB_TUNNELS_LOADED" ] || fatal_error "Shorewall clib.tunnels module not loaded" eval ${zone}_is_ipsec=Yes eval ${zone}_is_complex=Yes merge_zone @@ -602,19 +596,6 @@ masq_chain() # $1 = interface echo $(chain_base $1)_masq } -# -# MAC Verification Chain for an interface -# -mac_chain() # $1 = interface -{ - echo $(chain_base $1)_mac -} - -macrecent_target() # $1 - interface -{ - [ -n "$MACLIST_TTL" ] && echo $(chain_base $1)_rec || echo RETURN -} - # # DNAT Chain from a zone # @@ -631,14 +612,6 @@ snat_chain() # $1 = interface echo $(chain_base $1)_snat } -# -# ECN Chain to an interface -# -ecn_chain() # $1 = interface -{ - echo $(chain_base $1)_ecn -} - # # First chains for an interface # @@ -1140,7 +1113,11 @@ validate_hosts_file() { for option in $(separate_list $options) ; do case $option in - norfc1918|blacklist|maclist|tcpflags|nosmurfs|-) + norfc1918|blacklist|tcpflags|nosmurfs|-) + ;; + maclist) + [ -n "$CLIB_MACLIST_LOADED" ] || \ + fatal_error "Shorewall module clib.maclist not loaded" ;; ipsec) [ -n "$CLIB_TUNNELS_LOADED" ] || \ @@ -1588,339 +1565,6 @@ disable_critical_hosts() done } -# -# Setup Proxy ARP -# -setup_proxy_arp() { - - local setlist= resetlist= - - print_error() { - error_message "Invalid value for HAVEROUTE - ($haveroute)" - error_message "Entry \"$address $interface $external $haveroute\" ignored" - } - - print_error1() { - error_message "Invalid value for PERSISTENT - ($persistent)" - error_message "Entry \"$address $interface $external $haveroute $persistent\" ignored" - } - - print_warning() { - error_message "PERSISTENT setting ignored - ($persistent)" - error_message "Entry \"$address $interface $external $haveroute $persistent\"" - } - - setup_one_proxy_arp() { - - case $haveroute in - [Nn][Oo]) - haveroute= - ;; - [Yy][Ee][Ss]) - ;; - *) - if [ -n "$haveroute" ]; then - print_error - return - fi - ;; - esac - - case $persistent in - [Nn][Oo]) - persistent= - ;; - [Yy][Ee][Ss]) - [ -z "$haveroute" ] || print_warning - ;; - *) - if [ -n "$persistent" ]; then - print_error1 - return - fi - ;; - esac - - if [ -z "$haveroute" ]; then - save_command "[ -n \"\$NOROUTES\" ] || run_ip route replace $address dev $interface" - [ -n "$persistent" ] && haveroute=yes - fi - - indent >&3 << __EOF__ -if ! arp -i $external -Ds $address $external pub; then - fatal_error "Command \"arp -i $external -Ds $address $external pub\" failed" -fi - -progress_message " Host $address connected to $interface added to ARP on $external" - -__EOF__ - echo $address $interface $external $haveroute >> $STATEDIR/proxyarp - - progress_message " Host $address connected to $interface added to ARP on $external" - } - - > $STATEDIR/proxyarp - - save_progress_message "Setting up Proxy ARP..." - - while read address interface external haveroute persistent; do - expandv address interface external haveroute persistent - list_search $interface $setlist || setlist="$setlist $interface" - list_search $external $resetlist || list_search $external $setlist || resetlist="$resetlist $external" - setup_one_proxy_arp - done < $TMP_DIR/proxyarp - - for interface in $resetlist; do - list_search $interface $setlist || \ - save_command "echo 0 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" - done - - for interface in $setlist; do - save_command "echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp" - done - - interfaces=$(find_interfaces_by_option proxyarp) - - for interface in $interfaces; do - indent >&3 << __EOF__ -if [ -f /proc/sys/net/ipv4/conf/$interface/proxy_arp ] ; then - echo 1 > /proc/sys/net/ipv4/conf/$interface/proxy_arp -else - error_message "WARNING: Unable to enable proxy ARP on $interface" -fi - -__EOF__ - done - -} - -# -# Set up MAC Verification -# -setup_mac_lists() { - local interface - local mac - local addresses - local address - local chain - local chain1 - local macpart - local blob - local hosts - local ipsec - local policy= - - create_mac_chain() - { - case $MACLIST_TABLE in - filter) - createchain $1 no - ;; - *) - createmanglechain $1 - ;; - esac - } - - have_mac_chain() - { - local result - - case $MACLIST_TABLE in - filter) - havechain $1 && result=0 || result=1 - ;; - *) - havemanglechain $1 && result=0 || result=1 - ;; - esac - - return $result - } - # - # Generate the list of interfaces having MAC verification - # - maclist_interfaces= - - for hosts in $maclist_hosts; do - hosts=${hosts#*^} - interface=${hosts%%:*} - if ! list_search $interface $maclist_interfaces; then\ - if [ -z "$maclist_interfaces" ]; then - maclist_interfaces=$interface - else - maclist_interfaces="$maclist_interfaces $interface" - fi - fi - done - - progress_message "$DOING MAC Verification on $maclist_interfaces..." - # - # Create chains. - # - for interface in $maclist_interfaces; do - chain=$(mac_chain $interface) - create_mac_chain $chain - # - # If we're using the mangle table and the interface is DHCP-enabled then we need to accept DHCP broadcasts from 0.0.0.0 - # - if [ $MACLIST_TABLE = mangle ] && interface_has_option $interface dhcp; then - run_iptables -t mangle -A $chain -s 0.0.0.0 -d 255.255.255.255 -p udp --dport 67:68 -j RETURN - fi - - if [ -n "$MACLIST_TTL" ]; then - chain1=$(macrecent_target $interface) - create_mac_chain $chain1 - run_iptables -A $chain -t $MACLIST_TABLE -m recent --rcheck --seconds $MACLIST_TTL --name $chain -j RETURN - run_iptables -A $chain -t $MACLIST_TABLE -j $chain1 - run_iptables -A $chain -t $MACLIST_TABLE -m recent --update --name $chain -j RETURN - run_iptables -A $chain -t $MACLIST_TABLE -m recent --set --name $chain - fi - done - - # - # Process the maclist file producing the verification rules - # - while read disposition interface mac addresses; do - expandv disposition interface mac addresses - - level= - - case $disposition in - ACCEPT:*) - level=${disposition#*:} - disposition=ACCEPT - target=RETURN - ;; - ACCEPT) - target=RETURN - ;; - REJECT:*) - [ $MACLIST_TABLE = mangle ] && fatal_error "DISPOSITION = REJECT is incompatible with MACLIST_TABLE=mangle" - target=reject - disposition=REJECT - ;; - REJECT) - [ $MACLIST_TABLE = mangle ] && fatal_error "DISPOSITION = REJECT is incompatible with MACLIST_TABLE=mangle" - target=reject - ;; - DROP:*) - level=${disposition#*:} - disposition=DROP - target=DROP - ;; - DROP) - target=DROP - ;; - *) - addresses="$mac" - mac="$interface" - interface="$disposition" - disposition=ACCEPT - target=RETURN - ;; - esac - - physdev_part= - - if [ -n "$BRIDGING" ]; then - case $interface in - *:*) - physdev_part="-m physdev --physdev-in ${interface#*:}" - interface=${interface%:*} - ;; - esac - fi - - [ -n "$MACLIST_TTL" ] && chain=$(macrecent_target $interface) || chain=$(mac_chain $interface) - - if ! have_mac_chain $chain ; then - fatal_error "No hosts on $interface have the maclist option specified" - fi - - if [ x${mac:=-} = x- ]; then - if [ -z "$addresses" ]; then - fatal_error "You must specify a MAC address or an IP address" - else - macpart= - fi - else - macpart=$(mac_match $mac) - fi - - if [ -z "$addresses" ]; then - [ -n "$level" ] && \ - log_rule_limit $level $chain $(mac_chain $interface) $disposition "$LOGLIMIT" "" -A -t $MACLIST_TABLE $macpart $physdev_part - run_iptables -A $chain -t $MACLIST_TABLE $macpart $physdev_part -j $target - else - for address in $(separate_list $addresses) ; do - [ -n "$level" ] && \ - log_rule_limit $level $chain $(mac_chain $interface) $disposition "$LOGLIMIT" "" -A -t $MACLIST_TABLE $macpart -s $address $physdev_part - run_iptables2 -A $chain -t $MACLIST_TABLE $macpart -s $address $physdev_part -j $target - done - fi - done < $TMP_DIR/maclist - # - # Must take care of our own broadcasts and multicasts then terminate the verification - # chains - # - for interface in $maclist_interfaces; do - - [ -n "$MACLIST_TTL" ] && chain=$(macrecent_target $interface) || chain=$(mac_chain $interface) - - if [ -n "$MACLIST_LOG_LEVEL" -o $MACLIST_DISPOSITION != ACCEPT ]; then - indent >&3 << __EOF__ - -blob=\$(ip link show $interface 2> /dev/null) - -[ -z "\$blob" ] && \ - fatal_error "Interface $interface must be up before Shorewall can start" - -ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | sed 's/inet //; s/brd //; s/scope.*//;' | while read address broadcast; do - address=\${address%/*} - if [ -n "\$broadcast" ]; then - run_iptables -t $MACLIST_TABLE -A $chain -s \$address -d \$broadcast -j RETURN - fi - - run_iptables -t $MACLIST_TABLE -A $chain -s \$address -d 255.255.255.255 -j RETURN - run_iptables -t $MACLIST_TABLE -A $chain -s \$address -d 224.0.0.0/4 -j RETURN -done - -__EOF__ - fi - - if [ -n "$MACLIST_LOG_LEVEL" ]; then - log_rule_limit $MACLIST_LOG_LEVEL $chain $(mac_chain $interface) $MACLIST_DISPOSITION "$LOGLIMIT" "" -A -t $MACLIST_TABLE - fi - - if [ $MACLIST_DISPOSITION != ACCEPT ]; then - run_iptables -A $chain -t $MACLIST_TABLE -j $maclist_target - fi - done - # - # Generate jumps from the input and forward chains - # - for hosts in $maclist_hosts; do - ipsec=${hosts%^*} - hosts=${hosts#*^} - [ -n "$POLICY_MATCH" ] && policy="-m policy --pol $ipsec --dir in" || policy= - interface=${hosts%%:*} - hosts=${hosts#*:} - case $MACLIST_TABLE in - filter) - for chain in $(first_chains $interface) ; do - run_iptables -A $chain $(match_source_hosts $hosts) -m state --state NEW \ - $policy -j $(mac_chain $interface) - done - ;; - *) - run_iptables -t mangle -A PREROUTING -i $interface $(match_source_hosts $hosts) -m state --state NEW \ - $policy -j $(mac_chain $interface) - ;; - esac - done -} - # # Set up SYN flood protection # @@ -1957,30 +1601,6 @@ setup_syn_flood_chains() done } -# -# Delete existing Proxy ARP -# -delete_proxy_arp() { - indent >&3 << __EOF__ -if [ -f \${VARDIR}/proxyarp ]; then - while read address interface external haveroute; do - qt arp -i \$external -d \$address pub - [ -z "\$haveroute" -a -z "\$NOROUTE" ] && qt ip route del \$address dev \$interface - done < \${VARDIR}/proxyarp - - rm -f \${VARDIR}/proxyarp -fi - -for f in /proc/sys/net/ipv4/conf/*; do - [ -f \$f/proxy_arp ] && echo 0 > \$f/proxy_arp -done - -__EOF__ - - [ -d $STATEDIR ] && touch $STATEDIR/proxyarp - - } - # # Setup Static Network Address Translation (NAT) # @@ -2109,54 +1729,6 @@ setup_netmap() { done < $TMP_DIR/netmap } -# -# Setup ECN disabling rules -# -setup_ecn() # $1 = file name -{ - local interfaces="" - local hosts= - local h - - strip_file ecn $1 - - progress_message2 "$DOING $1..." - - while read interface host; do - expandv interface host - list_search $interface $ALL_INTERFACES || \ - fatal_error "Unknown interface $interface" - list_search $interface $interfaces || \ - interfaces="$interfaces $interface" - [ "x$host" = "x-" ] && host= - for h in $(separate_list ${host:-0.0.0.0/0}); do - hosts="$hosts $interface:$h" - done - done < $TMP_DIR/ecn - - if [ -n "$interfaces" ]; then - progress_message "$DOING ECN control on${interfaces}..." - - for interface in $interfaces; do - chain=$(ecn_chain $interface) - if havemanglechain $chain; then - flushmangle $chain - else - createmanglechain $chain - run_iptables -t mangle -A POSTROUTING -p tcp -o $interface -j $chain - run_iptables -t mangle -A OUTPUT -p tcp -o $interface -j $chain - fi - done - - for host in $hosts; do - interface=${host%:*} - h=${host#*:} - run_iptables -t mangle -A $(ecn_chain $interface) -p tcp $(dest_ip_range $h) -j ECN --ecn-tcp-remove - progress_message_and_save " ECN Disabled to $h through $interface" - done - fi -} - # # Set up an exclusion chain # @@ -2850,75 +2422,6 @@ substitute_action() # $1 = parameter, $2 = action esac } -# -# This function maps old action names into their new macro equivalents -# -map_old_action() # $1 = Potential Old Action -{ - local macro= aktion - - if [ -n "$MAPOLDACTIONS" ]; then - case $1 in - */*) - echo $1 - return - ;; - *) - if [ -f $(find_file $1) ]; then - echo $1 - return - fi - - case $1 in - Allow*) - macro=${1#*w} - aktion=ACCEPT - ;; - Drop*) - macro=${1#*p} - aktion=DROP - ;; - Reject*) - macro=${1#*t} - aktion=REJECT - ;; - *) - echo $1 - return - ;; - esac - esac - - if [ -f $(find_file macro.$macro) ]; then - echo $macro/$aktion - return - fi - fi - - echo $1 -} - -# -# Combine a source/dest from the macro body with one from the macro invocation -# -merge_macro_source_dest() # $1 = source/dest from macro body, $2 = source/dest from invocation -{ - case $2 in - -) - echo ${1} - ;; - *.*.*|+*|~*|!~*) - # - # Value in the invocation is an address -- put it behind the value from the macro - # - echo ${1}:${2} - ;; - *) - echo ${2}:${1} - ;; - esac -} - # # The next three functions implement the three phases of action processing. # @@ -3001,52 +2504,11 @@ process_actions1() { eval requiredby=\"\$requiredby_${xaction}\" list_search $xtarget $requiredby || eval requiredby_${xaction}=\"$requiredby $xtarget\" else - temp=$(map_old_action $temp) - - case $temp in - */*) - param=${temp#*/} - case $param in - ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE) - ;; - *) - rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec" - fatal_error "Invalid Macro Parameter in rule \"$rule\"" - ;; - esac - temp=${temp%%/*} - ;; - esac - - f1=macro.${temp} - fn=$(find_file $f1) - - if [ ! -f $TMP_DIR/$f1 ]; then - # - # We must only verify macros once to ensure that they don't invoke any non-standard actions - # - if [ -f $fn ]; then - strip_file $f1 $fn - - progress_message " ..Expanding Macro $fn..." - - while read mtarget mclients mservers mprotocol mports mcports mratelimit muserspec; do - expandv mtarget - temp="${mtarget%%:*}" - case "$temp" in - ACCEPT|DROP|REJECT|LOG|QUEUE|CONTINUE|PARAM) - ;; - *) - rule="$mtarget $mclients $mservers $mprotocol $mports $mcports $mratelimit $muserspec" - fatal_error "Invalid TARGET in rule \"$rule\"" - esac - done < $TMP_DIR/$f1 - - progress_message " ..End Macro" - else - rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec" - fatal_error "Invalid TARGET in rule \"$rule\"" - fi + if [ -n "$CLIB_MACROS_LOADED" ]; then + verify_macro_from_action + else + rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec" + fatal_error "Invalid TARGET in rule \"$rule\"" fi fi ;; @@ -3313,70 +2775,7 @@ __EOF__ expandv xclients xservers xprotocol xports xcports xratelimit xuserspec if [ -n "$is_macro" ]; then - - xtarget1=$(map_old_action $xtarget1) - - case $xtarget1 in - */*) - param=${xtarget1#*/} - xtarget1=${xtarget1%%/*} - ;; - esac - - progress_message "..Expanding Macro $(find_file macro.$xtarget1)..." - while read mtarget mclients mservers mprotocol mports mcports mratelimit muserspec; do - expandv mtarget mclients mservers mprotocol mports mcports mratelimit muserspec - - mtarget=$(merge_levels $xaction2 $mtarget) - - case $mtarget in - PARAM|PARAM:*) - [ -n "$param" ] && mtarget=$(substitute_action $param $mtarget) || fatal_error "PARAM requires that a parameter be supplied in macro invocation" - ;; - esac - - if [ -n "$mclients" ]; then - case $mclients in - -|SOURCE) - mclients=${xclients} - ;; - DEST) - mclients=${xservers} - ;; - *) - mclients=$(merge_macro_source_dest $mclients $xclients) - ;; - esac - else - mclients=${xclients} - fi - - if [ -n "$mservers" ]; then - case $mservers in - -|DEST) - mservers=${xservers} - ;; - SOURCE) - mservers=${xclients} - ;; - *) - mservers=$(merge_macro_source_dest $mservers $xservers) - ;; - esac - else - mservers=${xserverss} - fi - - [ -n "$xprotocol" ] && [ "x${xprotocol}" != x- ] && mprotocol=$xprotocol - [ -n "$xports" ] && [ "x${xports}" != x- ] && mports=$xports - [ -n "$xcports" ] && [ "x${xcports}" != x- ] && mcports=$xcports - [ -n "$xratelimit" ] && [ "x${xratelimit}" != x- ] && mratelimit=$xratelimit - [ -n "$xuserspec" ] && [ "x${xuserspec}" != x- ] && muserspec=$xuserspec - - rule="$mtarget ${mclients:=-} ${mservers:=-} ${mprotocol:=-} ${mports:=-} ${mcports:=-} ${mratelimit:-} ${muserspec:=-}" - process_action $xchain $xaction1 $mtarget $mclients $mservers $mprotocol $mports $mcports $mratelimit $muserspec - done < $TMP_DIR/macro.$xtarget1 - progress_message "..End Macro" + expand_macro_in_action else rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec" process_action $xchain $xaction1 $xaction2 $xclients $xservers $xprotocol $xports $xcports $xratelimit $xuserspec @@ -4345,109 +3744,6 @@ __EOF__ save_progress_message_short " Rule \"$rule\" added." } -# -# Process a macro invocation in the rules file -# - -process_macro() # $1 = target - # $2 = param - # $2 = clients - # $3 = servers - # $4 = protocol - # $5 = ports - # $6 = cports - # $7 = address - # $8 = ratelimit - # $9 = userspec -{ - local itarget="$1" - local param="$2" - local iclients="$3" - local iservers="$4" - local iprotocol="$5" - local iports="$6" - local icports="$7" - local iaddress="$8" - local iratelimit="$9" - local iuserspec="${10}" - - progress_message "..Expanding Macro $(find_file macro.${itarget%%:*})..." - - while read mtarget mclients mservers mprotocol mports mcports mratelimit muserspec; do - expandv mtarget mclients mservers mprotocol mports mcports mratelimit muserspec - - mtarget=$(merge_levels $itarget $mtarget) - - case $mtarget in - PARAM|PARAM:*) - [ -n "$param" ] && mtarget=$(substitute_action $param $mtarget) || fatal_error "PARAM requires that a parameter be supplied in macro invocation" - ;; - esac - - case ${mtarget%%:*} in - ACCEPT|ACCEPT+|NONAT|DROP|REJECT|DNAT|DNAT-|REDIRECT|REDIRECT-|LOG|CONTINUE|QUEUE|SAME|SAME-) - ;; - *) - if list_search ${mtarget%%:*} $ACTIONS; then - if ! list_search $mtarget $USEDACTIONS; then - createactionchain $mtarget - USEDACTIONS="$USEDACTIONS $mtarget" - fi - - mtarget=$(find_logactionchain $mtarget) - else - fatal_error "Invalid Action in rule \"$mtarget ${mclients:--} ${mservers:--} ${mprotocol:--} ${mports:--} ${mcports:--} ${xaddress:--} ${mratelimit:--} ${muserspec:--}\"" - fi - ;; - esac - - if [ -n "$mclients" ]; then - case $mclients in - -|SOURCE) - mclients=${iclients} - ;; - DEST) - mclients=${iservers} - ;; - *) - mclients=$(merge_macro_source_dest $mclients $iclients) - ;; - esac - else - mclients=${iclients} - fi - - if [ -n "$mservers" ]; then - case $mservers in - -|DEST) - mservers=${iservers} - ;; - SOURCE) - mservers=${iclients} - ;; - *) - mservers=$(merge_macro_source_dest $mservers $iservers) - ;; - esac - else - mservers=${iservers} - fi - - [ -n "$iprotocol" ] && [ "x${iprotocol}" != x- ] && mprotocol=$iprotocol - [ -n "$iports" ] && [ "x${iports}" != x- ] && mports=$iports - [ -n "$icports" ] && [ "x${icports}" != x- ] && mcports=$icports - [ -n "$iratelimit" ] && [ "x${iratelimit}" != x- ] && mratelimit=$iratelimit - [ -n "$iuserspec" ] && [ "x${iuserspec}" != x- ] && muserspec=$iuserspec - - rule="$mtarget ${mclients=-} ${mservers:=-} ${mprotocol:=-} ${mports:=-} ${mcports:=-} ${xaddress:=-} ${mratelimit:=-} ${muserspec:=-}" - process_rule $mtarget $mclients $mservers $mprotocol $mports $mcports ${iaddress:=-} $mratelimit $muserspec - - done < $TMP_DIR/macro.${itarget%%:*} - - progress_message "..End Macro" - -} - # # Process the rules file # @@ -4602,20 +3898,25 @@ process_rules() ;; esac - f=macro.$xtarget1 - - if [ -f $TMP_DIR/$f ]; then - do_it Yes - else - fn=$(find_file $f) - - if [ -f $fn ]; then - strip_file $f $fn + if [ -n "$CLIB_MACROS_LOADED" ]; then + f=macro.$xtarget1 + + if [ -f $TMP_DIR/$f ]; then do_it Yes else - rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec" - fatal_error "Invalid Action in rule \"$rule\"" + fn=$(find_file $f) + + if [ -f $fn ]; then + strip_file $f $fn + do_it Yes + else + rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec" + fatal_error "Invalid Action in rule \"$rule\"" + fi fi + else + rule="$xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserspec" + fatal_error "Invalid Action in rule \"$rule\"" fi fi ;; @@ -4635,200 +3936,6 @@ process_rules() SECTION=DONE } -# -# Process a record from the tos file -# -# The caller has loaded the column contents from the record into the following -# variables: -# -# src dst protocol sport dport tos -# -# and has loaded a space-separated list of their values in "rule". -# -process_tos_rule() { - # - # Parse the contents of the 'src' variable - # - if [ "$src" = "${src%:*}" ]; then - srczone="$src" - src= - else - srczone="${src%:*}" - src="${src#*:}" - fi - - source= - # - # Validate the source zone - # - if validate_zone $srczone; then - source=$srczone - elif [ "$srczone" = "all" ]; then - source="all" - else - error_message "WARNING: Undefined Source Zone - rule \"$rule\" ignored" - return - fi - - [ -n "$src" ] && case "$src" in - *.*.*|+*|!+*) - # - # IP Address or networks - # - src="$(source_ip_range $src)" - ;; - ~*|!~*) - src=$(mac_match $src) - ;; - *) - # - # Assume that this is a device name - # - if ! verify_interface $src ; then - error_message "WARNING: Unknown Interface in rule \"$rule\" ignored" - return - fi - - src="$(match_source_dev $src)" - ;; - esac - - # - # Parse the contents of the 'dst' variable - # - if [ "$dst" = "${dst%:*}" ]; then - dstzone="$dst" - dst= - else - dstzone="${dst%:*}" - dst="${dst#*:}" - fi - - dest= - # - # Validate the destination zone - # - if validate_zone $dstzone; then - dest=$dstzone - elif [ "$dstzone" = "all" ]; then - dest="all" - else - error_message \ - "WARNING: Undefined Destination Zone - rule \"$rule\" ignored" - return - fi - - [ -n "$dst" ] && case "$dst" in - *.*.*|+*|!+*) - # - # IP Address or networks - # - ;; - *) - # - # Assume that this is a device name - # - error_message \ - "WARNING: Invalid Destination - rule \"$rule\" ignored" - return - ;; - esac - - # - # Setup PROTOCOL and PORT variables - # - sports="" - dports="" - - case $protocol in - tcp|udp|TCP|UDP|6|17) - [ -n "$sport" ] && [ "x${sport}" != "x-" ] && \ - sports="--sport $sport" - [ -n "$dport" ] && [ "x${dport}" != "x-" ] && \ - dports="--dport $dport" - ;; - icmp|ICMP|0) - [ -n "$dport" ] && [ "x${dport}" != "x-" ] && \ - dports="--icmp-type $dport" - ;; - all|ALL) - protocol= - ;; - *) - ;; - esac - - protocol="${protocol:+-p $protocol}" - - tos="-j TOS --set-tos $tos" - - case "$dstzone" in - all|ALL) - dst=0.0.0.0/0 - ;; - *) - [ -z "$dst" ] && eval dst=\$${dstzone}_hosts - ;; - esac - - for dest in $dst; do - dest="$(dest_ip_range $dest)" - - case $srczone in - $FW) - run_iptables2 -t mangle -A outtos \ - $protocol $dest $dports $sports $tos - ;; - all|ALL) - run_iptables2 -t mangle -A outtos \ - $protocol $dest $dports $sports $tos - run_iptables2 -t mangle -A pretos \ - $protocol $dest $dports $sports $tos - ;; - *) - if [ -n "$src" ]; then - run_iptables2 -t mangle -A pretos $src \ - $protocol $dest $dports $sports $tos - else - eval interfaces=\$${srczone}_interfaces - - for interface in $interfaces; do - run_iptables2 -t mangle -A pretos -i $interface \ - $protocol $dest $dports $sports $tos - done - fi - ;; - esac - done - - progress_message " Rule \"$rule\" $DONE." - save_progress_message "Rule \"$rule\" Added." -} - -# -# Process the tos file -# -process_tos() # $1 = name of tos file -{ - progress_message2 "$DOING $1..." - - strip_file tos $1 - - if [ -s $TMP_DIR/tos ] ; then - createmanglechain pretos - createmanglechain outtos - - while read src dst protocol sport dport tos; do - expandv src dst protocol sport dport tos - rule="$(echo $src $dst $protocol $sport $dport $tos)" - process_tos_rule - done < $TMP_DIR/tos - - run_iptables -t mangle -A PREROUTING -j pretos - run_iptables -t mangle -A OUTPUT -j outtos - fi -} - # # Display elements of a list with leading white space # @@ -5701,8 +4808,8 @@ initialize_netfilter () { # strip_file rules - strip_file proxyarp - strip_file maclist + [ -n "$CLIB_PROXYARP_LOADED" ] && strip_file proxyarp + [ -n "$CLIB_MACLIST_LOADED" ] && strip_file maclist strip_file nat strip_file netmap @@ -5720,7 +4827,7 @@ initialize_netfilter () { done fi - delete_proxy_arp + [ -n "$CLIB_PROXYARP_LOADED" ] && delete_proxy_arp if [ -n "$MANGLE_ENABLED" ]; then run_iptables -t mangle -F @@ -6770,6 +5877,10 @@ __EOF__ done fi +__EOF__ + + if [ -n "$CLIB_PROXYARP_LOADED" ]; then + cat >&3 << __EOF__ if [ -f \${VARDIR}/proxyarp ]; then while read address interface external haveroute; do qt arp -i \$external -d \$address pub @@ -6784,6 +5895,8 @@ __EOF__ done __EOF__ + fi + [ -n "$CLIB_TCRULES_LOADED" ] && [ -n "$CLEAR_TC" ] && save_command "delete_tc1" [ -n "$DISABLE_IPV6" ] && save_command "disable_ipv6" @@ -7267,13 +6380,15 @@ __EOF__ initialize_netfilter - progress_message2 "$DOING Proxy ARP"; setup_proxy_arp + if [ -n "$CLIB_PROXYARP_LOADED" ]; then + progress_message2 "$DOING Proxy ARP"; setup_proxy_arp + fi # # [re]-Establish routing # if [ -n "$CLIB_PROVIDERS_LOADED" ]; then setup_providers $(find_file providers) - [ -n "$ROUTEMARK_INTERFACES" ] && setup_routes + [ -n "$ROUTEMARK_INTERFACES" ] && setup_routes fi progress_message2 "$DOING NAT..."; setup_nat @@ -7291,11 +6406,13 @@ __EOF__ fatal_error "IPSEC Zones are defined but the Shorewall clib.tunnels module is not loaded" fi - maclist_hosts=$(find_hosts_by_option maclist) + if [ -n "$CLIB_MACLIST_LOADED" ]; then + maclist_hosts=$(find_hosts_by_option maclist) - if [ -n "$maclist_hosts" ]; then - save_progress_message "Setting up MAC Filtration..." - setup_mac_lists + if [ -n "$maclist_hosts" ]; then + save_progress_message "Setting up MAC Filtration..." + setup_mac_lists + fi fi progress_message2 "$DOING $(find_file rules)..." @@ -7326,16 +6443,20 @@ __EOF__ fi if [ -n "$MANGLE_ENABLED" ]; then - tos=$(find_file tos) - if [ -f $tos ]; then - save_progress_message "Setting up TOS..." - process_tos $tos + if [ -n "$CLIB_TOS_LOADED" ]; then + tos=$(find_file tos) + if [ -f $tos ]; then + save_progress_message "Setting up TOS..." + process_tos $tos + fi fi - ecn=$(find_file ecn) - if [ -f $ecn ]; then - save_progress_message "Setting up ECN..." - setup_ecn $ecn + if [ -n "$CLIB_ECN_LOADED" ]; then + ecn=$(find_file ecn) + if [ -f $ecn ]; then + save_progress_message "Setting up ECN..." + setup_ecn $ecn + fi fi if [ -n "$CLIB_TCRULES_LOADED" ]; then @@ -7352,11 +6473,13 @@ __EOF__ save_command add_ip_aliases $ALIASES_TO_ADD fi - for file in chains nat proxyarp zones; do - save_command "cat > \${VARDIR}/$file $LEFTSHIFT __EOF__" - cat $STATEDIR/$file >&3 - save_command_unindented __EOF__ - done + if [ -n "$CLIB_PROXYARP_LOADED" ]; then + for file in chains nat proxyarp zones; do + save_command "cat > \${VARDIR}/$file $LEFTSHIFT __EOF__" + cat $STATEDIR/$file >&3 + save_command_unindented __EOF__ + done + fi cat >&3 << __EOF__ diff --git a/Shorewall/functions b/Shorewall/functions index f71e9f571..69eb1c09b 100644 --- a/Shorewall/functions +++ b/Shorewall/functions @@ -6,11 +6,6 @@ # # (c) 1999,2000,2001,2002,2003,2004,2005,2006 - Tom Eastep (teastep@shorewall.net) # -# tcstart from tc4shorewall Version 0.5 -# (c) 2005 Arne Bernin -# Modified by Tom Eastep for integration into the Shorewall distribution -# published under GPL Version 2# -# # Complete documentation is available at http://shorewall.net # # This program is free software; you can redistribute it and/or modify @@ -32,1570 +27,25 @@ LIBVERSION=30192 [ -n "${SHAREDIR:=/usr/share/shorewall}" ] [ -n "${CONFDIR:=/etc/shorewall}" ] -# -# Message to stderr -# -error_message() # $* = Error Message -{ - echo " $@" >&2 -} - -# Function to truncate a string -- It uses 'cut -b -' -# rather than ${v:first:last} because light-weight shells like ash and -# dash do not support that form of expansion. -# - -truncate() # $1 = length -{ - cut -b -${1} -} - -# -# Split a colon-separated list into a space-separated list -# -split() { - local ifs=$IFS - IFS=: - set -- $1 - echo $* - IFS=$ifs -} - -# -# Search a list looking for a match -- returns zero if a match found -# 1 otherwise -# -list_search() # $1 = element to search for , $2-$n = list -{ - local e=$1 - - while [ $# -gt 1 ]; do - shift - [ "x$e" = "x$1" ] && return 0 - done - - return 1 -} - -# -# Return a space separated list of values matching -# -list_walk() # $1 = element to search for, $2-$n = list -{ - local e=$1 result= - - while [ $# -gt 1 ]; do - shift - case $1 in - $e*) - result="$result ${1##$e}" - ;; - esac - done - echo $result -} - -# -# Functions to count list elements -# - - - - - - - - - - - - - - - - -# Whitespace-separated list -# -list_count1() { - echo $# -} -# -# Comma-separated list -# -list_count() { - list_count1 $(separate_list $1) -} - -# -# Conditionally produce message -# -progress_message() # $* = Message -{ - local timestamp= - - if [ $VERBOSE -gt 1 ]; then - [ -n "$TIMESTAMP" ] && timestamp="$(date +%H:%M:%S) " - echo "${timestamp}$@" - fi -} - -progress_message2() # $* = Message -{ - local timestamp= - - if [ $VERBOSE -gt 0 ]; then - [ -n "$TIMESTAMP" ] && timestamp="$(date +%H:%M:%S) " - echo "${timestamp}$@" - fi -} - -progress_message3() # $* = Message -{ - local timestamp= - - if [ $VERBOSE -ge 0 ]; then - [ -n "$TIMESTAMP" ] && timestamp="$(date +%H:%M:%S) " - echo "${timestamp}$@" - fi -} - -# -# Suppress all output for a command -# -qt() -{ - "$@" >/dev/null 2>&1 -} - -# -# Determine if Shorewall is "running" -# -shorewall_is_started() { - qt $IPTABLES -L shorewall -n -} - -# -# Perform variable substitution on the passed argument and echo the result -# -expand() # $@ = contents of variable which may be the name of another variable -{ - eval echo \"$@\" -} - -# -# Perform variable substitition on the values of the passed list of variables -# -expandv() # $* = list of variable names -{ - local varval - - while [ $# -gt 0 ]; do - eval varval=\$${1} - eval $1=\"$varval\" - shift - done -} - -# -# Add whitespace after "!" -# -fix_bang() -{ - local result= - - while [ $# -gt 0 ]; do - case $1 in - !*) - result="$result ! ${1#!}" - ;; - *) - result="$result $1" - ;; - esac - shift - done - - echo $result -} - -# -# Echos the fully-qualified name of the calling shell program -# -my_pathname() { - cd $(dirname $0) - echo $PWD/$(basename $0) -} - -# -# Set default config path -# -ensure_config_path() { - local F=${SHAREDIR}/configpath - if [ -z "$CONFIG_PATH" ]; then - [ -f $F ] || { echo " ERROR: $F does not exist"; exit 2; } - . $F - fi -} - -# -# Find a File -- For relative file name, look first in $SHOREWALL_DIR then in ${CONFDIR} -# -find_file() -{ - local saveifs= directory - - case $1 in - /*) - echo $1 - ;; - *) - if [ -n "$SHOREWALL_DIR" -a -f $SHOREWALL_DIR/$1 ]; then - echo $SHOREWALL_DIR/$1 - else - saveifs=$IFS - IFS=: - for directory in $CONFIG_PATH; do - if [ -f $directory/$1 ]; then - echo $directory/$1 - IFS=$saveifs - return - fi - done - - IFS=$saveifs - - echo ${CONFDIR}/$1 - fi - ;; - esac -} - -# -# Get fully-qualified name of file -# -resolve_file() # $1 = file name -{ - local pwd=$PWD - - case $1 in - /*) - echo $1 - ;; - ./*) - echo ${pwd}${1#.} - ;; - ../*) - cd .. - resolve_file ${1#../} - cd $pwd - ;; - *) - echo $pwd/$1 - ;; - esac -} - -## -# Source a user exit file if it exists -# -run_user_exit() # $1 = file name -{ - local user_exit=$(find_file $1) - - if [ -f $user_exit ]; then - progress_message "Processing $user_exit ..." - . $user_exit - fi -} - -# -# Replace commas with spaces and echo the result -# -separate_list() { - local list="$@" - local part - local newlist - local firstpart - local lastpart - local enclosure - - case "$list" in - *,|,*|*,,*|*[[:space:]]*) - # - # There's been whining about us not catching embedded white space in - # comma-separated lists. This is an attempt to snag some of the cases. - # - # The 'TERMINATOR' function will be set by the 'firewall' script to - # either 'startup_error' or 'fatal_error' depending on the command and - # command phase - # - [ -n "$TERMINATOR" ] && \ - $TERMINATOR "Invalid comma-separated list \"$@\"" - echo "WARNING -- invalid comma-separated list \"$@\"" >&2 - ;; - *\[*\]*) - # - # Where we need to embed comma-separated lists within lists, we enclose them - # within square brackets. - # - firstpart=${list%%\[*} - lastpart=${list#*\[} - enclosure=${lastpart%%\]*} - lastpart=${lastpart#*\]} - case $lastpart in - \,*) - case $firstpart in - *\,) - echo "$(separate_list ${firstpart%,}) [$enclosure] $(separate_list ${lastpart#,})" - ;; - *) - echo "$(separate_list $firstpart)[$enclosure] $(separate_list ${lastpart#,})" - ;; - esac - ;; - *) - case $firstpart in - *\,) - echo "$(separate_list ${firstpart%,}) [$enclosure]$(separate_list $lastpart)" - ;; - *) - echo "$(separate_list $firstpart)[$enclosure]$(separate_list $lastpart)" - ;; - esac - ;; - esac - return - ;; - esac - - list="$@" - part="${list%%,*}" - newlist="$part" - - while [ "x$part" != "x$list" ]; do - list="${list#*,}"; - part="${list%%,*}"; - newlist="$newlist $part"; - done - - echo "$newlist" -} - -# -# Undo the effect of 'separate_list()' -# -combine_list() -{ - local f o= - - for f in $* ; do - o="${o:+$o,}$f" - done - - echo $o -} - -# -# Load a Kernel Module -# -loadmodule() # $1 = module name, $2 - * arguments -{ - local modulename=$1 - local modulefile - local suffix - moduleloader=modprobe - - if ! qt mywhich modprobe; then - moduleloader=insmod - fi - - if ! list_search $modulename $MODULES ; then - shift - - for suffix in $MODULE_SUFFIX ; do - modulefile=$MODULESDIR/${modulename}.${suffix} - - if [ -f $modulefile ]; then - case $moduleloader in - insmod) - insmod $modulefile $* - ;; - *) - modprobe $modulename $* - ;; - esac - - MODULES=$(lsmod | cut -d ' ' -f1) - break - fi - done - fi -} - -# -# Reload the Modules -# -reload_kernel_modules() { - - [ -z "$MODULESDIR" ] && MODULESDIR=/lib/modules/$(uname -r)/kernel/net/ipv4/netfilter - MODULES=$(lsmod | cut -d ' ' -f1) - - while read command; do - eval $command - done - -} - -# -# Load kernel modules required for Shorewall -# -load_kernel_modules() -{ - save_modules_dir=$MODULESDIR - - [ -z "$MODULESDIR" ] && \ - MODULESDIR=/lib/modules/$(uname -r)/kernel/net/ipv4/netfilter - - modules=$(find_file modules) - - if [ -f $modules -a -d $MODULESDIR ]; then - MODULES=$(lsmod | cut -d ' ' -f1) - progress_message "Loading Modules..." - . $modules - fi - - MODULESDIR=$save_modules_dir -} - -# -# Call this function to assert mutual exclusion with Shorewall. If you invoke the -# /sbin/shorewall program while holding mutual exclusion, you should pass "nolock" as -# the first argument. Example "shorewall nolock refresh" -# -# This function uses the lockfile utility from procmail if it exists. -# Otherwise, it uses a somewhat race-prone algorithm to attempt to simulate the -# behavior of lockfile. -# -mutex_on() -{ - local try=0 - local lockf=${VARDIR}/lock - - MUTEX_TIMEOUT=${MUTEX_TIMEOUT:-60} - - if [ $MUTEX_TIMEOUT -gt 0 ]; then - - [ -d ${VARDIR} ] || mkdir -p ${VARDIR} - - if qt mywhich lockfile; then - lockfile -${MUTEX_TIMEOUT} -r1 ${lockf} - else - while [ -f ${lockf} -a ${try} -lt ${MUTEX_TIMEOUT} ] ; do - sleep 1 - try=$((${try} + 1)) - done - - if [ ${try} -lt ${MUTEX_TIMEOUT} ] ; then - # Create the lockfile - echo $$ > ${lockf} - else - echo "Giving up on lock file ${lockf}" >&2 - fi - fi - fi -} - -# -# Call this function to release mutual exclusion -# -mutex_off() -{ - rm -f ${VARDIR}/lock -} - -# -# Determine which version of mktemp is present (if any) and set MKTEMP accortingly: -# -# None - No mktemp -# BSD - BSD mktemp (Mandrake) -# STD - mktemp.org mktemp -# -find_mktemp() { - local mktemp=`mywhich mktemp 2> /dev/null` - - if [ -n "$mktemp" ]; then - if qt mktemp -V ; then - MKTEMP=STD - else - MKTEMP=BSD - fi - else - MKTEMP=None - fi -} - -# -# create a temporary file. If a directory name is passed, the file will be created in -# that directory. Otherwise, it will be created in a temporary directory. -# -mktempfile() { - - [ -z "$MKTEMP" ] && find_mktemp - - if [ $# -gt 0 ]; then - case "$MKTEMP" in - BSD) - mktemp $1/shorewall.XXXXXX - ;; - STD) - mktemp -p $1 shorewall.XXXXXX - ;; - None) - > $1/shorewall-$$ && echo $1/shorewall-$$ - ;; - *) - error_message "ERROR:Internal error in mktempfile" - ;; - esac - else - case "$MKTEMP" in - BSD) - mktemp /tmp/shorewall.XXXXXX - ;; - STD) - mktemp -t shorewall.XXXXXX - ;; - None) - rm -f /tmp/shorewall-$$ - > /tmp/shorewall-$$ && echo /tmp/shorewall-$$ - ;; - *) - error_message "ERROR:Internal error in mktempfile" - ;; - esac - fi -} - -# -# create a temporary directory -# -mktempdir() { - - [ -z "$MKTEMP" ] && find_mktemp - - case "$MKTEMP" in - STD) - mktemp -td shorewall.XXXXXX - ;; - None|BSD) - # - # Not all versions of the BSD mktemp support the -d option under Linux - # - qt rm -rf /tmp/shorewall-$$ - mkdir -p /tmp/shorewall-$$ && chmod 700 /tmp/shorewall-$$ && echo /tmp/shorewall-$$ - ;; - *) - error_message "ERROR:Internal error in mktempdir" - ;; - esac -} - -# -# Read a file and handle "INCLUDE" directives -# - -read_file() # $1 = file name, $2 = nest count -{ - local first rest - - if [ -f $1 ]; then - while read first rest; do - if [ "x$first" = "xINCLUDE" ]; then - if [ $2 -lt 4 ]; then - read_file $(find_file $(expand ${rest%#*})) $(($2 + 1)) - else - error_message "WARNING: INCLUDE in $1 ignored (nested too deeply)" - fi - else - echo "$first $rest" - fi - done < $1 - else - [ -n "$TERMINATOR" ] && $TERMINATOR "No such file: $1" - echo "WARNING -- No such file: $1" - fi -} - -# -# Function for including one file into another -# -INCLUDE() { - . $(find_file $(expand $@)) -} - -# -# Strip comments and blank lines from a file and place the result in the -# temporary directory -# -strip_file() # $1 = Base Name of the file, $2 = Full Name of File (optional) -{ - local fname - - [ $# = 1 ] && fname=$(find_file $1) || fname=$2 - - if [ -f $fname ]; then - read_file $fname 0 | cut -d'#' -f1 | grep -v '^[[:space:]]*$' > $TMP_DIR/$1 - else - > $TMP_DIR/$1 - fi -} - -# -# Note: The following set of IP address manipulation functions have anomalous -# behavior when the shell only supports 32-bit signed arithmatic and -# the IP address is 128.0.0.0 or 128.0.0.1. -# - -LEFTSHIFT='<<' - - -# -# Convert an IP address in dot quad format to an integer -# -decodeaddr() { - local x - local temp=0 - local ifs=$IFS - - IFS=. - - for x in $1; do - temp=$(( $(( $temp $LEFTSHIFT 8 )) | $x )) - done - - echo $temp - - IFS=$ifs -} - -# -# convert an integer to dot quad format -# -encodeaddr() { - addr=$1 - local x - local y=$(($addr & 255)) - - for x in 1 2 3 ; do - addr=$(($addr >> 8)) - y=$(($addr & 255)).$y - done - - echo $y -} - -# -# Enumerate the members of an IP range -- When using a shell supporting only -# 32-bit signed arithmetic, the range cannot span 128.0.0.0. -# -# Comes in two flavors: -# -# ip_range() - produces a mimimal list of network/host addresses that spans -# the range. -# -# ip_range_explicit() - explicitly enumerates the range. -# -ip_range() { - local first last l x y z vlsm - - case $1 in - !*) - # - # Let iptables complain if it's a range - # - echo $1 - return - ;; - [0-9]*.*.*.*-*.*.*.*) - ;; - *) - echo $1 - return - ;; - esac - - first=$(decodeaddr ${1%-*}) - last=$(decodeaddr ${1#*-}) - - if [ $first -gt $last ]; then - fatal_error "Invalid IP address range: $1" - fi - - l=$(( $last + 1 )) - - while [ $first -le $last ]; do - vlsm= - x=31 - y=2 - z=1 - - while [ $(( $first % $y )) -eq 0 -a $(( $first + $y )) -le $l ]; do - vlsm=/$x - x=$(( $x - 1 )) - z=$y - y=$(( $y * 2 )) - done - - echo $(encodeaddr $first)$vlsm - first=$(($first + $z)) - done -} - -ip_range_explicit() { - local first last - - case $1 in - [0-9]*.*.*.*-*.*.*.*) - ;; - *) - echo $1 - return - ;; - esac - - first=$(decodeaddr ${1%-*}) - last=$(decodeaddr ${1#*-}) - - if [ $first -gt $last ]; then - fatal_error "Invalid IP address range: $1" - fi - - while [ $first -le $last ]; do - echo $(encodeaddr $first) - first=$(($first + 1)) - done -} - -# -# Netmask from CIDR -# -ip_netmask() { - local vlsm=${1#*/} - - [ $vlsm -eq 0 ] && echo 0 || echo $(( -1 $LEFTSHIFT $(( 32 - $vlsm )) )) -} - -# -# Network address from CIDR -# -ip_network() { - local decodedaddr=$(decodeaddr ${1%/*}) - local netmask=$(ip_netmask $1) - - echo $(encodeaddr $(($decodedaddr & $netmask))) -} - -# -# The following hack is supplied to compensate for the fact that many of -# the popular light-weight Bourne shell derivatives don't support XOR ("^"). -# - -ip_broadcast() { - local x=$(( 32 - ${1#*/} )) - - [ $x -eq 0 ] && echo -1 || echo $(( $(( 1 $LEFTSHIFT $x )) - 1 )) -} - -# -# Calculate broadcast address from CIDR -# -broadcastaddress() { - local decodedaddr=$(decodeaddr ${1%/*}) - local netmask=$(ip_netmask $1) - local broadcast=$(ip_broadcast $1) - - echo $(encodeaddr $(( $(($decodedaddr & $netmask)) | $broadcast ))) -} - -# -# Test for network membership -# -in_network() # $1 = IP address, $2 = CIDR network -{ - local netmask=$(ip_netmask $2) - - test $(( $(decodeaddr $1) & $netmask)) -eq $(( $(decodeaddr ${2%/*}) & $netmask )) -} - -# -# Netmask to VLSM -# -ip_vlsm() { - local mask=$(decodeaddr $1) - local vlsm=0 - local x=$(( 128 << 24 )) # 0x80000000 - - while [ $(( $x & $mask )) -ne 0 ]; do - [ $mask -eq $x ] && mask=0 || mask=$(( $mask $LEFTSHIFT 1 )) # Not all shells shift 0x80000000 left properly. - vlsm=$(($vlsm + 1)) - done - - if [ $(( $mask & 2147483647 )) -ne 0 ]; then # 2147483647 = 0x7fffffff - echo "Invalid net mask: $1" >&2 - else - echo $vlsm - fi -} - - -# -# Chain name base for an interface -- replace all periods with underscores in the passed name. -# The result is echoed (less trailing "+"). -# -chain_base() #$1 = interface -{ - local c=${1%%+} - - while true; do - case $c in - *.*) - c="${c%.*}_${c##*.}" - ;; - *-*) - c="${c%-*}_${c##*-}" - ;; - *%*) - c="${c%\%*}_${c##*%}" - ;; - *) - echo ${c:=common} - return - ;; - esac - done -} - -# -# Loosly Match the name of an interface -# - -if_match() # $1 = Name in interfaces file - may end in "+" - # $2 = Full interface name - may also end in "+" -{ - local pattern=${1%+} - - case $1 in - *+) - test "x$(echo $2 | truncate ${#pattern} )" = "x${pattern}" - ;; - *) - test "x$1" = "x$2" - ;; - esac -} - -# -# Source IP range -# -source_ip_range() # $1 = Address or Address Range -{ - [ $# -gt 0 ] && case $1 in - *.*.*.*-*.*.*.*) - case $1 in - !*) - iprange_echo "! --src-range ${1#!}" - ;; - *) - iprange_echo "--src-range $1" - ;; - esac - ;; - !+*) - echo "-m set ! $(get_set_flags ${1#!} src)" - ;; - +*) - echo "-m set $(get_set_flags $1 src)" - ;; - *) - echo "-s $1" - ;; - esac -} - -# -# Destination IP range -# -dest_ip_range() # $1 = Address or Address Range -{ - [ $# -gt 0 ] && case $1 in - *.*.*.*-*.*.*.*) - case $1 in - !*) - iprange_echo "! --dst-range ${1#!}" - ;; - *) - iprange_echo "--dst-range $1" - ;; - esac - ;; - !+*) - echo "-m set ! $(get_set_flags ${1#!} dst)" - ;; - +*) - echo "-m set $(get_set_flags $1 dst)" - ;; - *) - echo "-d $1" - ;; - esac -} - -both_ip_ranges() # $1 = Source address or range, $2 = dest address or range -{ - local rangeprefix= setprefix= rangematch= setmatch= - - case $1 in - *.*.*.*-*.*.*.*) - rangeprefix="-m iprange" - rangematch="--src-range $1" - ;; - !+*) - setprefix="-m set" - setmatch="! $(get_set_flags ${1#!} src)" - ;; - +*) - setprefix="-m set" - setmatch="$(get_set_flags $1 src)" - ;; - *) - rangematch="-s $1" - ;; - esac - - case $2 in - *.*.*.*-*.*.*.*) - rangeprefix="-m iprange" - rangematch="$rangematch --dst-range $2" - ;; - !+*) - setprefix="-m set" - match="$setmatch ! $(get_set_flags ${2#!} dst)" - ;; - +*) - setprefix="-m set" - setmatch="$setmatch $(get_set_flags $2 dst)" - ;; - *) - rangematch="$rangematch -d $2" - ;; - esac - - echo "$rangeprefix $rangematch $setprefix $setmatch" -} - -# -# Find the value 'dev' in the passed arguments then echo the next value -# - -find_device() { - while [ $# -gt 1 ]; do - [ "x$1" = xdev ] && echo $2 && return - shift - done -} - -# -# Find the value 'via' in the passed arguments then echo the next value -# - -find_gateway() { - while [ $# -gt 1 ]; do - [ "x$1" = xvia ] && echo $2 && return - shift - done -} - -# -# Find the value 'mtu' in the passed arguments then echo the next value -# - -find_mtu() { - while [ $# -gt 1 ]; do - [ "x$1" = xmtu ] && echo $2 && return - shift - done -} - -# -# Find the value 'peer' in the passed arguments then echo the next value up to -# "/" -# - -find_peer() { - while [ $# -gt 1 ]; do - [ "x$1" = xpeer ] && echo ${2%/*} && return - shift - done -} - -# -# Find the interfaces that have a route to the passed address - the default -# route is not used. -# - -find_rt_interface() { - ip route ls | while read addr rest; do - case $addr in - */*) - in_network ${1%/*} $addr && echo $(find_device $rest) - ;; - default) - ;; - *) - if [ "$addr" = "$1" -o "$addr/32" = "$1" ]; then - echo $(find_device $rest) - fi - ;; - esac - done -} - -# -# Try to find the gateway through an interface looking for 'nexthop' - -find_nexthop() # $1 = interface -{ - echo $(find_gateway `ip route ls | grep "[[:space:]]nexthop.* $1"`) -} - -# -# Find the default route's interface -# -find_default_interface() { - ip route ls | while read first rest; do - [ "$first" = default ] && echo $(find_device $rest) && return - done -} - -# -# Echo the name of the interface(s) that will be used to send to the -# passed address -# - -find_interface_by_address() { - local dev="$(find_rt_interface $1)" - local first rest - - [ -z "$dev" ] && dev=$(find_default_interface) - - [ -n "$dev" ] && echo $dev -} - -# -# Find the interface with the passed MAC address -# - -find_interface_by_mac() { - local mac=$1 first second rest dev - - ip link ls | while read first second rest; do - case $first in - *:) - dev=$second - ;; - *) - if [ "$second" = $mac ]; then - echo ${dev%:} - return - fi - esac - done -} - -# -# Find interface address--returns the first IP address assigned to the passed -# device -# -find_first_interface_address() # $1 = interface -{ - # - # get the line of output containing the first IP address - # - addr=$(ip -f inet addr show $1 2> /dev/null | grep 'inet .* global' | head -n1) - # - # If there wasn't one, bail out now - # - [ -n "$addr" ] || fatal_error "Can't determine the IP address of $1" - # - # Strip off the trailing VLSM mask (or the peer IP in case of a P-t-P link) - # along with everything else on the line - # - echo $addr | sed 's/\s*inet //;s/\/.*//;s/ peer.*//' -} - -find_first_interface_address_if_any() # $1 = interface -{ - # - # get the line of output containing the first IP address - # - addr=$(ip -f inet addr show $1 2> /dev/null | grep 'inet .* global' | head -n1) - # - # Strip off the trailing VLSM mask (or the peer IP in case of a P-t-P link) - # along with everything else on the line - # - [ -n "$addr" ] && echo $addr | sed 's/\s*inet //;s/\/.*//;s/ peer.*//' || echo 0.0.0.0 -} - -# -# Find interface addresses--returns the set of addresses assigned to the passed -# device -# -find_interface_addresses() # $1 = interface -{ - ip -f inet addr show $1 | grep inet\ | sed 's/\s*inet //;s/\/.*//;s/ peer.*//' -} - -# -# echo the list of networks routed out of a given interface -# -get_routed_networks() # $1 = interface name -{ - local address - local rest - - ip route show dev $1 2> /dev/null | - while read address rest; do - if [ "x$address" = xdefault ]; then - if [ $# -gt 1 ]; then - shift - fatal_error "$@" - else - "WARNING: default route ignored on interface $1" - fi - else - [ "$address" = "${address%/*}" ] && address="${address}/32" - echo $address - fi - done -} - -# -# Internal version of 'which' -# -mywhich() { - local dir - - for dir in $(split $PATH); do - if [ -x $dir/$1 ]; then - echo $dir/$1 - return 0 - fi - done - - return 2 -} - -# -# Set the Shorewall state -# -set_state () # $1 = state -{ - echo "$1 ($(date))" > ${VARDIR}/state -} - -# -# Determine which optional facilities are supported by iptables/netfilter -# -determine_capabilities() { - qt $IPTABLES -t nat -L -n && NAT_ENABLED=Yes || NAT_ENABLED= - qt $IPTABLES -t mangle -L -n && MANGLE_ENABLED=Yes || MANGLE_ENABLED= - - CONNTRACK_MATCH= - MULTIPORT= - XMULTIPORT= - POLICY_MATCH= - PHYSDEV_MATCH= - IPRANGE_MATCH= - RECENT_MATCH= - OWNER_MATCH= - IPSET_MATCH= - CONNMARK= - XCONNMARK= - CONNMARK_MATCH= - XCONNMARK_MATCH= - RAW_TABLE= - IPP2P_MATCH= - LENGTH_MATCH= - CLASSIFY_TARGET= - ENHANCED_REJECT= - USEPKTTYPE= - KLUDGEFREE= - MARK= - XMARK= - MANGLE_FORWARD= - - qt $IPTABLES -N fooX1234 - qt $IPTABLES -A fooX1234 -m conntrack --ctorigdst 192.168.1.1 -j ACCEPT && CONNTRACK_MATCH=Yes - qt $IPTABLES -A fooX1234 -p tcp -m multiport --dports 21,22 -j ACCEPT && MULTIPORT=Yes - qt $IPTABLES -A fooX1234 -p tcp -m multiport --dports 21:22 -j ACCEPT && XMULTIPORT=Yes - qt $IPTABLES -A fooX1234 -m policy --pol ipsec --mode tunnel --dir in -j ACCEPT && POLICY_MATCH=Yes - - if qt $IPTABLES -A fooX1234 -m physdev --physdev-in eth0 -j ACCEPT; then - PHYSDEV_MATCH=Yes - fi - - if qt $IPTABLES -A fooX1234 -m iprange --src-range 192.168.1.5-192.168.1.124 -j ACCEPT; then - IPRANGE_MATCH=Yes - if [ -z "${KLUDGEFREE}" ]; then - qt $IPTABLES -A fooX1234 -m iprange --src-range 192.168.1.5-192.168.1.124 -m iprange --dst-range 192.168.1.5-192.168.1.124 -j ACCEPT && KLUDGEFREE=Yes - fi - fi - - qt $IPTABLES -A fooX1234 -m recent --update -j ACCEPT && RECENT_MATCH=Yes - qt $IPTABLES -A fooX1234 -m owner --uid-owner 0 -j ACCEPT && OWNER_MATCH=Yes - - if qt $IPTABLES -A fooX1234 -m connmark --mark 2 -j ACCEPT; then - CONNMARK_MATCH=Yes - qt $IPTABLES -A fooX1234 -m connmark --mark 2/0xFF -j ACCEPT && XCONNMARK_MATCH=Yes - fi - - qt $IPTABLES -A fooX1234 -p tcp -m ipp2p --ipp2p -j ACCEPT && IPP2P_MATCH=Yes - qt $IPTABLES -A fooX1234 -m length --length 10:20 -j ACCEPT && LENGTH_MATCH=Yes - qt $IPTABLES -A fooX1234 -j REJECT --reject-with icmp-host-prohibited && ENHANCED_REJECT=Yes - - if [ -n "$MANGLE_ENABLED" ]; then - qt $IPTABLES -t mangle -N fooX1234 - - if qt $IPTABLES -t mangle -A fooX1234 -j MARK --set-mark 1; then - MARK=Yes - qt $IPTABLES -t mangle -A fooX1234 -j MARK --and-mark 0xFF && XMARK=Yes - fi - - if qt $IPTABLES -t mangle -A fooX1234 -j CONNMARK --save-mark; then - CONNMARK=Yes - qt $IPTABLES -t mangle -A fooX1234 -j CONNMARK --save-mark --mask 0xFF && XCONNMARK=Yes - fi - - qt $IPTABLES -t mangle -A fooX1234 -j CLASSIFY --set-class 1:1 && CLASSIFY_TARGET=Yes - qt $IPTABLES -t mangle -F fooX1234 - qt $IPTABLES -t mangle -X fooX1234 - qt $IPTABLES -t mangle -L FORWARD -n && MANGLE_FORWARD=Yes - fi - - qt $IPTABLES -t raw -L -n && RAW_TABLE=Yes - - if qt mywhich ipset; then - qt ipset -X fooX1234 # Just in case something went wrong the last time - - if qt ipset -N fooX1234 iphash ; then - if qt $IPTABLES -A fooX1234 -m set --set fooX1234 src -j ACCEPT; then - qt $IPTABLES -D fooX1234 -m set --set fooX1234 src -j ACCEPT - IPSET_MATCH=Yes - fi - qt ipset -X fooX1234 - fi - fi - - qt $IPTABLES -A fooX1234 -m pkttype --pkt-type broadcast -j ACCEPT && USEPKTTYPE=Yes - - qt $IPTABLES -F fooX1234 - qt $IPTABLES -X fooX1234 -} - -report_capabilities() { - report_capability() # $1 = Capability Description , $2 Capability Setting (if any) - { - local setting= - - [ "x$2" = "xYes" ] && setting="Available" || setting="Not available" - - echo " " $1: $setting - } - - if [ $VERBOSE -gt 1 ]; then - echo "Shorewall has detected the following iptables/netfilter capabilities:" - report_capability "NAT" $NAT_ENABLED - report_capability "Packet Mangling" $MANGLE_ENABLED - report_capability "Multi-port Match" $MULTIPORT - [ -n "$MULTIPORT" ] && report_capability "Extended Multi-port Match" $XMULTIPORT - report_capability "Connection Tracking Match" $CONNTRACK_MATCH - report_capability "Packet Type Match" $USEPKTTYPE - report_capability "Policy Match" $POLICY_MATCH - report_capability "Physdev Match" $PHYSDEV_MATCH - report_capability "Packet length Match" $LENGTH_MATCH - report_capability "IP range Match" $IPRANGE_MATCH - report_capability "Recent Match" $RECENT_MATCH - report_capability "Owner Match" $OWNER_MATCH - report_capability "Ipset Match" $IPSET_MATCH - report_capability "CONNMARK Target" $CONNMARK - [ -n "$CONNMARK" ] && report_capability "Extended CONNMARK Target" $XCONNMARK - report_capability "Connmark Match" $CONNMARK_MATCH - [ -n "$CONNMARK_MATCH" ] && report_capability "Extended Connmark Match" $XCONNMARK_MATCH - report_capability "Raw Table" $RAW_TABLE - report_capability "IPP2P Match" $IPP2P_MATCH - report_capability "CLASSIFY Target" $CLASSIFY_TARGET - report_capability "Extended REJECT" $ENHANCED_REJECT - report_capability "Repeat match" $KLUDGEFREE - report_capability "MARK Target" $MARK - [ -n "$MARK" ] && report_capability "Extended MARK Target" $XMARK - report_capability "Mangle FORWARD Chain" $MANGLE_FORWARD - fi - - [ -n "$PKTTYPE" ] || USEPKTTYPE= - -} - -report_capabilities1() { - report_capability1() # $1 = Capability - { - eval echo $1=\$$1 - } - - echo "#" - echo "# Shorewall $VERSION detected the following iptables/netfilter capabilities - $(date)" - echo "#" - report_capability1 NAT_ENABLED - report_capability1 MANGLE_ENABLED - report_capability1 MULTIPORT - report_capability1 XMULTIPORT - report_capability1 CONNTRACK_MATCH - report_capability1 USEPKTTYPE - report_capability1 POLICY_MATCH - report_capability1 PHYSDEV_MATCH - report_capability1 LENGTH_MATCH - report_capability1 IPRANGE_MATCH - report_capability1 RECENT_MATCH - report_capability1 OWNER_MATCH - report_capability1 IPSET_MATCH - report_capability1 CONNMARK - report_capability1 XCONNMARK - report_capability1 CONNMARK_MATCH - report_capability1 XCONNMARK_MATCH - report_capability1 RAW_TABLE - report_capability1 IPP2P_MATCH - report_capability1 CLASSIFY_TARGET - report_capability1 ENHANCED_REJECT - report_capability1 KLUDGEFREE - report_capability1 MARK - report_capability1 XMARK - report_capability1 MANGLE_FORWARD -} - -# -# Delete IP address -# -del_ip_addr() # $1 = address, $2 = interface -{ - [ $(find_first_interface_address_if_any $2) = $1 ] || qt ip addr del $1 dev $2 -} - -# Add IP Aliases -# -add_ip_aliases() # $* = List of addresses -{ - local addresses external interface inet cidr rest val arping=$(mywhich arping) - - address_details() - { - # - # Folks feel uneasy if they don't see all of the same - # decoration on these IP addresses that they see when their - # distro's net config tool adds them. In an attempt to reduce - # the anxiety level, we have the following code which sets - # the VLSM and BRD from an existing address in the same networks - # - # Get all of the lines that contain inet addresses with broadcast - # - ip -f inet addr show $interface 2> /dev/null | grep 'inet.*brd' | while read inet cidr rest ; do - case $cidr in - */*) - if in_network $external $cidr; then - echo "/${cidr#*/} brd $(broadcastaddress $cidr)" - break - fi - ;; - esac - done - } - - do_one() - { - val=$(address_details) - - ip addr add ${external}${val} dev $interface $label - [ -n "$arping" ] && qt $arping -U -c 2 -I $interface $external - echo "$external $interface" >> $STATEDIR/nat - [ -n "$label" ] && label="with $label" - progress_message " IP Address $external added to interface $interface $label" - } - - progress_message "Adding IP Addresses..." - - while [ $# -gt 0 ]; do - external=$1 - interface=$2 - label= - - if [ "$interface" != "${interface%:*}" ]; then - label="${interface#*:}" - interface="${interface%:*}" - label="label $interface:$label" - fi - - shift 2 - - list_search $external $(find_interface_addresses $interface) || do_one - done -} - -detect_gateway() # $1 = interface -{ - local interface=$1 - # - # First assume that this is some sort of point-to-point interface - # - gateway=$( find_peer $(ip addr ls $interface ) ) - # - # Maybe there's a default route through this gateway already - # - [ -n "$gateway" ] || gateway=$(find_gateway $(ip route ls dev $interface)) - # - # Last hope -- is there a load-balancing route through the interface? - # - [ -n "$gateway" ] || gateway=$(find_nexthop $interface) - # - # Be sure we found one - # - [ -n "$gateway" ] && echo $gateway -} - -# -# Disable IPV6 -# -disable_ipv6() { - local foo="$(ip -f inet6 addr ls 2> /dev/null)" - - if [ -n "$foo" ]; then - if qt mywhich ip6tables; then - ip6tables -P FORWARD DROP - ip6tables -P INPUT DROP - ip6tables -P OUTPUT DROP - ip6tables -F - ip6tables -X - ip6tables -A OUTPUT -o lo -j ACCEPT - ip6tables -A INPUT -i lo -j ACCEPT - else - error_message "WARNING: DISABLE_IPV6=Yes in shorewall.conf but this system does not appear to have ip6tables" - fi - fi -} - -# -# Add a logging rule. -# -log_rule_limit() # $1 = log level, $2 = chain, $3 = display Chain $4 = disposition , $5 = rate limit $6=log tag $7=command $... = predicates for the rule -{ - local level=$1 - local chain=$2 - local displayChain=$3 - local disposition=$4 - local rulenum= - local limit= - local tag=${6:+$6 } - local command=${7:--A} - local prefix - local base=$(chain_base $displayChain) - - limit="${5:-$LOGLIMIT}" # Do this here rather than in the declaration above to appease /bin/ash. - - shift 7 - - if [ -n "$tag" -a -n "$LOGTAGONLY" ]; then - displayChain=$tag - tag= - fi - - if [ -n "$LOGRULENUMBERS" ]; then - eval rulenum=\$${base}_logrules - - rulenum=${rulenum:-1} - - prefix="$(printf "$LOGFORMAT" $displayChain $rulenum $disposition)${tag}" - - rulenum=$(($rulenum + 1)) - eval ${base}_logrules=$rulenum - else - prefix="$(printf "$LOGFORMAT" $displayChain $disposition)${tag}" - fi - - if [ ${#prefix} -gt 29 ]; then - prefix="$(echo $prefix | truncate 29)" - error_message "WARNING: Log Prefix shortened to \"$prefix\"" - fi - - [ "$COMMAND" = compile ] && prefix="\"$prefix\"" - - case $level in - ULOG) - run_iptables $command $chain $@ $limit -j ULOG $LOGPARMS --ulog-prefix "$prefix" - ;; - *) - run_iptables $command $chain $@ $limit -j LOG $LOGPARMS --log-level $level --log-prefix "$prefix" - ;; - esac - - if [ $? -ne 0 ] ; then - [ -z "$STOPPING" ] && { stop_firewall; exit 2; } - fi -} - -log_rule() # $1 = log level, $2 = chain, $3 = disposition , $... = predicates for the rule -{ - local level=$1 - local chain=$2 - local disposition=$3 - - shift 3 - - log_rule_limit $level $chain $chain $disposition "$LOGLIMIT" "" -A $@ -} - -# -# Check that a mark value or mask is less that 256 or that it is less than 65536 and -# that it's lower 8 bits are zero. -# -verify_mark() # $1 = value to test -{ - verify_mark2() - { - case $1 in - 0*) - [ $(($1)) -lt 256 ] && return 0 - [ -n "$HIGH_ROUTE_MARKS" ] || return 1 - [ $(($1)) -gt 65535 ] && return 1 - return $(($1 & 0xFF)) - ;; - [1-9]*) - [ $1 -lt 256 ] && return 0 - [ -n "$HIGH_ROUTE_MARKS" ] || return 1 - [ $1 -gt 65535 ] && return 1 - return $(($1 & 0xFF)) - ;; - *) - return 2 - ;; - esac - } - - verify_mark2 $1 || fatal_error "Invalid Mark or Mask value: $1" -} - -# -# Detect a device's MTU -# -get_device_mtu() # $1 = device -{ - local output="$(ip link ls dev $1 2> /dev/null)" # quotes required for /bin/ash - - if [ -n "$output" ]; then - echo $(find_mtu $output) - else - echo 1500 - fi -} - SHOREWALL_LIBRARY=Loaded -for lib in ${SHAREDIR}/lib.*; do - case $lib in - ${SHAREDIR}/lib.\*) +if [ $# -gt 0 ]; then + # + # Load a specific set of libraries + # + for lib in $@; do + . ${SHAREDIR}/lib.${lib} + done +else + for lib in ${SHAREDIR}/lib.*; do + case $lib in + ${SHAREDIR}/lib.\*) + echo " ERROR: ${SHAREDIR}/lib.\* not found" >&2 + exit 2 ;; - *) - . $clib - ;; - esac -done + *) + . $lib + ;; + esac + done +fi diff --git a/Shorewall/shorewall b/Shorewall/shorewall index ea3bfd0ca..45da9d0e7 100755 --- a/Shorewall/shorewall +++ b/Shorewall/shorewall @@ -1681,11 +1681,12 @@ FIREWALL=$SHAREDIR/firewall FUNCTIONS=$SHAREDIR/functions VERSION_FILE=$SHAREDIR/version HELP=$SHAREDIR/help +LIBRARIES="base" if [ -f $FUNCTIONS ]; then - . $FUNCTIONS + . $FUNCTIONS $LIBRARIES else - echo "$FUNCTIONS does not exist!" >&2 + echo " ERROR: $FUNCTIONS does not exist!" >&2 exit 2 fi