Kill switch спрацьовує: що відбувається з відкритими TCP-сесіями?
Заблокований пакет — це не закрите з’єднання. Вирішіть, чи має сесія пережити розрив, а потім перевіряйте блокування й відновлення як дві окремі властивості.
Тунель падає, kill switch спрацьовує, і завантаження, завершене на три чверті, або завмирає, або одразу завершується помилкою. Ці два наслідки походять від різних рішень щодо застосування правил, а не від різних рівнів захисту. Відкинутий пакет залишає з’єднання в очікуванні, а відхилений закриває його й повідомляє застосунок. Вирішити, якої поведінки ви хочете, — питання проєктування, а перевірка — окрема вправа.
Відкидання, відхилення й скидання — різні речі
Правило міжмережевого екрана, яке відкидає трафік, знищує пакет і нічого не повертає, тому відправник продовжує повторювати надсилання за власними таймерами. Правило, яке відхиляє з TCP reset, негайно закриває з’єднання, і застосунок бачить помилку. Більшість kill switch відкидають, бо відхилення розкрило б політику і бо відкидання схоже на поведінку мертвої мережі.
Блокування — це не те саме, що закриття сокета. Застосунок досі тримає дескриптор у встановленому стані, і бракує лише пакетів. Тому сторінка може хвилинами висіти на індикаторі завантаження, поки операційна система наполягає, що з’єднання існує. Читайте документоване застосування правил, а не виводьте його з повідомлення застосунку, оскільки обидві поведінки виглядають як мережа, що впала.
Що робить застосунок, поки триває розрив
TCP повторює надсилання зі зростаючими затримками, і стандартний бюджет повторів Linux вичерпується приблизно за чверть години, а не за секунди. До того часу сокет не є ні корисно відкритим, ні закритим. Застосунки з власними keepalive або тайм-аутами запитів часто здаються раніше, тому дві програми на одній машині поводяться по-різному під час одного збою.
Коли тунель повертається, локальний сокет не змінився, а шлях може. Нова публічна адреса джерела створює на сервері іншу четвірку, тому міжмережевий екран зі станом на тому боці більше не відповідає сесії. З’єднання мертве, хоча клієнт так і не побачив помилки.
Вирішіть, чи потрібне відновлення
Виберіть між двома контрактами. Або сесія має пережити короткий розрив, що потребує стабільної адресації та сервера, який зберігає свій стан, або застосунок має чисто перепідключитися, що потребує логіки повторів, безпечної для повторення. Усе проміжне дає найгірший результат: клієнт, який повторно надсилає те, що сервер уже зафіксував, або клієнт, який повідомляє про успіх для сесії, якої ніхто не бачить.
Стабільна адресація — та частина, яку забувають, бо перепідключення, що приземляється на іншій публічній адресі, анулює стан на боці сервера навіть тоді, коли сокет клієнта виглядає здоровим. Запишіть, який із двох контрактів стосується кожного застосунку, оскільки вони рідко збігаються всі.
Перевіряйте блокування й відновлення окремо
Розглядайте захист від витоків і виживання сесії як дві властивості, бо проходження однієї нічого не каже про іншу. Сесія, що вижила, не є доказом того, що прямий трафік було заблоковано, а сесія, що загинула, не є доказом того, що було заблоковано кожен прямий маршрут.
ss -tnp state established '( dport = :443 )'
sudo conntrack -L -p tcp --dport 443
sudo tcpdump -ni any 'tcp port 443 and tcp[tcpflags] & tcp-syn != 0'
Спостерігаючи за відновленням, використовуйте нешкідливу тестову операцію, щоб дубльоване надсилання не стало інцидентом. Запишіть режим відмови, який ви справді бачили: що показав застосунок, чи вижив сокет і коли він відновився сам.
Запишіть очікувану поведінку поруч із правилом застосування й поставте дату. Наступній людині, яка змінить це правило, треба знати, який із двох контрактів обіцяло розгортання.