85f98a
From 3d27384fc5f2a437b7bce128c8ba62e8d6e12df7 Mon Sep 17 00:00:00 2001
85f98a
From: Brian Haley <haleyb.dev@gmail.com>
85f98a
Date: Wed, 28 Aug 2019 16:13:23 -0400
85f98a
Subject: [PATCH] Change dhcp_release to use default address when no IP subnet
85f98a
 matches
85f98a
85f98a
Currently, dhcp_release will only send a 'fake' release
85f98a
when the address given is in the same subnet as an IP
85f98a
on the interface that was given.
85f98a
85f98a
This doesn't work in an environment where dnsmasq is
85f98a
managing leases for remote subnets via a DHCP relay, as
85f98a
running dhcp_release locally will just cause it to
85f98a
silently exit without doing anything, leaving the lease
85f98a
in the database.
85f98a
85f98a
Change it to use the default IP on the interface, as the
85f98a
dnsmasq source code at src/dhcp.c does, if no matching subnet
85f98a
IP is found, as a fall-back.  This fixes an issue we are
85f98a
seeing in certain Openstack deployments where we are using
85f98a
dnsmasq to provision baremetal systems in a datacenter.
85f98a
85f98a
While using Dbus might have seemed like an obvious solution,
85f98a
because of our extensive use of network namespaces (which
85f98a
Dbus doesn't support), this seemed like a better solution
85f98a
than creating system.d policy files for each dnsmasq we
85f98a
might spawn and using --enable-dbus=$id in order to isolate
85f98a
messages to specific dnsmasq instances.
85f98a
85f98a
Signed-off-by: Brian Haley <haleyb.dev@gmail.com>
85f98a
(cherry picked from commit d9f882bea2806799bf3d1f73937f5e72d0bfc650)
85f98a
---
85f98a
 contrib/lease-tools/dhcp_release.c | 12 +++++++++---
85f98a
 1 file changed, 9 insertions(+), 3 deletions(-)
85f98a
85f98a
diff --git a/contrib/lease-tools/dhcp_release.c b/contrib/lease-tools/dhcp_release.c
85f98a
index a51f04b..1dd8d32 100644
85f98a
--- a/contrib/lease-tools/dhcp_release.c
85f98a
+++ b/contrib/lease-tools/dhcp_release.c
85f98a
@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
85f98a
   return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
85f98a
 }
85f98a
 
85f98a
-static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
85f98a
+static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index, int ifrfd, struct ifreq *ifr)
85f98a
 {
85f98a
   struct sockaddr_nl addr;
85f98a
   struct nlmsghdr *h;
85f98a
@@ -218,7 +218,13 @@ static struct in_addr find_interface(struct in_addr client, int fd, unsigned int
85f98a
 
85f98a
       for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
85f98a
 	if (h->nlmsg_type == NLMSG_DONE)
85f98a
-	  exit(0);
85f98a
+          {
85f98a
+	    /* No match found, return first address as src/dhcp.c code does */
85f98a
+	    ifr->ifr_addr.sa_family = AF_INET;
85f98a
+	    if (ioctl(ifrfd, SIOCGIFADDR, ifr) != -1)
85f98a
+	      return ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
85f98a
+	    exit(0);
85f98a
+          }
85f98a
 	else if (h->nlmsg_type == RTM_NEWADDR)
85f98a
           {
85f98a
             struct ifaddrmsg *ifa = NLMSG_DATA(h);  
85f98a
@@ -284,7 +290,7 @@ int main(int argc, char **argv)
85f98a
     }
85f98a
   
85f98a
   lease.s_addr = inet_addr(argv[2]);
85f98a
-  server = find_interface(lease, nl, if_nametoindex(argv[1]));
85f98a
+  server = find_interface(lease, nl, if_nametoindex(argv[1]), fd, &ifr);
85f98a
   
85f98a
   memset(&packet, 0, sizeof(packet));
85f98a
  
85f98a
-- 
85f98a
2.20.1
85f98a