...

пятница, 14 ноября 2014 г.

FreeBSD, dhcp, ip unnumbered и все все все…

Наша небольшая компания подключает абонентов к интернету по технологии vlan-per-user.

Так исторически сложилось и в этом есть как плюсы, так и минусы, но разговор сейчас не об этом.

Обычно на каждый vlan выделяется сеть серых адресов, которая потом через NAT выпускается в большой мир. Но иногда абоненты хотят реальный белый адрес, и до недавнего времени им выдавалась /30 сеть. Что в реалиях настоящего очень расточительно и абоненты с реальными адресами переводятся на подключение по технологии SuperVLAN (RFC 3069).

Все адреса – и серые, и белые выдаются абонентам через DHCP. Сервисы DHCP, NAT и шейпер работают на одном сервере под управлением FreeBSD 9.3. Железо у сервера вполне обычное – Core i7, 8Gb RAM, Intel E1G42ET.


Задача:


Выдавать каждому абоненту адрес тот же реальный адрес, что у него был, но уже не с маской /30, а с новой, общей для всех маской /24 и шлюзом x.x.x.1. Обеспечить невозможность работы абонента с чужим реальным адресом.

Абонентам с серыми адресами продолжать выдавать сеть на абонента.


Строим SuperVlan ala FreeBSD


Vlan9 – технологический vlan, к нему ничего не подключено, туда будет уходить трафик для еще не выданных абонентам реальных адресов.

Vlan10 – абонент с серым адресом

Vlan11 и vlan12 два абонента с реальными адресами.



ifconfig vlan9 inet 1.1.1.1/24
ifconfig vlan10 inet 192.168.10.1/24
ifconfig vlan11 inet 1.1.1.1/32
route add 1.1.1.11 –iface vlan11
ifconfig vlan12 inet 1.1.1.1/32
route add 1.1.1.12 –iface vlan12


Ставим на клиенте vlan11 руками адрес 1.1.1.11/24, gw 1.1.1.1 – интернетик у клиента работает.


(Bridge из private sticky vlan (man bridge) в данном случае использовать не получилось, о причинах будет сказано ниже)


Теперь займемся самым интересным


Раздача адресов через DHCP


А конкретно ISC-DHCPD ver 4.3


Адреса надо выдавать на основании интерфейса, с которого пришел запрос.

К большому сожалению авторы isc-dhcpd твердо уверены, что они точно знают лучше, что надо сисадмину, чем сам сисадмин. И не дают ему прострелить себе ногу, отрубая сисадмину указательный палец по самый локоть.


В итоге можно указать список интерфейсов на которых хотелось бы слушать запросы от клиентов, но если в конфиге dhcpd.conf не указать subnet в которую попадает адрес на этом интерфейсе – то он будет проигнорирован.

А если на нескольких интерфейсах указаны одинаковые адреса – то запросы DHCPREQ будут обрабатываться в одном subnet.

И нельзя прописать в dhcpd.conf ни subnet, ни pool, ни host которые были бы жестко привязаны к опеределенному интерфейсу.


Это мечта, на самом деле так не работает:



subnet 1.1.1.11 netmask 255.255.255.255 {
option routers 1.1.1.1;
range 1.1.1.11;
interface vlan11;
}


Ну чтож… Есть же DHCP relay. Запускаем релей на нужных портах, который добавит Option 82 Agent Circuit ID, и отдаст запрос dhcpd.


Попытка 1:


Так как на лупбек интерфейсе dhcp категорически не желает слушать – заводим дополнительный vlan5


rc.conf:



ifconfig_vlan5=”inet 192.168.5.1/24”
dhcrelay_flags =”-a”
dhcrelay_servers =”192.168.5.1”
dhcrelay_ifaces =”vlan11 vlan12”
dhcpd_ifaces =”vlan5 vlan10”


Запускаем – не запускается…

dhcpd сообщает, что не может bind socket.

Хотя прямо указаны разные интерфейсы для релея и для демона, они оба на всякий случай хотят забиндить fallback socket на адрес *:67

о чем и сообщают вот этой строчкой при старте “Sending on Socket/fallback”.


Естественно тому, кто стартует вторым система говорит: “Занято!”

Как и можно ли отключить этот fallback сокет я не смог найти.


Попытка 2:


Альтернативные программы – dhcprelya и dhcprelay.

Опять сообщают, что не могут сделать bind socket. Смотрим в код и понимаем их кардинальное отличие от isc-творений. ISC использует device bpf и выхватывает свои пакеты у системы практически в самом начале сетевого стека, еще до фаерволла и прочих излишеств … Альтернативщики используют стандартный механизм socket, но так как у нас на нескольких интерфейсах одинаковые адреса, то на второй bind на адрес 1.1.1.1:67 система опять сообщает: “Занято!”


Попытка 3:


А пусть dhcrelay слушает ВСЕ интерфейсы и пересылает запросы в dhcpd, который будет прибит только к адресу 192.168.5.1

Пересобираем dhcpd, чтобы он не использовал BPF, а подключался бы через socket.

Для этого по быстрому подправляем Makefile порта isc-dhcp43-server

Добавляем в него:

CONFIGURE_ARGS+=--enable-use-sockets

Собираем, запускаем – запустилось, но не работает. Dhcpd в логи пишет, что присвоил клиенту адрес, но клиент ответа от dhcpd не получает.


Смотрим tcpdump как пытается получить адрес клиент на vlan10, тот, что с серыми адресами.

tcpdump –i vlan10 — Запрос от клиента есть – ответа от сервера нет.

tcpdump –i vlan5 – тишина

tcpdump –i lo0 – а вот тут интересно:

видим udp пакет от релея к демону с адреса 192.168.5.1 на адрес 192.168.5.1

видим udp ответ от демона к релею с адреса 192.168.5.1 на адрес 192.168.10.1


И тут становиться понятно, что так как dhcrelay слушает только через BPF – то пакеты, которые проходят через внутренних интерфейс lo0 он просто не видит, пересобирать dhcrelay на использование сокетов смысла нет, тогда мы вернемся в ситуацию “Попытка 2”


Попытка 4:


Разносим dhcrelay и dhcpd на ОТДЕЛЬНЫЕ сервера.


Server dhcpd rc.conf:



ifconfig_vlan5=”inet 192.168.5.1/24”


Server dhcrelay rc.conf:



ifconfig_vlan5=”inet 192.168.5.2/24”
dhcrelay_flags =”-a”
dhcrelay_servers =”192.168.5.1”


Не работает.

Ах да….

Вспоминает tcpdump из “попытки 3”, прописываем на dhcpd -сервере

route add 192.168.10.0/24 192.168.5.2

route add 1.1.1.0/24 192.168.5.2


Теперь работает. Адреса клиенту в vlan10 отдает.

Теперь добавляем в dhcpd информацию о клиентах с реальными адресами.

В интернете полно примеров с классами, в которых вырезают подстроки из agent id и circuit-id, создают подклассы, чтобы можно было выделять несколько адресов на порт подключения.


Мне достаточно одного адреса, поэтому достаточно описать host вот с такой строчкой внутри:

host-identifier option agent.circuit-id «vlan11»


Если собрать SuperVLAN с помощью bridge, то dhcrelay будет пересылать запросы со всех интерфейсов объединенных в мост с agent.circuit-id=«bridge0», так что только интерфейсы с одинаковыми адресами и принудительной маршрутизацией.


Итого:


Достоинства решения — клиент автоматически получит новые настройки, при этом у него останется его старый адрес.

Недостатки — Потребовался второй сервер

ToDo: Проверить как отрабатывается ситуация со сменой мак-адреса у клиента. Выдаст ли dhcpd тот же реальный адрес из host, если у него еще не истек срок выдачи на предыдущий мак.


И возвращаясь к заботливым и непосредственным авторам isc-dhcpd.

Чтобы dhcpd перехватывал через bpf запросы, пришедшие на интерфейс надо прописать в конфиг dhcpd.conf секцию subnet в который входит адрес на этом интерфейсе.

В то же время нет необходимости указывать какие именно subnet использовать для выдачи ответов через relay – он ищет совпадения во всех.


Вот конфиг dhcpd.conf



option domain-name "example.org";
option domain-name-servers 8.8.8.8, 8.8.4.4;

default-lease-time 600;
max-lease-time 7200;
one-lease-per-client true;
stash-agent-options true;
update-conflict-detection false;

authoritative;
log-facility local7;

subnet 192.168.5.0 netmask 255.255.255.0 {
}

subnet 192.168.10.0 netmask 255.255.255.0 {
range 192.168.10.2 192.168.10.254;
option routers 192.168.10.1;
}

subnet 192.168.14.0 netmask 255.255.255.0 {
range 192.168.14.2 192.168.14.254;
option routers 192.168.14.1;
}

subnet 1.1.1.0 netmask 255.255.255.0 {
}

group realip1 {
option routers 1.1.1.1;
host client11 {
host-identifier option agent.circuit-id "vlan11";
fixed-address 1.1.1.11;
}
host client12 {
host-identifier option agent.circuit-id "vlan12";
fixed-address 1.1.1.12;
}
host client28 {
host-identifier option agent.circuit-id "vlan28";
fixed-address 1.1.1.13;
}
}


PS: Неожиданные грабли и решение:



если кому понадобится поднять isc dhcrelay на 8к интерфейсов

надо поменять

значение FD_SETSIZE в файлах

/usr/src/sys/sys/select.h

/usr/include/sys/select.h


с

#define FD_SETSIZE 1024U

на

#define FD_SETSIZE 16384U


Пересобираем isc-hcrelay или isc-dhcpd



This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий