Merge branch 'ra-names'

This commit is contained in:
Simon Kelley
2012-03-09 11:37:42 +00:00
5 changed files with 206 additions and 10 deletions

View File

@@ -106,16 +106,14 @@ int main (int argc, char **argv)
else
open("/dev/null", O_RDWR);
#ifdef HAVE_LINUX_NETWORK
netlink_init();
#elif !(defined(IP_RECVDSTADDR) && \
defined(IP_RECVIF) && \
defined(IP_SENDSRCADDR))
#ifndef HAVE_LINUX_NETWORK
# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
if (!option_bool(OPT_NOWILD))
{
bind_fallback = 1;
set_option_bool(OPT_NOWILD);
}
# endif
#endif
#ifndef HAVE_TFTP
@@ -180,10 +178,25 @@ int main (int argc, char **argv)
if (daemon->dhcp6)
dhcp6_init();
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
# endif
#endif
#ifdef HAVE_LINUX_NETWORK
/* After lease_init */
netlink_init();
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
#endif
#ifdef HAVE_DHCP
/* after netlink_init */
if (daemon->dhcp || daemon->dhcp6)
lease_find_interfaces();
#endif
if (!enumerate_interfaces())
@@ -552,6 +565,8 @@ int main (int argc, char **argv)
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_RA_NAME) ?
_("router advertisement with DHCPv4-derived names on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
_("router advertisement only on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?

View File

@@ -621,6 +621,7 @@ struct dhcp_context {
#define CONTEXT_PROXY 8
#define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32
#define CONTEXT_RA_NAME 64
struct ping_result {
struct in_addr addr;
@@ -629,6 +630,13 @@ struct ping_result {
struct ping_result *next;
};
struct subnet_map {
int iface;
struct in6_addr subnet;
struct subnet_map *next;
};
struct tftp_file {
int refcount, fd;
off_t size;
@@ -948,6 +956,7 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void);
int do_script_run(time_t now);
void rerun_scripts(void);
void lease_find_interfaces(void);
#ifdef HAVE_SCRIPT
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
unsigned int len, int delim);
@@ -1083,4 +1092,5 @@ void ra_init(time_t now);
void icmp6_packet(void);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now);
struct subnet_map *build_subnet_map(void);
#endif

View File

@@ -340,20 +340,115 @@ void lease_update_file(time_t now)
alarm((unsigned)difftime(next_event, now));
}
static int find_interface_v4(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_lease *lease;
(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->last_interface = if_index;
return 1;
}
#ifdef HAVE_DHCP6
static int find_interface_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_lease *lease;
(void) scope;
(void) vparam;
(void)dad;
for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
lease->last_interface = if_index;
return 1;
}
#endif
/* Find interfaces associated with leases at start-up. This gets updated as
we do DHCP transactions, but information about directly-connected subnets
is useful from scrips and necessary for determining SLAAC addresses from
start-time. */
void lease_find_interfaces(void)
{
iface_enumerate(AF_INET, NULL, find_interface_v4);
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, NULL, find_interface_v6);
#endif
}
void lease_update_dns(void)
{
struct dhcp_lease *lease;
if (daemon->port != 0 && dns_dirty)
{
#ifdef HAVE_DHCP6
struct subnet_map *subnets = build_subnet_map();
#endif
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)
{
int prot = AF_INET;
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
prot = AF_INET6;
else if (lease->hostname || lease->fqdn)
{
struct subnet_map *map;
for (map = subnets; map; map = map->next)
if (lease->last_interface == map->iface)
{
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)
cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&addr, lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&addr, lease->expires);
}
}
#endif
if (lease->fqdn)

View File

@@ -2345,6 +2345,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_RA_ONLY;
}
else if (strcmp(a[1], "ra-names") == 0)
{
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_RA_NAME | CONTEXT_RA_ONLY;
}
else if (!inet_pton(AF_INET6, a[1], &new->end6))
option = '?';
@@ -2370,7 +2375,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{
new->prefix = pref;
leasepos = 3;
if (new->prefix < 64)
if ((new->flags & CONTEXT_RA_ONLY) && new->prefix != 64)
problem = _("prefix must be exactly 64 for RA subnets");
else if (new->prefix < 64)
problem = _("prefix must be at least 64");
}
}

View File

@@ -426,4 +426,73 @@ static int iface_search(struct in6_addr *local, int prefix,
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