Add ra-names SLAAC-hostnames from DHCPv4 option.

This commit is contained in:
Simon Kelley
2012-03-06 19:30:17 +00:00
parent df66e341de
commit 801ca9a7b7
5 changed files with 190 additions and 10 deletions

View File

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

View File

@@ -621,6 +621,7 @@ struct dhcp_context {
#define CONTEXT_PROXY 8 #define CONTEXT_PROXY 8
#define CONTEXT_RA_ONLY 16 #define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32 #define CONTEXT_RA_DONE 32
#define CONTEXT_RA_NAME 64
struct ping_result { struct ping_result {
struct in_addr addr; struct in_addr addr;
@@ -629,6 +630,13 @@ 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;
@@ -948,6 +956,7 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void); void lease_update_from_configs(void);
int do_script_run(time_t now); int do_script_run(time_t now);
void rerun_scripts(void); void rerun_scripts(void);
void lease_find_interfaces(void);
#ifdef HAVE_SCRIPT #ifdef HAVE_SCRIPT
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
unsigned int len, int delim); unsigned int len, int delim);
@@ -1083,4 +1092,5 @@ 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 subnet_map *build_subnet_map(void);
#endif #endif

View File

@@ -340,20 +340,103 @@ void lease_update_file(time_t now)
alarm((unsigned)difftime(next_event, now)); alarm((unsigned)difftime(next_event, now));
} }
void lease_update_dns(void)
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; 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) if (daemon->port != 0 && dns_dirty)
{ {
cache_unhash_dhcp(); #ifdef HAVE_DHCP6
struct subnet_map *subnets = build_subnet_map();
#endif
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
int prot = AF_INET; int prot = AF_INET;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA)) if (lease->flags & (LEASE_TA | LEASE_NA))
prot = AF_INET6; prot = AF_INET6;
else
{
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)
{
/* 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;
addr.s6_addr[8] ^= 0x02;
}
else if (lease->hwaddr_len == 8)
memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
else
continue;
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 #endif
if (lease->fqdn) 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); memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_RA_ONLY; 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)) else if (!inet_pton(AF_INET6, a[1], &new->end6))
option = '?'; option = '?';
@@ -2370,7 +2375,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{ {
new->prefix = pref; new->prefix = pref;
leasepos = 3; 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"); problem = _("prefix must be at least 64");
} }
} }

View File

@@ -426,4 +426,69 @@ 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)
break;
else if (map->iface == if_index && is_same_net6(local, &map->subnet, prefix))
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;
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