@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
# Вызывается из socat EXEC; в окружении есть SOCAT_PEERADDR.
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
STATUS_FILE="${STATUS_FILE:-/var/www/cfb/status.html}"
|
||||
ALLOW="${STATUS_HTTP_ALLOW_IPS:-}"
|
||||
|
||||
ip_to_int() {
|
||||
local a b c d IFS=.
|
||||
read -r a b c d <<<"$1"
|
||||
[[ -n "$d" ]] || return 1
|
||||
echo $(((a << 24) | (b << 16) | (c << 8) | d))
|
||||
}
|
||||
|
||||
ipv4_in_cidr() {
|
||||
local ip="$1" cidr="$2" base masklen ipn basen mask
|
||||
[[ "$cidr" =~ ^([0-9]{1,3}(\.[0-9]{1,3}){3})/([0-9]{1,2})$ ]] || return 1
|
||||
base="${BASH_REMATCH[1]}"
|
||||
masklen="${BASH_REMATCH[3]}"
|
||||
(( masklen >= 0 && masklen <= 32 )) || return 1
|
||||
(( masklen == 0 )) && return 0
|
||||
ipn=$(ip_to_int "$ip") || return 1
|
||||
basen=$(ip_to_int "$base") || return 1
|
||||
(( masklen == 32 )) && { [[ "$ip" == "$base" ]]; return; }
|
||||
mask=$(( (0xFFFFFFFF << (32 - masklen)) & 0xFFFFFFFF ))
|
||||
(( (ipn & mask) == (basen & mask) ))
|
||||
}
|
||||
|
||||
extract_peer_ip() {
|
||||
local raw="${SOCAT_PEERADDR:-}"
|
||||
[[ -n "$raw" ]] || { echo ""; return 1; }
|
||||
if [[ "$raw" == \[*\]* ]]; then
|
||||
local inner="${raw#\[}"
|
||||
echo "${inner%%\]*}"
|
||||
return 0
|
||||
fi
|
||||
if [[ "$raw" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}:[0-9]+$ ]]; then
|
||||
echo "${raw%:*}"
|
||||
return 0
|
||||
fi
|
||||
echo "$raw"
|
||||
}
|
||||
|
||||
allowed_ip() {
|
||||
local peer="$1" entry trimmed
|
||||
[[ -n "$peer" ]] || return 1
|
||||
IFS=',' read -ra _entries <<<"$ALLOW"
|
||||
for entry in "${_entries[@]}"; do
|
||||
trimmed="${entry#"${entry%%[![:space:]]*}"}"
|
||||
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
|
||||
[[ -n "$trimmed" ]] || continue
|
||||
if [[ "$trimmed" == */* ]]; then
|
||||
if [[ "$peer" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then
|
||||
ipv4_in_cidr "$peer" "$trimmed" && return 0
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
[[ "$peer" == "$trimmed" ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Считать минимальный HTTP-запрос
|
||||
while IFS= read -r line; do
|
||||
line="${line%$'\r'}"
|
||||
[[ -z "$line" ]] && break
|
||||
done
|
||||
|
||||
peer_ip=$(extract_peer_ip)
|
||||
|
||||
hdr_ok=$'HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\n\r\n'
|
||||
hdr_denied=$'HTTP/1.0 403 Forbidden\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\nForbidden\r\n'
|
||||
|
||||
if [[ -z "${ALLOW// }" ]]; then
|
||||
# только loopback — на всякий случай
|
||||
if [[ "$peer_ip" != "127.0.0.1" && "$peer_ip" != "::1" ]]; then
|
||||
printf '%b' "$hdr_denied"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
if ! allowed_ip "$peer_ip"; then
|
||||
printf '%b' "$hdr_denied"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '%b' "$hdr_ok"
|
||||
if [[ -r "$STATUS_FILE" ]]; then
|
||||
cat "$STATUS_FILE"
|
||||
else
|
||||
printf '%s\n' '<!DOCTYPE html><html><body><p>status pending</p></body></html>'
|
||||
fi
|
||||
Reference in New Issue
Block a user