import of dnsmasq-2.48.tar.gz
diff --git a/src/dhcp.c b/src/dhcp.c
index 706f8d4..3a9ffd7 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -16,6 +16,8 @@
#include "dnsmasq.h"
+#ifdef HAVE_DHCP
+
struct iface_param {
struct in_addr relay, primary;
struct dhcp_context *current;
@@ -35,7 +37,7 @@
#endif
if (fd == -1)
- die (_("cannot create DHCP socket : %s"), NULL, EC_BADNET);
+ die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
if (!fix_fd(fd) ||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
@@ -43,7 +45,7 @@
#endif
#if defined(HAVE_LINUX_NETWORK)
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
-#elif defined(IP_RECVIF)
+#else
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
#endif
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
@@ -51,12 +53,7 @@
/* When bind-interfaces is set, there might be more than one dnmsasq
instance binding port 67. That's OK if they serve different networks.
- Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD.
- OpenBSD <= 4.0 screws up IP_RECVIF when SO_REUSEPORT is set, but
- OpenBSD <= 3.9 doesn't have IP_RECVIF anyway, so we just have to elide
- this for OpenBSD 4.0, if you want more than one instance on oBSD4.0, tough. */
-
-#ifndef OpenBSD4_0
+ Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
if (daemon->options & OPT_NOWILD)
{
#ifdef SO_REUSEPORT
@@ -67,7 +64,6 @@
if (rc == -1)
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
}
-#endif
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
@@ -124,7 +120,7 @@
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(HAVE_SOLARIS_NETWORK)
char control[CMSG_SPACE(sizeof(unsigned int))];
-#elif defined(IP_RECVIF)
+#elif defined(HAVE_BSD_NETWORK)
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
} control_u;
@@ -136,13 +132,30 @@
msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1;
- do
+ while (1)
{
msg.msg_flags = 0;
- while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
+ while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
+
+ if (sz == -1)
+ return;
+
+ if (!(msg.msg_flags & MSG_TRUNC))
+ break;
+
+ /* Very new Linux kernels return the actual size needed,
+ older ones always return truncated size */
+ if ((size_t)sz == daemon->dhcp_packet.iov_len)
+ {
+ if (!expand_buf(&daemon->dhcp_packet, sz + 100))
+ return;
+ }
+ else
+ {
+ expand_buf(&daemon->dhcp_packet, sz);
+ break;
+ }
}
- while (sz != -1 && (msg.msg_flags & MSG_TRUNC) &&
- expand_buf(&daemon->dhcp_packet, daemon->dhcp_packet.iov_len + 100));
/* expand_buf may have moved buffer */
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
@@ -154,7 +167,7 @@
while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
- if (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
+ if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
return;
#if defined (HAVE_LINUX_NETWORK)
@@ -166,41 +179,31 @@
if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
unicast_dest = 1;
}
-
- if (!(ifr.ifr_ifindex = iface_index) ||
- ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
- return;
-
-#elif defined(IP_RECVIF)
+
+#elif defined(HAVE_BSD_NETWORK)
if (msg.msg_controllen >= sizeof(struct cmsghdr))
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
-#ifdef HAVE_SOLARIS_NETWORK
- iface_index = *((unsigned int *)CMSG_DATA(cmptr));
-#else
iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
-#endif
-
- if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
- return;
+
+#elif defined(HAVE_SOLARIS_NETWORK)
+ if (msg.msg_controllen >= sizeof(struct cmsghdr))
+ for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
+ if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
+ iface_index = *((unsigned int *)CMSG_DATA(cmptr));
+
+#endif
+
+ if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
+ return;
+
#ifdef MSG_BCAST
/* OpenBSD tells us when a packet was broadcast */
if (!(msg.msg_flags & MSG_BCAST))
unicast_dest = 1;
#endif
-#else
- /* fallback for systems without IP_RECVIF - allow only one interface
- and assume packets arrive from it - yuk. */
- {
- struct iname *name;
- for (name = daemon->if_names; name->isloop; name = name->next);
- strcpy(ifr.ifr_name, name->name);
- iface_index = if_nametoindex(name->name);
- }
-#endif
-
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
{
@@ -208,7 +211,7 @@
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
}
- if (!iface_check(AF_INET, (struct all_addr *)addrp, &ifr, &iface_index))
+ if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -218,9 +221,9 @@
/* interface may have been changed by alias in iface_check */
if (!addrp)
{
- if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1)
+ if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
{
- my_syslog(LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
+ my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
else
@@ -319,7 +322,7 @@
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port);
/* note that we don't specify the interface here: that's done by the
- IP_XMIT_IF sockopt lower down. */
+ IP_BOUND_IF sockopt lower down. */
}
else
{
@@ -345,12 +348,7 @@
#endif
#ifdef HAVE_SOLARIS_NETWORK
- /* OpenSolaris eliminates IP_XMIT_IF */
-# ifdef IP_XMIT_IF
- setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_XMIT_IF, &iface_index, sizeof(iface_index));
-# else
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
-# endif
#endif
while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
@@ -384,7 +382,7 @@
{
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
- my_syslog(LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
+ my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
}
context->netmask = netmask;
@@ -474,9 +472,9 @@
if (!(tmp = address_available(context, taddr, netids)))
{
for (tmp = context; tmp; tmp = tmp->current)
- if (is_same_net(taddr, tmp->start, tmp->netmask) &&
- (tmp->flags & CONTEXT_STATIC))
- break;
+ if (is_same_net(taddr, tmp->start, tmp->netmask) &&
+ (tmp->flags & CONTEXT_STATIC))
+ break;
if (!tmp)
for (tmp = context; tmp; tmp = tmp->current)
@@ -667,7 +665,8 @@
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname)
{
- struct dhcp_config *config;
+ int count, new;
+ struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
@@ -699,17 +698,21 @@
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config))
return config;
-
- for (config = configs; config; config = config->next)
- for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
- if (conf_addr->wildcard_mask != 0 &&
- conf_addr->hwaddr_len == hw_len &&
- (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
- is_addr_in_context(context, config) &&
- memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask))
- return config;
-
- return NULL;
+
+ /* use match with fewest wildcast octets */
+ for (candidate = NULL, count = 0, config = configs; config; config = config->next)
+ if (is_addr_in_context(context, config))
+ for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
+ if (conf_addr->wildcard_mask != 0 &&
+ conf_addr->hwaddr_len == hw_len &&
+ (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
+ (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
+ {
+ count = new;
+ candidate = config;
+ }
+
+ return candidate;
}
void dhcp_read_ethers(void)
@@ -728,7 +731,7 @@
if (!f)
{
- my_syslog(LOG_ERR, _("failed to read %s:%s"), ETHERSFILE, strerror(errno));
+ my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
return;
}
@@ -764,7 +767,7 @@
*ip = 0;
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
{
- my_syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
+ my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
continue;
}
@@ -777,7 +780,7 @@
{
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
{
- my_syslog(LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
+ my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
continue;
}
@@ -791,7 +794,7 @@
{
if (!canonicalise(ip))
{
- my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
+ my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
continue;
}
@@ -857,7 +860,7 @@
fclose(f);
- my_syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
+ my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
}
void check_dhcp_hosts(int fatal)
@@ -882,7 +885,7 @@
die(_("duplicate IP address %s in dhcp-config directive."),
inet_ntoa(cp->addr), EC_BADCONF);
else
- my_syslog(LOG_ERR, _("duplicate IP address %s in %s."),
+ my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
configs->flags &= ~CONFIG_ADDR;
}
@@ -925,12 +928,12 @@
crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
if (!crec)
continue; /* should be never */
- my_syslog(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, inet_ntoa(crec->addr.addr.addr.addr4));
}
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
- my_syslog(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"),
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
else
{
@@ -982,14 +985,5 @@
return NULL;
}
-char *get_domain(struct in_addr addr)
-{
- struct cond_domain *c;
+#endif
- for (c = daemon->cond_domain; c; c = c->next)
- if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
- ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
- return c->domain;
-
- return daemon->domain_suffix;
-}