Difficulties in administering guest hotspots (part 1)

    In this short article I will tell you how to relieve the headache of administering large subnets tied to the distribution of the Internet to incoming users.
    Basic tools:
    • Head
    • Head again
    • Hands
    • Freebsd
    • Pf
    • isc-dhcpd
    • memcached
    • perl

    Those who want to learn about everything written under the cut, the rest a good look at other topics.
    Link to the second part

    The main problems of large dhcp servers

    Everyone who dealt with isc-dhcpd knows how problematic it is to steer access within several ip networks. The main problem is the allocation of static entries for specific hosts, the spelling of rules in the firewall to provide access, and other appropriate system administrator's routine. This solution was found, written and tested literally a couple of months ago. So…

    Existing Management Methods

    ISC-DHCPD server has practically no built-in methods for managing its state. The only exception is the omshell appendage, which provides access to the internal isc-dhcpd database and allows you to get and change the values ​​of internal fields without restarting the server. The EMNIP configuration file dhcpd.conf remains unchanged. Changes are automatically recorded in dhcpd.leases. To control the appearance, delivery of addresses and their status, many of you have already tried the methods of parsing the isc-dhcpd system log and maybe even got the result, but not that you were 100% satisfied. But as experience shows, many of you missed the possibility of using dhcpd events in the manuals.

    What are dhcpd events?

    Each operation (event) of issuing, releasing and deleting an address triggers an internal handler that can be reassigned. Below is a short excerpt from man dhcpd.conf What do these cryptic letters mean? But they mean the following. isc-dhcpd using its internal events can update DNS records in BIND and if you want to reassign event handlers, then do not forget to add the code for updating DNS records in your handler. Confused? Unraveling! For any address pool inside the dhcpd.conf configuration file, you can specify an external event handler. In any place of the config, it looks like this:

    There are three kinds of events that can happen regarding a lease, and
    it is possible to declare statements that occur when any of these
    events happen. These events are the commit event, when the server has
    made a commitment of a certain lease to a client, the release event,
    when the client has released the server from its commitment, and the
    expiry event, when the commitment expires.

    To declare a set of statements to execute when an event happens, you
    must use the on statement, followed by the name of the event, followed
    by a series of statements to execute when the event happens, enclosed
    in braces. Events are used to implement DNS updates, so you should
    not define your own event handlers if you are using the built-in DNS
    update mechanism.

    The built-in version of the DNS update mechanism is in a text string
    towards the top of server/dhcpd.c. If you want to use events for
    things other than DNS updates, and you also want DNS updates, you will
    have to start out by copying this code into your dhcpd.conf file and
    modifying it.

    on commit {
    on release {
    on expiry {

    Handlers can be defined for address pools, as well as globally for the entire system. The most interesting thing is that the handlers previously used in the address pool do not overlap with the global one. This way your DNS updates will not be affected.

    Practical use

    Below you can see my current config for calling handlers. We will not go into details and analyze the internal data format used in the dhcpd internal database, we will dwell only on a few points that may come in handy.
    • clientIP - current address of the action
    • clientMAC - current mac address for clientIP
    • host-name - internal host name (can be obtained when issuing the address from the client or set automatically as in our case
    • ddns-hostname - host name that will be sent when updating in bind

    In our case, the host-name and ddns-hostname entries should be generated automatically if the host name is empty ( Note: the host name in UTF-8 or in any other encoding is not considered empty ) Actually, as a piece of the above code shows, a script with parameters. Parameters are passed to ARGV. A script can be anything (shell script, php, python and any other program). Well, with release and expiry everything seems to be clear. Why does commit use 2 script calls separately for the address and for the host name? Because if the host name is not in ANSI, the handler stupidly crashes and the script is not called. Well, for the sweet script code
    on commit {
    set clientIP = binary-to-ascii(10, 8, ".", leased-address);
    set clientMAC = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
    if option host-name = "" {
    option host-name = concat( "wifi-" , binary-to-ascii( 10, 8, "", substring( reverse( 1, leased-address), 0, 1)));
    ddns-hostname = concat( "wifi-" , binary-to-ascii( 10, 8, "", substring( reverse( 1, leased-address), 0, 1)));
    set clientHostName = option host-name;
    execute("/usr/local/etc/dhcp_helper/publish-ip-mac.pl", "commit", clientIP, clientMAC);
    execute("/usr/local/etc/dhcp_helper/publish-ip-mac.pl", "hostname", clientIP, clientHostName);

    on release {
    set clientIP = binary-to-ascii(10, 8, ".", leased-address);
    set clientMAC = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
    execute("/usr/local/etc/dhcp_helper/publish-ip-mac.pl", "release", clientIP, clientMAC);

    on expiry {
    set clientIP = binary-to-ascii(10, 8, ".", leased-address);
    if(exists agent.remote-id) {
    set clientMAC = binary-to-ascii(16, 8, ":", substring(option agent.remote-id, 2, 6));
    execute("/usr/local/etc/dhcp_helper/publish-ip-mac.pl", "expiry", clientIP, clientMAC);
    } else {
    execute("/usr/local/etc/dhcp_helper/publish-ip-mac.pl", "expiry", clientIP);

    use strict;
    use warnings;

    my $type = shift;
    my $ip = shift;
    my $mac = shift;

    # Fork so we can return control
    # to the dhcp server ASAP.
    my $pid = fork();

    # If we're the child, do whatever we need to do
    if($pid == 0) {
    open OUT,">>/var/tmp/publish.tmp";
    $mac = join(":",map { sprintf("%02s",$_); } split(":",$mac));
    print OUT "$type $ip $mac\n";
    close OUT;

    For everyone who wants to learn how to connect pf, dhcpd and web muzzle to manage all this economy, the continuation will be in the second part.
    In the meantime, your brain is aware of what is written here, application methods and ease of solution, you can ask questions.

    © Aborche 2011

    Also popular now: