📜 ⬆️ ⬇️

FreeBSD, dhcp, ip unnumbered and everything is all all ...

Our small company connects subscribers to the Internet using vlan-per-user technology.
So historically, there are both pluses and minuses in this, but the conversation is not about that now.
Usually, a network of gray addresses is allocated to each vlan, which is then released via NAT to the big world. But sometimes subscribers want a real white address, and until recently they were given a / 30 network. That in the realities of the present is very wasteful and subscribers with real addresses are transferred to the connection using SuperVLAN technology (RFC 3069).



All addresses - both gray and white are given out to subscribers via DHCP. The DHCP, NAT, and shaper services run on the same server running FreeBSD 9.3. Iron server is quite normal - Core i7, 8Gb RAM, Intel E1G42ET.
')
Task:

To give each subscriber the address of the same real address that he had, but no longer with a mask / 30, but with a new, general for all mask / 24 and gateway xxx1. Ensure the inability of the subscriber to work with someone else's real address.
Subscribers with gray addresses continue to issue a network to the subscriber.

Building a SuperVlan ala FreeBSD

Vlan9 is a technological vlan, nothing is connected to it, traffic will go there for real addresses not yet given out to subscribers.
Vlan10 - subscriber with gray address
Vlan11 and vlan12 are two subscribers with real addresses.

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 


We put on the client vlan11 with hands the address 1.1.1.11/24, gw 1.1.1.1 - the Internet client works.

If you want traffic to go between clients with real addresses, turn on ProxyARP

 sysctl net.link.ether.inet.proxyall=1 


(Bridge from private sticky vlan (man bridge) did not work in this case, the reasons will be discussed below)

Now let's do the most interesting

Distribution of addresses through DHCP

Specifically ISC-DHCPD ver 4.3

Addresses must be issued based on the interface from which the request came.
Unfortunately, the authors of isc-dhcpd are firmly convinced that they definitely know better what a sysadmin needs than a sysadmin himself. And they do not allow him to shoot himself in the leg, chopping off the system administrator's index finger to the very elbow.

As a result, you can specify a list of interfaces on which I would like to listen to requests from clients, but if in the dhcpd.conf config not specify a subnet to which the address on this interface falls, then it will be ignored.
And if the same addresses are specified on several interfaces, then DHCPREQ requests will be processed in one subnet.
And you can not register in dhcpd.conf neither subnet, nor pool, nor host, which would be tightly bound to a specific interface.

This is a dream, in fact it does not work:
 subnet 1.1.1.11 netmask 255.255.255.255 { option routers 1.1.1.1; range 1.1.1.11; interface vlan11; } 


Well, well ... There is a DHCP relay. We start the relay on the necessary ports, which will add Option 82 Agent Circuit ID, and give the dhcpd request.

Attempt 1:

Since the dhcp interface categorically does not want to listen to the loopback interface, we start an additional 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” 


Starting - does not start ...
dhcpd reports that it cannot bind socket.
Although different interfaces for the relay and for the daemon are directly indicated, both of them just in case want to bind the fallback socket to the address *: 67
what they report here with this line when starting “Sending on Socket / fallback”.

Naturally the one who starts the second system says: “Busy!”
How can I disable this fallback socket I could not find.

Attempt 2:

Alternative programs are dhcprelya and dhcprelay.
Again they report that they cannot make a bind socket. We look into the code and understand their fundamental difference from isc-creations. ISC uses device bpf and snatches its packets from the system almost at the very beginning of the network stack, even before the firewall and other excesses ... Alternators use the standard socket mechanism, but since we have the same address on several interfaces, the second bind is addressed to 1.1.1.1 : 67 the system again reports: “Busy!”

Attempt 3:

And let dhcrelay listen to ALL interfaces and forward requests to dhcpd, which will be nailed only to the address 192.168.5.1
We rebuild dhcpd so that it does not use BPF, but would connect via socket.
To do this, we quickly fix the isc-dhcp43-server port Makefile
Add to it:
CONFIGURE_ARGS + = - enable-use-sockets
We collect, we start - it was launched, but does not work. Dhcpd logs that it has assigned an address to the client, but the client does not receive a response from dhcpd.

We look tcpdump as the client on vlan10, that with gray addresses tries to receive the address.
tcpdump –i vlan10 - The request from the client is - there is no response from the server.
tcpdump –i vlan5 - silence
tcpdump –i lo0 - and here it is interesting:
see udp packet from relay to daemon from address 192.168.5.1 to address 192.168.5.1
see udp response from the daemon to the relay from the address 192.168.5.1 to the address 192.168.10.1

And here it becomes clear that since dhcrelay listens only through BPF - then the packets that pass through the internal interface lo0 he just does not see, there is no sense in rebuilding dhcrelay to use sockets, then we will return to the situation “Attempt 2”

Attempt 4:

We distribute dhcrelay and dhcpd to SEPARATE servers.

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” 


Does not work.
Oh yes….
Recalls tcpdump from “Attempt 3”, write to dhcpd server
route add 192.168.10.0/24 192.168.5.2
route add 1.1.1.0/24 192.168.5.2

It works now. Addresses to the client in vlan10 gives.
Now add to the dhcpd information about customers with real addresses.
The Internet is full of examples with classes in which substrings are cut out from agent id and circuit-id, create subclasses so that several addresses can be allocated to the connection port.

One address is enough for me, so it’s enough to describe the host with this line inside:
host-identifier option agent.circuit-id "vlan11"

If you compile SuperVLAN using bridge, then dhcrelay will forward requests from all interfaces connected to the bridge with agent.circuit-id = "bridge0", so that only interfaces with the same addresses and forced routing.

Total:

Advantages of the solution - the client will automatically receive the new settings, while he will have his old address.
Disadvantages - Second server required
ToDo: Check how the situation with the change of the MAC address of the client is handled. Whether dhcpd will issue the same real address from the host if it has not yet expired on the previous poppy.

And returning to the caring and direct authors isc-dhcpd.
In order for dhcpd to intercept bpf requests that come to the interface, it is necessary to register in the dhcpd.conf config section of the subnet which includes the address on this interface.
At the same time, there is no need to specify which subnet to use for issuing responses through the relay - it searches for matches in all.

Here is the dhcpd.conf config

 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: Unexpected rake and solution:
if anyone needs to raise isc dhcrelay on 8k interfaces
need to change
FD_SETSIZE value in files
/usr/src/sys/sys/select.h
/usr/include/sys/select.h

with
#define FD_SETSIZE 1024U
on
#define FD_SETSIZE 16384U

Reassemble isc-dhcrelay or isc-dhcpd

Source: https://habr.com/ru/post/243203/


All Articles