[Kea-users] Need help assigning subnets by class with host reservations

Thomas Markwalder tmark at isc.org
Mon Nov 14 13:55:15 UTC 2016

On 11/12/16 1:22 PM, mrobti at insiberia.net wrote:
> On 2016-11-11 04:23, Thomas Markwalder wrote:
>> On 11/10/16 11:50 PM, mrobti at insiberia.net wrote:
>>> On 2016-11-10 06:12, Thomas Markwalder wrote:
>>> On 11/9/16 2:28 PM, mrobti at insiberia.net wrote:
>>> On 2016-11-09 07:56, Thomas Markwalder wrote:
>>> On 11/9/16 4:20 AM, mrobti at insiberia.net wrote:
>>> On 2016-11-08 15:44, mrobti at insiberia.net wrote:
>>> I want to assign a client-class using hwaddr, from MySQL backend,
>>> and
>>> restrict a subnet for that client-class. In other words, only allow
>>> clients with known MAC addresses to use the subnet they are trying
>>> to
>>> connect to.
>>> DB hosts table has an entry for the client:
>>> dhcp4_subnet_id = 1
>>> dhcp_identifier_type = 0
>>> dhcp_identifier = UNHEX(REPLACE('aa:bb:cc:dd:ee:ff', ':', ''))
>>> hostname = test.local
>>> dhcp4_client_classes = test_class
>>> Config file has:
>>> "client-classes": [ {
>>> "name": "test_class"
>>> } ],
>>> "subnet4": [ {
>>> "id": 1,
>>> "subnet": "",
>>> "pools": [ { "pool": " -" } ],
>>> "client-class": "test_class"
>>> } ],
>>> But Kea says (debug level 50):
>>> : client packet has been assigned to the following class(es):
>>> : failed to select subnet for the client
>>> : no suitable subnet configured for a direct client
>>> It works if I remove "client-class" from the subnet definition, so
>>> something is not synchronizing the class somewhere.
>>> Could it be a problem that the DB hosts entry has no ipv4_address
>>> listed? (that column is NULL)  I don't have any other ideas.
>>> I've found this in the logs:
>>> : HOSTS_CFG_GET_ALL_IDENTIFIER get all hosts with reservations using
>>> identifier: hwaddr=aa:bb:cc:dd:ee:ff
>>> hwaddr=aa:bb:cc:dd:ee:ff, found 0 host(s)
>>> Why would this happen? Yes, I double checked the MAC address. I
>>> enabled MySQL logging, and I can't match up timestamps exactly, but
>>> I
>>> do find a query:
>>> SELECT host_id, dhcp_identifier, dhcp_identifier_type,
>>> dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname,
>>> dhcp4_client_classes, dhcp6_client_classes FROM hosts WHERE
>>> dhcp4_subnet_id = ? AND dhcp_identifier_type = ?    AND
>>> dhcp_identifier = ?
>>> I don't know if it's possible to see the executed version of this
>>> prepared query(?). Is it possible that the value Kea is placing in
>>> the
>>> query is not the correct binary string?
>>> _______________________________________________
>>> Kea-users mailing list
>>> Kea-users at lists.isc.org
>>> https://lists.isc.org/mailman/listinfo/kea-users
>>> Hello:
>>> We are looking into this for you.  As you probably know,  Kea will
>>> look
>>> first for hosts defined its configuration file and then within the
>>> hosts
>>> database (if it is specified).  Any log statements you see that
>>> contain
>>> "HOSTS_CFG_" pertain to looking at hosts defined via the
>>> configuration
>>> file.  In your case, since there are none, you see none found.  When
>>> Kea
>>> accesses the host database the logs should contain
>>> HOSTS_MGR_ALTERNATIVE_.   The following is a snippet from of the log
>>> in
>>> a setup I am testing with:
>>> 2016-11-09 10:18:45.018 DEBUG [kea-dhcp4.hosts/24940]
>>> HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4 get one host with reservation
>>> for
>>> subnet id 1 and IPv4 address
>>> 2016-11-09 10:18:45.018 DEBUG [kea-dhcp4.hosts/24940]
>>> HOSTS_CFG_GET_ALL_ADDRESS4 get all hosts with reservations for IPv4
>>> address
>>> 2016-11-09 10:18:45.018 DEBUG [kea-dhcp4.hosts/24940]
>>> HOSTS_CFG_GET_ALL_ADDRESS4_COUNT using address, found 0
>>> host(s)
>>> 2016-11-09 10:18:45.018 DEBUG [kea-dhcp4.hosts/24940]
>>> HOSTS_CFG_GET_ONE_SUBNET_ID_ADDRESS4_NULL host not found using
>>> subnet
>>> id
>>> 1 and address
>>> 2016-11-09 10:18:45.018 DEBUG [kea-dhcp4.hosts/24940]
>>> HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4 trying alternate source
>>> for
>>> host using subnet id 1 and address
>>> The last log statement indicates that Kea is looking in MySQL for
>>> hosts
>>> that have the allocated address.  It just so happens that Kea
>>> actually
>>> conducted a search in MySQL prior to the last one show above.  This
>>> search is done by subnet id and dhcp identifier.   However the
>>> function
>>> that performs this search happens to be missing a log entry.  This
>>> is
>>> why you see  the two selects  you cited in the MySQL log but only
>>> one
>>> log message against the alternate.   The original function we used
>>> was deprecated without the new one getting a log message.  Sorry
>>> about
>>> that.
>>> On the surface, it looks like Kea should be matching your host,
>>> we're
>>> still researching it.  You might try defining your host in the
>>> configuration file, for testing purposes.   Do you have a packet
>>> capture
>>> and what version of Kea are you running?
>>> Thank you for your response. I don't have a packet capture at the
>>> moment, but I do see the HOSTS_MGR_ALTERNATE_ line just like yours.
>>> I'm running the ubuntu package which shows version 1.0.0, the
>>> package
>>> name is version 1.0.0-1build1. I know that's behind the curve, but
>>> sometimes don't these packages include bugfixes from newer versions
>>> than they report?
>>> I can begrudgingly compile from source, but would not be happy
>>> taking
>>> it outside the system package manager.
>>> I just tried to test by putting the host in the config file, got
>>> this
>>> startup error:
>>> DHCP4_PARSER_FAIL failed to create or run parser for configuration
>>> element subnet4: unsupported configuration parameter
>>> 'client-classes'
>>> I think you meant client-classes failed to parse as part of the
>>> host
>>> element (not subnet4) ?
>> I think so, you mean the host element inside the subnet4 reservations
>> list, right? I put "client-classes" in a "reservations" entry in the
>> "subnet4" as such:
>> "subnet4": [ {
>>   "reservations": [ {
>>     "hw-address": "aa:bb:cc:dd:ee:ff",
>>     "client-classes": [ "test_class" ]
>>   }],
>>   "id": 1,
>>   "subnet": "",
>> ...
>> That's the right way to do it, correct? Version 1.0.0 didn't see
>> "client-classes" as valid in that context.
>>> But yes, "client-classes" was added in 1.1.0.
>>> 1.1.0 added a good deal more functionality to the RDBMS Host
>>> Reservations implementations, as well as a lot more with
>>> classification expression matching.
>>>> Looks like assigning client-classes to host reservations was a
>>>> feature only added after version 1.0? Can you please confirm when
>>>> it
>>>> was added?
>>>> _______________________________________________
>>>> Kea-users mailing list
>>>> Kea-users at lists.isc.org
>>>> https://lists.isc.org/mailman/listinfo/kea-users
>>> When an inbound packet is received things happen in this order:
>>> 1. The packet is classified by evaluating it against the test
>>> expression for defined classes
>>> 2. Subnet matching is conducted based on packet content.  This
>>> includes comparing the classes matched to the packet in step 1
>>> against
>>> the classes specified by the subnet's "client-class" list.
>>> 3. Look for host reservations
>>> The problem you have is two fold.   First, your "test-class" does
>>> not
>>> define a "test" expression and thus matching it against a packet
>>> always fails.   This causes the subnet selection to fail and the
>>> server drops the packet.  The second issue is that you are assigning
>>> a
>>> class to the host reservation, but associating the client to a
>>> reservation occurs after the subnet selection.  This is something of
>>> a
>>> chicken-and-the-egg situation.
>> This question did come up when I was reading the docs. It does seem
>> like the host class assignment needs to happen earlier and in a
>> different configuration scope.
>>> So while you can specify that a host belongs to one or more classes,
>>> this currently only means the host inherits options from those
>>> classes.
>>> I think it would help to understand what problem you are trying to
>>> solve.  Are you trying to ensure that only known clients get
>>> addresses?
>> Yes, that's the primary goal.
>>> Are you trying to map specific hosts to specific subnets?
>> Secondary goal is not mapping hosts to subnets, but to pools within
>> the same subnet. (Later we will add subnets and map to those.)
>>> How any hosts in how many subnets do you anticipate having?
>> Not many for now, but storing configuration information in a database
>> is a requirement in this case.
>>> If your network isn't large, you could define a class for each host
>>> whose "test" expression matches the host's hardware address. Then
>>> add
>>> these classes to the desired subnet4 client-class list.   Not ideal
>>> but it would work.  This would be akin to ISC DHCP sub-classing,
>>> though not quite as neat.   Another alternative would be to write a
>>> hook but we would need to understand your problem to offer a more
>>> detailed suggestion.  Our example hook library, user-chk,  does
>>> something similar to what you're after and is a good starting point
>>> for what is possible,
>>> http://kea.isc.org/docs/kea-guide.html#idp54000992.   Hooks are
>>> described in detail in our developer's guide:
>> https://jenkins.isc.org/job/Kea_doc/doxygen/df/d46/hooksdgDevelopersGuide.html.
>> Sounds like Kea doesn't support a "known-clients" type of
>> configuration. I'll read about hooks next, but I wouldn't think the
>> "known-clients" feature is unusual - is this design issue something
>> that will be addressed in a future version without the need for
>> external hook libraries?
>>  This is a feature that is likely to be added.  ISC is a small,
>> non-profit company and we can only do so much at a time.  Of course we
>> are also an open-source project so contributors are always welcome.
>> As you mention, this is likely a feature many users would like to
>> have.
>>> Now, I read briefly about user-chk. Reading a text file upon each
>>> packet arrival doesn't sound efficient, regardless our requirement
>>> is using a database. Would it be possible to:
>>> 1. remove "client-class" from the subnet so all clients can
>>> initially be assigned to the subnet just for purposes of working
>>> around the chicken/egg problem you mentioned
>>> 2. assign class names to known clients using the existing database
>>> reservations system (note, class would be defined in config file
>>> with no "test" expression and our reservations have NULL for the IP
>>> address)
>>> 3. have the user-chk hook library inspect the assigned class and
>>> deny or reassign if the class is empty (not having been assigned in
>>> step 2)
>>> If this is possible, can I do it in version 1.0 or is 1.1.0 required
>>> for any of the above?
>> The user_chk library as it stands is really meant as a learning
>> tool/starting point, not as something intended for busy production
>> environment.   You are free to alter it however you like.   You may
>> find it more expedient to use it as guide or skeleton for your own new
>> hook lib.  It likely has a fair amount of stuff you don't need.
> Right, I've put together a library that is only a few lines of code
> that seems to do what we need. Thanks for the examples and documentation.
>> What
>> you are proposing is doable, but not with 1.0 as it does not support
>> client-classes in the host reservations.
>> If you look at the lease4_select hook point arguments:
>>     * ARGUMENTS:
>>      * name: QUERY4, type: isc::dhcp::Pkt4Ptr [1], direction: IN
>>      * name: SUBNET4, type: isc::dhcp::Subnet4Ptr [2], direction: IN
>>      * name: FAKE_ALLOCATION, type: bool, direction: IN
>>      * name: LEASE4, type: isc::dhcp::Lease4Ptr [3], direction: IN/OUT
> I had looked earlier myself, but was not able to find a list of hook
> points. Can you please provide a link to where that is?
> In any case, thank you for this pointer which has what was needed. It
> appears I have things working, but I ran into a couple problems and
> had a couple questions if you don't mind:
> 1. FYI, on a Debian-based system, the include and lib directories for
> compiling the hook library were somewhat different (especially the
> lib) than the example in the docs:
> -I /usr/local/include/kea
> -L /usr/local/lib
Our apologies. Could you point us to the specific reference?
> 2. There is a bug in the 1.1.0 tarball: the dhcpsrv/lease.h file does
> not get installed, so compiling a hook library that does anything with
> leases is not possible. I had to add to the end of
> src/lib/dhcpsrv/Makefile.am:
> libkea_dhcpsrv___includedir = $(pkgincludedir)/dhcpsrv
> libkea_dhcpsrv___include_HEADERS = \
>     lease.h
> Then re-run aclocal, automake and make.

Sorry for the inconvenience, we have a ticket already open for the 1.2
milestone to correct this.

> 3. Is using "lease.decline(0)" the best (only) way, at least in this
> hook point, to turn away unknown clients? That's what I've done and it
> works, though the lease is still processed and sent to the client, but
> with what I think is a lease for zero seconds.
> Trimmed log, showing what I think is the 0-second lease (type 51):
> ... DEBUG [kea-dhcp4.packets] DHCP4_RESPONSE_DATA ... responding with
> packet DHCPOFFER (type 2), packet details: ...
> remote_adress=, msg_type=DHCPOFFER (2) ...
> options:
>   type=001...
>   type=051, len=004: 0 (uint32)
>   type=053, len=001: 2 (uint8)
>   ...
> [BTW, note you have a typo somewhere in your code "remote_adress"]
> Is it possible for a client to ignore the lease time and use the
> address it received anyway? Does having done "lease.decline(0)" force
> Kea to update anything it needed to invalidate the lease?
> I see in the logs that the client came back immediately using the
> assigned address - perhaps asking for a renew of what it thinks was
> only an expired lease? If so, that may not be ideal. Indeed, Kea's
> next response looks to be a renewal(?) (though here, too, the lease
> time (type 51) is sent back as zero seconds). Could this create a
> feedback loop that would burden the server?
> I do see that it looks to have been cleaned up, though after the
> client's first couple tries:
> [kea-dhcp4.alloc-engine] ALLOC_ENGINE_V4_DECLINED_RECOVERED IPv4
> address was recovered after 0 seconds of probation-period
> Some time after that, the client sent a DHCPDECLINE (type 4) message,
> but Kea seems to already have cleaned it up, and I see a warning logged:
> WARN  [kea-dhcp4.dhcp4] DHCP4_DECLINE_LEASE_NOT_FOUND Received
> DHCPDECLINE for addr from client ... but no such lease
> found.
Declining a lease is intended to be a client initiated action, so I
don't really think this is direction to go.  If you set the
lease4_select next step action to SKIP before returning from your
lease4_select hook:

"*Next step status*: If any callout installed on the "lease4_select"
hook sets the next step action to SKIP, the server will not assign any
lease and the callouts become responsible for the lease assignment. If
the callouts fail to provide a lease, the packet processing will
continue, but client will not get an address."

If your callout does not then assign a lease using its own decision
making,  the server will generate a NAK to your client.

> If this is not best, is there a way to change the assigned subnet
> (invalid one or sandboxed one) at this late hook point?
> Also, is there a way to change the assigned pool?
If you want to alter the subnet that was selected you'll have to
intervene in the subnet4_select hook point.   

>>  All classes matched to the client, including those via host
>> reservations, are accessible via query4->getClasses() (inherited from
>> isc::dhcp::Pkt).
>> If you want to do something earlier in the process, it would have be
>> in the subnet4_select hook point, but bear in mind two things:
>> 1. The host matching as not yet been done, so query4->getClasses()
>> would not contain any classes contributed by a reservation.  You can,
>> however, look for a host reservation yourself via the HostMgr
>> singleton, which can be accessed
>> with this static method:
>>     HostMgr::instance()
>> and the reservation can be searched for with either of these:
>>     virtual ConstHostPtr
>>     get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
>>          const DuidPtr& duid = DuidPtr()) const;
>>     virtual ConstHostPtr
>>     get4(const SubnetID& subnet_id, const Host::IdentifierType&
>> identifier_type,
>>          const uint8_t* identifier_begin, const size_t identifier_len)
>> const;
>>     (I would recommend the latter, as the former may eventually be
>> deprecated)
>> 2. Host reservations are tied to a subnet via subnet ID.  Kea does not
>> support subnet-less host reservations.  Suppose  you define a host
>> reservation to subnet id 1, and you override the subnet selection with
>> a different subnet, say subnet 23.  When
>> Kea attempts to match hosts to this client, it will use subnet id 23
>> and fail to find any, unless you add a second reservation for the host
>> with subnet id 23.    On the other hand, if you only want to use the
>> host reservation to attribute hosts to classes,  this may not matter
>> to you, as you're doing the look explicitly in your hook.
>> Thomas Markwalder
>> ISC Software Engineering
>> Links:
>> ------
>> [1]
>> https://jenkins.isc.org/job/Kea_doc/doxygen/d5/d8c/namespaceisc_1_1dhcp.html#a3f332dc70d05fbe8e0fb453434c22d93
>> [2]
>> https://jenkins.isc.org/job/Kea_doc/doxygen/d5/d8c/namespaceisc_1_1dhcp.html#a17ccc4cfb9f7534dfcedc83ebe0e5d5a
>> [3]
>> https://jenkins.isc.org/job/Kea_doc/doxygen/d5/d8c/namespaceisc_1_1dhcp.html#aec4424838e2e5bb397345cdc32c0ef28
> _______________________________________________
> Kea-users mailing list
> Kea-users at lists.isc.org
> https://lists.isc.org/mailman/listinfo/kea-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.isc.org/pipermail/kea-users/attachments/20161114/0583d7c5/attachment-0001.html>

More information about the Kea-users mailing list