|
|
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 |
|