Простой загрузчик таблицы маршрутизации, он же "пример на массивы"

BASH
Да, я в курсе, что есть некие другие средства для того, чтобы делать тоже самое.
Тем не менее, есть у меня некое подозрение, что мой скрипт делает это наиболее наглядным, прямолинейным и безопасным способом.
Собственно, он даже и вовсе ничего не меняет, он ведь просто «печатает» команды, которые нужно выполнить для того, чтобы привести текущую таблицу маршрутизации в полное соответствие с сохранённой. Сами команды пишутся на STDOUT, редкие отладочные сообщения — на STDERR.
Пользоваться можно так:

# ... save routing table anywhere ...
# route -n > /etc/sysconfig/saved-routed
# ... change routing table ...
# route-diff /etc/sysconfig/saved-routed
# ... analyze, what you see, and if all is ok, do the following ...
# source <(route-diff /etc/sysconfig/saved-routed 2>/dev/null)
# route -n

А скрипт вот такой:

#!/bin/bash
route_ () {
local action="$1" what gw netmask rt
declare -a rt
 if [[ $action == 'add' ]]; then
  rt=(${newRoute[$tgt]})
 else
  rt=(${actRoute[$tgt]})
 fi
 ip4=${tgt%/*}; msk4=${tgt#*/}
 if [[ $ip4 == '0.0.0.0' && $msk4 == '0.0.0.0' ]]; then
  what='default'
 elif [[ $msk4 == '255.255.255.255' ]]; then
  what="-host $ip4"
 else
  what="-net $ip4"
  netmask="netmask $msk4"
 fi
 [[ ${rt[0]} == '0.0.0.0' ]] || gw="gw ${rt[0]}"
 echo "route $action ${what}${gw:+ $gw}${netmask:+ $netmask} dev ${rt[5]}"
 return 0
}

declare -a tbl rt
declare -A actRoute newRoute

savedRoutes="$1"
actualRoutes=$(route -n | sed '1,2d')

while read line; do
 tbl=($line)
 tgt="${tbl[0]}/${tbl[2]}"
 actRoute["$tgt"]="${tbl[1]} ${tbl[@]:3}"
 echo "Actual route to $tgt = ${actRoute[$tgt]}" >&2
done <<<"$actualRoutes"

while read line; do
 [[ ${line:0:1} =~ ^[0-9]$ ]] || continue
   
 tbl=($line)
 tgt="${tbl[0]}/${tbl[2]}"
 newRoute[$tgt]="${tbl[1]} ${tbl[@]:3}"
 echo "New route to $tgt = ${newRoute[$tgt]}" >&2
 if [[ ${newRoute[$tgt]} == ${actRoute[$tgt]} ]]; then
  echo "Route to $tgt already exists in routing table, skipping it" >&2
 else 
  if [[ ${actRoute[$tgt]} && ${newRoute[$tgt]} != ${actRoute[$tgt]} ]]; then
   echo 'Actual route superseds with new route, so we have to remove it' >&2
   route_ del
  fi
  route_ add
 fi
 [[ ${actRoute[$tgt]} ]] && unset actRoute[$tgt]
done <${savedRoutes:-<(cat -)}

for tgt in ${!actRoute[@]}; do
 route_ del
done


Код также интересен как пример использования ассоциативных массивов, впервые появившихся в BASH 4.0
Несложно догадаться, что основной зависимостью является собственно BASH 4 (см. echo $BASH_VERSION). Для запуска под FreeBSD код можно слегка изменить, поскольку аналогом route -n здесь является netstat -rn.

Принципиальное ограничение: данный скрипт не может правильно работать с маршрутными таблицами, содержащими несколько маршрутов к одному назначению и отличающихся, например, метрикой.

3 комментария

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.