318 lines
13 KiB
Diff
318 lines
13 KiB
Diff
|
From 653481c6ebf46dcadb5a017085325d956dd04a28 Mon Sep 17 00:00:00 2001
|
||
|
From: Simon Kelley <simon@thekelleys.org.uk>
|
||
|
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
|
||
|
|