X-Git-Url: http://git.pld-linux.org/?p=packages%2Fdhcp.git;a=blobdiff_plain;f=dhcp-rfc3442-classless-static-routes.patch;fp=dhcp-rfc3442-classless-static-routes.patch;h=2ab5a5e72759ed116e062aa59886d0a6dfe60f9c;hp=0000000000000000000000000000000000000000;hb=15c1a8319287edff43305ebc37c8b7fab896f48b;hpb=b8e4f380a8c521bad8c663cf38e4ea69ac42dd00 diff --git a/dhcp-rfc3442-classless-static-routes.patch b/dhcp-rfc3442-classless-static-routes.patch new file mode 100644 index 0000000..2ab5a5e --- /dev/null +++ b/dhcp-rfc3442-classless-static-routes.patch @@ -0,0 +1,436 @@ +From 7e6299e72feaaf7e8bd499614999ba8a07dd1a8a Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +Date: Thu, 21 Feb 2019 10:32:35 +0100 +Subject: [PATCH 12/28] RFC 3442 - Classless Static Route Option for DHCPv4 + (#516325) + +(Submitted to dhcp-bugs@isc.org - [ISC-Bugs #24572]) +--- + client/clparse.c | 13 ++++++++-- + common/dhcp-options.5 | 43 +++++++++++++++++++++++++++++++++ + common/inet.c | 54 +++++++++++++++++++++++++++++++++++++++++ + common/options.c | 49 ++++++++++++++++++++++++++++++++++++- + common/parse.c | 56 ++++++++++++++++++++++++++++++++++++++++++- + common/tables.c | 2 ++ + includes/dhcp.h | 1 + + includes/dhcpd.h | 2 ++ + includes/dhctoken.h | 3 ++- + 9 files changed, 218 insertions(+), 5 deletions(-) + +diff --git a/client/clparse.c b/client/clparse.c +index 902b523..57f6456 100644 +--- a/client/clparse.c ++++ b/client/clparse.c +@@ -31,7 +31,7 @@ + + struct client_config top_level_config; + +-#define NUM_DEFAULT_REQUESTED_OPTS 14 ++#define NUM_DEFAULT_REQUESTED_OPTS 15 + /* There can be 2 extra requested options for DHCPv4-over-DHCPv6. */ + struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 2 + 1]; + +@@ -90,7 +90,11 @@ isc_result_t read_client_conf () + dhcp_universe.code_hash, &code, 0, MDL); + + /* 4 */ +- code = DHO_ROUTERS; ++ /* The Classless Static Routes option code MUST appear in the parameter ++ * request list prior to both the Router option code and the Static ++ * Routes option code, if present. (RFC3442) ++ */ ++ code = DHO_CLASSLESS_STATIC_ROUTES; + option_code_hash_lookup(&default_requested_options[3], + dhcp_universe.code_hash, &code, 0, MDL); + +@@ -144,6 +148,11 @@ isc_result_t read_client_conf () + option_code_hash_lookup(&default_requested_options[13], + dhcp_universe.code_hash, &code, 0, MDL); + ++ /* 15 */ ++ code = DHO_ROUTERS; ++ option_code_hash_lookup(&default_requested_options[14], ++ dhcp_universe.code_hash, &code, 0, MDL); ++ + for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) { + if (default_requested_options[code] == NULL) + log_fatal("Unable to find option definition for " +diff --git a/common/dhcp-options.5 b/common/dhcp-options.5 +index a784b32..86f04ed 100644 +--- a/common/dhcp-options.5 ++++ b/common/dhcp-options.5 +@@ -117,6 +117,26 @@ hexadecimal, separated by colons. For example: + or + option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f; + .fi ++.PP ++The ++.B destination-descriptor ++describe the IP subnet number and subnet mask ++of a particular destination using a compact encoding. This encoding ++consists of one octet describing the width of the subnet mask, ++followed by all the significant octets of the subnet number. ++The following table contains some examples of how various subnet ++number/mask combinations can be encoded: ++.nf ++.sp 1 ++Subnet number Subnet mask Destination descriptor ++0 0 0 ++10.0.0.0 255.0.0.0 8.10 ++10.0.0.0 255.255.255.0 24.10.0.0 ++10.17.0.0 255.255.0.0 16.10.17 ++10.27.129.0 255.255.255.0 24.10.27.129 ++10.229.0.128 255.255.255.128 25.10.229.0.128 ++10.198.122.47 255.255.255.255 32.10.198.122.47 ++.fi + .SH SETTING OPTION VALUES USING EXPRESSIONS + Sometimes it's helpful to be able to set the value of a DHCP option + based on some value that the client has sent. To do this, you can +@@ -1093,6 +1113,29 @@ dhclient-script will create routes: + .RE + .PP + .nf ++.B option \fBclassless-static-routes\fR \fIdestination-descriptor ip-address\fR ++ [\fB,\fR \fIdestination-descriptor ip-address\fR...]\fB;\fR ++.fi ++.RS 0.25i ++.PP ++This option (see RFC3442) specifies a list of classless static routes ++that the client should install in its routing cache. ++.PP ++This option can contain one or more static routes, each of which ++consists of a destination descriptor and the IP address of the router ++that should be used to reach that destination. ++.PP ++Many clients may not implement the Classless Static Routes option. ++DHCP server administrators should therefore configure their DHCP ++servers to send both a Router option and a Classless Static Routes ++option, and should specify the default router(s) both in the Router ++option and in the Classless Static Routes option. ++.PP ++If the DHCP server returns both a Classless Static Routes option and ++a Router option, the DHCP client ignores the Router option. ++.RE ++.PP ++.nf + .B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR + [\fB,\fR \fIip-address\fR...]\fB;\fR + .fi +diff --git a/common/inet.c b/common/inet.c +index 0f7f168..7c446d4 100644 +--- a/common/inet.c ++++ b/common/inet.c +@@ -519,6 +519,60 @@ free_iaddrcidrnetlist(struct iaddrcidrnetlist **result) { + return ISC_R_SUCCESS; + } + ++static const char * ++inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size) ++{ ++ char tmp[sizeof("32.255.255.255.255")]; ++ int len; ++ ++ switch (srclen) { ++ case 2: ++ len = sprintf (tmp, "%u.%u", src[0], src[1]); ++ break; ++ case 3: ++ len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]); ++ break; ++ case 4: ++ len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); ++ break; ++ case 5: ++ len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]); ++ break; ++ default: ++ return NULL; ++ } ++ if (len < 0) ++ return NULL; ++ ++ if (len > size) { ++ errno = ENOSPC; ++ return NULL; ++ } ++ ++ return strcpy (dst, tmp); ++} ++ ++/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */ ++const char * ++pdestdesc(const struct iaddr addr) { ++ static char pbuf[sizeof("255.255.255.255.255")]; ++ ++ if (addr.len == 0) { ++ return ""; ++ } ++ if (addr.len == 1) { ++ return "0"; ++ } ++ if ((addr.len >= 2) && (addr.len <= 5)) { ++ return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf)); ++ } ++ ++ log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.", ++ MDL, addr.len); ++ /* quell compiler warnings */ ++ return NULL; ++} ++ + /* piaddr() turns an iaddr structure into a printable address. */ + /* XXX: should use a const pointer rather than passing the structure */ + const char * +diff --git a/common/options.c b/common/options.c +index 92c8fee..66433c4 100644 +--- a/common/options.c ++++ b/common/options.c +@@ -734,7 +734,11 @@ cons_options(struct packet *inpacket, struct dhcp_packet *outpacket, + * packet. + */ + priority_list[priority_len++] = DHO_SUBNET_MASK; +- priority_list[priority_len++] = DHO_ROUTERS; ++ if (lookup_option(&dhcp_universe, cfg_options, ++ DHO_CLASSLESS_STATIC_ROUTES)) ++ priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES; ++ else ++ priority_list[priority_len++] = DHO_ROUTERS; + priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS; + priority_list[priority_len++] = DHO_HOST_NAME; + priority_list[priority_len++] = DHO_FQDN; +@@ -1812,6 +1816,7 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes) + unsigned long tval; + isc_boolean_t a_array = ISC_FALSE; + int len_used; ++ unsigned int octets = 0; + + if (emit_commas) + comma = ','; +@@ -1820,6 +1825,7 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes) + + memset (enumbuf, 0, sizeof enumbuf); + ++ if (option->format[0] != 'R') { /* see explanation lower */ + /* Figure out the size of the data. */ + for (l = i = 0; option -> format [i]; i++, l++) { + if (l >= sizeof(fmtbuf) - 1) +@@ -2029,6 +2035,33 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes) + if (numhunk < 0) + numhunk = 1; + ++ } else { /* option->format[i] == 'R') */ ++ /* R (destination descriptor) has variable length. ++ * We can find it only in classless static route option, ++ * so we are for sure parsing classless static route option now. ++ * We go through whole the option to check whether there are no ++ * missing/extra bytes. ++ * I didn't find out how to improve the existing code and that's the ++ * reason for this separate 'else' where I do my own checkings. ++ * I know it's little bit unsystematic, but it works. ++ */ ++ numhunk = 0; ++ numelem = 2; /* RI */ ++ fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0; ++ for (i =0; i < len; i = i + octets + 5) { ++ if (data[i] > 32) { /* subnet mask width */ ++ log_error ("wrong subnet mask width in destination descriptor"); ++ break; ++ } ++ numhunk++; ++ octets = ((data[i]+7) / 8); ++ } ++ if (i != len) { ++ log_error ("classless static routes option has wrong size or " ++ "there's some garbage in format"); ++ } ++ } ++ + /* Cycle through the array (or hunk) printing the data. */ + for (i = 0; i < numhunk; i++) { + if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) { +@@ -2197,6 +2230,20 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes) + strcpy(op, piaddr(iaddr)); + dp += 4; + break; ++ ++ case 'R': ++ if (dp[0] <= 32) ++ iaddr.len = (((dp[0]+7)/8)+1); ++ else { ++ log_error ("wrong subnet mask width in destination descriptor"); ++ return ""; ++ } ++ ++ memcpy(iaddr.iabuf, dp, iaddr.len); ++ strcpy(op, pdestdesc(iaddr)); ++ dp += iaddr.len; ++ break; ++ + case '6': + iaddr.len = 16; + memcpy(iaddr.iabuf, dp, 16); +diff --git a/common/parse.c b/common/parse.c +index b123a6c..7cf4f2a 100644 +--- a/common/parse.c ++++ b/common/parse.c +@@ -344,6 +344,39 @@ int parse_ip_addr (cfile, addr) + return 0; + } + ++/* ++ * destination-descriptor :== NUMBER DOT NUMBER | ++ * NUMBER DOT NUMBER DOT NUMBER | ++ * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER | ++ * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER DOT NUMBER ++ */ ++ ++int parse_destination_descriptor (cfile, addr) ++ struct parse *cfile; ++ struct iaddr *addr; ++{ ++ unsigned int mask_width, dest_dest_len; ++ addr -> len = 0; ++ if (parse_numeric_aggregate (cfile, addr -> iabuf, ++ &addr -> len, DOT, 10, 8)) { ++ mask_width = (unsigned int)addr->iabuf[0]; ++ dest_dest_len = (((mask_width+7)/8)+1); ++ if (mask_width > 32) { ++ parse_warn (cfile, ++ "subnet mask width (%u) greater than 32.", mask_width); ++ } ++ else if (dest_dest_len != addr->len) { ++ parse_warn (cfile, ++ "destination descriptor with subnet mask width %u " ++ "should have %u octets, but has %u octets.", ++ mask_width, dest_dest_len, addr->len); ++ } ++ ++ return 1; ++ } ++ return 0; ++} ++ + /* + * Return true if every character in the string is hexadecimal. + */ +@@ -724,8 +757,10 @@ unsigned char *parse_numeric_aggregate (cfile, buf, + if (count) { + token = peek_token (&val, (unsigned *)0, cfile); + if (token != separator) { +- if (!*max) ++ if (!*max) { ++ *max = count; + break; ++ } + if (token != RBRACE && token != LBRACE) + token = next_token (&val, + (unsigned *)0, +@@ -1672,6 +1707,9 @@ int parse_option_code_definition (cfile, option) + case IP_ADDRESS: + type = 'I'; + break; ++ case DESTINATION_DESCRIPTOR: ++ type = 'R'; ++ break; + case IP6_ADDRESS: + type = '6'; + break; +@@ -5124,6 +5162,15 @@ int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) + } + break; + ++ case 'R': /* destination descriptor */ ++ if (!parse_destination_descriptor (cfile, &addr)) { ++ return 0; ++ } ++ if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) { ++ return 0; ++ } ++ break; ++ + case '6': /* IPv6 address. */ + if (!parse_ip6_addr(cfile, &addr)) { + return 0; +@@ -5401,6 +5448,13 @@ int parse_option_decl (oc, cfile) + goto exit; + len = ip_addr.len; + dp = ip_addr.iabuf; ++ goto alloc; ++ ++ case 'R': /* destination descriptor */ ++ if (!parse_destination_descriptor (cfile, &ip_addr)) ++ goto exit; ++ len = ip_addr.len; ++ dp = ip_addr.iabuf; + + alloc: + if (hunkix + len > sizeof hunkbuf) { +diff --git a/common/tables.c b/common/tables.c +index ce12fcd..96521a6 100644 +--- a/common/tables.c ++++ b/common/tables.c +@@ -45,6 +45,7 @@ HASH_FUNCTIONS (option_code, const unsigned *, struct option, + Format codes: + + I - IPv4 address ++ R - destination descriptor (RFC3442) + 6 - IPv6 address + l - 32-bit signed integer + L - 32-bit unsigned integer +@@ -223,6 +224,7 @@ static struct option dhcp_options[] = { + #endif + { "subnet-selection", "I", &dhcp_universe, 118, 1 }, + { "domain-search", "D", &dhcp_universe, 119, 1 }, ++ { "classless-static-routes", "RIA", &dhcp_universe, 121, 1 }, + { "vivco", "Evendor-class.", &dhcp_universe, 124, 1 }, + { "vivso", "Evendor.", &dhcp_universe, 125, 1 }, + #if 0 +diff --git a/includes/dhcp.h b/includes/dhcp.h +index cafe172..5a73129 100644 +--- a/includes/dhcp.h ++++ b/includes/dhcp.h +@@ -159,6 +159,7 @@ struct dhcp_packet { + #define DHO_V6_ONLY_PREFERRED 108 /* RFC8925 */ + #define DHO_SUBNET_SELECTION 118 /* RFC3011! */ + #define DHO_DOMAIN_SEARCH 119 /* RFC3397 */ ++#define DHO_CLASSLESS_STATIC_ROUTES 121 /* RFC3442 */ + #define DHO_VIVCO_SUBOPTIONS 124 + #define DHO_VIVSO_SUBOPTIONS 125 + +diff --git a/includes/dhcpd.h b/includes/dhcpd.h +index 4a57002..25e1c72 100644 +--- a/includes/dhcpd.h ++++ b/includes/dhcpd.h +@@ -2967,6 +2967,7 @@ isc_result_t range2cidr(struct iaddrcidrnetlist **result, + const struct iaddr *lo, const struct iaddr *hi); + isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result); + const char *piaddr (struct iaddr); ++const char *pdestdesc (struct iaddr); + char *piaddrmask(struct iaddr *, struct iaddr *); + char *piaddrcidr(const struct iaddr *, unsigned int); + u_int16_t validate_port(char *); +@@ -3189,6 +3190,7 @@ void parse_client_lease_declaration (struct parse *, + int parse_option_decl (struct option_cache **, struct parse *); + void parse_string_list (struct parse *, struct string_list **, int); + int parse_ip_addr (struct parse *, struct iaddr *); ++int parse_destination_descriptor (struct parse *, struct iaddr *); + int parse_ip_addr_with_subnet(struct parse *, struct iaddrmatch *); + void parse_reject_statement (struct parse *, struct client_config *); + +diff --git a/includes/dhctoken.h b/includes/dhctoken.h +index 6daa422..3f5334e 100644 +--- a/includes/dhctoken.h ++++ b/includes/dhctoken.h +@@ -378,7 +378,8 @@ enum dhcp_token { + TOKEN_OCTAL = 678, + KEY_ALGORITHM = 679, + BOOTP_BROADCAST_ALWAYS = 680, +- DISCONNECT = 681 ++ DESTINATION_DESCRIPTOR = 681, ++ DISCONNECT = 682 + }; + + #define is_identifier(x) ((x) >= FIRST_TOKEN && \ +-- +2.35.1 +