Писал я как-то раньше о том, что мы планируем отказываться от PPTP в пользу L2TP. Это время как раз пришло, как это обычно бывает после новогодних праздников, когда после длительных выходных хочется приступить к какой-то интересной работе. Я, впрочем, хочу рассказать не о самом процессе перехода или установки и настройки сервера, нет. Я хочу рассказать о проблеме, которая мучила меня двое суток и которая решилась за минуту глубокого изучения исходного кода.
Итак, тестовый VPN-сервер. Настроена работа L2TP, проведено нагрузочное тестирование на предмет разрывов связи и проседания скорости соединения, проведен пробный запуск IP-телефонии через этот VPN, проверена программа учета. В программе учета при всем этом один из главных параметров — это IP-адрес, с которого происходит соединение, так как внутри системы весь учет и проверка прав доступа происходит именно по IP-адресу. Все работает отлично, по тестовому серверу написан учебный материал, по которому в дальнейшем будет происходить настройка L2TP на других серверах. Все отлично. Дождались перехода очередного сервера на L2TP, этим делом занимался я, поскольку нововведения чаще всего не передаются младшим операторам в связи с тем, что те самостоятельно могут решить достаточно малое количество возникающих в ходе проведения работ проблем.
Я, не отклоняясь от инструкции ни на букву (ведь ее правильность-то мне тоже предстоит проверить и дополнить/отредактировать то, что не соответствует процессу либо может быть успешно оптимизировано) устанавливаю все необходимые компоненты, настраиваю маршрутизацию соединений и произвожу пробный запуск: все работает нормально. Впрочем, радость моя достаточно быстро пропала: не работает самое главное — не передается IP-адрес клиента. Скажу сразу, что данный параметр передается в pppd при помощи шестой переменной, которая в скриптах ifupdown именуется PPP_IPPARAM. Удивительным образом оказалось, что переменная эта не содержит вообще ничего. Удивительно, не правда ли?
Я сразу не смог понять, как так вышло, что при одинаковых конфигурациях двух серверов на одном все работает нормально, а на втором имеются проблемы. Сверил версии и выяснил, что на нормальном сервере xl2tpd имеет версию 1.3.1, а на сбоящем — 1.3.6. Откатил до 1.3.1, но вместо результата xl2tpd вообще отказался стартовать, ссылаясь на отсутствие знака равенства в тринадцатой строке xl2tpd.conf. Как я не извращался с этой строкой, ничего не изменилось (кроме номера строки при установке в файл знаков перевода каретки). Ok, пойдем другим путем, — подумал я. Мое неокрепшее после новогодних праздников сознание сгенерировало отличный план: получить при установке соединения pppd название интерфейса (ppp0, например, но учитывая то, что пользователей много, может быть и ppp39), а затем через ifconfig ppp0 получить IP-адрес инициатора. Ага, сейчас. Оказалось, что через ifconfig можно получить исключительно внутреннюю адресацию, которую, к слову, xl2tpd итак без вопросов отдает в систему статистики (только десяток пользователей под внутренним IP 10.*.*.88 мне ни о чем не говорит, как, впрочем, и системе учета). Идем дальше.
После некоторого времени, потраченного на осмысление сути проблемы, я выявил, что в системный журнал при включенном режиме debug записывается IP-адрес клиента в связке с соответствующим ему tty, а это уже что-то, так как теперь мы уже можем установить соответствие между tty, временем соединения и адресом инициатора. Что правда, пришлось достаточно быстро отказаться от этой идеи. Во-первых, нет никаких гарантий того, что на сервере ничего не будет происходит параллельно подключению клиента по L2TP. Это я к тому, что tail -n10 в этом случае вообще не поможет, а весь журнал сканировать ради одного только адреса может быть достаточно таки затратно с точки зрения ресурсов как вычислительных, так и памяти. Во-вторых, время журнала и время подключения могут не сойтись (мы уже как-то такое практиковали: расхождение бывает на несколько секунд, но и это уже что-то). В-третьих, никто не гарантирует того, что пользователь будет подключаться только один. Быть может, подключение одновременно инициирует два или три пользователя, тогда вполне вероятно то, что адреса их будут перепутаны, что для нас ничего хорошего в себе не несет. Смотрим дальше.
В Интернете на эту тему ничего нет, только миллион сообщений о том, как настроить L2TP от «Корбины»/«Билайна». В забугорном сегменте сети тоже глухо, только способы получения MAC-адреса, но нам это не интересно, так как у нас не точка доступа Wi-Fi. Наткнулся на одно интересное сообщение об ошибке в xl2tpd. Что правда, в чем именно заключалась суть ошибки я не понял, но это касалось реального IP-адреса (очень уж витиеватое объяснение). Нашел путь исправления ошибки, скачал исходники xl2tpd, начал творить.
Итак, в файле controls.c есть обращения к функции start_pppd. Это как раз то, что нам нужно, так как именно эта функция передает параметры в pppd. Параметры добавляются в массив при условии, что при чтении конфигурационного документа найдено то или иное ключевое слово. Меня поначалу насторожила функция IPADDY, поскольку со сбоями аналогичной я сталкивался в WebEngine, но там суть заключалась в том, что из-за различий в разрядности операционной системы вычисление могло давать в итоге два разных IP-адреса. Нашел ее в misc.h, но ничего интересного не обнаружил: простое преобразование адреса из одной системы в другую, всего-то одна строка. Идем дальше. Быть может, порядок этих самых if в controls.c мешает выводить ipparam? Автор статьи, на которую я полагался, сообщал о том, что ipparam должен присваиваться раньше, чем файл ppp-опций. Честно говоря, особого смысла в перемещении блока я не увидел, поэтому решил искать другое объяснение проблемы. Так бы и ковырялся я дальше в исходном коде, если бы не решил посмотреть, откуда берется условие, при исполнении которого ipparam добавляется в массив, передаваемый pppd. «pass_peer». Хм, интересно.
После того, как я немного почитал инструкции, все стало на свои места. Дело в том, что в xl2tpd.conf есть параметр «pass peer» (без подчеркивания), который может принимать значения «yes» и «no». Эти самые «yes» и «no» и определяют поведение xl2tpd по передаче реального IP-адреса клинета pppd. By default этот параметр отсутствует в xl2tpd.conf и несмотря на то, что согласно инструкции он должен быть включен по умолчанию, у меня он оказался выключен (а вот в 1.3.1 все работает и без дополнительного объявления). Включение «pass peer» и перезагрузка xl2tpd решили все проблемы, для которых я изобретал столь извращенные варианты обхода.
Вывод: внимательно читать документацию перед тем, как начинать поиски ошибок, допущенных разработчиками.