]> git.pld-linux.org Git - packages/dhcp.git/blobdiff - dhcp-rfc3442-classless-static-routes.patch
- updated to 4.4.3, more patches from Fedora
[packages/dhcp.git] / dhcp-rfc3442-classless-static-routes.patch
diff --git a/dhcp-rfc3442-classless-static-routes.patch b/dhcp-rfc3442-classless-static-routes.patch
new file mode 100644 (file)
index 0000000..2ab5a5e
--- /dev/null
@@ -0,0 +1,436 @@
+From 7e6299e72feaaf7e8bd499614999ba8a07dd1a8a Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov@redhat.com>
+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 "<null destination descriptor>";
++      }
++      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 "<error>";
++                              }
++
++                              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
+
This page took 0.108187 seconds and 4 git commands to generate.