From: Thomas Markwalder Date: Fri, 4 Mar 2016 19:16:29 +0000 (-0500) Subject: [master] Added lease-id-format to server and client X-Git-Tag: v4_3_4b1~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cc1bd34e09bad3313a16d89f7ad491ff16754dc7;p=thirdparty%2Fdhcp.git [master] Added lease-id-format to server and client Merges in rt26378 --- diff --git a/RELNOTES b/RELNOTES index 445deba9e..84fcc49d8 100644 --- a/RELNOTES +++ b/RELNOTES @@ -236,7 +236,7 @@ by Eric Young (eay@cryptsoft.com). Please look at doc/DHCPv4-over-DHCPv6 for more details. [ISC-Bugs #35711] -- Corrected interface name formation when using DLPI under Solaris 11. As of +- Correct interface name formation when using DLPI under Solaris 11. As of Solaris 11, ethernet device files are located in "/dev/net". The configure script has been modified to detect this situation and adjust the directory used accordingly. Thanks to Jarkko Torppa for reporting this issue and @@ -248,6 +248,12 @@ by Eric Young (eay@cryptsoft.com). decoding a packet. [ISC-Bugs #41774] +- Add a new parameter, lease-id-format, to both dhcpd and dhclient. The + parameter controls the format in which certain values are written to lease + files. Formats supported are octal - quoted string containing octal + escapes, and hex - unquoted, colon separated hex digits. + [ISC-Busg #26378] + Changes since 4.3.3b1 - None diff --git a/client/clparse.c b/client/clparse.c index 643b3faed..03190c33a 100644 --- a/client/clparse.c +++ b/client/clparse.c @@ -3,7 +3,7 @@ Parser for dhclient config and lease files... */ /* - * Copyright (c) 2004-2014,2016 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any @@ -45,6 +45,8 @@ static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile); static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile); #endif /* DHCPv6 */ +static void parse_lease_id_format (struct parse *cfile); + /* client-conf-file :== client-declarations END_OF_FILE client-declarations :== | client-declaration @@ -168,6 +170,7 @@ isc_result_t read_client_conf () top_level_config.retry_interval = 300; top_level_config.backoff_cutoff = 15; top_level_config.initial_interval = 3; + top_level_config.lease_id_format = TOKEN_OCTAL; /* * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a @@ -809,6 +812,12 @@ void parse_client_statement (cfile, ip, config) parse_reject_statement (cfile, config); return; + case LEASE_ID_FORMAT: + skip_token(&val, (unsigned *)0, cfile); + parse_lease_id_format(cfile); + break; + + default: lose = 0; stmt = (struct executable_statement *)0; @@ -1324,25 +1333,17 @@ static void parse_client_default_duid(struct parse *cfile) { struct data_string new_duid; - const char *val = NULL; + u_int8_t buf[128]; unsigned len; - int token; - - memset(&new_duid, 0, sizeof(new_duid)); - - token = next_token(&val, &len, cfile); - if (token != STRING) { - parse_warn(cfile, "Expected DUID string."); - skip_to_semi(cfile); - return; - } + len = parse_X(cfile, buf, sizeof(buf)); if (len <= 2) { parse_warn(cfile, "Invalid DUID contents."); skip_to_semi(cfile); return; } + memset(&new_duid, 0, sizeof(new_duid)); if (!buffer_allocate(&new_duid.buffer, len, MDL)) { parse_warn(cfile, "Out of memory parsing default DUID."); skip_to_semi(cfile); @@ -1351,7 +1352,7 @@ parse_client_default_duid(struct parse *cfile) new_duid.data = new_duid.buffer->data; new_duid.len = len; - memcpy(new_duid.buffer->data, val, len); + memcpy(new_duid.buffer->data, buf, len); /* Rotate the last entry into place. */ if (default_duid.buffer != NULL) @@ -2310,3 +2311,45 @@ int parse_allow_deny (oc, cfile, flag) skip_to_semi (cfile); return 0; } + + + +/*! + * \brief Parses an lease-id-format statement + * + * A valid statement looks like this: + * + * lease-id-format :== + * LEASE_ID_FORMAT TOKEN_OCTAL | TOKEN_HEX ; + * + * This function is used to parse the lease-id-format statement. It sets + * top_level_config.lease_id_format. + * + * \param cfile the current parse file + * +*/ +void parse_lease_id_format (struct parse *cfile) +{ + enum dhcp_token token; + const char *val; + + token = next_token(&val, NULL, cfile); + switch(token) { + case TOKEN_OCTAL: + top_level_config.lease_id_format = TOKEN_OCTAL; + break; + case TOKEN_HEX: + top_level_config.lease_id_format = TOKEN_HEX; + break; + default: + parse_warn(cfile, "lease-id-format is invalid: " + " it must be octal or hex."); + skip_to_semi(cfile); + return; + } + + log_debug("lease_id_format is: %s", + (top_level_config.lease_id_format == TOKEN_OCTAL + ? "octal" : "hex")); + +} diff --git a/client/dhclient.c b/client/dhclient.c index d1d83a013..98e691b51 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -3489,10 +3489,12 @@ form_duid(struct data_string *duid, const char *file, int line) ip->hw_address.hlen - 1); } - str = quotify_buf(duid->data, duid->len, MDL); - if (str == NULL) - log_info("Created duid."); - else { + /* Now format the output based on lease-id-format */ + str = format_lease_id(duid->data, duid->len, + top_level_config.lease_id_format, MDL); + if (str == NULL) { + log_info("form_duid: Couldn't allocate memory to log duid!"); + } else { log_info("Created duid %s.", str); dfree(str, MDL); } @@ -3516,16 +3518,13 @@ write_duid(struct data_string *duid) } } - /* It would make more sense to write this as a hex string, - * but our function to do that (print_hex_n) uses a fixed - * length buffer...and we can't guarantee a duid would be - * less than the fixed length. - */ - str = quotify_buf(duid->data, duid->len, MDL); + /* Generate a formatted duid string per lease-id-format */ + str = format_lease_id(duid->data, duid->len, + top_level_config.lease_id_format, MDL); if (str == NULL) return ISC_R_NOMEMORY; - stat = fprintf(leaseFile, "default-duid \"%s\";\n", str); + stat = fprintf(leaseFile, "default-duid %s;\n", str); dfree(str, MDL); if (stat <= 0) return ISC_R_IOERROR; @@ -3586,8 +3585,35 @@ write_client6_lease(struct client_state *client, struct dhc6_lease *lease, ianame = "ia-pd"; break; } - stat = fprintf(leaseFile, " %s %s {\n", - ianame, print_hex_1(4, ia->iaid, 12)); + + /* For some reason IAID was never octal or hex, but string or + * hex. Go figure. So for compatibilty's sake we will either + * do hex or "legacy" i.e string rather than octal. What a + * cluster. */ + switch(top_level_config.lease_id_format) { + case TOKEN_HEX: { + char* iaid_str = format_lease_id( + (const unsigned char *) &ia->iaid, 4, + top_level_config.lease_id_format, MDL); + + if (!iaid_str) { + log_error("Can't format iaid"); + return ISC_R_IOERROR; + } + + stat = fprintf(leaseFile, " %s %s {\n", + ianame, iaid_str); + dfree(iaid_str, MDL); + break; + } + + case TOKEN_OCTAL: + default: + stat = fprintf(leaseFile, " %s %s {\n", ianame, + print_hex_1(4, ia->iaid, 12)); + break; + } + if (stat <= 0) return ISC_R_IOERROR; diff --git a/client/dhclient.conf.5 b/client/dhclient.conf.5 index 11706d9ef..382837c0b 100644 --- a/client/dhclient.conf.5 +++ b/client/dhclient.conf.5 @@ -1,8 +1,6 @@ .\" $Id: dhclient.conf.5,v 1.34 2012/01/24 22:23:39 sar Exp $ .\" -.\" Copyright (c) 2014,2016 by Internet Systems Consortium, Inc. ("ISC") -.\" Copyright (c) 2009-2012 by Internet Systems Consortium, Inc. ("ISC") -.\" Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 2004-2016 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -599,6 +597,28 @@ day-and-time in UTC, whereas \fIlocal\fR uses a seconds-since-epoch to store the time value, and helpfully places a local timezone time in a comment on the same line. The formats are described in detail in this manpage, within the LEASE DECLARATIONS section. +.PP +The +.I lease-id-format +parameter +.RS 0.25i +.PP +.B lease-id-format \fIformat\fB;\fR +.PP +The \fIformat\fR parameter must be either \fBoctal\fR or \fBhex\fR. +This parameter governs the format used to write certain values to lease +files. With the default format, octal, values are written as quoted strings in +which non-printable characters are represented as octal escapes - +a backslash character followed by three octal digits. When the hex format +is specified, values are written as an unquoted series of hexadecimal digit +pairs, separated by colons. + +Currently, the values written out based on lease-id-format are the default-duid +and the IAID value (DHCPv6 only). The client automatically reads the values +in either format. Note that when the format is octal, rather than as an octal +string, IAID is output as hex if it contains no printable characters or as a +string if contains only printable characters. This is done to maintain backward +compatibility. .PP \fBreject \fIcidr-ip-address\fR [\fB,\fR \fI...\fB \fIcidr-ip-address\fR ] \fB;\fR .PP diff --git a/common/conflex.c b/common/conflex.c index a1ba95fda..fe994acf8 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -3,7 +3,7 @@ Lexical scanner for dhcpd config file... */ /* - * Copyright (c) 2004-2015 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2004-2016 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 @@ -1050,6 +1050,9 @@ intern(char *atom, enum dhcp_token dfv) { return HOSTNAME; if (!strcasecmp (atom + 1, "elp")) return TOKEN_HELP; + if (!strcasecmp (atom + 1, "ex")) { + return TOKEN_HEX; + } break; case 'i': if (!strcasecmp(atom+1, "a-na")) @@ -1136,6 +1139,9 @@ intern(char *atom, enum dhcp_token dfv) { if (!strcasecmp(atom+1, "ittle-endian")) { return TOKEN_LITTLE_ENDIAN; } + if (!strcasecmp (atom + 1, "ease-id-format")) { + return LEASE_ID_FORMAT; + } break; case 'm': if (!strncasecmp (atom + 1, "ax", 2)) { @@ -1236,6 +1242,9 @@ intern(char *atom, enum dhcp_token dfv) { return OF; if (!strcasecmp (atom + 1, "wner")) return OWNER; + if (!strcasecmp (atom + 1, "ctal")) { + return TOKEN_OCTAL; + } break; case 'p': if (!strcasecmp (atom + 1, "arse-vendor-option")) diff --git a/common/print.c b/common/print.c index dfe0593bc..40b64fb69 100644 --- a/common/print.c +++ b/common/print.c @@ -3,7 +3,7 @@ Turn data structures into printable text. */ /* - * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2009-2014,2016 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * @@ -69,7 +69,7 @@ char *quotify_string (const char *s, const char *file, int line) return buf; } -char *quotify_buf (const unsigned char *s, unsigned len, +char *quotify_buf (const unsigned char *s, unsigned len, char enclose_char, const char *file, int line) { unsigned nulen = 0; @@ -87,9 +87,17 @@ char *quotify_buf (const unsigned char *s, unsigned len, nulen++; } + if (enclose_char) { + nulen +=2 ; + } + buf = dmalloc (nulen + 1, MDL); if (buf) { nsp = buf; + if (enclose_char) { + *nsp++ = enclose_char; + } + for (i = 0; i < len; i++) { if (s [i] == ' ') *nsp++ = ' '; @@ -102,6 +110,10 @@ char *quotify_buf (const unsigned char *s, unsigned len, } else *nsp++ = s [i]; } + + if (enclose_char) { + *nsp++ = enclose_char; + } *nsp++ = 0; } return buf; @@ -1517,3 +1529,87 @@ print_time(TIME t) return buf; } + +/* !brief Return the given data as a string of hex digits "xx:xx:xx ..." + * + * Converts the given data into a null-terminated, string of hex digits, + * stored in an allocated buffer. It is the caller's responsiblity to free + * the buffer. + * + * \param s - pointer to the data to convert + * \param len - length of the data to convert + * \param file - source file of invocation + * \param line - line number of invocation + * + * \return Returns an allocated buffer containing the hex string +*/ +char *buf_to_hex (const unsigned char *s, unsigned len, + const char *file, int line) +{ + unsigned nulen = 0; + char *buf; + + /* If somebody hands us length of zero, we'll give them + * back an empty string */ + if (!len) { + buf = dmalloc (1, MDL); + if (buf) { + *buf = 0x0; + } + + return (buf); + } + + + /* Figure out how big it needs to be. print_to_hex uses + * "%02x:" per character. Note since there's no trailing colon + * we'll have room for the null */ + nulen = (len * 3); + + /* Allocate our buffer */ + buf = dmalloc (nulen, MDL); + + /* Hex-ify it */ + if (buf) { + print_hex_only (len, s, nulen, buf); + } + + return buf; +} + +/* !brief Formats data into a string based on a lease id format + * + * Takes the given data and returns an allocated string whose contents are + * the string version of that data, formatted according to the output lease + * id format. Note it is the caller's responsiblity to delete the string. + * + * Currently two formats are supported: + * + * OCTAL - Default or "legacy" CSL format enclosed in quotes '"'. + * + * HEX - Bytes represented as string colon seperated of hex digit pairs + * (xx:xx:xx...) + * + * \param s - data to convert + * \param len - length of the data to convert + * \param format - desired format of the result + * \param file - source file of invocation + * \param line - line number of invocation + * + * \return A pointer to the allocated, null-terminated string +*/ +char *format_lease_id(const unsigned char *s, unsigned len, + int format, const char *file, int line) { + char *idstr = NULL; + + switch (format) { + case TOKEN_HEX: + idstr = buf_to_hex(s, len, MDL); + break; + case TOKEN_OCTAL: + default: + idstr = quotify_buf(s, len, '"', MDL); + break; + } + return (idstr); +} diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 4b3001a84..d14979284 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -1243,6 +1243,9 @@ struct client_config { int do_forward_update; /* If nonzero, and if we have the information we need, update the A record for the address we get. */ + + int lease_id_format; /* format for IDs in lease file, + TOKEN_OCTAL or TOKEN_HEX */ }; /* Per-interface state used in the dhcp client... */ @@ -2065,6 +2068,7 @@ extern int server_id_check; extern int prefix_length_mode; extern int authoring_byte_order; +extern int lease_id_format; extern const char *path_dhcpd_conf; extern const char *path_dhcpd_db; @@ -2089,6 +2093,7 @@ extern enum dhcp_shutdown_state shutdown_state; isc_result_t dhcp_io_shutdown (omapi_object_t *, void *); isc_result_t dhcp_set_control_state (control_object_state_t oldstate, control_object_state_t newstate); + #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) void relinquish_ackqueue(void); #endif @@ -2532,13 +2537,13 @@ int binding_scope_reference (struct binding_scope **, int dns_zone_allocate (struct dns_zone **, const char *, int); int dns_zone_reference (struct dns_zone **, struct dns_zone *, const char *, int); - /* print.c */ #define DEFAULT_TIME_FORMAT 0 #define LOCAL_TIME_FORMAT 1 extern int db_time_format; char *quotify_string (const char *, const char *, int); -char *quotify_buf (const unsigned char *, unsigned, const char *, int); +char *quotify_buf (const unsigned char *, unsigned, const char, + const char *, int); char *print_base64 (const unsigned char *, unsigned, const char *, int); char *print_hw_addr (const int, const int, const unsigned char *); void print_lease (struct lease *); @@ -2572,7 +2577,10 @@ void print_dns_status (int, struct dhcp_ddns_cb *, isc_result_t); const char *print_time(TIME); void get_hw_addr(const char *name, struct hardware *hw); - +char *buf_to_hex (const unsigned char *s, unsigned len, + const char *file, int line); +char *format_lease_id(const unsigned char *s, unsigned len, int format, + const char *file, int line); /* socket.c */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \ || defined (USE_SOCKET_FALLBACK) diff --git a/includes/dhctoken.h b/includes/dhctoken.h index c1db9da39..fa3c0bc21 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -3,7 +3,7 @@ Tokens for config file lexer and parser. */ /* - * Copyright (c) 2011-2015 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2011-2016 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004,2007-2009 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1996-2003 by Internet Software Consortium * @@ -371,7 +371,10 @@ enum dhcp_token { PARSE_VENDOR_OPT = 672, AUTHORING_BYTE_ORDER = 673, TOKEN_LITTLE_ENDIAN = 674, - TOKEN_BIG_ENDIAN = 675 + TOKEN_BIG_ENDIAN = 675, + LEASE_ID_FORMAT = 676, + TOKEN_HEX = 677, + TOKEN_OCTAL = 678 }; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ diff --git a/server/confpars.c b/server/confpars.c index 1b37a22eb..e4c690b6c 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -36,6 +36,9 @@ static int parse_binding_value(struct parse *cfile, struct binding_value *value); static void parse_authoring_byte_order (struct parse *cfile); +static void parse_lease_id_format (struct parse *cfile); +static int parse_iaid_duid(struct parse *cfile, struct ia_xx** ia, + u_int32_t *iaid, const char* file, int line); #if defined (TRACING) trace_type_t *trace_readconf_type; @@ -802,6 +805,11 @@ int parse_statement (cfile, group, type, host_decl, declaration) break; #endif /* DHCPv6 */ + case LEASE_ID_FORMAT: + token = next_token (&val, (unsigned *)0, cfile); + parse_lease_id_format(cfile); + break; + default: et = (struct executable_statement *)0; lose = 0; @@ -1451,6 +1459,52 @@ void parse_authoring_byte_order (struct parse *cfile) } } +/*! + * \brief Parses a lease-id-format statement + * + * A valid statement looks like this: + * + * lease-id-format :== + * LEASE_ID_FORMAT TOKEN_OCTAL | TOKEN_HEX ; + * + * This function is used to parse the lease-id-format statement. It sets the + * global variable, lease_id_format. + * + * \param cfile the current parse file + * +*/ +void parse_lease_id_format (struct parse *cfile) +{ + enum dhcp_token token; + const char *val; + unsigned int len; + + token = next_token(&val, NULL, cfile); + switch(token) { + case TOKEN_OCTAL: + lease_id_format = TOKEN_OCTAL; + break; + case TOKEN_HEX: + lease_id_format = TOKEN_HEX; + break; + default: + parse_warn(cfile, "lease-id-format is invalid: " + " it must be octal or hex."); + skip_to_semi(cfile); + return; + } + + log_debug("lease_id_format is: %s", + lease_id_format == TOKEN_OCTAL ? "octal" : "hex"); + + 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 @@ -4664,10 +4718,9 @@ parse_ia_na_declaration(struct parse *cfile) { skip_to_semi(cfile); #else /* defined(DHCPv6) */ enum dhcp_token token; - struct ia_xx *ia; + struct ia_xx *ia = NULL; const char *val; struct ia_xx *old_ia; - unsigned int len; u_int32_t iaid; struct iaddr iaddr; binding_state_t state; @@ -4690,26 +4743,10 @@ parse_ia_na_declaration(struct parse *cfile) { return; } - token = next_token(&val, &len, cfile); - if (token != STRING) { - parse_warn(cfile, "corrupt lease file; " - "expecting an iaid+ia_na string"); - skip_to_semi(cfile); - return; - } - if (len < 5) { - parse_warn(cfile, "corrupt lease file; " - "iaid+ia_na string too short"); - skip_to_semi(cfile); + if (!parse_iaid_duid(cfile, &ia, &iaid, MDL)) { return; } - 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."); - } ia->ia_type = D6O_IA_NA; token = next_token(&val, NULL, cfile); @@ -5117,10 +5154,9 @@ parse_ia_ta_declaration(struct parse *cfile) { skip_to_semi(cfile); #else /* defined(DHCPv6) */ enum dhcp_token token; - struct ia_xx *ia; + struct ia_xx *ia = NULL; const char *val; struct ia_xx *old_ia; - unsigned int len; u_int32_t iaid; struct iaddr iaddr; binding_state_t state; @@ -5143,26 +5179,10 @@ parse_ia_ta_declaration(struct parse *cfile) { return; } - token = next_token(&val, &len, cfile); - if (token != STRING) { - parse_warn(cfile, "corrupt lease file; " - "expecting an iaid+ia_ta string"); - skip_to_semi(cfile); - return; - } - if (len < 5) { - parse_warn(cfile, "corrupt lease file; " - "iaid+ia_ta string too short"); - skip_to_semi(cfile); + if (!parse_iaid_duid(cfile, &ia, &iaid, MDL)) { return; } - 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."); - } ia->ia_type = D6O_IA_TA; token = next_token(&val, NULL, cfile); @@ -5570,10 +5590,9 @@ parse_ia_pd_declaration(struct parse *cfile) { skip_to_semi(cfile); #else /* defined(DHCPv6) */ enum dhcp_token token; - struct ia_xx *ia; + struct ia_xx *ia = NULL; const char *val; struct ia_xx *old_ia; - unsigned int len; u_int32_t iaid; struct iaddr iaddr; u_int8_t plen; @@ -5597,26 +5616,10 @@ parse_ia_pd_declaration(struct parse *cfile) { return; } - token = next_token(&val, &len, cfile); - if (token != STRING) { - parse_warn(cfile, "corrupt lease file; " - "expecting an iaid+ia_pd string"); - skip_to_semi(cfile); + if (!parse_iaid_duid(cfile, &ia, &iaid, MDL)) { return; } - if (len < 5) { - parse_warn(cfile, "corrupt lease file; " - "iaid+ia_pd string too short"); - skip_to_semi(cfile); - return; - } - - 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."); - } ia->ia_type = D6O_IA_PD; token = next_token(&val, NULL, cfile); @@ -6024,39 +6027,37 @@ parse_ia_pd_declaration(struct parse *cfile) { * DUID stored in a string: * * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y"; + * + * OR as a hex string of digits: + * + * server-duid 00:01:00:01:1e:68:b3:db:0a:00:27:00:00:02; */ void parse_server_duid(struct parse *cfile) { - enum dhcp_token token; - const char *val; - unsigned int len; struct data_string duid; + unsigned char bytes[128]; /* Maximum valid DUID is 128 */ + unsigned int len; - token = next_token(&val, &len, cfile); - if (token != STRING) { - parse_warn(cfile, "corrupt lease file; expecting a DUID"); + len = parse_X(cfile, bytes, sizeof(bytes)); + if (len <= 2) { + parse_warn(cfile, "Invalid duid contents"); skip_to_semi(cfile); return; } - memset(&duid, 0, sizeof(duid)); - duid.len = len; - if (!buffer_allocate(&duid.buffer, duid.len, MDL)) { - log_fatal("Out of memory storing DUID"); + memset(&duid, 0x0, sizeof(duid)); + if (!buffer_allocate(&duid.buffer, len, MDL)) { + log_fatal("parse_server_duid: out of memory"); } - duid.data = (unsigned char *)duid.buffer->data; - memcpy(duid.buffer->data, val, len); - set_server_duid(&duid); + memcpy(duid.buffer->data, bytes, len); + duid.len = len; + duid.data = duid.buffer->data; + set_server_duid(&duid); data_string_forget(&duid, MDL); - token = next_token(&val, &len, cfile); - if (token != SEMI) { - parse_warn(cfile, "corrupt lease file; expecting a semicolon"); - skip_to_semi(cfile); - return; - } + parse_semi(cfile); } /* @@ -6343,5 +6344,51 @@ uint32_t parse_byte_order_uint32(const void *source) { return (value); } +/* !brief Parses an iaid/duid string into an iaid and struct ia + * + * Given a string containing the iaid-duid value read from the file, + * and using the format specified by input lease-id-format, convert + * it into an IAID value and an ia_xx struct. + * + * \param cfile - file being parsed + * \param ia - pointer in which to store the allocated ia_xx struct + * \param iaid - pointer in which to return the IAID value + * \param file - source file name of invocation + * \param line - line numbe of invocation + * + * \return 0 if parsing fails, non-zero otherwise +*/ +int +parse_iaid_duid(struct parse* cfile, struct ia_xx** ia, u_int32_t *iaid, + const char* file, int line) { + unsigned char bytes[132]; /* Maximum valid IAID-DUID is 132 */ + unsigned int len; + + if (!ia) { + log_error("parse_iaid_duid: ia ptr cannot be null"); + return (0); + } + + *ia = NULL; + len = parse_X(cfile, bytes, sizeof(bytes)); + if (len <= 5) { + parse_warn(cfile, "corrupt lease file; " + "iaid+ia_xx string too short"); + skip_to_semi(cfile); + return (0); + } + + /* Extract the IAID from the front */ + *iaid = parse_byte_order_uint32(bytes); + + /* Instantiate the ia_xx */ + if (ia_allocate(ia, *iaid, (const char*)bytes + 4, len - 4, file, line) + != ISC_R_SUCCESS) { + log_fatal("parse_iaid_duid:Out of memory."); + } + + return (1); +} + #endif /* DHCPv6 */ diff --git a/server/db.c b/server/db.c index 645ea0dc8..0eaa8d12f 100644 --- a/server/db.c +++ b/server/db.c @@ -3,7 +3,7 @@ Persistent database management routines for DHCPD... */ /* - * Copyright (c) 2012-2015 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2012-2016 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * @@ -56,10 +56,10 @@ write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend) { if (bnd->value->type == binding_data) { if (bnd->value->value.data.data != NULL) { s = quotify_buf(bnd->value->value.data.data, - bnd->value->value.data.len, MDL); + bnd->value->value.data.len, '"', MDL); if (s != NULL) { errno = 0; - fprintf(db_file, "%sset %s = \"%s\";", + fprintf(db_file, "%sset %s = %s;", prepend, bnd->name, s); dfree(s, MDL); if (errno) @@ -207,10 +207,11 @@ int write_lease (lease) ++errors; } if (lease -> uid_len) { - s = quotify_buf (lease -> uid, lease -> uid_len, MDL); + s = format_lease_id(lease->uid, lease->uid_len, lease_id_format, + MDL); if (s) { errno = 0; - fprintf (db_file, "\n uid \"%s\";", s); + fprintf (db_file, "\n uid %s;", s); if (errno) ++errors; dfree (s, MDL); @@ -539,23 +540,23 @@ write_ia(const struct ia_xx *ia) { ++count; } - - s = quotify_buf(ia->iaid_duid.data, ia->iaid_duid.len, MDL); + s = format_lease_id(ia->iaid_duid.data, ia->iaid_duid.len, + lease_id_format, MDL); if (s == NULL) { goto error_exit; } switch (ia->ia_type) { case D6O_IA_NA: - fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s); + fprintf_ret = fprintf(db_file, "ia-na %s {\n", s); break; case D6O_IA_TA: - fprintf_ret = fprintf(db_file, "ia-ta \"%s\" {\n", s); + fprintf_ret = fprintf(db_file, "ia-ta %s {\n", s); break; case D6O_IA_PD: - fprintf_ret = fprintf(db_file, "ia-pd \"%s\" {\n", s); + fprintf_ret = fprintf(db_file, "ia-pd %s {\n", s); break; default: - log_error("Unknown ia type %u for \"%s\" at %s:%d", + log_error("Unknown ia type %u for %s at %s:%d", (unsigned)ia->ia_type, s, MDL); fprintf_ret = -1; } @@ -712,7 +713,8 @@ write_server_duid(void) { */ memset(&server_duid, 0, sizeof(server_duid)); copy_server_duid(&server_duid, MDL); - s = quotify_buf(server_duid.data, server_duid.len, MDL); + s = format_lease_id(server_duid.data, server_duid.len, lease_id_format, + MDL); data_string_forget(&server_duid, MDL); if (s == NULL) { goto error_exit; @@ -721,7 +723,7 @@ write_server_duid(void) { /* * Write to the leases file. */ - fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s); + fprintf_ret = fprintf(db_file, "server-duid %s;\n\n", s); dfree(s, MDL); if (fprintf_ret < 0) { goto error_exit; @@ -1183,7 +1185,6 @@ int new_lease_file () 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 145561c06..abf333d18 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -77,6 +77,7 @@ 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 */ +int lease_id_format = TOKEN_OCTAL; /* octal by default */ const char *path_dhcpd_conf = _PATH_DHCPD_CONF; const char *path_dhcpd_db = _PATH_DHCPD_DB; diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index ebc99120c..a6b197767 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -2509,6 +2509,26 @@ is, the latter value will be used. .RE .PP The +.I lease-id-format +parameter +.RS 0.25i +.PP +.B lease-id-format \fIformat\fB;\fR +.PP +The \fIformat\fR parameter must be either \fBoctal\fR or \fBhex\fR. +This parameter governs the format used to write certain values to lease +files. With the default format, octal, values are written as quoted strings in +which non-printable characters are represented as octal escapes - +a backslash character followed by three octal digits. When the hex format +is specified, values are written as an unquoted series of pairs of +hexadecimal digits, separated by colons. + +Currently, the values written out based on lease-id-format are the server-duid, +the uid (DHCPv4 leases), and the IAID_DUID (DHCPv6 leases). Note the server +automatically reads the values in either format. +.RE +.PP +The .I local-port statement .RS 0.25i diff --git a/server/dhcpd.leases.5 b/server/dhcpd.leases.5 index 025b9bf8d..df59d8252 100644 --- a/server/dhcpd.leases.5 +++ b/server/dhcpd.leases.5 @@ -1,6 +1,6 @@ .\" dhcpd.leases.5 .\" -.\" Copyright (c) 2014-2015 by Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (c) 2014-2016 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 2004,2009 by Internet Systems Consortium, Inc. ("ISC") .\" Copyright (c) 1996-2003 by Internet Software Consortium .\" @@ -246,7 +246,8 @@ The client identifier is recorded as a colon-separated hexadecimal list or as a quoted string. If it is recorded as a quoted string and it contains one or more non-printable characters, those characters are represented as octal escapes - a backslash character followed by three -octal digits. +octal digits. The format used is determined by the lease-id-format +parameter, which defaults to octal. .PP .B client-hostname "\fIhostname\fB";\fR .PP @@ -327,7 +328,8 @@ The IAID_DUID value is recorded as a colon-separated hexadecimal list or as a quoted string. If it is recorded as a quoted string and it contains one or more non-printable characters, those characters are represented as octal escapes - a backslash character followed by three -octal digits. +octal digits. The format used is governed by the lease-id-format parameter, +which defaults to octal. .PP .B cltt \fIdate\fB;\fR .PP