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