summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dhcp.c24
-rw-r--r--src/dnsmasq.h7
-rw-r--r--src/rfc2131.c11
3 files changed, 24 insertions, 18 deletions
diff --git a/src/dhcp.c b/src/dhcp.c
index 5b8c319..232e344 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -145,7 +145,7 @@ void dhcp_packet(time_t now, int pxe_fd)
struct cmsghdr *cmptr;
struct iovec iov;
ssize_t sz;
- int iface_index = 0, unicast_dest = 0, is_inform = 0;
+ int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
int rcvd_iface_index;
struct in_addr iface_addr;
struct iface_param parm;
@@ -223,9 +223,13 @@ void dhcp_packet(time_t now, int pxe_fd)
}
#endif
- if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
+ if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
+ ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != -1)
return;
-
+
+ mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
+ loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
+
#ifdef HAVE_LINUX_NETWORK
/* ARP fiddling uses original interface even if we pretend to use a different one. */
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
@@ -331,7 +335,7 @@ void dhcp_packet(time_t now, int pxe_fd)
/* We're relaying this request */
if (parm.relay_local.s_addr != 0 &&
- relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
+ relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
return;
/* May have configured relay, but not DHCP server */
@@ -340,7 +344,7 @@ void dhcp_packet(time_t now, int pxe_fd)
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
- now, unicast_dest, &is_inform, pxe_fd, iface_addr, recvtime);
+ now, unicast_dest, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
lease_update_file(now);
lease_update_dns(0);
@@ -647,7 +651,7 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
This wrapper handles a cache and load-limiting.
Return is NULL is address in use, or a pointer to a cache entry
recording that it isn't. */
-struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash)
+struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
{
static struct ping_result dummy;
struct ping_result *r, *victim = NULL;
@@ -671,9 +675,9 @@ struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int h
}
/* didn't find cached entry */
- if ((count >= max) || option_bool(OPT_NO_PING))
+ if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
{
- /* overloaded, or configured not to check, return "not in use" */
+ /* overloaded, or configured not to check, loopback interface, return "not in use" */
dummy.hash = 0;
return &dummy;
}
@@ -705,7 +709,7 @@ struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int h
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
- struct dhcp_netid *netids, time_t now)
+ struct dhcp_netid *netids, time_t now, int loopback)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
@@ -763,7 +767,7 @@ int address_allocate(struct dhcp_context *context,
{
struct ping_result *r;
- if ((r = do_icmp_ping(now, addr, j)))
+ if ((r = do_icmp_ping(now, addr, j, loopback)))
{
/* consec-ip mode: we offered this address for another client
(different hash) recently, don't offer it to this one. */
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 14783c9..06fae35 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1292,10 +1292,10 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr,
struct dhcp_netid *netids);
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr,
- unsigned int hash);
+ unsigned int hash, int loopback);
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
- struct dhcp_netid *netids, time_t now);
+ struct dhcp_netid *netids, time_t now, int loopback);
void dhcp_read_ethers(void);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *host_from_dns(struct in_addr addr);
@@ -1344,7 +1344,8 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
/* rfc2131.c */
#ifdef HAVE_DHCP
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_fd, struct in_addr fallback, time_t recvtime);
+ size_t sz, time_t now, int unicast_dest, int loopback,
+ int *is_inform, int pxe_fd, struct in_addr fallback, time_t recvtime);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
#endif
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 023a559..484eeaa 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -67,7 +67,8 @@ static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dh
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
- size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback, time_t recvtime)
+ 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;
struct dhcp_lease *ltmp, *lease = NULL;
@@ -575,7 +576,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_prune(lease, now);
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");
}
else
@@ -1036,7 +1037,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if (have_config(config, CONFIG_DECLINED) &&
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);
- else if (!do_icmp_ping(now, config->addr, 0))
+ else if (!do_icmp_ping(now, config->addr, 0, loopback))
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
else
conf = config->addr;
@@ -1050,11 +1051,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
!config_find_by_address(daemon->dhcp_conf, lease->addr))
mess->yiaddr = lease->addr;
else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
- !config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0))
+ !config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0, loopback))
mess->yiaddr = addr;
else if (emac_len == 0)
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");
}