shell bypass 403
#!/bin/sh
#
# Copyright (c) 2006-2017 Varnish Software AS
# All rights reserved.
#
# Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
set -e
set -u
MAXIMUM=
VCL_FILE=
VCL_LABEL=
VCL_NAME=
WARMUP=
WORK_DIR=
SCRIPT="$0"
usage() {
test $# -eq 1 &&
printf 'Error: %s.\n\n' "$1"
cat <<-EOF
Usage: $SCRIPT [-l <label>] [-m <max>] [-n <workdir>] [-w <warmup>] [<file>]
$SCRIPT -h
Reload and use a VCL on a running Varnish instance.
Available options:
-h : show this help and exit
-l <label> : name of the VCL label to reload
-m <max> : maximum number of available reloads to leave behind
-n <workdir> : specify the name or directory for the varnishd instance
-w <warmup> : the number of seconds between load and use operations
When <label> is empty or missing, the active VCL is reloaded. If the
reloaded VCL is a label, the underlying VCL program is reloaded, and
the label is updated to reference the new program.
When <file> is empty or missing, the selected VCL's file is used but
reload will fail if it wasn't loaded from a file. The <file>, when
specified, is passed as-is to the vcl.load command. Refer to the
varnishd manual regarding the handling of absolute or relative paths.
Upon success, the name of the loaded VCL is constructed from the
current date and time, for example:
$(vcl_reload_name)
Afterwards available VCLs created by this script are discarded until
<max> are left, unless it was empty or undefined. VCLs referenced by
a label aren't discarded.
EOF
exit $#
}
varnishadm() {
if ! OUTPUT=$(command varnishadm -n "$WORK_DIR" -- "$@" 2>&1)
then
echo "Command: varnishadm -n '$WORK_DIR' -- $*"
echo
echo "$OUTPUT"
echo
return 1
fi >&2
echo "$OUTPUT"
}
fail() {
echo "Error: $*" >&2
exit 1
}
vcl_reload_name() {
# NB: The PID compensates the lack of sub-second resolution.
# Varnish will vcl.list in chronological vcl.load order anyway.
printf "reload_%s" "$(date -u +%Y%m%d_%H%M%S_$$)"
}
awk_vcl_list() {
printf '%s' "$VCL_LIST" | awk "$@"
}
active_vcl() {
awk_vcl_list '$1 == "active" {print $4}'
}
find_label_ref() {
awk_vcl_list '$4 == "'"$VCL_LABEL"'" && $5 == "->" {print $6}'
}
find_vcl_file() {
VCL_SHOW=$(varnishadm vcl.show -v "$VCL_NAME") ||
fail "failed to get the VCL file name"
echo "$VCL_SHOW" |
awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}' | {
# all this ceremony to handle blanks in FILE
read -r DELIM VCL_SHOW INDEX SIZE FILE
echo "$FILE"
}
}
find_vcl_reloads() {
awk_vcl_list 'NF == 4 &&
$1 == "available" &&
$4 ~ /^reload_[0-9]+_[0-9]+_[0-9]+$/ {print $4}'
}
while getopts hl:m:n:w: OPT
do
case $OPT in
h) usage ;;
l) VCL_LABEL=$OPTARG ;;
m) MAXIMUM=$OPTARG ;;
n) WORK_DIR=$OPTARG ;;
w) WARMUP=$OPTARG ;;
*) usage "wrong usage" >&2 ;;
esac
done
shift $((OPTIND - 1))
test $# -gt 1 && usage "too many arguments" >&2
test $# -eq 1 && VCL_FILE="$1"
VCL_LIST=$(varnishadm vcl.list) ||
fail "failed to get the VCL list"
if [ -z "$VCL_LABEL" ]
then
VCL_NAME=$(active_vcl)
VCL_LABEL=$VCL_NAME
VCL_REF=$(find_label_ref)
if [ -n "$VCL_REF" ]
then
# active VCL is a label, swap
VCL_LABEL=$VCL_NAME
VCL_NAME=$VCL_REF
else
# not a label after all
VCL_LABEL=
fi
else
VCL_NAME=$(find_label_ref)
fi
test -n "$VCL_NAME" ||
fail "'$VCL_LABEL' is not a label"
if [ -z "$VCL_FILE" ]
then
VCL_FILE=$(find_vcl_file)
case $VCL_FILE in
/*) ;;
*) fail "VCL file not found for $VCL_NAME (got $VCL_FILE)" ;;
esac
fi
RELOAD_NAME=$(vcl_reload_name)
varnishadm vcl.load "$RELOAD_NAME" "$VCL_FILE" >/dev/null
echo "VCL '$RELOAD_NAME' compiled"
test -n "$WARMUP" && sleep "$WARMUP"
if [ -n "$VCL_LABEL" ]
then
varnishadm vcl.label "$VCL_LABEL" "$RELOAD_NAME" >/dev/null
echo "VCL label '$VCL_LABEL' references '$RELOAD_NAME'"
fi
if [ "$VCL_NAME" = "$(active_vcl)" ]
then
varnishadm vcl.use "$RELOAD_NAME"
fi
test -n "$MAXIMUM" || exit 0
test "$MAXIMUM" -ge 0 || exit 0
VCL_LIST=$(varnishadm vcl.list) ||
fail "failed to refresh the VCL list"
AVAILABLE=$(find_vcl_reloads | wc -l)
DISCARDED=$((AVAILABLE - MAXIMUM))
test "$DISCARDED" -gt 0 || exit 0
find_vcl_reloads |
head -n "$DISCARDED" |
while read -r DISCARD_NAME
do
varnishadm vcl.discard "$DISCARD_NAME" >/dev/null
echo "VCL '$DISCARD_NAME' discarded"
done