DHCPDECLINE handling, domain handling, more complete address selection.

This commit is contained in:
Simon Kelley
2012-02-06 22:05:15 +00:00
parent 4cb1b32009
commit 70c5e3e076
4 changed files with 156 additions and 30 deletions

View File

@@ -936,7 +936,7 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
#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);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *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);
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,

View File

@@ -146,10 +146,10 @@ void lease_init(time_t now)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (v6pass) if (v6pass)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr)); lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
else else
#endif #endif
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr)); lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
} }
/* set these correctly: the "old" events are generated later from /* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */ the startup synthesised SIGHUP. */
@@ -216,9 +216,9 @@ void lease_update_from_configs(void)
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) && (config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr)); lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
else if ((name = host_from_dns(lease->addr))) else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, 1, get_domain(lease->addr)); /* updates auth flag only */ lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
} }
static void ourprintf(int *errp, char *format, ...) static void ourprintf(int *errp, char *format, ...)
@@ -669,11 +669,14 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL; lease->hostname = lease->fqdn = NULL;
} }
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain) void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
{ {
struct dhcp_lease *lease_tmp; struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL; char *new_name = NULL, *new_fqdn = NULL;
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
if (lease->hostname && name && hostname_isequal(lease->hostname, name)) if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{ {
if (auth) if (auth)

View File

@@ -46,7 +46,7 @@ static void do_options(struct dhcp_context *context,
unsigned char *real_end, unsigned char *real_end,
unsigned char *req_options, unsigned char *req_options,
char *hostname, char *hostname,
char *domain, char *config_domain, char *config_domain,
struct dhcp_netid *netid, struct dhcp_netid *netid,
struct in_addr subnet_addr, struct in_addr subnet_addr,
unsigned char fqdn_flags, unsigned char fqdn_flags,
@@ -487,7 +487,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0); lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
if (hostname) if (hostname)
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr)); 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,
@@ -496,7 +496,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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),
domain, netid, subnet_addr, 0, 0, 0, NULL, 0, now); netid, subnet_addr, 0, 0, 0, NULL, 0, now);
} }
} }
@@ -1022,7 +1022,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T2, 4, (time*7)/8); option_put(mess, end, OPTION_T2, 4, (time*7)/8);
} }
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
@@ -1307,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
} }
if (hostname) if (hostname)
lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr)); 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);
@@ -1331,7 +1331,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz); option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
} }
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
} }
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
@@ -1391,7 +1391,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
} }
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr), do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
*is_inform = 1; /* handle reply differently */ *is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
@@ -2144,7 +2144,7 @@ static void do_options(struct dhcp_context *context,
unsigned char *end, unsigned char *end,
unsigned char *req_options, unsigned char *req_options,
char *hostname, char *hostname,
char *domain, char *config_domain, char *domain,
struct dhcp_netid *netid, struct dhcp_netid *netid,
struct in_addr subnet_addr, struct in_addr subnet_addr,
unsigned char fqdn_flags, unsigned char fqdn_flags,
@@ -2166,9 +2166,6 @@ static void do_options(struct dhcp_context *context,
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */ /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
tagif = option_filter(netid, &context->netid, config_opts); tagif = option_filter(netid, &context->netid, config_opts);
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
/* logging */ /* logging */
if (option_bool(OPT_LOG_OPTS) && req_options) if (option_bool(OPT_LOG_OPTS) && req_options)
{ {

View File

@@ -20,6 +20,7 @@
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
static size_t outpacket_counter; static size_t outpacket_counter;
static void end_opt6(int container); static void end_opt6(int container);
static int save_counter(int newval); static int save_counter(int newval);
static void *expand(size_t headroom); static void *expand(size_t headroom);
@@ -179,7 +180,8 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
unsigned char *clid = NULL; unsigned char *clid = NULL;
int clid_len = 0, start_opts; int clid_len = 0, start_opts;
struct dhcp_netid *tagif, *context_tags = NULL; struct dhcp_netid *tagif, *context_tags = NULL;
char *client_hostname= NULL, *hostname = NULL, *domain= NULL; char *client_hostname= NULL, *hostname = NULL;
char *domain = NULL, *send_domain = NULL;
struct dhcp_config *config = NULL; struct dhcp_config *config = NULL;
struct dhcp_netid known_id; struct dhcp_netid known_id;
int done_dns = 0, hostname_auth = 0, do_encap = 0; int done_dns = 0, hostname_auth = 0, do_encap = 0;
@@ -326,7 +328,6 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
else if (client_hostname) else if (client_hostname)
{ {
domain = strip_hostname(client_hostname); domain = strip_hostname(client_hostname);
/* TODO verify legal domain */
if (strlen(client_hostname) != 0) if (strlen(client_hostname) != 0)
{ {
@@ -364,6 +365,9 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
switch (msg_type) switch (msg_type)
{ {
default:
return 0;
case DHCP6SOLICIT: case DHCP6SOLICIT:
case DHCP6REQUEST: case DHCP6REQUEST:
{ {
@@ -463,14 +467,32 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
/* Don't used configured addresses for temporary leases. */ /* Don't used configured addresses for temporary leases. */
if (have_config(config, CONFIG_ADDR6) && !used_config && ia_type == OPTION6_IA_NA) if (have_config(config, CONFIG_ADDR6) && !used_config && ia_type == OPTION6_IA_NA)
{ {
struct dhcp_lease *ltmp = lease6_find_by_addr(&config->addr6, 128, 0);
used_config = 1; used_config = 1;
inet_ntop(AF_INET6, &config->addr6, daemon->addrbuff, ADDRSTRLEN);
if (ltmp && ltmp->clid &&
(ltmp->clid_len != clid_len || memcmp(ltmp->clid, clid, clid_len) != 0))
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
daemon->addrbuff, print_mac(daemon->namebuff, ltmp->clid, ltmp->clid_len));
else if (have_config(config, CONFIG_DECLINED) &&
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"),
daemon->addrbuff);
else
addrp = &config->addr6; addrp = &config->addr6;
} }
/* existing lease */ /* existing lease */
else if ((lease = lease6_find(clid, clid_len, if (!addrp &&
ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, iaid, NULL))) (lease = lease6_find(clid, clid_len,
ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, iaid, NULL)) &&
address6_available(context, (struct in6_addr *)&lease->hwaddr, tags) &&
!config_find_by_address6(daemon->dhcp_conf, (struct in6_addr *)&lease->hwaddr))
addrp = (struct in6_addr *)&lease->hwaddr; addrp = (struct in6_addr *)&lease->hwaddr;
else if (address6_allocate(context, clid, clid_len, serial++, tags, &alloced_addr))
if (!addrp && address6_allocate(context, clid, clid_len, serial++, tags, &alloced_addr))
addrp = &alloced_addr; addrp = &alloced_addr;
} }
@@ -518,8 +540,16 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
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);
if (hostname && ia_type == OPTION6_IA_NA) if (hostname && ia_type == OPTION6_IA_NA)
lease_set_hostname(lease, hostname, hostname_auth, domain); {
char *addr_domain = get_domain6(addrp);
if (!send_domain)
send_domain = addr_domain;
lease_set_hostname(lease, hostname, hostname_auth, addr_domain, domain);
} }
}
else if (!send_domain)
send_domain = get_domain6(addrp);
if (lease || !make_lease) if (lease || !make_lease)
{ {
@@ -672,7 +702,12 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
lease_set_expires(lease, lease_time, now); lease_set_expires(lease, lease_time, now);
if (ia_type == OPTION6_IA_NA && hostname) if (ia_type == OPTION6_IA_NA && hostname)
lease_set_hostname(lease, hostname, hostname_auth, domain); {
char *addr_domain = get_domain6(req_addr);
if (!send_domain)
send_domain = addr_domain;
lease_set_hostname(lease, hostname, hostname_auth, addr_domain, domain);
}
if (lease_time < min_time) if (lease_time < min_time)
min_time = lease_time; min_time = lease_time;
@@ -839,6 +874,97 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
return 1; return 1;
} }
case DHCP6DECLINE:
{
/* set reply message type */
*outmsgtypep = DHCP6REPLY;
log6_packet("DHCPDECLINE", clid, clid_len, NULL, xid, iface_name, NULL);
for (opt = packet_options; opt; opt = opt6_next(opt, end))
{
int iaid, ia_type = opt6_type(opt);
void *ia_option, *ia_end;
int made_ia = 0;
if (ia_type != OPTION6_IA_NA && ia_type != OPTION6_IA_TA)
continue;
if (ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
continue;
if (ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
continue;
iaid = opt6_uint(opt, 0, 4);
ia_end = opt6_ptr(opt, opt6_len(opt));
ia_option = opt6_ptr(opt, ia_type == OPTION6_IA_NA ? 12 : 4);
/* reset "USED" flags on leases */
lease6_find(NULL, 0, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, iaid, NULL);
for (ia_option = opt6_find(ia_option, ia_end, OPTION6_IAADDR, 24);
ia_option;
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct dhcp_lease *lease;
struct in6_addr *addrp = opt6_ptr(ia_option, 0);
if (have_config(config, CONFIG_ADDR6) &&
memcmp(&config->addr6, addrp, IN6ADDRSZ) == 0)
{
prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
daemon->addrbuff, daemon->dhcp_buff);
config->flags |= CONFIG_DECLINED;
config->decline_time = now;
}
else
/* make sure this host gets a different address next time. */
for (; context; context = context->current)
context->addr_epoch++;
if ((lease = lease6_find(clid, clid_len, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
iaid, opt6_ptr(ia_option, 0))))
lease_prune(lease, now);
else
{
if (!made_ia)
{
o = new_opt6(ia_type);
put_opt6_long(iaid);
if (ia_type == OPTION6_IA_NA)
{
put_opt6_long(0);
put_opt6_long(0);
}
made_ia = 1;
}
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
put_opt6_long(0);
put_opt6_long(0);
end_opt6(o1);
}
}
if (made_ia)
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string("No binding found");
end_opt6(o1);
end_opt6(o);
}
}
return 1;
}
} }
@@ -948,15 +1074,15 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags,
unsigned char *p; unsigned char *p;
size_t len = strlen(hostname); size_t len = strlen(hostname);
if (domain) if (send_domain)
len += strlen(domain) + 1; len += strlen(send_domain) + 1;
o = new_opt6(OPTION6_FQDN); o = new_opt6(OPTION6_FQDN);
p = expand(len + 3); p = expand(len + 3);
*(p++) = fqdn_flags; *(p++) = fqdn_flags;
p = do_rfc1035_name(p, hostname); p = do_rfc1035_name(p, hostname);
if (domain) if (send_domain)
p = do_rfc1035_name(p, domain); p = do_rfc1035_name(p, send_domain);
*p = 0; *p = 0;
end_opt6(o); end_opt6(o);
} }