#!/bin/sh argc=$# if [ $argc -lt 5 -o $((argc % 2)) -ne 1 ]; then { echo "tcplb.sh 20260917 - TCP loadbalancing shell script" echo echo "Usage:" echo " tcplb.sh \\" echo " ... \\" echo " " echo echo " tag each line written to syslog with " echo " write syslog messages in the given " echo " disconnect after being idle for seconds" echo " ..." echo " backend or real server address" echo echo "Example:" echo " To start tcplb.sh from inetd, add this line to /etc/inetd.conf:" echo echo " http stream tcp nowait nobody /usr/local/libexec/tcplb.sh \\" echo " tcplb.sh webproxy daemon 5 10.0.0.1 8081 10.0.0.2 8080" echo echo " Each connection to port 80 on the local machine will randomly be" echo " connected to 10.0.0.1:8081 or 10.0.0.2:8080. If one backend service" echo " is down, then another one is chosen." echo " In the above example, tcplb.sh runs as unprivileged user 'nobody'," echo " each syslog message is tagged as 'webproxy' and is written to the" echo " 'daemon' facility. If a connection has been inactive for at least" echo " 5 seconds, it will be terminated." exit 1 } >&2 fi progname="$1" facility="$2" timeout="$3" shift 3 # "host port" per line, lines shuffled hosts=`while [ -n "$2" ]; do echo "$1 $2" shift 2 done | random -f -` cntavail=$(((argc-3)/2)) retval=1 # retry until connection succeeds, or no more hosts available while [ $cntavail -ge 1 -a $retval -ne 0 ]; do # split host and port addr=`echo "$hosts" | head -n $cntavail | tail -n 1` host="${addr%% *}" port="${addr##* }" # the actual proxy connection # connect fd 3 to stdout outside the command group, i.e. to the client who # connected to inetd # inside the command group, connect stderr to stdout, captured by errmsg # connect stdout of nc to fd 3, opened outside the command group { errmsg=`nc -v -w "$timeout" "$host" "$port" 2>&1 >&3 3>&-` } 3>&1 retval=$? # log to syslog if [ $retval -eq 0 ]; then logger -p "$facility.info" -t "$progname[$$]" \ "host=$host port=$port retval=$retval" else logger -p "$facility.warn" -t "$progname[$$]" \ "host=$host port=$port retval=$retval errmsg=$errmsg" fi # start at bottom line, then work up to first entry of hosts cntavail=$((cntavail-1)) done exit $retval