]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Added authoring-btye-order parameter to lease file handling
authorThomas Markwalder <tmark@isc.org>
Tue, 13 Oct 2015 10:49:32 +0000 (06:49 -0400)
committerThomas Markwalder <tmark@isc.org>
Tue, 13 Oct 2015 10:49:32 +0000 (06:49 -0400)
    Merged in rt38396.

RELNOTES
common/conflex.c
includes/dhcpd.h
includes/dhctoken.h
server/confpars.c
server/db.c
server/dhcpd.c
server/dhcpd.leases.5
server/tests/simple_unittest.c

index 43740f09e9554d841a144c09ecbfd583e43191ea..ce7d4a18ea5c8b4157a921da108373df042ca992 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -60,6 +60,13 @@ by Eric Young (eay@cryptsoft.com).
 
                        Changes since 4.1-ESV-R12
 
+- Added a parameter, authoring-byte-order, to the lease file. This value
+  is automatically added to the top of new lease files by the server and
+  indicates the internal byte order (big endian or little endian) of the
+  server.  This permits lease files generated on a server with one form of
+  byte order to be used on a server with the opposite form.
+  [ISC-Bugs #38396]
+
 - Added dhcpv6 and delayed-ack to settings listed in the "Features:"
   section of the configure script output.  Additionally, all of the
   features reported on will now always show either a "yes" or "no"
index 0a7ce420bacf87ad2aa2501c87a6972d606c41d4..67c4fc917c62fa5c01a68c3b7a71ce9ec98d6c51 100644 (file)
@@ -3,7 +3,7 @@
    Lexical scanner for dhcpd config file... */
 
 /*
- * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2015 by Internet Systems Consortium, Inc. ("ISC")
  * Copyright (c) 1995-2003 by Internet Software Consortium
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -719,6 +719,8 @@ intern(char *atom, enum dhcp_token dfv) {
                        }
                        if (!strcasecmp (atom + 1, "uthoritative"))
                                return AUTHORITATIVE;
+                       if (!strcasecmp(atom + 1, "uthoring-byte-order"))
+                               return AUTHORING_BYTE_ORDER;
                        break;
                }
                if (!strcasecmp (atom + 1, "nd"))
@@ -777,6 +779,9 @@ intern(char *atom, enum dhcp_token dfv) {
                        return BALANCE;
                if (!strcasecmp (atom + 1, "ound"))
                        return BOUND;
+               if (!strcasecmp(atom+1, "ig-endian")) {
+                       return TOKEN_BIG_ENDIAN;
+               }
                break;
              case 'c':
                if (!strcasecmp(atom + 1, "ase"))
@@ -1077,6 +1082,9 @@ intern(char *atom, enum dhcp_token dfv) {
                if (!strcasecmp(atom+1, "l")) {
                        return LL;
                }
+               if (!strcasecmp(atom+1, "ittle-endian")) {
+                       return TOKEN_LITTLE_ENDIAN;
+               }
                break;
              case 'm':
                if (!strncasecmp (atom + 1, "ax", 2)) {
index ae548e51ce4a8fa3b0cce97ecbdfc1d060a52e14..f654cc40b18f3bcb93a38980241d4b2c912747a0 100644 (file)
@@ -1681,6 +1681,7 @@ extern struct timeval cur_tv;
 #define cur_time cur_tv.tv_sec
 
 extern int ddns_update_style;
+extern int authoring_byte_order;
 
 extern const char *path_dhcpd_conf;
 extern const char *path_dhcpd_db;
@@ -1775,6 +1776,7 @@ void parse_ia_ta_declaration(struct parse *);
 void parse_ia_pd_declaration(struct parse *);
 void parse_server_duid(struct parse *cfile);
 void parse_server_duid_conf(struct parse *cfile);
+uint32_t parse_byte_order_uint32(const void *source);
 
 /* ddns.c */
 int ddns_updates(struct packet *, struct lease *, struct lease *,
index 652c362c1214f8e8963777105fe385a5a976013d..02242f7551dfa34d43c891329599f9eeb3e0e307 100644 (file)
@@ -353,7 +353,10 @@ enum dhcp_token {
        CONFLICT_DONE = 660,
        INITIAL_DELAY = 664,
        GETHOSTBYNAME = 665,
-       TOKEN_INFINIBAND = 668
+       TOKEN_INFINIBAND = 668,
+       AUTHORING_BYTE_ORDER = 669,
+       TOKEN_LITTLE_ENDIAN = 670,
+       TOKEN_BIG_ENDIAN = 671
 };
 
 #define is_identifier(x)       ((x) >= FIRST_TOKEN &&  \
index d587450fe3f8dbbbcc5ab5eeb04a0d48099fa75e..128cf6a260be86f502dbc9b374b24075ad713909 100644 (file)
@@ -34,6 +34,8 @@ static unsigned char dhcpv6_class_once = 1;
 static int parse_binding_value(struct parse *cfile,
                                struct binding_value *value);
 
+static void parse_authoring_byte_order (struct parse *cfile);
+
 #if defined (TRACING)
 trace_type_t *trace_readconf_type;
 trace_type_t *trace_readleases_type;
@@ -291,6 +293,8 @@ isc_result_t lease_file_subparse (struct parse *cfile)
                } else if (token == SERVER_DUID) {
                        parse_server_duid(cfile);
 #endif /* DHCPv6 */
+               } else if (token == AUTHORING_BYTE_ORDER) {
+                       parse_authoring_byte_order(cfile);
                } else {
                        log_error ("Corrupt lease file - possible data loss!");
                        skip_to_semi (cfile);
@@ -1394,6 +1398,70 @@ void parse_failover_state (cfile, state, stos)
 }
 #endif /* defined (FAILOVER_PROTOCOL) */
 
+/*!
+ * \brief Parses an authoring-byte-order statement
+ *
+ * A valid statement looks like this:
+ *
+ *     authoring-byte-order :==
+ *             AUTHORING_BYTE_ORDER TOKEN_LITTLE_ENDIAN | TOKEN_BIG_ENDIAN ;
+ *
+ * If the global, authoring_byte_order is not zero, then either the statement
+ * has already been parsed or the function, parse_byte_order_uint32, has
+ * been called which set it to the default.  In either case, this is invalid
+ * so we'll log it and bail.
+ *
+ * If the value is different from the current server's byte order, then we'll
+ * log that fact and set authoring_byte_order to given value. This causes all
+ * invocations of the function, parse_byte_order_uint32, to perform byte-order
+ * conversion before returning the value.
+ *
+ * \param cfile the current parse file
+ *
+*/
+void parse_authoring_byte_order (struct parse *cfile)
+{
+       enum dhcp_token token;
+       const char *val;
+       unsigned int len;
+
+       /* Either we've seen it already or it's after the first lease */
+       if (authoring_byte_order != 0) {
+               parse_warn (cfile,
+                           "authoring-byte-order specified too late.\n"
+                           "It must occur before the first lease in file\n");
+               skip_to_semi (cfile);
+               return;
+       }
+
+       token = next_token(&val, (unsigned *)0, cfile);
+       switch(token) {
+       case TOKEN_LITTLE_ENDIAN:
+               authoring_byte_order =  LITTLE_ENDIAN;
+               break;
+       case TOKEN_BIG_ENDIAN:
+               authoring_byte_order =  BIG_ENDIAN;
+               break;
+       default:
+               parse_warn(cfile, "authoring-byte-order is invalid: "
+                                   " it must be big-endian or little-endian.");
+               skip_to_semi(cfile);
+               return;
+       }
+
+       if (authoring_byte_order != DHCP_BYTE_ORDER)  {
+               log_error ("WARNING: Lease file authored using different"
+                           " byte order, will attempt to convert");
+       }
+
+        token = next_token(&val, &len, cfile);
+        if (token != SEMI) {
+                parse_warn(cfile, "corrupt lease file; expecting a semicolon");
+                skip_to_semi(cfile);
+                return;
+        }
+}
+
 /* Permit_list_match returns 1 if every element of the permit list in lhs
    also appears in rhs.   Note that this doesn't by itself mean that the
    two lists are equal - to check for equality, permit_list_match has to
@@ -4210,7 +4278,8 @@ parse_ia_na_declaration(struct parse *cfile) {
                return;
        }
 
-       memcpy(&iaid, val, 4);
+       iaid = parse_byte_order_uint32(val);
+
        ia = NULL;
        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
                log_fatal("Out of memory.");
@@ -4601,7 +4670,8 @@ parse_ia_ta_declaration(struct parse *cfile) {
                return;
        }
 
-       memcpy(&iaid, val, 4);
+       iaid = parse_byte_order_uint32(val);
+
        ia = NULL;
        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
                log_fatal("Out of memory.");
@@ -4993,7 +5063,8 @@ parse_ia_pd_declaration(struct parse *cfile) {
                return;
        }
 
-       memcpy(&iaid, val, 4);
+       iaid = parse_byte_order_uint32(val);
+
        ia = NULL;
        if (ia_allocate(&ia, iaid, val+4, len-4, MDL) != ISC_R_SUCCESS) {
                log_fatal("Out of memory.");
@@ -5628,5 +5699,42 @@ parse_server_duid_conf(struct parse *cfile) {
        }
 }
 
+/*!
+ * \brief Creates a byte-order corrected uint32 from a buffer
+ *
+ * This function creates an integer value from a buffer, converting from
+ * the byte order specified by authoring-byte-order to the current server's
+ * byte order if they are different. The conversion works in either direction.
+ *
+ * If the parameter, authoring-byte-order hasn't yet been encountered we will
+ * emit a warning and then default the byte order to match the current server's
+ * byte order (i.e. no conversion will done).
+ *
+ * \param source buffer containing the "raw" four byte data
+ * \return uint32_t containing the corrected value
+*/
+uint32_t parse_byte_order_uint32(const void *source) {
+       uint32_t value;
+
+       /* use memcpy to avoid any alignment monkey business */
+       memcpy(&value, source, 4);
+
+       if (authoring_byte_order == 0) {
+               log_error ("WARNING: "
+                            "authoring-byte-order not in the lease file.\n"
+                            "Assuming file byte order matches this server.\n");
+               authoring_byte_order = DHCP_BYTE_ORDER;
+       }
+
+       if (authoring_byte_order != DHCP_BYTE_ORDER) {
+               value = (((value >> 24) & 0xff) | // move byte 3 to byte 0
+                    ((value << 8) & 0xff0000) | // move byte 1 to byte 2
+                    ((value >> 8) & 0xff00) | // move byte 2 to byte 1
+                    ((value << 24) & 0xff000000)); // byte 0 to byte 3
+       }
+
+       return (value);
+}
+
 #endif /* DHCPv6 */
 
index 1de4867c3811c717a366a89dc8e43756b3064a4a..eefc599aac9355bf7f372e6b7f470cf17cd20740 100644 (file)
@@ -1012,6 +1012,10 @@ void db_startup (testp)
 #if defined (TRACING)
        if (!trace_playback ()) {
 #endif
+               /* Unset authoring_byte_order so we'll know if it was specified
+                  in the lease file or not. */
+               authoring_byte_order = 0;
+
                /* Read in the existing lease file... */
                status = read_conf_file (path_dhcpd_db,
                                         (struct group *)0, 0, 1);
@@ -1116,6 +1120,7 @@ int new_lease_file ()
        errno = 0;
        fprintf (db_file, "# The format of this file is documented in the %s",
                 "dhcpd.leases(5) manual page.\n");
+
        if (errno)
                goto fail;
 
@@ -1124,6 +1129,18 @@ int new_lease_file ()
        if (errno)
                goto fail;
 
+       fprintf (db_file, "# authoring-byte-order entry is generated,"
+                          " DO NOT DELETE\n");
+       if (errno)
+               goto fail;
+
+       fprintf (db_file, "authoring-byte-order %s;\n\n",
+                (DHCP_BYTE_ORDER == LITTLE_ENDIAN ?
+                 "little-endian" : "big-endian"));
+       if (errno)
+               goto fail;
+
+
        /* At this point we have a new lease file that, so far, could not
         * be described as either corrupt nor valid.
         */
index 8b161c21196a3517ed31a54ebfbff9329906487a..51f4ae52c2ce4aa4598150a2ffd4edf48e5be5e3 100644 (file)
@@ -157,6 +157,8 @@ on commit {                                                             \n\
 int ddns_update_style;
 #endif /* NSUPDATE */
 
+int authoring_byte_order = 0; /* 0 = not set */
+
 const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
 const char *path_dhcpd_db = _PATH_DHCPD_DB;
 const char *path_dhcpd_pid = _PATH_DHCPD_PID;
index 4ca77fe9899b46a6972aefb00d51e89844f942fd..60b3bcb6caf48ff8c74f2ee5cd2b493a72750248 100644 (file)
@@ -180,6 +180,23 @@ certain event occurs.   The possible events that can occur for an
 active lease are \fBrelease\fR and \fBexpiry\fR.   More than one event
 can be specified - if so, the events are separated by '|' characters.
 .PP
+The \fIauthoring-byte-order\fR statement
+.RS 0.25i
+.PP
+.B authoring-byte-order \fR[ \fIbig-endian\fR | \fIlittle-endian\fR ] \fB;\fR
+.PP
+This statement is automatically added to the top of new lease files by
+the server. It indicates the internal byte order of the server.  This
+permits lease files generated on a server with one form of byte order
+to be read by a server with a different form.  Lease files which do not
+contain this entry are simply treated as having the same byte order as
+the server reading them.  If you are migrating lease files generated
+by a server that predates this statement and is of a different byte
+order than the your destination server, you can manually add this
+statement.  It must proceed any lease entries.  Valid values for this
+parameter are \fIlittle-endian\fR and \fIbig-endian\fR.
+.RE
+.PP
 .SH THE DHCPv4 LEASE DECLARATION
 .PP
 .B lease \fIip-address\fB { \fIstatements...\fB }
index e6d04b9003e718a99f87b1c45a30fccee07c9a69..5e1db91972f1a6773f6db836c2e2111ec95ec02d 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <config.h>
+#include <dhcpd.h>
 #include <atf-c.h>
 
 /* That is an example ATF test case, tailored to ISC DHCP sources.
@@ -66,12 +67,58 @@ ATF_TC_BODY(simple_test_case, tc)
 
 }
 
+
+ATF_TC(parse_byte_order);
+
+ATF_TC_HEAD(parse_byte_order, tc)
+{
+    atf_tc_set_md_var(tc, "descr", "Tests byte-order conversion.");
+}
+
+ATF_TC_BODY(parse_byte_order, tc)
+{
+    uint32_t ret_value = 0;
+    uint32_t source_value = 0xaabbccdd;
+
+    /* With order set to 0, function should default to no conversion */
+    authoring_byte_order = 0;
+    ret_value = parse_byte_order_uint32(&source_value);
+    if (ret_value != source_value) {
+        atf_tc_fail("default/non-conversion failed!");
+    }
+
+    /* With matching byte order, function should not do the conversion */
+    authoring_byte_order = DHCP_BYTE_ORDER;
+    ret_value = parse_byte_order_uint32(&source_value);
+    if (ret_value != source_value) {
+        atf_tc_fail("matching/non-conversion failed!");
+    }
+
+    /* With opposite byte order, function should do the conversion */
+    authoring_byte_order = (DHCP_BYTE_ORDER == LITTLE_ENDIAN ?
+                            BIG_ENDIAN : LITTLE_ENDIAN);
+    ret_value = parse_byte_order_uint32(&source_value);
+    if (ret_value != 0xddccbbaa) {
+        atf_tc_fail("conversion failed!");
+    }
+
+    /* Converting the converted value should give us the original value */
+    ret_value = parse_byte_order_uint32(&ret_value);
+    if (ret_value != source_value) {
+        atf_tc_fail("round trip conversion failed!");
+    }
+
+    atf_tc_pass();
+}
+
+
 /* This macro defines main() method that will call specified
    test cases. tp and simple_test_case names can be whatever you want
    as long as it is a valid variable identifier. */
 ATF_TP_ADD_TCS(tp)
 {
     ATF_TP_ADD_TC(tp, simple_test_case);
+    ATF_TP_ADD_TC(tp, parse_byte_order);
 
     return (atf_no_error());
 }