Дали хук скрипт ще стигне до отсрещната страна на тунела зависи от три условия: към кое събитие е прикачен, дали OpenVPN все още е в последователността си на стартиране, когато скриптът се изпълнява, и дали работата е отделена от тази последователност. Повечето скриптове се провалят на третото. Добавянето на изчакване третира проблем на жизнения цикъл като проблем на времето и работи точно толкова често, че да подведе.

Първо решете събитието, после механизма за отлагане на работа, после мястото, където се изпълнява отложената работа. Тези три решения са независими и точно тяхното смесване превръща кука от два реда в следобед.

Защо куката чака тунел, който чака нея

OpenVPN извиква куките си синхронно, в същия процес, който движи пакетите. up се задейства, след като устройството tun или tap съществува, но преди да е добавен маршрут, а route-up — след маршрутите; нито един от тези моменти не обещава, че отсрещната страна ще отговори. Докато скрипт от която и да е кука още работи, демонът не препраща, затова команда, която очаква трафикът да премине през тунела, чака тунел, който чака командата. Това кръгово чакане е причината ръчно пускане да минава, а куката да изтича.

Очевидната кръпка — изчакване от няколко секунди — понякога работи, защото далечната страна се вдигна сама, а не защото изчакването поправи нещо. Помощник, който проверява готовността, е друг отговор: куката се връща, препращането започва и помощникът получава нужното, щом то наистина е налице.

Избирайте куката по събитие, не по удобство

Прикачете up към работа, на която е нужно само устройството, route-up към работа, на която са нужни маршрути, а client-connect и client-disconnect запазете за задачи за всеки клиент от страна на сървъра. Почистването при прекъсване трябва да понася двукратно изпълнение, защото повторните връзки през постоянен интерфейс не следват същата последователност като пълно рестартиране. На сървъра client-connect се задейства, когато клиентът се удостовери, а не когато демонът стартира, което си струва да се потвърди, преди логиката да се мести там. Ако работата принадлежи на жизнения цикъл на услугата, а не на една връзка, systemd модул е по-добър дом от всяка кука.

Командите на куката се изпълняват директно от демона, без обвивка помежду, затова ifconfig_remote в ред up пристига като буквален текст. Обвийте командата в явна обвивка или дръжте логиката в скрипт, който чете средата. ipchange е една директива, която добавя свои аргументи: подава адреса и порта на командата, затова скрипт, писан за нито един, вижда два неочаквани.

Три начина да отделите работата

Първият вариант е да пуснете помощника във фонов режим отвътре в куката: стартирайте го с setsid или systemd-run --scope, затворете наследените дескриптори и излезте веднага с нула. Вторият е куката да запише малък файл на състоянието и таймер на systemd или пътен модул да действа по него; така куката остава проста, а политиката за повторения отива там, където има журнали. Третият е да изоставите куката напълно и да преместите работата в модул, подреден след VPN услугата; това е верният отговор, когато работата изобщо не е за всяка връзка. И трите споделят едно правило: куката трябва да се върне, преди да ѝ потрябва тунелът.

Кое и да изберете, направете помощника идемпотентен и наблюдаем. Две припокриващи се извиквания не бива да изпълнят два пъти едно и също необратимо действие, а помощник, който се провали, трябва да остави нещо, което човек да прочете.

Отделете отказите на пясъчника от отказите на жизнения цикъл

Когато скрипт се изпълнява от root подкана и се проваля като услуга, причината обикновено е пясъчник, а не мрежата. Ограничаващ ProtectHome, само за четене ProtectSystem или работна директория, която не съществува могат да оставят скрипта или данните му недостъпни, а на SELinux хост файлът се нуждае и от контекст, който разрешава изпълнение. Прочетете модула с systemctl cat openvpn-server@server и журнала с journalctl -u openvpn-server@server -n 80, после търсете грешка в права или контекст, а не таймаут на връзката. Изключването на пясъчника трябва да е последният ход, не първият.

Отказът на жизнения цикъл изглежда различно: куката стартира, помощникът работи, а сокетът просто още го няма. Запишете ред с времева отметка от самата кука, прекъснете и се свържете отново, прочетете събитията по ред. Когато помощникът наистина се нуждае от тунела, нека проверява готовността, вместо да спи фиксиран период.

Три полета правят следващия доклад полезен: коя кука е работила, кой акаунт е използвала и къде е спряла. Без тях всяко следващо разследване започва отначало.

Подобни статии