Где должна находиться месячная квота трафика на учётную запись OpenVPN
Квота, которая сбрасывается при каждом переподключении, — не ограничение. Следите за расходом по учётной записи, списывайте каждую разницу байтов один раз и делайте исчерпание блокировкой допуска.
Квота, которая сбрасывается каждый раз при переподключении туннеля, не является ограничением, и именно это получается, когда счётчик байтов прикручивают к VPN-серверу без места для хранения устойчивого состояния. Счётчик принадлежит сеансу; квота принадлежит человеку или договору на устройство. Вся сложность функции проистекает из этого несоответствия, поэтому проверки ниже касаются того, где живёт состояние и какому слою разрешено принимать решение.
Привяжите квоту к учётной записи, а не к туннелю
Начните с того, чтобы назвать субъект квоты. Один человек может держать три сертификата устройств, и ни один из них не должен получать независимый месячный бюджет только потому, что они аутентифицируются отдельно. Стабильный идентификатор учётной записи, который переживает переподключения, новые адреса туннеля и переезд на второй шлюз, — единственный якорь, который может использовать квота. Общее имя сертификата работает таким ключом только тогда, когда ваша политика выпуска гарантирует одну учётную запись на имя.
Назначенный адрес туннеля никогда не является ответом. Адреса переиспользуются, пулы разделяются, и одна и та же учётная запись может появиться дважды на двух шлюзах в одну и ту же минуту. Если реестр опирается на адрес, отключения и повторного подключения достаточно, чтобы снова наполнить бак.
Записывайте по каждому сеансу достаточно, чтобы арифметика была проверяемой: учётную запись, расчётный период, экземпляр шлюза, идентичность сеанса, последние наблюдённые счётчики и утверждённый итог. Включите поколение запуска демона в идентичность сеанса, потому что перезапущенный сервер повторно использует идентификаторы клиентов, и наивное сопоставление унаследовало бы прежнюю базовую линию.
Зафиксируйте единицу, направление и границу сброса
Четыре определения нужно закрепить письменно до начала любого сбора. Считает ли квота байты, которые клиент отправляет, которые получает, или сумму обоих? Гигабайт — это 10^9 байт или 2^30? В какой местный час и в каком часовом поясе переключается период? И что именно измеряет счётчик, учитывая, что накладные расходы туннеля и повторные передачи включены, а размер файла приложения и счёт поставщика — нет?
Ни один из этих выборов не является ошибочным, но реализация и число, которое видит клиент, должны совпадать. Две половины одной системы, расходящиеся в GiB или в переключении, которое происходит в полночь UTC вместо местного времени, порождают именно тот тип обращения, который подрывает доверие ко всей квоте.
Превратите суммы байтов в одну списанную разницу
Интерфейс управления сообщает периодические строки BYTECOUNT_CLI, несущие идентификатор клиента и накопленные суммы байтов в каждом направлении, а команда bytecount задаёт, как часто они приходят. С точки зрения сервера полученное число считает байты, отправленные клиентом, а отправленное число считает байты, доставленные ему. Задайте интервал таким, чтобы реестр мог его усвоить; очень короткий интервал покупает точность, которой вы на самом деле не получаете.
Одно ограничение формирует весь дизайн: сокет управления принимает единственное управляющее соединение. Экспортёр мониторинга, графический интерфейс и ваш контроллер не могут открыть каждый своё. Решите, какой процесс владеет каналом, и позвольте остальным читать состояние из него, потому что этот интерфейс даёт административные действия и в любом случае не должен выставляться за пределы хоста.
rx_delta = sample.rx_now - session.prev_rx
tx_delta = sample.tx_now - session.prev_tx
charge = rx_delta + tx_delta
# same transaction:
ledger.total += charge
session.prev_rx, session.prev_tx = sample.rx_now, sample.tx_now
Фиксируйте новые базовые линии и прирост расхода вместе, чтобы повторное воспроизведение выборки ничего не списывало вместо двойного списания. Счётчик, движущийся назад, — это сигнал, а не долг: он означает, что сеанс был заменён или демон перезапущен, и правильный ответ — согласовать идентичность сеанса, а не зачислить отрицательную сумму.
Путь отключения требует такой же аккуратности. Если завершающее событие несёт итоги конца сеанса, списывайте только разницу с последней утверждённой выборкой. Добавление полного итога после того, как периодическая выборка уже списана, — самый распространённый двойной учёт в самодельных системах квот. Сеансы, пересекающие границу периода, тоже нуждаются в правиле, так как один итог не несёт информации о том, когда байты пересекли полночь.
Исчерпание должно отказывать в допуске, а не просто убивать туннель
Когда учётная запись достигает своего предела, должны произойти две вещи: существующие сеансы завершаются, а новые отклоняются. Протокол управления предоставляет client-kill по идентификатору клиента, что решает первую половину, если вы перечислите каждый живой сеанс учётной записи, вместо того чтобы убивать единственный адрес, который случайно заметили.
Вторая половина — это место, где дизайны квот терпят неудачу. Одно лишь убийство — это гонка с циклом переподключения клиента, который охотно вернётся через несколько секунд. Допуск должен обращаться к общему реестру, а при развёртывании с несколькими шлюзами эта проверка не может быть файлом на каждой машине. Каждый экземпляр, способный принять вход, должен видеть одно и то же исчерпанное состояние.
Переподключения на основе токена заслуживают собственной проверки. OpenVPN 2.6 может проверять токен сеанса внутренне с помощью auth-gen-token, пропуская внешний вызов аутентификации, который ваш контроллер использовал для обеспечения предела. Поэтому всё ещё действительный токен доказывает идентичность, а не остаток квоты, и каждый новый экземпляр клиента всё равно должен обращаться к реестру. Если вместо этого включить management-client-auth, контроллер становится аутентификатором и наследует обязанность сам разбирать состояние сеанса и отклонять истёкшие или недействительные токены.
Примите превышение, которое создаёт выборка
Периодическое наблюдение плюс отключение дают вам квоту по выборке с известным допуском. Клиент может превысить примерно на один интервал отчётности плюс время, необходимое контроллеру для реакции, а параллельные сеансы на одной учётной записи умножают это окно. Скажите это в интерфейсе вместо того, чтобы рекламировать точное отсечение на последнем байте, которое вы не можете обеспечить.
Настоящий жёсткий потолок — это другая инженерная задача: обеспечение внутри пути пересылки, привязанное к одной и той же учётной записи на протяжении сеансов. Более быстрое чтение счётчиков — не то же самое, и оно не выдерживает клиента, который просто открывает больше туннелей.
Перед развёртыванием прогоните приёмочные случаи, которые ломают наивные реализации: повторные переподключения, два устройства одновременно, перезапуски контроллера и шлюза, потерянное событие отключения, переключение периода в середине сеанса и попытка переподключения по токену сразу после исчерпания. Затем определите режим отказа для перебоев в учёте. Устойчивый реестр защищает записанный расход; он не может воскресить наблюдения, которые так и не пришли, и клиент заслуживает знать, в какой из этих двух ситуаций он находится.