return config_dhcp.auth_token != NULL;
}
+void config_set_client_opt_cfg(struct odhcp6c_opt_cfg *opt_cfg)
+{
+ config_dhcp.strict_rfc7550 = opt_cfg->strict_rfc7550 != 0;
+}
+
static int config_parse_opt_u8(const char *src, uint8_t **dst)
{
int len = strlen(src);
uint16_t rand_factor;
enum odhcp6c_auth_protocol auth_protocol;
char* auth_token;
+ bool strict_rfc7550;
};
struct config_dhcp *config_dhcp_get(void);
bool config_set_rand_factor(unsigned int value);
bool config_set_auth_protocol(const char* protocol);
bool config_set_auth_token(const char* token);
+void config_set_client_opt_cfg(struct odhcp6c_opt_cfg *opt_cfg);
int config_add_opt(const uint16_t code, const uint8_t *data, const uint16_t len);
int config_parse_opt_data(const char *data, uint8_t **dst, const unsigned int type, const bool array);
switch (req_msg_type) {
case DHCPV6_MSG_REQUEST:
- /* Some broken ISPs won't behave properly if IA_NA is
- * sent on Requests when they have provided an empty
- * IA_NA on Advertise.
- * Therefore we don't comply with RFC7550 and omit
- * IA_NA as a workaround.
- */
- iov[IOV_HDR_IA_NA].iov_len = 0;
+ if (!config_dhcp->strict_rfc7550) {
+ /* Some broken ISPs won't behave properly if IA_NA is
+ * sent on Requests when they have provided an empty
+ * IA_NA on Advertise.
+ * Therefore we don't comply with RFC7550 and omit
+ * IA_NA as a workaround.
+ */
+ iov[IOV_HDR_IA_NA].iov_len = 0;
+ }
break;
case DHCPV6_MSG_SOLICIT:
break;
struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
uint16_t hdr[2];
int ret = DHCPV6_STATELESS;
+ bool override_ia = false;
// Clear lingering candidate state info
odhcp6c_clear_state(STATE_SERVER_ID);
if (!cand_len)
return -1;
- if (!cand->ia_pd_len && cand->has_noaddravail) {
- bool override = false;
+ if (config_dhcp->strict_rfc7550) {
+ if (!cand->ia_pd_len && cand->has_noaddravail) {
+ /* Some ISPs provide neither IA_NA nor IA_PD, so we
+ * should fallback to SLAAC.
+ */
+
+ if (na_mode == IA_MODE_TRY) {
+ na_mode = IA_MODE_NONE;
+ override_ia = true;
+ }
- if (na_mode == IA_MODE_TRY) {
+ if (pd_mode == IA_MODE_TRY) {
+ pd_mode = IA_MODE_NONE;
+ override_ia = true;
+ }
+ }
+ } else {
+ if (cand->has_noaddravail && na_mode == IA_MODE_TRY) {
+ /* Some broken ISPs require a new Solicit message
+ * without IA_NA if they haven't provided an address
+ * on the Advertise message.
+ */
na_mode = IA_MODE_NONE;
- override = true;
+ override_ia = true;
}
- if (pd_mode == IA_MODE_TRY) {
+ if (!cand->ia_pd_len && pd_mode == IA_MODE_TRY) {
+ /* Some broken ISPs require a new Solicit message
+ * without IA_PD if they haven't provided a prefix
+ * on the Advertise message.
+ */
pd_mode = IA_MODE_NONE;
- override = true;
+ override_ia = true;
}
+ }
- if (override) {
- dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
- dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
+ if (override_ia) {
+ dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
+ dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
- return -1;
- }
+ return -1;
}
hdr[0] = htons(DHCPV6_OPT_SERVERID);
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <limits.h>
#include <linux/if_addr.h>
#include <net/if.h>
{ .code = 0, .flags = 0, .str = NULL },
};
+static struct odhcp6c_opt_cfg opt_cfg = {
+ .strict_rfc7550 = 0,
+};
+
+static struct option opt_long[] = {
+ { "strict-rfc7550", no_argument, &opt_cfg.strict_rfc7550, 1 },
+ { NULL, 0, NULL, 0 },
+};
+
int main(_o_unused int argc, char* const argv[])
{
static struct in6_addr ifid = IN6ADDR_ANY_INIT;
const char *script = "/lib/netifd/dhcpv6.script";
ssize_t l;
uint8_t buf[134], *o_data;
+ int optidx;
char *optpos;
uint16_t opttype;
struct odhcp6c_opt *opt;
atexit(odhcp6c_cleanup);
- while ((c = getopt(argc, argv, "SDN:V:P:FB:c:i:r:Ru:Ux:s:EkK:t:C:m:Lhedp:favl:")) != -1) {
+ while ((c = getopt_long(argc, argv, "SDN:V:P:FB:c:i:r:Ru:Ux:s:EkK:t:C:m:Lhedp:favl:", opt_long, &optidx)) != -1) {
switch (c) {
+ case 0:
+ break;
+
case 'S':
config_set_allow_slaac_only(false);
break;
}
}
+ config_set_client_opt_cfg(&opt_cfg);
+
openlog("odhcp6c", logopt, LOG_DAEMON);
setlogmask(LOG_UPTO(config_dhcp->log_level));
" -m <seconds> Minimum time between accepting RA updates (3)\n"
" -L Ignore default lifetime for RDNSS records\n"
" -U Ignore Server Unicast option\n"
+ " --strict-rfc7550 Enforce RFC7550 compliance\n"
"\nInvocation options:\n"
" -p <pidfile> Set pidfile (/var/run/odhcp6c.pid)\n"
" -d Daemonize\n"
const char *str;
};
+struct odhcp6c_opt_cfg {
+ int strict_rfc7550;
+};
+
uint32_t hash_ifname(const char *s);
int init_dhcpv6(const char *ifname);
int dhcpv6_get_ia_mode(void);