mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-24 12:48:32 +00:00
pxe: support pxe clients with custom vendor-class
From 606d638918edb0e0ec07fe27eb68d06fb5ebd981 Mon Sep 17 00:00:00 2001 From: Miao Wang <shankerwangmiao@gmail.com> Date: Fri, 4 Dec 2020 09:59:37 +0800 Subject: [PATCH v2] pxe: support pxe clients with custom vendor-class According to UEFI[1] and PXE[2] specs, PXE clients are required to have `PXEClient` identfier in the vendor-class field of DHCP requests, and PXE servers should also include that identifier in their responses. However, the firmware of servers from a few vendors[3] are customized to include a different identifier. This patch adds an option named `dhcp-pxe-vendor` to provide a list of such identifiers. The identifier used in responses sent from dnsmasq is identical to that in the coresponding request. [1]: https://uefi.org/sites/default/files/resources/UEFI%20Spec%202.8B%20May%202020.pdf [2]: http://www.pix.net/software/pxeboot/archive/pxespec.pdf [3]: For instance, TaiShan servers from Huawei, which are Arm64-based, send `HW-Client` in PXE requests up to now. Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
This commit is contained in:
committed by
Simon Kelley
parent
f60fea1fb0
commit
4ded96209e
@@ -1481,6 +1481,22 @@ to allow netbooting. This mode is enabled using the
|
|||||||
keyword in
|
keyword in
|
||||||
.B --dhcp-range.
|
.B --dhcp-range.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-pxe-vendor=<vendor>[,...]
|
||||||
|
According to UEFI and PXE specifications, DHCP packets between PXE clients and
|
||||||
|
proxy PXE servers should have
|
||||||
|
.I PXEClient
|
||||||
|
in their vendor-class field. However, the firmware of computers from a few
|
||||||
|
vendors is customized to carry a different identifier in that field. This option
|
||||||
|
is used to consider such identifiers valid for identifying PXE clients. For
|
||||||
|
instance
|
||||||
|
|
||||||
|
.B --dhcp-pxe-vendor=PXEClient,HW-Client
|
||||||
|
|
||||||
|
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
|
||||||
|
.I HW-Client
|
||||||
|
in as their identifier.
|
||||||
|
>>>>>>> 907def3... pxe: support pxe clients with custom vendor-class
|
||||||
|
.TP
|
||||||
.B \-X, --dhcp-lease-max=<number>
|
.B \-X, --dhcp-lease-max=<number>
|
||||||
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||||
default is 1000. This limit is to prevent DoS attacks from hosts which
|
default is 1000. This limit is to prevent DoS attacks from hosts which
|
||||||
|
|||||||
@@ -829,6 +829,7 @@ struct dhcp_opt {
|
|||||||
#define DHOPT_RFC3925 2048
|
#define DHOPT_RFC3925 2048
|
||||||
#define DHOPT_TAGOK 4096
|
#define DHOPT_TAGOK 4096
|
||||||
#define DHOPT_ADDR6 8192
|
#define DHOPT_ADDR6 8192
|
||||||
|
#define DHOPT_VENDOR_PXE 16384
|
||||||
|
|
||||||
struct dhcp_boot {
|
struct dhcp_boot {
|
||||||
char *file, *sname, *tftp_sname;
|
char *file, *sname, *tftp_sname;
|
||||||
@@ -852,6 +853,8 @@ struct pxe_service {
|
|||||||
struct pxe_service *next;
|
struct pxe_service *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DHCP_PXE_DEF_VENDOR "PXEClient"
|
||||||
|
|
||||||
#define MATCH_VENDOR 1
|
#define MATCH_VENDOR 1
|
||||||
#define MATCH_USER 2
|
#define MATCH_USER 2
|
||||||
#define MATCH_CIRCUIT 3
|
#define MATCH_CIRCUIT 3
|
||||||
@@ -867,6 +870,11 @@ struct dhcp_vendor {
|
|||||||
struct dhcp_vendor *next;
|
struct dhcp_vendor *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dhcp_pxe_vendor {
|
||||||
|
char *data;
|
||||||
|
struct dhcp_pxe_vendor *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct dhcp_mac {
|
struct dhcp_mac {
|
||||||
unsigned int mask;
|
unsigned int mask;
|
||||||
int hwaddr_len, hwaddr_type;
|
int hwaddr_len, hwaddr_type;
|
||||||
@@ -1040,6 +1048,7 @@ extern struct daemon {
|
|||||||
struct dhcp_config *dhcp_conf;
|
struct dhcp_config *dhcp_conf;
|
||||||
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
|
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
|
||||||
struct dhcp_match_name *dhcp_name_match;
|
struct dhcp_match_name *dhcp_name_match;
|
||||||
|
struct dhcp_pxe_vendor *dhcp_pxe_vendors;
|
||||||
struct dhcp_vendor *dhcp_vendors;
|
struct dhcp_vendor *dhcp_vendors;
|
||||||
struct dhcp_mac *dhcp_macs;
|
struct dhcp_mac *dhcp_macs;
|
||||||
struct dhcp_boot *boot_config;
|
struct dhcp_boot *boot_config;
|
||||||
|
|||||||
27
src/option.c
27
src/option.c
@@ -167,6 +167,7 @@ struct myoption {
|
|||||||
#define LOPT_IGNORE_CLID 358
|
#define LOPT_IGNORE_CLID 358
|
||||||
#define LOPT_SINGLE_PORT 359
|
#define LOPT_SINGLE_PORT 359
|
||||||
#define LOPT_SCRIPT_TIME 360
|
#define LOPT_SCRIPT_TIME 360
|
||||||
|
#define LOPT_PXE_VENDOR 361
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -270,6 +271,7 @@ static const struct myoption opts[] =
|
|||||||
{ "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
|
{ "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
|
||||||
{ "dhcp-remoteid", 1, 0, LOPT_REMOTE },
|
{ "dhcp-remoteid", 1, 0, LOPT_REMOTE },
|
||||||
{ "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
|
{ "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
|
||||||
|
{ "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
|
||||||
{ "interface-name", 1, 0, LOPT_INTNAME },
|
{ "interface-name", 1, 0, LOPT_INTNAME },
|
||||||
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
|
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
|
||||||
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
|
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
|
||||||
@@ -383,6 +385,7 @@ static struct {
|
|||||||
{ LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
|
{ LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
|
||||||
{ LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
|
{ LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
|
||||||
{ LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
|
{ LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
|
||||||
|
{ LOPT_PXE_VENDOR, ARG_DUP, "<vendor>[,...]", gettext_noop("Specify vendor class to match for PXE requests."), NULL },
|
||||||
{ 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
|
{ 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
|
||||||
{ LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
|
{ LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
|
||||||
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
|
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
|
||||||
@@ -3672,8 +3675,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
new->val = opt_malloc(new->len);
|
new->val = opt_malloc(new->len);
|
||||||
memcpy(new->val + 1, arg, new->len - 1);
|
memcpy(new->val + 1, arg, new->len - 1);
|
||||||
|
|
||||||
new->u.vendor_class = (unsigned char *)"PXEClient";
|
new->u.vendor_class = NULL;
|
||||||
new->flags = DHOPT_VENDOR;
|
new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE;
|
||||||
|
|
||||||
if (comma && atoi_check(comma, &timeout))
|
if (comma && atoi_check(comma, &timeout))
|
||||||
*(new->val) = timeout;
|
*(new->val) = timeout;
|
||||||
@@ -3938,6 +3941,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LOPT_PXE_VENDOR: /* --dhcp-pxe-vendor */
|
||||||
|
{
|
||||||
|
while (arg) {
|
||||||
|
struct dhcp_pxe_vendor *new = opt_malloc(sizeof(struct dhcp_pxe_vendor));
|
||||||
|
comma = split(arg);
|
||||||
|
new->data = opt_string_alloc(arg);
|
||||||
|
new->next = daemon->dhcp_pxe_vendors;
|
||||||
|
daemon->dhcp_pxe_vendors = new;
|
||||||
|
arg = comma;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case LOPT_RELAY: /* --dhcp-relay */
|
case LOPT_RELAY: /* --dhcp-relay */
|
||||||
{
|
{
|
||||||
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
||||||
@@ -5213,6 +5229,13 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||||||
daemon->hostmaster = opt_string_alloc(buff);
|
daemon->hostmaster = opt_string_alloc(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!daemon->dhcp_pxe_vendors)
|
||||||
|
{
|
||||||
|
daemon->dhcp_pxe_vendors = opt_malloc(sizeof(struct dhcp_pxe_vendor));
|
||||||
|
daemon->dhcp_pxe_vendors->data = opt_string_alloc(DHCP_PXE_DEF_VENDOR);
|
||||||
|
daemon->dhcp_pxe_vendors->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* only one of these need be specified: the other defaults to the host-name */
|
/* only one of these need be specified: the other defaults to the host-name */
|
||||||
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
|
|||||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
||||||
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
|
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
|
||||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
||||||
int opt, char *string, int null_term);
|
int opt, const char *string, int null_term);
|
||||||
static struct in_addr option_addr(unsigned char *opt);
|
static struct in_addr option_addr(unsigned char *opt);
|
||||||
static unsigned int option_uint(unsigned char *opt, int offset, int size);
|
static unsigned int option_uint(unsigned char *opt, int offset, int size);
|
||||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||||
@@ -54,17 +54,19 @@ static void do_options(struct dhcp_context *context,
|
|||||||
int vendor_class_len,
|
int vendor_class_len,
|
||||||
time_t now,
|
time_t now,
|
||||||
unsigned int lease_time,
|
unsigned int lease_time,
|
||||||
unsigned short fuzz);
|
unsigned short fuzz,
|
||||||
|
const char *pxevendor);
|
||||||
|
|
||||||
|
|
||||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||||
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
|
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
|
||||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
|
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor);
|
||||||
static int prune_vendor_opts(struct dhcp_netid *netid);
|
static int prune_vendor_opts(struct dhcp_netid *netid);
|
||||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
|
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
|
||||||
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
||||||
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
|
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
|
||||||
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
|
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
|
||||||
|
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor);
|
||||||
|
|
||||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||||
size_t sz, time_t now, int unicast_dest, int loopback,
|
size_t sz, time_t now, int unicast_dest, int loopback,
|
||||||
@@ -76,6 +78,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
struct dhcp_mac *mac;
|
struct dhcp_mac *mac;
|
||||||
struct dhcp_netid_list *id_list;
|
struct dhcp_netid_list *id_list;
|
||||||
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
|
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
|
||||||
|
const char *pxevendor = NULL;
|
||||||
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||||
unsigned char *end = (unsigned char *)(mess + 1);
|
unsigned char *end = (unsigned char *)(mess + 1);
|
||||||
unsigned char *real_end = (unsigned char *)(mess + 1);
|
unsigned char *real_end = (unsigned char *)(mess + 1);
|
||||||
@@ -647,7 +650,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
clear_packet(mess, end);
|
clear_packet(mess, end);
|
||||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
|
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -836,8 +839,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
/* Check if client is PXE client. */
|
/* Check if client is PXE client. */
|
||||||
if (daemon->enable_pxe &&
|
if (daemon->enable_pxe &&
|
||||||
(opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
|
is_pxe_client(mess, sz, &pxevendor))
|
||||||
strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
|
|
||||||
{
|
{
|
||||||
if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
|
if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
|
||||||
{
|
{
|
||||||
@@ -899,7 +901,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||||
pxe_misc(mess, end, uuid);
|
pxe_misc(mess, end, uuid, pxevendor);
|
||||||
|
|
||||||
prune_vendor_opts(tagif_netid);
|
prune_vendor_opts(tagif_netid);
|
||||||
opt71.val = save71;
|
opt71.val = save71;
|
||||||
@@ -979,7 +981,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
|
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
|
||||||
pxe_misc(mess, end, uuid);
|
pxe_misc(mess, end, uuid, pxevendor);
|
||||||
prune_vendor_opts(tagif_netid);
|
prune_vendor_opts(tagif_netid);
|
||||||
if ((pxe && !workaround) || !redirect4011)
|
if ((pxe && !workaround) || !redirect4011)
|
||||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||||
@@ -1150,7 +1152,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||||
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
|
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
|
||||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
|
||||||
|
|
||||||
return dhcp_packet_size(mess, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
|
|
||||||
@@ -1499,7 +1501,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
if (rapid_commit)
|
if (rapid_commit)
|
||||||
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
|
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
|
||||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dhcp_packet_size(mess, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
@@ -1566,7 +1568,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
|
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor);
|
||||||
|
|
||||||
*is_inform = 1; /* handle reply differently */
|
*is_inform = 1; /* handle reply differently */
|
||||||
return dhcp_packet_size(mess, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
@@ -1948,7 +1950,7 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
|
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
|
||||||
char *string, int null_term)
|
const char *string, int null_term)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
size_t len = strlen(string);
|
size_t len = strlen(string);
|
||||||
@@ -2026,11 +2028,27 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
|
|||||||
dopt->flags &= ~DHOPT_VENDOR_MATCH;
|
dopt->flags &= ~DHOPT_VENDOR_MATCH;
|
||||||
if (opt && (dopt->flags & DHOPT_VENDOR))
|
if (opt && (dopt->flags & DHOPT_VENDOR))
|
||||||
{
|
{
|
||||||
int i, len = 0;
|
const struct dhcp_pxe_vendor *pv;
|
||||||
if (dopt->u.vendor_class)
|
struct dhcp_pxe_vendor dummy_vendor = {
|
||||||
len = strlen((char *)dopt->u.vendor_class);
|
.data = (char *)dopt->u.vendor_class,
|
||||||
|
.next = NULL,
|
||||||
|
};
|
||||||
|
if (dopt->flags & DHOPT_VENDOR_PXE)
|
||||||
|
pv = daemon->dhcp_pxe_vendors;
|
||||||
|
else
|
||||||
|
pv = &dummy_vendor;
|
||||||
|
for (; pv; pv = pv->next)
|
||||||
|
{
|
||||||
|
int i, len = 0, matched = 0;
|
||||||
|
if (pv->data)
|
||||||
|
len = strlen(pv->data);
|
||||||
for (i = 0; i <= (option_len(opt) - len); i++)
|
for (i = 0; i <= (option_len(opt) - len); i++)
|
||||||
if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
|
if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0)
|
||||||
|
{
|
||||||
|
matched = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (matched)
|
||||||
{
|
{
|
||||||
dopt->flags |= DHOPT_VENDOR_MATCH;
|
dopt->flags |= DHOPT_VENDOR_MATCH;
|
||||||
break;
|
break;
|
||||||
@@ -2038,6 +2056,7 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
|
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
|
||||||
struct dhcp_packet *mess, unsigned char *end, int null_term)
|
struct dhcp_packet *mess, unsigned char *end, int null_term)
|
||||||
@@ -2087,11 +2106,13 @@ static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
|
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
|
||||||
option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
|
if (!pxevendor)
|
||||||
|
pxevendor="PXEClient";
|
||||||
|
option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
|
||||||
if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
|
if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
|
||||||
memcpy(p, uuid, 17);
|
memcpy(p, uuid, 17);
|
||||||
}
|
}
|
||||||
@@ -2308,6 +2329,29 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid)
|
|||||||
return boot;
|
return boot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor)
|
||||||
|
{
|
||||||
|
const unsigned char *opt = NULL;
|
||||||
|
ssize_t conf_len = 0;
|
||||||
|
const struct dhcp_pxe_vendor *conf = daemon->dhcp_pxe_vendors;
|
||||||
|
opt = option_find(mess, sz, OPTION_VENDOR_ID, 0);
|
||||||
|
if (!opt)
|
||||||
|
return 0;
|
||||||
|
for (; conf; conf = conf->next)
|
||||||
|
{
|
||||||
|
conf_len = strlen(conf->data);
|
||||||
|
if (option_len(opt) < conf_len)
|
||||||
|
continue;
|
||||||
|
if (strncmp(option_ptr(opt, 0), conf->data, conf_len) == 0)
|
||||||
|
{
|
||||||
|
if (pxe_vendor)
|
||||||
|
*pxe_vendor = conf->data;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void do_options(struct dhcp_context *context,
|
static void do_options(struct dhcp_context *context,
|
||||||
struct dhcp_packet *mess,
|
struct dhcp_packet *mess,
|
||||||
unsigned char *end,
|
unsigned char *end,
|
||||||
@@ -2322,7 +2366,8 @@ static void do_options(struct dhcp_context *context,
|
|||||||
int vendor_class_len,
|
int vendor_class_len,
|
||||||
time_t now,
|
time_t now,
|
||||||
unsigned int lease_time,
|
unsigned int lease_time,
|
||||||
unsigned short fuzz)
|
unsigned short fuzz,
|
||||||
|
const char *pxevendor)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||||
struct dhcp_boot *boot;
|
struct dhcp_boot *boot;
|
||||||
@@ -2696,7 +2741,7 @@ static void do_options(struct dhcp_context *context,
|
|||||||
|
|
||||||
if (context && pxe_arch != -1)
|
if (context && pxe_arch != -1)
|
||||||
{
|
{
|
||||||
pxe_misc(mess, end, uuid);
|
pxe_misc(mess, end, uuid, pxevendor);
|
||||||
if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
|
if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
|
||||||
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
|
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user