mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
291 lines
9.1 KiB
Bash
Executable File
291 lines
9.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
|
|
#
|
|
# This software is licensed under the GNU General Public License v3 or later.
|
|
#
|
|
# It is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or any later version.
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# $Id: firewall.sh 9947 2010-06-25 19:34:24Z manuel $ $HeadURL: svn://svn.lab.vmops.com/repos/vmdev/java/patches/xenserver/root/firewall.sh $
|
|
# firewall.sh -- allow some ports / protocols to vm instances
|
|
#
|
|
#
|
|
# @VERSION@
|
|
|
|
source /root/func.sh
|
|
|
|
lock="biglock"
|
|
locked=$(getLockFile $lock)
|
|
if [ "$locked" != "1" ]
|
|
then
|
|
exit 1
|
|
fi
|
|
|
|
usage() {
|
|
printf "Usage: %s: (-A|-D) -r <target-instance-ip> -P protocol (-p port_range | -t icmp_type_code) -l <public ip address> -d <target port> -s <source cidrs> [-G] \n" $(basename $0) >&2
|
|
}
|
|
|
|
#set -x
|
|
|
|
get_dev_list() {
|
|
ip link show | grep -e eth[2-9] | awk -F ":" '{print $2}'
|
|
ip link show | grep -e eth1[0-9] | awk -F ":" '{print $2}'
|
|
}
|
|
|
|
ip_to_dev() {
|
|
local ip=$1
|
|
|
|
for dev in $DEV_LIST; do
|
|
ip addr show dev $dev | grep inet | grep $ip &>> /dev/null
|
|
[ $? -eq 0 ] && echo $dev && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
|
|
#Port (address translation) forwarding for tcp or udp
|
|
tcp_or_udp_entry() {
|
|
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
|
|
local dev=$(ip_to_dev $publicIp)
|
|
# shortcircuit the process if error and it is an append operation
|
|
# continue if it is delete
|
|
(sudo iptables -t nat $op PREROUTING --proto $proto -i $dev -d $publicIp \
|
|
--destination-port $port -j DNAT \
|
|
--to-destination $instIp:$dport &>> $OUTFILE || [ "$op" == "-D" ]) &&
|
|
(sudo iptables -t nat $op OUTPUT --proto $proto -d $publicIp \
|
|
--destination-port $port -j DNAT \
|
|
--to-destination $instIp:$dport &>> $OUTFILE || [ "$op" == "-D" ]) &&
|
|
(sudo iptables $op FORWARD -p $proto -s $cidrs -d $instIp -m state \
|
|
--state ESTABLISHED,RELATED -m comment --comment "$publicIp:$port" -j ACCEPT &>> $OUTFILE || [ "$op" == "-D" ]) &&
|
|
(sudo iptables $op FORWARD -p $proto -s $cidrs -d $instIp \
|
|
--destination-port $dport0 -m state --state NEW -m comment --comment "$publicIp:$port" -j ACCEPT &>> $OUTFILE)
|
|
|
|
|
|
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
|
|
local dev=$(ip_to_dev $publicIp)
|
|
sudo iptables -t nat $op PREROUTING --proto icmp -i $dev -d $publicIp --icmp-type $icmptype -j DNAT --to-destination $instIp &>> $OUTFILE
|
|
|
|
sudo iptables -t nat $op OUTPUT --proto icmp -d $publicIp --icmp-type $icmptype -j DNAT --to-destination $instIp &>> $OUTFILE
|
|
sudo iptables $op FORWARD -p icmp -s 0/0 -d $instIp --icmp-type $icmptype -j ACCEPT &>> $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
|
|
|
|
local dev=$(ip_to_dev $publicIp)
|
|
[ $? -ne 0 ] && echo "Could not find device associated with $publicIp" && return 1
|
|
|
|
# shortcircuit the process if error and it is an append operation
|
|
# continue if it is delete
|
|
(sudo iptables -t nat $op PREROUTING -i $dev -d $publicIp --proto $proto \
|
|
--destination-port $portRange -j DNAT \
|
|
--to-destination $instIp &>> $OUTFILE || [ "$op" == "-D" ]) &&
|
|
(sudo iptables $op FORWARD -i $dev -o eth0 -d $instIp --proto $proto \
|
|
--destination-port $portRange -m state \
|
|
--state NEW -j ACCEPT &>> $OUTFILE )
|
|
|
|
result=$?
|
|
logger -t cloud "$(basename $0): done firewall entry public ip=$publicIp op=$op result=$result"
|
|
return $result
|
|
}
|
|
|
|
fw_chain_for_ip() {
|
|
local pubIp=$1
|
|
if iptables -t mangle -N FIREWALL_$pubIp &> /dev/null
|
|
then
|
|
logger -t cloud "$(basename $0): created a firewall chain for $pubIp"
|
|
(sudo iptables -t mangle -A FIREWALL_$pubIp -j DROP) &&
|
|
(sudo iptables -t mangle -I FIREWALL_$pubIp -m state --state RELATED,ESTABLISHED -j ACCEPT ) &&
|
|
(sudo iptables -t mangle -I PREROUTING 2 -d $pubIp -j FIREWALL_$pubIp)
|
|
return $?
|
|
fi
|
|
logger -t cloud "fw chain for $pubIp already exists"
|
|
return 0
|
|
}
|
|
|
|
static_nat() {
|
|
local publicIp=$1
|
|
local instIp=$2
|
|
local op=$3
|
|
local op2="-D"
|
|
local rulenum=
|
|
logger -t cloud "$(basename $0): static nat: public ip=$publicIp \
|
|
instance ip=$instIp op=$op"
|
|
|
|
#TODO check error below
|
|
fw_chain_for_ip $publicIp
|
|
|
|
#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"
|
|
|
|
local dev=$(ip_to_dev $publicIp)
|
|
[ $? -ne 0 ] && echo "Could not find device associated with $publicIp" && return 1
|
|
|
|
# shortcircuit the process if error and it is an append operation
|
|
# continue if it is delete
|
|
(sudo iptables -t nat $op PREROUTING -i $dev -d $publicIp -j DNAT \
|
|
--to-destination $instIp &>> $OUTFILE || [ "$op" == "-D" ]) &&
|
|
(sudo iptables $op FORWARD -i $dev -o eth0 -d $instIp -m state \
|
|
--state NEW -j ACCEPT &>> $OUTFILE || [ "$op" == "-D" ]) &&
|
|
(sudo iptables -t nat $op2 POSTROUTING $rulenum -s $instIp -j SNAT \
|
|
--to-source $publicIp &>> $OUTFILE || [ "$op" == "-D" ])
|
|
|
|
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=$?
|
|
[ "$result" -ne 0 ] && cat $OUTFILE >&2
|
|
rm -f $OUTFILE
|
|
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=$?
|
|
[ "$result" -ne 0 ] && cat $OUTFILE >&2
|
|
rm -f $OUTFILE
|
|
unlock_exit $result $lock $locked
|
|
;;
|
|
"icmp")
|
|
|
|
icmp_entry $instanceIp $icmptype $publicIp $op
|
|
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
|