From: Thomas Markwalder Date: Tue, 13 Oct 2015 10:49:32 +0000 (-0400) Subject: [master] Added authoring-btye-order parameter to lease file handling X-Git-Tag: v4_1_esv_r13b1~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=01a4ad11b43d649297a62e374562e8cd7d08f70b;p=thirdparty%2Fdhcp.git [master] Added authoring-btye-order parameter to lease file handling Merged in rt38396. --- diff --git a/RELNOTES b/RELNOTES index 43740f09e..ce7d4a18e 100644 --- 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" diff --git a/common/conflex.c b/common/conflex.c index 0a7ce420b..67c4fc917 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -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)) { diff --git a/includes/dhcpd.h b/includes/dhcpd.h index ae548e51c..f654cc40b 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -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 *, diff --git a/includes/dhctoken.h b/includes/dhctoken.h index 652c362c1..02242f755 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -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 && \ diff --git a/server/confpars.c b/server/confpars.c index d587450fe..128cf6a26 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -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 */ diff --git a/server/db.c b/server/db.c index 1de4867c3..eefc599aa 100644 --- a/server/db.c +++ b/server/db.c @@ -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. */ diff --git a/server/dhcpd.c b/server/dhcpd.c index 8b161c211..51f4ae52c 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -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; diff --git a/server/dhcpd.leases.5 b/server/dhcpd.leases.5 index 4ca77fe98..60b3bcb6c 100644 --- a/server/dhcpd.leases.5 +++ b/server/dhcpd.leases.5 @@ -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 } diff --git a/server/tests/simple_unittest.c b/server/tests/simple_unittest.c index e6d04b900..5e1db9197 100644 --- a/server/tests/simple_unittest.c +++ b/server/tests/simple_unittest.c @@ -15,6 +15,7 @@ */ #include +#include #include /* 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()); }