summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2014-07-12 16:39:00 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2014-07-12 16:39:00 +0100
commit24b167ada814875df3cf43a5084627755ad912c5 (patch)
tree703b6ce6a2fd01d4ed972834c126c698b03a6190
parent993f8cbb1bec7552f237e9ed40ed1ec7871d8639 (diff)
parentdc8a1b1bcf1a4420063c3a708580fcd3277130c5 (diff)
downloaddnsmasq-24b167ada814875df3cf43a5084627755ad912c5.tar.gz
Fix logic for associating leases with interfaces.
This handles the case that more than one interface contains the network the lease address is on, but the interfaces have different prefix lengths. Use the longest prefix length.
-rw-r--r--src/dnsmasq.h4
-rw-r--r--src/lease.c40
-rw-r--r--src/util.c12
3 files changed, 47 insertions, 9 deletions
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 30f176a..8e103d3 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -641,6 +641,8 @@ struct dhcp_lease {
unsigned char *extradata;
unsigned int extradata_len, extradata_size;
int last_interface;
+ int new_interface; /* save possible originated interface */
+ int new_prefixlen; /* and its prefix length */
#ifdef HAVE_DHCP6
struct in6_addr addr6;
int iaid;
@@ -1132,6 +1134,7 @@ int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
int hostname_isequal(const char *a, const char *b);
time_t dnsmasq_time(void);
+int netmask_length(struct in_addr mask);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
#ifdef HAVE_IPV6
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
@@ -1244,6 +1247,7 @@ char *host_from_dns(struct in_addr addr);
#ifdef HAVE_DHCP
void lease_update_file(time_t now);
void lease_update_dns(int force);
+void lease_update_interface(time_t now);
void lease_init(time_t now);
struct dhcp_lease *lease4_allocate(struct in_addr addr);
#ifdef HAVE_DHCP6
diff --git a/src/lease.c b/src/lease.c
index 5d1eefc..9479afc 100644
--- a/src/lease.c
+++ b/src/lease.c
@@ -352,16 +352,21 @@ 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 dhcp_lease *lease;
-
+ int prefix;
+
(void) label;
(void) broadcast;
(void) vparam;
for (lease = leases; lease; lease = lease->next)
- if (!(lease->flags & (LEASE_TA | LEASE_NA)))
- if (is_same_net(local, lease->addr, netmask))
- lease_set_interface(lease, if_index, *((time_t *)vparam));
-
+ if (!(lease->flags & (LEASE_TA | LEASE_NA))) {
+ prefix = netmask_length(netmask);
+ if (is_same_net(local, lease->addr, netmask) && prefix > lease->new_prefixlen) {
+ lease->new_interface = if_index;
+ lease->new_prefixlen = prefix;
+ }
+ }
+
return 1;
}
@@ -371,17 +376,23 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
int preferred, int valid, void *vparam)
{
struct dhcp_lease *lease;
-
+
(void)scope;
(void)flags;
(void)preferred;
(void)valid;
+ (void)vparam;
for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA)))
- if (is_same_net6(local, &lease->addr6, prefix))
- lease_set_interface(lease, if_index, *((time_t *)vparam));
-
+ if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
+ /* save prefix length for comparison, as we might get shorter matching
+ * prefix in upcoming netlink GETADDR responses
+ * */
+ lease->new_interface = if_index;
+ lease->new_prefixlen = prefix;
+ }
+
return 1;
}
@@ -418,6 +429,7 @@ void lease_find_interfaces(time_t now)
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, &now, find_interface_v6);
#endif
+ lease_update_interface(now);
}
#ifdef HAVE_DHCP6
@@ -492,6 +504,16 @@ void lease_update_dns(int force)
}
}
+void lease_update_interface(time_t now)
+{
+ struct dhcp_lease *lease;
+
+ for (lease = leases; lease; lease = lease->next)
+ if (lease->new_interface > 0) {
+ lease_set_interface(lease, lease->new_interface, now);
+ }
+}
+
void lease_prune(struct dhcp_lease *target, time_t now)
{
struct dhcp_lease *lease, *tmp, **up;
diff --git a/src/util.c b/src/util.c
index a503082..c1b0c50 100644
--- a/src/util.c
+++ b/src/util.c
@@ -319,6 +319,18 @@ time_t dnsmasq_time(void)
#endif
}
+int netmask_length(struct in_addr mask)
+{
+ int zero_count = 0;
+
+ while (0x0 == (mask.s_addr & 0x1)) {
+ mask.s_addr >>= 1;
+ ++zero_count;
+ }
+
+ return 32 - zero_count;
+}
+
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
{
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);