diff --git a/patches/systemvm/debian/config/opt/cloud/bin/vpc_nat.sh b/patches/systemvm/debian/config/opt/cloud/bin/vpc_nat.sh new file mode 100755 index 00000000000..a331365a02c --- /dev/null +++ b/patches/systemvm/debian/config/opt/cloud/bin/vpc_nat.sh @@ -0,0 +1,255 @@ +#!/usr/bin/env bash +# Copyright 2012 Citrix Systems, Inc. Licensed under the +# Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. Citrix Systems, Inc. +# reserves all rights not expressly granted by the License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Automatically generated by addcopyright.py at 04/03/2012 +# @VERSION@ + +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + +usage() { + printf "Usage: %s: (-A|-D) -r -P protocol (-p port_range | -t icmp_type_code) -l -d -s [-G] \n" $(basename $0) >&2 +} + +#set -x + +#Port (address translation) forwarding for tcp or udp +tcp_or_udp_nat() { + local instIp=$1 + local dport0=$2 + local dport=$(echo $2 | sed 's/:/-/') + local publicIp=$3 + local port=$4 + local op=$5 + local proto=$6 + local cidrs=$7 + + logger -t cloud "$(basename $0): creating port fwd entry for PAT: public ip=$publicIp \ + instance ip=$instIp proto=$proto port=$port dport=$dport op=$op" + + #if adding, this might be a duplicate, so delete the old one first + [ "$op" == "-A" ] && tcp_or_udp_entry $instIp $dport0 $publicIp $port "-D" $proto $cidrs + # the delete operation may have errored out but the only possible reason is + # that the rules didn't exist in the first place + # shortcircuit the process if error and it is an append operation + # continue if it is delete + (sudo iptables -t nat $op PREROUTING --proto $proto -d $publicIp \ + --destination-port $port -j DNAT \ + --to-destination $instIp:$dport &>> $OUTFILE || [ "$op" == "-D" ]) && + + local result=$? + logger -t cloud "$(basename $0): done port fwd entry for PAT: public ip=$publicIp op=$op result=$result" + return $result +} + +#Forward icmp +icmp_entry() { + local instIp=$1 + local icmptype=$2 + local publicIp=$3 + local op=$4 + + logger -t cloud "$(basename $0): creating port fwd entry for PAT: public ip=$publicIp \ + instance ip=$instIp proto=icmp port=$port dport=$dport op=$op" + #if adding, this might be a duplicate, so delete the old one first + [ "$op" == "-A" ] && icmp_entry $instIp $icmpType $publicIp "-D" + # the delete operation may have errored out but the only possible reason is + # that the rules didn't exist in the first place + sudo iptables -t nat $op PREROUTING --proto icmp -d $publicIp --icmp-type $icmptype -j DNAT --to-destination $instIp &>> $OUTFILE + + result=$? + logger -t cloud "$(basename $0): done port fwd entry for PAT: public ip=$publicIp op=$op result=$result" + return $result +} + +one_to_one_fw_entry() { + local publicIp=$1 + local instIp=$2 + local proto=$3 + local portRange=$4 + local op=$5 + logger -t cloud "$(basename $0): create firewall entry for static nat: public ip=$publicIp \ + instance ip=$instIp proto=$proto portRange=$portRange op=$op" + + #if adding, this might be a duplicate, so delete the old one first + [ "$op" == "-A" ] && one_to_one_fw_entry $publicIp $instIp $proto $portRange "-D" + # the delete operation may have errored out but the only possible reason is + # that the rules didn't exist in the first place + + # shortcircuit the process if error and it is an append operation + # continue if it is delete + sudo iptables -t nat $op PREROUTING -d $publicIp --proto $proto \ + --destination-port $portRange -j DNAT \ + --to-destination $instIp &>> $OUTFILE || [ "$op" == "-D" ] + + result=$? + logger -t cloud "$(basename $0): done firewall entry public ip=$publicIp op=$op result=$result" + return $result +} + +static_nat() { + local publicIp=$1 + local instIp=$2 + local op=$3 + local op2="-D" + local rulenum= + local proto="all" + local tableNo = "" + logger -t cloud "$(basename $0): static nat: public ip=$publicIp \ + instance ip=$instIp op=$op" + + + #if adding, this might be a duplicate, so delete the old one first + [ "$op" == "-A" ] && static_nat $publicIp $instIp "-D" + # the delete operation may have errored out but the only possible reason is + # that the rules didn't exist in the first place + [ "$op" == "-A" ] && rulenum=1 + [ "$op" == "-A" ] && op2="-I" + DEV_LIST = `ls /sys/class/net/ | grep eth` + for dev in $DEV_LIST; do + ip addr show dev $dev | grep inet | grep $ip &>> /dev/null + if [ $? -eq 0 ] + then + tableNo=$(echo $dev | awk -F'eth' '{print $2}') + break + fi + done + if [ -z "$tableNo" ] + then + logger -t cloud "$(basename $0): failed due to cannot find eth device for public IP $publicIp" + return 3 + fi + + # shortcircuit the process if error and it is an append operation + # continue if it is delete + (sudo iptables -t nat $op PREROUTING -d $publicIp -j DNAT \ + --to-destination $instIp &>> $OUTFILE || [ "$op" == "-D" ]) && + # add mark to force the package go out through the eth the public IP is on + (sudo iptables -t mangle $op PREROUTING -s $instIp -j MARK \ + --set-mark $tableNo &> $OUTFILE || [ "$op" == "-D" ]) && + (sudo iptables -t nat $op2 POSTROUTING $rulenum -s $instIp -j SNAT \ + --to-source $publicIp &>> $OUTFILE ) + result=$? + logger -t cloud "$(basename $0): done static nat entry public ip=$publicIp op=$op result=$result" + return $result +} + + + +rflag= +Pflag= +pflag= +tflag= +lflag= +dflag= +sflag= +Gflag= +op="" + +while getopts 'ADr:P:p:t:l:d:s:G' OPTION +do + case $OPTION in + A) op="-A" + ;; + D) op="-D" + ;; + r) rflag=1 + instanceIp="$OPTARG" + ;; + P) Pflag=1 + protocol="$OPTARG" + ;; + p) pflag=1 + ports="$OPTARG" + ;; + t) tflag=1 + icmptype="$OPTARG" + ;; + l) lflag=1 + publicIp="$OPTARG" + ;; + s) sflag=1 + cidrs="$OPTARG" + ;; + d) dflag=1 + dport="$OPTARG" + ;; + G) Gflag=1 + ;; + ?) usage + unlock_exit 2 $lock $locked + ;; + esac +done + +DEV_LIST=$(get_dev_list) +OUTFILE=$(mktemp) + +#Firewall ports for one-to-one/static NAT +if [ "$Gflag" == "1" ] +then + if [ "$protocol" == "" ] + then + static_nat $publicIp $instanceIp $op + else + one_to_one_fw_entry $publicIp $instanceIp $protocol $dport $op + fi + result=$? + if [ "$result" -ne 0 ] && [ "$op" != "-D" ]; then + cat $OUTFILE >&2 + fi + rm -f $OUTFILE + if [ "$op" == "-D" ];then + result=0 + fi + unlock_exit $result $lock $locked +fi + +if [ "$sflag" != "1" ] +then + cidrs="0/0" +fi + +case $protocol in + tcp|udp) + tcp_or_udp_entry $instanceIp $dport $publicIp $ports $op $protocol $cidrs + result=$? + if [ "$result" -ne 0 ] && [ "$op" != "-D" ];then + cat $OUTFILE >&2 + fi + rm -f $OUTFILE + if [ "$op" == "-D" ];then + result=0 + fi + unlock_exit $result $lock $locked + ;; + "icmp") + + icmp_entry $instanceIp $icmptype $publicIp $op + if [ "$op" == "-D" ];then + result=0 + fi + unlock_exit $? $lock $locked + ;; + *) + printf "Invalid protocol-- must be tcp, udp or icmp\n" >&2 + unlock_exit 5 $lock $locked + ;; +esac + +unlock_exit 0 $lock $locked