Re: DHCPv6 and OPTION_USER_CLASS
Roy Marples
Sun Apr 29 15:49:48 2018
On 29/04/2018 15:03, Mattieu Baptiste wrote:
WOW!
You're using token authentication, but the token you're sending does not
match the token being sent back. This is not what I expected.
Yes, that was my first thought.
Can I see your working dibbler configuration please?
Looking at the dibbler documentation (I can't read the source, it hurts my
eyes and I don't understand c++ too well) they don't even have an option for
sending token based authentication which is what it's actually sending ....
They don't support the required options directly, but you can set the
options manually. Here is the configuration:
script "/etc/dibbler/radvd.sh"
downlink-prefix-ifaces "none"
iface "vlan832" {
pd
option 16 hex 00:00:04:0e:00:05:73:61:67:65:6d
option 15 hex
00:2b:46:53:56:44:53:4c:5f:6c:69:76:65:62:6f:78:2e:49:6e:74:65:72:6e:65:74:2e:73:6f:66:74:61:74:68:6f:6d:65:2e:6c:69:76:65:62:6f:78:33
option 11 hex
00:00:00:00:00:00:00:00:00:00:00:66:74:69:2f:XX:XX:XX:XX:XX:XX:XX
option 11 hex
00:00:00:00:00:00:00:00:00:00:00:66:74:69:2f:XX:XX:XX:XX:XX:XX:XX
}
Don't pay attention to the dublicate "option 11". In fact it's due to
a dibbler bug that don't set the auth option anymore in the "DHCPv6
request" if we don't set the option twice (it only sets it in the
DHCPv6 solicit).
But it might we we need two tokens, 1 the server expects and 2 the client
expects. I've always taken the assumption that both are the same.
Exactly, the server sends the different auth token "dhcpliveboxfr".
I think dibbler doesn't care about the authentication server response.
Test this new patch for auth.c
It disables the returned token check. If this works then I guess we need an
option to specify the receive token as well as the send token.
Yeah, seems to work fine!
# 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 0x861cf0), next in 0.8 seconds
vlan832: broadcasting SOLICIT6 (xid 0x861cf0), next in 1.1 seconds
vlan832: validated using 0x00000000
vlan832: ADV 2a01:cb00:7c8:7f00::/56 from fe80::ba0:bab
vlan832: broadcasting REQUEST6 (xid 0xb0e0e3), next in 1.0 seconds
vlan832: validated using 0x00000000
vlan832: REPLY6 received from fe80::ba0:bab
vlan832: renew in 49290, 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
^Creceived SIGINT, stopping
vlan832: removing interface
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' STOPPED
dhcpcd exited
Great stuff!
Attached is a new patch which adjust dhcpcd.conf slightly.
Here is an example of it working:
authprotocol token 0x123/0x456
authtoken 0x123 "" forever "foobar"
authtoken 0x456 "" forever "barfoo"
This allows us to specify which tokens to use for sending and receiving.
If not specified then a default of 0 is used so existing configs work as
before.
Let me know how it works for you!
Roy
diff --git a/src/auth.c b/src/auth.c
index be7dd7ad..6e911918 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)) {
@@ -482,11 +499,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