Commit 3f2873d4 authored by Simon Kelley's avatar Simon Kelley

Handle IPv4 interface-address labels in Linux.

parent ab915f83
...@@ -21,6 +21,15 @@ version 2.67 ...@@ -21,6 +21,15 @@ version 2.67
Fix failure to compile ipset.c if old kernel headers are Fix failure to compile ipset.c if old kernel headers are
in use. Thanks to Eugene Rudoy for pointing this out. in use. Thanks to Eugene Rudoy for pointing this out.
Handle IPv4 interface-address labels in Linux. These are
often used to emulate the old IP-alias addresses. Before,
using --interface=eth0 would service all the addresses of
eth0, including ones configured as aliases, which appear
in ifconfig as eth0:0. Now, only addresses with the label
eth0 are active. This is not backwards compatible: if you
want to continue to bind the aliases too, you need to add
eg. --interface=eth0:0 to the config.
version 2.66 version 2.66
......
...@@ -123,7 +123,7 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -123,7 +123,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
else else
broadcast.s_addr = 0; broadcast.s_addr = 0;
if (!((*callback)(addr, iface_index, netmask, broadcast, parm))) if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
goto err; goto err;
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
......
...@@ -28,9 +28,9 @@ struct match_param { ...@@ -28,9 +28,9 @@ struct match_param {
struct in_addr netmask, broadcast, addr; struct in_addr netmask, broadcast, addr;
}; };
static int complete_context(struct in_addr local, int if_index, static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam); struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int check_listen_addrs(struct in_addr local, int if_index, static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam); struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int make_fd(int port) static int make_fd(int port)
...@@ -287,7 +287,7 @@ void dhcp_packet(time_t now, int pxe_fd) ...@@ -287,7 +287,7 @@ void dhcp_packet(time_t now, int pxe_fd)
iface_addr = match.addr; iface_addr = match.addr;
/* make sure secondary address gets priority in case /* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */ there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm); complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
} }
if (!iface_enumerate(AF_INET, &parm, complete_context)) if (!iface_enumerate(AF_INET, &parm, complete_context))
...@@ -411,12 +411,14 @@ void dhcp_packet(time_t now, int pxe_fd) ...@@ -411,12 +411,14 @@ void dhcp_packet(time_t now, int pxe_fd)
} }
/* check against secondary interface addresses */ /* check against secondary interface addresses */
static int check_listen_addrs(struct in_addr local, int if_index, static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam) struct in_addr netmask, struct in_addr broadcast, void *vparam)
{ {
struct match_param *param = vparam; struct match_param *param = vparam;
struct iname *tmp; struct iname *tmp;
(void) label;
if (if_index == param->ind) if (if_index == param->ind)
{ {
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next) for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
...@@ -444,11 +446,13 @@ static int check_listen_addrs(struct in_addr local, int if_index, ...@@ -444,11 +446,13 @@ static int check_listen_addrs(struct in_addr local, int if_index,
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */ Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
static int complete_context(struct in_addr local, int if_index, static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam) struct in_addr netmask, struct in_addr broadcast, void *vparam)
{ {
struct dhcp_context *context; struct dhcp_context *context;
struct iface_param *param = vparam; struct iface_param *param = vparam;
(void)label;
for (context = daemon->dhcp; context; context = context->next) for (context = daemon->dhcp; context; context = context->next)
{ {
......
...@@ -1030,6 +1030,7 @@ void create_bound_listeners(int die); ...@@ -1030,6 +1030,7 @@ void create_bound_listeners(int die);
int is_dad_listeners(void); int is_dad_listeners(void);
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns); int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
int loopback_exception(int fd, int family, struct all_addr *addr, char *name); int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
int label_exception(int index, int family, struct all_addr *addr);
int fix_fd(int fd); int fix_fd(int fd);
int tcp_interface(int fd, int af); int tcp_interface(int fd, int af);
struct in_addr get_ifaddr(char *intr); struct in_addr get_ifaddr(char *intr);
......
...@@ -789,7 +789,8 @@ void receive_query(struct listener *listen, time_t now) ...@@ -789,7 +789,8 @@ void receive_query(struct listener *listen, time_t now)
{ {
if (!option_bool(OPT_CLEVERBIND)) if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces(); enumerate_interfaces();
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name)) if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
!label_exception(if_index, listen->family, &dst_addr))
return; return;
} }
......
...@@ -345,11 +345,12 @@ void lease_update_file(time_t now) ...@@ -345,11 +345,12 @@ void lease_update_file(time_t now)
} }
static int find_interface_v4(struct in_addr local, int if_index, static int find_interface_v4(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam) struct in_addr netmask, struct in_addr broadcast, void *vparam)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
(void) label;
(void) broadcast; (void) broadcast;
(void) vparam; (void) vparam;
......
...@@ -215,7 +215,8 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -215,7 +215,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (ifa->ifa_family == AF_INET) if (ifa->ifa_family == AF_INET)
{ {
struct in_addr netmask, addr, broadcast; struct in_addr netmask, addr, broadcast;
char *label = NULL;
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen)); netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
addr.s_addr = 0; addr.s_addr = 0;
broadcast.s_addr = 0; broadcast.s_addr = 0;
...@@ -226,12 +227,14 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -226,12 +227,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr = *((struct in_addr *)(rta+1)); addr = *((struct in_addr *)(rta+1));
else if (rta->rta_type == IFA_BROADCAST) else if (rta->rta_type == IFA_BROADCAST)
broadcast = *((struct in_addr *)(rta+1)); broadcast = *((struct in_addr *)(rta+1));
else if (rta->rta_type == IFA_LABEL)
label = RTA_DATA(rta);
rta = RTA_NEXT(rta, len1); rta = RTA_NEXT(rta, len1);
} }
if (addr.s_addr && callback_ok) if (addr.s_addr && callback_ok)
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm))) if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
callback_ok = 0; callback_ok = 0;
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
......
...@@ -204,7 +204,27 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name) ...@@ -204,7 +204,27 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
return 0; return 0;
} }
static int iface_allowed(struct irec **irecp, int if_index, /* If we're configured with something like --interface=eth0:0 then we'll listen correctly
on the relevant address, but the name of the arrival interface, derived from the
index won't match the config. Check that we found an interface address for the arrival
interface: daemon->interfaces must be up-to-date. */
int label_exception(int index, int family, struct all_addr *addr)
{
struct irec *iface;
/* labels only supported on IPv4 addresses. */
if (family != AF_INET)
return 0;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
return 1;
return 0;
}
static int iface_allowed(struct irec **irecp, int if_index, char *label,
union mysockaddr *addr, struct in_addr netmask, int dad) union mysockaddr *addr, struct in_addr netmask, int dad)
{ {
struct irec *iface; struct irec *iface;
...@@ -242,8 +262,8 @@ static int iface_allowed(struct irec **irecp, int if_index, ...@@ -242,8 +262,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
loopback = ifr.ifr_flags & IFF_LOOPBACK; loopback = ifr.ifr_flags & IFF_LOOPBACK;
if (loopback) if (loopback)
dhcp_ok = 0; dhcp_ok = 0;
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1) if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu; mtu = ifr.ifr_mtu;
...@@ -272,13 +292,16 @@ static int iface_allowed(struct irec **irecp, int if_index, ...@@ -272,13 +292,16 @@ static int iface_allowed(struct irec **irecp, int if_index,
} }
} }
if (!label)
label = ifr.ifr_name;
if (addr->sa.sa_family == AF_INET && if (addr->sa.sa_family == AF_INET &&
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns)) !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
return 1; return 1;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 && if (addr->sa.sa_family == AF_INET6 &&
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns)) !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
return 1; return 1;
#endif #endif
...@@ -348,11 +371,11 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix, ...@@ -348,11 +371,11 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
addr.in6.sin6_port = htons(daemon->port); addr.in6.sin6_port = htons(daemon->port);
addr.in6.sin6_scope_id = if_index; addr.in6.sin6_scope_id = if_index;
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE)); return iface_allowed((struct irec **)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
} }
#endif #endif
static int iface_allowed_v4(struct in_addr local, int if_index, static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam) struct in_addr netmask, struct in_addr broadcast, void *vparam)
{ {
union mysockaddr addr; union mysockaddr addr;
...@@ -366,7 +389,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, ...@@ -366,7 +389,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
addr.in.sin_addr = local; addr.in.sin_addr = local;
addr.in.sin_port = htons(daemon->port); addr.in.sin_port = htons(daemon->port);
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0); return iface_allowed((struct irec **)vparam, if_index, label, &addr, netmask, 0);
} }
int enumerate_interfaces(void) int enumerate_interfaces(void)
......
...@@ -202,7 +202,8 @@ void tftp_request(struct listener *listen, time_t now) ...@@ -202,7 +202,8 @@ void tftp_request(struct listener *listen, time_t now)
{ {
if (!option_bool(OPT_CLEVERBIND)) if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces(); enumerate_interfaces();
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name)) if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
!label_exception(if_index, listen->family, &addra) )
return; return;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment