}
#ifdef HAVE_DHCP6
- if (prot == AF_INET6 && !config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 129, 0))
+ if (prot == AF_INET6 && !config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0))
{
- memcpy(config->hwaddr, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
+ memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
continue;
}
struct iface_param {
struct dhcp_context *current;
+ struct in6_addr fallback;
int ind;
};
/* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp6; context; context = context->next)
- context->current = context;
-
+ {
+ context->current = context;
+ memset(&context->local6, 0, IN6ADDRSZ);
+ }
+
parm.current = NULL;
parm.ind = if_index;
+ memset(&parm.fallback, 0, IN6ADDRSZ);
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
lease_prune(NULL, now); /* lose any expired leases */
msg.msg_iov = &daemon->dhcp_packet;
- sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, sz, IN6_IS_ADDR_MULTICAST(&from.in6.sin6_addr), now);
+ sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, sz, IN6_IS_ADDR_MULTICAST(&from.in6.sin6_addr), now);
lease_update_file(now);
lease_update_dns();
(void)scope; /* warning */
(void)dad;
-
- for (context = daemon->dhcp6; context; context = context->next)
+
+ if (if_index == param->ind &&
+ !IN6_IS_ADDR_LOOPBACK(local) &&
+ !IN6_IS_ADDR_LINKLOCAL(local) &&
+ !IN6_IS_ADDR_MULTICAST(local))
{
- if (prefix == context->prefix &&
- !IN6_IS_ADDR_LOOPBACK(local) &&
- !IN6_IS_ADDR_LINKLOCAL(local) &&
- !IN6_IS_ADDR_MULTICAST(local) &&
- is_same_net6(local, &context->start6, prefix) &&
- is_same_net6(local, &context->end6, prefix))
- {
- /* link it onto the current chain if we've not seen it before */
- if (if_index == param->ind && context->current == context)
- {
- context->current = param->current;
- param->current = context;
- context->local6 = *local;
- }
+ /* Determine a globally address on the arrival interface, even
+ if we have no matching dhcp-context, because we're only
+ allocating on remote subnets via relays. This
+ is used as a default for the DNS server option. */
+ memcpy(¶m->fallback, &local, IN6ADDRSZ);
+
+ for (context = daemon->dhcp6; context; context = context->next)
+ {
+ if (prefix == context->prefix &&
+ is_same_net6(local, &context->start6, prefix) &&
+ is_same_net6(local, &context->end6, prefix))
+ {
+ /* link it onto the current chain if we've not seen it before */
+ if (context->current == context)
+ {
+ context->current = param->current;
+ param->current = context;
+ context->local6 = *local;
+ }
+ }
}
}
return 1;
do {
/* eliminate addresses in use by the server. */
for (d = context; d; d = d->current)
- if (addr == addr6part(&d->router6))
+ if (addr == addr6part(&d->local6))
break;
if (!d &&
struct in_addr start, end; /* range of available addresses */
#ifdef HAVE_DHCP6
struct in6_addr start6, end6; /* range of available addresses */
- struct in6_addr local6, router6;
+ struct in6_addr local6;
int prefix;
#endif
int flags;
/* rfc3315.c */
#ifdef HAVE_DHCP6
-size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name, size_t sz, int is_multicast, time_t now);
+size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
+ struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
#endif
/* dhcp-common.c */
struct nlmsghdr *h;
ssize_t len;
static unsigned int seq = 0;
+ int callback_ok = 1;
struct {
struct nlmsghdr nlh;
else if (h->nlmsg_type == NLMSG_ERROR)
nl_err(h);
else if (h->nlmsg_type == NLMSG_DONE)
- return 1;
+ return callback_ok;
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
{
struct ifaddrmsg *ifa = NLMSG_DATA(h);
rta = RTA_NEXT(rta, len1);
}
- if (addr.s_addr)
+ if (addr.s_addr && callback_ok)
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
- return 0;
+ callback_ok = 0;
}
#ifdef HAVE_IPV6
else if (ifa->ifa_family == AF_INET6)
rta = RTA_NEXT(rta, len1);
}
- if (addrp)
+ if (addrp && callback_ok)
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
- return 0;
+ callback_ok = 0;
}
#endif
}
rta = RTA_NEXT(rta, len1);
}
- if (inaddr && mac)
+ if (inaddr && mac && callback_ok)
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
- return 0;
+ callback_ok = 0;
}
#ifdef HAVE_DHCP6
else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
rta = RTA_NEXT(rta, len1);
}
- if (mac && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
+ if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
!((*callback)((unsigned int)link->ifi_type, mac, maclen, parm)))
- return 0;
+ callback_ok = 0;
}
#endif
}
static void put_opt6_string(char *s);
static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
- int interface, char *iface_name, void *inbuff, size_t sz, int is_unicast, time_t now);
+ int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context,
- int interface, char *iface_name, void *inbuff, size_t sz, int is_unicast, time_t now);
+ int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
static void log6_packet(char *type, unsigned char *clid, int clid_len, struct in6_addr *addr, int xid, char *iface, char *string);
static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
-size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name, size_t sz, int is_unicast, time_t now)
+size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
+ struct in6_addr *fallback, size_t sz, int is_unicast, time_t now)
{
struct dhcp_netid *relay_tags = NULL;
struct dhcp_vendor *vendor;
outpacket_counter = 0;
- if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, daemon->dhcp_packet.iov_base, sz, is_unicast, now))
+ if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, fallback, daemon->dhcp_packet.iov_base, sz, is_unicast, now))
return outpacket_counter;
return 0;
/* This cost me blood to write, it will probably cost you blood to understand - srk. */
static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
- int interface, char *iface_name, void *inbuff, size_t sz, int is_unicast, time_t now)
+ int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now)
{
void *end = inbuff + sz;
void *opts = inbuff + 34;
return 0;
}
- return dhcp6_no_relay(msg_type, link_address, *relay_tagsp, context, interface, iface_name, inbuff, sz, is_unicast, now);
+ return dhcp6_no_relay(msg_type, link_address, *relay_tagsp, context, interface, iface_name, fallback, inbuff, sz, is_unicast, now);
}
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
memcpy(&link_address, inbuff + 2, IN6ADDRSZ);
/* Not, zero is_unicast since that is now known to refer to the
relayed packet, not the original sent by the client */
- if (!dhcp6_maybe_relay(&link_address, relay_tagsp, context, interface, iface_name, opt6_ptr(opt, 0), opt6_len(opt), 0, now))
+ if (!dhcp6_maybe_relay(&link_address, relay_tagsp, context, interface, iface_name, fallback, opt6_ptr(opt, 0), opt6_len(opt), 0, now))
return 0;
}
else
}
static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context,
- int interface, char *iface_name, void *inbuff, size_t sz, int is_unicast, time_t now)
+ int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now)
{
void *packet_options = inbuff + 4;
void *end = inbuff + sz;
/* link temporarily */
for (n = context_tags; n && n->next; n = n->next);
- if (l = n)
+ if ((l = n))
l->next = tags;
for (n = run_tag_if(context_tags); n; n = n->next)
}
- if (!done_dns)
+ if (!done_dns &&
+ (!IN6_IS_ADDR_UNSPECIFIED(&context->local6) ||
+ !IN6_IS_ADDR_UNSPECIFIED(fallback)))
{
o = new_opt6(OPTION6_DNS_SERVER);
- put_opt6(&context->local6, IN6ADDRSZ);
+ if (IN6_IS_ADDR_UNSPECIFIED(&context->local6))
+ put_opt6(fallback, IN6ADDRSZ);
+ else
+ put_opt6(&context->local6, IN6ADDRSZ);
end_opt6(o);
}