FreeBSD, VPN интернет: DHCP-скипт настройки маршрутизации и DNS-сервера

Локальная сеть подключена к интернету через FreeBSD сервер. Провайдер предоставляет выход в интернет через VPN соединение. В сети провайдера внутренние IP адреса и DNS серверы раздаются автоматически DHCP сервером.

Штатный скрипт DHCP клиента FreeBSD задает полученный по DHCP маршрутизатор шлюзом по умолчанию, что в  этом случае не годится, поскольку шлюзом по умолчанию будет VPN сервер. Кроме того на сервере работает Bind, чтобы использовать DNS серверы провайдера, потребуется обновить named.conf. Штатный DHCP скрипт обновляет только resolv.conf, править который в нашем случае не требуется, поскольку он указывает на локальный DNS сервер.

В данном решении список внутренних сетей провайдера задается администратором. Полученные от DHCP маршруты игнорируются.

Модификация dhclient-script

Создаем папку с файлами конфигурации DHCP

mkdir /etc/dhcp-client && cd /etc/dhcp-client 

Копируем скрипт настройки сети:

cp /sbin/dhclient-script /etc/dhcp-client

Правим скрипт настройки:

$EDITOR /etc/dhcp-client/dhclient-script

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

Находим  процедуру delete_old_routes(), первой строкой добавляем return 0. Старые маршруты будут удалены при добавлении новых.

delete_old_routes() {
        return 0
        #route delete "$old_ip_address" $LOCALHOST >/dev/null 2>&1
        if [ -n "$old_classless_routes" ]; then

Процедурой ниже: add_new_routes(), вызываем свой скрипт настройки маршрутов и завершаем выполнение функции. Вывод скрипта сохраняем для отладки и последующего мониторинга.

add_new_routes() {
        sh /etc/dhcp-client/set-routes >> /var/log/dhcp-settings.log 2>&1
        return 0

        #route add $new_ip_address $LOCALHOST >/dev/null 2>&1

        # RFC 3442: If the DHCP server returns both a Classless Static
        # Routes option and a Router option, the DHCP client MUST ignore
        # the Router option.

Ниже в процедуре add_new_resolv_conf() отключаем корректировку resolv.conf, запускаем свой скрипт правки named.conf:

add_new_resolv_conf() {
        sh /etc/dhcp-client/set-dns >> /var/log/dhcp-settings.log 2>&1
        return 0

        # XXX Old code did not create/update resolv.conf unless both
        # $new_domain_name and $new_domain_name_servers were provided. PR
        # #3135 reported some ISP's only provide $new_domain_name_servers and
        # thus broke the script. This code creates the resolv.conf if either
        # are provided.

Скрипт настройки маршрутов

Создаем скрипт настройки маршрутов

$EDITOR /etc/dhcp-client/set-routes

Скрипт выполняет следующие действия:

  • Выход, если при продлении шлюз не изменился.
  • Протоколирует событие.
  • Получает первый шлюз из списка.
  • Удаляет старые маршруты и задает новые. Можно задать общий маршрут к служебной сети провайдера, либо маршрут только к  VPN-серверу.
#!/bin/sh

#If set $old_routers and renew
if [ -n "$old_routers" -a "$reason" = "RENEW" ]; then
    if [ "$old_routers" = "$new_routers" ]; then
        #Router not changed
        return
    fi
fi

#if set $new_routers
if [ -n "$new_routers" ]; then
    echo
    date
    echo "Reason: $reason"
    echo "Router: $old_routers -> $new_routers"

    #Get first router
    for router in $new_routers; do
        # 2nd and subsequent default routers error out, so explicitly
        # stop processing the list after the first one.
        break
    done

    route delete -net 10.0.0.0/8 >/dev/null 2>&1
    route add -net 10.0.0.0/8 $router
    route delete -net 172.16.0.0/12 >/dev/null 2>&1
    route add -net 172.16.0.0/12 $router
    #route delete -host 10.0.0.1 >/dev/null 2>&1
    #route add -host 10.0.0.1 $router
fi

Задаем права доступа:

chmod 755 /etc/dhcp-client/set-routes

Скрипт настройки DNS

Создаем скрипт:

$EDITOR /etc/dhcp-client/set-dns

Скрипт выполняет следующие действия:

  • Выход, если при продлении параметры DNS не изменились.
  • Удаляет маршруты к старым DNS серверам (раскомментировать, если на предыдущем шаге не был указан общий маршрут к сетям провайдера).
  • Пишет событие в протокол.
  • Получает первый шлюз из списка.
  • Перебирает все DNS серверы, преобразует список в формат, понятный Bind'у.
  • Добавляет маршруты к DNS серверам, (раскомментировать при необходимости). Перед добавлением маршрута, проводится экспресс проверка, на принадлежность сервера к локальной сети, если сервер является локальным, маршрут не добавляется. Для корректной работы команда  route -n get $localIP должна возвращать строку "flags: <UP,DONE>" для адресов доступных напрямую без маршрутизатора. Проверка успешно отработала под FreeBSD 8.1, если вывод у вашей версии отличается, скрипт придется скорректировать.
  • Если параметры DNS не совпадают с записанными в named.conf, обновляет. Если Bind загружен, отправляет уведомление об обновлении конфига.
#!/bin/sh

if [ -n "$old_domain_name_servers" -a "$reason" = "RENEW" ]; then
    if [ "$old_domain_name_servers" = "$new_domain_name_servers" ]; then
        #Domain name servers not changed
        return
    fi

    ##Remove old routes
    #for nameserver in "$old_domain_name_servers"; do
    #    route delete -host $nameserver >/dev/null 2>&1
    #done
fi

if [ -n "$new_domain_name_servers" -a -n "$new_routers" ]; then
    echo
    date
    echo "Reason: $reason"
    echo "DNS: $old_domain_name_servers -> $new_domain_name_servers"

    #Get first router
    for router in $new_routers; do
        # 2nd and subsequent default routers error out, so explicitly
        # stop processing the list after the first one.
        break
    done

    #Сonvert addresses to Bind format, optional add routes
    for nameserver in $new_domain_name_servers; do
            fwds="$fwds $nameserver;"

            ##Add route if not local IP
            #if route -n get $nameserver 2>/dev/null | grep "<UP,DONE>" >/dev/null 2>&1; then
            #    echo "Local IP: $nameserver, skip route"
            #else
            #    route delete -host $nameserver >/dev/null 2>&1
            #    route add -host $nameserver $router
            #fi
    done
    fwds="forwarders {$fwds }"

    #Exit if servers not changed
    grep "$fwds" /etc/namedb/named.conf >/dev/null && return 0

    #Upate Bind config
    sed "s/forwarders {[^}]*};/$fwds;/" /etc/namedb/named.conf > /etc/namedb/named.conf.tmp
    if grep "$fwds" /etc/namedb/named.conf.tmp >/dev/null; then
        mv -f /etc/namedb/named.conf.tmp /etc/namedb/named.conf
        #Reload if deamon started
        pgrep named >/dev/null 2>&1 && /etc/rc.d/named reload
    else
       echo Error update named.conf
    fi
fi

Задаем права доступа:

chmod 755 /etc/dhcp-client/set-dns

Правим конфиг Bind'а:

$EDITOR /etc/namedb/named.conf

Для корректной работы скрипта директива forwarders должна располагаться целиком в одной строке:

forwarders { 10.0.0.1; 10.0.0.2; };

Настройка системы

Приступаем к изменению параметров, непосредственно влияющих на работу сети. Что может привести сеть в нерабочее состояние. Действия производим из сети со статичным IP адресом сервера, в непосредственной близости к физической консоли.

Правим конфиг DHCP-клиента:

$EDITOR /etc/dhclient.conf

Задаем путь к нашему скрипту настройки параметров:

script "/etc/dhcp-client/dhclient-script";

Правим rc.conf:

$EDITOR /etc/rc.conf 

Задаем время ожидания шлюза по умолчанию. При старте, на этапе инициализации сетевых интерфейсов, система будет ждать появление шлюза по умолчанию 30 секунд. Поскольку на данном этапе загрузки система шлюза не дождется, укоротим время ожидания до 5 секунд, чтобы дать возможность DHCP клиенту настроить параметры сети.

defaultroute_delay=5

Тестирование.

Перезагружаемся, проверяем присвоение IP адреса:

ifconfig

Проверяем маршруты:

netstat -rn

Проверяем протокол работы скриптов:

cat /var/log/dhcp-settings.log

 Вывод должен быть примерно следующим:

Sat Apr 30 16:44:26 YEKST 2011
Reason: REBOOT
Router: -> 192.168.255.1
add host 10.0.0.3: gateway 192.168.255.1

Sat Apr 30 16:44:26 YEKST 2011
Reason: REBOOT
DNS: -> 10.0.0.2 10.0.0.1
add host 10.0.0.2: gateway 192.168.255.1
add host 10.0.0.1: gateway 192.168.255.1

Проверяем конфиг Bind'а:

cat /etc/namedb/named.conf | grep forwarders 

Проверяем, разрешаются ли имена:

nslookup ya.ru 127.0.0.1

Проверяем маршрут до VPN серверов:

traceroute -nP ICMP 10.0.0.1

Решение проблем

При отладке скриптов чтобы посмотреть все переданные параметры в начало скрипта добавьте команду env.


Может возникнуть проблема, когда VPN сервер в качестве удаленного IP, выдает адрес из той же служебной подсети. В этом случае возникнет конфликт VPN-шлюза с маршрутом к служебной сети.

Придется либо согласовать другой удаленный IP туннеля, не входящий в служебную подсеть. Успех согласования зависит от настроек провайдера.

Либо вместо общего маршрута к сети, задать отдельные маршруты к VPN и DNS серверам, раскомментировав в сценариях соответствующие строчки. Если адрес VPN сервера является доменным именем, на котором зарегистрировано несколько VPN серверов, потребуется дополнительное программирование, чтобы динамически задавать отдельные маршруты к каждому серверу. Команда route add -host name $router, добавит маршрут только к первому попавшемуся серверу.


Если из локальной сети необходим доступ к транспортной сети провайдера, потребуется настроить дополнительный транслятор адресов для транспортного интерфейса.

Дополнительная информация:

Глава о DHCP руководства по FreeBSD: http://www.freebsd.org/doc/ru_RU.KOI8-R/books/handbook/network-dhcp.html

Введение в DHCP: http://citkit.ru/articles/73/

Страницы справки: dhclient(8), dhclient.conf(5), dhclient-script(8).

Использование mpd5 в качестве vpn-клиента (pptp): http://adw0rd.ru/2009/mpd5-vpn-client/ 

Как поднять VPN подключение клиента во FreeBSD/PCBSD (mpd4): http://blogfreebsd.com/freebsd/kak-podnyat-vpn-podklyuchenie-klienta-vo-freebsdpcbsd.html