Blame SOURCES/dnsmasq-2.66-Handle_IPv4_interface_address_labels_in_Linux.patch

cab8d5
From 3f2873d42c4d7e7dba32b6e64a3687d43928bc8e Mon Sep 17 00:00:00 2001
cab8d5
From: Simon Kelley <simon@thekelleys.org.uk>
cab8d5
Date: Tue, 14 May 2013 11:28:47 +0100
cab8d5
Subject: [PATCH]  Handle IPv4 interface-address labels in Linux.
cab8d5
cab8d5
---
cab8d5
 CHANGELOG     |  9 +++++++++
cab8d5
 src/bpf.c     |  2 +-
cab8d5
 src/dhcp.c    | 14 +++++++++-----
cab8d5
 src/dnsmasq.h |  1 +
cab8d5
 src/forward.c |  3 ++-
cab8d5
 src/lease.c   |  3 ++-
cab8d5
 src/netlink.c |  7 +++++--
cab8d5
 src/network.c | 39 +++++++++++++++++++++++++++++++--------
cab8d5
 src/tftp.c    |  3 ++-
cab8d5
 9 files changed, 62 insertions(+), 19 deletions(-)
cab8d5
cab8d5
diff --git a/CHANGELOG b/CHANGELOG
cab8d5
index f6ce80e..7aa0024 100644
cab8d5
--- a/CHANGELOG
cab8d5
+++ b/CHANGELOG
cab8d5
@@ -21,6 +21,15 @@ version 2.67
cab8d5
	    Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
cab8d5
	    to work with BOOTP and well as DHCP. Thanks to Peter
cab8d5
	    Korsgaard for spotting the problem. 
cab8d5
+
cab8d5
+	    Handle IPv4 interface-address labels in Linux. These are
cab8d5
+	    often used to emulate the old IP-alias addresses. Before,
cab8d5
+	    using --interface=eth0 would service all the addresses of
cab8d5
+	    eth0, including ones configured as aliases, which appear
cab8d5
+	    in ifconfig as eth0:0. Now, only addresses with the label
cab8d5
+	    eth0 are active. This is not backwards compatible: if you
cab8d5
+	    want to continue to bind the aliases too, you need to add
cab8d5
+	    eg. --interface=eth0:0 to the config. 
cab8d5
 	
cab8d5
 
cab8d5
 version 2.66
cab8d5
diff --git a/src/bpf.c b/src/bpf.c
cab8d5
index 02a3abb..e75b0c6 100644
cab8d5
--- a/src/bpf.c
cab8d5
+++ b/src/bpf.c
cab8d5
@@ -123,7 +123,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
cab8d5
 		broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; 
cab8d5
 	      else 
cab8d5
 		broadcast.s_addr = 0;	      
cab8d5
-	      if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
cab8d5
+	      if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
cab8d5
 		goto err;
cab8d5
 	    }
cab8d5
 #ifdef HAVE_IPV6
cab8d5
diff --git a/src/dhcp.c b/src/dhcp.c
cab8d5
index dd25632..333a327 100644
cab8d5
--- a/src/dhcp.c
cab8d5
+++ b/src/dhcp.c
cab8d5
@@ -28,9 +28,9 @@ struct match_param {
cab8d5
   struct in_addr netmask, broadcast, addr;
cab8d5
 };
cab8d5
 
cab8d5
-static int complete_context(struct in_addr local, int if_index, 
cab8d5
+static int complete_context(struct in_addr local, int if_index, char *label,
cab8d5
 			    struct in_addr netmask, struct in_addr broadcast, void *vparam);
cab8d5
-static int check_listen_addrs(struct in_addr local, int if_index, 
cab8d5
+static int check_listen_addrs(struct in_addr local, int if_index, char *label,
cab8d5
 			      struct in_addr netmask, struct in_addr broadcast, void *vparam);
cab8d5
 
cab8d5
 static int make_fd(int port)
cab8d5
@@ -287,7 +287,7 @@ void dhcp_packet(time_t now, int pxe_fd)
cab8d5
       iface_addr = match.addr;
cab8d5
       /* make sure secondary address gets priority in case
cab8d5
 	 there is more than one address on the interface in the same subnet */
cab8d5
-      complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm;;
cab8d5
+      complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm;;
cab8d5
     }    
cab8d5
       
cab8d5
   if (!iface_enumerate(AF_INET, &parm, complete_context))
cab8d5
@@ -411,12 +411,14 @@ void dhcp_packet(time_t now, int pxe_fd)
cab8d5
 }
cab8d5
  
cab8d5
 /* check against secondary interface addresses */
cab8d5
-static int check_listen_addrs(struct in_addr local, int if_index, 
cab8d5
+static int check_listen_addrs(struct in_addr local, int if_index, char *label,
cab8d5
 			      struct in_addr netmask, struct in_addr broadcast, void *vparam)
cab8d5
 {
cab8d5
   struct match_param *param = vparam;
cab8d5
   struct iname *tmp;
cab8d5
 
cab8d5
+  (void) label;
cab8d5
+
cab8d5
   if (if_index == param->ind)
cab8d5
     {
cab8d5
       for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
cab8d5
@@ -444,11 +446,13 @@ static int check_listen_addrs(struct in_addr local, int if_index,
cab8d5
 
cab8d5
    Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
cab8d5
 
cab8d5
-static int complete_context(struct in_addr local, int if_index, 
cab8d5
+static int complete_context(struct in_addr local, int if_index, char *label,
cab8d5
 			    struct in_addr netmask, struct in_addr broadcast, void *vparam)
cab8d5
 {
cab8d5
   struct dhcp_context *context;
cab8d5
   struct iface_param *param = vparam;
cab8d5
+
cab8d5
+  (void)label;
cab8d5
   
cab8d5
   for (context = daemon->dhcp; context; context = context->next)
cab8d5
     {
cab8d5
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
cab8d5
index e177cea..8866dd8 100644
cab8d5
--- a/src/dnsmasq.h
cab8d5
+++ b/src/dnsmasq.h
cab8d5
@@ -1030,6 +1030,7 @@ void create_bound_listeners(int die);
cab8d5
 int is_dad_listeners(void);
cab8d5
 int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
cab8d5
 int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
cab8d5
+int label_exception(int index, int family, struct all_addr *addr);
cab8d5
 int fix_fd(int fd);
cab8d5
 int tcp_interface(int fd, int af);
cab8d5
 struct in_addr get_ifaddr(char *intr);
cab8d5
diff --git a/src/forward.c b/src/forward.c
cab8d5
index 78495ca..28fe9eb 100644
cab8d5
--- a/src/forward.c
cab8d5
+++ b/src/forward.c
cab8d5
@@ -789,7 +789,8 @@ void receive_query(struct listener *listen, time_t now)
cab8d5
 	{
cab8d5
 	   if (!option_bool(OPT_CLEVERBIND))
cab8d5
 	     enumerate_interfaces(); 
cab8d5
-	   if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name))
cab8d5
+	   if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
cab8d5
+	       !label_exception(if_index, listen->family, &dst_addr))
cab8d5
 	     return;
cab8d5
 	}
cab8d5
 
cab8d5
diff --git a/src/lease.c b/src/lease.c
cab8d5
index a4560ba..b85cf57 100644
cab8d5
--- a/src/lease.c
cab8d5
+++ b/src/lease.c
cab8d5
@@ -345,11 +345,12 @@ void lease_update_file(time_t now)
cab8d5
 }
cab8d5
 
cab8d5
 
cab8d5
-static int find_interface_v4(struct in_addr local, int if_index, 
cab8d5
+static int find_interface_v4(struct in_addr local, int if_index, char *label,
cab8d5
 			     struct in_addr netmask, struct in_addr broadcast, void *vparam)
cab8d5
 {
cab8d5
   struct dhcp_lease *lease;
cab8d5
   
cab8d5
+  (void) label;
cab8d5
   (void) broadcast;
cab8d5
   (void) vparam;
cab8d5
 
cab8d5
diff --git a/src/netlink.c b/src/netlink.c
cab8d5
index 0881b71..78d0926 100644
cab8d5
--- a/src/netlink.c
cab8d5
+++ b/src/netlink.c
cab8d5
@@ -215,7 +215,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
cab8d5
 		if (ifa->ifa_family == AF_INET)
cab8d5
 		  {
cab8d5
 		    struct in_addr netmask, addr, broadcast;
cab8d5
-		    
cab8d5
+		    char *label = NULL;
cab8d5
+
cab8d5
 		    netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
cab8d5
 		    addr.s_addr = 0;
cab8d5
 		    broadcast.s_addr = 0;
cab8d5
@@ -226,12 +227,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
cab8d5
 			  addr = *((struct in_addr *)(rta+1));
cab8d5
 			else if (rta->rta_type == IFA_BROADCAST)
cab8d5
 			  broadcast = *((struct in_addr *)(rta+1));
cab8d5
+			else if (rta->rta_type == IFA_LABEL)
cab8d5
+			  label = RTA_DATA(rta);
cab8d5
 			
cab8d5
 			rta = RTA_NEXT(rta, len1);
cab8d5
 		      }
cab8d5
 		    
cab8d5
 		    if (addr.s_addr && callback_ok)
cab8d5
-		      if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
cab8d5
+		      if (!((*callback)(addr, ifa->ifa_index, label,  netmask, broadcast, parm)))
cab8d5
 			callback_ok = 0;
cab8d5
 		  }
cab8d5
 #ifdef HAVE_IPV6
cab8d5
diff --git a/src/network.c b/src/network.c
cab8d5
index 792914b..473e85f 100644
cab8d5
--- a/src/network.c
cab8d5
+++ b/src/network.c
cab8d5
@@ -204,7 +204,27 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
cab8d5
   return 0;
cab8d5
 }
cab8d5
 
cab8d5
-static int iface_allowed(struct irec **irecp, int if_index, 
cab8d5
+/* If we're configured with something like --interface=eth0:0 then we'll listen correctly
cab8d5
+   on the relevant address, but the name of the arrival interface, derived from the
cab8d5
+   index won't match the config. Check that we found an interface address for the arrival 
cab8d5
+   interface: daemon->interfaces must be up-to-date. */
cab8d5
+int label_exception(int index, int family, struct all_addr *addr)
cab8d5
+{
cab8d5
+  struct irec *iface;
cab8d5
+
cab8d5
+  /* labels only supported on IPv4 addresses. */
cab8d5
+  if (family != AF_INET)
cab8d5
+    return 0;
cab8d5
+
cab8d5
+  for (iface = daemon->interfaces; iface; iface = iface->next)
cab8d5
+    if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
cab8d5
+	iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
cab8d5
+      return 1;
cab8d5
+
cab8d5
+  return 0;
cab8d5
+}
cab8d5
+
cab8d5
+static int iface_allowed(struct irec **irecp, int if_index, char *label,
cab8d5
 			 union mysockaddr *addr, struct in_addr netmask, int dad) 
cab8d5
 {
cab8d5
   struct irec *iface;
cab8d5
@@ -242,8 +262,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
cab8d5
   loopback = ifr.ifr_flags & IFF_LOOPBACK;
cab8d5
   
cab8d5
   if (loopback)
cab8d5
-     dhcp_ok = 0;
cab8d5
-
cab8d5
+    dhcp_ok = 0;
cab8d5
+  
cab8d5
   if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
cab8d5
     mtu = ifr.ifr_mtu;
cab8d5
   
cab8d5
@@ -272,13 +292,16 @@ static int iface_allowed(struct irec **irecp, int if_index,
cab8d5
 	}
cab8d5
     }
cab8d5
   
cab8d5
+  if (!label)
cab8d5
+    label = ifr.ifr_name;
cab8d5
+
cab8d5
   if (addr->sa.sa_family == AF_INET &&
cab8d5
-      !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
cab8d5
+      !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
cab8d5
     return 1;
cab8d5
 
cab8d5
 #ifdef HAVE_IPV6
cab8d5
   if (addr->sa.sa_family == AF_INET6 &&
cab8d5
-      !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
cab8d5
+      !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
cab8d5
     return 1;
cab8d5
 #endif
cab8d5
     
cab8d5
@@ -348,11 +371,11 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
cab8d5
   addr.in6.sin6_port = htons(daemon->port);
cab8d5
   addr.in6.sin6_scope_id = if_index;
cab8d5
   
cab8d5
-  return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
cab8d5
+  return iface_allowed((struct irec **)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
cab8d5
 }
cab8d5
 #endif
cab8d5
 
cab8d5
-static int iface_allowed_v4(struct in_addr local, int if_index, 
cab8d5
+static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
cab8d5
 			    struct in_addr netmask, struct in_addr broadcast, void *vparam)
cab8d5
 {
cab8d5
   union mysockaddr addr;
cab8d5
@@ -366,7 +389,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
cab8d5
   addr.in.sin_addr = local;
cab8d5
   addr.in.sin_port = htons(daemon->port);
cab8d5
 
cab8d5
-  return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
cab8d5
+  return iface_allowed((struct irec **)vparam, if_index, label, &addr, netmask, 0);
cab8d5
 }
cab8d5
    
cab8d5
 int enumerate_interfaces(void)
cab8d5
diff --git a/src/tftp.c b/src/tftp.c
cab8d5
index 960b1ee..d7d050f 100644
cab8d5
--- a/src/tftp.c
cab8d5
+++ b/src/tftp.c
cab8d5
@@ -202,7 +202,8 @@ void tftp_request(struct listener *listen, time_t now)
cab8d5
 	{
cab8d5
 	  if (!option_bool(OPT_CLEVERBIND))
cab8d5
 	    enumerate_interfaces(); 
cab8d5
-	  if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
cab8d5
+	  if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
cab8d5
+	      !label_exception(if_index, listen->family, &addra) )
cab8d5
 	    return;
cab8d5
 	}
cab8d5
       
cab8d5
-- 
cab8d5
1.8.1.4
cab8d5