|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- #!/bin/bash
-
- if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
- echo 'usage: ./natfwd.sh <action> <extif> <port> <netns>'
- exit 1
- fi
-
- if [ "$UID" -ne 0 ] && [ -z "$SKIP_ROOT_CHECK" ]; then
- echo 'must be root!'
- exit 1
- fi
-
- # Check if we should add an exemption for UFW.
- ufw=no
- if [ "$1" = "--ufw" ]; then
- ufw=yes
- shift
- fi
-
- action=$1
- extip=$2
- ports=$3
- netnsname=$4
-
- pipeouter=$netnsname"_veth0"
- pipeinner=$netnsname"_veth1"
-
- # use /31 here to minimize chance of something fucking up later
- # CONFIG: change pouterip and pinnerip to something in case there's a conflict,
- # but there probably won't be
- pouterip=192.168.69.42
- pinnerip=192.168.69.43
- pouteripmasked=$pouterip/31
- pinneripmasked=$pinnerip/31
-
- # Used in testing:
- # -A PREROUTING -d 192.168.1.9/32 -p tcp -m tcp --dport 1337 -j DNAT --to-destination 10.13.37.69
- # -A POSTROUTING -d 10.13.37.69/32 -p tcp -m tcp --dport 1337 -j SNAT --to-source 10.13.37.42
- dnatrule="PREROUTING -d $extip -p tcp --dport $port -j DNAT --to-destination $pinnerip"
- snatrule="POSTROUTING -d $pinnerip -p tcp --dport $port -j SNAT --to-source $pouterip"
-
- function get_dnat_rule {
- port=$1
- echo "PREROUTING -d $extip -p tcp --dport $port -j DNAT --to-destination $pinnerip"
- }
-
- function get_snat_rule {
- port=$1
- echo "POSTROUTING -d $pinnerip -p tcp --dport $port -j SNAT --to-source $pouterip"
- }
-
- function get_ufw_rule {
- port=$1
- echo "proto tcp from any to $pinnerip port $port"
- }
-
- # CONFIG: make sure this is set right
- ufwcomment="natfwd_"$netnsname
-
- if [ $action = "enable" ]; then
- echo 'enabling'
- set -x
-
- # Make sure we have IP forwarding enabled. We don't bother disabling
- # this later.
- sysctl -w net.ipv4.ip_forward=1 > /dev/null
-
- # Create the interface and move to the network namespace.
- ip link add $pipeouter type veth peer name $pipeinner
- ip link set $pipeinner netns $netnsname
-
- # Assign IP addresses to the new devices.
- ip addr add $pouteripmasked dev $pipeouter
- ip netns exec $netnsname ip addr add $pinneripmasked dev $pipeinner
-
- # Create the routing rules to allow the packets.
- for p in $ports; do
- iptables -t nat -A $(get_dnat_rule $p)
- iptables -t nat -A $(get_snat_rule $p)
- done
-
- [ "$ufw" = "yes" ] && [ -z "$(ufw status | grep '# $ufwcomment')" ] && \
- for p in $ports; do
- ufw route allow $(get_ufw_rule $p) comment $ufwcomment
- done
-
- # Enable the interfaces.
- ip link set dev $pipeouter up
- ip netns exec $netnsname ip link set dev $pipeinner up
-
- elif [ $action = "disable" ]; then
- echo 'disabling'
- set -x
-
- # Delete the routing rules. Deleting the interfaces doesn't
- # automatically remove these.
- for p in $ports; do
- iptables -t nat -D $(get_dnat_rule $p)
- iptables -t nat -D $(get_snat_rule $p)
- done
-
- if [ "$ufw" = "yes" ]; then
- rulenum=$(ufw status numbered | grep "# $ufwcomment" | awk '{ print substr($1, 2, length($1) - 2) }')
- if [ -n "$rulenum" ]; then
- yes | ufw delete $rulenum
- fi
- fi
-
- # Deleting this interface deletes everything else associated with it.
- ip link delete $pipeouter
-
- else
- echo 'actions are "enable" or "disable"'
- exit 1
- fi
-
- set +x
- echo 'OK'
-
|