home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / rescue / etc / sysconfig / network / scripts / ifup-route < prev    next >
Text File  |  2006-11-29  |  17KB  |  492 lines

  1. #! /bin/bash
  2. # Copyright (c) 2002 SuSE Linux AG Nuernberg, Germany. All rights reserved.
  3. # This program is free software; you can redistribute it and/or modify it under
  4. # the terms of the GNU General Public License as published by the Free Software
  5. # Foundation; either version 2 of the License, or (at your option) any later
  6. # version.
  7. #
  8. # This program is distributed in the hope that it will be useful, but WITHOUT
  9. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  10. # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  11. # details.
  12. #
  13. # You should have received a copy of the GNU General Public License along with
  14. # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  15. # Place, Suite 330, Boston, MA 02111-1307 USA
  16. #
  17. # Author: Christian Zoz <zoz@suse.de>, 2002
  18. # Based on rcroute: Burchard Steinbild <bs@suse.de>, 1996
  19. #                   Werner Fink <werner@suse.de>, 1996-2000
  20. #
  21. # $Id: ifup-route 1382 2006-01-30 18:20:31Z zoz $
  22. #
  23.  
  24. usage () {
  25.     echo $@
  26.     echo "Usage: if{up,down,status}-route [<config>] <hwdesc> [-o <options>]"
  27.     echo "  hwdesc may be the interface name or any valid description"
  28.     echo "  of the corresponding device, for details see ifup(8)."
  29.     echo "Options are:"
  30.     echo "    dhcp     : we are called from dhcp client (read only ifroute-*)" 
  31.     echo "All other or wrong options are silently ignored"
  32.     exit $R_USAGE
  33. }
  34.  
  35. ######################################################################
  36. # change the working direcory and source some common files
  37. #
  38. R_INTERNAL=1      # internal error, e.g. no config or missing scripts
  39. cd /etc/sysconfig/network || exit $R_INTERNAL
  40. test -f ./config && . ./config
  41. test -f scripts/functions && . scripts/functions || exit $R_INTERNAL
  42.  
  43. ######################################################################
  44. # check arguments and how we are called (in case of links)
  45. #
  46. SCRIPTNAME=${0##*/}
  47. debug $*
  48. case "$SCRIPTNAME" in
  49.     ifup-route) ACTION=replace ;;
  50.     ifdown-route) ACTION=del ;;
  51.     ifstatus-route) ACTION=status ;;
  52.     *) usage
  53. esac
  54. INTERFACE=$1
  55. case "$INTERFACE" in ""|-h|*help*) usage; esac
  56. shift
  57. if [ -n "$1" -a "$1" != "-o" ] ; then
  58.     CONFIG=$INTERFACE
  59.     INTERFACE=$1
  60. fi
  61. shift
  62. test "$1" = "-o" && shift
  63. OPTIONS="$@"
  64. MODE=manual
  65. while [ $# -gt 0 ]; do
  66.     case $1 in
  67.         boot|onboot) MODE=auto ;;
  68.         hotplug)     MODE=auto ;;
  69.         rc)          export RUN_FROM_RC=yes
  70.                      SUPPRESS_ERROR_MESSAGE=yes ;;
  71.         quiet)       be_quiet_has_gone ;;
  72.         debug)       DEBUG=yes ;;
  73.         dhcp)        DHCP=yes ;;
  74.         *)           debug "unknown option $1 ignored" ;;
  75.     esac
  76.     shift
  77. done
  78.  
  79. ######################################################################
  80. # get the interface and check if it is up
  81. # There are some exceptions where we do not have an active interface:
  82. # - when adding/deleting special routes (INTERFACE == 'noiface')
  83. # - when deleting routes of an already unplugged hotplug device:
  84. #   we have possibly to restore an old default route in this case
  85. #
  86. if ! is_iface_up $INTERFACE && [ "$INTERFACE" != noiface ] ; then
  87.     # This is a quick fix, don't know if it has drawbacks
  88.     # if [ "$ACTION" = del -a "$MODE" = auto ] ; then
  89.     if [ "$ACTION" = del ] ; then
  90.         REPLACE_ONLY=yes
  91.     else
  92.         logerror "interface $INTERFACE is not up"
  93.         exit $R_NOTRUNNING
  94.     fi
  95. fi
  96.  
  97. ######################################################################
  98. # check presence of configuration files and source one 
  99. #
  100. test -f ./ifcfg-$CONFIG && . ./ifcfg-$CONFIG
  101. # The global route configuration file must not be read if we were called from
  102. # dhcp client. In this case we only read the ifroute-* file.
  103. if [ "$DHCP" != yes ] ; then
  104.     ROUTECONF=routes
  105. fi
  106. test -f $ROUTECONF || ROUTECONF=""
  107. EXTRAROUTECONF=ifroute-$CONFIG
  108. test -f $EXTRAROUTECONF || EXTRAROUTECONF=""
  109.  
  110. #
  111. # add special link local route
  112. # can configure only one interface this way at the moment
  113. #
  114. EXTRALINKLOCAL=
  115. islinklocal=
  116. if test -n "$LINKLOCAL_INTERFACES" ; then
  117.         eval "case \$INTERFACE in $LINKLOCAL_INTERFACES) islinklocal=true ;; esac"
  118. fi
  119. # Don't add this route if interface has no v4 address (Bug 65557)
  120. test -z "`ip -4 a l dev $INTERFACE 2>/dev/null`" && islinklocal=
  121. if test -n "$islinklocal" ; then
  122.         current=`ip route show 169.254.0.0/16`
  123.         if test -z "$current" -o "$current" != "${current/ dev $INTERFACE }" ; then
  124.                 EXTRALINKLOCAL="169.254.0.0 - 255.255.0.0 $INTERFACE"
  125.         fi
  126. fi
  127.  
  128. # Having no routing configuration file is no error
  129. test -z "${ROUTECONF}${EXTRAROUTECONF}${EXTRALINKLOCAL}" && exit $R_SUCCESS
  130.  
  131.  
  132. reverse ()
  133. {
  134.     local LINE
  135.     while read -r LINE ; do
  136.         case "$LINE" in \#*|"") continue ;; esac
  137.         test "$ACTION" = "del" && reverse
  138.         echo "$LINE"
  139.     done
  140. }
  141.  
  142. run_iproute() {
  143.     test "$REPLACE_ONLY" = yes -a "$1" != replace && return
  144.     local COMMAND="ip route $@"
  145.     RETMESSAGE="$($COMMAND 2>&1)"
  146.     RETVALUE=$?
  147.     if test $RETVALUE -ne 0 ; then
  148.         debug "calling: $COMMAND  ---> FAILED"
  149.         case "$RETMESSAGE" in
  150.             RTNETLINK*answers:*File*exists) return ;;
  151.             RTNETLINK*answers:*No*such*process) return;;
  152.             RTNETLINK*answers:*Network*is*unreachable)
  153.                 if [ "$3" = default -a "$7" != "$INTERFACE" ] ; then
  154.                     eval \
  155.                     logerror "Warning: Could not set up default route via interface" \
  156.                         "$INTERFACEi\\\n" \
  157.                         " Command '$COMMAND' returned:\\\n . \"${RETMESSAGE%%Usage:*}\"\\\n"\
  158.                         " Configuration line: $LINE\\\n" \
  159.                         " This needs NOT to be AN ERROR if you set up multiple" \
  160.                         "interfaces.\\\n  See 'man 5 routes' how to avoid this warning.\\\n" \
  161.                         ${SUPPRESS_ERROR_MESSAGE:+>/dev/null}
  162.                     return 
  163.                 fi
  164.                 ;;
  165.             *)
  166.         esac
  167. #        logerror "\033[1mError while executing:\n  $COMMAND\033[m"
  168.         logerror "Error while executing:\n" \
  169.                  "  Command '$COMMAND' returned:\n  ${RETMESSAGE%%Usage:*}\n"\
  170.                  "  Configuration line: $LINE"
  171.     else
  172.         debug "calling: $COMMAND  ---> OK"
  173.     fi
  174. }
  175.  
  176. wrong_entry ()
  177. {
  178.     logerror "\033[1mWrong entry in $ROUTECONF\033[m"
  179.     logerror "  $@"
  180. }
  181.  
  182. ROUTESTACKDIR=$RUN_FILES_BASE
  183.  
  184. push_route_stack () {
  185.     pushd $ROUTESTACKDIR &>/dev/null || return
  186.     if [ "$OLDDEFROUTEIFACE" != "$INTERFACE" ] ; then
  187.         declare -i i
  188.         test -r route-stack-number && read i < route-stack-number
  189.         i=$((i+1))
  190.         echo $i > route-stack-number
  191.         ii=`printf "%.6d\n" $i`
  192.         echo $OLDDEFROUTEARGS > route-stack-$ii-${OLDDEFROUTEIFACE}-${INTERFACE}
  193.     fi
  194.     popd &>/dev/null
  195. }
  196.  
  197. pop_route_stack () {
  198.     # The default route stack consists of files named route-stack-<i>-<X>-<Y>.
  199.     # If the topmost entry (with highest i) has for Y the current interface, then
  200.     # the current interface hosts the current default route. We can look for the
  201.     # current default route interface via 'ip route', but in one case thsi does not
  202.     # work. 
  203.     # NICs that are handled by '/sbin/hotplug' (cardmgr behaves different) loose
  204.     # their registered interface immediately when the NIC is ejected. Therefore
  205.     # we must get the name of the current default route interface from the stack
  206.     # itself and not via 'ip route'.
  207.  
  208.     local f g # variables for route-stack-* filenames
  209.  
  210.     # At first look for the current default route interface via 'ip route' and store
  211.     # it in $DR_IFACE.
  212.     set -- `ip route` 
  213.     while [ "$1" != default -a $# -gt 0 ] ; do shift; done
  214.     while [ "$1" != dev -a $# -gt 0 ] ; do shift; done
  215.     DR_IFACE=$2
  216.     if [ -z "$DR_IFACE" ] ; then
  217.         # Get the latest stack entry (with highest number)
  218.         for f in $ROUTESTACKDIR/route-stack-*-*-* ; do true; done
  219.         IFS=-; set -- $f; DR_IFACE=$5; unset IFS
  220.     fi
  221.     # If $DR_IFACE equals $INTERFACE we have to restore the previous default
  222.     # route. That means we look for the newest route-stack-X-$INTERFACE (which in
  223.     # this case should be the newest route-stack-X-*). This file may be deleted
  224.     # after the default route via dev X was restored.
  225.     # 
  226.     # Then we look for the newest route-stack-$INTERFACE-X and again for the now
  227.     # newest route-stack-Y-$INTERFACE. If X==Y these files may just be deleted.
  228.     # If X!=Y and there  is no route-stack-Y-X we have to copy
  229.     # route-stack-Y-$INTERFACE to route-stack-Y-X and delete the two old files
  230.     # afterwards.
  231.     # Repeat that until no more route-stack-*-$INTERFACE exists.
  232.     #
  233.     # Finally remove all route-stack-$INTERFACE-*.
  234.     #
  235.     if [ "$DR_IFACE" = "$INTERFACE" ] ; then
  236.         local restore_nullglob="$(shopt -p nullglob)"
  237.         shopt -s nullglob
  238.         for f in $ROUTESTACKDIR/route-stack-*-*-${INTERFACE} ; do true; done
  239.         eval $restore_nullglob
  240.         IFS=-; set -- $f; OLDDEFROUTEIFACE=$4; unset IFS
  241.         read OLDDEFROUTEARGS < ${f:-<(echo)}
  242.         debug `rm -vf $f 2>&1`
  243.     fi
  244.     while true ; do 
  245.         for f in $ROUTESTACKDIR/route-stack-*-*-${INTERFACE} ; do true; done
  246.         for g in $ROUTESTACKDIR/route-stack-*-${INTERFACE}-* ; do true; done
  247.         test -f "$f" -a -f "$g" || break
  248.         IFS=-
  249.         set -- $f ; fi=$4
  250.         set -- $g ; gi=$5
  251.         unset IFS
  252.         if [ "$fi" != "$gi" ] ; then
  253.             declare -i i
  254.             read i < $ROUTESTACKDIR/route-stack-number
  255.             i=$((i+1))
  256.             echo $i > $ROUTESTACKDIR/route-stack-number
  257.             ii=`printf "%.6d\n" $i`
  258.             cp -v $f $ROUTESTACKDIR/route-stack-$ii-${fi}-${gi}
  259.         fi
  260.         rm -vf $f $g
  261.     done
  262.     debug `rm -vf $ROUTESTACKDIR/route-stack-*-${INTERFACE}-*`
  263.     debug "PRS: OLDDEFROUTEIFACE=$OLDDEFROUTEIFACE"
  264.     debug "PRS: OLDDEFROUTEARGS=$OLDDEFROUTEARGS"
  265.     test -z "$OLDDEFROUTEARGS"    && return 1
  266.     test -z "$OLDDEFROUTEIFACE"   && return
  267.     is_iface_up $OLDDEFROUTEIFACE && return || return 1
  268. }
  269.  
  270. get_default_route() {
  271.     local DEST VIA GWAY DEV IFACE IPOPTS
  272.     while read DEST VIA GWAY DEV IFACE IPOPTS; do
  273.         # $DEST can be one of unreachable|blackhole|prohibit|throw
  274.         if [    \( "$DEST" = default -a "$DEV" = dev \) \
  275.              -o \( "$VIA"  = default -a -z "$GWAY$DEV$IFACE$IPOPTS" \) ] ; then
  276.             OLDDEFROUTEARGS="$DEST $VIA $GWAY $DEV $IFACE $IPOPTS"
  277.             OLDDEFROUTEIFACE=$IFACE
  278.             return
  279.         fi
  280.     done < <(ip route show)
  281.     return 1
  282. }
  283.  
  284. read_routes() {
  285.     test -r "$1" || return
  286.     local DEST GWAY MASK IFACE IPOPTS
  287.     while read DEST GWAY MASK IFACE IPOPTS; do 
  288.         test -z "$GWAY" && GWAY=-
  289.         test -z "$MASK" && MASK=-
  290.         test -z "$IFACE" -o "$IFACE" = "-" && IFACE="$INTERFACE"
  291.         echo $DEST $GWAY $MASK $IFACE $IPOPTS
  292.     done < $1 
  293. }
  294.  
  295. # for status we need to prepare the output of ip route and store it in
  296. # ALL_ROUTES. IFACE_ROUTES is needed to list active routes of 'noiface'.
  297. if [ "$ACTION" = status ] ; then
  298.     while read DEST VIA GWAY DEV IFACE IPOPTS; do
  299.         LINE="$DEST $VIA $GWAY $DEV $IFACE $IPOPTS"
  300.         # routes to the local net and blocking routes are listed in a different way
  301.         if [ "$VIA" = dev ] ; then
  302.             IPOPTS="$DEV $IFACE $IPOPTS"
  303.             IFACE=$GWAY
  304.             GWAY=""
  305.         fi
  306.         if [ "$INTERFACE" = noiface ] ; then
  307.             test -z "$IFACE" && IFACE_ROUTES="${IFACE_ROUTES:+$IFACE_ROUTES\n}  $LINE"
  308.         fi
  309.         case $DEST in
  310.             unreachable|blackhole|prohibit|throw)
  311.                 ALL_ROUTES="$ALL_ROUTES ${VIA}:::${DEST}" ;;
  312.             *)
  313.                 ALL_ROUTES="$ALL_ROUTES ${DEST}:${GWAY}:${IFACE}:" ;;
  314.         esac
  315.     done < <(ip route show)
  316.  
  317.     declare -i n=0 m=0
  318. fi
  319.  
  320. while read DEST GWAY MASK IFACE TYPE IPOPTS ; do
  321.     # Save the original line for error reporting
  322.     LINE="$DEST $GWAY $MASK $IFACE $TYPE $IPOPTS"
  323.     # debug routeconfigline: $LINE
  324.     test "$GWAY" = "-" && GWAY=""
  325.     test "$MASK" = "-" && MASK=""
  326.     test "$IFACE" = "-" && IFACE=""
  327.     test "$TYPE" = "-" && TYPE=""
  328.     
  329.     # If we are setting up a route for 6to4 tunnel we must
  330.     # differentiate between USAGI and non-USAGI stack as they
  331.     # accept gateway addresses in different notations.
  332.     # What is ::192.88.99.1 for non-USAGI kernel must 
  333.     # be written as 2002:c058:6301::1 for USAGI.
  334.     if [ "$TUNNEL" = "sit" -a "$BOOTPROTO" = "6to4" ]; then
  335.         if [ ! -f /proc/net/inet6_version ]; then
  336.             # This is non-USAGI kernel.
  337.             # If the IPv6 gateway is set to 2002:IPV4:ADDR::1
  338.             # we must convert it to ::IP.V4.AD.DR
  339.             test "x$GWAY" != "x${GWAY#2002:}" && \
  340.                 GWAY=`convert_6to4_to_ipv4address $GWAY`
  341.         else
  342.             # This is a USAGI kernel.
  343.             # If IPv6 gateway is set as ::IP.V4.AD.DR we must 
  344.             # convert it to 2002:IPV4:ADDR::1
  345.             test "x$GWAY" != "x${GWAY#::}" && \
  346.                 GWAY=`convert_ipv4address_to_6to4 ${GWAY#::}`
  347.         fi
  348.     fi
  349.  
  350.     # There are routes assigned to a certain interface and general routes. We
  351.     # only set up routes that match the current interface. General routes are
  352.     # only set up when we are called with the interface name 'noiface'.
  353.     # Only exception is the default route, which is set up with the current
  354.     # interface if no interface was specified in the configuration
  355.     if [ -n "$IFACE" ] ; then
  356.         IFACE=`/sbin/getcfg-interface -- $IFACE`
  357.         test "$INTERFACE" != "$IFACE" && continue
  358.     else
  359.         if [ "$DEST" = default ] ; then
  360.             case $INTERFACE in
  361.                 lo*|dummy*|noiface) continue ;;
  362.                 *) test "$ACTION" = del && IFACE=$INTERFACE ;;
  363.             esac
  364.         else
  365.             test "$INTERFACE" != noiface  && continue
  366.         fi
  367.     fi
  368.     # Check if $MASK is a netmask or prefixlength and calculate prefixlength if
  369.     # it is a netmask. Then add the prefixlength to the destination. Finally we
  370.     # get the prefixlength back from the destination to have always the right
  371.     # prefixlength in $PFXL.
  372.     if [ "$MASK" -ge 0 -a "$MASK" -le 32 ] 2>/dev/null; then
  373.         PFXL=$MASK
  374.     else
  375.         PFXL=`mask2pfxlen $MASK`
  376.     fi
  377.     test "${DEST%%/*}" = "$DEST" && DEST="$DEST${PFXL:+/$PFXL}"
  378.     test "${DEST#*/}" != "$DEST" && PFXL=${DEST#*/}
  379.  
  380.     # If the first word of the options ($TYPE) is a value that is respected
  381.     # as an valid type by ip route, then keep it. If $TYPE is anything else
  382.     # then it must be part of an ordinary option and we prepend it to $IPOPTS.
  383.     case $TYPE in
  384.         unicast|local|broadcast|nat|anycast|multicast) ;;
  385.         unreachable|blackhole|prohibit|throw)
  386.             IFACE="" 
  387.             ;;
  388.         *) IPOPTS="$TYPE $IPOPTS" ; TYPE="" ;;
  389.     esac
  390.  
  391.     case "$ACTION" in
  392.     replace|del)
  393.  
  394.         test -n "$IFACE" && IFACE="dev $IFACE"
  395.  
  396.         case "$DEST" in
  397.             \#*|"")
  398.                 ;;
  399.             224.0.0.0*|224/4)
  400.                 # We are doing multicast
  401.                 if [ -e /proc/net/igmp -a "$GWAY" = 0.0.0.0 \
  402.                      -a \( "$PFXL" = 4 -o "$DEST" = 224/4 \) ] ; then
  403.                     run_iproute $ACTION to $TYPE 224/4 $IFACE $IPOPTS
  404.                 else
  405.                     logerror "Skipping multicast route 224/4 for $IFACE"
  406.                     test ! -e /proc/net/igmp && logerror "    no /proc/net/igmp available"
  407.                     test "$GWAY" != 0.0.0.0 \
  408.                         && logerror "    wrong dummy gateway entry $GWAY in $ROUTECONF"
  409.                     test "$PFXL" != 4 \
  410.                         && logerror "    wrong netmask/prefixlength entry $MASK in $ROUTECONF"
  411.                 fi
  412.                 ;;
  413.             default*)
  414.                 if [ "$ACTION" != "del" ] ; then
  415.                     # I cannot remember why we were running run_iproute always after
  416.                     # the possible ip route command. But it hurts if there are two
  417.                     # interfaces in the same subnet which should get the default
  418.                     # route. Therefore we now run run_iproute only if ip route was
  419.                     # not run successfully. (See bug 49123)
  420.                     #get_default_route \
  421.                     #    && ip route $ACTION to $TYPE $DEST via $GWAY \
  422.                     #                ${INTERFACE:+dev $INTERFACE} $IPOPTS &>/dev/null \
  423.                     #        && push_route_stack
  424.                     #run_iproute $ACTION to $TYPE $DEST via $GWAY $IFACE $IPOPTS
  425.                     if get_default_route \
  426.                           && ip route $ACTION to $TYPE $DEST via $GWAY \
  427.                              ${INTERFACE:+dev $INTERFACE} $IPOPTS &>/dev/null ; then
  428.                         push_route_stack
  429.                     else
  430.                         run_iproute $ACTION to $TYPE $DEST via $GWAY $IFACE $IPOPTS
  431.                     fi
  432.                 fi
  433.                 if [ "$ACTION" = "del" ] ; then
  434.                     pop_route_stack && run_iproute replace to $OLDDEFROUTEARGS
  435.                 fi
  436.                 ;;
  437.             *)
  438.                 case "$GWAY" in
  439.                     0.0.0.0|\*)     # Add/Delete a local Network
  440.                         GWAY=""
  441.                         ;;
  442.                     $DEST)
  443.                         test "$PFXL" = 32 && GWAY=""
  444.                         ;;
  445.                 esac
  446.                 run_iproute $ACTION to $TYPE $DEST ${GWAY:+via $GWAY} $IFACE $IPOPTS
  447.         esac
  448.         ;;
  449.  
  450.     status)
  451.  
  452.         # To be able to compare destination later we possibly have to fill up $DEST
  453.         # with some '.0'. For this we have to seperate DIST and PFXL once again.
  454.         # Don't do that if $DEST = default ;)
  455.         if [ "$DEST" != default ] ; then
  456.             DEST=${DEST%%/*}
  457.             read D1 D2 D3 D4 < <(IFS=.; echo $DEST)
  458.             for a in D1 D2 D3 D4; do test -z "${!a}" && eval $a=0; done
  459.             DEST=$D1.$D2.$D3.$D4${PFXL:+/$PFXL}
  460.         fi
  461.  
  462.         case "$DEST" in \#*|"")  continue ;; esac
  463.         n=$((n + 1))
  464.         test $n = 1 && message_if_not_run_from_rc "Configured routes for interface $INTERFACE:"
  465.         message_if_not_run_from_rc "  $LINE"
  466.         for R in $ALL_ROUTES ; do
  467.             if test "$R" = "${DEST}:${GWAY}:${IFACE}:${TYPE}" ; then
  468.                 m=$((m + 1))
  469.             fi
  470.         done
  471.         ;;
  472.  
  473.     esac
  474.  
  475. done < <(reverse < <(${ROUTECONF:+cat $ROUTECONF}; \
  476.              ${EXTRALINKLOCAL:+echo $EXTRALINKLOCAL} ; \
  477.                      read_routes $EXTRAROUTECONF)  )
  478.  
  479. # Write a summary for status
  480. if [ "$ACTION" = status ] ; then
  481.     while read LINE; do
  482.         IFACE_ROUTES="${IFACE_ROUTES:+$IFACE_ROUTES\n}  $LINE"
  483.     done < <(ip route show dev $INTERFACE 2>/dev/null)
  484.     test -n "$IFACE_ROUTES" && message_if_not_run_from_rc "Active routes for interface $INTERFACE:"
  485.     message_if_not_run_from_rc "$IFACE_ROUTES"
  486.     test $n -gt 0  && \
  487.         message_if_not_run_from_rc "$m of $n configured routes for interface $INTERFACE up"
  488.     test $n -ne $m && exit 3
  489. fi
  490.  
  491. exit 0
  492.