#!/usr/bin/bash ################################################################################# # # Logon-скрипт для ocserv. # # На основе переменных передаваемых ocserv и географических # данных формирует файл-журнал с данными пользовательских сессий # ################################################################################# # Автор: Сергей Калинин # https://nuk-svk.ru # svk@nuk-svk.ru ################################################################################# # Список переменных: # REASON, VHOST, USERNAME, GROUPNAME, DEVICE, IP_REAL (the real IP of the client), # IP_REAL_LOCAL (the local interface IP the client connected), IP_LOCAL # (the local IP in the P-t-P connection), IP_REMOTE (the VPN IP of the client), # IPV6_LOCAL (the IPv6 local address if there are both IPv4 and IPv6 # assigned), IPV6_REMOTE (the IPv6 remote address), IPV6_PREFIX, and # ID (a unique numeric ID); REASON may be "connect" or "disconnect". # In addition the following variables OCSERV_ROUTES (the applied routes for this # client), OCSERV_NO_ROUTES, OCSERV_DNS LOG_DIR="/var/log/ocserv" LOG_FILE=${LOG_DIR}/sessions.log # Формат выходной строки (text, json) LOG_FORMAT="json" # Коды стран разрешённые к соединению # можно передать ввиде списка "RU SA IC TW" ALLOW_COUNTRY_CODES="RU" if [ ! -d "$LOG_DIR" ]; then mkdir -p ${LOG_DIR} fi # Получаем географические данные по IP адресу, вернет строку вида: #109.106.141.24,RU,Russia,VOR,Voronezhskaya Oblast',Voronezh,394000,Europe/Moscow,51.6592,39.2269,0 # можно получать в json - "curl -s https://freegeoip.live/json/${IP_REAL}" GEO_DATA=`curl --connect-timeout 5 -s https://freegeoip.live/csv/${IP_REAL}` if [ -z "${GEO_DATA}" ]; then COUNTRY_CODE="RU" LAT="0" LON="0" else # Выбираем код страны и координаты COUNTRY_CODE=`echo ${GEO_DATA} | cut -d"," -f 2` LAT=`echo ${GEO_DATA} | cut -d"," -f 9` LON=`echo ${GEO_DATA} | cut -d"," -f 10` fi DATE=`date +'%d.%m.%Y %T'` # Преобразуем имена пользователей к нижнему регистру USER_NAME=`echo ${USERNAME} | tr '[:upper:]' '[:lower:]'` # Проверяем имя пользователя на имя домена, # сперва в формате "user@domain" потом "domain\user" \\domain\user # и выдергиваем только имя пользователя TEMP_USER_NAME=`echo ${USER_NAME} | egrep -E "[[:alnum:]]+@" -o | tr -d "@"` if [ -n "${TEMP_USER_NAME}" ]; then SHORT_USER_NAME="${TEMP_USER_NAME}" else TEMP_USER_NAME=`echo $USER_NAME | awk -F '\\' '{print $2}'` if [ -n "${TEMP_USER_NAME}" ]; then SHORT_USER_NAME="${TEMP_USER_NAME}" else TEMP_USER_NAME=`echo $USER_NAME | awk -F '\\' '{print $4}'` if [ -n "${TEMP_USER_NAME}" ]; then SHORT_USER_NAME="${TEMP_USER_NAME}" else SHORT_USER_NAME="${USER_NAME}" fi fi fi # Проверяем что ocserv вернул нам реальный ip адрес (откуда пользователь заходит) # если адреса нет - в соединении отказываем # И соответствующим образом формируем строку для журнала в нужном формате if [ "x${IP_REAL}" = "x" ]; then if [ ${LOG_FORMAT} == 'json' ]; then OUT_STRING="{\"session-datetime\": \"${DATE}\", \"reason\": \"empty_real_ip\", \"remote-user\": \"${SHORT_USER_NAME}\", \ \"remote-user-group\": \"${GROUPNAME}\", \"session-id\": \"${ID}\", \ \"country_code\": \"${COUNTRY_CODE}\", \"location\": {\"lat\": ${LAT},\"lon\": ${LON}}}" else OUT_STRING="${DATE} ${SHORT_USER_NAME} \"Empty real IP address\" ${ID} ${VHOST} ${DEVICE} ${IP_REAL} ${IP_REAL_LOCAL} \ ${IP_LOCAL} ${IP_REMOTE} ${OCSERV_ROUTES} ${OCSERV_NO_ROUTES} ${OCSERV_DNS} ${COUNTRY_CODE}" fi echo "${OUT_STRING}" >> ${LOG_FILE} exit 1 fi # Формируем выходную строку, для раазрешенного соединения, в нужном формате if [ ${LOG_FORMAT} == 'json' ]; then OUT_STRING="{\"session-datetime\": \"${DATE}\", \"reason\": \"${REASON}\", \"remote-user\": \"${SHORT_USER_NAME}\", \ \"remote-user-group\": \"${GROUPNAME}\", \"session-id\": \"${ID}\", \"vhost\": \"${VHOST}\", \"device\": \"${DEVICE}\", \ \"real-ip\": \"${IP_REAL}\", \"real-local-ip\": \"${IP_REAL_LOCAL}\", \"local-ip\": \"${IP_LOCAL}\", \"remote-ip\": \"${IP_REMOTE}\", \ \"ocserv-routes\": \"${OCSERV_ROUTES}\", \"ocserv-no-routes\": \"${OCSERV_NO_ROUTES}\", \"ocserv-dns\": \"${OCSERV_DNS}\", \ \"country_code\": \"${COUNTRY_CODE}\", \"location\": {\"lat\": ${LAT},\"lon\": ${LON}}}" else OUT_STRING="${DATE} ${SHORT_USER_NAME} ${REASON} ${ID} ${VHOST} ${DEVICE} ${IP_REAL} ${IP_REAL_LOCAL} \ ${IP_LOCAL} ${IP_REMOTE} ${OCSERV_ROUTES} ${OCSERV_NO_ROUTES} ${OCSERV_DNS} ${COUNTRY_CODE}" fi # Если значение COUNTRY_CODE пустое (e.g. RFC 1918 addresses) то if [ "x${COUNTRY_CODE}" = "x" ]; then echo "${OUT_STRING}" >> ${LOG_FILE} # Разрешаем соединение exit 0 # Запрещаем соединение # exit 1 fi # Если COUNTRY_CODE совпадает с одним из разрешенных то пишем в лог # и благополучно завершаем скрипт for c in $ALLOW_COUNTRY_CODES; do if [ "${c}" = "${COUNTRY_CODE}" ]; then echo "${OUT_STRING}" >> ${LOG_FILE} exit 0 fi done # Если COUNTRY_CODE не совпадает с разрешенным то даём отлуп # И пишем о сём факте в лог if [ ${LOG_FORMAT} == 'json' ]; then OUT_STRING="{\"session-datetime\": \"${DATE}\", \"reason\": \"not_allowed_country_code\", \"remote-user\": \"${SHORT_USER_NAME}\", \ \"remote-user-group\": \"${GROUPNAME}\", \"session-id\": \"${ID}\", \"real-ip\": \"${IP_REAL}\", \ \"country_code\": \"${COUNTRY_CODE}\", \"location\": {\"lat\": ${LAT},\"lon\": ${LON}}}" else OUT_STRING="${DATE} ${SHORT_USER_NAME} \"Not allowed country code\" ${ID} ${VHOST} ${DEVICE} ${IP_REAL} ${IP_REAL_LOCAL} \ ${IP_LOCAL} ${IP_REMOTE} ${OCSERV_ROUTES} ${OCSERV_NO_ROUTES} ${OCSERV_DNS} ${COUNTRY_CODE}" fi echo "${OUT_STRING}" >> ${LOG_FILE} exit 1