Настройка OpenVPN. Запретить конкурентные подключения

Не такой уж и праздный вопрос оказался — запретить конкурентные подключения с одним и тем же сертификатом. По умолчанию, если такие соединения случаются, то «живая» сессия будет с тем, кто подключился последним. Предыдущие сессии ломаются и в последствии отвативаются. И это не зависит от того с одного внешнего IP были соединения или с разных. Один читатель этого блога задал подобный вопрос. И вот какое решение удалось найти (сразу скажу — не мое) и протестировать

На стороне сервера

Общая идея состоит в том, что на стороне сервера мы разрешаем конкурентные подключения, однако будем ограничивать их количество

В openvpn.conf добавляем следующие параметры

duplicate-cn
script-security 2
up /etc/openvpn/connectScript.sh
client-connect /etc/openvpn/connectScript.sh
client-disconnect /etc/openvpn/connectScript.sh

duplicate-cn — разрешает одновременные подключения
script-security 2 — разрешает запуск внешних скриптов
up, client-connect, client-disconnect — переменные окружения, передаются в скрипт connectScript.sh (см. Environmental Variables)

Скрипт connectScript.sh

#!/bin/bash

PERSIST_DIR=/tmp/pDir
mkdir -p $PERSIST_DIR
# владелец $PERSIST_DIR должен быть тот же, о чьего имени работает OpenVPN
chown nobody:nobody $PERSIST_DIR

function handle_connect {
CLIENTFILE=$PERSIST_DIR/$common_name
if [ -e "$CLIENTFILE" ]; then
NUMCONN=$(cat $CLIENTFILE)
NEWCONN=$(expr $NUMCONN + 1)
# следующая строка ограничивает кол-во подключений
# в данном случае не больше чем одно
if [ $NEWCONN -gt 1 ]; then exit 1; fi
echo $NEWCONN >$CLIENTFILE
else
echo 1 >$CLIENTFILE
fi
}

function handle_disconnect {
CLIENTFILE=$PERSIST_DIR/$common_name
if [ -e "$CLIENTFILE" ]; then
NUMCONN=$(cat $CLIENTFILE)
NEWCONN=$(expr $NUMCONN - 1)
echo $NEWCONN >$CLIENTFILE
fi
}

case "$script_type" in
  up)
      rm -f $PERSIST_DIR/$common_name
      ;;
  client-connect)
      "handle_connect"
      ;;
  client-disconnect)
      "handle_disconnect"
      ;;
esac

Задаем владельца и права на скрипт

chown nobody:nobody connectScript.sh
chmod 755 connectScript.sh

Проверка конфига и перезапуск сервера

openvpn --config openvpn.conf
rc-service openvpn restart

На стороне клиента

Добавляем в конфиг параметр

explicit-exit-notify

Без этого параметра сервер не получит сообщение о разъединении в случае отключения клиента. Поэтому сценарий отключения будет вызываться только по таймауту

Пробуем

P.S.

Обращаюсь к админам, которым это нужно. Объясните в комментариях, зачем?

378