diff --git a/src/dnsmasq.h b/src/dnsmasq.h index e0d33f6..3068f5f 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -566,7 +566,8 @@ struct pxe_service { /* vendorclass, userclass, remote-id or cicuit-id */ struct dhcp_vendor { - int len, match_type, option; + int len, match_type; + unsigned int enterprise; char *data; struct dhcp_netid netid; struct dhcp_vendor *next; diff --git a/src/helper.c b/src/helper.c index db5f097..4e92d25 100644 --- a/src/helper.c +++ b/src/helper.c @@ -467,11 +467,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err); #ifdef HAVE_DHCP6 else - for (i = 0; i < data.hwaddr_len; i++) - { - sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i); - buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err); - } + { + if (data.hwaddr_len != 0) + { + buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err); + for (i = 0; i < data.hwaddr_len - 1; i++) + { + sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i); + buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err); + } + } + } #endif buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err); diff --git a/src/option.c b/src/option.c index a9abbc7..2840670 100644 --- a/src/option.c +++ b/src/option.c @@ -2870,6 +2870,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) new->netid.net = opt_string_alloc(set_prefix(arg)); /* check for hex string - must digits may include : must not have nothing else, only allowed for agent-options. */ + + arg = comma; + if ((comma = split(arg))) + { + if (option != 'U' || strstr(arg, "enterprise:") != arg) + option = '?'; + else + new->enterprise = atoi(arg+11); + } + else + comma = arg; + for (p = (unsigned char *)comma; *p; p++) if (isxdigit(*p)) dig = 1; diff --git a/src/rfc3315.c b/src/rfc3315.c index 8e0f1cc..7f5c35f 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -269,7 +269,20 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, struct dhcp_con if ((opt = opt6_find(packet_options, end, mopt, 2))) { void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt)); - for (enc_opt = opt6_ptr(opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) + int offset = 0; + + if (mopt == OPTION6_VENDOR_CLASS) + { + if (opt6_len(opt) < 4) + continue; + + if (vendor->enterprise != opt6_uint(opt, 0, 4)) + continue; + + offset = 4; + } + + for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) for (i = 0; i <= (opt6_len(enc_opt) - vendor->len); i++) if (memcmp(vendor->data, opt6_ptr(enc_opt, i), vendor->len) == 0) { @@ -620,14 +633,20 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, struct dhcp_con lease->extradata_size = lease->extradata_len = 0; lease->hwaddr_len = 0; /* surrogate for no of vendor classes */ - if ((class_opt = opt6_find(packet_options, end, OPTION6_VENDOR_CLASS, 2))) + if ((class_opt = opt6_find(packet_options, end, OPTION6_VENDOR_CLASS, 4))) { void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt)); - for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) - { - lease->hwaddr_len++; - lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0); - } + lease->hwaddr_len++; + /* send enterprise number first */ + sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4)); + lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0); + + if (opt6_len(class_opt) >= 6) + for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end)) + { + lease->hwaddr_len++; + lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0); + } } lease_add_extradata(lease, (unsigned char *)client_hostname,