]> 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:34:15 +0000 (06:34 -0400)
committerThomas Markwalder <tmark@isc.org>
Tue, 13 Oct 2015 10:34:15 +0000 (06:34 -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 db930e0a488c7e501b1ca2a2cfaf481face019ff..b87f3307180ffcd658be61f4eaac00636dcd9d2e 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -54,6 +54,13 @@ by Eric Young (eay@cryptsoft.com).
 
                        Changes since 4.3.3
 
+- 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 f23a8c783dc637a2dbe5bfce12501134a1611f46..a1ba95fda90ce0602fd88522bb87fdda3dbbae6d 100644 (file)
@@ -783,6 +783,8 @@ intern(char *atom, enum dhcp_token dfv) {
                                return ATSFP;
                        break;
                }
+               if (!strcasecmp(atom + 1, "uthoring-byte-order"))
+                       return AUTHORING_BYTE_ORDER;
                if (!strncasecmp(atom + 1, "ut", 2)) {
                        if (isascii(atom[3]) &&
                            (tolower((unsigned char)atom[3]) == 'h')) {
@@ -827,6 +829,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"))
@@ -1128,6 +1133,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 1fd12dbb4bb09a2ec6309a29e4d671e3a144d8b5..89f0e55f8d9d2963ce2689591ba0cf0fdb651940 100644 (file)
@@ -2037,6 +2037,7 @@ extern int dont_use_fsync;
 extern int server_id_check;
 
 extern int prefix_length_mode;
+extern int authoring_byte_order;
 
 extern const char *path_dhcpd_conf;
 extern const char *path_dhcpd_db;
@@ -2134,6 +2135,7 @@ void parse_ia_pd_declaration(struct parse *);
 void parse_server_duid(struct parse *cfile);
 void parse_server_duid_conf(struct parse *cfile);
 void parse_pool6_statement (struct parse *, struct group *, int);
+uint32_t parse_byte_order_uint32(const void *source);
 
 /* ddns.c */
 int ddns_updates(struct packet *, struct lease *, struct lease *,
index c4b77a7c3a70a2bab073a9c9e158ff85796ea5fd..c1db9da39f5df8c8abf4bfd2a87df85cd9cb8be9 100644 (file)
@@ -368,7 +368,10 @@ enum dhcp_token {
        POOL6 = 669,
        V6RELAY = 670,
        V6RELOPT = 671,
-       PARSE_VENDOR_OPT = 672
+       PARSE_VENDOR_OPT = 672,
+       AUTHORING_BYTE_ORDER = 673,
+       TOKEN_LITTLE_ENDIAN = 674,
+       TOKEN_BIG_ENDIAN = 675
 };
 
 #define is_identifier(x)       ((x) >= FIRST_TOKEN &&  \
index 42a1712d9f3a0a92b8b07378898328b3ae1bb4ea..6358fe2db68f148a51d4920aa81352f0550fbb3b 100644 (file)
@@ -35,6 +35,8 @@ static unsigned char global_host_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;
@@ -302,6 +304,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);
@@ -1391,6 +1395,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 :==
+ *             PARSE_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;
+        }
+}
+
+/*!
  * 
  * \brief Parse allow and deny statements
  *
@@ -4634,7 +4702,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.");
@@ -5086,7 +5155,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.");
@@ -5539,7 +5609,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.");
@@ -6233,5 +6304,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 5238ed86c7522646d438c933dd44fd1b073a32b0..103be8aab385c501bf96ba6bde30ce95dec4a412 100644 (file)
@@ -1051,6 +1051,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);
@@ -1155,6 +1159,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;
 
@@ -1163,6 +1168,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 ab73443a7a2c537dddc6abe8494f1dbb5ef29816..792684d1531225ad6d27dc98de1a06935961184f 100644 (file)
@@ -80,6 +80,8 @@ int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */
 int server_id_check = 0; /* 0 = default, don't check server id, 1 = do check */
 int prefix_length_mode = PLM_EXACT;
 
+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 f490a634fd9220f7bf29c14b0344e767f71bfd73..025b9bf8da1e526ad3a2df447469294ac8b8a8d5 100644 (file)
@@ -181,6 +181,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());
 }