From 653481c6ebf46dcadb5a017085325d956dd04a28 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Tue, 21 Aug 2018 22:06:36 +0100 Subject: [PATCH] Properly deal with unaligned addresses in DHCPv6 packets. Thanks to Vladislav Grishenko for spotting this. (cherry picked from commit 97f876b64c22b2b18412e2e3d8506ee33e42db7c) Conflicts: src/rfc3315.c --- src/rfc1035.c | 2 +- src/rfc3315.c | 101 ++++++++++++++++++++++++++++++++++------------------------ 2 files changed, 61 insertions(+), 42 deletions(-) diff --git a/src/rfc1035.c b/src/rfc1035.c index 6b3bb27..ee5f7a0 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1376,7 +1376,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL, t->class, C_IN, "t", t->len, t->txt)) - anscount ++; + anscount++; } } diff --git a/src/rfc3315.c b/src/rfc3315.c index 21fcd9b..ee1cf17 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -639,9 +639,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ int plain_range = 1; u32 lease_time; struct dhcp_lease *ltmp; - struct in6_addr *req_addr; - struct in6_addr addr; - + struct in6_addr req_addr, addr; + if (!check_ia(state, opt, &ia_end, &ia_option)) continue; @@ -709,9 +708,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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); + /* worry about alignment here. */ + memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); - if ((c = address6_valid(state->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, @@ -719,14 +719,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ addresses automatic. */ if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr)) { - req_addr = &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(state->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 */ @@ -734,8 +734,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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, req_addr); + 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; } @@ -768,15 +768,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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))) { - req_addr = <mp->addr6; - if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range))) + req_addr = ltmp->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); #endif - add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now); - mark_context_used(state, req_addr); + 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; } @@ -892,16 +892,19 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ for (; 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); + struct in6_addr req_addr; struct dhcp_context *dynamic, *c; unsigned int lease_time; struct in6_addr addr; int config_ok = 0; + + /* align. */ + memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); - 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 ((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(state->context, req_addr, tagif, 1)) || c) + if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c) { if (!dynamic && !config_ok) { @@ -911,7 +914,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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); @@ -933,7 +936,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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); + add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now); get_context_tag(state, dynamic); address_assigned = 1; } @@ -996,15 +999,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { struct dhcp_lease *lease = NULL; - struct in6_addr *req_addr = opt6_ptr(ia_option, 0); + struct in6_addr req_addr; unsigned int preferred_time = opt6_uint(ia_option, 16, 4); unsigned int valid_time = opt6_uint(ia_option, 20, 4); char *message = NULL; struct dhcp_context *this_context; + + memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); if (!(lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, - state->iaid, req_addr))) + 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 @@ -1012,7 +1017,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ save_counter(iacntr); t1cntr = 0; - 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); @@ -1024,15 +1029,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ } - if ((this_context = address6_available(state->context, req_addr, tagif, 1)) || - (this_context = address6_valid(state->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); - if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME)) + if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME)) lease_time = config->lease_time; else lease_time = this_context->lease_time; @@ -1045,7 +1050,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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); + 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); @@ -1063,12 +1068,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ } if (message && (message != state->hostname)) - log6_packet(state, "DHCPREPLY", req_addr, message); + log6_packet(state, "DHCPREPLY", &req_addr, message); else - log6_quiet(state, "DHCPREPLY", req_addr, message); + log6_quiet(state, "DHCPREPLY", &req_addr, message); o1 = new_opt6(OPTION6_IAADDR); - put_opt6(req_addr, sizeof(*req_addr)); + put_opt6(&req_addr, sizeof(req_addr)); put_opt6_long(preferred_time); put_opt6_long(valid_time); end_opt6(o1); @@ -1100,19 +1105,23 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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); + struct in6_addr req_addr; + + /* alignment */ + memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); - if (!address6_valid(state->context, req_addr, tagif, 1)) + if (!address6_valid(state->context, &req_addr, tagif, 1)) { o1 = new_opt6(OPTION6_STATUS_CODE); put_opt6_short(DHCP6NOTONLINK); put_opt6_string(_("confirm failed")); end_opt6(o1); + log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed")); return 1; } good_addr = 1; - log6_quiet(state, "DHCPREPLY", req_addr, state->hostname); + log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname); } } @@ -1171,9 +1180,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { struct dhcp_lease *lease; - + struct in6_addr addr; + + /* align */ + memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); 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)))) + state->iaid, &addr))) lease_prune(lease, now); else { @@ -1233,12 +1245,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) { struct dhcp_lease *lease; - struct in6_addr *addrp = opt6_ptr(ia_option, 0); + struct in6_addr addr; - if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp)) + /* align */ + memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); + + if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr)) { prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF); - inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN); + inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN); my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), daemon->addrbuff, daemon->dhcp_buff3); config->flags |= CONFIG_DECLINED; @@ -1250,7 +1265,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ 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)))) + state->iaid, &addr))) lease_prune(lease, now); else { @@ -1267,7 +1282,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_ } o1 = new_opt6(OPTION6_IAADDR); - put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ); + put_opt6(&addr, IN6ADDRSZ); put_opt6_long(0); put_opt6_long(0); end_opt6(o1); @@ -1935,7 +1950,11 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op } else if (type == OPTION6_IAADDR) { - inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN); + struct in6_addr addr; + + /* align */ + memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ); + inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN); sprintf(daemon->namebuff, "%s PL=%u VL=%u", daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4)); optname = "iaaddr"; -- 1.8.3.1