#!/bin/bash # # Rainbow GW helper service provides and RPC functionality for # obtaining predefined network configuration on WN side and # testing network connection to VM from the central point. # # Service also responsible for all centralized operations like # sending e-mails # # Request syntax: CMD_TYPE CMD [ ARGUMENTS ] # # Supported requests: # # NETCONFIG LEASEMAC # RELEASEMAC # GETIP # GETRDP # GETSSH # GETFWD # # NETTEST PING # MPING # NC # MNC # # NETSEND EMAIL # # # Authentication requests: # # AUTH GETTYPE # GENCOOKIE # DELCOOKIE # COOKIE # # # Setup environment # RAINBOW_CONFIG="/etc/rainbow-helper.conf" [ -f "$RAINBOW_CONFIG" ] && source "$RAINBOW_CONFIG" RAINBOW_MAC_BASE=${RAINBOW_MAC_BASE:-00:52:54:c1:0d:00} RAINBOW_STATEDIR=${RAINBOW_STATEDIR:-/var/spool/rainbow-helper} RAINBOW_LIBEXEC=${RAINBOW_LIBEXEC:-/usr/libexec/rainbow} # # Source libs # [ -f "$RAINBOW_LIBEXEC/libdhcpd.sh" ] && source "$RAINBOW_LIBEXEC/libdhcpd.sh" || exit 1 [ -f "$RAINBOW_LIBEXEC/libiptables.sh" ] && source "$RAINBOW_LIBEXEC/libiptables.sh" || exit 1 [ -f "$RAINBOW_LIBEXEC/libmail.sh" ] && source "$RAINBOW_LIBEXEC/libmail.sh" || exit 1 # # Functions # release_mac () { local macaddr=$1 macaddr=${macaddr//:/} macdir="$RAINBOW_STATEDIR/$macaddr" # remove iptables forwards for ipt in $( find "$macdir" -name '*forward*' ); do eval $( cat $ipt | sed 's/-A RAINBOW/-D RAINBOW/' ) done # remove spool directory rm -rf $macdir } lease_mac () { lease_time=$1 [ -z "$lease_time" ] && lease_time=86400 mac2lease=${RAINBOW_MAC_BASE//:/} while true; do macdir="$RAINBOW_STATEDIR/$mac2lease" # check if already leased if [ -d "$macdir" ]; then # check expired if [ -f "$macdir/expired" ]; then lease_expired=$( cat "$macdir/expired" ) if [ $lease_expired -lt $(date +'%s') ]; then # if expired - release and reuse release_mac $mac2lease continue fi fi mac2lease=$( printf "%012x\n" $((0x${mac2lease}+1)) ) continue else # create spool dir and write lease expiration time mkdir -p "$macdir" echo $(( $( date +'%s' ) + $lease_time )) > "$macdir/expired" mac_colons ${mac2lease} break fi done } get_mac2ip () { local macaddr=$1 macdir="$RAINBOW_STATEDIR/${macaddr//:/}" mkdir -p "$macdir" if [ -f "$macdir/ipaddr" ]; then cat "$macdir/ipaddr" else dhcpip=$( get_dhcp_ip "$macaddr" ) if [ -n "$dhcpip" ]; then echo "$dhcpip" > $macdir/ipaddr echo "$dhcpip" fi fi } get_vm_ip () { local macaddr=$1 get_mac2ip "$macaddr" } get_port_forward () { local macaddr=$1 local fwdport=$2 macdir="$RAINBOW_STATEDIR/${macaddr//:/}" mkdir -p "$macdir" fwdfile="$macdir/forward.${fwdport}" if [ -f "$fwdfile" ]; then localport=$( cat "$fwdfile" | sed 's/.*--dport \([0-9]\+\).*/\1/' ) else ipaddr=$( get_mac2ip "$macaddr" ) localport=$( get_next_fwd_port ) iptr=$( get_rainbow_fwdrule "${localport}" "${ipaddr}:${fwdport}" | tee "$fwdfile" ) eval $iptr fi echo "${FWD_WAN_IP}:${localport}" } get_rdp_forward () { local macaddr=$1 get_port_forward $macaddr 3389 } get_ssh_forward () { local macaddr=$1 get_port_forward $macaddr 22 } nettest_ping () { local ip=$1 ping -c 1 $ip >/dev/null 2>&1 echo $? } nettest_ping_mac () { local macaddr=$1 ip=$( get_mac2ip "$macaddr" ) [ -n "$ip" ] && nettest_ping "$ip" || echo 1 } nettest_nc () { local ip=$1 local port=$2 nmap $ip -p $port -oG - | grep -iq "${port}/open" echo $? } nettest_nc_mac () { local macaddr=$1 local port=$2 ip=$( get_mac2ip "$macaddr" ) [ -n "$ip" ] && nettest_nc "$ip" "$port" || echo 1 } create_auth_cookie () { local authtime=$1 local cookies_dir="$RAINBOW_STATEDIR/cookies" mkdir -p "$cookies_dir" local cookie=$( ( date +'%s'; ss ) | md5sum | cut -f1 -d' ' ) echo $(( $( date +'%s' ) + $authtime )) > "$cookies_dir/$cookie" echo $cookie } check_auth_cookie () { local cookie=$1 local cookies_dir="$RAINBOW_STATEDIR/cookies" local current_utime=$( date +'%s' ) # regular expired cookies cleaning (once per 12 hours) [ ! -f "$cookies_dir/cleanup" ] && echo "9999999999" > "$cookies_dir/cleanup" local lastcleanup=$( stat -c '%Y' $cookies_dir/cleanup ) if [ $current_utime -gt $(( lastcleanup + 43200 )) ]; then find $cookies_dir | while read cname; do local cookie_utime=$( cat "$cname" ) [ $current_utime -ge "$cookie_utime" ] && rm -f $cname done fi # check cookie exists and not expired if [ -f "$cookies_dir/$cookie" ]; then local cookie_utime=$( cat "$cookies_dir/$cookie" ) [ $current_utime -lt "$cookie_utime" ] && return 0 fi return 1 } clean_auth_cookie () { local cookie=$1 local cookies_dir="$RAINBOW_STATEDIR/cookies" rm -f "$cookies_dir/$cookie" } # # activate iptables rules if not previously activated # if ! check_rainbow_rules; then cleanup_rainbow_rules init_rainbow_rules fi # # Process request # read cmdtype cmd args if [ -z "${REMOTE_HOST}" ]; then # systemd socket activation instead of xinetd REMOTE_HOST=$1 REMOTE_HOST=${REMOTE_HOST##*-} REMOTE_HOST=${REMOTE_HOST%:*} fi if [ "$cmdtype" = "AUTH" ]; then if [ "$cmd" = "GETTYPE" ]; then echo ${HELPER_AUTH:-none} exit elif [ "$HELPER_AUTH" = "cookie" ]; then if [ "$cmd" = "GENCOOKIE" ]; then # check source IP cookie_ip_var="COOKIE_CREATOR_IP" cookie_ip_idx=1 while [ -n "${!cookie_ip_var}" ]; do if [ "${REMOTE_HOST/::ffff:/}" = "${!cookie_ip_var}" ]; then create_auth_cookie $args exit fi cookie_ip_idx=$(( cookie_ip_idx+1 )) cookie_ip_var="COOKIE_CREATOR_IP${cookie_ip_idx}" done echo "Failed. Unauthorized attempt to create a new auth cookie." exit elif [ "$cmd" = "DELCOOKIE" ]; then clean_auth_cookie $args exit elif [ "$cmd" = "COOKIE" ]; then if ! check_auth_cookie $args ; then echo "Failed. Bad authentication cookie provided." exit 1 fi else echo "Failed. Unsupported AUTH command." exit 1 fi fi read cmdtype cmd args elif [ -n "${HELPER_AUTH}" -a "${HELPER_AUTH}" != "none" ]; then echo "FAILED: Authentication is required but not performed. Request denied." exit 1 fi case "$cmdtype" in NETCONFIG) case "$cmd" in LEASEMAC) lease_mac "$args" ;; RELEASEMAC) release_mac "$args" ;; GETIP) get_vm_ip "$args" ;; GETFWD) get_port_forward $args ;; GETRDP) get_rdp_forward "$args" ;; GETSSH) get_ssh_forward "$args" ;; *) echo "Invalid command" ;; esac ;; NETTEST) case "$cmd" in PING) nettest_ping "$args" ;; NC) nettest_nc $args ;; MPING) nettest_ping_mac "$args" ;; MNC) nettest_nc_mac $args ;; *) echo "Invalid command" ;; esac ;; NETSEND) case "$cmd" in EMAIL) read state state_args send_email $args "$state" $state_args ;; *) echo "Invalid command" ;; esac ;; *) echo "Invalid command type" ;; esac