jablonka.czprosek.czf

sedlo

Subversion Repositories:
[/] [trunk/] [sedlo] - Rev 19 Go to most recent revision

Compare with Previous - Blame - Download


#!/bin/bash
# author       : Petr Simandl www.simandl.cz
# release date : 23/04/2007 
# name         : sedlo
# description  : dynamic side routing tables tool
# license      : GPL

sl_version="0.0.4pre8"

PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

sl_nmcnf="sedlo.conf"
sl_sedlocnf="/etc/$sl_nmcnf"
sl_sedlocache="/var/cache/sedlo"

sl_rttab="/etc/iproute2/rt_tables"
sl_rtnmin=110
sl_rtnmax=200
#all traffic that is handled as internal (CZF traffic)
sl_ipnodef="10.0.0.0/8"
#this will specify rupriority in rule table
sl_priorules=10000
#no default traffic will have rule at higher priority
sl_prionodef=$(($sl_priorules - 1))

slm_unknown="Nezname parametry : "

sl_ipcmd=`which ip`
sl_trcmd=`which tr`
sl_wgetcmd=`which wget`
sl_hnmcmd=`which hostname`
sl_awkcmd=`which awk`
sl_catcmd=`which cat`
sl_grepcmd=`which grep`
sl_diffcmd=`which diff`

if [ -e $sl_sedlocnf ]
  then 
    sl_nop=1  
  else 
  echo "$sl_sedlocnf not found"
  exit 1
fi

if [ -e $sl_rttab ]
  then 
    sl_nop=1  
  else 
  echo "$sl_rttab not found"
  exit 1
fi

sl_murlcfg=`cat $sl_sedlocnf | grep "^mcnf" | uniq | awk '{print $2" "$3" "$4}'`

######################################################################
s_maru()
{
if [ $scm_info -gt 0 ]; then echo "Managing rules" ; fi

sl_rules=`($sl_ipcmd ru ls | $sl_grepcmd -v "from all lookup" | $sl_awkcmd '{print $3"*ru"}' ; \
$sl_catcmd $sl_sedlocache/$sl_nmcnf | $sl_grepcmd "^ip" | $sl_awkcmd '{print $2"*ip"}') | sort | uniq`

sl_merged=`echo $sl_rules $sl_ips | sort | uniq`

echo $sl_merged

} # s_maru

######################################################################
#this will delete all rules at sl_prionodef an sl_priorules priorities
s_flruall()
{
if [ $scm_info -gt 0 ]; then echo "Flushing all rules" ; fi

sl_rules=`$sl_ipcmd ru ls | $sl_grepcmd  "^"$sl_prionodef":" | $sl_trcmd '[:blank:]' '*'`
for sl_rule in $sl_rules 
do
  sl_ipgws=`echo $sl_rule | $sl_awkcmd -F '*' '{print $2,$3,$4,$5,$6,$7}'`
  $sl_ipcmd ru del $sl_ipgws
  #this should make faster applying of new routing tables
  $sl_ipcmd ro flush cache
done

sl_rules=`$sl_ipcmd ru ls | $sl_grepcmd  "^"$sl_priorules":" | $sl_trcmd '[:blank:]' '*'`
for sl_rule in $sl_rules 
do
  sl_ipgws=`echo $sl_rule | $sl_awkcmd -F '*' '{print $2,$3,$4,$5,$6,$7}'`
  $sl_ipcmd ru del $sl_ipgws
  #this should make faster applying of new routing tables
  $sl_ipcmd ro flush cache
done

} # s_flruall

######################################################################
s_flru()
{
if [ $scm_info -gt 0 ]; then echo "Flushing all rules" ; fi

sl_rules=`$sl_ipcmd ru ls | $sl_grepcmd ^$sl_priorules":" | $sl_trcmd '[:blank:]' '*'`

for sl_rule in $sl_rules 
do
  sl_ipgws=`echo $sl_rule | $sl_awkcmd -F '*' '{print $2,$3,$4,$5,$6,$7}'`
  $sl_ipcmd ru del $sl_ipgws
  #this should make faster applying of new routing tables
  $sl_ipcmd ro flush cache
done

} # s_flru

######################################################################
s_checknodefru()
{
#checking if we have present nodef rule and if not we create it
sl_nodefrule=`$sl_ipcmd ru ls | $sl_grepcmd "^"$sl_prionodef":" | $sl_trcmd '[:blank:]' '*'`
#echo $sl_nodefrule
if [ "$sl_nodefrule x" == " x" ]
  then
    if [ $scm_info -gt 0 ]; then echo "Creating rule for nodef route" ; fi
    $sl_ipcmd ru add from $sl_ipnodef to $sl_ipnodef lookup main prio $sl_prionodef
    echo "delam novou"
fi

}

######################################################################
# here we get each ip and we create a rule to send this ip to a
# certain table
# this routine can be skipped when the number of ips and ip directions
# are still the same = old and new configs are the same
s_fillrules()
{

#this will check no default rule if exists and if not it will be created
s_checknodefru

#flush old rules before filling new ones
#not so nice solution - it is planned to change just what's necessary
#by s_maru
#s_flru

if [ $scm_info -gt 0 ]; then echo "Checking rules for ips" ; fi

sl_ips=`$sl_catcmd $sl_sedlocache/$sl_nmcnf | $sl_grepcmd "^ip" | $sl_awkcmd '{print $2"*"$4"*"$5"*"$6}'`
sl_rules=`$sl_ipcmd ru ls | $sl_grepcmd ^$sl_priorules":" | $sl_trcmd '[:blank:]' '*'`



#for all IPs we check and leave, change or create rule 
for sl_ip in $sl_ips 
do
  sl_ipn=`echo $sl_ip | $sl_awkcmd -F '*' '{print $1}'`
  sl_ipgws=`echo $sl_ip | $sl_awkcmd -F '*' '{print $2,$3,$4}'`
  sl_ok="no"
  #for all GWs we check rules
  for sl_ipgw in $sl_ipgws
  do
    sl_tbl=`$sl_ipcmd ro ls ta $sl_ipgw`
    #check if table exists
    if [ "$sl_tbl x" != " x" ] && [ "$sl_ok" = "no" ]
      then
        #we have IP and GW table
        #check if the rule alredady exists
        sl_oldrule=`echo $sl_rules | $sl_trcmd " " "\n" | $sl_grepcmd "\*"$sl_ipn"\*"`
        sl_exactrule=`echo $sl_oldrule | $sl_trcmd " " "\n" | $sl_grepcmd "\*"$sl_ipgw"\*"`
        if [ "$sl_exactrule x" == " x" ]
          then
            #exact rule doesn't exist so we check if an old rule for this IP is present
            if [ "$sl_oldrule x" != " x" ]
              then
                #some old rule(s) for IP is present so we delete it
                for sl_rule in $sl_oldrule 
                do
                  sl_ipgws=`echo $sl_rule | $sl_awkcmd -F '*' '{print $2,$3,$4,$5,$6,$7}'`
                  if [ $scm_info -gt 0 ]; then echo "Deleting old rule $sl_ipgws" ; fi
                  $sl_ipcmd ru del $sl_ipgws
                  #this should make faster applying of new routing tables
                  $sl_ipcmd ro flush cache
                done
            fi
            
            if [ $scm_info -gt 0 ]; then echo "Creating new rule to send $sl_ipn to table $sl_ipgw" ; fi
            $sl_ipcmd ru add from $sl_ipn lookup $sl_ipgw prio $sl_priorules
          
          else
            if [ $scm_info -gt 1 ]; then echo "Rule to send $sl_ipn to table $sl_ipgw already exists" ; fi
        fi
        sl_ok="yes"
      else
        #we have no table
        if [ "$sl_ok" = "no" ]
          then
            if [ $scm_info -gt 1 ]; then echo "For $sl_ipn table $sl_ipgw not used because it is empty" ; fi
          else
            if [ $scm_info -gt 1 ]; then echo "For $sl_ipn table $sl_ipgw not used because it has lower priority" ; fi
        fi
    fi
  done
done

#finally we check all rules and if there is a rule without IP from config we delete it
for sl_rule in $sl_rules 
do
  sl_iprule=`echo $sl_rule | $sl_awkcmd -F '*' '{print $3}'`
  sl_ipconf=`echo $sl_ips | $sl_trcmd " " "\n" | $sl_grepcmd "^"$sl_iprule"\*"`

  if [ "$sl_ipconf x" == " x" ]
  then
    #we have a rule without an IP in config so we delete this rule
    sl_ipgws=`echo $sl_rule | $sl_awkcmd -F '*' '{print $2,$3,$4,$5,$6,$7}'`
    if [ $scm_info -gt 0 ]; then echo "Deleting non config rule $sl_ipgws" ; fi
    $sl_ipcmd ru del $sl_ipgws
    #this should make faster applying of new routing tables
    $sl_ipcmd ro flush cache
  fi
done

} # s_fillrules

######################################################################
# here we look into the main routing table for path to our iGWs
# and we fill these tables with two halves default nets that
# point to appropriate direction
# this routine can be skipped when the routing table is the same
s_filltables()
{
if [ $scm_info -gt 0 ]; then echo "Checking main routing table" ; fi

if [ $scm_info -gt 0 ]; then echo "Filling tables" ; fi

sl_igws=`$sl_catcmd $sl_sedlocache/$sl_nmcnf | $sl_grepcmd -E "^igw|^myigw" | $sl_awkcmd '{print $3"*"$2"*"$1}'`

for sl_igw in $sl_igws 
  do
    sl_igwn=`echo $sl_igw | $sl_awkcmd -F '*' '{print $1}'`
    sl_igwip=`echo $sl_igw | $sl_awkcmd -F '*' '{print $2}'`
    sl_igwtype=`echo $sl_igw | $sl_awkcmd -F '*' '{print $3}'`

#oprava falesneho routovani na lokalni iface - pokud jsme lokalni igw tak se nema najit ip
#protoze cesta dal neni - jsme totiz uz na lokalnim iface
#head je tam proto ze se pro prespolni(a bgp) muze objevit vice rout s ruznou metrikou tak vezmem jen prvni (head)
#s nejmensi metrikou (sort)
    sl_igwgt=`$sl_ipcmd ro ls | $sl_grepcmd -v "proto kernel" | $sl_grepcmd "^$sl_igwip " | sort | $sl_awkcmd '{print $3}' | head -n 1`

    # equal cost multipath detection - just first IP is taken as way to igw
    if [ "$sl_igwgt x" = "zebra x" ]
      then
        sl_igwgt=`$sl_ipcmd ro ls | $sl_grepcmd -A 1 "^$sl_igwip " | $sl_grepcmd "nexthop" | $sl_awkcmd '{print $3}'`
    fi

    #if myigw then fill table for local gateway with single ip from config
    if [ "$sl_igwtype x" = "myigw x" ]
      then
        sl_igwgt=$sl_igwip
    fi
    #testing if the igw has not a route in global routing table
    if [ "$sl_igwgt x" = " x" ]
      then
        if [ $scm_info -gt 1 ]; then echo "Route not found for igw $sl_igwn" ; fi
        sl_myigw=`cat $sl_sedlocnf | $sl_grepcmd "^myigw" | $sl_grepcmd $sl_igwn | $sl_awkcmd '{print $3}'`
        #testing if the igw without route is in local config
        #if not we go to flush its table and set flag to redo rules
        if [ "$sl_myigw x" = " x" ]
          then
            #getting num of routes of igw
            sl_igwnr=`$sl_ipcmd ro ls ta all | $sl_grepcmd -c "table ${sl_igwn} "`
            if [ "$sl_igwnr x" = "0 x" ]
              then
                if [ $scm_info -gt 1 ]; then echo "Table $sl_igwn is already empty - no action taken" ; fi
              else
                if [ $scm_info -gt 1 ]; then echo "Table $sl_igwn will be flushed and rules rearranged" ; fi
                $sl_ipcmd ro fl ta $sl_igwn
                #because this igw dissapeared we set a flag for rules recreation
                sl_diffigw=1
            fi
          else
            if [ $scm_info -gt 1 ]; then echo "Igw $sl_igwn found in local config - leaving table as is" ; fi
        fi
      else
        sl_tbl=`$sl_ipcmd ro ls ta $sl_igwn`
        #if the table is empty we fill it and we set flag for rules recreation
        if [ "$sl_tbl x" = " x" ]
          then
            sl_diffigw=1
            $sl_ipcmd ro add 0.0.0.0/1 via $sl_igwgt ta $sl_igwn 
            $sl_ipcmd ro add 128.0.0.0/1 via $sl_igwgt ta $sl_igwn 
            if [ "$sl_igwtype x" = "myigw x" ]
              then
                if [ $scm_info -gt 1 ]; then echo "Table $sl_igwn filled with default myigw $sl_igwgt" ; fi
              else
                if [ $scm_info -gt 1 ]; then echo "Table $sl_igwn filled with default gw $sl_igwgt" ; fi
            fi
          #the table is not empty so we check if routes are the same
          else
            #picking default gateway from the table
            sl_igwogt=`$sl_ipcmd ro ls ta $sl_igwn | $sl_awkcmd '{print $3}' | uniq`
            #checking if the old default is same as the new one
            if [ "$sl_igwogt x" = "$sl_igwgt x" ]
              then
                if [ $scm_info -gt 1 ]; then echo "Table $sl_igwn will not be changed and default is $sl_igwgt" ; fi
              else
              #the new default is different so we will flush the table, fill new default    
                if [ $scm_info -gt 1 ]; then echo "Table $sl_igwn will be rewritten to default $sl_igwgt" ; fi
                #flushing old default route in the table
                $sl_ipcmd ro fl ta $sl_igwn
                #filling new default
                $sl_ipcmd ro add 0.0.0.0/1 via $sl_igwgt ta $sl_igwn 
                $sl_ipcmd ro add 128.0.0.0/1 via $sl_igwgt ta $sl_igwn 
            fi
        fi
    fi
  done

} # s_filltables

######################################################################
# filling rttab with tables from config
# only new tables are created with a new uniq number that is not important because
# usually we handle tables just by their names
# this routine acts only when a new iGW appears - only adding a table is supported
# no deleting is implemented because it seems to be not necessary to delete an old table
# because there is space enough and after reboot table will not be created
s_mktables()
{
if [ $scm_info -gt 0 ]; then echo "Checking tables" ; fi

sl_igws=`$sl_catcmd $sl_sedlocache/$sl_nmcnf | $sl_grepcmd -E "^igw|^myigw" | $sl_awkcmd '{print $3}'`
for sl_igw in $sl_igws 
  do
    sl_igwrttb=`$sl_catcmd $sl_rttab | $sl_awkcmd '{print $2}' | $sl_grepcmd $sl_igw ` 
    if [ "$sl_igwrttb x" = " x" ]
      then
        if [ $scm_info -gt 1 ]; then echo "Creating table for $sl_igw" ; fi
        sl_cnt="$sl_rtnmax"
        sl_ok="no"
        until [ "$sl_cnt" -eq "$sl_rtnmin" ] || [ "$sl_ok" = "yes" ]
        do
          #space is used to recognized two and three digit numbers
          sl_igwrttb=`cat $sl_rttab | awk '{print $1" "}' | grep "$sl_cnt " ` 
          if [ "$sl_igwrttb x" = " x" ]
            then
              sl_ok="yes"
              echo "$sl_cnt     $sl_igw" >> $sl_rttab 
          fi
          sl_cnt=$(($sl_cnt - 1 ))
        done
        # a new table was created so we should set a flag for rules creation
        sl_difftbl=1
      else
        if [ $scm_info -gt 1 ]; then echo "Table found for $sl_igw no action taken" ; fi
    fi
  done
} # s_mktables

######################################################################
s_getcfg()
{
if [ $scm_info -gt 0 ]; then echo "Getting config" ; fi
if [ $scm_info -gt 1 ]; then echo "Using main config $sl_murlcfg" ; fi
if [ $scm_info -gt 1 ]; then echo "Using local config $sl_sedlocnf" ; fi

rm -f "$sl_sedlocache/$sl_nmcnf.main.tmp"

$sl_wgetcmd -q -t 3 $sl_murlcfg -O "$sl_sedlocache/$sl_nmcnf.main.tmp" 

if [ -s $sl_sedlocache/$sl_nmcnf.main.tmp ]
  then 
    date > $sl_sedlocache/last_getcnf.txt
    cp $sl_sedlocache/$sl_nmcnf.main.tmp $sl_sedlocache/$sl_nmcnf.main  
    if [ $scm_info -gt 1 ]; then echo "Main config downloaded and accepted" ; fi
  else 
    if [ $scm_info -gt 1 ]; then echo "Main config not downloaded - cached config will be used" ; fi
    echo -n "Main config not downloaded " > $sl_sedlocache/last_getcnf.txt  
    date >> $sl_sedlocache/last_getcnf.txt  
fi

# before generating a new cached config we store the old one for
# comparison with the new one
rm -f "$sl_sedlocache/$sl_nmcnf.old"
if [ -s $sl_sedlocache/$sl_nmcnf ]
  then 
    cp $sl_sedlocache/$sl_nmcnf $sl_sedlocache/$sl_nmcnf.old
  else
    touch $sl_sedlocache/$sl_nmcnf.old
fi

# preparing cached config from local and main
# the local config should be processed as the second to have
# higher priority for rules from local config
echo "# generated file" > $sl_sedlocache/$sl_nmcnf
for sl_file in `ls $sl_sedlocache/$sl_nmcnf.main ; ls $sl_sedlocnf`
do
cat $sl_file | grep "^mcnf" | $sl_trcmd ';' '#' | awk '{print $1"\t"$2}' >> $sl_sedlocache/$sl_nmcnf
cat $sl_file | grep "^igw" | $sl_trcmd ';' '#' | awk '{print $1"\t"$2"\t"$3}' >> $sl_sedlocache/$sl_nmcnf
cat $sl_file | grep "^ip" | $sl_trcmd ';' '#' | awk '{print $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6}' >> $sl_sedlocache/$sl_nmcnf
done

#local gateways taken from local config
cat $sl_sedlocnf | grep "^myigw" | $sl_trcmd ';' '#' | awk '{print $1"\t"$2"\t"$3}' >> $sl_sedlocache/$sl_nmcnf

#cat $sl_sedlocache/$sl_nmcnf | sort | uniq  > $sl_sedlocache/$sl_nmcnf.uniq
#mv $sl_sedlocache/$sl_nmcnf.uniq $sl_sedlocache/$sl_nmcnf

sl_diffcfg=`diff $sl_sedlocache/$sl_nmcnf $sl_sedlocache/$sl_nmcnf.old | grep -c .`
if [ $sl_diffcfg -gt 0 ]
  then
    if [ $scm_info -gt 0 ]; then echo "New config is different than the old one" ; fi
  else 
    if [ $scm_info -gt 0 ]; then echo "New config is the same as the old one" ; fi
fi

# showing number of rules in config and system
sl_numru=`ip ru ls | grep -c lookup`
sl_numip=`grep -c ^ip $sl_sedlocache/$sl_nmcnf`
sl_numru=$(($sl_numru - 3 ))
if [ $sl_numip -gt $sl_numru ]
  then
    if [ $scm_info -gt 0 ]; then echo "We have less rules ($sl_numru) than new config has ips ($sl_numip)" ; fi
#    sl_diffcfg="1"
  else 
    if [ $scm_info -gt 0 ]; then echo "We have $sl_numru rules and $sl_numip ips" ; fi
fi

}

######################################################################
s_version()
{
  echo sedlo $sl_version
} # s_version

######################################################################
s_report()
{
  echo Content-type: text/html
  echo
  echo "Sedlo na routeru `hostname`"
  echo "<pre>"
  echo "##### SEDLO #####"
  echo "date         : `date`"
  echo "version      : $sl_version"
  echo "local_config : $sl_sedlocnf"
  echo "main_config  : <a href=\"$sl_murlcfg\">$sl_murlcfg</a>"
  echo "last update  : `cat $sl_sedlocache/last_getcnf.txt`"
  echo "##### TABLES #####"
  cat $sl_rttab
  echo ; echo "##### DEFAULT ROUTES IN TABLES #####"
  $sl_ipcmd ro ls ta all | $sl_grepcmd table | $sl_grepcmd -v local | $sl_trcmd " " "\t"
  echo ; echo "##### RULES FOR IPS #####"
  $sl_ipcmd ru ls | $sl_trcmd " " "\t"
  echo "</pre>"
} # s_report



######################################################################
s_help()
{
  echo Pouziti: sedlo [param]
  echo param:
  echo -V vypise verzi
  echo -help vypise napovedu
  echo -v malo upovidany
  echo -vv hodne upovidany
  echo -nogetcfg zajisti ze se nedude znovu nacitat konfigurace a pouzije se predchozi z cache
  echo -report vypise prehled pravidel a tabulek
  echo -flru odstrani vsechny pravidla
  echo -force bezpodminecne znovu obnovi vsechny pravidla
} # s_help

######################################################################
######################################################################

sl_unknown=""
scm_nogetcfg=0
scm_flru=0
scm_info=0
scm_force=0
sl_diffigw=0
sl_difftbl=0

# parsing input parameters
while [ "a$1" != "a" ]
do
  case $1 in
  -V)
    s_version
    exit 0
  ;;
  -h)
    s_help
    exit 0
  ;;
  -report)
    s_report
    exit 0
  ;;
  -flru)
    scm_flru=1
    shift
  ;;
  -force)
    scm_force=1
    shift
  ;;
  -help)
    s_help
    exit 0
  ;;
  -nogetcfg)
    scm_nogetcfg=1
    shift
  ;;
  -v)
    scm_info=1
    shift
  ;;
  -vv)
    scm_info=2
    shift
  ;;
  *)
    sl_unknown="$sl_unknown$1 "
    shift
  esac
done

# printing the list of bad parameters (if there are some)
if [ "a$sl_unknown" != "a" ]
then
  echo "$slm_unknown $sl_unknown"
  s_help
  exit 0
fi

if [ $scm_flru -eq 1 ]
then
  s_flruall
  exit 0
fi

if [ $scm_nogetcfg -eq 0 ]
then
  s_getcfg      
fi

s_mktables
s_filltables
#toto je pro ladici ucely
#echo $sl_difftbl
#echo $sl_diffcfg
#echo $sl_diffigw
#echo $scm_force
#exit 0

#flushing and filling rules is done only when
#new table is created
#config is changed
#some igw dissapears or appears
#-force command line parameter was used
if [ $sl_difftbl -gt 0 ] || [ $sl_diffcfg -gt 0 ] || [ $sl_diffigw -gt 0 ] || [ $scm_force -gt 0 ]
then
  s_fillrules
fi


exit 0

Powered by WebSVN 2.2.1