|
|
cab8d5 |
From 86e92f998379d219e10517dfa2c42f544ba164ce Mon Sep 17 00:00:00 2001
|
|
|
cab8d5 |
From: Simon Kelley <simon@thekelleys.org.uk>
|
|
|
cab8d5 |
Date: Tue, 23 Apr 2013 11:31:39 +0100
|
|
|
cab8d5 |
Subject: [PATCH] --dhcp-match et al now work with BOOTP as well as DHCP.
|
|
|
cab8d5 |
|
|
|
cab8d5 |
---
|
|
|
cab8d5 |
CHANGELOG | 4 ++
|
|
|
cab8d5 |
src/rfc2131.c | 227 +++++++++++++++++++++++++++++-----------------------------
|
|
|
cab8d5 |
2 files changed, 117 insertions(+), 114 deletions(-)
|
|
|
cab8d5 |
|
|
|
cab8d5 |
diff --git a/CHANGELOG b/CHANGELOG
|
|
|
cab8d5 |
index 268b64d..0a34b64 100644
|
|
|
cab8d5 |
--- a/CHANGELOG
|
|
|
cab8d5 |
+++ b/CHANGELOG
|
|
|
cab8d5 |
@@ -11,6 +11,10 @@ version 2.67
|
|
|
cab8d5 |
lease-time only if it's specifically requested
|
|
|
cab8d5 |
(maintaining standards) and the dhcp_lease_time utility
|
|
|
cab8d5 |
has been taught to ask for it (restoring functionality).
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
|
|
|
cab8d5 |
+ to work with BOOTP and well as DHCP. Thanks to Peter
|
|
|
cab8d5 |
+ Korsgaard for spotting the problem.
|
|
|
cab8d5 |
|
|
|
cab8d5 |
|
|
|
cab8d5 |
version 2.66
|
|
|
cab8d5 |
diff --git a/src/rfc2131.c b/src/rfc2131.c
|
|
|
cab8d5 |
index 013a446..54e444b 100644
|
|
|
cab8d5 |
--- a/src/rfc2131.c
|
|
|
cab8d5 |
+++ b/src/rfc2131.c
|
|
|
cab8d5 |
@@ -355,6 +355,117 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|
|
cab8d5 |
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
|
|
|
cab8d5 |
}
|
|
|
cab8d5 |
}
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
|
|
cab8d5 |
+ Otherwise assume the option is an array, and look for a matching element.
|
|
|
cab8d5 |
+ If no data given, existance of the option is enough. This code handles
|
|
|
cab8d5 |
+ rfc3925 V-I classes too. */
|
|
|
cab8d5 |
+ for (o = daemon->dhcp_match; o; o = o->next)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ unsigned int len, elen, match = 0;
|
|
|
cab8d5 |
+ size_t offset, o2;
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ if (o->flags & DHOPT_RFC3925)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
|
|
cab8d5 |
+ continue;
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ len = option_uint(opt, offset + 4 , 1);
|
|
|
cab8d5 |
+ /* Need to take care that bad data can't run us off the end of the packet */
|
|
|
cab8d5 |
+ if ((offset + len + 5 <= (option_len(opt))) &&
|
|
|
cab8d5 |
+ (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
|
|
cab8d5 |
+ for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ elen = option_uint(opt, o2, 1);
|
|
|
cab8d5 |
+ if ((o2 + elen + 1 <= option_len(opt)) &&
|
|
|
cab8d5 |
+ (match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
|
|
cab8d5 |
+ break;
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ if (match)
|
|
|
cab8d5 |
+ break;
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ else
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ if (!(opt = option_find(mess, sz, o->opt, 1)))
|
|
|
cab8d5 |
+ continue;
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ if (match)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ o->netid->next = netid;
|
|
|
cab8d5 |
+ netid = o->netid;
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ /* user-class options are, according to RFC3004, supposed to contain
|
|
|
cab8d5 |
+ a set of counted strings. Here we check that this is so (by seeing
|
|
|
cab8d5 |
+ if the counts are consistent with the overall option length) and if
|
|
|
cab8d5 |
+ so zero the counts so that we don't get spurious matches between
|
|
|
cab8d5 |
+ the vendor string and the counts. If the lengths don't add up, we
|
|
|
cab8d5 |
+ assume that the option is a single string and non RFC3004 compliant
|
|
|
cab8d5 |
+ and just do the substring match. dhclient provides these broken options.
|
|
|
cab8d5 |
+ The code, later, which sends user-class data to the lease-change script
|
|
|
cab8d5 |
+ relies on the transformation done here.
|
|
|
cab8d5 |
+ */
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ unsigned char *ucp = option_ptr(opt, 0);
|
|
|
cab8d5 |
+ int tmp, j;
|
|
|
cab8d5 |
+ for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
|
|
cab8d5 |
+ if (j == option_len(opt))
|
|
|
cab8d5 |
+ for (j = 0; j < option_len(opt); j = tmp)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ tmp = j + ucp[j] + 1;
|
|
|
cab8d5 |
+ ucp[j] = 0;
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ int mopt;
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ if (vendor->match_type == MATCH_VENDOR)
|
|
|
cab8d5 |
+ mopt = OPTION_VENDOR_ID;
|
|
|
cab8d5 |
+ else if (vendor->match_type == MATCH_USER)
|
|
|
cab8d5 |
+ mopt = OPTION_USER_CLASS;
|
|
|
cab8d5 |
+ else
|
|
|
cab8d5 |
+ continue;
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ if ((opt = option_find(mess, sz, mopt, 1)))
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ int i;
|
|
|
cab8d5 |
+ for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
|
|
cab8d5 |
+ if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ vendor->netid.next = netid;
|
|
|
cab8d5 |
+ netid = &vendor->netid;
|
|
|
cab8d5 |
+ break;
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ /* mark vendor-encapsulated options which match the client-supplied vendor class,
|
|
|
cab8d5 |
+ save client-supplied vendor class */
|
|
|
cab8d5 |
+ if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
|
|
cab8d5 |
+ vendor_class_len = option_len(opt);
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
+ match_vendor_opts(opt, daemon->dhcp_opts);
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
+ if (option_bool(OPT_LOG_OPTS))
|
|
|
cab8d5 |
+ {
|
|
|
cab8d5 |
+ if (sanitise(opt, daemon->namebuff))
|
|
|
cab8d5 |
+ my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
|
|
cab8d5 |
+ if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
|
|
cab8d5 |
+ my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
|
|
cab8d5 |
+ }
|
|
|
cab8d5 |
|
|
|
cab8d5 |
mess->op = BOOTREPLY;
|
|
|
cab8d5 |
|
|
|
cab8d5 |
@@ -494,9 +605,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|
|
cab8d5 |
lease_set_interface(lease, int_index, now);
|
|
|
cab8d5 |
|
|
|
cab8d5 |
clear_packet(mess, end);
|
|
|
cab8d5 |
- match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
|
|
|
cab8d5 |
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
|
|
cab8d5 |
- netid, subnet_addr, 0, 0, -1, NULL, 0, now);
|
|
|
cab8d5 |
+ netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
|
|
|
cab8d5 |
}
|
|
|
cab8d5 |
}
|
|
|
cab8d5 |
|
|
|
cab8d5 |
@@ -623,119 +733,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|
|
cab8d5 |
}
|
|
|
cab8d5 |
}
|
|
|
cab8d5 |
|
|
|
cab8d5 |
- /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
|
|
cab8d5 |
- Otherwise assume the option is an array, and look for a matching element.
|
|
|
cab8d5 |
- If no data given, existance of the option is enough. This code handles
|
|
|
cab8d5 |
- rfc3925 V-I classes too. */
|
|
|
cab8d5 |
- for (o = daemon->dhcp_match; o; o = o->next)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- unsigned int len, elen, match = 0;
|
|
|
cab8d5 |
- size_t offset, o2;
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- if (o->flags & DHOPT_RFC3925)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
|
|
cab8d5 |
- continue;
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- len = option_uint(opt, offset + 4 , 1);
|
|
|
cab8d5 |
- /* Need to take care that bad data can't run us off the end of the packet */
|
|
|
cab8d5 |
- if ((offset + len + 5 <= (option_len(opt))) &&
|
|
|
cab8d5 |
- (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
|
|
cab8d5 |
- for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- elen = option_uint(opt, o2, 1);
|
|
|
cab8d5 |
- if ((o2 + elen + 1 <= option_len(opt)) &&
|
|
|
cab8d5 |
- (match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
|
|
cab8d5 |
- break;
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- if (match)
|
|
|
cab8d5 |
- break;
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- else
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- if (!(opt = option_find(mess, sz, o->opt, 1)))
|
|
|
cab8d5 |
- continue;
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- if (match)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- o->netid->next = netid;
|
|
|
cab8d5 |
- netid = o->netid;
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- /* user-class options are, according to RFC3004, supposed to contain
|
|
|
cab8d5 |
- a set of counted strings. Here we check that this is so (by seeing
|
|
|
cab8d5 |
- if the counts are consistent with the overall option length) and if
|
|
|
cab8d5 |
- so zero the counts so that we don't get spurious matches between
|
|
|
cab8d5 |
- the vendor string and the counts. If the lengths don't add up, we
|
|
|
cab8d5 |
- assume that the option is a single string and non RFC3004 compliant
|
|
|
cab8d5 |
- and just do the substring match. dhclient provides these broken options.
|
|
|
cab8d5 |
- The code, later, which sends user-class data to the lease-change script
|
|
|
cab8d5 |
- relies on the transformation done here.
|
|
|
cab8d5 |
- */
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- unsigned char *ucp = option_ptr(opt, 0);
|
|
|
cab8d5 |
- int tmp, j;
|
|
|
cab8d5 |
- for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
|
|
cab8d5 |
- if (j == option_len(opt))
|
|
|
cab8d5 |
- for (j = 0; j < option_len(opt); j = tmp)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- tmp = j + ucp[j] + 1;
|
|
|
cab8d5 |
- ucp[j] = 0;
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- int mopt;
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- if (vendor->match_type == MATCH_VENDOR)
|
|
|
cab8d5 |
- mopt = OPTION_VENDOR_ID;
|
|
|
cab8d5 |
- else if (vendor->match_type == MATCH_USER)
|
|
|
cab8d5 |
- mopt = OPTION_USER_CLASS;
|
|
|
cab8d5 |
- else
|
|
|
cab8d5 |
- continue;
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- if ((opt = option_find(mess, sz, mopt, 1)))
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- int i;
|
|
|
cab8d5 |
- for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
|
|
cab8d5 |
- if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- vendor->netid.next = netid;
|
|
|
cab8d5 |
- netid = &vendor->netid;
|
|
|
cab8d5 |
- break;
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- /* mark vendor-encapsulated options which match the client-supplied vendor class,
|
|
|
cab8d5 |
- save client-supplied vendor class */
|
|
|
cab8d5 |
- if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
|
|
cab8d5 |
- vendor_class_len = option_len(opt);
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
- match_vendor_opts(opt, daemon->dhcp_opts);
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
- if (option_bool(OPT_LOG_OPTS))
|
|
|
cab8d5 |
- {
|
|
|
cab8d5 |
- if (sanitise(opt, daemon->namebuff))
|
|
|
cab8d5 |
- my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
|
|
cab8d5 |
- if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
|
|
cab8d5 |
- my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
|
|
cab8d5 |
- }
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
tagif_netid = run_tag_if(netid);
|
|
|
cab8d5 |
-
|
|
|
cab8d5 |
+
|
|
|
cab8d5 |
/* if all the netids in the ignore list are present, ignore this client */
|
|
|
cab8d5 |
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
|
|
cab8d5 |
if (match_netid(id_list->list, tagif_netid, 0))
|
|
|
cab8d5 |
--
|
|
|
cab8d5 |
1.8.1.4
|
|
|
cab8d5 |
|