version 1.1.1.3, 2016/11/02 09:57:01
|
version 1.1.1.4, 2021/03/17 00:56:46
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2021 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 20
|
Line 20
|
|
|
void dhcp_common_init(void) |
void dhcp_common_init(void) |
{ |
{ |
/* These each hold a DHCP option max size 255 | /* These each hold a DHCP option max size 255 |
and get a terminating zero added */ | and get a terminating zero added */ |
daemon->dhcp_buff = safe_malloc(256); | daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ); |
daemon->dhcp_buff2 = safe_malloc(256); | daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ); |
daemon->dhcp_buff3 = safe_malloc(256); | daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ); |
|
|
/* dhcp_packet is used by v4 and v6, outpacket only by v6 |
/* dhcp_packet is used by v4 and v6, outpacket only by v6 |
sizeof(struct dhcp_packet) is as good an initial size as any, |
sizeof(struct dhcp_packet) is as good an initial size as any, |
Line 38 void dhcp_common_init(void)
|
Line 38 void dhcp_common_init(void)
|
|
|
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg) |
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg) |
{ |
{ |
ssize_t sz; | ssize_t sz, new_sz; |
|
|
while (1) |
while (1) |
{ |
{ |
Line 65 ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
Line 65 ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
} |
} |
} |
} |
|
|
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR); | while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR); |
| |
| /* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway. |
| If that happens we get EAGAIN here because the socket is non-blocking. |
| Use the result of the original testing recvmsg as long as the buffer |
| was big enough. There's a small race here that may lose the odd packet, |
| but it's UDP anyway. */ |
|
|
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz; | if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) |
| new_sz = sz; |
| |
| return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz; |
} |
} |
|
|
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags) |
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags) |
Line 271 static int is_config_in_context(struct dhcp_context *c
|
Line 280 static int is_config_in_context(struct dhcp_context *c
|
{ |
{ |
if (!context) /* called via find_config() from lease_update_from_configs() */ |
if (!context) /* called via find_config() from lease_update_from_configs() */ |
return 1; |
return 1; |
|
|
if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6))) |
|
return 1; |
|
|
|
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD)) | if (context->flags & CONTEXT_V6) |
return 1; | { |
#endif | struct addrlist *addr_list; |
|
|
for (; context; context = context->current) | if (!(config->flags & CONFIG_ADDR6)) |
#ifdef HAVE_DHCP6 | return 1; |
if (context->flags & CONTEXT_V6) | |
{ | for (; context; context = context->current) |
if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix)) | for (addr_list = config->addr6; addr_list; addr_list = addr_list->next) |
return 1; | { |
} | if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64) |
else | return 1; |
| |
| if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix)) |
| return 1; |
| } |
| } |
| else |
#endif |
#endif |
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask)) | { |
| if (!(config->flags & CONFIG_ADDR)) |
return 1; |
return 1; |
|
|
|
for (; context; context = context->current) |
|
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask)) |
|
return 1; |
|
} |
|
|
return 0; |
return 0; |
} |
} |
|
|
struct dhcp_config *find_config(struct dhcp_config *configs, | static struct dhcp_config *find_config_match(struct dhcp_config *configs, |
struct dhcp_context *context, | struct dhcp_context *context, |
unsigned char *clid, int clid_len, | unsigned char *clid, int clid_len, |
unsigned char *hwaddr, int hw_len, | unsigned char *hwaddr, int hw_len, |
int hw_type, char *hostname) | int hw_type, char *hostname, |
| struct dhcp_netid *tags, int tag_not_needed) |
{ |
{ |
int count, new; |
int count, new; |
struct dhcp_config *config, *candidate; |
struct dhcp_config *config, *candidate; |
Line 311 struct dhcp_config *find_config(struct dhcp_config *co
|
Line 330 struct dhcp_config *find_config(struct dhcp_config *co
|
{ |
{ |
if (config->clid_len == clid_len && |
if (config->clid_len == clid_len && |
memcmp(config->clid, clid, clid_len) == 0 && |
memcmp(config->clid, clid, clid_len) == 0 && |
is_config_in_context(context, config)) | is_config_in_context(context, config) && |
| match_netid(config->filter, tags, tag_not_needed)) |
| |
return config; |
return config; |
|
|
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and |
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and |
Line 319 struct dhcp_config *find_config(struct dhcp_config *co
|
Line 340 struct dhcp_config *find_config(struct dhcp_config *co
|
see lease_update_from_configs() */ |
see lease_update_from_configs() */ |
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 && |
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 && |
memcmp(config->clid, clid+1, clid_len-1) == 0 && |
memcmp(config->clid, clid+1, clid_len-1) == 0 && |
is_config_in_context(context, config)) | is_config_in_context(context, config) && |
| match_netid(config->filter, tags, tag_not_needed)) |
return config; |
return config; |
} |
} |
|
|
Line 327 struct dhcp_config *find_config(struct dhcp_config *co
|
Line 349 struct dhcp_config *find_config(struct dhcp_config *co
|
if (hwaddr) |
if (hwaddr) |
for (config = configs; config; config = config->next) |
for (config = configs; config; config = config->next) |
if (config_has_mac(config, hwaddr, hw_len, hw_type) && |
if (config_has_mac(config, hwaddr, hw_len, hw_type) && |
is_config_in_context(context, config)) | is_config_in_context(context, config) && |
| match_netid(config->filter, tags, tag_not_needed)) |
return config; |
return config; |
|
|
if (hostname && context) |
if (hostname && context) |
for (config = configs; config; config = config->next) |
for (config = configs; config; config = config->next) |
if ((config->flags & CONFIG_NAME) && |
if ((config->flags & CONFIG_NAME) && |
hostname_isequal(config->hostname, hostname) && |
hostname_isequal(config->hostname, hostname) && |
is_config_in_context(context, config)) | is_config_in_context(context, config) && |
| match_netid(config->filter, tags, tag_not_needed)) |
return config; |
return config; |
|
|
|
|
Line 343 struct dhcp_config *find_config(struct dhcp_config *co
|
Line 367 struct dhcp_config *find_config(struct dhcp_config *co
|
|
|
/* use match with fewest wildcard octets */ |
/* use match with fewest wildcard octets */ |
for (candidate = NULL, count = 0, config = configs; config; config = config->next) |
for (candidate = NULL, count = 0, config = configs; config; config = config->next) |
if (is_config_in_context(context, config)) | if (is_config_in_context(context, config) && |
| match_netid(config->filter, tags, tag_not_needed)) |
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) |
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) |
if (conf_addr->wildcard_mask != 0 && |
if (conf_addr->wildcard_mask != 0 && |
conf_addr->hwaddr_len == hw_len && |
conf_addr->hwaddr_len == hw_len && |
Line 357 struct dhcp_config *find_config(struct dhcp_config *co
|
Line 382 struct dhcp_config *find_config(struct dhcp_config *co
|
return candidate; |
return candidate; |
} |
} |
|
|
|
/* Find tagged configs first. */ |
|
struct dhcp_config *find_config(struct dhcp_config *configs, |
|
struct dhcp_context *context, |
|
unsigned char *clid, int clid_len, |
|
unsigned char *hwaddr, int hw_len, |
|
int hw_type, char *hostname, struct dhcp_netid *tags) |
|
{ |
|
struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0); |
|
|
|
if (!ret) |
|
ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1); |
|
|
|
return ret; |
|
} |
|
|
void dhcp_update_configs(struct dhcp_config *configs) |
void dhcp_update_configs(struct dhcp_config *configs) |
{ |
{ |
/* Some people like to keep all static IP addresses in /etc/hosts. |
/* Some people like to keep all static IP addresses in /etc/hosts. |
Line 371 void dhcp_update_configs(struct dhcp_config *configs)
|
Line 411 void dhcp_update_configs(struct dhcp_config *configs)
|
int prot = AF_INET; |
int prot = AF_INET; |
|
|
for (config = configs; config; config = config->next) |
for (config = configs; config; config = config->next) |
|
{ |
if (config->flags & CONFIG_ADDR_HOSTS) |
if (config->flags & CONFIG_ADDR_HOSTS) |
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS); | config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS); |
| #ifdef HAVE_DHCP6 |
| if (config->flags & CONFIG_ADDR6_HOSTS) |
| config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS); |
| #endif |
| } |
|
|
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
again: |
again: |
Line 403 void dhcp_update_configs(struct dhcp_config *configs)
|
Line 449 void dhcp_update_configs(struct dhcp_config *configs)
|
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags); |
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags); |
if (!crec) |
if (!crec) |
continue; /* should be never */ |
continue; /* should be never */ |
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN); | inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN); |
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), |
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), |
config->hostname, daemon->addrbuff); |
config->hostname, daemon->addrbuff); |
} |
} |
|
|
if (prot == AF_INET && |
if (prot == AF_INET && |
(!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config)) | (!(conf_tmp = config_find_by_address(configs, crec->addr.addr4)) || conf_tmp == config)) |
{ |
{ |
config->addr = crec->addr.addr.addr.addr4; | config->addr = crec->addr.addr4; |
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS; |
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS; |
continue; |
continue; |
} |
} |
|
|
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
if (prot == AF_INET6 && |
if (prot == AF_INET6 && |
(!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config)) | (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr6)) || conf_tmp == config)) |
{ |
{ |
memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ); | /* host must have exactly one address if comming from /etc/hosts. */ |
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS; | if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist)))) |
| { |
| config->addr6->next = NULL; |
| config->addr6->flags = 0; |
| } |
| |
| if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX))) |
| { |
| memcpy(&config->addr6->addr.addr6, &crec->addr.addr6, IN6ADDRSZ); |
| config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS; |
| } |
| |
continue; |
continue; |
} |
} |
#endif |
#endif |
|
|
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN); | inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN); |
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), |
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), |
daemon->addrbuff, config->hostname); |
daemon->addrbuff, config->hostname); |
|
|
Line 485 char *whichdevice(void)
|
Line 542 char *whichdevice(void)
|
|
|
void bindtodevice(char *device, int fd) |
void bindtodevice(char *device, int fd) |
{ |
{ |
struct ifreq ifr; | size_t len = strlen(device)+1; |
| if (len > IFNAMSIZ) |
strcpy(ifr.ifr_name, device); | len = IFNAMSIZ; |
/* only allowed by root. */ |
/* only allowed by root. */ |
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 && | if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 && |
errno != EPERM) |
errno != EPERM) |
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET); |
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET); |
} |
} |
Line 559 static const struct opttab_t {
|
Line 616 static const struct opttab_t {
|
{ "nntp-server", 71, OT_ADDR_LIST }, |
{ "nntp-server", 71, OT_ADDR_LIST }, |
{ "irc-server", 74, OT_ADDR_LIST }, |
{ "irc-server", 74, OT_ADDR_LIST }, |
{ "user-class", 77, 0 }, |
{ "user-class", 77, 0 }, |
|
{ "rapid-commit", 80, 0 }, |
{ "FQDN", 81, OT_INTERNAL }, |
{ "FQDN", 81, OT_INTERNAL }, |
{ "agent-id", 82, OT_INTERNAL }, |
{ "agent-id", 82, OT_INTERNAL }, |
{ "client-arch", 93, 2 | OT_DEC }, |
{ "client-arch", 93, 2 | OT_DEC }, |
Line 569 static const struct opttab_t {
|
Line 627 static const struct opttab_t {
|
{ "sip-server", 120, 0 }, |
{ "sip-server", 120, 0 }, |
{ "classless-static-route", 121, 0 }, |
{ "classless-static-route", 121, 0 }, |
{ "vendor-id-encap", 125, 0 }, |
{ "vendor-id-encap", 125, 0 }, |
|
{ "tftp-server-address", 150, OT_ADDR_LIST }, |
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */ |
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */ |
{ NULL, 0, 0 } |
{ NULL, 0, 0 } |
}; |
}; |
Line 599 static const struct opttab_t opttab6[] = {
|
Line 658 static const struct opttab_t opttab6[] = {
|
{ "sntp-server", 31, OT_ADDR_LIST }, |
{ "sntp-server", 31, OT_ADDR_LIST }, |
{ "information-refresh-time", 32, OT_TIME }, |
{ "information-refresh-time", 32, OT_TIME }, |
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME }, |
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME }, |
{ "ntp-server", 56, 0 }, | { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ }, |
{ "bootfile-url", 59, OT_NAME }, |
{ "bootfile-url", 59, OT_NAME }, |
{ "bootfile-param", 60, OT_CSTRING }, |
{ "bootfile-param", 60, OT_CSTRING }, |
{ NULL, 0, 0 } |
{ NULL, 0, 0 } |
Line 692 char *option_string(int prot, unsigned int opt, unsign
|
Line 751 char *option_string(int prot, unsigned int opt, unsign
|
|
|
if (ot[o].size & OT_ADDR_LIST) |
if (ot[o].size & OT_ADDR_LIST) |
{ |
{ |
struct all_addr addr; | union all_addr addr; |
int addr_len = INADDRSZ; |
int addr_len = INADDRSZ; |
|
|
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
Line 855 void log_context(int family, struct dhcp_context *cont
|
Line 914 void log_context(int family, struct dhcp_context *cont
|
if (context->flags & CONTEXT_RA_STATELESS) |
if (context->flags & CONTEXT_RA_STATELESS) |
{ |
{ |
if (context->flags & CONTEXT_TEMPLATE) |
if (context->flags & CONTEXT_TEMPLATE) |
strncpy(daemon->dhcp_buff, context->template_interface, 256); | strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ); |
else |
else |
strcpy(daemon->dhcp_buff, daemon->addrbuff); |
strcpy(daemon->dhcp_buff, daemon->addrbuff); |
} |
} |
else |
else |
#endif |
#endif |
inet_ntop(family, start, daemon->dhcp_buff, 256); | inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ); |
inet_ntop(family, end, daemon->dhcp_buff3, 256); | inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ); |
my_syslog(MS_DHCP | LOG_INFO, |
my_syslog(MS_DHCP | LOG_INFO, |
(context->flags & CONTEXT_RA_STATELESS) ? |
(context->flags & CONTEXT_RA_STATELESS) ? |
_("%s stateless on %s%.0s%.0s%s") : |
_("%s stateless on %s%.0s%.0s%s") : |