ssahani / rpms / dhcp

Forked from rpms/dhcp 6 years ago
Clone
fe8e822
diff -up dhcp-4.2.0/client/clparse.c.rfc3442 dhcp-4.2.0/client/clparse.c
fe8e822
--- dhcp-4.2.0/client/clparse.c.rfc3442	2010-08-31 10:12:51.000000000 +0200
fe8e822
+++ dhcp-4.2.0/client/clparse.c	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -37,7 +37,7 @@
fe8e822
 
fe8e822
 struct client_config top_level_config;
fe8e822
 
fe8e822
-#define NUM_DEFAULT_REQUESTED_OPTS	14
fe8e822
+#define NUM_DEFAULT_REQUESTED_OPTS	15
fe8e822
 struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
fe8e822
 
fe8e822
 static void parse_client_default_duid(struct parse *cfile);
fe8e822
@@ -82,7 +82,11 @@ isc_result_t read_client_conf ()
fe8e822
 				dhcp_universe.code_hash, &code, 0, MDL);
fe8e822
 
fe8e822
 	/* 4 */
fe8e822
-	code = DHO_ROUTERS;
fe8e822
+	/* The Classless Static Routes option code MUST appear in the parameter
fe8e822
+     * request list prior to both the Router option code and the Static
fe8e822
+     * Routes option code, if present. (RFC3442)
fe8e822
+	 */
fe8e822
+	code = DHO_CLASSLESS_STATIC_ROUTES;
fe8e822
 	option_code_hash_lookup(&default_requested_options[3],
fe8e822
 				dhcp_universe.code_hash, &code, 0, MDL);
fe8e822
 
fe8e822
@@ -136,6 +140,11 @@ isc_result_t read_client_conf ()
fe8e822
 	option_code_hash_lookup(&default_requested_options[13],
fe8e822
 				dhcp_universe.code_hash, &code, 0, MDL);
fe8e822
 
fe8e822
+	/* 15 */
fe8e822
+	code = DHO_ROUTERS;
fe8e822
+	option_code_hash_lookup(&default_requested_options[14],
fe8e822
+				dhcp_universe.code_hash, &code, 0, MDL);
fe8e822
+
fe8e822
 	for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
fe8e822
 		if (default_requested_options[code] == NULL)
fe8e822
 			log_fatal("Unable to find option definition for "
fe8e822
diff -up dhcp-4.2.0/common/dhcp-options.5.rfc3442 dhcp-4.2.0/common/dhcp-options.5
fe8e822
--- dhcp-4.2.0/common/dhcp-options.5.rfc3442	2010-08-31 10:12:51.000000000 +0200
fe8e822
+++ dhcp-4.2.0/common/dhcp-options.5	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -115,6 +115,26 @@ hexadecimal, separated by colons.   For 
fe8e822
 or
fe8e822
   option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f;
fe8e822
 .fi
fe8e822
+.PP
fe8e822
+The
fe8e822
+.B destination-descriptor
fe8e822
+describe the IP subnet number and subnet mask
fe8e822
+of a particular destination using a compact encoding. This encoding
fe8e822
+consists of one octet describing the width of the subnet mask,
fe8e822
+followed by all the significant octets of the subnet number.
fe8e822
+The following table contains some examples of how various subnet
fe8e822
+number/mask combinations can be encoded:
fe8e822
+.nf
fe8e822
+.sp 1
fe8e822
+Subnet number   Subnet mask      Destination descriptor
fe8e822
+0               0                0
fe8e822
+10.0.0.0        255.0.0.0        8.10
fe8e822
+10.0.0.0        255.255.255.0    24.10.0.0
fe8e822
+10.17.0.0       255.255.0.0      16.10.17
fe8e822
+10.27.129.0     255.255.255.0    24.10.27.129
fe8e822
+10.229.0.128    255.255.255.128  25.10.229.0.128
fe8e822
+10.198.122.47   255.255.255.255  32.10.198.122.47
fe8e822
+.fi
fe8e822
 .SH SETTING OPTION VALUES USING EXPRESSIONS
fe8e822
 Sometimes it's helpful to be able to set the value of a DHCP option
fe8e822
 based on some value that the client has sent.   To do this, you can
fe8e822
@@ -931,6 +951,29 @@ dhclient-script will create routes:
fe8e822
 .RE
fe8e822
 .PP
fe8e822
 .nf
fe8e822
+.B option \fBclassless-static-routes\fR \fIdestination-descriptor ip-address\fR
fe8e822
+                  [\fB,\fR \fIdestination-descriptor ip-address\fR...]\fB;\fR
fe8e822
+.fi
fe8e822
+.RS 0.25i
fe8e822
+.PP
fe8e822
+This option (see RFC3442) specifies a list of classless static routes
fe8e822
+that the client should install in its routing cache.
fe8e822
+.PP
fe8e822
+This option can contain one or more static routes, each of which
fe8e822
+consists of a destination descriptor and the IP address of the router
fe8e822
+that should be used to reach that destination.
fe8e822
+.PP
fe8e822
+Many clients may not implement the Classless Static Routes option.
fe8e822
+DHCP server administrators should therefore configure their DHCP
fe8e822
+servers to send both a Router option and a Classless Static Routes
fe8e822
+option, and should specify the default router(s) both in the Router
fe8e822
+option and in the Classless Static Routes option.
fe8e822
+.PP
fe8e822
+If the DHCP server returns both a Classless Static Routes option and
fe8e822
+a Router option, the DHCP client ignores the Router option.
fe8e822
+.RE
fe8e822
+.PP
fe8e822
+.nf
fe8e822
 .B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR
fe8e822
                                            [\fB,\fR \fIip-address\fR...]\fB;\fR
fe8e822
 .fi
fe8e822
diff -up dhcp-4.2.0/common/inet.c.rfc3442 dhcp-4.2.0/common/inet.c
fe8e822
--- dhcp-4.2.0/common/inet.c.rfc3442	2009-11-20 02:49:00.000000000 +0100
fe8e822
+++ dhcp-4.2.0/common/inet.c	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -526,6 +526,60 @@ free_iaddrcidrnetlist(struct iaddrcidrne
fe8e822
 	return ISC_R_SUCCESS;
fe8e822
 }
fe8e822
 
fe8e822
+static const char *
fe8e822
+inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size)
fe8e822
+{
fe8e822
+	char tmp[sizeof("32.255.255.255.255")];
fe8e822
+	int len;
fe8e822
+
fe8e822
+	switch (srclen) {
fe8e822
+		case 2:
fe8e822
+			len = sprintf (tmp, "%u.%u", src[0], src[1]);
fe8e822
+			break;
fe8e822
+		case 3:
fe8e822
+			len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]);
fe8e822
+			break;
fe8e822
+		case 4:
fe8e822
+			len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
fe8e822
+			break;
fe8e822
+		case 5:
fe8e822
+			len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]);
fe8e822
+			break;
fe8e822
+		default:
fe8e822
+			return NULL;
fe8e822
+	}
fe8e822
+	if (len < 0)
fe8e822
+		return NULL;
fe8e822
+
fe8e822
+	if (len > size) {
fe8e822
+		errno = ENOSPC;
fe8e822
+		return NULL;
fe8e822
+	}
fe8e822
+
fe8e822
+	return strcpy (dst, tmp);
fe8e822
+}
fe8e822
+
fe8e822
+/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */
fe8e822
+const char *
fe8e822
+pdestdesc(const struct iaddr addr) {
fe8e822
+	static char pbuf[sizeof("255.255.255.255.255")];
fe8e822
+
fe8e822
+	if (addr.len == 0) {
fe8e822
+		return "<null destination descriptor>";
fe8e822
+	}
fe8e822
+	if (addr.len == 1) {
fe8e822
+		return "0";
fe8e822
+	}
fe8e822
+	if ((addr.len >= 2) && (addr.len <= 5)) {
fe8e822
+		return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf));
fe8e822
+	}
fe8e822
+
fe8e822
+	log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.",
fe8e822
+		  MDL, addr.len);
fe8e822
+	/* quell compiler warnings */
fe8e822
+	return NULL;
fe8e822
+}
fe8e822
+
fe8e822
 /* piaddr() turns an iaddr structure into a printable address. */
fe8e822
 /* XXX: should use a const pointer rather than passing the structure */
fe8e822
 const char *
fe8e822
diff -up dhcp-4.2.0/common/options.c.rfc3442 dhcp-4.2.0/common/options.c
fe8e822
--- dhcp-4.2.0/common/options.c.rfc3442	2010-06-01 19:29:59.000000000 +0200
fe8e822
+++ dhcp-4.2.0/common/options.c	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -706,7 +706,11 @@ cons_options(struct packet *inpacket, st
fe8e822
 		 * packet.
fe8e822
 		 */
fe8e822
 		priority_list[priority_len++] = DHO_SUBNET_MASK;
fe8e822
-		priority_list[priority_len++] = DHO_ROUTERS;
fe8e822
+		if (op = lookup_option(&dhcp_universe, cfg_options,
fe8e822
+								DHO_CLASSLESS_STATIC_ROUTES))
fe8e822
+			priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES;
fe8e822
+		else
fe8e822
+			priority_list[priority_len++] = DHO_ROUTERS;
fe8e822
 		priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
fe8e822
 		priority_list[priority_len++] = DHO_HOST_NAME;
fe8e822
 		priority_list[priority_len++] = DHO_FQDN;
fe8e822
@@ -1683,6 +1687,7 @@ const char *pretty_print_option (option,
fe8e822
 	const unsigned char *dp = data;
fe8e822
 	char comma;
fe8e822
 	unsigned long tval;
fe8e822
+        unsigned int octets = 0;
fe8e822
 
fe8e822
 	if (emit_commas)
fe8e822
 		comma = ',';
fe8e822
@@ -1691,6 +1696,7 @@ const char *pretty_print_option (option,
fe8e822
 
fe8e822
 	memset (enumbuf, 0, sizeof enumbuf);
fe8e822
 
fe8e822
+	if (option->format[0] != 'R') { /* see explanation lower */
fe8e822
 	/* Figure out the size of the data. */
fe8e822
 	for (l = i = 0; option -> format [i]; i++, l++) {
fe8e822
 		if (l >= sizeof(fmtbuf) - 1)
fe8e822
@@ -1840,6 +1846,33 @@ const char *pretty_print_option (option,
fe8e822
 	if (numhunk < 0)
fe8e822
 		numhunk = 1;
fe8e822
 
fe8e822
+	} else { /* option->format[i] == 'R') */
fe8e822
+		/* R (destination descriptor) has variable length.
fe8e822
+		 * We can find it only in classless static route option,
fe8e822
+		 * so we are for sure parsing classless static route option now.
fe8e822
+		 * We go through whole the option to check whether there are no
fe8e822
+		 * missing/extra bytes.
fe8e822
+		 * I didn't find out how to improve the existing code and that's the
fe8e822
+		 * reason for this separate 'else' where I do my own checkings.
fe8e822
+		 * I know it's little bit unsystematic, but it works.
fe8e822
+		 */
fe8e822
+		numhunk = 0;
fe8e822
+		numelem = 2; /* RI */
fe8e822
+		fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0;
fe8e822
+		for (i =0; i < len; i = i + octets + 5) {
fe8e822
+			if (data[i] > 32) { /* subnet mask width */
fe8e822
+				log_error ("wrong subnet mask width in destination descriptor");
fe8e822
+				break;
fe8e822
+			}
fe8e822
+			numhunk++;
fe8e822
+			octets = ((data[i]+7) / 8);
fe8e822
+		}
fe8e822
+		if (i != len) {
fe8e822
+			log_error ("classless static routes option has wrong size or "
fe8e822
+					   "there's some garbage in format");
fe8e822
+		}
fe8e822
+	}
fe8e822
+
fe8e822
 	/* Cycle through the array (or hunk) printing the data. */
fe8e822
 	for (i = 0; i < numhunk; i++) {
fe8e822
 		for (j = 0; j < numelem; j++) {
fe8e822
@@ -1978,6 +2011,20 @@ const char *pretty_print_option (option,
fe8e822
 				strcpy(op, piaddr(iaddr));
fe8e822
 				dp += 4;
fe8e822
 				break;
fe8e822
+
fe8e822
+			      case 'R':
fe8e822
+				if (dp[0] <= 32)
fe8e822
+					iaddr.len = (((dp[0]+7)/8)+1);
fe8e822
+				else {
fe8e822
+					log_error ("wrong subnet mask width in destination descriptor");
fe8e822
+					return "<error>";
fe8e822
+				}
fe8e822
+
fe8e822
+				memcpy(iaddr.iabuf, dp, iaddr.len);
fe8e822
+				strcpy(op, pdestdesc(iaddr));
fe8e822
+				dp += iaddr.len;
fe8e822
+				break;
fe8e822
+
fe8e822
 			      case '6':
fe8e822
 				iaddr.len = 16;
fe8e822
 				memcpy(iaddr.iabuf, dp, 16);
fe8e822
diff -up dhcp-4.2.0/common/parse.c.rfc3442 dhcp-4.2.0/common/parse.c
fe8e822
--- dhcp-4.2.0/common/parse.c.rfc3442	2010-08-31 10:12:51.000000000 +0200
fe8e822
+++ dhcp-4.2.0/common/parse.c	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -341,6 +341,39 @@ int parse_ip_addr (cfile, addr)
fe8e822
 }	
fe8e822
 
fe8e822
 /*
fe8e822
+ * destination-descriptor :== NUMBER DOT NUMBER |
fe8e822
+ *                            NUMBER DOT NUMBER DOT NUMBER |
fe8e822
+ *                            NUMBER DOT NUMBER DOT NUMBER DOT NUMBER |
fe8e822
+ *                            NUMBER DOT NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
fe8e822
+ */
fe8e822
+
fe8e822
+int parse_destination_descriptor (cfile, addr)
fe8e822
+	struct parse *cfile;
fe8e822
+	struct iaddr *addr;
fe8e822
+{
fe8e822
+		unsigned int mask_width, dest_dest_len;
fe8e822
+		addr -> len = 0;
fe8e822
+		if (parse_numeric_aggregate (cfile, addr -> iabuf,
fe8e822
+									 &addr -> len, DOT, 10, 8)) {
fe8e822
+			mask_width = (unsigned int)addr->iabuf[0];
fe8e822
+			dest_dest_len = (((mask_width+7)/8)+1);
fe8e822
+			if (mask_width > 32) {
fe8e822
+				parse_warn (cfile,
fe8e822
+				"subnet mask width (%u) greater than 32.", mask_width);
fe8e822
+			}
fe8e822
+			else if (dest_dest_len != addr->len) {
fe8e822
+				parse_warn (cfile,
fe8e822
+				"destination descriptor with subnet mask width %u "
fe8e822
+				"should have %u octets, but has %u octets.",
fe8e822
+				mask_width, dest_dest_len, addr->len);
fe8e822
+			}
fe8e822
+
fe8e822
+			return 1;
fe8e822
+		}
fe8e822
+		return 0;
fe8e822
+}
fe8e822
+
fe8e822
+/*
fe8e822
  * Return true if every character in the string is hexadecimal.
fe8e822
  */
fe8e822
 static int
fe8e822
@@ -707,8 +740,10 @@ unsigned char *parse_numeric_aggregate (
fe8e822
 		if (count) {
fe8e822
 			token = peek_token (&val, (unsigned *)0, cfile);
fe8e822
 			if (token != separator) {
fe8e822
-				if (!*max)
fe8e822
+				if (!*max) {
fe8e822
+					*max = count;
fe8e822
 					break;
fe8e822
+				}
fe8e822
 				if (token != RBRACE && token != LBRACE)
fe8e822
 					token = next_token (&val,
fe8e822
 							    (unsigned *)0,
fe8e822
@@ -1619,6 +1654,9 @@ int parse_option_code_definition (cfile,
fe8e822
 	      case IP_ADDRESS:
fe8e822
 		type = 'I';
fe8e822
 		break;
fe8e822
+	      case DESTINATION_DESCRIPTOR:
fe8e822
+		type = 'R';
fe8e822
+		break;
fe8e822
 	      case IP6_ADDRESS:
fe8e822
 		type = '6';
fe8e822
 		break;
fe8e822
@@ -5232,6 +5270,15 @@ int parse_option_token (rv, cfile, fmt, 
fe8e822
 		}
fe8e822
 		break;
fe8e822
 
fe8e822
+	      case 'R': /* destination descriptor */
fe8e822
+		if (!parse_destination_descriptor (cfile, &addr)) {
fe8e822
+			return 0;
fe8e822
+		}
fe8e822
+		if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) {
fe8e822
+			return 0;
fe8e822
+		}
fe8e822
+		break;
fe8e822
+
fe8e822
 	      case '6': /* IPv6 address. */
fe8e822
 		if (!parse_ip6_addr(cfile, &addr)) {
fe8e822
 			return 0;
fe8e822
@@ -5492,6 +5539,13 @@ int parse_option_decl (oc, cfile)
fe8e822
 					goto exit;
fe8e822
 				len = ip_addr.len;
fe8e822
 				dp = ip_addr.iabuf;
fe8e822
+				goto alloc;
fe8e822
+
fe8e822
+			      case 'R': /* destination descriptor */
fe8e822
+				if (!parse_destination_descriptor (cfile, &ip_addr))
fe8e822
+					goto exit;
fe8e822
+				len = ip_addr.len;
fe8e822
+				dp = ip_addr.iabuf;
fe8e822
 
fe8e822
 			      alloc:
fe8e822
 				if (hunkix + len > sizeof hunkbuf) {
fe8e822
diff -up dhcp-4.2.0/common/tables.c.rfc3442 dhcp-4.2.0/common/tables.c
fe8e822
--- dhcp-4.2.0/common/tables.c.rfc3442	2010-08-31 10:12:51.000000000 +0200
fe8e822
+++ dhcp-4.2.0/common/tables.c	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -51,6 +51,7 @@ HASH_FUNCTIONS (option_code, const unsig
fe8e822
    Format codes:
fe8e822
 
fe8e822
    I - IPv4 address
fe8e822
+   R - destination descriptor (RFC3442)
fe8e822
    6 - IPv6 address
fe8e822
    l - 32-bit signed integer
fe8e822
    L - 32-bit unsigned integer
fe8e822
@@ -208,6 +209,7 @@ static struct option dhcp_options[] = {
fe8e822
 	{ "default-url", "t",			&dhcp_universe, 114, 1 },
fe8e822
 	{ "subnet-selection", "I",		&dhcp_universe, 118, 1 },
fe8e822
 	{ "domain-search", "D",		&dhcp_universe, 119, 1 },
fe8e822
+	{ "classless-static-routes", "RIA",	&dhcp_universe, 121, 1 },
fe8e822
 	{ "vivco", "Evendor-class.",		&dhcp_universe, 124, 1 },
fe8e822
 	{ "vivso", "Evendor.",			&dhcp_universe, 125, 1 },
fe8e822
 #if 0
fe8e822
diff -up dhcp-4.2.0/includes/dhcpd.h.rfc3442 dhcp-4.2.0/includes/dhcpd.h
fe8e822
--- dhcp-4.2.0/includes/dhcpd.h.rfc3442	2010-08-31 10:12:51.000000000 +0200
fe8e822
+++ dhcp-4.2.0/includes/dhcpd.h	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -2638,6 +2638,7 @@ isc_result_t range2cidr(struct iaddrcidr
fe8e822
 			const struct iaddr *lo, const struct iaddr *hi);
fe8e822
 isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result);
fe8e822
 const char *piaddr PROTO ((struct iaddr));
fe8e822
+const char *pdestdesc PROTO ((struct iaddr));
fe8e822
 char *piaddrmask(struct iaddr *, struct iaddr *);
fe8e822
 char *piaddrcidr(const struct iaddr *, unsigned int);
fe8e822
 u_int16_t validate_port(char *);
fe8e822
@@ -2849,6 +2850,7 @@ void parse_client_lease_declaration PROT
fe8e822
 int parse_option_decl PROTO ((struct option_cache **, struct parse *));
fe8e822
 void parse_string_list PROTO ((struct parse *, struct string_list **, int));
fe8e822
 int parse_ip_addr PROTO ((struct parse *, struct iaddr *));
fe8e822
+int parse_destination_descriptor PROTO ((struct parse *, struct iaddr *));
fe8e822
 int parse_ip_addr_with_subnet(struct parse *, struct iaddrmatch *);
fe8e822
 void parse_reject_statement PROTO ((struct parse *, struct client_config *));
fe8e822
 
fe8e822
diff -up dhcp-4.2.0/includes/dhcp.h.rfc3442 dhcp-4.2.0/includes/dhcp.h
fe8e822
--- dhcp-4.2.0/includes/dhcp.h.rfc3442	2009-11-20 02:49:01.000000000 +0100
fe8e822
+++ dhcp-4.2.0/includes/dhcp.h	2010-08-31 10:13:49.000000000 +0200
fe8e822
@@ -158,6 +158,7 @@ struct dhcp_packet {
fe8e822
 #define DHO_ASSOCIATED_IP			92
fe8e822
 #define DHO_SUBNET_SELECTION			118 /* RFC3011! */
fe8e822
 #define DHO_DOMAIN_SEARCH			119 /* RFC3397 */
fe8e822
+#define DHO_CLASSLESS_STATIC_ROUTES		121 /* RFC3442 */
fe8e822
 #define DHO_VIVCO_SUBOPTIONS			124
fe8e822
 #define DHO_VIVSO_SUBOPTIONS			125
fe8e822
 
fe8e822
diff -up dhcp-4.2.0/includes/dhctoken.h.rfc3442 dhcp-4.2.0/includes/dhctoken.h
fe8e822
--- dhcp-4.2.0/includes/dhctoken.h.rfc3442	2010-08-31 10:12:51.000000000 +0200
fe8e822
+++ dhcp-4.2.0/includes/dhctoken.h	2010-08-31 10:15:39.000000000 +0200
fe8e822
@@ -358,7 +358,8 @@ enum dhcp_token {
fe8e822
 	AUTO_PARTNER_DOWN = 661,
fe8e822
 	GETHOSTNAME = 662,
fe8e822
 	REWIND = 663,
fe8e822
-	BOOTP_BROADCAST_ALWAYS = 664
fe8e822
+	BOOTP_BROADCAST_ALWAYS = 664,
fe8e822
+	DESTINATION_DESCRIPTOR = 666
fe8e822
 };
fe8e822
 
fe8e822
 #define is_identifier(x)	((x) >= FIRST_TOKEN &&	\