From 407c7a5c5676491678f01f92b8b7f113da949073 Mon Sep 17 00:00:00 2001 From: victek Date: Fri, 27 Sep 2013 05:52:43 +0200 Subject: [PATCH] dnsmasq: v2.67test16 patch Sept.25th/2013. --- release/src/router/dnsmasq/CHANGELOG | 11 + release/src/router/dnsmasq/VERSION | 2 +- release/src/router/dnsmasq/man/dnsmasq.8 | 26 +- release/src/router/dnsmasq/src/bpf.c | 6 + release/src/router/dnsmasq/src/dhcp-common.c | 110 ++++- release/src/router/dnsmasq/src/dhcp.c | 83 ---- release/src/router/dnsmasq/src/dhcp6-protocol.h | 1 + release/src/router/dnsmasq/src/dhcp6.c | 153 ++++--- release/src/router/dnsmasq/src/dnsmasq.c | 6 +- release/src/router/dnsmasq/src/dnsmasq.h | 66 +-- release/src/router/dnsmasq/src/helper.c | 106 ++--- release/src/router/dnsmasq/src/lease.c | 120 +++--- release/src/router/dnsmasq/src/netlink.c | 2 + release/src/router/dnsmasq/src/network.c | 10 +- release/src/router/dnsmasq/src/radv-protocol.h | 7 + release/src/router/dnsmasq/src/radv.c | 15 +- release/src/router/dnsmasq/src/rfc3315.c | 545 +++++++++++++----------- release/src/router/dnsmasq/src/tftp.c | 2 - 18 files changed, 723 insertions(+), 548 deletions(-) diff --git a/release/src/router/dnsmasq/CHANGELOG b/release/src/router/dnsmasq/CHANGELOG index 14ac3d64ab..c0c6661290 100644 --- a/release/src/router/dnsmasq/CHANGELOG +++ b/release/src/router/dnsmasq/CHANGELOG @@ -114,6 +114,17 @@ version 2.67 Cope with DHCPv6 clients which send REQUESTs without address options - treat them as SOLICIT with rapid commit. + Support identification of clients by MAC address in + DHCPv6. When using a relay, the relay must support RFC + 6939 for this to work. It always works for directly + connected clients. Thanks to Vladislav Grishenko + for prompting this feature. + + Remove the rule for constructed DHCP ranges that the local + address must be either the first or last address in the + range. This was originally to avoid SLAAC addresses, but + we now explicitly autoconfig and privacy addresses instead. + version 2.66 Add the ability to act as an authoritative DNS diff --git a/release/src/router/dnsmasq/VERSION b/release/src/router/dnsmasq/VERSION index 454923cf75..2a0986e06f 100644 --- a/release/src/router/dnsmasq/VERSION +++ b/release/src/router/dnsmasq/VERSION @@ -1 +1 @@ -2.67test14 +2.67test16/09/25/2013 diff --git a/release/src/router/dnsmasq/man/dnsmasq.8 b/release/src/router/dnsmasq/man/dnsmasq.8 index 05733b8da9..2b1570a0af 100644 --- a/release/src/router/dnsmasq/man/dnsmasq.8 +++ b/release/src/router/dnsmasq/man/dnsmasq.8 @@ -652,24 +652,20 @@ This forms a template which describes how to create ranges, based on the address .B --dhcp-range=::1,::400,constructor:eth0 -will look for addresses of the form ::1 or :400 on +will look for addresses on eth0 and then create a range from ::1 to ::400. If the interface is assigned more than one network, then the corresponding ranges will be automatically created, and then deprecated and finally removed again as the address is deprecated and then deleted. The interface name may have a final "*" wildcard. Note -that just any address on eth0 will not do: the non-prefix part must be -equal either the start or end address given in the dhcp-range. This is -to prevent prefixes becoming perpetual if the interface -gains a SLAAC address for the prefix when it is advertised by dnsmasq. +that just any address on eth0 will not do: it must not be an +autoconfigured or privacy address, or be deprecated. If a dhcp-range is only being used for stateless DHCP and/or SLAAC, then the address can be simply :: .B --dhcp-range=::,constructor:eth0 -This removes the condition above, and will pick up the prefix from any address on eth0 which is NOT -autoconfigured, slaac, temporary or deprecated. There is a variant of the constructor: syntax using the keyword .B constructor-noauth. @@ -766,7 +762,8 @@ the same subnet as some valid dhcp-range. For subnets which don't need a pool of dynamically allocated addresses, use the "static" keyword in the dhcp-range declaration. -It is allowed to use client identifiers rather than +It is allowed to use client identifiers (called client +DUID in IPv6-land rather than hardware addresses to identify hosts by prefixing with 'id:'. Thus: .B --dhcp-host=id:01:02:03:04,..... refers to the host with client identifier 01:02:03:04. It is also @@ -781,11 +778,12 @@ IPv6 addresses may contain only the host-identifier part: .B --dhcp-host=laptop,[::56] in which case they act as wildcards in constructed dhcp ranges, with the appropriate network part inserted. -Note that in IPv6 DHCP, the hardware address is not normally -available, so a client must be identified by client-id (called client -DUID in IPv6-land) or hostname. +Note that in IPv6 DHCP, the hardware address may not be +available, though it normally is for direct-connected clients, or +clients using DHCP relays which support RFC 6939. -The special option id:* means "ignore any client-id + +For DHCPv4, the special option id:* means "ignore any client-id and use MAC addresses only." This is useful when a client presents a client-id sometimes but not others. @@ -1033,7 +1031,7 @@ this to set a different printer server for hosts in the class "accounts" than for hosts in the class "engineering". .TP .B \-4, --dhcp-mac=set:, -(IPv4 only) Map from a MAC address to a tag. The MAC address may include +Map from a MAC address to a tag. The MAC address may include wildcards. For example .B --dhcp-mac=set:3com,01:34:23:*:*:* will set the tag "3com" for any host whose MAC address matches the pattern. @@ -1339,7 +1337,7 @@ every call to the script. DNSMASQ_IAID containing the IAID for the lease. If the lease is a temporary allocation, this is prefixed to 'T'. - +DNSMASQ_MAC containing the MAC address of the client, if known. Note that the supplied hostname, vendorclass and userclass data is only supplied for diff --git a/release/src/router/dnsmasq/src/bpf.c b/release/src/router/dnsmasq/src/bpf.c index 619a662ac5..390d0767f6 100644 --- a/release/src/router/dnsmasq/src/bpf.c +++ b/release/src/router/dnsmasq/src/bpf.c @@ -160,9 +160,15 @@ int iface_enumerate(int family, void *parm, int (*callback)()) if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) flags |= IFACE_DEPRECATED; +#ifdef IN6_IFF_TEMPORARY if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY))) flags |= IFACE_PERMANENT; +#endif +#ifdef IN6_IFF_PRIVACY + if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY))) + flags |= IFACE_PERMANENT; +#endif } ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr); diff --git a/release/src/router/dnsmasq/src/dhcp-common.c b/release/src/router/dnsmasq/src/dhcp-common.c index 939f25a831..7e99fc9123 100644 --- a/release/src/router/dnsmasq/src/dhcp-common.c +++ b/release/src/router/dnsmasq/src/dhcp-common.c @@ -253,6 +253,110 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len) return 0; } +int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type) +{ + struct hwaddr_config *conf_addr; + + for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) + if (conf_addr->wildcard_mask == 0 && + conf_addr->hwaddr_len == len && + (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) && + memcmp(conf_addr->hwaddr, hwaddr, len) == 0) + return 1; + + return 0; +} + +static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config) +{ + if (!context) /* called via find_config() from lease_update_from_configs() */ + return 1; + + if (!(context->flags & CONTEXT_V6)) + { + if (!(config->flags & CONFIG_ADDR)) + return 1; + + for (; context; context = context->current) + if (is_same_net(config->addr, context->start, context->netmask)) + return 1; + } +#ifdef HAVE_DHCP6 + else + { + if (!(config->flags & CONFIG_ADDR6) || (config->flags & CONFIG_WILDCARD)) + return 1; + + for (; context; context = context->current) + if (is_same_net6(&config->addr6, &context->start6, context->prefix)) + return 1; + } +#endif + + return 0; +} + +struct dhcp_config *find_config(struct dhcp_config *configs, + struct dhcp_context *context, + unsigned char *clid, int clid_len, + unsigned char *hwaddr, int hw_len, + int hw_type, char *hostname) +{ + int count, new; + struct dhcp_config *config, *candidate; + struct hwaddr_config *conf_addr; + + if (clid) + for (config = configs; config; config = config->next) + if (config->flags & CONFIG_CLID) + { + if (config->clid_len == clid_len && + memcmp(config->clid, clid, clid_len) == 0 && + is_config_in_context(context, config)) + return config; + + /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and + cope with that here */ + if (!(context->flags & CONTEXT_V6) && *clid == 0 && config->clid_len == clid_len-1 && + memcmp(config->clid, clid+1, clid_len-1) == 0 && + is_config_in_context(context, config)) + return config; + } + + + if (hwaddr) + for (config = configs; config; config = config->next) + if (config_has_mac(config, hwaddr, hw_len, hw_type) && + is_config_in_context(context, config)) + return config; + + if (hostname && context) + for (config = configs; config; config = config->next) + if ((config->flags & CONFIG_NAME) && + hostname_isequal(config->hostname, hostname) && + is_config_in_context(context, config)) + return config; + + + if (!hwaddr) + return NULL; + + /* use match with fewest wildcard octets */ + for (candidate = NULL, count = 0, config = configs; config; config = config->next) + if (is_config_in_context(context, config)) + for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) + if (conf_addr->wildcard_mask != 0 && + conf_addr->hwaddr_len == hw_len && + (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) && + (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count) + { + count = new; + candidate = config; + } + + return candidate; +} + void dhcp_update_configs(struct dhcp_config *configs) { /* Some people like to keep all static IP addresses in /etc/hosts. @@ -523,6 +627,8 @@ int lookup_dhcp_opt(int prot, char *name) const struct opttab_t *t; int i; + (void)prot; + #ifdef HAVE_DHCP6 if (prot == AF_INET6) t = opttab6; @@ -542,6 +648,8 @@ int lookup_dhcp_len(int prot, int val) const struct opttab_t *t; int i; + (void)prot; + #ifdef HAVE_DHCP6 if (prot == AF_INET6) t = opttab6; @@ -719,7 +827,7 @@ void log_context(int family, struct dhcp_context *context) template = p; p += sprintf(p, ", "); - if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name)) + if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name)) sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name); } else if (context->flags & CONTEXT_TEMPLATE) diff --git a/release/src/router/dnsmasq/src/dhcp.c b/release/src/router/dnsmasq/src/dhcp.c index 573de5b08c..67a82b530d 100644 --- a/release/src/router/dnsmasq/src/dhcp.c +++ b/release/src/router/dnsmasq/src/dhcp.c @@ -749,89 +749,6 @@ int address_allocate(struct dhcp_context *context, return 0; } -static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config) -{ - if (!context) /* called via find_config() from lease_update_from_configs() */ - return 1; - if (!(config->flags & CONFIG_ADDR)) - return 1; - for (; context; context = context->current) - if (is_same_net(config->addr, context->start, context->netmask)) - return 1; - - return 0; -} - -int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type) -{ - struct hwaddr_config *conf_addr; - - for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) - if (conf_addr->wildcard_mask == 0 && - conf_addr->hwaddr_len == len && - (conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) && - memcmp(conf_addr->hwaddr, hwaddr, len) == 0) - return 1; - - return 0; -} - -struct dhcp_config *find_config(struct dhcp_config *configs, - struct dhcp_context *context, - unsigned char *clid, int clid_len, - unsigned char *hwaddr, int hw_len, - int hw_type, char *hostname) -{ - int count, new; - struct dhcp_config *config, *candidate; - struct hwaddr_config *conf_addr; - - if (clid) - for (config = configs; config; config = config->next) - if (config->flags & CONFIG_CLID) - { - if (config->clid_len == clid_len && - memcmp(config->clid, clid, clid_len) == 0 && - is_addr_in_context(context, config)) - return config; - - /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and - cope with that here */ - if (*clid == 0 && config->clid_len == clid_len-1 && - memcmp(config->clid, clid+1, clid_len-1) == 0 && - is_addr_in_context(context, config)) - return config; - } - - - for (config = configs; config; config = config->next) - if (config_has_mac(config, hwaddr, hw_len, hw_type) && - is_addr_in_context(context, config)) - return config; - - if (hostname && context) - for (config = configs; config; config = config->next) - if ((config->flags & CONFIG_NAME) && - hostname_isequal(config->hostname, hostname) && - is_addr_in_context(context, config)) - return config; - - /* use match with fewest wildcard octets */ - for (candidate = NULL, count = 0, config = configs; config; config = config->next) - if (is_addr_in_context(context, config)) - for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) - if (conf_addr->wildcard_mask != 0 && - conf_addr->hwaddr_len == hw_len && - (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) && - (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count) - { - count = new; - candidate = config; - } - - return candidate; -} - void dhcp_read_ethers(void) { FILE *f = fopen(ETHERSFILE, "r"); diff --git a/release/src/router/dnsmasq/src/dhcp6-protocol.h b/release/src/router/dnsmasq/src/dhcp6-protocol.h index c4eef3559b..f8e98ec981 100644 --- a/release/src/router/dnsmasq/src/dhcp6-protocol.h +++ b/release/src/router/dnsmasq/src/dhcp6-protocol.h @@ -59,6 +59,7 @@ #define OPTION6_REMOTE_ID 37 #define OPTION6_SUBSCRIBER_ID 38 #define OPTION6_FQDN 39 +#define OPTION6_CLIENT_MAC 79 /* replace this with the real number when allocated. defining this also enables the relevant code. */ diff --git a/release/src/router/dnsmasq/src/dhcp6.c b/release/src/router/dnsmasq/src/dhcp6.c index 35bb74829b..1a7aa48fb8 100644 --- a/release/src/router/dnsmasq/src/dhcp6.c +++ b/release/src/router/dnsmasq/src/dhcp6.c @@ -18,6 +18,8 @@ #ifdef HAVE_DHCP6 +#include + struct iface_param { struct dhcp_context *current; struct dhcp_relay *relay; @@ -25,10 +27,17 @@ struct iface_param { int ind, addr_match; }; +struct mac_param { + struct in6_addr *target; + unsigned char *mac; + unsigned int maclen; +}; + + static int complete_context6(struct in6_addr *local, int prefix, int scope, int if_index, int flags, unsigned int preferred, unsigned int valid, void *vparam); - +static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv); static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); void dhcp6_init(void) @@ -102,6 +111,9 @@ void dhcp6_packet(time_t now) struct ifreq ifr; struct iname *tmp; unsigned short port; + struct in6_addr dst_addr; + + memset(&dst_addr, 0, sizeof(dst_addr)); msg.msg_control = control_u.control6; msg.msg_controllen = sizeof(control_u); @@ -124,6 +136,7 @@ void dhcp6_packet(time_t now) p.c = CMSG_DATA(cmptr); if_index = p.p->ipi6_ifindex; + dst_addr = p.p->ipi6_addr; } if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name)) @@ -131,7 +144,6 @@ void dhcp6_packet(time_t now) if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0) { - for (tmp = daemon->if_except; tmp; tmp = tmp->next) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) return; @@ -166,7 +178,7 @@ void dhcp6_packet(time_t now) if (!iface_enumerate(AF_INET6, &parm, complete_context6)) return; - + if (daemon->if_names || daemon->if_addrs) { @@ -180,7 +192,14 @@ void dhcp6_packet(time_t now) if (parm.relay) { - relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id); + /* Ignore requests sent to the ALL_SERVERS multicast address for relay when + we're listening there for DHCPv6 server reasons. */ + struct in6_addr all_servers; + + inet_pton(AF_INET6, ALL_SERVERS, &all_servers); + + if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers)) + relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id); return; } @@ -191,7 +210,7 @@ void dhcp6_packet(time_t now) lease_prune(NULL, now); /* lose any expired leases */ port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, - sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now); + sz, &from.sin6_addr, now); lease_update_file(now); lease_update_dns(0); @@ -210,6 +229,73 @@ void dhcp6_packet(time_t now) } } +void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep) +{ + /* Recieving a packet from a host does not populate the neighbour + cache, so we send a neighbour discovery request if we can't + find the sender. Repeat a few times in case of packet loss. */ + + struct neigh_packet neigh; + struct sockaddr_in6 addr; + struct mac_param mac_param; + int i; + + neigh.type = ND_NEIGHBOR_SOLICIT; + neigh.code = 0; + neigh.reserved = 0; + neigh.target = *client; + + memset(&addr, 0, sizeof(addr)); +#ifdef HAVE_SOCKADDR_SA_LEN + addr.sin6_len = sizeof(struct sockaddr_in6); +#endif + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(IPPROTO_ICMPV6); + addr.sin6_addr = *client; + addr.sin6_scope_id = iface; + + mac_param.target = client; + mac_param.maclen = 0; + mac_param.mac = mac; + + for (i = 0; i < 5; i++) + { + struct timespec ts; + + iface_enumerate(AF_UNSPEC, &mac_param, find_mac); + + if (mac_param.maclen != 0) + break; + + sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr)); + + ts.tv_sec = 0; + ts.tv_nsec = 100000000; /* 100ms */ + nanosleep(&ts, NULL); + } + + *maclenp = mac_param.maclen; + *mactypep = ARPHRD_ETHER; +} + +static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv) +{ + struct mac_param *parm = parmv; + + if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp)) + { + if (maclen <= DHCP_CHADDR_MAX) + { + parm->maclen = maclen; + memcpy(parm->mac, mac, maclen); + } + + return 0; /* found, abort */ + } + + return 1; +} + static int complete_context6(struct in6_addr *local, int prefix, int scope, int if_index, int flags, unsigned int preferred, unsigned int valid, void *vparam) @@ -435,48 +521,6 @@ int config_valid(struct dhcp_config *config, struct dhcp_context *context, struc return 0; } -static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config) -{ - if (!(config->flags & CONFIG_ADDR6) || - (config->flags & CONFIG_WILDCARD)) - - return 1; - - for (; context; context = context->current) - if (is_same_net6(&config->addr6, &context->start6, context->prefix)) - return 1; - - return 0; -} - - -struct dhcp_config *find_config6(struct dhcp_config *configs, - struct dhcp_context *context, - unsigned char *duid, int duid_len, - char *hostname) -{ - struct dhcp_config *config; - - if (duid) - for (config = configs; config; config = config->next) - if (config->flags & CONFIG_CLID) - { - if (config->clid_len == duid_len && - memcmp(config->clid, duid, duid_len) == 0 && - is_config_in_context6(context, config)) - return config; - } - - if (hostname && context) - for (config = configs; config; config = config->next) - if ((config->flags & CONFIG_NAME) && - hostname_isequal(config->hostname, hostname) && - is_config_in_context6(context, config)) - return config; - - return NULL; -} - void make_duid(time_t now) { if (daemon->duid_config) @@ -510,6 +554,7 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo unsigned char *p; (void)index; + (void)parm; if (type >= 256) return 1; @@ -557,7 +602,13 @@ static int construct_worker(struct in6_addr *local, int prefix, IN6_IS_ADDR_MULTICAST(local)) return 1; - if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name)) + if (!(flags & IFACE_PERMANENT)) + return 1; + + if (flags & IFACE_DEPRECATED) + return 1; + + if (!indextoname(daemon->icmp6fd, if_index, ifrn_name)) return 0; for (template = daemon->dhcp6; template; template = template->next) @@ -573,11 +624,7 @@ static int construct_worker(struct in6_addr *local, int prefix, } } - else if ((addr6part(local) == addr6part(&template->start6) || - addr6part(local) == addr6part(&template->end6) || - (IN6_IS_ADDR_UNSPECIFIED(&template->start6) && - IFACE_PERMANENT == (flags & (IFACE_PERMANENT | IFACE_DEPRECATED)))) && - wildcard_match(template->template_interface, ifrn_name)) + else if (wildcard_match(template->template_interface, ifrn_name)) { start6 = *local; setaddr6part(&start6, addr6part(&template->start6)); diff --git a/release/src/router/dnsmasq/src/dnsmasq.c b/release/src/router/dnsmasq/src/dnsmasq.c index 5556fd6ee0..b3c20c0777 100644 --- a/release/src/router/dnsmasq/src/dnsmasq.c +++ b/release/src/router/dnsmasq/src/dnsmasq.c @@ -95,8 +95,10 @@ int main (int argc, char **argv) cap_user_header_t hdr = NULL; cap_user_data_t data = NULL; #endif +#if defined(HAVE_DHCP) || defined(HAVE_DHCP6) struct dhcp_context *context; struct dhcp_relay *relay; +#endif #ifdef LOCALEDIR setlocale(LC_ALL, ""); @@ -246,7 +248,7 @@ int main (int argc, char **argv) dhcp_init(); # ifdef HAVE_DHCP6 - if (daemon->doing_ra) + if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6) ra_init(now); if (daemon->doing_dhcp6 || daemon->relay6) @@ -1294,6 +1296,8 @@ void poll_resolv(int force, int do_reload, time_t now) void clear_cache_and_reload(time_t now) { + (void)now; + if (daemon->port != 0) cache_reload(); diff --git a/release/src/router/dnsmasq/src/dnsmasq.h b/release/src/router/dnsmasq/src/dnsmasq.h index 6680f072d3..cd755abcb9 100644 --- a/release/src/router/dnsmasq/src/dnsmasq.h +++ b/release/src/router/dnsmasq/src/dnsmasq.h @@ -548,13 +548,15 @@ struct dhcp_lease { #ifdef HAVE_BROKEN_RTC unsigned int length; #endif - int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */ - unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */ + int hwaddr_len, hwaddr_type; + unsigned char hwaddr[DHCP_CHADDR_MAX]; struct in_addr addr, override, giaddr; unsigned char *extradata; unsigned int extradata_len, extradata_size; int last_interface; #ifdef HAVE_DHCP6 + struct in6_addr addr6; + int iaid; struct slaac_address { struct in6_addr addr, local; time_t ping_time; @@ -726,24 +728,25 @@ struct dhcp_context { struct dhcp_context *next, *current; }; -#define CONTEXT_STATIC 1 -#define CONTEXT_NETMASK 2 -#define CONTEXT_BRDCAST 4 -#define CONTEXT_PROXY 8 -#define CONTEXT_RA_ONLY 16 -#define CONTEXT_RA_DONE 32 -#define CONTEXT_RA_NAME 64 -#define CONTEXT_RA_STATELESS 128 -#define CONTEXT_DHCP 256 -#define CONTEXT_DEPRECATE 512 -#define CONTEXT_TEMPLATE 1024 /* create contexts using addresses */ -#define CONTEXT_CONSTRUCTED 2048 -#define CONTEXT_GC 4096 -#define CONTEXT_RA 8192 -#define CONTEXT_CONF_USED 16384 -#define CONTEXT_USED 32768 -#define CONTEXT_NOAUTH 65536 -#define CONTEXT_OLD 131072 +#define CONTEXT_STATIC (1u<<0) +#define CONTEXT_NETMASK (1u<<1) +#define CONTEXT_BRDCAST (1u<<2) +#define CONTEXT_PROXY (1u<<3) +#define CONTEXT_RA_ONLY (1u<<4) +#define CONTEXT_RA_DONE (1u<<5) +#define CONTEXT_RA_NAME (1u<<6) +#define CONTEXT_RA_STATELESS (1u<<7) +#define CONTEXT_DHCP (1u<<8) +#define CONTEXT_DEPRECATE (1u<<9) +#define CONTEXT_TEMPLATE (1u<<10) /* create contexts using addresses */ +#define CONTEXT_CONSTRUCTED (1u<<11) +#define CONTEXT_GC (1u<<12) +#define CONTEXT_RA (1u<<13) +#define CONTEXT_CONF_USED (1u<<14) +#define CONTEXT_USED (1u<<15) +#define CONTEXT_NOAUTH (1u<<16) +#define CONTEXT_OLD (1u<<17) +#define CONTEXT_V6 (1u<<18) struct ping_result { @@ -1081,12 +1084,6 @@ struct dhcp_context *narrow_context(struct dhcp_context *context, int address_allocate(struct dhcp_context *context, struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct dhcp_netid *netids, time_t now); -int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type); -struct dhcp_config *find_config(struct dhcp_config *configs, - struct dhcp_context *context, - unsigned char *clid, int clid_len, - unsigned char *hwaddr, int hw_len, - int hw_type, char *hostname); void dhcp_read_ethers(void); struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr); char *host_from_dns(struct in_addr addr); @@ -1108,6 +1105,7 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add u64 lease_find_max_addr6(struct dhcp_context *context); void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface); void lease_update_slaac(time_t now); +void lease_set_iaid(struct dhcp_lease *lease, int iaid); #endif void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force); @@ -1225,20 +1223,18 @@ struct dhcp_context *address6_valid(struct dhcp_context *context, struct in6_addr *taddr, struct dhcp_netid *netids, int plain_range); -struct dhcp_config *find_config6(struct dhcp_config *configs, - struct dhcp_context *context, - unsigned char *duid, int duid_len, - char *hostname); struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr); void make_duid(time_t now); void dhcp_construct_contexts(time_t now); +void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, + unsigned int *maclenp, unsigned int *mactypep); #endif - + /* rfc3315.c */ #ifdef HAVE_DHCP6 unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name, - struct in6_addr *fallback, size_t sz, int is_multicast, time_t now); + struct in6_addr *fallback, size_t sz, struct in6_addr *client_addr, time_t now); void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id); unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface); @@ -1261,6 +1257,12 @@ int lookup_dhcp_opt(int prot, char *name); int lookup_dhcp_len(int prot, int val); char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len); +struct dhcp_config *find_config(struct dhcp_config *configs, + struct dhcp_context *context, + unsigned char *clid, int clid_len, + unsigned char *hwaddr, int hw_len, + int hw_type, char *hostname); +int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type); #ifdef HAVE_LINUX_NETWORK void bindtodevice(int fd); #endif diff --git a/release/src/router/dnsmasq/src/helper.c b/release/src/router/dnsmasq/src/helper.c index ab691b7f51..d6bcd63ba3 100644 --- a/release/src/router/dnsmasq/src/helper.c +++ b/release/src/router/dnsmasq/src/helper.c @@ -61,9 +61,12 @@ struct script_data #else time_t expires; #endif +#ifdef HAVE_DHCP6 + struct in6_addr addr6; + int iaid, vendorclass_count; +#endif unsigned char hwaddr[DHCP_CHADDR_MAX]; char interface[IF_NAMESIZE]; - }; static struct script_data *buf = NULL; @@ -215,20 +218,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) continue; - if (!is6) + /* stringify MAC into dhcp_buff */ + p = daemon->dhcp_buff; + if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) + p += sprintf(p, "%.2x-", data.hwaddr_type); + for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++) { - /* stringify MAC into dhcp_buff */ - p = daemon->dhcp_buff; - if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) - p += sprintf(p, "%.2x-", data.hwaddr_type); - for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++) - { - p += sprintf(p, "%.2x", data.hwaddr[i]); - if (i != data.hwaddr_len - 1) - p += sprintf(p, ":"); - } + p += sprintf(p, "%.2x", data.hwaddr[i]); + if (i != data.hwaddr_len - 1) + p += sprintf(p, ":"); } - + /* supplied data may just exceed normal buffer (unlikely) */ if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME && !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len))) @@ -239,32 +239,25 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) continue; /* CLID into packet */ - if (!is6) - for (p = daemon->packet, i = 0; i < data.clid_len; i++) - { - p += sprintf(p, "%.2x", buf[i]); - if (i != data.clid_len - 1) + for (p = daemon->packet, i = 0; i < data.clid_len; i++) + { + p += sprintf(p, "%.2x", buf[i]); + if (i != data.clid_len - 1) p += sprintf(p, ":"); - } + } + #ifdef HAVE_DHCP6 - else + if (is6) { /* or IAID and server DUID for IPv6 */ - sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type); - for (p = daemon->packet, i = 0; i < daemon->duid_len; i++) + sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid); + for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++) { p += sprintf(p, "%.2x", daemon->duid[i]); if (i != daemon->duid_len - 1) p += sprintf(p, ":"); } - /* duid not MAC for IPv6 */ - for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++) - { - p += sprintf(p, "%.2x", buf[i]); - if (i != data.clid_len - 1) - p += sprintf(p, ":"); - } } #endif @@ -293,12 +286,12 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN); #ifdef HAVE_DHCP6 else - inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN); + inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN); #endif /* file length */ if (data.action == ACTION_TFTP) - sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len); + sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%u", data.iaid); #ifdef HAVE_LUASCRIPT if (daemon->luascript) @@ -316,7 +309,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) lua_setfield(lua, -2, "destination_address"); lua_pushstring(lua, hostname); lua_setfield(lua, -2, "file_name"); - lua_pushstring(lua, daemon->dhcp_buff); + lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff); lua_setfield(lua, -2, "file_size"); lua_call(lua, 2, 0); /* pass 2 values, expect 0 */ } @@ -329,9 +322,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) if (is6) { - lua_pushstring(lua, daemon->dhcp_buff); - lua_setfield(lua, -2, "client_duid"); lua_pushstring(lua, daemon->packet); + lua_setfield(lua, -2, "client_duid"); + lua_pushstring(lua, daemon->dhcp_packet.iov_base); lua_setfield(lua, -2, "server_duid"); lua_pushstring(lua, daemon->dhcp_buff3); lua_setfield(lua, -2, "iaid"); @@ -375,12 +368,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) if (!is6) buf = grab_extradata_lua(buf, end, "vendor_class"); #ifdef HAVE_DHCP6 - else - for (i = 0; i < data.hwaddr_len; i++) - { - sprintf(daemon->dhcp_buff2, "vendor_class%i", i); - buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2); - } + else if (data.vendorclass_count != 0) + { + sprintf(daemon->dhcp_buff2, "vendor_class_id"); + buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2); + for (i = 0; i < data.vendorclass_count - 1; i++) + { + sprintf(daemon->dhcp_buff2, "vendor_class%i", i); + buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2); + } + } #endif buf = grab_extradata_lua(buf, end, "supplied_hostname"); @@ -423,7 +420,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) lua_setfield(lua, -2, "old_hostname"); } - if (!is6) + if (!is6 || data.hwaddr_len != 0) { lua_pushstring(lua, daemon->dhcp_buff); lua_setfield(lua, -2, "mac_address"); @@ -476,11 +473,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) if (data.action != ACTION_TFTP) { +#ifdef HAVE_DHCP6 if (is6) { my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err); - my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err); + my_setenv("DNSMASQ_SERVER_DUID", daemon->dhcp_packet.iov_base, &err); + if (data.hwaddr_len != 0) + my_setenv("DNSMASQ_MAC", daemon->dhcp_buff, &err); } +#endif if (!is6 && data.clid_len != 0) my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err); @@ -507,10 +508,10 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) #ifdef HAVE_DHCP6 else { - if (data.hwaddr_len != 0) + if (data.vendorclass_count != 0) { buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err); - for (i = 0; i < data.hwaddr_len - 1; i++) + for (i = 0; i < data.vendorclass_count - 1; i++) { sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i); buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err); @@ -570,7 +571,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) { execl(daemon->lease_change_command, p ? p+1 : daemon->lease_change_command, - action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL); + action_str, is6 ? daemon->packet : daemon->dhcp_buff, + daemon->addrbuff, hostname, (char*)NULL); err = errno; } /* failed, send event so the main process logs the problem */ @@ -656,8 +658,6 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n unsigned int hostname_len = 0, clid_len = 0, ed_len = 0; int fd = daemon->dhcpfd; #ifdef HAVE_DHCP6 - int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA)); - if (!daemon->dhcp) fd = daemon->dhcp6fd; #endif @@ -678,11 +678,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n buf->action = action; buf->flags = lease->flags; #ifdef HAVE_DHCP6 - if (is6) - buf->hwaddr_len = lease->vendorclass_count; - else + buf->vendorclass_count = lease->vendorclass_count; + buf->addr6 = lease->addr6; + buf->iaid = lease->iaid; #endif - buf->hwaddr_len = lease->hwaddr_len; + buf->hwaddr_len = lease->hwaddr_len; buf->hwaddr_type = lease->hwaddr_type; buf->clid_len = clid_len; buf->ed_len = ed_len; @@ -739,13 +739,13 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer) buf->action = ACTION_TFTP; buf->hostname_len = filename_len; - buf->hwaddr_len = file_len; + buf->iaid = file_len; if ((buf->flags = peer->sa.sa_family) == AF_INET) buf->addr = peer->in.sin_addr; #ifdef HAVE_IPV6 else - memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ); + buf->addr6 = peer->in6.sin6_addr; #endif memcpy((unsigned char *)(buf+1), filename, filename_len); diff --git a/release/src/router/dnsmasq/src/lease.c b/release/src/router/dnsmasq/src/lease.c index 70601ef8da..4a910990bd 100644 --- a/release/src/router/dnsmasq/src/lease.c +++ b/release/src/router/dnsmasq/src/lease.c @@ -108,6 +108,7 @@ void lease_init(time_t now) { char *s = daemon->dhcp_buff2; int lease_type = LEASE_NA; + int iaid; if (s[0] == 'T') { @@ -115,12 +116,12 @@ void lease_init(time_t now) s++; } - hw_type = strtoul(s, NULL, 10); + iaid = strtoul(s, NULL, 10); if ((lease = lease6_allocate(&addr.addr.addr6, lease_type))) { - lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now, 0); - + lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0); + lease_set_iaid(lease, iaid); if (strcmp(daemon->dhcp_buff, "*") != 0) lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL); } @@ -132,15 +133,12 @@ void lease_init(time_t now) if (!lease) die (_("too many stored leases"), NULL, EC_MISC); -//Some ASUS & TOMATO tweaks -#if defined(HAVE_BROKEN_RTC) || defined(HAVE_LEASEFILE_EXPIRE) +#ifdef HAVE_BROKEN_RTC if (ei != 0) lease->expires = (time_t)ei + now; else lease->expires = (time_t)0; -#ifdef HAVE_BROKEN_RT lease->length = ei; -#endif #else /* strictly time_t is opaque, but this hack should work on all sane systems, even when sizeof(time_t) == 8 */ @@ -190,10 +188,12 @@ void lease_update_from_configs(void) char *name; for (lease = leases; lease; lease = lease->next) - if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, - 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)) + if (lease->flags & (LEASE_TA | LEASE_NA)) + continue; + else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, + 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), NULL); else if ((name = host_from_dns(lease->addr))) lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */ @@ -232,17 +232,13 @@ void lease_update_file(time_t now) //ASUS and TOMATO tweaks to output remaining leasetime #ifdef HAVE_LEASEFILE_EXPIRE - ourprintf(&err, "%u ", + ourprintf(&err, "%u "); +#endif + #ifdef HAVE_BROKEN_RTC - (lease->length == 0) ? 0 : + ourprintf(&err, "%u ", lease->length); #else - (lease->expires == 0) ? 0 : -#endif - (unsigned int)difftime(lease->expires, now)); -#elif defined(HAVE_BROKEN_RTC) - ourprintf(&err, "%u ", lease->length); -else - ourprintf(&err, "%lu ", (unsigned long)lease->expires); + ourprintf(&err, "%lu ", (unsigned long)lease->expires); #endif if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0) @@ -285,22 +281,19 @@ else //ASUS and TOMATO tweaks to output remaining leasetime #ifdef HAVE_LEASEFILE_EXPIRE - ourprintf(&err, "%u ", + ourprintf(&err, "%u "); +#endif + #ifdef HAVE_BROKEN_RTC - (lease->length == 0) ? 0 : + ourprintf(&err, "%u ", lease->length); #else - (lease->expires == 0) ? 0 : + ourprintf(&err, "%lu ", (unsigned long)lease->expires); #endif - (unsigned int)difftime(lease->expires, now)); -#elif defined(HAVE_BROKEN_RTC) - ourprintf(&err, "%u ", lease->length); -else - ourprintf(&err, "%lu ", (unsigned long)lease->expires); -#endif - inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN); + + inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN); ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "", - lease->hwaddr_type, daemon->addrbuff); + lease->iaid, daemon->addrbuff); ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*"); if (lease->clid && lease->clid_len != 0) @@ -396,7 +389,7 @@ static int find_interface_v6(struct in6_addr *local, int prefix, 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)) + if (is_same_net6(local, &lease->addr6, prefix)) lease_set_interface(lease, if_index, *((time_t *)vparam)); return 1; @@ -479,17 +472,24 @@ void lease_update_dns(int force) cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires); } } -#endif if (lease->fqdn) cache_add_dhcp_entry(lease->fqdn, prot, - prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr, + prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6, lease->expires); if (!option_bool(OPT_DHCP_FQDN) && lease->hostname) cache_add_dhcp_entry(lease->hostname, prot, - prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr, + prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6, lease->expires); + +#else + if (lease->fqdn) + cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires); + + if (!option_bool(OPT_DHCP_FQDN) && lease->hostname) + cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires); +#endif } dns_dirty = 0; @@ -584,10 +584,10 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len, for (lease = leases; lease; lease = lease->next) { - if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) + if (!(lease->flags & lease_type) || lease->iaid != iaid) continue; - if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0) + if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr)) continue; if ((clid_len != lease->clid_len || @@ -624,7 +624,7 @@ struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_typ if (lease->flags & LEASE_USED) continue; - if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) + if (!(lease->flags & lease_type) || lease->iaid != iaid) continue; if ((clid_len != lease->clid_len || @@ -646,8 +646,8 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add if (!(lease->flags & (LEASE_TA | LEASE_NA))) continue; - if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) && - (prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr)) + if (is_same_net6(&lease->addr6, net, prefix) && + (prefix == 128 || addr6part(&lease->addr6) == addr)) return lease; } @@ -666,11 +666,11 @@ u64 lease_find_max_addr6(struct dhcp_context *context) if (!(lease->flags & (LEASE_TA | LEASE_NA))) continue; - if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) && - addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) && - addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) && - addr6part((struct in6_addr *)lease->hwaddr) > addr) - addr = addr6part((struct in6_addr *)lease->hwaddr); + if (is_same_net6(&lease->addr6, &context->start6, 64) && + addr6part(&lease->addr6) > addr6part(&context->start6) && + addr6part(&lease->addr6) <= addr6part(&context->end6) && + addr6part(&lease->addr6) > addr) + addr = addr6part(&lease->addr6); } return addr; @@ -712,6 +712,7 @@ static struct dhcp_lease *lease_allocate(void) #ifdef HAVE_BROKEN_RTC lease->length = 0xffffffff; /* illegal value */ #endif + lease->hwaddr_len = 256; /* illegal value */ lease->next = leases; leases = lease; @@ -725,11 +726,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr) { struct dhcp_lease *lease = lease_allocate(); if (lease) - { - lease->addr = addr; - lease->hwaddr_len = 256; /* illegal value */ - } - + lease->addr = addr; + return lease; } @@ -740,8 +738,9 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type) if (lease) { - memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ; + lease->addr6 = *addrp; lease->flags |= lease_type; + lease->iaid = 0; } return lease; @@ -778,6 +777,17 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now) #endif } +#ifdef HAVE_DHCP6 +void lease_set_iaid(struct dhcp_lease *lease, int iaid) +{ + if (lease->iaid != iaid) + { + lease->iaid = iaid; + lease->flags |= LEASE_CHANGED; + } +} +#endif + void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force) @@ -788,6 +798,7 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, #endif (void)force; + (void)now; if (hw_len != lease->hwaddr_len || hw_type != lease->hwaddr_type || @@ -799,9 +810,6 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, lease->hwaddr_type = hw_type; lease->flags |= LEASE_CHANGED; file_dirty = 1; /* run script on change */ -#ifdef HAVE_DHCP6 - change = 1; -#endif } /* only update clid when one is available, stops packets @@ -959,6 +967,8 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *do void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now) { + (void)now; + if (lease->last_interface == interface) return; @@ -987,6 +997,8 @@ int do_script_run(time_t now) { struct dhcp_lease *lease; + (void)now; + #ifdef HAVE_DBUS /* If we're going to be sending DBus signals, but the connection is not yet up, delay everything until it is. */ diff --git a/release/src/router/dnsmasq/src/netlink.c b/release/src/router/dnsmasq/src/netlink.c index 2bcaf0185d..d093988d75 100644 --- a/release/src/router/dnsmasq/src/netlink.c +++ b/release/src/router/dnsmasq/src/netlink.c @@ -402,6 +402,8 @@ static int nl_async(struct nlmsghdr *h) static void nl_newaddress(time_t now) { + (void)now; + if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra) enumerate_interfaces(0); diff --git a/release/src/router/dnsmasq/src/network.c b/release/src/router/dnsmasq/src/network.c index 8e62538887..fc0346e146 100644 --- a/release/src/router/dnsmasq/src/network.c +++ b/release/src/router/dnsmasq/src/network.c @@ -115,7 +115,9 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth) int ret = 1, match_addr = 0; /* Note: have to check all and not bail out early, so that we set the - "used" flags. */ + "used" flags. + + May be called with family == AF_LOCALto check interface by name only. */ if (auth) *auth = 0; @@ -241,7 +243,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label, int tftp_ok = !!option_bool(OPT_TFTP); int dhcp_ok = 1; int auth_dns = 0; -#ifdef HAVE_DHCP +#if defined(HAVE_DHCP) || defined(HAVE_TFTP) struct iname *tmp; #endif @@ -360,6 +362,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label, #endif +#ifdef HAVE_TFTP if (daemon->tftp_interfaces) { /* dedicated tftp interface list */ @@ -368,6 +371,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label, if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) tftp_ok = 1; } +#endif /* add to list */ if ((iface = whine_malloc(sizeof(struct irec)))) @@ -705,6 +709,8 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in struct listener *l = NULL; int fd = -1, tcpfd = -1, tftpfd = -1; + (void)do_tftp; + if (daemon->port != 0) { fd = make_sock(addr, SOCK_DGRAM, dienow); diff --git a/release/src/router/dnsmasq/src/radv-protocol.h b/release/src/router/dnsmasq/src/radv-protocol.h index 1f0f88aeb6..8d5b153958 100644 --- a/release/src/router/dnsmasq/src/radv-protocol.h +++ b/release/src/router/dnsmasq/src/radv-protocol.h @@ -33,6 +33,13 @@ struct ra_packet { u32 retrans_time; }; +struct neigh_packet { + u8 type, code; + u16 checksum; + u16 reserved; + struct in6_addr target; +}; + struct prefix_opt { u8 type, len, prefix_len, flags; u32 valid_lifetime, preferred_lifetime, reserved; diff --git a/release/src/router/dnsmasq/src/radv.c b/release/src/router/dnsmasq/src/radv.c index 2a8cd3d406..3b499e45cd 100644 --- a/release/src/router/dnsmasq/src/radv.c +++ b/release/src/router/dnsmasq/src/radv.c @@ -70,10 +70,15 @@ void ra_init(time_t now) if ((context->flags & CONTEXT_RA_NAME)) break; + /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */ + ICMP6_FILTER_SETBLOCKALL(&filter); - ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); - if (context) - ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter); + if (daemon->doing_ra) + { + ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); + if (context) + ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter); + } if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 || getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) || @@ -89,7 +94,8 @@ void ra_init(time_t now) daemon->icmp6fd = fd; - ra_start_unsolicted(now, NULL); + if (daemon->doing_ra) + ra_start_unsolicted(now, NULL); } void ra_start_unsolicted(time_t now, struct dhcp_context *context) @@ -191,7 +197,6 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de { struct ra_packet *ra; struct ra_param parm; - struct ifreq ifr; struct sockaddr_in6 addr; struct dhcp_context *context, *tmp, **up; struct dhcp_netid iface_id; diff --git a/release/src/router/dnsmasq/src/rfc3315.c b/release/src/router/dnsmasq/src/rfc3315.c index 8537564ac3..12d6aca4b3 100644 --- a/release/src/router/dnsmasq/src/rfc3315.c +++ b/release/src/router/dnsmasq/src/rfc3315.c @@ -24,23 +24,23 @@ struct state { int clid_len, iaid, ia_type, interface, hostname_auth, lease_allocate; char *client_hostname, *hostname, *domain, *send_domain; struct dhcp_context *context; - struct in6_addr *link_address; + struct in6_addr *link_address, *fallback; unsigned int xid, fqdn_flags; char *iface_name; void *packet_options, *end; struct dhcp_netid *tags, *context_tags; + unsigned char mac[DHCP_CHADDR_MAX]; + unsigned int mac_len, mac_type; #ifdef OPTION6_PREFIX_CLASS struct prefix_class *send_prefix_class; #endif }; -static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context, - 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, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now); +static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, + struct in6_addr *client_addr, int is_unicast, time_t now); +static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now); static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts); static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string); - static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize); static void *opt6_next(void *opts, void *end); static unsigned int opt6_uint(unsigned char *opt, int offset, int size); @@ -51,14 +51,14 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz); #ifdef OPTION6_PREFIX_CLASS static struct prefix_class *prefix_class_from_context(struct dhcp_context *context); #endif -static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr); +static void mark_context_used(struct state *state, struct in6_addr *addr); static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr); static int check_address(struct state *state, struct in6_addr *addr); static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option, unsigned int *min_time, struct in6_addr *addr, time_t now); static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now); static int add_local_addrs(struct dhcp_context *context); -static struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context, int do_refresh); +static struct dhcp_netid *add_options(struct state *state, int do_refresh); static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep, unsigned int *preferred_timep, unsigned int lease_time); @@ -68,11 +68,11 @@ static void calculate_times(struct dhcp_context *context, unsigned int *min_time unsigned short 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 in6_addr *fallback, size_t sz, struct in6_addr *client_addr, time_t now) { - struct dhcp_netid *relay_tags = NULL; struct dhcp_vendor *vendor; int msg_type; + struct state state; if (sz <= 4) return 0; @@ -84,16 +84,24 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if vendor->netid.next = &vendor->netid; save_counter(0); - - if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, fallback, daemon->dhcp_packet.iov_base, sz, is_unicast, now)) + state.context = context; + state.interface = interface; + state.iface_name = iface_name; + state.fallback = fallback; + state.mac_len = 0; + state.tags = NULL; + state.link_address = NULL; + + if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr, + IN6_IS_ADDR_MULTICAST(client_addr), now)) return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT; 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, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now) +static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, + struct in6_addr *client_addr, int is_unicast, time_t now) { void *end = inbuff + sz; void *opts = inbuff + 34; @@ -108,45 +116,50 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid ** /* if link_address != NULL if points to the link address field of the innermost nested RELAYFORW message, which is where we find the address of the network on which we can allocate an address. - Recalculate the available contexts using that information. */ + Recalculate the available contexts using that information. + + link_address == NULL means there's no relay in use, so we try and find the client's + MAC address from the local ND cache. */ - if (link_address) + if (!state->link_address) + get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type); + else { struct dhcp_context *c; - context = NULL; + state->context = NULL; - if (!IN6_IS_ADDR_LOOPBACK(link_address) && - !IN6_IS_ADDR_LINKLOCAL(link_address) && - !IN6_IS_ADDR_MULTICAST(link_address)) + if (!IN6_IS_ADDR_LOOPBACK(state->link_address) && + !IN6_IS_ADDR_LINKLOCAL(state->link_address) && + !IN6_IS_ADDR_MULTICAST(state->link_address)) for (c = daemon->dhcp6; c; c = c->next) if ((c->flags & CONTEXT_DHCP) && !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && - is_same_net6(link_address, &c->start6, c->prefix) && - is_same_net6(link_address, &c->end6, c->prefix)) + is_same_net6(state->link_address, &c->start6, c->prefix) && + is_same_net6(state->link_address, &c->end6, c->prefix)) { c->preferred = c->valid = 0xffffffff; - c->current = context; - context = c; + c->current = state->context; + state->context = c; } - if (!context) + if (!state->context) { - inet_ntop(AF_INET6, link_address, daemon->addrbuff, ADDRSTRLEN); + inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN); my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCPv6 request from relay at %s"), daemon->addrbuff); return 0; } } - - if (!context) + + if (!state->context) { my_syslog(MS_DHCP | LOG_WARNING, - _("no address range available for DHCPv6 request via %s"), iface_name); + _("no address range available for DHCPv6 request via %s"), state->iface_name); return 0; } - return dhcp6_no_relay(msg_type, link_address, *relay_tagsp, context, interface, iface_name, fallback, inbuff, sz, is_unicast, now); + return dhcp6_no_relay(state, msg_type, inbuff, sz, is_unicast, now); } /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option @@ -176,26 +189,35 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid ** memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 && vendor->netid.next != &vendor->netid) { - vendor->netid.next = *relay_tagsp; - *relay_tagsp = &vendor->netid; + vendor->netid.next = state->tags; + state->tags = &vendor->netid; break; } } + /* RFC-6939 */ + if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3))) + { + state->mac_type = opt6_uint(opt, 0, 2); + state->mac_len = opt6_len(opt) - 2; + memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len); + } + for (opt = opts; opt; opt = opt6_next(opt, end)) { int o = new_opt6(opt6_type(opt)); if (opt6_type(opt) == OPTION6_RELAY_MSG) { - struct in6_addr link_address; + struct in6_addr align; /* the packet data is unaligned, copy to aligned storage */ - memcpy(&link_address, inbuff + 2, IN6ADDRSZ); - /* Not, zero is_unicast since that is now known to refer to the + memcpy(&align, inbuff + 2, IN6ADDRSZ); + state->link_address = &align; + /* 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, fallback, opt6_ptr(opt, 0), opt6_len(opt), 0, now)) + if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now)) return 0; } - else + else if (opt6_type(opt) != OPTION6_CLIENT_MAC) put_opt6(opt6_ptr(opt, 0), opt6_len(opt)); end_opt6(o); } @@ -203,8 +225,7 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid ** return 1; } -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, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now) +static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now) { void *opt; int i, o, o1, start_opts; @@ -215,55 +236,50 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh unsigned char *outmsgtypep; struct dhcp_vendor *vendor; struct dhcp_context *context_tmp; + struct dhcp_mac *mac_opt; unsigned int ignore = 0; - struct state state; #ifdef OPTION6_PREFIX_CLASS struct prefix_class *p; int dump_all_prefix_classes = 0; #endif - state.packet_options = inbuff + 4; - state.end = inbuff + sz; - state.clid = NULL; - state.clid_len = 0; - state.lease_allocate = 0; - state.context_tags = NULL; - state.tags = tags; - state.link_address = link_address; - state.interface = interface; - state.domain = NULL; - state.send_domain = NULL; - state.context = context; - state.hostname_auth = 0; - state.hostname = NULL; - state.client_hostname = NULL; - state.iface_name = iface_name; - state.fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */ + state->packet_options = inbuff + 4; + state->end = inbuff + sz; + state->clid = NULL; + state->clid_len = 0; + state->lease_allocate = 0; + state->context_tags = NULL; + state->domain = NULL; + state->send_domain = NULL; + state->hostname_auth = 0; + state->hostname = NULL; + state->client_hostname = NULL; + state->fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */ #ifdef OPTION6_PREFIX_CLASS - state.send_prefix_class = NULL; + state->send_prefix_class = NULL; #endif /* set tag with name == interface */ - iface_id.net = iface_name; - iface_id.next = state.tags; - state.tags = &iface_id; + iface_id.net = state->iface_name; + iface_id.next = state->tags; + state->tags = &iface_id; /* set tag "dhcpv6" */ v6_id.net = "dhcpv6"; - v6_id.next = state.tags; - state.tags = &v6_id; + v6_id.next = state->tags; + state->tags = &v6_id; /* copy over transaction-id, and save pointer to message type */ if (!(outmsgtypep = put_opt6(inbuff, 4))) return 0; start_opts = save_counter(-1); - state.xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16; + state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16; /* We're going to be linking tags from all context we use. mark them as unused so we don't link one twice and break the list */ - for (context_tmp = context; context_tmp; context_tmp = context_tmp->current) + for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current) { - context->netid.next = &context->netid; + context_tmp->netid.next = &context_tmp->netid; if (option_bool(OPT_LOG_OPTS)) { @@ -271,19 +287,19 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN); if (context_tmp->flags & (CONTEXT_STATIC)) my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"), - state.xid, daemon->dhcp_buff, context_tmp->prefix); + state->xid, daemon->dhcp_buff, context_tmp->prefix); else my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"), - state.xid, daemon->dhcp_buff, daemon->dhcp_buff2); + state->xid, daemon->dhcp_buff, daemon->dhcp_buff2); } } - if ((opt = opt6_find(state.packet_options, state.end, OPTION6_CLIENT_ID, 1))) + if ((opt = opt6_find(state->packet_options, state->end, OPTION6_CLIENT_ID, 1))) { - state.clid = opt6_ptr(opt, 0); - state.clid_len = opt6_len(opt); + state->clid = opt6_ptr(opt, 0); + state->clid_len = opt6_len(opt); o = new_opt6(OPTION6_CLIENT_ID); - put_opt6(state.clid, state.clid_len); + put_opt6(state->clid, state->clid_len); end_opt6(o); } else if (msg_type != DHCP6IREQ) @@ -291,7 +307,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh /* server-id must match except for SOLICIT and CONFIRM messages */ if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && - (!(opt = opt6_find(state.packet_options, state.end, OPTION6_SERVER_ID, 1)) || + (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) || opt6_len(opt) != daemon->duid_len || memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0)) return 0; @@ -323,7 +339,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh else continue; - if ((opt = opt6_find(state.packet_options, state.end, mopt, 2))) + if ((opt = opt6_find(state->packet_options, state->end, mopt, 2))) { void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt)); int offset = 0; @@ -343,15 +359,15 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh for (i = 0; i <= (opt6_len(enc_opt) - vendor->len); i++) if (memcmp(vendor->data, opt6_ptr(enc_opt, i), vendor->len) == 0) { - vendor->netid.next = state.tags; - state.tags = &vendor->netid; + vendor->netid.next = state->tags; + state->tags = &vendor->netid; break; } } } - if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state.packet_options, state.end, OPTION6_VENDOR_CLASS, 4))) - my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state.xid, opt6_uint(opt, 0, 4)); + if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4))) + my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4)); /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match. Otherwise assume the option is an array, and look for a matching element. @@ -363,9 +379,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh if (opt_cfg->flags & DHOPT_RFC3925) { - for (opt = opt6_find(state.packet_options, state.end, OPTION6_VENDOR_OPTS, 4); + for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4); opt; - opt = opt6_find(opt6_next(opt, state.end), state.end, OPTION6_VENDOR_OPTS, 4)) + opt = opt6_find(opt6_next(opt, state->end), state->end, OPTION6_VENDOR_OPTS, 4)) { void *vopt; void *vend = opt6_ptr(opt, opt6_len(opt)); @@ -381,7 +397,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh } else { - if (!(opt = opt6_find(state.packet_options, state.end, opt_cfg->opt, 1))) + if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1))) continue; match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt)); @@ -389,23 +405,41 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh if (match) { - opt_cfg->netid->next = state.tags; - state.tags = opt_cfg->netid; + opt_cfg->netid->next = state->tags; + state->tags = opt_cfg->netid; } } + + if (state->mac_len != 0) + { + if (option_bool(OPT_LOG_OPTS)) + { + print_mac(daemon->dhcp_buff, state->mac, state->mac_len); + my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff); + } + + for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next) + if ((unsigned)mac_opt->hwaddr_len == state->mac_len && + ((unsigned)mac_opt->hwaddr_type == state->mac_type || mac_opt->hwaddr_type == 0) && + memcmp_masked(mac_opt->hwaddr, state->mac, state->mac_len, mac_opt->mask)) + { + mac_opt->netid.next = state->tags; + state->tags = &mac_opt->netid; + } + } - if ((opt = opt6_find(state.packet_options, state.end, OPTION6_FQDN, 1))) + if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1))) { /* RFC4704 refers */ int len = opt6_len(opt) - 1; - state.fqdn_flags = opt6_uint(opt, 0, 1); + state->fqdn_flags = opt6_uint(opt, 0, 1); /* Always force update, since the client has no way to do it itself. */ - if (!option_bool(OPT_FQDN_UPDATE) && !(state.fqdn_flags & 0x01)) - state.fqdn_flags |= 0x03; + if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01)) + state->fqdn_flags |= 0x03; - state.fqdn_flags &= ~0x04; + state->fqdn_flags &= ~0x04; if (len != 0 && len < 255) { @@ -427,36 +461,36 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh if (legal_hostname(daemon->dhcp_buff)) { - state.client_hostname = daemon->dhcp_buff; + state->client_hostname = daemon->dhcp_buff; if (option_bool(OPT_LOG_OPTS)) - my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state.xid, state.client_hostname); + my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname); } } } - if (state.clid) + if (state->clid) { - config = find_config6(daemon->dhcp_conf, context, state.clid, state.clid_len, NULL); + config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL); if (have_config(config, CONFIG_NAME)) { - state.hostname = config->hostname; - state.domain = config->domain; - state.hostname_auth = 1; + state->hostname = config->hostname; + state->domain = config->domain; + state->hostname_auth = 1; } - else if (state.client_hostname) + else if (state->client_hostname) { - state.domain = strip_hostname(state.client_hostname); + state->domain = strip_hostname(state->client_hostname); - if (strlen(state.client_hostname) != 0) + if (strlen(state->client_hostname) != 0) { - state.hostname = state.client_hostname; + state->hostname = state->client_hostname; if (!config) { /* Search again now we have a hostname. Only accept configs without CLID here, (it won't match) to avoid impersonation by name. */ - struct dhcp_config *new = find_config6(daemon->dhcp_conf, context, NULL, 0, state.hostname); + struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname); if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) config = new; } @@ -470,14 +504,14 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh for (list = config->netid; list; list = list->next) { - list->list->next = state.tags; - state.tags = list->list; + list->list->next = state->tags; + state->tags = list->list; } /* set "known" tag for known hosts */ known_id.net = "known"; - known_id.next = state.tags; - state.tags = &known_id; + known_id.next = state->tags; + state->tags = &known_id; if (have_config(config, CONFIG_DISABLE)) ignore = 1; @@ -489,7 +523,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh { void *oro; - if ((oro = opt6_find(state.packet_options, state.end, OPTION6_ORO, 0))) + if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0))) for (i = 0; i < opt6_len(oro) - 1; i += 2) if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS) { @@ -502,13 +536,13 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh Not done for SOLICIT as we add them one-at-time. */ for (p = daemon->prefix_classes; p ; p = p->next) { - p->tag.next = state.tags; - state.tags = &p->tag; + p->tag.next = state->tags; + state->tags = &p->tag; } } #endif - tagif = run_tag_if(state.tags); + tagif = run_tag_if(state->tags); /* if all the netids in the ignore list are present, ignore this client */ if (daemon->dhcp_ignore) @@ -521,7 +555,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh } /* if all the netids in the ignore_name list are present, ignore client-supplied name */ - if (!state.hostname_auth) + if (!state->hostname_auth) { struct dhcp_netid_list *id_list; @@ -529,7 +563,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh if ((!id_list->list) || match_netid(id_list->list, tagif, 0)) break; if (id_list) - state.hostname = NULL; + state->hostname = NULL; } @@ -537,29 +571,29 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh { default: return 0; - - + + case DHCP6SOLICIT: { int address_assigned = 0; /* tags without all prefix-class tags */ - struct dhcp_netid *solicit_tags = tagif; + struct dhcp_netid *solicit_tags; struct dhcp_context *c; - + *outmsgtypep = DHCP6ADVERTISE; - - if (opt6_find(state.packet_options, state.end, OPTION6_RAPID_COMMIT, 0)) + + if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0)) { *outmsgtypep = DHCP6REPLY; - state.lease_allocate = 1; + state->lease_allocate = 1; o = new_opt6(OPTION6_RAPID_COMMIT); end_opt6(o); } - log6_packet(&state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL); + log6_packet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL); request_no_address: - + solicit_tags = tagif; #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif @@ -570,10 +604,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh lease6_reset(); /* Can use configured address max once per prefix */ - for (c = context; c; c = c->current) + for (c = state->context; c; c = c->current) c->flags &= ~CONTEXT_CONF_USED; - for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end)) + for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) { void *ia_option, *ia_end; unsigned int min_time = 0xffffffff; @@ -587,15 +621,15 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh struct in6_addr *req_addr; struct in6_addr addr; - if (!check_ia(&state, opt, &ia_end, &ia_option)) + if (!check_ia(state, opt, &ia_end, &ia_option)) continue; /* reset USED bits in contexts - one address per prefix per IAID */ - for (c = context; c; c = c->current) + for (c = state->context; c; c = c->current) c->flags &= ~CONTEXT_USED; #ifdef OPTION6_PREFIX_CLASS - if (daemon->prefix_classes && state.ia_type == OPTION6_IA_NA) + if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA) { void *prefix_opt; int prefix_class; @@ -619,10 +653,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh else { /* add tag to list, and exclude undecorated dhcp-ranges */ - p->tag.next = state.tags; + p->tag.next = state->tags; solicit_tags = run_tag_if(&p->tag); plain_range = 0; - state.send_prefix_class = p; + state->send_prefix_class = p; } } else @@ -638,103 +672,103 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh if (p) { plain_range = 0; - state.send_prefix_class = p; + state->send_prefix_class = p; } } if (p && option_bool(OPT_LOG_OPTS)) - my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state.xid, p->class, p->tag.net); + my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state->xid, p->class, p->tag.net); } } #endif - o = build_ia(&state, &t1cntr); + o = build_ia(state, &t1cntr); for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { req_addr = opt6_ptr(ia_option, 0); - if ((c = address6_valid(context, req_addr, solicit_tags, plain_range))) + if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range))) { lease_time = c->lease_time; /* If the client asks for an address on the same network as a configured address, offer the configured address instead, to make moving to newly-configured addresses automatic. */ - if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(&state, &addr)) + if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr)) { req_addr = &addr; mark_config_used(c, &addr); if (have_config(config, CONFIG_TIME)) lease_time = config->lease_time; } - else if (!(c = address6_available(context, req_addr, solicit_tags, plain_range))) + else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range))) continue; /* not an address we're allowed */ - else if (!check_address(&state, req_addr)) + else if (!check_address(state, req_addr)) continue; /* address leased elsewhere */ /* add address to output packet */ #ifdef OPTION6_PREFIX_CLASS - if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) - state.send_prefix_class = prefix_class_from_context(c); + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); #endif - add_address(&state, c, lease_time, ia_option, &min_time, req_addr, now); - mark_context_used(&state, context, req_addr); - get_context_tag(&state, c); + add_address(state, c, lease_time, ia_option, &min_time, req_addr, now); + mark_context_used(state, req_addr); + get_context_tag(state, c); address_assigned = 1; } } /* Suggest configured address(es) */ - for (c = context; c; c = c->current) + for (c = state->context; c; c = c->current) if (!(c->flags & CONTEXT_CONF_USED) && match_netid(c->filter, solicit_tags, plain_range) && config_valid(config, c, &addr) && - check_address(&state, &addr)) + check_address(state, &addr)) { - mark_config_used(context, &addr); + mark_config_used(state->context, &addr); if (have_config(config, CONFIG_TIME)) lease_time = config->lease_time; else lease_time = c->lease_time; /* add address to output packet */ #ifdef OPTION6_PREFIX_CLASS - if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) - state.send_prefix_class = prefix_class_from_context(c); + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); #endif - add_address(&state, c, lease_time, NULL, &min_time, &addr, now); - mark_context_used(&state, context, &addr); - get_context_tag(&state, c); + add_address(state, c, lease_time, NULL, &min_time, &addr, now); + mark_context_used(state, &addr); + get_context_tag(state, c); address_assigned = 1; } /* return addresses for existing leases */ ltmp = NULL; - while ((ltmp = lease6_find_by_client(ltmp, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.clid, state.clid_len, state.iaid))) + while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid))) { - req_addr = (struct in6_addr *)ltmp->hwaddr; - if ((c = address6_available(context, req_addr, solicit_tags, plain_range))) + req_addr = <mp->addr6; + if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range))) { #ifdef OPTION6_PREFIX_CLASS - if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) - state.send_prefix_class = prefix_class_from_context(c); + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); #endif - add_address(&state, c, c->lease_time, NULL, &min_time, req_addr, now); - mark_context_used(&state, context, req_addr); - get_context_tag(&state, c); + add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now); + mark_context_used(state, req_addr); + get_context_tag(state, c); address_assigned = 1; } } /* Return addresses for all valid contexts which don't yet have one */ - while ((c = address6_allocate(context, state.clid, state.clid_len, state.iaid, ia_counter, solicit_tags, plain_range, &addr))) + while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->iaid, ia_counter, solicit_tags, plain_range, &addr))) { #ifdef OPTION6_PREFIX_CLASS - if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) - state.send_prefix_class = prefix_class_from_context(c); + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); #endif - add_address(&state, c, c->lease_time, NULL, &min_time, &addr, now); - mark_context_used(&state, context, &addr); - get_context_tag(&state, c); + add_address(state, c, c->lease_time, NULL, &min_time, &addr, now); + mark_context_used(state, &addr); + get_context_tag(state, c); address_assigned = 1; } @@ -754,7 +788,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh o = new_opt6(OPTION6_PREFERENCE); put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0); end_opt6(o); - tagif = add_options(&state, fallback, context, 0); + tagif = add_options(state, 0); } else { @@ -766,7 +800,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPADVERTISE", NULL, _("no addresses available")); + log6_packet(state, "DHCPADVERTISE", NULL, _("no addresses available")); } break; @@ -779,23 +813,23 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh /* set reply message type */ *outmsgtypep = DHCP6REPLY; - state.lease_allocate = 1; + state->lease_allocate = 1; #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL); + log6_packet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL); if (ignore) return 0; - for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end)) + for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) { void *ia_option, *ia_end; unsigned int min_time = 0xffffffff; int t1cntr; - if (!check_ia(&state, opt, &ia_end, &ia_option)) + if (!check_ia(state, opt, &ia_end, &ia_option)) continue; if (!ia_option) @@ -806,7 +840,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh goto request_no_address; } - o = build_ia(&state, &t1cntr); + o = build_ia(state, &t1cntr); for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { @@ -816,10 +850,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh struct in6_addr addr; int config_ok = 0; - if ((c = address6_valid(context, req_addr, tagif, 1))) + if ((c = address6_valid(state->context, req_addr, tagif, 1))) config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr); - if ((dynamic = address6_available(context, req_addr, tagif, 1)) || c) + if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c) { if (!dynamic && !config_ok) { @@ -829,7 +863,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh put_opt6_string(_("address unavailable")); end_opt6(o1); } - else if (!check_address(&state, req_addr)) + else if (!check_address(state, req_addr)) { /* Address leased to another DUID/IAID */ o1 = new_opt6(OPTION6_STATUS_CODE); @@ -848,11 +882,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh lease_time = config->lease_time; #ifdef OPTION6_PREFIX_CLASS - if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA) - state.send_prefix_class = prefix_class_from_context(c); + if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) + state->send_prefix_class = prefix_class_from_context(c); #endif - add_address(&state, dynamic, lease_time, ia_option, &min_time, req_addr, now); - get_context_tag(&state, dynamic); + add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now); + get_context_tag(state, dynamic); address_assigned = 1; } } @@ -887,10 +921,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPREPLY", NULL, _("no addresses available")); + log6_packet(state, "DHCPREPLY", NULL, _("no addresses available")); } - tagif = add_options(&state, fallback, context, 0); + tagif = add_options(state, 0); break; } @@ -903,18 +937,18 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPRENEW", NULL, NULL); + log6_packet(state, "DHCPRENEW", NULL, NULL); - for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end)) + for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) { void *ia_option, *ia_end; unsigned int min_time = 0xffffffff; int t1cntr, iacntr; - if (!check_ia(&state, opt, &ia_end, &ia_option)) + if (!check_ia(state, opt, &ia_end, &ia_option)) continue; - o = build_ia(&state, &t1cntr); + o = build_ia(state, &t1cntr); iacntr = save_counter(-1); for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) @@ -926,9 +960,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh char *message = NULL; struct dhcp_context *this_context; - if (!(lease = lease6_find(state.clid, state.clid_len, - state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, - state.iaid, req_addr))) + if (!(lease = lease6_find(state->clid, state->clid_len, + state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, + state->iaid, req_addr))) { /* If the server cannot find a client entry for the IA the server returns the IA containing no addresses with a Status Code option set @@ -939,7 +973,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPREPLY", req_addr, _("lease not found")); + log6_packet(state, "DHCPREPLY", req_addr, _("lease not found")); o1 = new_opt6(OPTION6_STATUS_CODE); put_opt6_short(DHCP6NOBINDING); @@ -951,13 +985,13 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh } - if ((this_context = address6_available(context, req_addr, tagif, 1)) || - (this_context = address6_valid(context, req_addr, tagif, 1))) + if ((this_context = address6_available(state->context, req_addr, tagif, 1)) || + (this_context = address6_valid(state->context, req_addr, tagif, 1))) { struct in6_addr addr; unsigned int lease_time; - get_context_tag(&state, this_context); + get_context_tag(state, this_context); if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME)) lease_time = config->lease_time; @@ -967,13 +1001,16 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time); lease_set_expires(lease, valid_time, now); - if (state.ia_type == OPTION6_IA_NA && state.hostname) + /* Update MAC record in case it's new information. */ + if (state->mac_len != 0) + lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0); + if (state->ia_type == OPTION6_IA_NA && state->hostname) { char *addr_domain = get_domain6(req_addr); - if (!state.send_domain) - state.send_domain = addr_domain; - lease_set_hostname(lease, state.hostname, state.hostname_auth, addr_domain, state.domain); - message = state.hostname; + if (!state->send_domain) + state->send_domain = addr_domain; + lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain); + message = state->hostname; } @@ -989,7 +1026,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPREPLY", req_addr, message); + log6_packet(state, "DHCPREPLY", req_addr, message); o1 = new_opt6(OPTION6_IAADDR); put_opt6(req_addr, sizeof(*req_addr)); @@ -1002,7 +1039,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh end_opt6(o); } - tagif = add_options(&state, fallback, context, 0); + tagif = add_options(state, 0); break; } @@ -1015,19 +1052,19 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPCONFIRM", NULL, NULL); + log6_packet(state, "DHCPCONFIRM", NULL, NULL); - for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end)) + for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) { void *ia_option, *ia_end; - for (check_ia(&state, opt, &ia_end, &ia_option); + for (check_ia(state, opt, &ia_end, &ia_option); ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { struct in6_addr *req_addr = opt6_ptr(ia_option, 0); - if (!address6_available(context, req_addr, tagif, 1)) + if (!address6_available(state->context, req_addr, tagif, 1)) { o1 = new_opt6(OPTION6_STATUS_CODE); put_opt6_short(DHCP6NOTONLINK); @@ -1039,7 +1076,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPREPLY", req_addr, state.hostname); + log6_packet(state, "DHCPREPLY", req_addr, state->hostname); } } @@ -1054,28 +1091,28 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh { /* We can't discriminate contexts based on address, as we don't know it. If there is only one possible context, we can use its tags */ - if (context && context->netid.net && !context->current) + if (state->context && state->context->netid.net && !state->context->current) { - context->netid.next = NULL; - state.context_tags = &context->netid; + state->context->netid.next = NULL; + state->context_tags = &state->context->netid; } /* Similarly, we can't determine domain from address, but if the FQDN is given in --dhcp-host, we can use that, and failing that we can use the unqualified configured domain, if any. */ - if (state.hostname_auth) - state.send_domain = state.domain; + if (state->hostname_auth) + state->send_domain = state->domain; else - state.send_domain = get_domain6(NULL); + state->send_domain = get_domain6(NULL); #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state.hostname); + log6_packet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname); if (ignore) return 0; *outmsgtypep = DHCP6REPLY; - tagif = add_options(&state, fallback, context, 1); + tagif = add_options(state, 1); break; } @@ -1088,29 +1125,29 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPRELEASE", NULL, NULL); + log6_packet(state, "DHCPRELEASE", NULL, NULL); - for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end)) + for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) { void *ia_option, *ia_end; int made_ia = 0; - for (check_ia(&state, opt, &ia_end, &ia_option); + for (check_ia(state, opt, &ia_end, &ia_option); ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { struct dhcp_lease *lease; - if ((lease = lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, - state.iaid, opt6_ptr(ia_option, 0)))) + if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, + state->iaid, opt6_ptr(ia_option, 0)))) lease_prune(lease, now); else { if (!made_ia) { - o = new_opt6(state.ia_type); - put_opt6_long(state.iaid); - if (state.ia_type == OPTION6_IA_NA) + o = new_opt6(state->ia_type); + put_opt6_long(state->iaid); + if (state->ia_type == OPTION6_IA_NA) { put_opt6_long(0); put_opt6_long(0); @@ -1153,14 +1190,14 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh #ifdef HAVE_QUIET_DHCP if (!option_bool(OPT_QUIET_DHCP6)) #endif - log6_packet(&state, "DHCPDECLINE", NULL, NULL); + log6_packet(state, "DHCPDECLINE", NULL, NULL); - for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end)) + for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end)) { void *ia_option, *ia_end; int made_ia = 0; - for (check_ia(&state, opt, &ia_end, &ia_option); + for (check_ia(state, opt, &ia_end, &ia_option); ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { @@ -1178,19 +1215,19 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh } else /* make sure this host gets a different address next time. */ - for (; context; context = context->current) - context->addr_epoch++; + for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current) + context_tmp->addr_epoch++; - if ((lease = lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, - state.iaid, opt6_ptr(ia_option, 0)))) + if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, + state->iaid, opt6_ptr(ia_option, 0)))) lease_prune(lease, now); else { if (!made_ia) { - o = new_opt6(state.ia_type); - put_opt6_long(state.iaid); - if (state.ia_type == OPTION6_IA_NA) + o = new_opt6(state->ia_type); + put_opt6_long(state->iaid); + if (state->ia_type == OPTION6_IA_NA) { put_opt6_long(0); put_opt6_long(0); @@ -1222,19 +1259,14 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh } - log_tags(tagif, state.xid); - - if (option_bool(OPT_LOG_OPTS)) - log6_opts(0, state.xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1)); + log_tags(tagif, state->xid); + log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1)); return 1; } -static struct dhcp_netid *add_options(struct state *state, - struct in6_addr *fallback, - struct dhcp_context *context, - int do_refresh) +static struct dhcp_netid *add_options(struct state *state, int do_refresh) { void *oro; /* filter options based on tags, those we want get DHOPT_TAGOK bit set */ @@ -1282,8 +1314,8 @@ static struct dhcp_netid *add_options(struct state *state, /* zero means "self" (but not in vendorclass options.) */ if (IN6_IS_ADDR_UNSPECIFIED(a)) { - if (!add_local_addrs(context)) - put_opt6(fallback, IN6ADDRSZ); + if (!add_local_addrs(state->context)) + put_opt6(state->fallback, IN6ADDRSZ); } else put_opt6(a, IN6ADDRSZ); @@ -1297,12 +1329,12 @@ static struct dhcp_netid *add_options(struct state *state, if (daemon->port == NAMESERVER_PORT && !done_dns) { o = new_opt6(OPTION6_DNS_SERVER); - if (!add_local_addrs(context)) - put_opt6(fallback, IN6ADDRSZ); + if (!add_local_addrs(state->context)) + put_opt6(state->fallback, IN6ADDRSZ); end_opt6(o); } - if (context && !done_refresh) + if (state->context && !done_refresh) { struct dhcp_context *c; unsigned int lease_time = 0xffffffff; @@ -1310,7 +1342,7 @@ static struct dhcp_netid *add_options(struct state *state, /* Find the smallest lease tie of all contexts, subjext to the RFC-4242 stipulation that this must not be less than 600. */ - for (c = context; c; c = c->next) + for (c = state->context; c; c = c->next) if (c->lease_time < lease_time) { if (c->lease_time < 600) @@ -1612,19 +1644,21 @@ static void add_address(struct state *state, struct dhcp_context *context, unsig if (!option_bool(OPT_QUIET_DHCP6)) #endif log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname); + } -static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr) +static void mark_context_used(struct state *state, struct in6_addr *addr) { + struct dhcp_context *context; + /* Mark that we have an address for this prefix. */ #ifdef OPTION6_PREFIX_CLASS - for (; context; context = context->current) + for (context = state->context; context; context = context->current) if (is_same_net6(addr, &context->start6, context->prefix) && (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context))) context->flags |= CONTEXT_USED; #else - (void)state; /* warning */ - for (; context; context = context->current) + for (context = state->context; context; context = context->current) if (is_same_net6(addr, &context->start6, context->prefix)) context->flags |= CONTEXT_USED; #endif @@ -1647,7 +1681,7 @@ static int check_address(struct state *state, struct in6_addr *addr) if (lease->clid_len != state->clid_len || memcmp(lease->clid, state->clid, state->clid_len) != 0 || - lease->hwaddr_type != state->iaid) + lease->iaid != state->iaid) return 0; return 1; @@ -1720,7 +1754,11 @@ static void calculate_times(struct dhcp_context *context, unsigned int *min_time static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now) { struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0); +#ifdef HAVE_SCRIPT struct dhcp_netid *tagif = run_tag_if(state->tags); +#endif + + (void)context; if (!lease) lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA); @@ -1728,7 +1766,8 @@ static void update_leases(struct state *state, struct dhcp_context *context, str if (lease) { lease_set_expires(lease, lease_time, now); - lease_set_hwaddr(lease, NULL, state->clid, 0, state->iaid, state->clid_len, now, 0); + lease_set_iaid(lease, state->iaid); + lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0); lease_set_interface(lease, state->interface, now); if (state->hostname && state->ia_type == OPTION6_IA_NA) { @@ -1815,7 +1854,7 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op void *opt; char *desc = nest ? "nest" : "sent"; - if (start_opts == end_opts) + if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts) return; for (opt = start_opts; opt; opt = opt6_next(opt, end_opts)) @@ -1975,9 +2014,12 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer int msg_type = *inbuff; int hopcount; struct in6_addr multicast; + unsigned int maclen, mactype; + unsigned char mac[DHCP_CHADDR_MAX]; inet_pton(AF_INET6, ALL_SERVERS, &multicast); - + get_client_mac(peer_address, scope_id, mac, &maclen, &mactype); + /* source address == relay address */ from.addr.addr6 = relay->local.addr.addr6; @@ -2001,6 +2043,15 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer header[1] = hopcount; memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ); memcpy(&header[18], peer_address, IN6ADDRSZ); + + /* RFC-6939 */ + if (maclen != 0) + { + o = new_opt6(OPTION6_CLIENT_MAC); + put_opt6_short(mactype); + put_opt6(mac, maclen); + end_opt6(o); + } o = new_opt6(OPTION6_RELAY_MSG); put_opt6(inbuff, sz); diff --git a/release/src/router/dnsmasq/src/tftp.c b/release/src/router/dnsmasq/src/tftp.c index d611dea9df..d752e7125d 100644 --- a/release/src/router/dnsmasq/src/tftp.c +++ b/release/src/router/dnsmasq/src/tftp.c @@ -49,9 +49,7 @@ void tftp_request(struct listener *listen, time_t now) struct iovec iov; struct ifreq ifr; int is_err = 1, if_index = 0, mtu = 0; -#ifdef HAVE_DHCP struct iname *tmp; -#endif struct tftp_transfer *transfer; int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */ #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) -- 2.11.4.GIT