mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Merge branch 'dhcpv6'
This commit is contained in:
235
src/rfc2131.c
235
src/rfc2131.c
@@ -18,16 +18,13 @@
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
#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);
|
||||
@@ -35,13 +32,11 @@ 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, char *string, int null_term);
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static struct in_addr option_addr_arr(unsigned char *opt, int offset);
|
||||
static unsigned int option_uint(unsigned char *opt, int i, int size);
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
int mac_len, char *interface, char *string, u32 xid);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
@@ -49,7 +44,7 @@ static void do_options(struct dhcp_context *context,
|
||||
unsigned char *real_end,
|
||||
unsigned char *req_options,
|
||||
char *hostname,
|
||||
char *domain, char *config_domain,
|
||||
char *config_domain,
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr,
|
||||
unsigned char fqdn_flags,
|
||||
@@ -468,7 +463,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
tagif_netid = run_tag_if(&context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
if (!message && !nailed)
|
||||
{
|
||||
@@ -490,7 +485,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
|
||||
if (hostname)
|
||||
lease_set_hostname(lease, hostname, 1);
|
||||
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
|
||||
/* infinite lease unless nailed in dhcp-host line. */
|
||||
lease_set_expires(lease,
|
||||
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
|
||||
@@ -499,7 +494,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
clear_packet(mess, end);
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
domain, netid, subnet_addr, 0, 0, 0, NULL, 0, now);
|
||||
netid, subnet_addr, 0, 0, 0, NULL, 0, now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,7 +816,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
@@ -873,7 +868,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
}
|
||||
@@ -1011,7 +1006,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
tagif_netid = run_tag_if(&context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||
|
||||
@@ -1027,7 +1022,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
|
||||
}
|
||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
@@ -1225,7 +1220,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
tagif_netid = run_tag_if( &context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (do_classes && daemon->lease_change_command)
|
||||
@@ -1235,7 +1230,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (mess->giaddr.s_addr)
|
||||
lease->giaddr = mess->giaddr;
|
||||
|
||||
lease->changed = 1;
|
||||
lease->flags |= LEASE_CHANGED;
|
||||
free(lease->extradata);
|
||||
lease->extradata = NULL;
|
||||
lease->extradata_size = lease->extradata_len = 0;
|
||||
@@ -1258,7 +1253,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (strcmp(n->net, n1->net) == 0)
|
||||
break;
|
||||
if (!n1)
|
||||
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
|
||||
lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
@@ -1268,7 +1263,7 @@ 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--;
|
||||
add_extradata_data(lease, ucp, len, 0);
|
||||
lease_add_extradata(lease, ucp, len, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1312,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
if (hostname)
|
||||
lease_set_hostname(lease, hostname, hostname_auth);
|
||||
lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
|
||||
|
||||
lease_set_expires(lease, time, now);
|
||||
lease_set_interface(lease, int_index);
|
||||
@@ -1336,7 +1331,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
|
||||
}
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
}
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -1366,10 +1361,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (context && context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
tagif_netid = run_tag_if( &context->netid);
|
||||
tagif_netid = run_tag_if(&context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||
|
||||
@@ -1396,7 +1391,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),
|
||||
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
*is_inform = 1; /* handle reply differently */
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -1405,37 +1400,6 @@ 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.
|
||||
@@ -1521,51 +1485,12 @@ static int sanitise(unsigned char *opt, char *buf)
|
||||
}
|
||||
|
||||
#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);
|
||||
lease_add_extradata(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);
|
||||
}
|
||||
lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1603,30 +1528,10 @@ static void log_options(unsigned char *start, u32 xid)
|
||||
{
|
||||
while (*start != OPTION_END)
|
||||
{
|
||||
int is_ip, is_name, i;
|
||||
char *text = option_string(start[0], &is_ip, &is_name);
|
||||
unsigned char trunc = option_len(start);
|
||||
char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
|
||||
|
||||
if (is_ip)
|
||||
for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
|
||||
{
|
||||
if (i != 0)
|
||||
strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff));
|
||||
strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), 256 - strlen(daemon->namebuff));
|
||||
}
|
||||
else if (!is_name || !sanitise(start, daemon->namebuff))
|
||||
{
|
||||
if (trunc > 13)
|
||||
trunc = 13;
|
||||
print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
|
||||
}
|
||||
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d%s%s%s%s%s",
|
||||
ntohl(xid), option_len(start), start[0],
|
||||
text ? ":" : "", text ? text : "",
|
||||
trunc == 0 ? "" : " ",
|
||||
trunc == 0 ? "" : daemon->namebuff,
|
||||
trunc == option_len(start) ? "" : "...");
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
|
||||
ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
|
||||
start += start[1] + 2;
|
||||
}
|
||||
}
|
||||
@@ -1681,22 +1586,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct in_addr option_addr_arr(unsigned char *opt, int offset)
|
||||
static struct in_addr option_addr(unsigned char *opt)
|
||||
{
|
||||
/* this worries about unaligned data in the option. */
|
||||
/* this worries about unaligned data in the option. */
|
||||
/* struct in_addr is network byte order */
|
||||
struct in_addr ret;
|
||||
|
||||
memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
|
||||
memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct in_addr option_addr(unsigned char *opt)
|
||||
{
|
||||
return option_addr_arr(opt, 0);
|
||||
}
|
||||
|
||||
static unsigned int option_uint(unsigned char *opt, int offset, int size)
|
||||
{
|
||||
/* this worries about unaligned data and byte order */
|
||||
@@ -1731,31 +1631,6 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess)
|
||||
{
|
||||
if (netid && option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
char *s = daemon->namebuff;
|
||||
for (*s = 0; netid; netid = netid->next)
|
||||
{
|
||||
/* kill dupes. */
|
||||
struct dhcp_netid *n;
|
||||
|
||||
for (n = netid->next; n; n = n->next)
|
||||
if (strcmp(netid->net, n->net) == 0)
|
||||
break;
|
||||
|
||||
if (!n)
|
||||
{
|
||||
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
|
||||
if (netid->next)
|
||||
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
|
||||
}
|
||||
}
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
|
||||
{
|
||||
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||
@@ -2200,7 +2075,7 @@ static void do_options(struct dhcp_context *context,
|
||||
unsigned char *end,
|
||||
unsigned char *req_options,
|
||||
char *hostname,
|
||||
char *domain, char *config_domain,
|
||||
char *domain,
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr,
|
||||
unsigned char fqdn_flags,
|
||||
@@ -2219,65 +2094,21 @@ static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_netid *tagif;
|
||||
struct dhcp_netid_list *id_list;
|
||||
|
||||
/* flag options which are valid with the current tag set (sans context tags) */
|
||||
tagif = run_tag_if(netid);
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
{
|
||||
opt->flags &= ~DHOPT_TAGOK;
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
|
||||
match_netid(opt->netid, tagif, 0))
|
||||
opt->flags |= DHOPT_TAGOK;
|
||||
}
|
||||
|
||||
/* now flag options which are valid, including the context tags,
|
||||
otherwise valid options are inhibited if we found a higher priotity one above */
|
||||
if (context && context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
tagif = run_tag_if(&context->netid);
|
||||
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
|
||||
match_netid(opt->netid, tagif, 0))
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = config_opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
|
||||
break;
|
||||
if (!tmp)
|
||||
opt->flags |= DHOPT_TAGOK;
|
||||
}
|
||||
}
|
||||
|
||||
/* now flag untagged options which are not overridden by tagged ones */
|
||||
for (opt = config_opts; opt; opt = opt->next)
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = config_opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
|
||||
break;
|
||||
if (!tmp)
|
||||
opt->flags |= DHOPT_TAGOK;
|
||||
else if (!tmp->netid)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
|
||||
}
|
||||
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
|
||||
tagif = option_filter(netid, &context->netid, config_opts);
|
||||
|
||||
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
|
||||
|
||||
/* logging */
|
||||
if (option_bool(OPT_LOG_OPTS) && req_options)
|
||||
{
|
||||
char *q = daemon->namebuff;
|
||||
for (i = 0; req_options[i] != OPTION_END; i++)
|
||||
{
|
||||
char *s = option_string(req_options[i], NULL, NULL);
|
||||
char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
|
||||
q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
|
||||
"%d%s%s%s",
|
||||
req_options[i],
|
||||
s ? ":" : "",
|
||||
s ? s : "",
|
||||
strlen(s) != 0 ? ":" : "",
|
||||
s,
|
||||
req_options[i+1] == OPTION_END ? "" : ", ");
|
||||
if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
|
||||
{
|
||||
@@ -2514,8 +2345,8 @@ 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,.......
|
||||
Also handle vendor-identifying vendor-encapsulated options,
|
||||
dhcp-option = vi-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)
|
||||
|
||||
Reference in New Issue
Block a user