summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2023-11-25 12:00:40 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2023-11-25 12:00:40 +0000
commitb0dea7eef94cfffe735de34fec3e7295949b94e1 (patch)
tree4725207d18802d427ae69dba205f9698f2f6c652
parent83988b68b53c45f9492b585f083bdb4bb6bdd860 (diff)
First stab at IPv6-only preferred from RFC8925.
This lets dhcpleased(8) request "IPv6-only preferred". If the server replies with this option dhcpleased stops and does not request a lease and deconfigures IPv4 on the interface. For now this is pretty much useless unless one dynamically configures pf(4) to act as a CLAT. gelatod(8) from ports can help with this. However, this helps me while hacking on a kernel based stateless CLAT by moving dhcpleased out of the way while having an IPv6-mostly network configured to compare behaviour with macOS. Input jmc OK phessler Input & OK sthen
-rw-r--r--sbin/dhcpleased/dhcpleased.conf.57
-rw-r--r--sbin/dhcpleased/dhcpleased.h4
-rw-r--r--sbin/dhcpleased/engine.c61
-rw-r--r--sbin/dhcpleased/frontend.c19
-rw-r--r--sbin/dhcpleased/parse.y9
-rw-r--r--sbin/dhcpleased/printconf.c4
6 files changed, 94 insertions, 10 deletions
diff --git a/sbin/dhcpleased/dhcpleased.conf.5 b/sbin/dhcpleased/dhcpleased.conf.5
index 4d3eb86fbad..27798d74d34 100644
--- a/sbin/dhcpleased/dhcpleased.conf.5
+++ b/sbin/dhcpleased/dhcpleased.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: dhcpleased.conf.5,v 1.12 2023/03/02 17:09:52 jmc Exp $
+.\" $OpenBSD: dhcpleased.conf.5,v 1.13 2023/11/25 12:00:39 florian Exp $
.\"
.\" Copyright (c) 2018, 2021 Florian Obser <florian@openbsd.org>
.\" Copyright (c) 2005 Esben Norby <norby@openbsd.org>
@@ -18,7 +18,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: March 2 2023 $
+.Dd $Mdocdate: November 25 2023 $
.Dt DHCPLEASED.CONF 5
.Os
.Sh NAME
@@ -68,6 +68,9 @@ Ignore leases from
.Ar server-ip .
This option can be listed multiple times.
The default is to not ignore servers.
+.It Ic prefer ipv6
+Send the IPv6-Only preferred option to the server.
+If the server responds with the option, no lease is configured.
.It Ic send client id Ar client-id
Send the DHCP client identifier option with a value of
.Ar client-id .
diff --git a/sbin/dhcpleased/dhcpleased.h b/sbin/dhcpleased/dhcpleased.h
index c5d7e204651..80fe9dcf5fe 100644
--- a/sbin/dhcpleased/dhcpleased.h
+++ b/sbin/dhcpleased/dhcpleased.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcpleased.h,v 1.14 2022/03/21 04:35:41 dlg Exp $ */
+/* $OpenBSD: dhcpleased.h,v 1.15 2023/11/25 12:00:39 florian Exp $ */
/*
* Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
@@ -132,6 +132,7 @@
#define DHO_NDS_SERVERS 85
#define DHO_NDS_TREE_NAME 86
#define DHO_NDS_CONTEXT 87
+#define DHO_IPV6_ONLY_PREFERRED 108
#define DHO_DOMAIN_SEARCH 119
#define DHO_CLASSLESS_STATIC_ROUTES 121
#define DHO_TFTP_CONFIG_FILE 144
@@ -258,6 +259,7 @@ struct iface_conf {
int ignore;
struct in_addr ignore_servers[MAX_SERVERS];
int ignore_servers_len;
+ int prefer_ipv6;
};
struct dhcpleased_conf {
diff --git a/sbin/dhcpleased/engine.c b/sbin/dhcpleased/engine.c
index b2e34ef6dbc..d435850af1d 100644
--- a/sbin/dhcpleased/engine.c
+++ b/sbin/dhcpleased/engine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: engine.c,v 1.39 2023/11/03 15:02:06 tb Exp $ */
+/* $OpenBSD: engine.c,v 1.40 2023/11/25 12:00:39 florian Exp $ */
/*
* Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
@@ -70,6 +70,7 @@ enum if_state {
IF_REBINDING,
/* IF_INIT_REBOOT, */
IF_REBOOTING,
+ IF_IPV6_ONLY,
};
const char* if_state_name[] = {
@@ -82,6 +83,7 @@ const char* if_state_name[] = {
"Rebinding",
/* "Init-Reboot", */
"Rebooting",
+ "IPv6 only",
};
struct dhcpleased_iface {
@@ -113,6 +115,7 @@ struct dhcpleased_iface {
uint32_t lease_time;
uint32_t renewal_time;
uint32_t rebinding_time;
+ uint32_t ipv6_only_time;
};
LIST_HEAD(, dhcpleased_iface) dhcpleased_interfaces;
@@ -339,6 +342,7 @@ engine_dispatch_frontend(int fd, short event, void *bula)
case IF_REBINDING:
case IF_REBOOTING:
case IF_BOUND:
+ case IF_IPV6_ONLY:
state_transition(iface, IF_REBOOTING);
break;
}
@@ -727,6 +731,7 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
size_t rem, i;
uint32_t sum, usum, lease_time = 0, renewal_time = 0;
uint32_t rebinding_time = 0;
+ uint32_t ipv6_only_time = 0;
uint8_t *p, dho = DHO_PAD, dho_len, slen;
uint8_t dhcp_message_type = 0;
int routes_len = 0, routers = 0, csr = 0;
@@ -1173,6 +1178,18 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
}
break;
}
+ case DHO_IPV6_ONLY_PREFERRED:
+ if (dho_len != sizeof(ipv6_only_time))
+ goto wrong_length;
+ memcpy(&ipv6_only_time, p, sizeof(ipv6_only_time));
+ ipv6_only_time = ntohl(ipv6_only_time);
+ if (log_getverbose() > 1) {
+ log_debug("DHO_IPV6_ONLY_PREFERRED %us",
+ ipv6_only_time);
+ }
+ p += dho_len;
+ rem -= dho_len;
+ break;
default:
if (log_getverbose() > 1)
log_debug("DHO_%u, len: %u", dho, dho_len);
@@ -1207,6 +1224,14 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
"offered IP address", __func__);
return;
}
+#ifndef SMALL
+ if (iface_conf != NULL && iface_conf->prefer_ipv6 &&
+ ipv6_only_time > 0) {
+ iface->ipv6_only_time = ipv6_only_time;
+ state_transition(iface, IF_IPV6_ONLY);
+ break;
+ }
+#endif
iface->server_identifier = server_identifier;
iface->dhcp_server = server_identifier;
iface->requested_ip = dhcp_hdr->yiaddr;
@@ -1307,6 +1332,14 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
strlcpy(iface->domainname, domainname,
sizeof(iface->domainname));
strlcpy(iface->hostname, hostname, sizeof(iface->hostname));
+#ifndef SMALL
+ if (iface_conf != NULL && iface_conf->prefer_ipv6 &&
+ ipv6_only_time > 0) {
+ iface->ipv6_only_time = ipv6_only_time;
+ state_transition(iface, IF_IPV6_ONLY);
+ break;
+ }
+#endif
state_transition(iface, IF_BOUND);
break;
case DHCPNAK:
@@ -1386,6 +1419,7 @@ state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
send_deconfigure_interface(iface);
/* fall through */
case IF_DOWN:
+ case IF_IPV6_ONLY:
iface->timo.tv_sec = START_EXP_BACKOFF;
break;
case IF_BOUND:
@@ -1434,6 +1468,25 @@ state_transition(struct dhcpleased_iface *iface, enum if_state new_state)
iface->timo.tv_sec /= 2;
request_dhcp_request(iface);
break;
+ case IF_IPV6_ONLY:
+ switch (old_state) {
+ case IF_REQUESTING:
+ case IF_RENEWING:
+ case IF_REBINDING:
+ case IF_REBOOTING:
+ /* going IPv6 only: delete legacy IP */
+ send_rdns_withdraw(iface);
+ send_deconfigure_interface(iface);
+ /* fall through */
+ case IF_INIT:
+ case IF_DOWN:
+ case IF_IPV6_ONLY:
+ iface->timo.tv_sec = iface->ipv6_only_time;
+ break;
+ case IF_BOUND:
+ fatal("invalid transition Bound -> IPv6 only");
+ break;
+ }
}
if_name = if_indextoname(iface->if_index, ifnamebuf);
@@ -1499,6 +1552,9 @@ iface_timeout(int fd, short events, void *arg)
else
state_transition(iface, IF_REBINDING);
break;
+ case IF_IPV6_ONLY:
+ state_transition(iface, IF_REQUESTING);
+ break;
}
}
@@ -1584,6 +1640,9 @@ request_dhcp_request(struct dhcpleased_iface *iface)
imsg.requested_ip.s_addr = INADDR_ANY; /* MUST NOT */
imsg.ciaddr = iface->requested_ip; /* IP address */
break;
+ case IF_IPV6_ONLY:
+ fatalx("invalid state IF_IPV6_ONLY in %s", __func__);
+ break;
}
engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg, sizeof(imsg));
diff --git a/sbin/dhcpleased/frontend.c b/sbin/dhcpleased/frontend.c
index e94a3591c6a..3640f3bdbbc 100644
--- a/sbin/dhcpleased/frontend.c
+++ b/sbin/dhcpleased/frontend.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: frontend.c,v 1.30 2022/07/14 15:23:09 florian Exp $ */
+/* $OpenBSD: frontend.c,v 1.31 2023/11/25 12:00:39 florian Exp $ */
/*
* Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
@@ -924,6 +924,11 @@ build_packet(uint8_t message_type, char *if_name, uint32_t xid,
8, DHO_SUBNET_MASK, DHO_ROUTERS, DHO_DOMAIN_NAME_SERVERS,
DHO_HOST_NAME, DHO_DOMAIN_NAME, DHO_BROADCAST_ADDRESS,
DHO_DOMAIN_SEARCH, DHO_CLASSLESS_STATIC_ROUTES};
+ static uint8_t dhcp_req_list_v6[] = {DHO_DHCP_PARAMETER_REQUEST_LIST,
+ 9, DHO_SUBNET_MASK, DHO_ROUTERS, DHO_DOMAIN_NAME_SERVERS,
+ DHO_HOST_NAME, DHO_DOMAIN_NAME, DHO_BROADCAST_ADDRESS,
+ DHO_DOMAIN_SEARCH, DHO_CLASSLESS_STATIC_ROUTES,
+ DHO_IPV6_ONLY_PREFERRED};
static uint8_t dhcp_requested_address[] = {DHO_DHCP_REQUESTED_ADDRESS,
4, 0, 0, 0, 0};
static uint8_t dhcp_server_identifier[] = {DHO_DHCP_SERVER_IDENTIFIER,
@@ -997,15 +1002,23 @@ build_packet(uint8_t message_type, char *if_name, uint32_t xid,
memcpy(p, iface_conf->vc_id, iface_conf->vc_id_len);
p += iface_conf->vc_id_len;
}
+ if (iface_conf->prefer_ipv6) {
+ memcpy(p, dhcp_req_list_v6, sizeof(dhcp_req_list_v6));
+ p += sizeof(dhcp_req_list_v6);
+
+ } else {
+ memcpy(p, dhcp_req_list, sizeof(dhcp_req_list));
+ p += sizeof(dhcp_req_list);
+ }
} else
#endif /* SMALL */
{
memcpy(dhcp_client_id + 3, hw_address, sizeof(*hw_address));
memcpy(p, dhcp_client_id, sizeof(dhcp_client_id));
p += sizeof(dhcp_client_id);
+ memcpy(p, dhcp_req_list, sizeof(dhcp_req_list));
+ p += sizeof(dhcp_req_list);
}
- memcpy(p, dhcp_req_list, sizeof(dhcp_req_list));
- p += sizeof(dhcp_req_list);
if (requested_ip->s_addr != INADDR_ANY) {
memcpy(dhcp_requested_address + 2, requested_ip,
diff --git a/sbin/dhcpleased/parse.y b/sbin/dhcpleased/parse.y
index e3a68953aea..eeae4289e39 100644
--- a/sbin/dhcpleased/parse.y
+++ b/sbin/dhcpleased/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.7 2022/03/21 04:35:41 dlg Exp $ */
+/* $OpenBSD: parse.y,v 1.8 2023/11/25 12:00:39 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -109,7 +109,7 @@ typedef struct {
%}
%token DHCP_IFACE ERROR SEND VENDOR CLASS ID CLIENT IGNORE DNS ROUTES HOST NAME
-%token NO
+%token NO PREFER IPV6
%token <v.string> STRING
%token <v.number> NUMBER
@@ -324,6 +324,9 @@ ifaceoptsl : SEND VENDOR CLASS ID STRING {
}
free($2);
}
+ | PREFER IPV6 {
+ iface_conf->prefer_ipv6 = 1;
+ }
;
%%
@@ -366,8 +369,10 @@ lookup(char *s)
{"id", ID},
{"ignore", IGNORE},
{"interface", DHCP_IFACE},
+ {"ipv6", IPV6},
{"name", NAME},
{"no", NO},
+ {"prefer", PREFER},
{"routes", ROUTES},
{"send", SEND},
{"vendor", VENDOR},
diff --git a/sbin/dhcpleased/printconf.c b/sbin/dhcpleased/printconf.c
index 076fe2ec0ad..0ef3970366c 100644
--- a/sbin/dhcpleased/printconf.c
+++ b/sbin/dhcpleased/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.4 2022/01/04 06:20:37 florian Exp $ */
+/* $OpenBSD: printconf.c,v 1.5 2023/11/25 12:00:39 florian Exp $ */
/*
* Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -126,6 +126,8 @@ print_config(struct dhcpleased_conf *conf)
printf("\tignore %s\n", hbuf);
}
+ if (iface->prefer_ipv6)
+ printf("\t prefer ipv6\n");
printf("}\n");
}
}