mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Check assumed SLAAC addresses by pinging them.
This commit is contained in:
2
Makefile
2
Makefile
@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
|||||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||||
dhcp-common.o outpacket.o radv.o
|
dhcp-common.o outpacket.o radv.o slaac.o
|
||||||
|
|
||||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||||
dns-protocol.h radv-protocol.h
|
dns-protocol.h radv-protocol.h
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
|||||||
netlink.c network.c option.c rfc1035.c \
|
netlink.c network.c option.c rfc1035.c \
|
||||||
rfc2131.c tftp.c util.c conntrack.c \
|
rfc2131.c tftp.c util.c conntrack.c \
|
||||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||||
radv.c
|
radv.c slaac.c
|
||||||
|
|
||||||
LOCAL_MODULE := dnsmasq
|
LOCAL_MODULE := dnsmasq
|
||||||
|
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
lease_update_dns();
|
lease_update_dns(0);
|
||||||
|
|
||||||
if (iov.iov_len == 0)
|
if (iov.iov_len == 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ void dhcp6_packet(time_t now)
|
|||||||
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
|
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
|
||||||
|
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
lease_update_dns();
|
lease_update_dns(0);
|
||||||
|
|
||||||
/* The port in the source address of the original request should
|
/* The port in the source address of the original request should
|
||||||
be correct, but at least once client sends from the server port,
|
be correct, but at least once client sends from the server port,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ struct daemon *daemon;
|
|||||||
|
|
||||||
static volatile pid_t pid = 0;
|
static volatile pid_t pid = 0;
|
||||||
static volatile int pipewrite;
|
static volatile int pipewrite;
|
||||||
|
static int alarm_queued = 0;
|
||||||
|
|
||||||
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
|
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
|
||||||
static void check_dns_listeners(fd_set *set, time_t now);
|
static void check_dns_listeners(fd_set *set, time_t now);
|
||||||
@@ -864,9 +865,23 @@ static void sig_handler(int sig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_alarm(void)
|
/* now == 0 -> queue immediate callback */
|
||||||
|
void send_alarm(time_t event, time_t now)
|
||||||
{
|
{
|
||||||
send_event(pipewrite, EVENT_ALARM, 0, NULL);
|
|
||||||
|
if (now != 0 && event == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((now == 0 || difftime(event, now) <= 0.0))
|
||||||
|
{
|
||||||
|
if (!alarm_queued)
|
||||||
|
{
|
||||||
|
send_event(pipewrite, EVENT_ALARM, 0, NULL);
|
||||||
|
alarm_queued = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
alarm((unsigned)difftime(event, now));
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_event(int fd, int event, int data, char *msg)
|
void send_event(int fd, int event, int data, char *msg)
|
||||||
@@ -980,6 +995,7 @@ static void async_event(int pipe, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_ALARM:
|
case EVENT_ALARM:
|
||||||
|
alarm_queued = 0;
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (daemon->dhcp || daemon->dhcp6)
|
if (daemon->dhcp || daemon->dhcp6)
|
||||||
{
|
{
|
||||||
@@ -988,13 +1004,8 @@ static void async_event(int pipe, time_t now)
|
|||||||
}
|
}
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
else if (daemon->ra_contexts)
|
else if (daemon->ra_contexts)
|
||||||
{
|
/* Not doing DHCP, so no lease system, manage alarms for ra only */
|
||||||
/* Not doing DHCP, so no lease system, manage
|
send_alarm(periodic_ra(now), now);
|
||||||
alarms for ra only */
|
|
||||||
time_t next_event = periodic_ra(now);
|
|
||||||
if (next_event != 0)
|
|
||||||
alarm((unsigned)difftime(next_event, now));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
@@ -1158,7 +1169,7 @@ void clear_cache_and_reload(time_t now)
|
|||||||
check_dhcp_hosts(0);
|
check_dhcp_hosts(0);
|
||||||
lease_update_from_configs();
|
lease_update_from_configs();
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
lease_update_dns();
|
lease_update_dns(1);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
else if (daemon->ra_contexts)
|
else if (daemon->ra_contexts)
|
||||||
|
|||||||
@@ -466,6 +466,7 @@ struct frec {
|
|||||||
#define LEASE_USED 16 /* used this DHCPv6 transaction */
|
#define LEASE_USED 16 /* used this DHCPv6 transaction */
|
||||||
#define LEASE_NA 32 /* IPv6 no-temporary lease */
|
#define LEASE_NA 32 /* IPv6 no-temporary lease */
|
||||||
#define LEASE_TA 64 /* IPv6 temporary lease */
|
#define LEASE_TA 64 /* IPv6 temporary lease */
|
||||||
|
#define LEASE_HAVE_HWADDR 128 /* Have set hwaddress */
|
||||||
|
|
||||||
struct dhcp_lease {
|
struct dhcp_lease {
|
||||||
int clid_len; /* length of client identifier */
|
int clid_len; /* length of client identifier */
|
||||||
@@ -483,6 +484,14 @@ struct dhcp_lease {
|
|||||||
unsigned char *extradata;
|
unsigned char *extradata;
|
||||||
unsigned int extradata_len, extradata_size;
|
unsigned int extradata_len, extradata_size;
|
||||||
int last_interface;
|
int last_interface;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct slaac_address {
|
||||||
|
struct in6_addr addr, local;
|
||||||
|
time_t ping_time;
|
||||||
|
int backoff; /* zero -> confirmed */
|
||||||
|
struct slaac_address *next;
|
||||||
|
} *slaac_address;
|
||||||
|
#endif
|
||||||
struct dhcp_lease *next;
|
struct dhcp_lease *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -627,7 +636,7 @@ struct dhcp_context {
|
|||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
struct in6_addr start6, end6; /* range of available addresses */
|
struct in6_addr start6, end6; /* range of available addresses */
|
||||||
struct in6_addr local6;
|
struct in6_addr local6;
|
||||||
int prefix;
|
int prefix, if_index;
|
||||||
time_t ra_time;
|
time_t ra_time;
|
||||||
#endif
|
#endif
|
||||||
int flags;
|
int flags;
|
||||||
@@ -651,13 +660,6 @@ struct ping_result {
|
|||||||
struct ping_result *next;
|
struct ping_result *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct subnet_map {
|
|
||||||
int iface;
|
|
||||||
struct in6_addr subnet;
|
|
||||||
struct subnet_map *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct tftp_file {
|
struct tftp_file {
|
||||||
int refcount, fd;
|
int refcount, fd;
|
||||||
off_t size;
|
off_t size;
|
||||||
@@ -957,7 +959,7 @@ char *host_from_dns(struct in_addr addr);
|
|||||||
/* lease.c */
|
/* lease.c */
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
void lease_update_file(time_t now);
|
void lease_update_file(time_t now);
|
||||||
void lease_update_dns();
|
void lease_update_dns(int force);
|
||||||
void lease_init(time_t now);
|
void lease_init(time_t now);
|
||||||
struct dhcp_lease *lease4_allocate(struct in_addr addr);
|
struct dhcp_lease *lease4_allocate(struct in_addr addr);
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
@@ -966,12 +968,13 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
|
|||||||
int lease_type, int iaid, struct in6_addr *addr);
|
int lease_type, int iaid, struct in6_addr *addr);
|
||||||
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
|
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
|
||||||
u64 lease_find_max_addr6(struct dhcp_context *context);
|
u64 lease_find_max_addr6(struct dhcp_context *context);
|
||||||
|
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
|
||||||
#endif
|
#endif
|
||||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||||
unsigned char *clid, int hw_len, int hw_type, int clid_len);
|
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now);
|
||||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
|
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
|
||||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
|
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
|
||||||
void lease_set_interface(struct dhcp_lease *lease, int interface);
|
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
|
||||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||||
unsigned char *clid, int clid_len);
|
unsigned char *clid, int clid_len);
|
||||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
||||||
@@ -1000,7 +1003,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
|||||||
int make_icmp_sock(void);
|
int make_icmp_sock(void);
|
||||||
int icmp_ping(struct in_addr addr);
|
int icmp_ping(struct in_addr addr);
|
||||||
#endif
|
#endif
|
||||||
void send_alarm(void);
|
void send_alarm(time_t event, time_t now);
|
||||||
void send_event(int fd, int event, int data, char *msg);
|
void send_event(int fd, int event, int data, char *msg);
|
||||||
void clear_cache_and_reload(time_t now);
|
void clear_cache_and_reload(time_t now);
|
||||||
void poll_resolv(int force, int do_reload, time_t now);
|
void poll_resolv(int force, int do_reload, time_t now);
|
||||||
@@ -1121,6 +1124,14 @@ void put_opt6_string(char *s);
|
|||||||
void ra_init(time_t now);
|
void ra_init(time_t now);
|
||||||
void icmp6_packet(void);
|
void icmp6_packet(void);
|
||||||
time_t periodic_ra(time_t now);
|
time_t periodic_ra(time_t now);
|
||||||
void ra_start_unsolicted(time_t now);
|
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
|
||||||
struct subnet_map *build_subnet_map(void);
|
#endif
|
||||||
|
|
||||||
|
/* slaac.c */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
void build_subnet_map(void);
|
||||||
|
void slaac_add_addrs(struct dhcp_lease *lease, time_t now);
|
||||||
|
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
|
||||||
|
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
|
||||||
|
void schedule_subnet_map(void);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
124
src/lease.c
124
src/lease.c
@@ -97,7 +97,8 @@ void lease_init(time_t now)
|
|||||||
if (hw_type == 0 && hw_len != 0)
|
if (hw_type == 0 && hw_len != 0)
|
||||||
hw_type = ARPHRD_ETHER;
|
hw_type = ARPHRD_ETHER;
|
||||||
|
|
||||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
|
||||||
|
hw_len, hw_type, clid_len, now);
|
||||||
|
|
||||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
|
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
|
||||||
@@ -118,7 +119,7 @@ void lease_init(time_t now)
|
|||||||
|
|
||||||
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
||||||
{
|
{
|
||||||
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len);
|
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now);
|
||||||
|
|
||||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||||
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
|
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
|
||||||
@@ -306,9 +307,16 @@ void lease_update_file(time_t now)
|
|||||||
next_event = 0;
|
next_event = 0;
|
||||||
|
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
/* do timed RAs and determine when the next is */
|
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
|
||||||
if (daemon->ra_contexts)
|
if (daemon->ra_contexts)
|
||||||
next_event = periodic_ra(now);
|
{
|
||||||
|
time_t ra_event = periodic_slaac(now, leases);
|
||||||
|
|
||||||
|
next_event = periodic_ra(now);
|
||||||
|
|
||||||
|
if (next_event == 0 || difftime(next_event, ra_event) > 0.0)
|
||||||
|
next_event = ra_event;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
@@ -326,8 +334,7 @@ void lease_update_file(time_t now)
|
|||||||
(unsigned int)difftime(next_event, now));
|
(unsigned int)difftime(next_event, now));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_event != 0)
|
send_alarm(next_event, now);
|
||||||
alarm((unsigned)difftime(next_event, now));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -342,7 +349,7 @@ static int find_interface_v4(struct in_addr local, int if_index,
|
|||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||||
if (is_same_net(local, lease->addr, netmask))
|
if (is_same_net(local, lease->addr, netmask))
|
||||||
lease->last_interface = if_index;
|
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -353,17 +360,22 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
|
|||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
(void) scope;
|
(void)scope;
|
||||||
(void) vparam;
|
|
||||||
(void)dad;
|
(void)dad;
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if ((lease->flags & (LEASE_TA | LEASE_NA)))
|
if ((lease->flags & (LEASE_TA | LEASE_NA)))
|
||||||
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
|
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
|
||||||
lease->last_interface = if_index;
|
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
|
||||||
|
{
|
||||||
|
slaac_ping_reply(sender, packet, interface, leases);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -373,9 +385,13 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
|
|||||||
start-time. */
|
start-time. */
|
||||||
void lease_find_interfaces(time_t now)
|
void lease_find_interfaces(time_t now)
|
||||||
{
|
{
|
||||||
iface_enumerate(AF_INET, NULL, find_interface_v4);
|
|
||||||
#ifdef HAVE_DHCP6
|
#ifdef HAVE_DHCP6
|
||||||
iface_enumerate(AF_INET6, NULL, find_interface_v6);
|
build_subnet_map();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
iface_enumerate(AF_INET, &now, find_interface_v4);
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
iface_enumerate(AF_INET6, &now, find_interface_v6);
|
||||||
|
|
||||||
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
|
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
|
||||||
if (!daemon->duid && daemon->dhcp6)
|
if (!daemon->duid && daemon->dhcp6)
|
||||||
@@ -388,16 +404,12 @@ void lease_find_interfaces(time_t now)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void lease_update_dns(void)
|
void lease_update_dns(int force)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
if (daemon->port != 0 && dns_dirty)
|
if (daemon->port != 0 && (dns_dirty || force))
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DHCP6
|
|
||||||
struct subnet_map *subnets = build_subnet_map();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cache_unhash_dhcp();
|
cache_unhash_dhcp();
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
@@ -409,41 +421,15 @@ void lease_update_dns(void)
|
|||||||
prot = AF_INET6;
|
prot = AF_INET6;
|
||||||
else if (lease->hostname || lease->fqdn)
|
else if (lease->hostname || lease->fqdn)
|
||||||
{
|
{
|
||||||
struct subnet_map *map;
|
struct slaac_address *slaac;
|
||||||
for (map = subnets; map; map = map->next)
|
|
||||||
if (lease->last_interface == map->iface)
|
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||||
|
if (slaac->backoff == 0)
|
||||||
{
|
{
|
||||||
struct in6_addr addr = map->subnet;
|
|
||||||
if (lease->hwaddr_len == 6 &&
|
|
||||||
(lease->hwaddr_type == ARPHRD_ETHER || lease->hwaddr_type == ARPHRD_IEEE802))
|
|
||||||
{
|
|
||||||
/* convert MAC address to EUI-64 */
|
|
||||||
memcpy(&addr.s6_addr[8], lease->hwaddr, 3);
|
|
||||||
memcpy(&addr.s6_addr[13], &lease->hwaddr[3], 3);
|
|
||||||
addr.s6_addr[11] = 0xff;
|
|
||||||
addr.s6_addr[12] = 0xfe;
|
|
||||||
}
|
|
||||||
#if defined(ARPHRD_EUI64)
|
|
||||||
else if (lease->hwaddr_len == 8 &&
|
|
||||||
lease->hwaddr_type == ARPHRD_EUI64)
|
|
||||||
memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
|
|
||||||
#endif
|
|
||||||
#if defined(ARPHRD_IEEE1394) && defined(ARPHRD_EUI64)
|
|
||||||
else if (lease->clid_len == 9 &&
|
|
||||||
lease->clid[0] == ARPHRD_EUI64 &&
|
|
||||||
lease->hwaddr_type == ARPHRD_IEEE1394)
|
|
||||||
/* firewire has EUI-64 identifier as clid */
|
|
||||||
memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
|
|
||||||
#endif
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
addr.s6_addr[8] ^= 0x02;
|
|
||||||
|
|
||||||
if (lease->fqdn)
|
if (lease->fqdn)
|
||||||
cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&addr, lease->expires);
|
cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
|
||||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||||
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&addr, lease->expires);
|
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -713,8 +699,13 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||||
unsigned char *clid, int hw_len, int hw_type, int clid_len)
|
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
int change = 0;
|
||||||
|
lease->flags |= LEASE_HAVE_HWADDR;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (hw_len != lease->hwaddr_len ||
|
if (hw_len != lease->hwaddr_len ||
|
||||||
hw_type != lease->hwaddr_type ||
|
hw_type != lease->hwaddr_type ||
|
||||||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
|
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
|
||||||
@@ -725,6 +716,9 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
|||||||
lease->hwaddr_type = hw_type;
|
lease->hwaddr_type = hw_type;
|
||||||
lease->flags |= LEASE_CHANGED;
|
lease->flags |= LEASE_CHANGED;
|
||||||
file_dirty = 1; /* run script on change */
|
file_dirty = 1; /* run script on change */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
change = 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only update clid when one is available, stops packets
|
/* only update clid when one is available, stops packets
|
||||||
@@ -742,17 +736,27 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
|||||||
free(lease->clid);
|
free(lease->clid);
|
||||||
if (!(lease->clid = whine_malloc(clid_len)))
|
if (!(lease->clid = whine_malloc(clid_len)))
|
||||||
return;
|
return;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
change = 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (memcmp(lease->clid, clid, clid_len) != 0)
|
else if (memcmp(lease->clid, clid, clid_len) != 0)
|
||||||
{
|
{
|
||||||
lease->flags |= LEASE_AUX_CHANGED;
|
lease->flags |= LEASE_AUX_CHANGED;
|
||||||
file_dirty = 1;
|
file_dirty = 1;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
change = 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
lease->clid_len = clid_len;
|
lease->clid_len = clid_len;
|
||||||
memcpy(lease->clid, clid, clid_len);
|
memcpy(lease->clid, clid, clid_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (change)
|
||||||
|
slaac_add_addrs(lease, now);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kill_name(struct dhcp_lease *lease)
|
static void kill_name(struct dhcp_lease *lease)
|
||||||
@@ -870,13 +874,17 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *do
|
|||||||
lease->flags |= LEASE_CHANGED; /* run script on change */
|
lease->flags |= LEASE_CHANGED; /* run script on change */
|
||||||
}
|
}
|
||||||
|
|
||||||
void lease_set_interface(struct dhcp_lease *lease, int interface)
|
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
|
||||||
{
|
{
|
||||||
if (lease->last_interface == interface)
|
if (lease->last_interface == interface)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lease->last_interface = interface;
|
lease->last_interface = interface;
|
||||||
lease->flags |= LEASE_CHANGED;
|
lease->flags |= LEASE_CHANGED;
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
slaac_add_addrs(lease, now);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void rerun_scripts(void)
|
void rerun_scripts(void)
|
||||||
@@ -919,6 +927,14 @@ int do_script_run(time_t now)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct slaac_address *slaac, *tmp;
|
||||||
|
for (slaac = lease->slaac_address; slaac; slaac = tmp)
|
||||||
|
{
|
||||||
|
tmp = slaac->next;
|
||||||
|
free(slaac);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
kill_name(lease);
|
kill_name(lease);
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
|
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
|
||||||
|
|||||||
@@ -345,10 +345,11 @@ static void nl_routechange(struct nlmsghdr *h)
|
|||||||
/* force RAs to sync new network and pick up new interfaces. */
|
/* force RAs to sync new network and pick up new interfaces. */
|
||||||
if (daemon->ra_contexts)
|
if (daemon->ra_contexts)
|
||||||
{
|
{
|
||||||
ra_start_unsolicted(dnsmasq_time());
|
schedule_subnet_map();
|
||||||
|
ra_start_unsolicted(dnsmasq_time(), NULL);
|
||||||
/* cause lease_update_file to run after we return, in case we were called from
|
/* cause lease_update_file to run after we return, in case we were called from
|
||||||
iface_enumerate and can't re-enter it now */
|
iface_enumerate and can't re-enter it now */
|
||||||
send_alarm();
|
send_alarm(0, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,13 @@
|
|||||||
#define ALL_HOSTS "FF02::1"
|
#define ALL_HOSTS "FF02::1"
|
||||||
#define ALL_ROUTERS "FF02::2"
|
#define ALL_ROUTERS "FF02::2"
|
||||||
|
|
||||||
|
struct ping_packet {
|
||||||
|
u8 type, code;
|
||||||
|
u16 checksum;
|
||||||
|
u16 identifier;
|
||||||
|
u16 sequence_no;
|
||||||
|
};
|
||||||
|
|
||||||
struct ra_packet {
|
struct ra_packet {
|
||||||
u8 type, code;
|
u8 type, code;
|
||||||
u16 checksum;
|
u16 checksum;
|
||||||
@@ -32,9 +39,6 @@ struct prefix_opt {
|
|||||||
struct in6_addr prefix;
|
struct in6_addr prefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ICMP6_ROUTER_SOLICIT 133
|
|
||||||
#define ICMP6_ROUTER_ADVERT 134
|
|
||||||
|
|
||||||
#define ICMP6_OPT_SOURCE_MAC 1
|
#define ICMP6_OPT_SOURCE_MAC 1
|
||||||
#define ICMP6_OPT_PREFIX 3
|
#define ICMP6_OPT_PREFIX 3
|
||||||
#define ICMP6_OPT_MTU 5
|
#define ICMP6_OPT_MTU 5
|
||||||
|
|||||||
117
src/radv.c
117
src/radv.c
@@ -55,13 +55,20 @@ void ra_init(time_t now)
|
|||||||
#endif
|
#endif
|
||||||
int val = 255; /* radvd uses this value */
|
int val = 255; /* radvd uses this value */
|
||||||
socklen_t len = sizeof(int);
|
socklen_t len = sizeof(int);
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
/* ensure this is around even if we're not doing DHCPv6 */
|
/* ensure this is around even if we're not doing DHCPv6 */
|
||||||
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
|
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
|
||||||
|
|
||||||
|
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME))
|
||||||
|
break;
|
||||||
|
|
||||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||||
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
|
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
|
||||||
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
|
if (context)
|
||||||
|
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
|
||||||
|
|
||||||
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
|
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
|
||||||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
|
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
|
||||||
@@ -77,21 +84,21 @@ void ra_init(time_t now)
|
|||||||
|
|
||||||
daemon->icmp6fd = fd;
|
daemon->icmp6fd = fd;
|
||||||
|
|
||||||
ra_start_unsolicted(now);
|
ra_start_unsolicted(now, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ra_start_unsolicted(time_t now)
|
void ra_start_unsolicted(time_t now, struct dhcp_context *context)
|
||||||
{
|
{
|
||||||
struct dhcp_context *context;
|
/* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
|
||||||
|
|
||||||
/* init timers so that we do ra's for all soon. some ra_times will end up zeroed
|
|
||||||
if it's not appropriate to advertise those contexts.
|
if it's not appropriate to advertise those contexts.
|
||||||
This gets re-called on a netlink route-change to re-do the advertisement
|
This gets re-called on a netlink route-change to re-do the advertisement
|
||||||
and pick up new interfaces */
|
and pick up new interfaces */
|
||||||
|
|
||||||
/* range 0 - 5 */
|
if (context)
|
||||||
for (context = daemon->ra_contexts; context; context = context->next)
|
context->ra_time = now;
|
||||||
context->ra_time = now + (rand16()/13000);
|
else
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
|
||||||
|
|
||||||
/* re-do frequently for a minute or so, in case the first gets lost. */
|
/* re-do frequently for a minute or so, in case the first gets lost. */
|
||||||
ra_short_period_start = now;
|
ra_short_period_start = now;
|
||||||
@@ -158,7 +165,19 @@ void icmp6_packet(void)
|
|||||||
|
|
||||||
p = (unsigned char *)daemon->outpacket.iov_base;
|
p = (unsigned char *)daemon->outpacket.iov_base;
|
||||||
|
|
||||||
if (p[0] != ICMP6_ROUTER_SOLICIT || p[1] != 0)
|
if (p[1] != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (p[0] == ICMP6_ECHO_REPLY)
|
||||||
|
{
|
||||||
|
/* We may be doing RA but not DHCPv4, in which case the lease
|
||||||
|
database may not exist and we have nothing to do anyway */
|
||||||
|
if (daemon->dhcp)
|
||||||
|
lease_ping_reply(&from.sin6_addr, p, interface);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p[0] != ND_ROUTER_SOLICIT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* look for link-layer address option for logging */
|
/* look for link-layer address option for logging */
|
||||||
@@ -184,7 +203,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
|||||||
save_counter(0);
|
save_counter(0);
|
||||||
ra = expand(sizeof(struct ra_packet));
|
ra = expand(sizeof(struct ra_packet));
|
||||||
|
|
||||||
ra->type = ICMP6_ROUTER_ADVERT;
|
ra->type = ND_ROUTER_ADVERT;
|
||||||
ra->code = 0;
|
ra->code = 0;
|
||||||
ra->hop_limit = hop_limit;
|
ra->hop_limit = hop_limit;
|
||||||
ra->flags = 0;
|
ra->flags = 0;
|
||||||
@@ -238,7 +257,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
|||||||
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
||||||
if (dest)
|
if (dest)
|
||||||
{
|
{
|
||||||
memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr));
|
addr.sin6_addr = *dest;
|
||||||
if (IN6_IS_ADDR_LINKLOCAL(dest) ||
|
if (IN6_IS_ADDR_LINKLOCAL(dest) ||
|
||||||
IN6_IS_ADDR_MC_LINKLOCAL(dest))
|
IN6_IS_ADDR_MC_LINKLOCAL(dest))
|
||||||
addr.sin6_scope_id = iface;
|
addr.sin6_scope_id = iface;
|
||||||
@@ -406,7 +425,7 @@ static int iface_search(struct in6_addr *local, int prefix,
|
|||||||
if (prefix == context->prefix &&
|
if (prefix == context->prefix &&
|
||||||
is_same_net6(local, &context->start6, prefix) &&
|
is_same_net6(local, &context->start6, prefix) &&
|
||||||
is_same_net6(local, &context->end6, prefix))
|
is_same_net6(local, &context->end6, prefix))
|
||||||
if (context->ra_time != 0 && difftime(context->ra_time, param->now) < 0.0)
|
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
|
||||||
{
|
{
|
||||||
/* found an interface that's overdue for RA determine new
|
/* found an interface that's overdue for RA determine new
|
||||||
timeout value and zap other contexts on the same interface
|
timeout value and zap other contexts on the same interface
|
||||||
@@ -426,73 +445,5 @@ static int iface_search(struct in6_addr *local, int prefix,
|
|||||||
return 1; /* keep searching */
|
return 1; /* keep searching */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_subnet(struct in6_addr *local, int prefix,
|
|
||||||
int scope, int if_index, int dad, void *vparam)
|
|
||||||
{
|
|
||||||
struct dhcp_context *context;
|
|
||||||
struct subnet_map **subnets = vparam;
|
|
||||||
struct subnet_map *map;
|
|
||||||
|
|
||||||
(void)scope;
|
|
||||||
(void)dad;
|
|
||||||
|
|
||||||
for (context = daemon->ra_contexts; context; context = context->next)
|
|
||||||
if ((context->flags & CONTEXT_RA_NAME) &&
|
|
||||||
prefix == context->prefix &&
|
|
||||||
is_same_net6(local, &context->start6, prefix) &&
|
|
||||||
is_same_net6(local, &context->end6, prefix))
|
|
||||||
{
|
|
||||||
for (map = *subnets; map; map = map->next)
|
|
||||||
if (map->iface == 0 ||
|
|
||||||
(map->iface == if_index && is_same_net6(local, &map->subnet, prefix)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* It's there already */
|
|
||||||
if (map && map->iface != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!map && (map = whine_malloc(sizeof(struct subnet_map))))
|
|
||||||
{
|
|
||||||
map->next = *subnets;
|
|
||||||
*subnets = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map)
|
|
||||||
{
|
|
||||||
map->iface = if_index;
|
|
||||||
map->subnet = *local;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build a map from ra-names subnets to corresponding interfaces. This
|
|
||||||
is used to go from DHCPv4 leases to SLAAC addresses,
|
|
||||||
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
|
|
||||||
*/
|
|
||||||
struct subnet_map *build_subnet_map(void)
|
|
||||||
{
|
|
||||||
struct subnet_map *map;
|
|
||||||
struct dhcp_context *context;
|
|
||||||
static struct subnet_map *subnets = NULL;
|
|
||||||
|
|
||||||
for (context = daemon->ra_contexts; context; context = context->next)
|
|
||||||
if ((context->flags & CONTEXT_RA_NAME))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* no ra-names, no need to go further. */
|
|
||||||
if (!context)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* mark unused */
|
|
||||||
for (map = subnets; map; map = map->next)
|
|
||||||
map->iface = 0;
|
|
||||||
|
|
||||||
if (iface_enumerate(AF_INET6, &subnets, add_subnet))
|
|
||||||
return subnets;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -483,14 +483,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
{
|
{
|
||||||
logaddr = &mess->yiaddr;
|
logaddr = &mess->yiaddr;
|
||||||
|
|
||||||
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
|
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now);
|
||||||
if (hostname)
|
if (hostname)
|
||||||
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
|
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
|
||||||
/* infinite lease unless nailed in dhcp-host line. */
|
/* infinite lease unless nailed in dhcp-host line. */
|
||||||
lease_set_expires(lease,
|
lease_set_expires(lease,
|
||||||
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
|
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
|
||||||
now);
|
now);
|
||||||
lease_set_interface(lease, int_index);
|
lease_set_interface(lease, int_index, now);
|
||||||
|
|
||||||
clear_packet(mess, end);
|
clear_packet(mess, end);
|
||||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||||
@@ -1276,7 +1276,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||||
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
|
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now);
|
||||||
|
|
||||||
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
|
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
|
||||||
if (!hostname_auth)
|
if (!hostname_auth)
|
||||||
@@ -1310,7 +1310,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
|
lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
|
||||||
|
|
||||||
lease_set_expires(lease, time, now);
|
lease_set_expires(lease, time, now);
|
||||||
lease_set_interface(lease, int_index);
|
lease_set_interface(lease, int_index, now);
|
||||||
|
|
||||||
if (override.s_addr != 0)
|
if (override.s_addr != 0)
|
||||||
lease->override = override;
|
lease->override = override;
|
||||||
@@ -1387,7 +1387,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
else
|
else
|
||||||
time = (unsigned int)difftime(lease->expires, now);
|
time = (unsigned int)difftime(lease->expires, now);
|
||||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||||
lease_set_interface(lease, int_index);
|
lease_set_interface(lease, int_index, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||||
|
|||||||
@@ -637,8 +637,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
|||||||
if (lease)
|
if (lease)
|
||||||
{
|
{
|
||||||
lease_set_expires(lease, lease_time, now);
|
lease_set_expires(lease, lease_time, now);
|
||||||
lease_set_hwaddr(lease, NULL, clid, 0, iaid, clid_len);
|
lease_set_hwaddr(lease, NULL, clid, 0, iaid, clid_len, now);
|
||||||
lease_set_interface(lease, interface);
|
lease_set_interface(lease, interface, now);
|
||||||
if (hostname && ia_type == OPTION6_IA_NA)
|
if (hostname && ia_type == OPTION6_IA_NA)
|
||||||
{
|
{
|
||||||
char *addr_domain = get_domain6(addrp);
|
char *addr_domain = get_domain6(addrp);
|
||||||
|
|||||||
243
src/slaac.c
Normal file
243
src/slaac.c
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
|
||||||
|
static int map_rebuild = 0;
|
||||||
|
static int ping_id = 0;
|
||||||
|
|
||||||
|
void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
|
||||||
|
{
|
||||||
|
struct slaac_address *slaac, *old, **up;
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
|
if (!(lease->flags & LEASE_HAVE_HWADDR) ||
|
||||||
|
lease->last_interface == 0 ||
|
||||||
|
!lease->hostname)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
old = lease->slaac_address;
|
||||||
|
lease->slaac_address = NULL;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
|
||||||
|
{
|
||||||
|
struct in6_addr addr = context->start6;
|
||||||
|
if (lease->hwaddr_len == 6 &&
|
||||||
|
(lease->hwaddr_type == ARPHRD_ETHER || lease->hwaddr_type == ARPHRD_IEEE802))
|
||||||
|
{
|
||||||
|
/* convert MAC address to EUI-64 */
|
||||||
|
memcpy(&addr.s6_addr[8], lease->hwaddr, 3);
|
||||||
|
memcpy(&addr.s6_addr[13], &lease->hwaddr[3], 3);
|
||||||
|
addr.s6_addr[11] = 0xff;
|
||||||
|
addr.s6_addr[12] = 0xfe;
|
||||||
|
}
|
||||||
|
#if defined(ARPHRD_EUI64)
|
||||||
|
else if (lease->hwaddr_len == 8 &&
|
||||||
|
lease->hwaddr_type == ARPHRD_EUI64)
|
||||||
|
memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
|
||||||
|
#endif
|
||||||
|
#if defined(ARPHRD_IEEE1394) && defined(ARPHRD_EUI64)
|
||||||
|
else if (lease->clid_len == 9 &&
|
||||||
|
lease->clid[0] == ARPHRD_EUI64 &&
|
||||||
|
lease->hwaddr_type == ARPHRD_IEEE1394)
|
||||||
|
/* firewire has EUI-64 identifier as clid */
|
||||||
|
memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
addr.s6_addr[8] ^= 0x02;
|
||||||
|
|
||||||
|
/* check if we already have this one */
|
||||||
|
for (up = &old, slaac = old; slaac; slaac = slaac->next)
|
||||||
|
{
|
||||||
|
if (IN6_ARE_ADDR_EQUAL(&addr, &slaac->addr))
|
||||||
|
{
|
||||||
|
*up = slaac->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
up = &slaac->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No, make new one */
|
||||||
|
if (!slaac && (slaac = whine_malloc(sizeof(struct slaac_address))))
|
||||||
|
{
|
||||||
|
slaac->ping_time = now;
|
||||||
|
slaac->backoff = 1;
|
||||||
|
slaac->addr = addr;
|
||||||
|
slaac->local = context->local6;
|
||||||
|
/* Do RA's to prod it */
|
||||||
|
ra_start_unsolicted(now, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slaac)
|
||||||
|
{
|
||||||
|
slaac->next = lease->slaac_address;
|
||||||
|
lease->slaac_address = slaac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free any no reused */
|
||||||
|
for (; old; old = slaac)
|
||||||
|
{
|
||||||
|
slaac = old->next;
|
||||||
|
free(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
struct slaac_address *slaac;
|
||||||
|
time_t next_event = 0;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* nothing configured */
|
||||||
|
if (!context)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (ping_id == 0)
|
||||||
|
ping_id = rand16();
|
||||||
|
|
||||||
|
if (map_rebuild)
|
||||||
|
{
|
||||||
|
map_rebuild = 0;
|
||||||
|
build_subnet_map();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||||
|
{
|
||||||
|
/* confirmed? */
|
||||||
|
if (slaac->backoff == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (difftime(slaac->ping_time, now) <= 0.0)
|
||||||
|
{
|
||||||
|
struct ping_packet *ping;
|
||||||
|
struct sockaddr_in6 addr;
|
||||||
|
|
||||||
|
save_counter(0);
|
||||||
|
ping = expand(sizeof(struct ping_packet));
|
||||||
|
ping->type = ICMP6_ECHO_REQUEST;
|
||||||
|
ping->code = 0;
|
||||||
|
ping->identifier = ping_id;
|
||||||
|
ping->sequence_no = slaac->backoff;
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
addr.sin6_family = AF_INET6;
|
||||||
|
addr.sin6_port = htons(IPPROTO_ICMPV6);
|
||||||
|
addr.sin6_addr = slaac->addr;
|
||||||
|
|
||||||
|
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
|
||||||
|
(union mysockaddr *)&addr, (struct all_addr *)&slaac->local, lease->last_interface);
|
||||||
|
|
||||||
|
slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
|
||||||
|
if (slaac->backoff > 4)
|
||||||
|
slaac->ping_time += rand16()/4000; /* 0 - 15 */
|
||||||
|
slaac->backoff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0)
|
||||||
|
next_event = slaac->ping_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
struct slaac_address *slaac;
|
||||||
|
struct ping_packet *ping = (struct ping_packet *)packet;
|
||||||
|
int gotone = 0;
|
||||||
|
|
||||||
|
if (ping->identifier == ping_id)
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||||
|
if (slaac->backoff != 0 && IN6_ARE_ADDR_EQUAL(sender, &slaac->addr))
|
||||||
|
{
|
||||||
|
slaac->backoff = 0;
|
||||||
|
gotone = 1;
|
||||||
|
inet_ntop(AF_INET6, sender, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
lease_update_dns(gotone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build a map from ra-names subnets to corresponding interfaces. This
|
||||||
|
is used to go from DHCPv4 leases to SLAAC addresses,
|
||||||
|
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
|
||||||
|
*/
|
||||||
|
static int add_subnet(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, int dad, void *vparam)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
|
||||||
|
(void)scope;
|
||||||
|
(void)dad;
|
||||||
|
(void)vparam;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME) &&
|
||||||
|
prefix == context->prefix &&
|
||||||
|
is_same_net6(local, &context->start6, prefix) &&
|
||||||
|
is_same_net6(local, &context->end6, prefix))
|
||||||
|
{
|
||||||
|
context->if_index = if_index;
|
||||||
|
context->local6 = *local;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_subnet_map(void)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
for (context = daemon->ra_contexts; context; context = context->next)
|
||||||
|
{
|
||||||
|
context->if_index = 0;
|
||||||
|
if ((context->flags & CONTEXT_RA_NAME))
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ra-names configured */
|
||||||
|
if (ok)
|
||||||
|
iface_enumerate(AF_INET6, NULL, add_subnet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void schedule_subnet_map(void)
|
||||||
|
{
|
||||||
|
map_rebuild = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user