mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.52.tar.gz
This commit is contained in:
418
src/rfc2131.c
418
src/rfc2131.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -54,6 +54,8 @@
|
||||
#define OPTION_ARCH 93
|
||||
#define OPTION_PXE_UUID 97
|
||||
#define OPTION_SUBNET_SELECT 118
|
||||
#define OPTION_VENDOR_IDENT 124
|
||||
#define OPTION_VENDOR_IDENT_OPT 125
|
||||
#define OPTION_END 255
|
||||
|
||||
#define SUBOPT_CIRCUIT_ID 1
|
||||
@@ -77,10 +79,17 @@
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
|
||||
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
||||
|
||||
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
|
||||
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
|
||||
#endif
|
||||
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
static int sanitise(unsigned char *opt, char *buf);
|
||||
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
|
||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
||||
@@ -114,12 +123,12 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||
static void do_encap_opts(struct dhcp_opt *opts, 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 int prune_vendor_opts(struct dhcp_netid *netid);
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid);
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local);
|
||||
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
||||
|
||||
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform)
|
||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe)
|
||||
{
|
||||
unsigned char *opt, *clid = NULL;
|
||||
struct dhcp_lease *ltmp, *lease = NULL;
|
||||
@@ -144,9 +153,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
unsigned char *agent_id = NULL, *uuid = NULL;
|
||||
unsigned char *emac = NULL;
|
||||
int emac_len = 0;
|
||||
struct dhcp_netid known_id, iface_id;
|
||||
struct dhcp_netid known_id, iface_id, cpewan_id;
|
||||
struct dhcp_opt *o;
|
||||
unsigned char pxe_uuid[17];
|
||||
unsigned char *oui = NULL, *serial = NULL, *class = NULL;
|
||||
|
||||
subnet_addr.s_addr = override.s_addr = 0;
|
||||
|
||||
@@ -194,6 +204,35 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
|
||||
mess->ciaddr.s_addr = 0;
|
||||
|
||||
/* search for device identity from CPEWAN devices, we pass this through to the script */
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_IDENT_OPT, 5)))
|
||||
{
|
||||
unsigned int elen, offset, len = option_len(opt);
|
||||
|
||||
for (offset = 0; offset < (len - 5); offset += elen + 5)
|
||||
{
|
||||
elen = option_uint(opt, offset + 4 , 1);
|
||||
if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
|
||||
{
|
||||
unsigned char *x = option_ptr(opt, offset + 5);
|
||||
unsigned char *y = option_ptr(opt, offset + elen + 5);
|
||||
oui = option_find1(x, y, 1, 1);
|
||||
serial = option_find1(x, y, 2, 1);
|
||||
class = option_find1(x, y, 3, 1);
|
||||
|
||||
/* If TR069-id is present set the tag "cpewan-id" to facilitate echoing
|
||||
the gateway id back. Note that the device class is optional */
|
||||
if (oui && serial)
|
||||
{
|
||||
cpewan_id.net = "cpewan-id";
|
||||
cpewan_id.next = netid;
|
||||
netid = &cpewan_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
|
||||
{
|
||||
/* Any agent-id needs to be copied back out, verbatim, as the last option
|
||||
@@ -370,7 +409,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
netid = &known_id;
|
||||
}
|
||||
|
||||
if (mess_type == 0)
|
||||
if (mess_type == 0 && !pxe)
|
||||
{
|
||||
/* BOOTP request */
|
||||
struct dhcp_netid id, bootp_id;
|
||||
@@ -601,38 +640,44 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
||||
Otherwise assume the option is an array, and look for a matching element.
|
||||
If no data given, existance of the option is enough. */
|
||||
If no data given, existance of the option is enough. This code handles
|
||||
rfc3925 V-I classes too. */
|
||||
for (o = daemon->dhcp_match; o; o = o->next)
|
||||
{
|
||||
int i, matched = 0;
|
||||
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)) ||
|
||||
o->len > option_len(opt))
|
||||
continue;
|
||||
|
||||
if (o->len == 0)
|
||||
matched = 1;
|
||||
else if (o->flags & DHOPT_HEX)
|
||||
{
|
||||
if (memcmp_masked(o->val, option_ptr(opt, 0), o->len, o->u.wildcard_mask))
|
||||
matched = 1;
|
||||
}
|
||||
else
|
||||
for (i = 0; i <= (option_len(opt) - o->len); )
|
||||
{
|
||||
if (memcmp(o->val, option_ptr(opt, i), o->len) == 0)
|
||||
{
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
unsigned int len, elen, match = 0;
|
||||
size_t offset, o2;
|
||||
|
||||
if (o->flags & DHOPT_STRING)
|
||||
i++;
|
||||
else
|
||||
i += o->len;
|
||||
}
|
||||
|
||||
if (matched)
|
||||
if (o->flags & DHOPT_RFC3925)
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
||||
continue;
|
||||
|
||||
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
||||
{
|
||||
len = option_uint(opt, offset + 4 , 1);
|
||||
/* Need to take care that bad data can't run us off the end of the packet */
|
||||
if ((offset + len + 5 <= (option_len(opt))) &&
|
||||
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)))
|
||||
continue;
|
||||
|
||||
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
o->netid->next = netid;
|
||||
netid = o->netid;
|
||||
@@ -778,8 +823,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
{
|
||||
pxearch = option_uint(opt, 0, 2);
|
||||
|
||||
/* proxy DHCP here. The DHCPREQUEST stuff is for gPXE */
|
||||
if ((mess_type == DHCPDISCOVER || mess_type == DHCPREQUEST) &&
|
||||
/* proxy DHCP here. */
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)) &&
|
||||
(context->flags & CONTEXT_PROXY))
|
||||
{
|
||||
struct dhcp_boot *boot = find_boot(netid);
|
||||
@@ -809,16 +854,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(netid);
|
||||
do_encap_opts(pxe_opts(pxearch, netid), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
do_encap_opts(pxe_opts(pxearch, netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy" : "proxy-ignored", mess->xid);
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
return ignore ? 0 : dhcp_packet_size(mess, netid, agent_id, real_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if we're just a proxy server, go no further */
|
||||
if (context->flags & CONTEXT_PROXY)
|
||||
if ((context->flags & CONTEXT_PROXY) || pxe)
|
||||
return 0;
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
|
||||
@@ -1135,13 +1180,37 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (do_classes)
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (do_classes && daemon->lease_change_command)
|
||||
{
|
||||
struct dhcp_netid *n;
|
||||
|
||||
if (mess->giaddr.s_addr)
|
||||
lease->giaddr = mess->giaddr;
|
||||
|
||||
lease->changed = 1;
|
||||
/* copy user-class and vendor class into new lease, for the script */
|
||||
free(lease->extradata);
|
||||
lease->extradata_size = lease->extradata_len = 0;
|
||||
|
||||
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
|
||||
add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
|
||||
add_extradata_opt(lease, oui);
|
||||
add_extradata_opt(lease, serial);
|
||||
add_extradata_opt(lease, class);
|
||||
|
||||
/* space-concat tag set */
|
||||
if (!netid)
|
||||
add_extradata_opt(lease, NULL);
|
||||
else
|
||||
for (n = netid; n; n = n->next)
|
||||
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
@@ -1149,39 +1218,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
/* If the user-class option started as counted strings, the first byte will be zero. */
|
||||
if (len != 0 && ucp[0] == 0)
|
||||
ucp++, len--;
|
||||
free(lease->userclass);
|
||||
if ((lease->userclass = whine_malloc(len+1)))
|
||||
{
|
||||
memcpy(lease->userclass, ucp, len);
|
||||
lease->userclass[len] = 0;
|
||||
lease->userclass_len = len+1;
|
||||
}
|
||||
}
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
free(lease->vendorclass);
|
||||
if ((lease->vendorclass = whine_malloc(len+1)))
|
||||
{
|
||||
memcpy(lease->vendorclass, ucp, len);
|
||||
lease->vendorclass[len] = 0;
|
||||
lease->vendorclass_len = len+1;
|
||||
}
|
||||
}
|
||||
if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
|
||||
{
|
||||
int len = option_len(opt);
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
free(lease->supplied_hostname);
|
||||
if ((lease->supplied_hostname = whine_malloc(len+1)))
|
||||
{
|
||||
memcpy(lease->supplied_hostname, ucp, len);
|
||||
lease->supplied_hostname[len] = 0;
|
||||
lease->supplied_hostname_len = len+1;
|
||||
}
|
||||
add_extradata_data(lease, ucp, len, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
|
||||
{
|
||||
@@ -1189,12 +1230,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
hostname_auth = 1;
|
||||
}
|
||||
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
}
|
||||
|
||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
|
||||
|
||||
@@ -1299,6 +1334,37 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (o->len > len)
|
||||
return 0;
|
||||
|
||||
if (o->len == 0)
|
||||
return 1;
|
||||
|
||||
if (o->flags & DHOPT_HEX)
|
||||
{
|
||||
if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
for (i = 0; i <= (len - o->len); )
|
||||
{
|
||||
if (memcmp(o->val, p + i, o->len) == 0)
|
||||
return 1;
|
||||
|
||||
if (o->flags & DHOPT_STRING)
|
||||
i++;
|
||||
else
|
||||
i += o->len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* find a good value to use as MAC address for logging and address-allocation hashing.
|
||||
This is normally just the chaddr field from the DHCP packet,
|
||||
but eg Firewire will have hlen == 0 and use the client-id instead.
|
||||
@@ -1383,6 +1449,55 @@ static int sanitise(unsigned char *opt, char *buf)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim)
|
||||
{
|
||||
if ((lease->extradata_size - lease->extradata_len) < (len + 1))
|
||||
{
|
||||
size_t newsz = lease->extradata_len + len + 100;
|
||||
unsigned char *new = whine_malloc(newsz);
|
||||
|
||||
if (!new)
|
||||
return;
|
||||
|
||||
if (lease->extradata)
|
||||
{
|
||||
memcpy(new, lease->extradata, lease->extradata_len);
|
||||
free(lease->extradata);
|
||||
}
|
||||
|
||||
lease->extradata = new;
|
||||
lease->extradata_size = newsz;
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
memcpy(lease->extradata + lease->extradata_len, data, len);
|
||||
lease->extradata[lease->extradata_len + len] = delim;
|
||||
lease->extradata_len += len + 1;
|
||||
}
|
||||
|
||||
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
|
||||
{
|
||||
if (!opt)
|
||||
add_extradata_data(lease, NULL, 0, 0);
|
||||
else
|
||||
{
|
||||
size_t i, len = option_len(opt);
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
|
||||
/* check for embeded NULLs */
|
||||
for (i = 0; i < len; i++)
|
||||
if (ucp[i] == 0)
|
||||
{
|
||||
len = i;
|
||||
break;
|
||||
}
|
||||
|
||||
add_extradata_data(lease, ucp, len, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
int mac_len, char *interface, char *string, u32 xid)
|
||||
{
|
||||
@@ -1761,7 +1876,7 @@ static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)))
|
||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
|
||||
if (match_netid(tmp->netid, netid, netid ? 0 : 1))
|
||||
return tmp;
|
||||
|
||||
@@ -1861,7 +1976,7 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
|
||||
return force;
|
||||
}
|
||||
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local)
|
||||
{
|
||||
#define NUM_OPTS 4
|
||||
|
||||
@@ -1869,18 +1984,16 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
|
||||
struct pxe_service *service;
|
||||
static struct dhcp_opt *o, *ret;
|
||||
int i, j = NUM_OPTS - 1;
|
||||
struct in_addr boot_server;
|
||||
|
||||
/* We pass back references to these, hence they are declared static */
|
||||
static unsigned char discovery_control;
|
||||
static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' };
|
||||
static struct dhcp_opt *fake_opts = NULL;
|
||||
|
||||
/* We are found by broadcast, so disable multicast. It gets switched on again
|
||||
if we point to other servers and don't give a unicast address. Note that
|
||||
we don't provide our own address for services we are the boot server for because unicast
|
||||
discovery is to port 4011 and we don't listen there. If you are using proxy DHCP
|
||||
and DHCP relays, the relay will need to forward to the proxy too. */
|
||||
discovery_control = 2;
|
||||
/* Disable multicast, since we don't support it, and broadcast
|
||||
unless we need it */
|
||||
discovery_control = 3;
|
||||
|
||||
ret = daemon->dhcp_opts;
|
||||
|
||||
@@ -1920,26 +2033,25 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
|
||||
return daemon->dhcp_opts;
|
||||
}
|
||||
|
||||
if (!service->basename)
|
||||
boot_server = service->basename ? local : service->server;
|
||||
|
||||
if (boot_server.s_addr != 0)
|
||||
{
|
||||
if (service->server.s_addr != 0)
|
||||
{
|
||||
if (q - (unsigned char *)daemon->dhcp_buff2 + 3 + INADDRSZ >= 253)
|
||||
goto toobig;
|
||||
|
||||
/* Boot service with known address - give it */
|
||||
*(q++) = service->type >> 8;
|
||||
*(q++) = service->type;
|
||||
*(q++) = 1;
|
||||
/* dest misaligned */
|
||||
memcpy(q, &service->server.s_addr, INADDRSZ);
|
||||
q += INADDRSZ;
|
||||
}
|
||||
else if (service->type != 0)
|
||||
/* We're not supplying a server, so let the client multicast.
|
||||
type zero is "local boot" so no need for M/C on that. */
|
||||
discovery_control = 0;
|
||||
}
|
||||
if (q - (unsigned char *)daemon->dhcp_buff2 + 3 + INADDRSZ >= 253)
|
||||
goto toobig;
|
||||
|
||||
/* Boot service with known address - give it */
|
||||
*(q++) = service->type >> 8;
|
||||
*(q++) = service->type;
|
||||
*(q++) = 1;
|
||||
/* dest misaligned */
|
||||
memcpy(q, &boot_server.s_addr, INADDRSZ);
|
||||
q += INADDRSZ;
|
||||
}
|
||||
else if (service->type != 0)
|
||||
/* We don't know the server for a service type, so we'll
|
||||
allow the client to broadcast for it */
|
||||
discovery_control = 2;
|
||||
}
|
||||
|
||||
/* if no prompt, wait forever if there's a choice */
|
||||
@@ -1975,14 +2087,11 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
|
||||
ret->opt = SUBOPT_PXE_MENU_PROMPT;
|
||||
}
|
||||
|
||||
if (discovery_control != 0)
|
||||
{
|
||||
ret = &fake_opts[j--];
|
||||
ret->len = 1;
|
||||
ret->opt = SUBOPT_PXE_DISCOVERY;
|
||||
ret->val= &discovery_control;
|
||||
}
|
||||
|
||||
ret = &fake_opts[j--];
|
||||
ret->len = 1;
|
||||
ret->opt = SUBOPT_PXE_DISCOVERY;
|
||||
ret->val= &discovery_control;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2270,45 +2379,78 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
/* Now send options to be encapsulated in arbitrary options,
|
||||
eg dhcp-option=encap:172,17,.......
|
||||
Also hand vendor-identifying vendor-encapsulated options,
|
||||
dhcp-option = rfc3925-encap:13,17,.......
|
||||
The may be more that one "outer" to do, so group
|
||||
all the options which match each outer in turn. */
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
opt->flags &= ~DHOPT_ENCAP_DONE;
|
||||
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
if ((opt->flags & (DHOPT_ENCAPSULATE | DHOPT_ENCAP_DONE)) == DHOPT_ENCAPSULATE)
|
||||
{
|
||||
struct dhcp_opt *o;
|
||||
int found = 0;
|
||||
|
||||
for (o = config_opts; o; o = o->next)
|
||||
{
|
||||
o->flags &= ~DHOPT_ENCAP_MATCH;
|
||||
if ((o->flags & DHOPT_ENCAPSULATE) && opt->u.encap == o->u.encap)
|
||||
{
|
||||
o->flags |= DHOPT_ENCAP_DONE;
|
||||
if (match_netid(o->netid, netid, 1) &&
|
||||
(o->flags & DHOPT_FORCE || in_list(req_options, o->u.encap)))
|
||||
{
|
||||
o->flags |= DHOPT_ENCAP_MATCH;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
|
||||
}
|
||||
{
|
||||
int flags;
|
||||
|
||||
if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
|
||||
{
|
||||
int found = 0;
|
||||
struct dhcp_opt *o;
|
||||
|
||||
if (opt->flags & DHOPT_ENCAP_DONE)
|
||||
continue;
|
||||
|
||||
for (len = 0, o = config_opts; o; o = o->next)
|
||||
{
|
||||
int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
|
||||
|
||||
o->flags &= ~DHOPT_ENCAP_MATCH;
|
||||
|
||||
if (!(o->flags & flags) || opt->u.encap != o->u.encap)
|
||||
continue;
|
||||
|
||||
o->flags |= DHOPT_ENCAP_DONE;
|
||||
if (match_netid(o->netid, netid, 1) &&
|
||||
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
|
||||
{
|
||||
o->flags |= DHOPT_ENCAP_MATCH;
|
||||
found = 1;
|
||||
len += do_opt(o, NULL, NULL, 0) + 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
if (flags & DHOPT_ENCAPSULATE)
|
||||
do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
|
||||
else if (len > 250)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
|
||||
else if ((p = free_space(mess, end, OPTION_VENDOR_IDENT_OPT, len + 5)))
|
||||
{
|
||||
int swap_ent = htonl(opt->u.encap);
|
||||
memcpy(p, &swap_ent, 4);
|
||||
p += 4;
|
||||
*(p++) = len;
|
||||
for (o = config_opts; o; o = o->next)
|
||||
if (o->flags & DHOPT_ENCAP_MATCH)
|
||||
{
|
||||
len = do_opt(o, p + 2, NULL, 0);
|
||||
*(p++) = o->opt;
|
||||
*(p++) = len;
|
||||
p += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Must precede pxe_opts, since it overwrites req_options */
|
||||
force_encap = prune_vendor_opts(netid);
|
||||
if (in_list(req_options, OPTION_VENDOR_CLASS_OPT))
|
||||
force_encap = 1;
|
||||
|
||||
if (pxe_arch != -1)
|
||||
if (context && pxe_arch != -1)
|
||||
{
|
||||
pxe_misc(mess, end, uuid);
|
||||
config_opts = pxe_opts(pxe_arch, netid);
|
||||
config_opts = pxe_opts(pxe_arch, netid, context->local);
|
||||
}
|
||||
|
||||
if (force_encap)
|
||||
|
||||
Reference in New Issue
Block a user