[RFC ] include with wildcard filenames

Ulf Samuelsson dhcp at emagii.com
Tue Feb 27 22:33:10 UTC 2018


I was trying out a dhcpd configuration, and found to my dismay
that the DHCP server did not support wildcards for include statements.
include "/etc/dhcp/pools/*.conf";
did not work.

BACKGROUND:

I have an application, where I want to use the DHCP server
as part of the authentication process for connected machines.

I want to use three ranges.
pool 0 => 169.254.128.x            trusted units
pool 1 => 169.254.254.x            units demanding to be trusted
pool 2 => 169.254.1.x              normal units
pool 3 => 169.254.253.x            untrusted units/intruders

The DHCP CPU Ethernet Controller communicates through a five port switch.
port 0: trusted units    pool 0
port 2: internet port
port 3: service port
port 4: CPU port    169.254.1.1

Units connected on port 0, provides a dhcp-client-identifier indicating 
that they want an address in pool 0, but initially they will get a short 
term lease in pool 1, until it is verified that they are on port 0.

Units without this dhcp-client-identifier, should get an address in pool 2.

An intruder, trying to get a pool 0 address, will supply the same 
dhcp-client-identifier as port 0 units. They will also initially get a 
short term pool 1 address, but when the intrusion attempt is detected, 
they should be declared "untrusted". Future leases should be in pool 3.

=====
When a pool 1 address is allocated, the commit event is used to run a 
script which will read out information from the switch and determine if 
the request comes from port 0.

Request comes from (port == 0) => the mac address should be "trusted"
Request comes from (port != 0) => the mac address should be "untrusted".

I define:
class "trusted" {
     match hardware;
}

class "untrusted" {
     match hardware;
}

An incoming request from "00:11:22:33:44:55" adds a file:
/etc/dhcp/trusted/00:11:22:33:44:55:
       sub-class "trusted" 1:00:11:22:33:44:55;
or
/etc/dhcp/untrusted/00:11:22:33:44:55:
       sub-class "trusted" 1:00:11:22:33:44:55;


When the short term pool 1 lease expires (after 1-2 minutes)
the new lease will be classified either as "trusted" (getting a pool 0 
lease) or "untrusted" (getting a pool 3 lease).

It would be practical to have the dhcpd.conf file contain:

include "/etc/dhcp/trusted/*";
include "/etc/dhcp/untrusted/*";

but unfortunately wildcards in include statements are not supported.

====================================

I did a patch for dhcp-4.3.6 which is slightly limited.
It supports only wildcards on files within a single directory.
I.E: include "/etc/dhcp/pools/*.conf"; is supported
I.E: include "/etc/dhcp/*/dhcp.conf"; is not supported
The wildcard may not be in a directory.

Did a small test program which tested the functionality of wildcards,
and then patched the dhcp server, but it has not been tested yet, as 
part of dhcp
Still would like to have peoples opinion, whether this type of 
functionality is desirable.
It is certainly possible to do this without wildcards,
but wildcards seems a much cleaner solution.
====================================

 From dcc981f1371f390befffc950b9dc3a8107059643 Mon Sep 17 00:00:00 2001
From: Ulf Samuelsson <ulf at emagii.com>
Date: Tue, 27 Feb 2018 21:03:52 +0100
Subject: [PATCH 14/14] Support wildcard in include files

Signed-off-by: Ulf Samuelsson <ulf at emagii.com>
---
  includes/dhcpd.h  |  3 +++
  server/confpars.c | 71 
+++++++++++++++++++++++++++++++++++++++++++++++++++++--
  2 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index eab09a6..8208fbe 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -53,6 +53,9 @@
  #include <sys/mman.h>
  #include <ctype.h>
  #include <time.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <fnmatch.h>

  #include <net/if.h>
  #undef FDDI
diff --git a/server/confpars.c b/server/confpars.c
index c0735fe..c12f5c7 100644
--- a/server/confpars.c
+++ b/server/confpars.c
@@ -327,7 +327,7 @@ isc_result_t lease_file_subparse (struct parse *cfile)
     parameter :== DEFAULT_LEASE_TIME lease_time
             | MAX_LEASE_TIME lease_time
             | DYNAMIC_BOOTP_LEASE_CUTOFF date
-           | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
+           | DYNAMIC_BOOTP_LEASE_LENGTH l#include <string.h>ease_time
             | BOOT_UNKNOWN_CLIENTS boolean
             | ONE_LEASE_PER_CLIENT boolean
             | GET_LEASE_HOSTNAMES boolean
@@ -352,6 +352,73 @@ isc_result_t lease_file_subparse (struct parse *cfile)
           | VENDOR_CLASS class-declaration
           | USER_CLASS class-declaration
           | RANGE address-range-declaration */
+#include <string.h>
+isc_result_t read_multiple_conf_files(path, group, type)
+    const char *path;
+    struct group *group;
+    int type;
+{
+    char    *buf_dir;
+    char    *dir;
+    char    *buf_base;
+    char    *base;
+    DIR    *d;
+    struct    dirent *entry;
+    int reti;
+    isc_result_t status;
+
+    dir    = dirname (buf_dir    = strdup(path));
+    base    = basename(buf_base    = strdup(path));
+
+    if (!(d = opendir(dir))) {
+        status = DHCP_R_INVALIDARG;
+        goto    exit;
+    }
+
+    while ((entry = readdir(d)) != NULL) {
+        if (entry->d_type == DT_DIR) {
+            continue;
+        } else {
+            reti = fnmatch(base, entry->d_name, 0);
+            if (reti == 0) {
+                status = read_conf_file (path, group, type, 0);
+                if (status != ISC_R_SUCCESS) {
+                    goto exit;
+                }
+            } else {
+                continue;
+            }
+        }
+    }
+    closedir(d);
+exit:
+    free(buf_dir);
+    free(buf_base);
+    return status;
+}
+
+isc_result_t include_files(path, group, type)
+    const char *path;
+    struct group *group;
+    int type;
+{
+    const char    *eos;
+    const char    *wildcard = strchr(path, '*');
+    char    *p;
+
+    if (wildcard == NULL) {
+        return read_conf_file (path, group, type, 0);
+    }
+
+    eos = &path[strlen(path)];
+    for (wildcard++; wildcard < eos; wildcard++) {
+        if (*wildcard == '/') {
+            /* wildcard in directory, not allowed */
+            return DHCP_R_INVALIDARG;
+        }
+    }
+    return read_multiple_conf_files(path, group, type);
+}

  int parse_statement (cfile, group, type, host_decl, declaration)
      struct parse *cfile;
@@ -383,7 +450,7 @@ int parse_statement (cfile, group, type, host_decl, 
declaration)
              parse_warn (cfile, "filename string expected.");
              skip_to_semi (cfile);
          } else {
-            status = read_conf_file (val, group, type, 0);
+            status = include_files(val, group, type);
              if (status != ISC_R_SUCCESS)
                  parse_warn (cfile, "%s: bad parse.", val);
              parse_semi (cfile);
-- 
1.9.1

Best Regards
Ulf Samuelsson


More information about the dhcp-users mailing list