- *req_addresses* (string{try|force|none}) : Request addresses
- *req_prefixes* (int) : Request Prefixes (0 = auto)
- *stateful_only* (bool) : Discard advertisements without any address or prefix proposed
+ - *irt_default* (int) : Default information refresh time (expressed in seconds)
+ - *irt_min* (int) : Minimum information refresh time (expressed in seconds)
+ - *rand_factor* (int) : Randomization factor for retransmission timeout
+ - *msg_solicit* (table) : Retransmission settings for SOLICIT
+ - *msg_request* (table) : Retransmission settings for REQUEST
+ - *msg_renew* (table) : Retransmission settings for RENEW
+ - *msg_rebind* (table) : Retransmission settings for REBIND
+ - *msg_release* (table) : Retransmission settings for RELEASE
+ - *msg_decline* (table) : Retransmission settings for DECLINE
+ - *msg_inforeq* (table) : Retransmission settings for INFORMATION-REQUEST
+ - *auth_protocol* (string) : Authentication protocol to be used ("None","ConfigurationToken", "ReconfigureKeyAuthentication")
+ - *auth_token* (string) : Authentication token to be used when AuthenticationProtocol is set to ConfigurationToken
+* *renew()* : Force transmission of RENEW/INFORMATION-REQUEST messages
+* *release()* : Force transmission of RELEASE message and start new cycle
+
+Input arguments for retransmission settings :
+ - *delay_max* (int) : Maximum delay of first message (expressed in seconds)
+ - *timeout_init* (int) : Initial message timeout (expressed in seconds)
+ - *timeout_max* (int) : Initial message timeout (expressed in seconds)
+ - *rc_max* (int) : Maximum message retry attempts
\ No newline at end of file
config_dhcp.irt_default = DHCPV6_IRT_DEFAULT;
config_dhcp.irt_min = DHCPV6_IRT_MIN;
config_dhcp.rand_factor = DHCPV6_RAND_FACTOR;
+ config_dhcp.auth_protocol = AUTH_PROT_RKAP;
+ free(config_dhcp.auth_token);
+ config_dhcp.auth_token = NULL;
}
void config_set_release(bool enable) {
return true;
}
+bool config_set_auth_protocol(const char* protocol)
+{
+ if (!strcmp(protocol, "None")) {
+ config_dhcp.auth_protocol = AUTH_PROT_NONE;
+ } else if (!strcmp(protocol, "ConfigurationToken")) {
+ config_dhcp.auth_protocol = AUTH_PROT_TOKEN;
+ } else if (!strcmp(protocol, "ReconfigureKeyAuthentication")) {
+ config_dhcp.auth_protocol = AUTH_PROT_RKAP;
+ } else {
+ syslog(LOG_ERR, "Invalid Authentication protocol");
+ return false;
+ }
+
+ return true;
+}
+
+bool config_set_auth_token(const char* token)
+{
+ free(config_dhcp.auth_token);
+
+ config_dhcp.auth_token = strdup(token);
+ return config_dhcp.auth_token != NULL;
+}
+
static int config_parse_opt_u8(const char *src, uint8_t **dst)
{
int len = strlen(src);
static enum dhcpv6_state dhcpv6_state = DHCPV6_INIT;
static int dhcpv6_state_timeout = 0;
-// Reconfigure key
+// Authentication options
+static enum odhcp6c_auth_protocol auth_protocol = AUTH_PROT_RKAP;
static uint8_t reconf_key[16];
// client options
na_mode = config_dhcp->ia_na_mode;
pd_mode = config_dhcp->ia_pd_mode;
stateful_only_mode = config_dhcp->stateful_only_mode;
+ auth_protocol = config_dhcp->auth_protocol;
sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
if (sock < 0)
rcmsg = DHCPV6_MSG_UNKNOWN;
uint16_t otype, olen = UINT16_MAX;
bool clientid_ok = false, serverid_ok = false, rcauth_ok = false,
- ia_present = false, options_valid = true;
+ auth_present = false, ia_present = false, options_valid = true;
size_t client_id_len, server_id_len;
void *client_id = odhcp6c_get_state(STATE_CLIENT_ID, &client_id_len);
&odata[-4], server_id, server_id_len);
else
serverid_ok = true;
- } else if (otype == DHCPV6_OPT_AUTH && olen == -4 +
- sizeof(struct dhcpv6_auth_reconfigure)) {
- struct dhcpv6_auth_reconfigure *r = (void*)&odata[-4];
- if (r->protocol != 3 || r->algorithm != 1 || r->reconf_type != 2)
+ } else if (otype == DHCPV6_OPT_AUTH) {
+ struct dhcpv6_auth *r = (void*)&odata[-4];
+ if (auth_present) {
+ options_valid = false;
continue;
+ }
- md5_ctx_t md5;
- uint8_t serverhash[16], secretbytes[64];
- uint32_t hash[4];
- memcpy(serverhash, r->key, sizeof(serverhash));
- memset(r->key, 0, sizeof(r->key));
+ auth_present = true;
+ if (auth_protocol == AUTH_PROT_RKAP) {
+ struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
+ if (r->protocol != AUTH_PROT_RKAP || r->algorithm != AUTH_ALG_HMACMD5 || r->len != 28 || rkap->reconf_type != RKAP_TYPE_HMACMD5)
+ continue;
- memset(secretbytes, 0, sizeof(secretbytes));
- memcpy(secretbytes, reconf_key, sizeof(reconf_key));
+ md5_ctx_t md5;
+ uint8_t serverhash[16], secretbytes[64];
+ uint32_t hash[4];
+ memcpy(serverhash, rkap->key, sizeof(serverhash));
+ memset(rkap->key, 0, sizeof(rkap->key));
- for (size_t i = 0; i < sizeof(secretbytes); ++i)
- secretbytes[i] ^= 0x36;
+ memset(secretbytes, 0, sizeof(secretbytes));
+ memcpy(secretbytes, reconf_key, sizeof(reconf_key));
- md5_begin(&md5);
- md5_hash(secretbytes, sizeof(secretbytes), &md5);
- md5_hash(buf, len, &md5);
- md5_end(hash, &md5);
+ for (size_t i = 0; i < sizeof(secretbytes); ++i)
+ secretbytes[i] ^= 0x36;
- for (size_t i = 0; i < sizeof(secretbytes); ++i) {
- secretbytes[i] ^= 0x36;
- secretbytes[i] ^= 0x5c;
- }
+ md5_begin(&md5);
+ md5_hash(secretbytes, sizeof(secretbytes), &md5);
+ md5_hash(buf, len, &md5);
+ md5_end(hash, &md5);
+
+ for (size_t i = 0; i < sizeof(secretbytes); ++i) {
+ secretbytes[i] ^= 0x36;
+ secretbytes[i] ^= 0x5c;
+ }
+
+ md5_begin(&md5);
+ md5_hash(secretbytes, sizeof(secretbytes), &md5);
+ md5_hash(hash, 16, &md5);
+ md5_end(hash, &md5);
- md5_begin(&md5);
- md5_hash(secretbytes, sizeof(secretbytes), &md5);
- md5_hash(hash, 16, &md5);
- md5_end(hash, &md5);
+ rcauth_ok = !memcmp(hash, serverhash, sizeof(hash));
+ } else if (auth_protocol == AUTH_PROT_TOKEN) {
+ if (r->protocol != AUTH_PROT_TOKEN || r->algorithm != AUTH_ALG_TOKEN || r->len < 12)
+ continue;
+
+ uint16_t token_len = r->len - 11;
+ if (config_dhcp->auth_token == NULL || strlen(config_dhcp->auth_token) != token_len)
+ continue;
- rcauth_ok = !memcmp(hash, serverhash, sizeof(hash));
+ rcauth_ok = !memcmp(r->data, config_dhcp->auth_token, token_len);
+ }
} else if (otype == DHCPV6_OPT_RECONF_MESSAGE && olen == 1) {
rcmsg = odata[0];
} else if ((otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA)) {
else if (otype == DHCPV6_OPT_INFO_REFRESH && olen >= 4) {
refresh = ntohl_unaligned(odata);
} else if (otype == DHCPV6_OPT_AUTH) {
- if (olen == -4 + sizeof(struct dhcpv6_auth_reconfigure)) {
- struct dhcpv6_auth_reconfigure *r = (void*)&odata[-4];
- if (r->protocol == 3 && r->algorithm == 1 &&
- r->reconf_type == 1)
- memcpy(reconf_key, r->key, sizeof(r->key));
- }
+ struct dhcpv6_auth *r = (void*)&odata[-4];
+ if (auth_protocol == AUTH_PROT_RKAP) {
+ struct dhcpv6_auth_reconfigure *rkap = (void*)r->data;
+ if (r->protocol == AUTH_PROT_RKAP || r->algorithm == AUTH_ALG_HMACMD5 || r->len == 28 || rkap->reconf_type == RKAP_TYPE_KEY)
+ memcpy(reconf_key, rkap->key, sizeof(rkap->key));
+ }
} else if (otype == DHCPV6_OPT_AFTR_NAME && olen > 3) {
size_t cur_len;
odhcp6c_get_state(STATE_AFTR_NAME, &cur_len);
odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
odhcp6c_add_state(STATE_SERVER_ID, cand->duid, cand->duid_len);
accept_reconfig = cand->wants_reconfigure;
+ memset(reconf_key, 0, sizeof(reconf_key));
if (cand->ia_na_len) {
odhcp6c_add_state(STATE_IA_NA, cand->ia_na, cand->ia_na_len);
RECONFIGURE_DHCP_ATTR_IRT_DEFAULT,
RECONFIGURE_DHCP_ATTR_IRT_MIN,
RECONFIGURE_DHCP_ATTR_RAND_FACTOR,
+ RECONFIGURE_DHCP_ATTR_AUTH_PROTO,
+ RECONFIGURE_DHCP_ATTR_AUTH_TOKEN,
RECONFIGURE_DHCP_ATTR_MAX,
};
[RECONFIGURE_DHCP_ATTR_IRT_DEFAULT] = { .name = "irt_default", .type = BLOBMSG_TYPE_INT32},
[RECONFIGURE_DHCP_ATTR_IRT_MIN] = { .name = "irt_min", .type = BLOBMSG_TYPE_INT32},
[RECONFIGURE_DHCP_ATTR_RAND_FACTOR] = { .name = "rand_factor", .type = BLOBMSG_TYPE_INT32},
+ [RECONFIGURE_DHCP_ATTR_AUTH_PROTO] = { .name = "auth_protocol", .type = BLOBMSG_TYPE_STRING},
+ [RECONFIGURE_DHCP_ATTR_AUTH_TOKEN] = { .name = "auth_token", .type = BLOBMSG_TYPE_STRING},
};
static struct ubus_method odhcp6c_object_methods[] = {
valid_args = true;
}
+ if ((cur = tb[RECONFIGURE_DHCP_ATTR_AUTH_PROTO])) {
+ string = blobmsg_get_string(cur);
+
+ if (string == NULL || !config_set_auth_protocol(string))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ need_reinit = true;
+ valid_args = true;
+ }
+
+ if ((cur = tb[RECONFIGURE_DHCP_ATTR_AUTH_TOKEN])) {
+ string = blobmsg_get_string(cur);
+
+ if (string == NULL || !config_set_auth_token(string))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ need_reinit = true;
+ valid_args = true;
+ }
+
if (need_reinit)
raise(SIGUSR2);