Differences between revisions 1 and 2
Revision 1 as of 2018-01-31 15:49:13
Size: 11666
Editor: Kurgan
Comment:
Revision 2 as of 2018-03-14 14:20:12
Size: 11667
Editor: Kurgan
Comment:
Deletions are marked like this. Additions are marked like this.
Line 59: Line 59:
#!/usr/bin/env bash  #!/usr/bin/env bash

Due connessioni a internet per un solo host

Questa configurazione permette a un host di avere due connessioni internet sempre attive. L'host e` accessibile da tutte e due le connessioni indistintamente, e le usa tutte e due in modo bilanciato per il traffico uscente. Usando uno script apposito (ho scopiazzato orrendamente, lo ammetto) e` possibile avere un controllo sulla connettivita` delle due connessioni e provvedere a smettere di usare quella che per qualche motivo dovesse andare offline. Questo ovviamente non impatta le connessioni entranti, ma solo quelle uscenti.

Attenzione: questa configurazione non e` stata provata come sistema per dare connettivita` a degli host nattati dietro a una terza interfaccia. Potrebbe funzionare (con due regole di nat) ma anche no.

Configurazione statica

Questa configurazione definisce le regole necessarie per il routing verso due gateway diversi. E` necessario avere due schede di rete, una per connessione.

  • Installare, se non c'e`, il pacchetto iproute2. Nelle nuove installazioni c'e` per default.
  • Modificare il file /etc/iproute2/rt_tables aggiungendo le nostre due tabelle di routing con nomi a nostro piacere:

    200 Fastweb
    201 Ehiweb
  • Modificare il file /etc/network/interfaces in modo da creare tutte le regole necessarie al routing per ogni interfaccia

    # prima connessione: subnet 93.33.25.248/29, gw 249, il mio host e` il 253
    auto ens18
    iface ens18 inet static
            address 93.33.25.253/29
            post-up ip route add 93.33.25.248/29 dev ens18 src 93.33.25.253 table Fastweb
            post-up ip route add default via 93.33.25.249 table Fastweb
            post-up ip rule add from 93.33.25.253 table Fastweb
            post-down ip rule del from 93.33.25.253 table Fastweb
    
    
    # seconda connessione: subnet 109.23.6.48/29, gw 49, il mio host e` il 53
    auto ens19
    iface ens19 inet static
            address 109.23.6.53/29
            post-up ip route add 109.23.6.48/29 dev ens19 src 109.23.6.53 table Ehiweb
            post-up ip route add default via 109.23.6.49 table Ehiweb
            post-up ip rule add from 109.23.6.53 table Ehiweb
            post-down ip rule del from 109.23.6.53 table Ehiweb

A questo punto abbiamo due interfacce ma nessun default routing. Per stabilire un routing di default statico, possiamo aggiungerlo come post-up all'ultima delle due interfacce, in questo modo:

# sotto alla interfaccia ens19, come ultima riga:
post-up p route add default scope global nexthop via 93.33.25.249 dev ens18 weight 1 nexthop via 109.23.6.49 dev ens19 weight 1

Se vogliamo che il traffico uscente eviti di usare una interfaccia che non funziona, occorre, INVECE del routing statico, usare uno script che effettui un controllo costante e cambi le regole di conseguenza.

Script per il controllo del gateway morto

Questo script puo` essere usato per il controllo delle due connettivita`. Provvede a cambiare il default gateway a seconda di quale connessione funziona e quale no. Questo script e` stato copiato, non e` mio. L'autore e` Steve Buzonas e questo e` il link alla versione originale: https://github.com/sbuzonas/multiwan

Installazione

  • Creare lo script /usr/local/sbin/multiwan contenente quanto segue:

     #!/usr/bin/env bash
    
    source /etc/multiwan.conf
    
    STARTUP=1
    CHECK_INTERVAL=1
    
    # IP address of each WAN interface
    WAN_NET1="$(ip addr show $WAN_IF1 | grep "inet " | tr -s [:space:] | cut -d ' ' -f3)"
    WAN_NET2="$(ip addr show $WAN_IF2 | grep "inet " | tr -s [:space:] | cut -d ' ' -f3)"
    
    WAN_IP1="$(echo $WAN_NET1 | cut -d '/' -f1)"
    WAN_IP2="$(echo $WAN_NET2 | cut -d '/' -f1)"
    
    # Last link status.  Defaults to down to force check of both on first run.
    LLS1=1
    LLS2=1
    
    # Last ping status.
    LPS1=1
    LPS2=1
    
    # Current ping status.
    CPS1=1
    CPS2=1
    
    # Change link status.
    CLS1=1
    CLS2=1
    
    # Count of consecutive status checks
    COUNT1=0
    COUNT2=0
    
    function link_status() {
      case $1 in
        0)
          echo "Up" ;;
        1)
          echo "Down" ;;
        *)
          echo "Unknown" ;;
      esac
    }
    
    # check_link $IP $TIMEOUT
    function check_link() {
      ping -W $2 -I $1 -c 1 $PING_TARGET > /dev/null 2>&1
      RETVAL=$?
      if [ $RETVAL -ne 0 ] ; then
        STATE=1
      else
        STATE=0
      fi
    
      link_status $STATE
    
      return $STATE
    }
    
    while : ; do
      LINK_STATE="$(check_link $WAN_IP1 $PING_TIMEOUT)"
      CPS1=$?
    
      if [ $LPS1 -ne $CPS1 ] ; then
        logger -p local6.notice -t MULTIWAN[$$] "Ping state changed for $WAN_TABLE1 from $(link_status $LPS1) to $(link_status $CPS1)"
        COUNT1=1
      else
        if [ $LPS1 -ne $LLS1 ] ; then
          COUNT1=`expr $COUNT1 + 1`
        fi
      fi
    
      if [[ $COUNT1 -ge $SUCCESS_COUNT || ($LLS1 -eq 0 && $COUNT1 -ge $FAILURE_COUNT) ]]; then
        CLS1=0
        COUNT1=0
    
        if [ $LLS1 -eq 1 ] ; then
          LLS1=0
        else
          LLS1=1
        fi
        logger -p local6.notice -t MULTIWAN[$$] "Link state for $WAN_TABLE1 is $(link_status $LLS1)"
      else
        CLS1=1
      fi
    
      LPS1=$CPS1
    
      LINK_STATE="$(check_link $WAN_IP2 $PING_TIMEOUT)"
      CPS2=$?
    
      if [ $LPS2 -ne $CPS2 ] ; then
        logger -p local6.notice -t MULTIWAN[$$] "Ping state changed for $WAN_TABLE2 from $(link_status $LPS2) to $(link_status $CPS2)"
        COUNT2=1
      else
        if [ $LPS2 -ne $LLS2 ] ; then
          COUNT2=`expr $COUNT2 + 1`
        fi
      fi
    
      if [[ $COUNT2 -ge $SUCCESS_COUNT || ($LLS2 -eq 0 && $COUNT2 -ge $FAILURE_COUNT) ]]; then
        CLS2=0
        COUNT2=0
    
        if [ $LLS2 -eq 1 ]; then
          LLS2=0
        else
          LLS2=1
        fi
        logger -p local6.notice -t MULTIWAN[$$] "Link state for $WAN_TABLE2 is $(link_status $LLS2)"
      else
        CLS2=1
      fi
    
      LPS2=$CPS2
    
      if [[ $CLS1 -eq 0 || $CLS2 -eq 0 ]] ; then
        if [[ $STARTUP -eq 1 ]] ; then
          STARTUP=0
          CHECK_INTERVAL=15
        fi
        if [[ $LLS1 -eq 1 && $LLS2 -eq 0 ]] ; then
          logger -p local6.notice -t MULTIWAN[$$] "Applying $WAN_TABLE2 only route."
          ip route change default scope global via $WAN_GW2 dev $WAN_IF2
        elif [[ $LLS1 -eq 0 && $LLS2 -eq 1 ]] ; then
          logger -p local6.notice -t MULTIWAN[$$] "Applying $WAN_TABLE1 only route."
          ip route change default scope global via $WAN_GW1 dev $WAN_IF1
        elif [[ $LLS1 -eq 0 && $LLS2 -eq 0 ]] ; then
          logger -p local6.notice -t MULTIWAN[$$] "Applying multiwan load balancing route."
          ip route replace default scope global nexthop via $WAN_GW1 dev $WAN_IF1 weight $WAN_WEIGHT1 nexthop via $WAN_GW2 dev $WAN_IF2 weight $WAN_WEIGHT2
        fi
      fi
    
      sleep $CHECK_INTERVAL
    done
  • Rendere eseguibile il suddetto script
  • Creare lo script di init /etc/init.d/multiwan (si suppone che non usiate quella ciofeca di systemd!)

    ### BEGIN INIT INFO
    # Provides:          multiwan
    # Required-Start:    $network $local_fs $remote_fs
    # Required-Stop:     $remote_fs
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: Monitor internet connection links and modify route depending upon link state
    # Description:       This is a startup script for multiwan. Multiwan monitors multiple internet connections
    #                    to provide failover routes depending upon link state.
    ### END INIT INFO
    
    # Author: Steve Buzonas <steve@fancyguy.com>
    
    # PATH should only include /usr/* if it runs after the mountnfs.sh script
    PATH=/sbin:/usr/sbin:/bin:/usr/bin
    DESC=multiwan             # Introduce a short description here
    NAME=multiwan             # Introduce the short server's name here
    DAEMON=/usr/sbin/multiwan # Introduce the server's location here
    DAEMON_ARGS=""             # Arguments to run the daemon with
    PIDFILE=/var/run/$NAME.pid
    SCRIPTNAME=/etc/init.d/$NAME
    
    # Exit if the package is not installed
    [ -x $DAEMON ] || exit 0
    
    # Read configuration variable file if it is present
    [ -r /etc/default/$NAME ] && . /etc/default/$NAME
    
    # Load the VERBOSE setting and other rcS variables
    . /lib/init/vars.sh
    
    # Define LSB log_* functions.
    # Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
    . /lib/lsb/init-functions
    
    #
    # Function that starts the daemon/service
    #
    do_start()
    {
            # Return
            #   0 if daemon has been started
            #   1 if daemon was already running
            #   2 if daemon could not be started
            start-stop-daemon --start --quiet -b -m --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
                    || return 1
            start-stop-daemon --start --quiet -b -m --pidfile $PIDFILE --exec $DAEMON -- \
                    $DAEMON_ARGS \
                    || return 2
    }
    
    #
    # Function that stops the daemon/service
    #
    do_stop()
    {
            # Return
            #   0 if daemon has been stopped
            #   1 if daemon was already stopped
            #   2 if daemon could not be stopped
            #   other if a failure occurred
            start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
            RETVAL="$?"
            [ "$RETVAL" = 2 ] && return 2
            # Wait for children to finish too if this is a daemon that forks
            # and if the daemon is only ever run from this initscript.
            # If the above conditions are not satisfied then add some other code
            # that waits for the process to drop all resources that could be
            # needed by services started subsequently.  A last resort is to
            # sleep for some time.
            start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
            [ "$?" = 2 ] && return 2
            # Many daemons don't delete their pidfiles when they exit.
            rm -f $PIDFILE
            return "$RETVAL"
    }
    
    case "$1" in
      start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
        do_start
        case "$?" in
                    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
            esac
      ;;
      stop)
            [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
            do_stop
            case "$?" in
                    0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                    2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
            esac
            ;;
      status)
           status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
           ;;
      restart|force-reload)
            log_daemon_msg "Restarting $DESC" "$NAME"
            do_stop
            case "$?" in
              0|1)
                    do_start
                    case "$?" in
                            0) log_end_msg 0 ;;
                            1) log_end_msg 1 ;; # Old process is still running
                            *) log_end_msg 1 ;; # Failed to start
                    esac
                    ;;
              *)
                    # Failed to stop
                    log_end_msg 1
                    ;;
            esac
            ;;
      *)
            echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
            exit 3
            ;;
    esac
    
    :
  • Rendere eseguibile il suddetto script
  • Creare la configurazione in /etc/multiwan.conf avendo cura di adattarla ai vostri nomi, interfacce e indirizzi IP

    PING_TARGET="8.8.8.8"
    PING_TIMEOUT=2
    
    SUCCESS_COUNT=4
    FAILURE_COUNT=1
    
    WAN_IF1="ens18"
    WAN_IF2="ens19"
    
    WAN_GW1="93.33.25.249"
    WAN_GW2="109.23.6.49"
    
    WAN_TABLE1="Fastweb"
    WAN_TABLE2="Ehiweb"
    
    WAN_WEIGHT1=1
    WAN_WEIGHT2=1
  • Fare eseguire lo script multiwan al boot, rendendolo attivo come demone, usando il comando:
    insserv multiwan

A questo punto, riavviando la macchina (ce l'avete una console che funzioni anche SENZA LA RETE, vero? Se abbiamo sbagliato qualcosa, addio connessione di rete, ci siamo chiusi fuori per sempre!) dovremmo avere due interfacce di rete attive, e nel syslog vedremo anche le righe relative allo script multiwan che ci dice quali interfacce sta usando e come.

Test

La macchina dovrebbe essere raggiungibile da fuori a tutti e due i suoi indirizzi pubblici. Staccando una delle due linee l'altra dovrebbe rimanere totalmente funzionante, e la macchina dovrebbe (dopo qualche secondo) usare sempre la connessione funzionante, saltando dall'una all'altra automaticamente.

LinuxDebian/MultiWAN (last edited 2019-05-06 09:04:20 by Kurgan)