diff --git a/src/dnsmasq.h b/src/dnsmasq.h index dfe8cfb..5ac1e99 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -936,7 +936,7 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add #endif void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, 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_interface(struct dhcp_lease *lease, int interface); struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type, diff --git a/src/lease.c b/src/lease.c index ef3c6cc..691ee61 100644 --- a/src/lease.c +++ b/src/lease.c @@ -146,10 +146,10 @@ void lease_init(time_t now) { #ifdef HAVE_DHCP6 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 #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 the startup synthesised SIGHUP. */ @@ -216,9 +216,9 @@ void lease_update_from_configs(void) lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && (config->flags & CONFIG_NAME) && (!(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))) - 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, ...) @@ -669,10 +669,13 @@ static void kill_name(struct dhcp_lease *lease) 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; 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)) { diff --git a/src/rfc2131.c b/src/rfc2131.c index fcd9bf8..d897087 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -46,7 +46,7 @@ static void do_options(struct dhcp_context *context, unsigned char *real_end, unsigned char *req_options, char *hostname, - char *domain, char *config_domain, + char *config_domain, struct dhcp_netid *netid, struct in_addr subnet_addr, 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); 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. */ lease_set_expires(lease, 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); 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); } 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); @@ -1307,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, } 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_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); } 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); @@ -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), - 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 */ 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 *req_options, char *hostname, - char *domain, char *config_domain, + char *domain, struct dhcp_netid *netid, struct in_addr subnet_addr, 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 */ 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 */ if (option_bool(OPT_LOG_OPTS) && req_options) { diff --git a/src/rfc3315.c b/src/rfc3315.c index 67aa624..43cb832 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -20,6 +20,7 @@ #ifdef HAVE_DHCP6 static size_t outpacket_counter; + static void end_opt6(int container); static int save_counter(int newval); 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; int clid_len = 0, start_opts; 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_netid known_id; int done_dns = 0, hostname_auth = 0, do_encap = 0; @@ -326,8 +328,7 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, else if (client_hostname) { domain = strip_hostname(client_hostname); - /* TODO verify legal domain */ - + if (strlen(client_hostname) != 0) { hostname = client_hostname; @@ -364,6 +365,9 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, switch (msg_type) { + default: + return 0; + case DHCP6SOLICIT: 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. */ 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; - addrp = &config->addr6; + 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; } + /* existing lease */ - else if ((lease = lease6_find(clid, clid_len, - ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, iaid, NULL))) + if (!addrp && + (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; - 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; } @@ -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_hwaddr(lease, NULL, clid, 0, iaid, clid_len); 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) { @@ -672,7 +702,12 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, lease_set_expires(lease, lease_time, now); 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) min_time = lease_time; @@ -839,6 +874,97 @@ static int dhcp6_no_relay(int msg_type, struct dhcp_netid *tags, 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; size_t len = strlen(hostname); - if (domain) - len += strlen(domain) + 1; + if (send_domain) + len += strlen(send_domain) + 1; o = new_opt6(OPTION6_FQDN); p = expand(len + 3); *(p++) = fqdn_flags; p = do_rfc1035_name(p, hostname); - if (domain) - p = do_rfc1035_name(p, domain); + if (send_domain) + p = do_rfc1035_name(p, send_domain); *p = 0; end_opt6(o); }