====== Mini FAQ ====== Q: Що потрібно від свіча, щоб запрацювала option 82? \\ A: Мати налаштований і працюючий dhcp relay з увімкненою option 82, dhcp snooping, що не пропускає клієнтські запити в обхід рілею, та ip source guard, що дропає пакети для айпішок, які не отримано крізь рілей.\\. Q: На яких свічах має бути рілей? \\ A: На всіх - рівня доступу.\\ Q: У нас тут пів мережі на мильницях, це буде працювати? А можна тримати частину мережі на IP+MAC та іншу частину на option 82? \\ A: Сталася критична помилка - у вас недостатньо грошей для використання цього функціоналу.\\ ====== Налаштування Ubilling та DHCP option 82 ====== Для того, щоб усе запрацювало в базовому варіанті, нам потрібно виконати шість простих кроків: 1. Підмережу користувачів додано як: ^ ID ^ Початкова ІР ^ Остання ІР ^ Мережа/CIDR ^ Тип мережі ^ | 1 | 172.16.0.0 | 172.16.0.255 | 172.16.0.0/24 | dhcp82 | 2. /etc/rc.conf виглядає наступним чином ifconfig_em0="inet 172.16.0.1 netmask 255.255.255.0" ifconfig_em0_alias0="inet 172.32.0.1 netmask 255.255.240.0" ifconfig_em0_alias1="inet 192.168.94.1 netmask 255.255.255.0" 3. Шаблон config/dhcp/global.template option domain-name "ourisp"; option domain-name-servers 172.16.0.1; default-lease-time 3600; max-lease-time 43200; authoritative; ddns-update-style none; log-facility local7; one-lease-per-client true; deny duplicates; shared-network ourisp { {SUBNETS} subnet 192.168.94.0 netmask 255.255.255.0 { } subnet 172.32.0.0 netmask 255.255.240.0 { default-lease-time 3600; option domain-name "isp"; option subnet-mask 255.255.240.0; option domain-name-servers 172.32.0.1; option routers 172.32.0.1; pool { range 172.32.0.100 172.32.0.254; {DENYMEMBERS} } log(info, "=="); if exists agent.remote-id and exists agent.circuit-id { if binary-to-ascii(16, 8, "", substring(option agent.remote-id, 2, 1)) = "0" { set switch-mac = concat("0", binary-to-ascii(16, 8, "", substring(option agent.remote-id, 2, 1)), ":", binary-to-ascii(16, 8, ":", substring(option agent.remote-id, 3, 6))); # log(info,concat("SWITCH-MAC1:",switch-mac)); } else { # set switch-mac = binary-to-ascii(16, 8, ":", substring(option agent.remote-id, 2, 6)); # log(info,concat("SWITCH-MAC2:",switch-mac)); set switch-mac = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,6,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(option agent.remote-id,7,1))),2) ); # log(info,concat("SWITCH-MAC3:",switch-mac3)); } set clip = binary-to-ascii(10,8,".",leased-address); set clremote = binary-to-ascii(16,8,"",option agent.remote-id); set clcircuit = binary-to-ascii(10,8,"",option agent.circuit-id); set switch-port = binary-to-ascii(10, 8, "", substring(option agent.circuit-id, 5, 1)); set switch-port-vlan = binary-to-ascii(10, 16, "", substring(option agent.circuit-id, 2, 2)); log( info,concat("OPTION82 INFO - SWITCHMAC: ",switch-mac," PORTSW: ",switch-port," VLAN: ",switch-port-vlan)); log( info,concat("*Leased IP: ",clip, " SWITCH: ",clremote," PORT: ",clcircuit," SWITCHMAC: ",switch-mac," PORTSW: ",switch-port," VLAN: ",switch-port-vlan," (with opt82)") ); } else { set clhw = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2) ); log( info,concat("*Leased IP: ",binary-to-ascii(10,8,".",leased-address), " MAC: ", clhw," (without opt82)") ); } log(info, "=="); } } 4. Шаблон config/dhcp/option82.template перебуває в дефолтному стані ([[templating#dhcp_option82|підтримувані макроси]])\\ 5. У конфізі alter.ini встановлено опцію NMLEASES = /var/log/dhcpd.log і налаштовано [[bsddhcpd|правильне логування ISP-DHCPD]] \\ 6. В OnConnect вимкнено прибивання за MAC-у. Тепер це проблема ip source guard і dhcp snooping вашого свіча (192.168.94.4 у прикладі). Виходячи з усього вищевказаного, не складно зробити висновок, що прив'язка планується за парою повних remote-id/circuit-id. Перевірити поведінку такого конфіга не складно за допомогою наступних нехитрих рухів тіла ====== Відлагодження scapy====== p="\x01\x01\x05\x02\x06\x11\x22\x34\x44\x55\x66" dhcp_discover = Ether(src=RandMAC(),dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=RandString(12,'0123456789abcdef'))/DHCP(options=[("message-type","discover"),("relay_agent_Information",p),"end"]) sendp(dhcp_discover) у відповідь на що ми маємо отримати щось на кшталт: Oct 15 00:38:20 test dhcpd: Wrote 0 class decls to leases file. Oct 15 00:38:20 test dhcpd: Wrote 1 leases to leases file. Oct 15 00:38:34 test dhcpd: == Oct 15 00:38:34 test dhcpd: *Leased IP: 172.16.0.2 SWITCH: 112234445566 PORT: 5 (with opt82) Oct 15 00:38:34 test dhcpd: == Oct 15 00:38:34 test dhcpd: == Oct 15 00:38:34 test dhcpd: *Leased IP: 172.16.0.2 SWITCH: 112234445566 PORT: 5 (with opt82) Oct 15 00:38:34 test dhcpd: == Oct 15 00:38:34 test dhcpd: DHCPDISCOVER from 30:32:63:30:35:62 via em0 Oct 15 00:38:35 test dhcpd: DHCPOFFER on 172.16.0.2 to 30:32:63:30:35:62 via em0 а також під час прослуховування за допомогою tcpdump -n -i em0 -s 0 -v -vv ми спостерігатимемо прилітаючі до нас Agent-Information Option 82, length 13: Remote-ID........ Circuit-ID....... ====== Особливості роботи на комутаторах Zyxel ====== GS-4012, GS-3012 взагалі не повертають remote-id. Тому орієнтуватися варто тільки на sub-option 1 (Agent Circuit ID). Тож при побудові шаблону потрібно керуватися ось цим: http://zyxel.ru/kb/2030 {{ :zyxelopt82.png?400 |}} У чорновому варіанті можна оформити це приблизно так: set clremote = binary-to-ascii(10,16,"",substring(option agent.circuit-id,4,2)); set clcircuit = binary-to-ascii(10,16,"",substring(option agent.circuit-id,1,2)); а також виправити option82.template відповідно до цих реалій що в результаті дає нам такий лог Oct 15 16:52:00 test dhcpd: == Oct 15 16:52:00 test dhcpd: *Leased IP: 172.32.0.100 SWITCH: 18259 PORT: 768 (with opt82) Oct 15 16:52:00 test dhcpd: == Приклад конфігурації Zyxel GS-3012: ip address inband-default 192.168.94.4 255.255.255.0 ip address default-gateway 192.168.94.1 interface port-channel 12 dhcp snooping trust exit dhcp smart-relay dhcp smart-relay helper-address 192.168.94.1 dhcp smart-relay option dhcp smart-relay information dhcp snooping dhcp snooping vlan 1 dhcp snooping vlan 1 option dhcp snooping vlan 1 information dhcp dhcp-vlan 1 ====== Спрощення життя ====== Для зручнішого виловлювання пар remote-id і circuit-id існує сервіс аналогічний [[uhw|UHW]], що знаходиться в **docs/opt82_uhw**. Налаштування в основному аналогічне такому в оригінального сервісу. Ходять чутки, що погрожували дописати ще й самостійну активацію абонентом ;) ====== Патч для isc-dhcp44-server ====== Для того, щоб користувачі могли змінювати свої пристрої скільки завгодно разів, і не чекати, поки на сервері закінчиться ліза під їхню адресу, - до DHCP-сервера потрібно застосувати патч і перезібрати пакет із вихідного коду. --- server/dhcp.c.orig 2017-07-25 16:39:54.000000000 +0300 +++ server/dhcp.c 2017-09-13 00:26:29.330284000 +0300 @@ -31,6 +31,7 @@ #include #include +extern int flag_dd_option; static void maybe_return_agent_options(struct packet *packet, struct option_state *options); static int reuse_lease (struct packet* packet, struct lease* new_lease, @@ -4900,8 +4901,13 @@ { if (LEASE_NOT_EMPTY(pool->free)) candl = LEASE_GET_FIRST(pool->free); - else + else if (LEASE_NOT_EMPTY(pool->abandoned)) candl = LEASE_GET_FIRST(pool->abandoned); + else if (flag_dd_option) + { + candl = LEASE_GET_FIRST(pool->active); + candl -> ends = cur_time; + } } /* --- server/dhcpd.c.orig 2017-07-25 16:39:54.000000000 +0300 +++ server/dhcpd.c 2017-09-13 03:25:44.556962000 +0300 @@ -57,6 +57,7 @@ gid_t set_gid = 0; #endif /* PARANOIA */ +int flag_dd_option = 0; struct iaddr server_identifier; int server_identifier_matched; @@ -184,6 +185,7 @@ " [-play trace-input-file]\n" #endif /* TRACING */ " [-pf pid-file] [--no-pid] [-s server]\n" + " [-dd] - enable dd mode\n" " [if0 [...ifN]]", isc_file_basename(progname)); } @@ -329,6 +331,8 @@ usage(use_noarg, argv[i-1]); set_chroot = argv [i]; #endif /* PARANOIA */ + } else if (!strcmp (argv [i], "-dd")) { + flag_dd_option = 1; } else if (!strcmp (argv [i], "-cf")) { if (++i == argc) usage(use_noarg, argv[i-1]); Після того, як перезібрали пакет та встановили його в системі, необхідно через rc.conf ввімкнути даний функціонал, додавши опцію ''-dd'' до параметрів запуску, наприклад: dhcpd_flags="-q -dd"