#! /bin/sh - # # nat; start and stop network address translations using iproute2 tools # # chkconfig: 345 45 55 # description: iproute2 tools allow for sophisticated routing, network # address translation, and policy based routing. This script # generalizes static NAT mappings and exceptions. # # - cleaned up and commented the code a bit # - altered the script to provide support for NAT from user-specified # networks instead of assuming that anything from 0/0 should be # translated # 2002-08-30; Martin A. Brown # - add configuration setting to flush all NAT rules and routes before # installing new rules and routes # - add a ./nat flush option # 2003-01-31; Matthew Callaway # - add validation routines # 2003-02-05; Martin A. Brown # - oversight identified by Shawn Balestracci; not all NAT rules # were flushed--we were looking only for map-to, not the exclude # rules as well gripe () { echo "$@" >&2; } abort () { gripe "Fatal: $@"; exit 1; } CONFIG=${CONFIG:-/etc/sysconfig/static-nat} [ -r "$CONFIG" ] || abort $CONFIG is not readable function isIP () { # -- this function validates a variable as a valid IP address or CIDR network # VAR=$1 echo ${VAR} | grep -Eq \ "[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}(|[[:digit:]]{1,2})" [ $? -eq 0 ] && return 0 return 1 } function isINT () { # -- this function validates a variable as a valid integer # VAR=$1 echo ${VAR} | grep -Eq \ "[[:digit:]]{1,}" [ $? -eq 0 ] && return 0 return 1 } function validate () { grep -Ev '^#|^$' $CONFIG | while read NET NAT REAL NPRIO RPRIO EXCLUDE ; do # Fields 5 and 6 are optional if [ -z "$NET" -o -z "$NAT" -o -z "$REAL" -o -z "$NPRIO" ]; then echo Syntax error: Missing field: $NET $NAT $REAL $NPRIO $RPRIO $EXCLUDE exit 1 fi if [ -n "$RPRIO" -a -z "$EXCLUDE" ]; then echo Syntax error: $NET $NAT $REAL $NPRIO $RPRIO $EXCLUDE echo Field 6 must be used with field 5 exit 1 fi for ITEM in $NET $NAT $REAL $EXCLUDE ; do isIP $ITEM if [ $? -ne 0 ]; then echo "In line:" echo $NET $NAT $REAL $NPRIO $RPRIO $EXCLUDE echo $ITEM is not a valid IP or CIDR block exit 1 fi done for ITEM in $NPRIO $RPRIO; do isINT $ITEM if [ $? -ne 0 ]; then echo "In line:" echo $NET $NAT $REAL $NPRIO $RPRIO $EXCLUDE echo $ITEM is not an integer exit 1 fi done done } function flush () { # -- this function should remove all NAT rules and routes # # -- remove all of the rules, except the three builtins and any IPSec # rule; -MAB; # ip rule show | grep -Ev '^(0|32766|32767):|iif lo' \ | while read PRIO NATRULE; do ip rule del prio ${PRIO%%:*} $( echo $NATRULE | sed 's|all|0/0|' ) done # -- remove all of the rules # ip route show table local | grep ^nat | while read NATROUTE; do ip route del $NATROUTE done ip route flush cache; } function nat () { grep -Ev '^#|^$' $CONFIG | while read NET NAT REAL NPRIO RPRIO EXCLUDE ; do # <-- set up the route for the NAT IP to turn it into the real IP # ip route add from $NET nat $NAT via ${REAL%%/*} [ "$?" -eq "0" ] || \ gripe cmd failed: ip route add nat $NAT via ${REAL%%/*} # <-- establish the minimum routing policy database; # this is required so that the outbound packet gets # rewritten to be from the IP which sent us the packet # ip rule add to $NET nat ${NAT%%/*} from $REAL prio $NPRIO [ "$?" -eq "0" ] || \ gripe cmd failed: ip rule add nat ${NAT%%/*} from $REAL prio $NPRIO # <-- determine if the user has supplied networks or address to be # excluded from the $NETwork address above # [ ! -z "$RPRIO" ] && [ ! -z "$EXCLUDE" ] && { for NETWORK in $EXCLUDE ; do ip rule add from $REAL to $NETWORK prio $RPRIO [ "$?" -eq "0" ] || \ gripe cmd failed: ip rule add from $REAL to $NETWORK prio $RPRIO done; } done; # <-- We don't want to forget to flush the cache, or the user will # sit around wondering for the next few minutes why the NAT rules # aren't working. After flushing the cache, the NAT rules will # work right away. # ip route flush cache; } # see how we were called case "$1" in start) validate && nat ;; stop) flush ;; restart) $0 stop; $0 start ;; status) ip route show table local | grep ^nat ip rule show | grep map-to ;; *) echo "usage: nat {start|stop|restart|status}" ;; esac # ]]> # - end of nat