Re: DHCPv6 and OPTION_USER_CLASS
Roy Marples
Sun Apr 29 18:40:53 2018
On 29/04/2018 19:28, Mattieu Baptiste wrote:
Great, it works! It just seem to have a little trouble when
relaunching (see below).
# dhcpcd -Bd
dhcpcd-7.0.3 starting
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' PREINIT
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' CARRIER
DUID 00:01:00:06:20:f6:4d:7a:00:0d:b9:33:8e:8c
vlan832: IAID ff:00:03:40
vlan832: IAID 00:00:00:01
vlan832: reading lease `/var/db/dhcpcd/vlan832.lease6'
vlan832: soliciting a DHCPv6 lease
vlan832: delaying SOLICIT6 (xid 0x790333), next in 0.5 seconds
vlan832: broadcasting SOLICIT6 (xid 0x790333), next in 1.1 seconds
vlan832: validated using 0x00001110
vlan832: ADV 2a01:cb00:7c8:7f00::/56 from fe80::ba0:bab
vlan832: broadcasting REQUEST6 (xid 0x422f0f), next in 1.0 seconds
vlan832: validated using 0x00001110
vlan832: REPLY6 received from fe80::ba0:bab
vlan832: renew in 36957, rebind in 207360, expire in 259200 seconds
lo0: adding reject route to 2a01:cb00:7c8:7f00::/56 via ::1
vlan832: writing lease `/var/db/dhcpcd/vlan832.lease6'
vlan832: delegated prefix 2a01:cb00:7c8:7f00::/56
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' BOUND6
One out of two times, when I launch dhcpcd in debug mode, it fails again with:
vlan832: broadcasting SOLICIT6 (xid 0x567cb9), next in 1.0 seconds
vlan832: broadcasting SOLICIT6 (xid 0x567cb9), next in 2.1 seconds
vlan832: broadcasting SOLICIT6 (xid 0x567cb9), next in 4.1 seconds
Dumping the trafic, when sending Rebind and then Solicit, it tries to
use the server token, and not the client one:
Authentication
Option: Authentication (11)
Length: 27
Value: 000000de908bb0960efd44646863706c697665626f786672...
Protocol: 0
Algorithm: 0
RDM: 0
Replay Detection: de908bb0960efd44
Authentication Information: 646863706c697665626f786672323530
Yes.
I've adjusted the patch to solve this. I need to test more fully as a
result of the change, but I don't see any reason why it would break
other protocols.
Roy
diff --git a/src/auth.c b/src/auth.c
index be7dd7ad..a272e93d 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -151,7 +151,24 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
memcpy(&replay, d, sizeof(replay));
replay = ntohll(replay);
- if (state->token) {
+ /*
+ * Test for a replay attack.
+ *
+ * NOTE: Some servers always send a replay data value of zero.
+ * This is strictly compliant with RFC 3315 and 3318 which say:
+ * "If the RDM field contains 0x00, the replay detection field MUST be
+ * set to the value of a monotonically increasing counter."
+ * An example of a monotonically increasing sequence is:
+ * 1, 2, 2, 2, 2, 2, 2
+ * Errata 3474 updates RFC 3318 to say:
+ * "If the RDM field contains 0x00, the replay detection field MUST be
+ * set to the value of a strictly increasing counter."
+ *
+ * Taking the above into account, dhcpcd will only test for
+ * strictly speaking replay attacks if it receives any non zero
+ * replay data to validate against.
+ */
+ if (state->token && state->replay != 0) {
if (state->replay == (replay ^ 0x8000000000000000ULL)) {
/* We don't know if the singular point is increasing
* or decreasing. */
@@ -174,7 +191,7 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
* Rest of data is MAC. */
switch (protocol) {
case AUTH_PROTO_TOKEN:
- secretid = 0;
+ secretid = auth->token_rcv_secretid;
break;
case AUTH_PROTO_DELAYED:
if (dlen < sizeof(secretid) + sizeof(hmac_code)) {
@@ -182,6 +199,7 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
return NULL;
}
memcpy(&secretid, d, sizeof(secretid));
+ secretid = ntohl(secretid);
d += sizeof(secretid);
dlen -= sizeof(secretid);
break;
@@ -197,6 +215,7 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
dlen -= realm_len;
}
memcpy(&secretid, d, sizeof(secretid));
+ secretid = ntohl(secretid);
d += sizeof(secretid);
dlen -= sizeof(secretid);
break;
@@ -266,7 +285,6 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
}
/* Find a token for the realm and secret */
- secretid = ntohl(secretid);
TAILQ_FOREACH(t, &auth->tokens, next) {
if (t->secretid == secretid &&
t->realm_len == realm_len &&
@@ -482,11 +500,12 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
uint32_t giaddr, secretid;
bool auth_info;
- if (auth->protocol == 0 && t == NULL) {
+ /* Ignore the token argument given to us - always send using the
+ * configured token. */
+ if (auth->protocol == AUTH_PROTO_TOKEN) {
TAILQ_FOREACH(t, &auth->tokens, next) {
- if (t->secretid == 0 &&
- t->realm_len == 0)
- break;
+ if (t->secretid == auth->token_snd_secretid)
+ break;
}
if (t == NULL) {
errno = EINVAL;
diff --git a/src/auth.h b/src/auth.h
index ac35ba76..f65d62c3 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -71,6 +71,8 @@ struct auth {
uint64_t last_replay;
uint8_t last_replay_set;
struct token_head tokens;
+ uint32_t token_snd_secretid;
+ uint32_t token_rcv_secretid;
#endif
};
diff --git a/src/dhcpcd.conf.5.in b/src/dhcpcd.conf.5.in
index f1a8a8d7..d56c4dd4 100644
--- a/src/dhcpcd.conf.5.in
+++ b/src/dhcpcd.conf.5.in
@@ -74,9 +74,16 @@ Example:
.D1 # A generic 192.168.0.1 network
.D1 profile 192.168.0.1
.D1 static ip_address=192.168.0.98/24
-.It Ic authprotocol Ar protocol Ar algorithm Ar rdm
+.It Ic authprotocol Ar protocol Op Ar algorithm Op Ar rdm
Authenticate DHCP messages.
See the Supported Authentication Protocols section.
+If
+.Ar protocol
+is
+.Ar token
+then
+.Ar algorithm is
+snd_secretid/rcv_secretid so you can send and recieve different tokens.
.It Ic authtoken Ar secretid Ar realm Ar expire Ar key
Define a shared key for use in authentication.
.Ar realm
@@ -863,7 +870,11 @@ References an option from the global definition.
.Ss Supported Authentication Protocols
.Bl -tag -width -indent
.It Ic token
-Sends and expects the token with the secretid 0 and realm of "" in each message.
+Sends a plain text token the server expects and matches a token sent by
+the server.
+The tokens to not have to be the same.
+If unspecified, the token with secretid of 0 will be used in sending messages
+and validating received messages.
.It Ic delayedrealm
Delayed Authentication.
.Nm dhcpcd
diff --git a/src/if-options.c b/src/if-options.c
index 4eb6e6ea..5943e700 100644
--- a/src/if-options.c
+++ b/src/if-options.c
@@ -1913,12 +1913,32 @@ err_sla:
}
if (fp)
*fp++ = '\0';
- if (strcasecmp(arg, "hmacmd5") == 0 ||
- strcasecmp(arg, "hmac-md5") == 0)
- ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
- else {
- logerrx("%s: unsupported algorithm", arg);
- return 1;
+ if (ifo->auth.protocol == AUTH_PROTO_TOKEN) {
+ np = strchr(arg, '/');
+ if (np) {
+ if (fp == NULL || np < fp)
+ *np++ = '\0';
+ else
+ np = NULL;
+ }
+ if (parse_uint32(&ifo->auth.token_snd_secretid,
+ arg) == -1)
+ logerrx("%s: not a number", arg);
+ else
+ ifo->auth.token_rcv_secretid =
+ ifo->auth.token_snd_secretid;
+ if (np &&
+ parse_uint32(&ifo->auth.token_rcv_secretid,
+ np) == -1)
+ logerrx("%s: not a number", arg);
+ } else {
+ if (strcasecmp(arg, "hmacmd5") == 0 ||
+ strcasecmp(arg, "hmac-md5") == 0)
+ ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
+ else {
+ logerrx("%s: unsupported algorithm", arg);
+ return 1;
+ }
}
arg = fp;
if (arg == NULL) {
Archive administrator: postmaster@marples.name