version 1.1.1.3, 2016/11/02 09:57:01
|
version 1.1.1.5, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
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 |
it under the terms of the GNU General Public License as published by |
Line 30 static struct in_addr server_id(struct dhcp_context *c
|
Line 30 static struct in_addr server_id(struct dhcp_context *c
|
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 i, 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, |
int mac_len, char *interface, char *string, char *err, u32 xid); |
int mac_len, char *interface, char *string, char *err, u32 xid); |
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize); |
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize); |
Line 42 static void clear_packet(struct dhcp_packet *mess, uns
|
Line 42 static void clear_packet(struct dhcp_packet *mess, uns
|
static int in_list(unsigned char *list, int opt); |
static int in_list(unsigned char *list, int opt); |
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 *real_end, | unsigned char *end, |
unsigned char *req_options, |
unsigned char *req_options, |
char *hostname, |
char *hostname, |
char *config_domain, | char *domain, |
struct dhcp_netid *netid, |
struct dhcp_netid *netid, |
struct in_addr subnet_addr, |
struct in_addr subnet_addr, |
unsigned char fqdn_flags, |
unsigned char fqdn_flags, |
int null_term, int pxearch, | int null_term, int pxe_arch, |
unsigned char *uuid, |
unsigned char *uuid, |
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 *opts, 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 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 *is_inform, int pxe, struct in_addr fallback) | size_t sz, time_t now, int unicast_dest, int loopback, |
| int *is_inform, int pxe, struct in_addr fallback, time_t recvtime) |
{ |
{ |
unsigned char *opt, *clid = NULL; |
unsigned char *opt, *clid = NULL; |
struct dhcp_lease *ltmp, *lease = NULL; |
struct dhcp_lease *ltmp, *lease = NULL; |
struct dhcp_vendor *vendor; |
struct dhcp_vendor *vendor; |
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, 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); |
Line 155 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 160 size_t dhcp_reply(struct dhcp_context *context, char *
|
for (offset = 0; offset < (len - 5); offset += elen + 5) |
for (offset = 0; offset < (len - 5); offset += elen + 5) |
{ |
{ |
elen = option_uint(opt, offset + 4 , 1); |
elen = option_uint(opt, offset + 4 , 1); |
if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA) | if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len) |
{ |
{ |
unsigned char *x = option_ptr(opt, offset + 5); |
unsigned char *x = option_ptr(opt, offset + 5); |
unsigned char *y = option_ptr(opt, offset + elen + 5); |
unsigned char *y = option_ptr(opt, offset + elen + 5); |
Line 186 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 191 size_t dhcp_reply(struct dhcp_context *context, char *
|
be enough free space at the end of the packet to copy the option. */ |
be enough free space at the end of the packet to copy the option. */ |
unsigned char *sopt; |
unsigned char *sopt; |
unsigned int total = option_len(opt) + 2; |
unsigned int total = option_len(opt) + 2; |
unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0); | unsigned char *last_opt = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + sz, |
| OPTION_END, 0); |
if (last_opt && last_opt < end - total) |
if (last_opt && last_opt < end - total) |
{ |
{ |
end -= total; |
end -= total; |
Line 231 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 237 size_t dhcp_reply(struct dhcp_context *context, char *
|
subnet_addr = option_addr(opt); |
subnet_addr = option_addr(opt); |
|
|
/* If there is no client identifier option, use the hardware address */ |
/* If there is no client identifier option, use the hardware address */ |
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1))) | if (!option_bool(OPT_IGNORE_CLID) && (opt = option_find(mess, sz, OPTION_CLIENT_ID, 1))) |
{ |
{ |
clid_len = option_len(opt); |
clid_len = option_len(opt); |
clid = option_ptr(opt, 0); |
clid = option_ptr(opt, 0); |
Line 271 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 277 size_t dhcp_reply(struct dhcp_context *context, char *
|
if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr) |
if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr) |
{ |
{ |
struct dhcp_context *context_tmp, *context_new = NULL; |
struct dhcp_context *context_tmp, *context_new = NULL; |
|
struct shared_network *share = NULL; |
struct in_addr addr; |
struct in_addr addr; |
int force = 0; | int force = 0, via_relay = 0; |
|
|
if (subnet_addr.s_addr) |
if (subnet_addr.s_addr) |
{ |
{ |
Line 283 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 290 size_t dhcp_reply(struct dhcp_context *context, char *
|
{ |
{ |
addr = mess->giaddr; |
addr = mess->giaddr; |
force = 1; |
force = 1; |
|
via_relay = 1; |
} |
} |
else |
else |
{ |
{ |
Line 299 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 307 size_t dhcp_reply(struct dhcp_context *context, char *
|
} |
} |
|
|
if (!context_new) |
if (!context_new) |
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next) | { |
{ | for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next) |
struct in_addr netmask = context_tmp->netmask; | { |
| struct in_addr netmask = context_tmp->netmask; |
| |
| /* guess the netmask for relayed networks */ |
| if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0) |
| { |
| if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr))) |
| netmask.s_addr = htonl(0xff000000); |
| else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr))) |
| netmask.s_addr = htonl(0xffff0000); |
| else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr))) |
| netmask.s_addr = htonl(0xffffff00); |
| } |
|
|
/* guess the netmask for relayed networks */ | /* check to see is a context is OK because of a shared address on |
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0) | the relayed subnet. */ |
{ | if (via_relay) |
if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr))) | for (share = daemon->shared_networks; share; share = share->next) |
netmask.s_addr = htonl(0xff000000); | { |
else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr))) | #ifdef HAVE_DHCP6 |
netmask.s_addr = htonl(0xffff0000); | if (share->shared_addr.s_addr == 0) |
else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr))) | continue; |
netmask.s_addr = htonl(0xffffff00); | #endif |
} | if (share->if_index != 0 || |
| share->match_addr.s_addr != mess->giaddr.s_addr) |
/* This section fills in context mainly when a client which is on a remote (relayed) | continue; |
network renews a lease without using the relay, after dnsmasq has restarted. */ | |
if (netmask.s_addr != 0 && | if (netmask.s_addr != 0 && |
is_same_net(addr, context_tmp->start, netmask) && | is_same_net(share->shared_addr, context_tmp->start, netmask) && |
is_same_net(addr, context_tmp->end, netmask)) | is_same_net(share->shared_addr, context_tmp->end, netmask)) |
{ | break; |
context_tmp->netmask = netmask; | } |
if (context_tmp->local.s_addr == 0) | |
context_tmp->local = fallback; | /* This section fills in context mainly when a client which is on a remote (relayed) |
if (context_tmp->router.s_addr == 0) | network renews a lease without using the relay, after dnsmasq has restarted. */ |
context_tmp->router = mess->giaddr; | if (share || |
| (netmask.s_addr != 0 && |
/* fill in missing broadcast addresses for relayed ranges */ | is_same_net(addr, context_tmp->start, netmask) && |
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 ) | is_same_net(addr, context_tmp->end, netmask))) |
context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr; | { |
| context_tmp->netmask = netmask; |
context_tmp->current = context_new; | if (context_tmp->local.s_addr == 0) |
context_new = context_tmp; | context_tmp->local = fallback; |
} | if (context_tmp->router.s_addr == 0 && !share) |
} | context_tmp->router = mess->giaddr; |
| |
| /* fill in missing broadcast addresses for relayed ranges */ |
| if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 ) |
| context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr; |
| |
| context_tmp->current = context_new; |
| context_new = context_tmp; |
| } |
| |
| } |
| } |
| |
if (context_new || force) |
if (context_new || force) |
context = context_new; |
context = context_new; |
} |
} |
|
|
if (!context) |
if (!context) |
{ |
{ |
my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"), | const char *via; |
subnet_addr.s_addr ? _("with subnet selector") : _("via"), | if (subnet_addr.s_addr) |
subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name)); | { |
| via = _("with subnet selector"); |
| inet_ntop(AF_INET, &subnet_addr, daemon->addrbuff, ADDRSTRLEN); |
| } |
| else |
| { |
| via = _("via"); |
| if (mess->giaddr.s_addr) |
| inet_ntop(AF_INET, &mess->giaddr, daemon->addrbuff, ADDRSTRLEN); |
| else |
| safe_strncpy(daemon->addrbuff, iface_name, ADDRSTRLEN); |
| } |
| my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"), |
| via, daemon->addrbuff); |
return 0; |
return 0; |
} |
} |
|
|
Line 352 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 396 size_t dhcp_reply(struct dhcp_context *context, char *
|
struct dhcp_context *context_tmp; |
struct dhcp_context *context_tmp; |
for (context_tmp = context; context_tmp; context_tmp = context_tmp->current) |
for (context_tmp = context; context_tmp; context_tmp = context_tmp->current) |
{ |
{ |
strcpy(daemon->namebuff, inet_ntoa(context_tmp->start)); | inet_ntop(AF_INET, &context_tmp->start, daemon->namebuff, MAXDNAME); |
if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) |
if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) |
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"), | { |
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask)); | inet_ntop(AF_INET, &context_tmp->netmask, daemon->addrbuff, ADDRSTRLEN); |
| my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"), |
| ntohl(mess->xid), daemon->namebuff, daemon->addrbuff); |
| } |
else |
else |
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"), | { |
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end)); | inet_ntop(AF_INET, &context_tmp->end, daemon->addrbuff, ADDRSTRLEN); |
| my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"), |
| ntohl(mess->xid), daemon->namebuff, daemon->addrbuff); |
| } |
} |
} |
} |
} |
|
|
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match. |
/* 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. |
Otherwise assume the option is an array, and look for a matching element. |
If no data given, existance of the option is enough. This code handles | If no data given, existence of the option is enough. This code handles |
rfc3925 V-I classes too. */ |
rfc3925 V-I classes too. */ |
for (o = daemon->dhcp_match; o; o = o->next) |
for (o = daemon->dhcp_match; o; o = o->next) |
{ |
{ |
Line 380 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 430 size_t dhcp_reply(struct dhcp_context *context, char *
|
{ |
{ |
len = option_uint(opt, offset + 4 , 1); |
len = option_uint(opt, offset + 4 , 1); |
/* Need to take care that bad data can't run us off the end of the packet */ |
/* Need to take care that bad data can't run us off the end of the packet */ |
if ((offset + len + 5 <= (option_len(opt))) && | if ((offset + len + 5 <= (unsigned)(option_len(opt))) && |
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap)) |
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap)) |
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1) |
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1) |
{ |
{ |
elen = option_uint(opt, o2, 1); |
elen = option_uint(opt, o2, 1); |
if ((o2 + elen + 1 <= option_len(opt)) && | if ((o2 + elen + 1 <= (unsigned)option_len(opt)) && |
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen))) |
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen))) |
break; |
break; |
} |
} |
Line 476 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 526 size_t dhcp_reply(struct dhcp_context *context, char *
|
mess->op = BOOTREPLY; |
mess->op = BOOTREPLY; |
|
|
config = find_config(daemon->dhcp_conf, context, clid, clid_len, |
config = find_config(daemon->dhcp_conf, context, clid, clid_len, |
mess->chaddr, mess->hlen, mess->htype, NULL); | mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid)); |
|
|
/* set "known" tag for known hosts */ |
/* set "known" tag for known hosts */ |
if (config) |
if (config) |
Line 485 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 535 size_t dhcp_reply(struct dhcp_context *context, char *
|
known_id.next = netid; |
known_id.next = netid; |
netid = &known_id; |
netid = &known_id; |
} |
} |
|
else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len, |
|
mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid))) |
|
{ |
|
known_id.net = "known-othernet"; |
|
known_id.next = netid; |
|
netid = &known_id; |
|
} |
|
|
if (mess_type == 0 && !pxe) |
if (mess_type == 0 && !pxe) |
{ |
{ |
Line 566 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 623 size_t dhcp_reply(struct dhcp_context *context, char *
|
lease_prune(lease, now); |
lease_prune(lease, now); |
lease = NULL; |
lease = NULL; |
} |
} |
if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now)) | if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now, loopback)) |
message = _("no address available"); |
message = _("no address available"); |
} |
} |
else |
else |
Line 612 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 669 size_t dhcp_reply(struct dhcp_context *context, char *
|
|
|
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); |
} |
} |
} |
} |
|
|
|
daemon->metrics[METRIC_BOOTP]++; |
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid); |
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid); |
|
|
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end); |
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end); |
Line 689 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 747 size_t dhcp_reply(struct dhcp_context *context, char *
|
client_hostname = daemon->dhcp_buff; |
client_hostname = daemon->dhcp_buff; |
} |
} |
|
|
if (client_hostname && option_bool(OPT_LOG_OPTS)) | if (client_hostname) |
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname); | { |
| struct dhcp_match_name *m; |
| size_t nl = strlen(client_hostname); |
| |
| if (option_bool(OPT_LOG_OPTS)) |
| my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname); |
| for (m = daemon->dhcp_name_match; m; m = m->next) |
| { |
| size_t ml = strlen(m->name); |
| char save = 0; |
| |
| if (nl < ml) |
| continue; |
| if (nl > ml) |
| { |
| save = client_hostname[ml]; |
| client_hostname[ml] = 0; |
| } |
| |
| if (hostname_isequal(client_hostname, m->name) && |
| (save == 0 || m->wildcard)) |
| { |
| m->netid->next = netid; |
| netid = m->netid; |
| } |
| |
| if (save != 0) |
| client_hostname[ml] = save; |
| } |
| } |
|
|
if (have_config(config, CONFIG_NAME)) |
if (have_config(config, CONFIG_NAME)) |
{ |
{ |
Line 708 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 795 size_t dhcp_reply(struct dhcp_context *context, char *
|
if (strlen(client_hostname) != 0) |
if (strlen(client_hostname) != 0) |
{ |
{ |
hostname = client_hostname; |
hostname = client_hostname; |
|
|
if (!config) |
if (!config) |
{ |
{ |
/* Search again now we have a hostname. |
/* Search again now we have a hostname. |
Line 715 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 803 size_t dhcp_reply(struct dhcp_context *context, char *
|
to avoid impersonation by name. */ |
to avoid impersonation by name. */ |
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, |
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, |
mess->chaddr, mess->hlen, |
mess->chaddr, mess->hlen, |
mess->htype, hostname); | mess->htype, hostname, run_tag_if(netid)); |
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) |
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) |
{ |
{ |
config = new; |
config = new; |
Line 769 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 857 size_t dhcp_reply(struct dhcp_context *context, char *
|
clid = NULL; |
clid = NULL; |
|
|
/* 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))) |
{ |
{ |
Line 824 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 911 size_t dhcp_reply(struct dhcp_context *context, char *
|
else |
else |
mess->siaddr = context->local; |
mess->siaddr = context->local; |
|
|
snprintf((char *)mess->file, sizeof(mess->file), | if (strchr(service->basename, '.')) |
strchr(service->basename, '.') ? "%s" :"%s.%d", | snprintf((char *)mess->file, sizeof(mess->file), |
service->basename, layer); | "%s", service->basename); |
| else |
| snprintf((char *)mess->file, sizeof(mess->file), |
| "%s.%d", service->basename, layer); |
|
|
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; |
Line 896 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 986 size_t dhcp_reply(struct dhcp_context *context, char *
|
|
|
if (!workaround && boot) |
if (!workaround && boot) |
{ |
{ |
/* Provide the bootfile here, for gPXE, and in case we have no menu items | /* Provide the bootfile here, for iPXE, and in case we have no menu items |
and set discovery_control = 8 */ |
and set discovery_control = 8 */ |
if (boot->next_server.s_addr) |
if (boot->next_server.s_addr) |
mess->siaddr = boot->next_server; |
mess->siaddr = boot->next_server; |
Line 904 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 994 size_t dhcp_reply(struct dhcp_context *context, char *
|
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now); |
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now); |
|
|
if (boot->file) |
if (boot->file) |
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1); | safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file)); |
} |
} |
|
|
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); |
|
|
|
daemon->metrics[METRIC_PXE]++; |
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid); |
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid); |
log_tags(tagif_netid, ntohl(mess->xid)); |
log_tags(tagif_netid, ntohl(mess->xid)); |
|
if (!ignore) |
|
apply_delay(mess->xid, recvtime, tagif_netid); |
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end); |
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end); |
} |
} |
} |
} |
Line 947 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1040 size_t dhcp_reply(struct dhcp_context *context, char *
|
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ))) |
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ))) |
return 0; |
return 0; |
|
|
|
daemon->metrics[METRIC_DHCPDECLINE]++; |
log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid); |
log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid); |
|
|
if (lease && lease->addr.s_addr == option_addr(opt).s_addr) |
if (lease && lease->addr.s_addr == option_addr(opt).s_addr) |
Line 956 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1050 size_t dhcp_reply(struct dhcp_context *context, char *
|
config->addr.s_addr == option_addr(opt).s_addr) |
config->addr.s_addr == option_addr(opt).s_addr) |
{ |
{ |
prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF); |
prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF); |
|
inet_ntop(AF_INET, &config->addr, daemon->addrbuff, ADDRSTRLEN); |
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), |
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), |
inet_ntoa(config->addr), daemon->dhcp_buff); | daemon->addrbuff, daemon->dhcp_buff); |
config->flags |= CONFIG_DECLINED; |
config->flags |= CONFIG_DECLINED; |
config->decline_time = now; |
config->decline_time = now; |
} |
} |
Line 979 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1074 size_t dhcp_reply(struct dhcp_context *context, char *
|
else |
else |
message = _("unknown lease"); |
message = _("unknown lease"); |
|
|
|
daemon->metrics[METRIC_DHCPRELEASE]++; |
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid); |
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid); |
|
|
return 0; |
return 0; |
Line 1002 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1098 size_t dhcp_reply(struct dhcp_context *context, char *
|
|
|
if (have_config(config, CONFIG_ADDR)) |
if (have_config(config, CONFIG_ADDR)) |
{ |
{ |
char *addrs = inet_ntoa(config->addr); | inet_ntop(AF_INET, &config->addr, daemon->addrbuff, ADDRSTRLEN); |
|
|
if ((ltmp = lease_find_by_addr(config->addr)) && |
if ((ltmp = lease_find_by_addr(config->addr)) && |
ltmp != lease && |
ltmp != lease && |
Line 1012 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1108 size_t dhcp_reply(struct dhcp_context *context, char *
|
unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len, |
unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len, |
ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len); |
ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len); |
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"), |
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"), |
addrs, print_mac(daemon->namebuff, mac, len)); | daemon->addrbuff, print_mac(daemon->namebuff, mac, len)); |
} |
} |
else |
else |
{ |
{ |
Line 1021 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1117 size_t dhcp_reply(struct dhcp_context *context, char *
|
if (context->router.s_addr == config->addr.s_addr) |
if (context->router.s_addr == config->addr.s_addr) |
break; |
break; |
if (tmp) |
if (tmp) |
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs); | my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), daemon->addrbuff); |
else if (have_config(config, CONFIG_DECLINED) && |
else if (have_config(config, CONFIG_DECLINED) && |
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF) |
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF) |
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs); | my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), daemon->addrbuff); |
else |
else |
conf = config->addr; |
conf = config->addr; |
} |
} |
Line 1037 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1133 size_t dhcp_reply(struct dhcp_context *context, char *
|
!config_find_by_address(daemon->dhcp_conf, lease->addr)) |
!config_find_by_address(daemon->dhcp_conf, lease->addr)) |
mess->yiaddr = lease->addr; |
mess->yiaddr = lease->addr; |
else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) && |
else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) && |
!config_find_by_address(daemon->dhcp_conf, addr)) | !config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0, loopback)) |
mess->yiaddr = addr; |
mess->yiaddr = addr; |
else if (emac_len == 0) |
else if (emac_len == 0) |
message = _("no unique-id"); |
message = _("no unique-id"); |
else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now)) | else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now, loopback)) |
message = _("no address available"); |
message = _("no address available"); |
} |
} |
|
|
|
daemon->metrics[METRIC_DHCPDISCOVER]++; |
log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); |
log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); |
|
|
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid))) |
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid))) |
Line 1056 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1153 size_t dhcp_reply(struct dhcp_context *context, char *
|
tagif_netid = run_tag_if(&context->netid); |
tagif_netid = run_tag_if(&context->netid); |
} |
} |
|
|
log_tags(tagif_netid, ntohl(mess->xid)); | apply_delay(mess->xid, recvtime, tagif_netid); |
| |
| if (option_bool(OPT_RAPID_COMMIT) && option_find(mess, sz, OPTION_RAPID_COMMIT, 0)) |
| { |
| rapid_commit = 1; |
| /* If a lease exists for this host and another address, squash it. */ |
| if (lease && lease->addr.s_addr != mess->yiaddr.s_addr) |
| { |
| lease_prune(lease, now); |
| lease = NULL; |
| } |
| goto rapid_commit; |
| } |
|
|
|
log_tags(tagif_netid, ntohl(mess->xid)); |
|
|
|
daemon->metrics[METRIC_DHCPOFFER]++; |
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid); |
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid); |
|
|
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4)); |
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4)); |
Line 1067 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1179 size_t dhcp_reply(struct dhcp_context *context, char *
|
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); |
| |
| |
case DHCPREQUEST: |
case DHCPREQUEST: |
if (ignore || have_config(config, CONFIG_DISABLE)) |
if (ignore || have_config(config, CONFIG_DISABLE)) |
return 0; |
return 0; |
Line 1168 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1281 size_t dhcp_reply(struct dhcp_context *context, char *
|
fuzz = rand16(); |
fuzz = rand16(); |
mess->yiaddr = mess->ciaddr; |
mess->yiaddr = mess->ciaddr; |
} |
} |
| |
| daemon->metrics[METRIC_DHCPREQUEST]++; |
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid); |
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid); |
| |
| rapid_commit: |
if (!message) |
if (!message) |
{ |
{ |
struct dhcp_config *addr_config; |
struct dhcp_config *addr_config; |
Line 1215 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1330 size_t dhcp_reply(struct dhcp_context *context, char *
|
a lease from one of it's MACs to give the address to another. */ |
a lease from one of it's MACs to give the address to another. */ |
if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type)) |
if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type)) |
{ |
{ |
|
inet_ntop(AF_INET, <mp->addr, daemon->addrbuff, ADDRSTRLEN); |
my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"), |
my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"), |
print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len), |
print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len), |
inet_ntoa(ltmp->addr)); | daemon->addrbuff); |
lease = ltmp; |
lease = ltmp; |
} |
} |
else |
else |
Line 1241 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1357 size_t dhcp_reply(struct dhcp_context *context, char *
|
|
|
if (message) |
if (message) |
{ |
{ |
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid); | daemon->metrics[rapid_commit ? METRIC_NOANSWER : METRIC_DHCPNAK]++; |
| log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid); |
| |
| /* rapid commit case: lease allocate failed but don't send DHCPNAK */ |
| if (rapid_commit) |
| return 0; |
|
|
mess->yiaddr.s_addr = 0; |
mess->yiaddr.s_addr = 0; |
clear_packet(mess, end); |
clear_packet(mess, end); |
Line 1303 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1424 size_t dhcp_reply(struct dhcp_context *context, char *
|
add_extradata_opt(lease, NULL); |
add_extradata_opt(lease, NULL); |
} |
} |
|
|
|
/* DNSMASQ_REQUESTED_OPTIONS */ |
|
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 1))) |
|
{ |
|
int i, len = option_len(opt); |
|
unsigned char *rop = option_ptr(opt, 0); |
|
|
|
for (i = 0; i < len; i++) |
|
lease_add_extradata(lease, (unsigned char *)daemon->namebuff, |
|
sprintf(daemon->namebuff, "%u", rop[i]), (i + 1) == len ? 0 : ','); |
|
} |
|
else |
|
lease_add_extradata(lease, NULL, 0, 0); |
|
|
|
add_extradata_opt(lease, option_find(mess, sz, OPTION_MUD_URL_V4, 1)); |
|
|
/* space-concat tag set */ |
/* space-concat tag set */ |
if (!tagif_netid) |
if (!tagif_netid) |
add_extradata_opt(lease, NULL); |
add_extradata_opt(lease, NULL); |
Line 1380 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1516 size_t dhcp_reply(struct dhcp_context *context, char *
|
else |
else |
override = lease->override; |
override = lease->override; |
|
|
|
daemon->metrics[METRIC_DHCPACK]++; |
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid); |
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid); |
| |
clear_packet(mess, end); |
clear_packet(mess, end); |
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, ntohl(server_id(context, override, fallback).s_addr)); |
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr)); |
option_put(mess, end, OPTION_LEASE_TIME, 4, time); |
option_put(mess, end, OPTION_LEASE_TIME, 4, time); |
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), | if (rapid_commit) |
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz); | option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0); |
| 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, pxevendor); |
} |
} |
|
|
return dhcp_packet_size(mess, agent_id, real_end); |
return dhcp_packet_size(mess, agent_id, real_end); |
Line 1396 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1535 size_t dhcp_reply(struct dhcp_context *context, char *
|
if (ignore || have_config(config, CONFIG_DISABLE)) |
if (ignore || have_config(config, CONFIG_DISABLE)) |
message = _("ignored"); |
message = _("ignored"); |
|
|
|
daemon->metrics[METRIC_DHCPINFORM]++; |
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid); |
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid); |
|
|
if (message || mess->ciaddr.s_addr == 0) |
if (message || mess->ciaddr.s_addr == 0) |
Line 1422 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1562 size_t dhcp_reply(struct dhcp_context *context, char *
|
|
|
log_tags(tagif_netid, ntohl(mess->xid)); |
log_tags(tagif_netid, ntohl(mess->xid)); |
|
|
|
daemon->metrics[METRIC_DHCPACK]++; |
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid); |
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid); |
|
|
if (lease) |
if (lease) |
Line 1452 size_t dhcp_reply(struct dhcp_context *context, char *
|
Line 1593 size_t dhcp_reply(struct dhcp_context *context, char *
|
} |
} |
|
|
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); |
Line 1537 static int sanitise(unsigned char *opt, char *buf)
|
Line 1678 static int sanitise(unsigned char *opt, char *buf)
|
for (i = option_len(opt); i > 0; i--) |
for (i = option_len(opt); i > 0; i--) |
{ |
{ |
char c = *p++; |
char c = *p++; |
if (isprint((int)c)) | if (isprint((unsigned char)c)) |
*buf++ = c; |
*buf++ = c; |
} |
} |
*buf = 0; /* add terminator */ |
*buf = 0; /* add terminator */ |
Line 1558 static void add_extradata_opt(struct dhcp_lease *lease
|
Line 1699 static void add_extradata_opt(struct dhcp_lease *lease
|
static void log_packet(char *type, void *addr, unsigned char *ext_mac, |
static void log_packet(char *type, void *addr, unsigned char *ext_mac, |
int mac_len, char *interface, char *string, char *err, u32 xid) |
int mac_len, char *interface, char *string, char *err, u32 xid) |
{ |
{ |
struct in_addr a; |
|
|
|
if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP)) |
if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP)) |
return; |
return; |
|
|
/* addr may be misaligned */ | daemon->addrbuff[0] = 0; |
if (addr) |
if (addr) |
memcpy(&a, addr, sizeof(a)); | inet_ntop(AF_INET, addr, daemon->addrbuff, ADDRSTRLEN); |
|
|
print_mac(daemon->namebuff, ext_mac, mac_len); |
print_mac(daemon->namebuff, ext_mac, mac_len); |
|
|
if(option_bool(OPT_LOG_OPTS)) | if (option_bool(OPT_LOG_OPTS)) |
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s", | my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s", |
ntohl(xid), | ntohl(xid), |
type, | type, |
interface, | interface, |
addr ? inet_ntoa(a) : "", | daemon->addrbuff, |
addr ? " " : "", | addr ? " " : "", |
daemon->namebuff, | daemon->namebuff, |
string ? string : "", | string ? string : "", |
err ? err : ""); | err ? err : ""); |
else |
else |
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s", |
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s", |
type, |
type, |
interface, |
interface, |
addr ? inet_ntoa(a) : "", | daemon->addrbuff, |
addr ? " " : "", |
addr ? " " : "", |
daemon->namebuff, |
daemon->namebuff, |
string ? string : "", |
string ? string : "", |
err ? err : ""); |
err ? err : ""); |
|
|
|
#ifdef HAVE_UBUS |
|
if (!strcmp(type, "DHCPACK")) |
|
ubus_event_bcast("dhcp.ack", daemon->namebuff, addr ? daemon->addrbuff : NULL, string, interface); |
|
else if (!strcmp(type, "DHCPRELEASE")) |
|
ubus_event_bcast("dhcp.release", daemon->namebuff, addr ? daemon->addrbuff : NULL, string, interface); |
|
#endif |
} |
} |
|
|
static void log_options(unsigned char *start, u32 xid) |
static void log_options(unsigned char *start, u32 xid) |
Line 1606 static unsigned char *option_find1(unsigned char *p, u
|
Line 1752 static unsigned char *option_find1(unsigned char *p, u
|
{ |
{ |
while (1) |
while (1) |
{ |
{ |
if (p > end) | if (p >= end) |
return NULL; |
return NULL; |
else if (*p == OPTION_END) |
else if (*p == OPTION_END) |
return opt == OPTION_END ? p : NULL; |
return opt == OPTION_END ? p : NULL; |
Line 1738 static size_t dhcp_packet_size(struct dhcp_packet *mes
|
Line 1884 static size_t dhcp_packet_size(struct dhcp_packet *mes
|
if (option_bool(OPT_LOG_OPTS)) |
if (option_bool(OPT_LOG_OPTS)) |
{ |
{ |
if (mess->siaddr.s_addr != 0) |
if (mess->siaddr.s_addr != 0) |
my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr)); | { |
| inet_ntop(AF_INET, &mess->siaddr, daemon->addrbuff, ADDRSTRLEN); |
| my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), daemon->addrbuff); |
| } |
|
|
if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0) |
if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0) |
my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid)); |
my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid)); |
Line 1827 static void option_put(struct dhcp_packet *mess, unsig
|
Line 1976 static void option_put(struct dhcp_packet *mess, unsig
|
} |
} |
|
|
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); |
Line 1905 static void match_vendor_opts(unsigned char *opt, stru
|
Line 2054 static void match_vendor_opts(unsigned char *opt, stru
|
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, |
for (i = 0; i <= (option_len(opt) - len); i++) | .next = NULL, |
if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0) | }; |
{ | if (dopt->flags & DHOPT_VENDOR_PXE) |
dopt->flags |= DHOPT_VENDOR_MATCH; | pv = daemon->dhcp_pxe_vendors; |
break; | 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++) |
| if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0) |
| { |
| matched = 1; |
| break; |
| } |
| if (matched) |
| { |
| dopt->flags |= DHOPT_VENDOR_MATCH; |
| break; |
| } |
| } |
} |
} |
} |
} |
} |
} |
Line 1966 static int do_encap_opts(struct dhcp_opt *opt, int enc
|
Line 2132 static int do_encap_opts(struct dhcp_opt *opt, int enc
|
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); |
} |
} |
Line 2036 static int pxe_uefi_workaround(int pxe_arch, struct dh
|
Line 2204 static int pxe_uefi_workaround(int pxe_arch, struct dh
|
inet_ntop(AF_INET, &mess->siaddr, (char *)mess->sname, INET_ADDRSTRLEN); |
inet_ntop(AF_INET, &mess->siaddr, (char *)mess->sname, INET_ADDRSTRLEN); |
} |
} |
|
|
snprintf((char *)mess->file, sizeof(mess->file), | if (found->basename) |
strchr(found->basename, '.') ? "%s" : "%s.0", found->basename); | snprintf((char *)mess->file, sizeof(mess->file), |
| strchr(found->basename, '.') ? "%s" : "%s.0", found->basename); |
|
|
return 1; |
return 1; |
} |
} |
Line 2187 struct dhcp_boot *find_boot(struct dhcp_netid *netid)
|
Line 2356 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, |
Line 2201 static void do_options(struct dhcp_context *context,
|
Line 2393 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; |
Line 2251 static void do_options(struct dhcp_context *context,
|
Line 2444 static void do_options(struct dhcp_context *context,
|
/* See if we can send the boot stuff as options. |
/* See if we can send the boot stuff as options. |
To do this we need a requested option list, BOOTP |
To do this we need a requested option list, BOOTP |
and very old DHCP clients won't have this, we also |
and very old DHCP clients won't have this, we also |
provide an manual option to disable it. | provide a manual option to disable it. |
Some PXE ROMs have bugs (surprise!) and need zero-terminated |
Some PXE ROMs have bugs (surprise!) and need zero-terminated |
names, so we always send those. */ |
names, so we always send those. */ |
if ((boot = find_boot(tagif))) |
if ((boot = find_boot(tagif))) |
Line 2263 static void do_options(struct dhcp_context *context,
|
Line 2456 static void do_options(struct dhcp_context *context,
|
in_list(req_options, OPTION_SNAME)) |
in_list(req_options, OPTION_SNAME)) |
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1); |
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1); |
else |
else |
strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1); | safe_strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)); |
} |
} |
|
|
if (boot->file) |
if (boot->file) |
Line 2273 static void do_options(struct dhcp_context *context,
|
Line 2466 static void do_options(struct dhcp_context *context,
|
in_list(req_options, OPTION_FILENAME)) |
in_list(req_options, OPTION_FILENAME)) |
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1); |
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1); |
else |
else |
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1); | safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file)); |
} |
} |
|
|
if (boot->next_server.s_addr) |
if (boot->next_server.s_addr) |
Line 2290 static void do_options(struct dhcp_context *context,
|
Line 2483 static void do_options(struct dhcp_context *context,
|
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) && |
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) && |
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE)) |
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE)) |
{ |
{ |
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1); | safe_strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)); |
done_file = 1; |
done_file = 1; |
} |
} |
|
|
if ((!req_options || !in_list(req_options, OPTION_SNAME)) && |
if ((!req_options || !in_list(req_options, OPTION_SNAME)) && |
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE)) |
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE)) |
{ |
{ |
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1); | safe_strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)); |
done_server = 1; |
done_server = 1; |
} |
} |
|
|
Line 2419 static void do_options(struct dhcp_context *context,
|
Line 2612 static void do_options(struct dhcp_context *context,
|
|
|
if (fqdn_flags & 0x04) |
if (fqdn_flags & 0x04) |
{ |
{ |
p = do_rfc1035_name(p, hostname); | p = do_rfc1035_name(p, hostname, NULL); |
if (domain) |
if (domain) |
{ |
{ |
p = do_rfc1035_name(p, domain); | p = do_rfc1035_name(p, domain, NULL); |
*p++ = 0; |
*p++ = 0; |
} |
} |
} |
} |
Line 2575 static void do_options(struct dhcp_context *context,
|
Line 2768 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); |
} |
} |
Line 2596 static void do_options(struct dhcp_context *context,
|
Line 2789 static void do_options(struct dhcp_context *context,
|
} |
} |
} |
} |
|
|
#endif | static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid) |
| { |
| struct delay_config *delay_conf; |
|
|
| /* Decide which delay_config option we're using */ |
| for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next) |
| if (match_netid(delay_conf->netid, netid, 0)) |
| break; |
|
|
| if (!delay_conf) |
| /* No match, look for one without a netid */ |
| for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next) |
| if (match_netid(delay_conf->netid, netid, 1)) |
| break; |
|
|
|
if (delay_conf) |
|
{ |
|
if (!option_bool(OPT_QUIET_DHCP)) |
|
my_syslog(MS_DHCP | LOG_INFO, _("%u reply delay: %d"), ntohl(xid), delay_conf->delay); |
|
delay_dhcp(recvtime, delay_conf->delay, -1, 0, 0); |
|
} |
|
} |
|
|
| #endif /* HAVE_DHCP */ |