Локальная сеть подключена к интернету через 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