Правильна робота DHCP Client з Classless Static Routes в ОС Linux

Опубліковано Vitovt 17 Грудень, 2008 - 16:31
версія для друку

Сьогодні на сайті дебютує нова людина - Сашко, ака Конус. Якщо подивитися на його сайт - Konus.in.ua, то можна зробити висновок, що це освічена та національно свідома людина. Як підтвердження своєї різнобічної освіченості, він прислав інструкцію для виконання певної задачі системного адміністрування Лінукс. Прошу до уваги:

==Вступ==

Нещодавно переді мною постала дилема: моя Fedora 7 ніяк не хотіла бачити сегментів мережі окрім рідного. Люди підказали, що проблема полягає в реалізації так званих Статичних Безкласових Маршрутів (далі СБМ). В інеті знайшов повно мануалів для Debian, але оскільки у мене був не Дебіан, те, що пропонувалося, у мене не запрацювало. Довелося гуглювати.
Тут я покажу, як настроїти СБМ для системи Linux Fedora і розкажу, як все це переробити для інших сімейств. Тестувалося на Fedora 7 та 8, ISC DHCP Client V3.0.6-Fedora (далі dhclient).


==Трошки теорії==
Організація СБМ (Classless Static Routes) регулюється стандартом RFC 3442 (http://www.ietf.org/rfc/rfc3442.txt). Такі маршрути є розширеною опцією для протоколу DHCP (Dynamic Host Configuration Protocol), що використовується для динамічного конфігурування комп'ютерів мережі.
Для чого вони потрібні? Якщо є мережа складної структури, простими засобами DHCP не можливо передати клієнтським комп'ютерам інформацію про всі підмережі, та маршрути, якими пакети мають проходити, щоб потрапити в ці підмережі. Тому стали використовувати спеціальні розширені параметри протоколу, які містять адресу підмережі та шлюзу до неї.
Для передачі клієнтським комп'ютерам СБМ використовується опція протоколу №121 (за RFC), але як і завжди, наша улюблена корпорація "Майкрософт", перепрошую, срати хотіла на стандарти, і придумала власну опцію №249, яка є аналогічною 121й. Тому в подальшому будемо використовувати саме №249.
Детальніше читайте в RFC3442.

==Практика==
!!!Всі вказані операції необхідно виконувати з правами root.!!!
Dhclient має у своєму арсеналі спеціальний конфігураційний скрипт /sbin/dhclient-script, який запускається час від часу. Взагалі він не призначений для редагування користувачем, тому розробниками передбачено можливість використання хуків (Hooks). Хуки дозволяють користувачеві змінювати стандартну поведінку dhclient при створенні файлу маршрутів /etc/resolv.conf та використанні нестандартних опцій.

Оскільки вищезгадані СБМ не є стандартною опцією, для їх використання необхідно сказати dhclient про необхідність їх отримання від сервера. Для цього у файлі /etc/dhclient.conf пишемо наступне:


# Classless Static Routes. RFC code 121. Windows code 249
# Using 249 except for 121 because most of computers uses this shit
option rfc3442-classless-static-routes code 249 = array of unsigned integer 8;
#

request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, host-name, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes;


Тепер dhclient буде отримувати необхідну інформацію про СБМ. Але тільки отримувати.

Для їх обробки будемо використовувати вже згадані Хуки. Якщо бути точним, існують вхідні та вихідні хуки, які відрізняються моментом їх виконання під час обробки таблиць маршрутизації, але не будемо лізти занадто глибоко, детальніше про це можна почитати у man dhclient-script. Нам потрібні саме вихідні хуки (Exit Hooks). Їх встановлення відбувається у файлі /etc/dhclient-exit-hooks, який в нашому випадку буде містити процедури для обробки інформації про СБМ.

Вміст /etc/dhclient-exit-hooks :


#!/bin/bash

function calc_num_bytes()
{
         if [ $1 -gt 32 -a $1 -lt 0 ]
         then
                 dst_addr_num_bytes=-1
         elif [ $1 -gt 24 ]
         then
                 dst_addr_num_bytes=4
         elif [ $1 -gt 16 ]
         then
                 dst_addr_num_bytes=3
         elif [ $1 -gt 8 ]
         then
                 dst_addr_num_bytes=2
         elif [ $1 -gt 0 ]
         then
                 dst_addr_num_bytes=1
         fi
}


function process_classless_static_routes()
{
         IFS=' '
         octet_array=($1)
         current_index=0
         while [ $current_index -lt ${#octet_array[@]} ]
         do
                 subnet_mask_width="${octet_array[$current_index]}"
                 current_index=$((current_index + 1 ))
                 if [ $subnet_mask_width -eq 0 ]
                 then
                         route_add_string="route add default"
                 elif [ $subnet_mask_width -eq 32 ]
                 then
                         dst_addr="${octet_array[@]:${current_index}:4}"
                         dst_addr="${dst_addr// /.}"
                         current_index=$((current_index + 4))
                         route_add_string="route add -host ${dst_addr}/${subnet_mask_width}"
                 else
                         calc_num_bytes $subnet_mask_width
                         [ $dst_addr_num_bytes -eq -1 ] && { echo "ERROR : Bad CIDR mask length." ; exit 1; }

                         dst_addr="${octet_array[@]:${current_index}:${dst_addr_num_bytes}}"

                         i=$dst_addr_num_bytes
                         while [ $i -lt 4 ]
                         do
                                 dst_addr="${dst_addr} 0"
                                 i=$((i + 1))
                         done

                         dst_addr="${dst_addr// /.}"
                         current_index=$((current_index + dst_addr_num_bytes))
                         route_add_string="route add -net ${dst_addr}/${subnet_mask_width}"
                 fi

                 gateway="${octet_array[@]:${current_index}:4}"
                 gateway="${gateway// /.}"
                 current_index=$((current_index + 4))

                 if [ "$gateway" = "0.0.0.0" ]
                 then
                         route_add_string="$route_add_string dev $interface"
                 else
                         route_add_string="$route_add_string gw $gateway"
                 fi

                 echo "$route_add_string"
                 eval "$route_add_string"
         done
 }

 echo "EXIT HOOK REACHED"
 if [ "$reason" = "BOUND" -a "$new_rfc3442_classless_static_routes" ]
 then
   process_classless_static_routes "$new_rfc3442_classless_static_routes"
 fi

Тепер все має працювати. Виконайте команду dhclient, і побачите щось на зразок цього:

[root@localhost ~]# dhclient
Internet Systems Consortium DHCP Client V3.0.6-Fedora
Copyright 2004-2007 Internet Systems Consortium.
All rights reserved.
For info, please visit http://www.isc.org/sw/dhcp/
Listening on LPF/eth0/00:17:31:af:ba:ef
Sending on   LPF/eth0/00:17:31:af:ba:ef
Sending on   Socket/fallback
DHCPREQUEST on eth0 to 255.255.255.255 port 67
DHCPACK from 10.4.0.222
bound to 10.4.0.27 -- renewal in 10593 seconds.

Потім перевірте таблицю маршрутизації командою ip route

[root@localhost ~]# ip route
10.4.0.0/16 dev eth0  proto kernel  scope link  src 10.4.0.27
192.168.0.0/16 via 10.4.0.253 dev eth0
10.0.0.0/8 via 10.4.0.253 dev eth0
default via 10.4.0.222 dev eth0

Рядок з 10.0.0.0/8 via 10.4.0.253 показує, що маршрути встановилися нормально (у нашому випадку).
Переконатися у правильності встановлення маршрутів можна пінгами на комп'ютери інших сегментів. Наприклад на: dc.local.bbn, dc.maj, та ін.

Якщо після перезавантаження системи маршрути автоматично не встановлюються - виконайте команду dhclient, або додайте її до автозавантаження.

==Інші системи==
На інших Linux'ах процедура загалом є аналогічною, але можуть відрізнятися шляхи до файлів конфігурації.
Для визначення місцезнаходження файлу вихідних хуків знайдіть у /sbin/dhclient-script рядок схожий на "# Must be used on exit. Invokes the local dhcp client exit hooks, if any." Нижче в коді можна побачити деякий шлях до файлу(ів) чи теки з вихіднимим хуками. Аналогічну інформацію може дати man dhclient-script.
Також може відрізнятися назва файлу самого dhclient (може бути dhclient3 тощо).

==Можливі проблеми==
Якщо нічого все зроблено, але нічого не працює, перевірте файл /var/lib/dhclient/dhclient.leases на наявність опції "option rfc3442-classless-static-routes".
Про таку помилку також може свідчити наявність у /var/log/messages рядків типу:
Jan 20 00:03:54 localhost dhclient: /etc/dhclient.conf line 4: no option named rfc3442-classless-static-routes
У мене при нормально сконфігурованих маршрутах dhclient.leases виглядає так:

lease {
  interface "eth0";
  fixed-address 10.4.0.27;
  option subnet-mask 255.255.0.0;
  option routers 10.4.0.222;
  option dhcp-lease-time 21600;
  option dhcp-message-type 5;
  option domain-name-servers 10.4.0.222,10.4.0.1;
  option dhcp-server-identifier 10.4.0.1;
  option netbios-name-servers 10.4.0.1;
  option rfc3442-classless-static-routes 8,10,10,4,0,253,16,192,168,10,4,0,253;
  renew 0 2008/1/20 01:03:16;
  rebind 0 2008/1/20 03:34:59;
  expire 0 2008/1/20 04:19:59;
}


Якщо рядок "option rfc3442-classless-static-routes 8,10,10,4,0,253,16,192,168,10,4,0,253;" відсутній (цифри можуть бути інші), просто видаліть цей файл та перезавантажте dhclient.

P.S. У мене така проблема виникла після оновлення пакету dhclient з версії 3.0.6-10.fc8.i386 до 3.0.6-12.fc8.i386, хоча я не перевіряв... Можливо причина в чомусь іншому.

==Загальні поради==

1. Люди, читайте логи! Особливо зверніть увагу на повідомлення у файлі /var/log/messages, які пишуться туди після ваших маніпуляцій з dhclient.  Особливо слід звернути увагу на повідомлення програм (служб) "dhclient", "avahi-daemon", "NET". Наприклад такі:

Jan 20 00:19:59 localhost dhclient: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 4
Jan 20 00:19:59 localhost dhclient: DHCPOFFER from 10.4.0.222
Jan 20 00:19:59 localhost dhclient: DHCPREQUEST on eth0 to 255.255.255.255 port 67
Jan 20 00:19:59 localhost dhclient: DHCPACK from 10.4.0.1
...
Jan 20 00:19:59 localhost NET[2833]: /sbin/dhclient-script : updated /etc/resolv.conf
Jan 20 00:19:59 localhost dhclient: bound to 10.4.0.27 -- renewal in 9797 seconds.

2. Гуглювання (http://www.google.com) може дати дуже багато користі.

3. Читайте manual'и:
    man dhclient
    man dhclient.conf
    man dhclient-script

4. Якщо хочеться глибше зрозуміти суть проблеми - читайте RFC3442 (http://www.ietf.org/rfc/rfc3442.txt)

==Контакти==

Якщо виникли якісь питання - пишіть, спробую допомогти. Мої контакти:

e-mail: admin[вухо]konus.in.ua
ICQ: 316226563

Хай щастить. Сашко (aka Konus).

Ваша оцінка: Немає Усереднена оцінка: 5 (1 vote)
Додати поточну сторінку в соціальні закладки
Доданий в Опубліковано Vitovt 17 Грудень, 2008 - 16:31

Коментарі

Anonymous (гість) | 14 Лютий, 2009 - 03:24

Дякую!!! Саме цього шукав!

Написати нове повідомлення

Вміст цього поля є приватним і не буде доступний широкому загалу.
  • Рядки та параграфи відокремлюються автоматично.
  • Дозволені теги HTML: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <table> <tbody> <tr> <td> <sub> <sup> <p> <br /> <div> <h2> <h3> <h4> <img /> <hr />

Детальніше про опції форматування

CAPTCHA
Це питання для того, щоб точно визначити, що ви людина, а не злісний спам-робот.
Фото Капча
Введіть букви та цифри показані на малюнку.
RSS-матеріал