Re: DHCPv6 and OPTION_USER_CLASS
Roy Marples
Sun Apr 29 18:03:09 2018
On 29/04/2018 17:34, Mattieu Baptiste wrote:
Mmm, with the following conf:
ipv6only
duid
authprotocol token 0x123/0x456
authtoken 0x123 "" forever fti/xxxxxxx
authtoken 0x456 "" forever dhcpliveboxfr250
userclass FSVDSL_livebox.Internet.softathome.livebox3
vendclass 1038 sagem
persistent
noipv6rs
allowinterfaces vlan832
interface vlan832
ia_pd 1
I now have this error:
# 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 0xd38e24), next in 0.2 seconds
vlan832: broadcasting SOLICIT6 (xid 0xd38e24), next in 0.9 seconds
vlan832: authentication failed from fe80::ba0:bab: No such process
vlan832: broadcasting SOLICIT6 (xid 0xd38e24), next in 1.8 seconds
vlan832: authentication failed from fe80::ba0:bab: No such process
vlan832: broadcasting SOLICIT6 (xid 0xd38e24), next in 3.8 seconds
vlan832: authentication failed from fe80::ba0:bab: No such process
^Creceived SIGINT, stopping
vlan832: removing interface
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' STOPPED
dhcpcd exited
Arrrggghhhh!
I tested on a network bit orientated arch.
Attached is a corrected patch which should now work.
Let me know!
Roy
diff --git a/src/auth.c b/src/auth.c
index be7dd7ad..6592f539 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,10 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
uint32_t giaddr, secretid;
bool auth_info;
- if (auth->protocol == 0 && t == NULL) {
+ if (auth->protocol == AUTH_PROTO_TOKEN && t == NULL) {
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