Skip to content

Instantly share code, notes, and snippets.

@mkorthof
Last active September 10, 2022 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkorthof/e02838ef68ca33ad3bad19d6c644749e to your computer and use it in GitHub Desktop.
Save mkorthof/e02838ef68ca33ad3bad19d6c644749e to your computer and use it in GitHub Desktop.
Piped logger for Apache to use with OpenVPN port_share (logs real client ip)
#!/bin/sh
# pslog.sh - Piped logger for Apache to use with OpenVPN + port sharing
# Replaces remote ip in logs with real client ip
#
# USAGE: ErrorLog "|/usr/local/bin/pslog.sh ${APACHE_LOG_DIR}/error.log"
# CustomLog "|/usr/local/bin/pslog.sh ${APACHE_LOG_DIR}/access.log" combined
#
# REQUIRES: openvpn server config "port-share 127.0.0.1 10443 portshare"
# where 'portshare' is journal dir for tmp files (e.g. /run/openvpn/portshare if chrooted)
#
test -n "$1" && test -w "$1" && logfile="$1" || exit 1 # check for writable log
journal_dir="/run/openvpn_as/portshare"
openvpn_log="/var/log/openvpnas.log"
ip_regex='s/(.*\[AF_INET\])?(([0-9]{1,3}\.){1}([0-9]{1,3}\.){2}[0-9]{1,3}(:[0-9]+)?) ?.*/\2/p'
test -d "$journal_dir" || \
{ install -m 700 -o openvpn_as -g openvpn_as -d "$journal_dir"; } # create journal dir
# EXAMPLE:
# tmpfile /run/openvpn/portshare/[AF_INET]127.0.0.1:12345 "[AF_INET]12.34.56.78:54321"
# logfile 2020-01-01T17:00:58+0200 [stdout#info] [OVPN 0] OUT: '2020-01-01 17:00:58 TCP connection established with [AF_INET]123.45.67.89:54321'
while read -r stdin; do
unset to_saddr from_saddr to_ip from_ip
for i in "$journal_dir"/\[AF_INET\]*:*; do
# first try to get ip from journal dir files
to_saddr="$( echo "$i" | sed -nr "$ip_regex" 2>/dev/null )" && \
{ to_ip="$( echo "$to_saddr" | cut -d: -f1 )" || to_ip=""; }
from_saddr="$( sed -nr "$ip_regex" "$i" 2>/dev/null )" && \
{ from_ip="$( echo "$from_saddr" | cut -d: -f1 )" || from_ip=""; }
# fallback: if no src ip found, try tailing openvpn log
if [ "$to_ip" = "" ] && [ -z "$to_saddr" ] && [ -z "$from_saddr" ]; then
to_saddr="$( echo "$stdin" | sed -nr "$ip_regex" 2>/dev/null )"
to_ip="$( echo "$to_saddr" | cut -d: -f1 )"
line="$( tail -10 "$openvpn_log" | tac | grep -m 1 "TCP.*AF_INET" )"
from_saddr="$( echo "$line" | awk '{ print $(NF) }' | sed -nr "$ip_regex" 2>/dev/null )"
from_ip="$( echo "$from_saddr" | cut -d: -f1 )"
ts="$( echo "$line" | awk '{ print $1, $2 }' | cut -d+ -f1 )"
if [ -n "$to_saddr" ] && [ -n "$from_saddr" ]; then
ap_fmt="+%d/%b/%Y:%H:%M:%S"
ap_ts="$( date "$ap_fmt" -d"$ts" )"
ap_ts_1s_add="$( date "$ap_fmt" -d"$ts 1 second" )"
ap_ts_1s_ago="$( date "$ap_fmt" -d"$ts 1 second ago" )"
# replace ip only if timestamp is between -1s and +1s
if echo "$stdin" | grep -Eq "($ap_ts|$ap_ts_1s_add|$ap_ts_1s_ago)"; then
if [ "$to_saddr" != "$to_ip" ]; then
echo "$stdin" | sed -e "s/$to_saddr/$from_saddr/" -e "s/$to_ip/$from_ip/" >> "$logfile"
else
echo "$stdin" | sed -e "s/$to_ip/$from_ip/" >> "$logfile"
fi
fi
# no matching lines
else
echo "$stdin" >> "$logfile"
fi
# cant get ip but have socket address, write that to log instead
elif [ -n "$to_saddr" ] && [ -n "$from_saddr" ]; then
echo "$stdin" | sed -e "s/$to_saddr/$from_saddr/" -e "s/$to_ip/$from_ip/" >> "$logfile"
# no tmp file matches, write unchanged input to log
else
echo "$stdin" >> "$logfile"
fi
done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment