Why is dhcpd not matching the MAC address as it should

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Why is dhcpd not matching the MAC address as it should

Andrew Falanga (afalanga)
Greetings to all,

On my little network, I have a simple device which is apparently using only bootp (as opposed to the dhcp extensions to bootp) for obtaining its address. My dhcpd.conf file looks something like this

class "user" {
    match if substring(hardware, 1, 3) = 00:01:02;
    log(info, "matched to a 3com";
}

class "controller" {
    # tried matching based on two different styles I've seen on the net
    #match if substring(hardware, 1, 3) = 00:a0:45;
    match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) = "1:00:a0:45");
    log(info, "found a controller");
}

subnet 192.168.0.0 netmask 255.255.0.0 {
    pool {
        allow members of "user";
        range 192.168.0.20 192.168.0.99;
        log(info, "A user just attached");
    }            

    pool {
        allow members of "controller";
        # never more than 1 on the network at a time
        range 192.168.1.240;
        log(info, "Allocated to a pwr user");
    }
}

The dhcp server simply will not match to the pool it's supposed to. From the log

BOOTREQUEST from 00:a0:45:95:ce:14 via eth1: BOOTP from dynamic client and no dynamic leases

The device is DENIED for both classes. Using tcpdump and wireshark for comparing packet dumps from a laptop and the controller device (I temporarily made a class for an HP laptop, added that class to the pool used for "controller" and extended the range by 2 addresses), it seems the only difference is that the controller device is literally a bootp packet (i.e. it lacks the mandatory option 53 identifying dhcp type), and carries only option 255. The laptop was matched by dhcpd without using the "binary-to-ascii" conversion.  Additionally, and curiously, the controller client IP header uses the IP address first allocated, 192.168.1.240, but in the bootp section of the packet, the ciaddr field is 0. If it believes it has a valid lease, shouldn't it reflect this in ciaddr?

Why is dhcpd failing to match the MAC address of this device?

Thanks,
Andy
_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

Re: Why is dhcpd not matching the MAC address as it should

Sten Carlsen

> On 17 Jan 2018, at 19.23, Andrew Falanga (afalanga) <[hidden email]> wrote:
>
> Greetings to all,
>
> On my little network, I have a simple device which is apparently using only bootp (as opposed to the dhcp extensions to bootp) for obtaining its address. My dhcpd.conf file looks something like this
>
> class "user" {
>    match if substring(hardware, 1, 3) = 00:01:02;
>    log(info, "matched to a 3com";
> }
>
> class "controller" {
>    # tried matching based on two different styles I've seen on the net
>    #match if substring(hardware, 1, 3) = 00:a0:45;
>    match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) = "1:00:a0:45");
>    log(info, "found a controller");
> }
Are you sure the “1:” is needed? I don’t think so.

>
> subnet 192.168.0.0 netmask 255.255.0.0 {
>    pool {
>        allow members of "user";
>        range 192.168.0.20 192.168.0.99;
>        log(info, "A user just attached");
>    }            
>
>    pool {
>        allow members of "controller";
>        # never more than 1 on the network at a time
>        range 192.168.1.240;
>        log(info, "Allocated to a pwr user");
>    }
> }
>
> The dhcp server simply will not match to the pool it's supposed to. From the log
>
> BOOTREQUEST from 00:a0:45:95:ce:14 via eth1: BOOTP from dynamic client and no dynamic leases
>
> The device is DENIED for both classes. Using tcpdump and wireshark for comparing packet dumps from a laptop and the controller device (I temporarily made a class for an HP laptop, added that class to the pool used for "controller" and extended the range by 2 addresses), it seems the only difference is that the controller device is literally a bootp packet (i.e. it lacks the mandatory option 53 identifying dhcp type), and carries only option 255. The laptop was matched by dhcpd without using the "binary-to-ascii" conversion.  Additionally, and curiously, the controller client IP header uses the IP address first allocated, 192.168.1.240, but in the bootp section of the packet, the ciaddr field is 0. If it believes it has a valid lease, shouldn't it reflect this in ciaddr?
>
> Why is dhcpd failing to match the MAC address of this device?
>
> Thanks,
> Andy
> _______________________________________________
> dhcp-users mailing list
> [hidden email]
> https://lists.isc.org/mailman/listinfo/dhcp-users
--
Best regards

Sten Carlsen

No improvements come from shouting:

      "MALE BOVINE MANURE!!!"
_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

RE: [EXT] Re: Why is dhcpd not matching the MAC address as it should

Andrew Falanga (afalanga)
> > class "controller" {
> >    # tried matching based on two different styles I've seen on the net
> >    #match if substring(hardware, 1, 3) = 00:a0:45;
> >    match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) =
> "1:00:a0:45");
> >    log(info, "found a controller");
> > }
> Are you sure the “1:” is needed? I don’t think so.

This is actually an irritating hole in the documentation.  It isn't truly clear what "hardware" returns nor is it made clear which method is "better" than the other.  I've tried both

match if substring(hardware, 1,3) = 00:a0:45;

and

match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) = "1:00:a0:45");

The one thing I do know for sure, the hardware operator returns, in addition to the MAC, the "type" field which is part of the bootp/dhcp header.  In this case, because it is Ethernet, it is 1.  In the first match, I'm only looking for the MAC  so the address is from 1 - 3 of the hardware "data-string" (the docs name for it, it doesn't elaborate anywhere that I know what a *data-string* is, from the usage in the config file, it's a *string*).  I'm pretty sure the first form of usage could be re-written as

match if substring(hardware, 0, 3) = 1:00:a0:45;

but I truthfully haven't tested it.

Andy
_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

Re: Why is dhcpd not matching the MAC address as it should

Simon Hobson
In reply to this post by Andrew Falanga (afalanga)
Andrew Falanga (afalanga) <[hidden email]> wrote:

> class "controller" {
>    # tried matching based on two different styles I've seen on the net
>    #match if substring(hardware, 1, 3) = 00:a0:45;
>    match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) = "1:00:a0:45");

This won't match, the string "1" (that you've used) will not match the string "01" (what binary-to-ascii will generate). Also you are comparing FIVE bytes from the MAC address to FOUR bytes in the string. What you should do is simply compare the binary values :
match if substring(hardware, 0, 3) = 1:00:a0:45;
or
match if substring(hardware, 1, 3) = 00:a0:45; (as you've shown as an alternative above)

Note: the leading "1" is the hardware type, 1 indicating Ethernet.

_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

Re: [EXT] Re: Why is dhcpd not matching the MAC address as it should

Sten Carlsen
In reply to this post by Andrew Falanga (afalanga)

On 17 Jan 2018, at 22.27, Andrew Falanga (afalanga) <[hidden email]> wrote:

class "controller" {
  # tried matching based on two different styles I've seen on the net
  #match if substring(hardware, 1, 3) = 00:a0:45;
  match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) =
"1:00:a0:45");
  log(info, "found a controller");
}
Are you sure the “1:” is needed? I don’t think so.

This is actually an irritating hole in the documentation.  It isn't truly clear what "hardware" returns nor is it made clear which method is "better" than the other.  I've tried both

match if substring(hardware, 1,3) = 00:a0:45;

and

match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) = "1:00:a0:45");

The one thing I do know for sure, the hardware operator returns, in addition to the MAC, the "type" field which is part of the bootp/dhcp header.  In this case, because it is Ethernet, it is 1.  In the first match, I'm only looking for the MAC  so the address is from 1 - 3 of the hardware "data-string" (the docs name for it, it doesn't elaborate anywhere that I know what a *data-string* is, from the usage in the config file, it's a *string*).  I'm pretty sure the first form of usage could be re-written as

match if substring(hardware, 0, 3) = 1:00:a0:45;

but I truthfully haven't tested ti
I Suggest trying:
match if substring(hardware, 0, 3) = 00:a0:45;
The 1: does not come on the wire.

Andy
_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
-- 
Best regards

Sten Carlsen

No improvements come from shouting:

      "MALE BOVINE MANURE!!!"


_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

Re: Why is dhcpd not matching the MAC address as it should

Bill Shirley-2
In reply to this post by Simon Hobson
Plus binary-to-ascii truncates leading zeros.  The result would be
"1:0:a0:45"

You could also use subclasses:
class "mobile_iPhone" {
    match substring(option dhcp6.client-id, 8, 3);
    set member_of = "mobile_iPhone";
    if ((not exists server.ddns-hostname) or (lcase(option fqdn.hostname) = "iphone")) {
        ddns-hostname = concat("iPhone-", binary-to-ascii(16, 8, "", suffix(option dhcp6.client-id, 3)));
    }
}
subclass "mobile_iPhone"    08:74:02;
subclass "mobile_iPhone"    10:41:7f;
subclass "mobile_iPhone"    24:a2:e1;
dhcp6.client-id is like dhcp4 hardware.


class "VoIP_phone" {
    match hardware;
    set member_of = "VoIP_phone";
}
subclass "VoIP_phone"    1:00:30:4d:02:6d:26    { ddns-hostname "Bob-VoIP"; }
subclass "VoIP_phone"    1:00:30:4d:02:6c:c7    { ddns-hostname "whoRu-VoIP"; }        # who are you?

class "Panasonic" {
    match if (
        substring(hardware, 1,3) = 08:00:23
        or substring(hardware, 1,3) = 00:80:45
    );
    set member_of = "Panasonic";
}

Bill

On 1/17/2018 4:34 PM, Simon Hobson wrote:
Andrew Falanga (afalanga) [hidden email] wrote:

class "controller" {
   # tried matching based on two different styles I've seen on the net
   #match if substring(hardware, 1, 3) = 00:a0:45;
   match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) = "1:00:a0:45");
This won't match, the string "1" (that you've used) will not match the string "01" (what binary-to-ascii will generate). Also you are comparing FIVE bytes from the MAC address to FOUR bytes in the string. What you should do is simply compare the binary values :
match if substring(hardware, 0, 3) = 1:00:a0:45;
or
match if substring(hardware, 1, 3) = 00:a0:45; (as you've shown as an alternative above)

Note: the leading "1" is the hardware type, 1 indicating Ethernet.

_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users


_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

RE: [EXT] Re: Why is dhcpd not matching the MAC address as it should

Andrew Falanga (afalanga)
In reply to this post by Simon Hobson
 

> > class "controller" {
> >    # tried matching based on two different styles I've seen on the net
> >    #match if substring(hardware, 1, 3) = 00:a0:45;
> >    match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) =
> > "1:00:a0:45");
>
> This won't match, the string "1" (that you've used) will not match the string
> "01" (what binary-to-ascii will generate). Also you are comparing FIVE bytes
> from the MAC address to FOUR bytes in the string. What you should do is
> simply compare the binary values :
> match if substring(hardware, 0, 3) = 1:00:a0:45; or match if
> substring(hardware, 1, 3) = 00:a0:45; (as you've shown as an alternative
> above)

I've done some further debugging and added some logging to dhcpd.c and
recompiled my dhcpd binary.  Why is there no class types associated with
my packet?  This is from the dhcpd binary output after my additional log_debug
statements :

allocate_lease ENTRY
 pool 0x209de50, prohibit_list (nil), permit_list 0x209e040
 permitted ENTRY
     packet 0x20aad70, permit_list 0x209e040
     checking permit_list 0x209e040
     permit_list type 6
     permit_class type, class count 0

To make this relevant, I'm using version 4.3.4 of dhcpd.  On line number 4784
of server/dhcp.c , is the function allocate_lease().  At the start of the for loop
are calls to permitted().  In permitted() is a case statement looking at the packet
type.  It matches the case for *permit_class* which is expected since the config
file defines 2 classes.  However, as the last line of the output shows, there are 0
classes associated with this packet.  Why would that be?  There are 2 classes
defined, why aren't they associated with the struct packet instance being evaluated
in this block of code?  I hope I'm not chasing down a rabbit hole but this does seem
to be the root issue.

Andy
_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

RE: [EXT] Re: Why is dhcpd not matching the MAC address as it should

glenn.satchell
This is a simple binary match on the hardware address, starting at offset
1 and 3 bytes long. So it doesn't care what the hardware type is.

match if substring(hardware, 1, 3) = 00:a0:45;

You could also, equally correctly, match starting at offset 0 and 4 bytes
long:

match if substring(hardware, 0, 4) = 01:00:a0:45;

In the dhcp-eval man page it defines the hardware operator:

"The hardware operator returns a data string whose first element is the
type of network interface indicated in packet being considered, and whose
subsequent elements are client's link-layer address. If  there  is  no
packet, or if the RFC2131 hlen field is invalid, then the result is null.
Hardware types include ethernet (1), token-ring (6), and fddi (8).
Hardware types are specified by the IETF, and details on how the type
numbers are defined can be found in RFC2131 (in the ISC DHCP distribution,
this is included in the doc/ subdirectory)."

Secondly, in the range declaration for bootp clients you need to use this
syntax:

range dynamic-bootp 1.2.3.4;

Your original class is probably matching, but in the allowed subnet there
are no dynamic bootp addresses on offer. In the dhcpd.conf man page it
says:

"The dynamic-bootp flag may be specified if addresses in the specified
range may be  dynamically  assigned  to BOOTP clients as well as DHCP
clients."

regards,
-glenn

On Fri, January 19, 2018 5:03 am, Andrew Falanga (afalanga) wrote:

>
>> > class "controller" {
>> >    # tried matching based on two different styles I've seen on the net
>> >    #match if substring(hardware, 1, 3) = 00:a0:45;
>> >    match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) =
>> > "1:00:a0:45");
>>
>> This won't match, the string "1" (that you've used) will not match the
>> string
>> "01" (what binary-to-ascii will generate). Also you are comparing FIVE
>> bytes
>> from the MAC address to FOUR bytes in the string. What you should do is
>> simply compare the binary values :
>> match if substring(hardware, 0, 3) = 1:00:a0:45; or match if
>> substring(hardware, 1, 3) = 00:a0:45; (as you've shown as an alternative
>> above)
>
> I've done some further debugging and added some logging to dhcpd.c and
> recompiled my dhcpd binary.  Why is there no class types associated with
> my packet?  This is from the dhcpd binary output after my additional
> log_debug
> statements :
>
> allocate_lease ENTRY
>  pool 0x209de50, prohibit_list (nil), permit_list 0x209e040
>  permitted ENTRY
>      packet 0x20aad70, permit_list 0x209e040
>      checking permit_list 0x209e040
>      permit_list type 6
>      permit_class type, class count 0
>
> To make this relevant, I'm using version 4.3.4 of dhcpd.  On line number
> 4784
> of server/dhcp.c , is the function allocate_lease().  At the start of the
> for loop
> are calls to permitted().  In permitted() is a case statement looking at
> the packet
> type.  It matches the case for *permit_class* which is expected since the
> config
> file defines 2 classes.  However, as the last line of the output shows,
> there are 0
> classes associated with this packet.  Why would that be?  There are 2
> classes
> defined, why aren't they associated with the struct packet instance being
> evaluated
> in this block of code?  I hope I'm not chasing down a rabbit hole but this
> does seem
> to be the root issue.
>
> Andy
> _______________________________________________
> dhcp-users mailing list
> [hidden email]
> https://lists.isc.org/mailman/listinfo/dhcp-users
>


_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users
Reply | Threaded
Open this post in threaded view
|

RE: [EXT] Re: Why is dhcpd not matching the MAC address as it should

Andrew Falanga (afalanga)
In reply to this post by Simon Hobson
> -----Original Message-----
> From: dhcp-users [mailto:[hidden email]] On Behalf Of
> Simon Hobson
> Sent: Wednesday, January 17, 2018 2:35 PM
> To: Users of ISC DHCP <[hidden email]>
> Subject: [EXT] Re: Why is dhcpd not matching the MAC address as it should
>
> Andrew Falanga (afalanga) <[hidden email]> wrote:
>
> > class "controller" {
> >    # tried matching based on two different styles I've seen on the net
> >    #match if substring(hardware, 1, 3) = 00:a0:45;
> >    match if (binary-to-ascii(16, 8, ":", substring(hardware, 0, 4)) =
> > "1:00:a0:45");
>
> This won't match, the string "1" (that you've used) will not match the string
> "01" (what binary-to-ascii will generate). Also you are comparing FIVE bytes
> from the MAC address to FOUR bytes in the string. What you should do is
> simply compare the binary values :
> match if substring(hardware, 0, 3) = 1:00:a0:45; or match if
> substring(hardware, 1, 3) = 00:a0:45; (as you've shown as an alternative
> above)
>
> Note: the leading "1" is the hardware type, 1 indicating Ethernet.
>

Simon (and others),

Thank you for the insights.  I have at last figured out the recipe.  I had to change my pool declaration/definition to be

    pool {
        allow dynamic bootp clients;
        allow members of "controller";
        range dynamic-bootp 192.168.1.240;
    }

I don't quite understand the reason why the server didn't figure out to allow them when the range had the "optional" modifier "dynamic-bootp" but with adding "allow dynamic bootp clients" to the pool definition, everything worked as it should.  

Thanks for the help and the insights.  Especially, thank you for the clarification that the binary-to-ascii function does return "both" 0's or leading 0's.  

Andy
_______________________________________________
dhcp-users mailing list
[hidden email]
https://lists.isc.org/mailman/listinfo/dhcp-users