From 76ddddefc8830f023b614e02a92d98dd2361aa1f Mon Sep 17 00:00:00 2001 From: florian Date: Thu, 6 Jun 2024 15:16:57 +0000 Subject: [PATCH] dhcp6leasectl --- usr.sbin/dhcp6leasectl/Makefile | 17 ++ usr.sbin/dhcp6leasectl/dhcp6leasectl.8 | 73 ++++++++ usr.sbin/dhcp6leasectl/dhcp6leasectl.c | 240 +++++++++++++++++++++++++ 3 files changed, 330 insertions(+) create mode 100644 usr.sbin/dhcp6leasectl/Makefile create mode 100644 usr.sbin/dhcp6leasectl/dhcp6leasectl.8 create mode 100644 usr.sbin/dhcp6leasectl/dhcp6leasectl.c diff --git a/usr.sbin/dhcp6leasectl/Makefile b/usr.sbin/dhcp6leasectl/Makefile new file mode 100644 index 00000000000..0af424ace83 --- /dev/null +++ b/usr.sbin/dhcp6leasectl/Makefile @@ -0,0 +1,17 @@ +# $OpenBSD: Makefile,v 1.1 2024/06/06 15:16:57 florian Exp $ + +PROG= dhcp6leasectl +SRCS= dhcp6leasectl.c + +MAN= dhcp6leasectl.8 + +CFLAGS+= -Wall +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CFLAGS+= -Wmissing-declarations +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../../sbin/dhcp6leased +LDADD= -lutil +DPADD= ${LIBUTIL} + +.include diff --git a/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 b/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 new file mode 100644 index 00000000000..f5ebd9a08a8 --- /dev/null +++ b/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 @@ -0,0 +1,73 @@ +.\" $OpenBSD: dhcp6leasectl.8,v 1.1 2024/06/06 15:16:57 florian Exp $ +.\" +.\" Copyright (c) 2021 Florian Obser +.\" Copyright (c) 2016 Kenneth R Westerback +.\" Copyright (c) 2004, 2005 Esben Norby +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: June 6 2024 $ +.Dt DHCP6LEASECTL 8 +.Os +.Sh NAME +.Nm dhcp6leasectl +.Nd control the dhcp6leased client +.Sh SYNOPSIS +.Nm +.Op Fl l +.Op Fl s Ar socket +.Op Fl w Ar maxwait +.Ar interface +.Sh DESCRIPTION +The +.Nm +program instructs the +.Xr dhcp6leased 8 +daemon to request a new lease. +.Pp +The following options are available: +.Bl -tag -width Ds +.It Fl l +List the configured lease on +.Ar interface +instead of requesting a new lease. +.It Fl s Ar socket +Use +.Ar socket +instead of the default +.Pa /dev/dhcp6leased.sock +to communicate with +.Xr dhcp6leased 8 . +.It Fl w Ar maxwait +Specify the maximum number of seconds to wait for +.Ar interface +to be configured. +The default is to wait 10 seconds unless +.Fl l +is specified. +.El +.Sh FILES +.Bl -tag -width "/dev/dhcp6leased.sockXX" -compact +.It Pa /dev/dhcp6leased.sock +.Ux Ns -domain +socket used for communication with +.Xr dhcp6leased 8 . +.El +.Sh SEE ALSO +.Xr dhcp6leased.conf 5 , +.Xr dhcp6leased 8 +.Sh HISTORY +The +.Nm +program first appeared in +.Ox 7.6 . diff --git a/usr.sbin/dhcp6leasectl/dhcp6leasectl.c b/usr.sbin/dhcp6leasectl/dhcp6leasectl.c new file mode 100644 index 00000000000..9398612e80d --- /dev/null +++ b/usr.sbin/dhcp6leasectl/dhcp6leasectl.c @@ -0,0 +1,240 @@ +/* $OpenBSD: dhcp6leasectl.c,v 1.1 2024/06/06 15:16:57 florian Exp $ */ + +/* + * Copyright (c) 2021, 2024 Florian Obser + * Copyright (c) 2005 Claudio Jeker + * Copyright (c) 2004, 2005 Esben Norby + * Copyright (c) 2003 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dhcp6leased.h" + +__dead void usage(void); +void show_interface_msg(struct ctl_engine_info *); + +struct imsgbuf *ibuf; + +__dead void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-l] [-s socket] [-w maxwait] interface\n", + __progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + struct sockaddr_un sun; + struct imsg imsg; + struct ctl_engine_info *cei; + int ctl_sock; + int n, lFlag = 0, maxwait_set = 0, didot = 0; + int ch, if_index = 0, maxwait = 10, bound = 0; + char *sockname; + const char *errstr; + + sockname = _PATH_CTRL_SOCKET; + while ((ch = getopt(argc, argv, "ls:w:")) != -1) { + switch (ch) { + case 'l': + lFlag = 1; + break; + case 's': + sockname = optarg; + break; + case 'w': + maxwait_set = 1; + maxwait = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr) + errx(1, "maxwait value is %s: %s", + errstr, optarg); + break; + + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + if ((if_index = if_nametoindex(argv[0])) == 0) + errx(1, "unknown interface"); + + if (lFlag && !maxwait_set) + maxwait = 0; + + /* Connect to control socket. */ + if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + err(1, "socket"); + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); + + if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) + err(1, "connect: %s", sockname); + + if (pledge("stdio", NULL) == -1) + err(1, "pledge"); + + if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) + err(1, NULL); + imsg_init(ibuf, ctl_sock); + + if (!lFlag) { + imsg_compose(ibuf, IMSG_CTL_SEND_REQUEST, 0, 0, -1, + &if_index, sizeof(if_index)); + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) + err(1, "write error"); + + } + + for(;;) { + imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE_INFO, 0, 0, -1, + &if_index, sizeof(if_index)); + + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) + err(1, "write error"); + + + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + errx(1, "imsg_read error"); + if (n == 0) + errx(1, "pipe closed"); + + if ((n = imsg_get(ibuf, &imsg)) == -1) + errx(1, "imsg_get error"); + if (n == 0) + break; + + if (imsg.hdr.type == IMSG_CTL_END) { + if (lFlag) + errx(1, "non-autoconf interface %s", argv[0]); + else if (--maxwait < 0) + break; + else + continue; + } + + cei = imsg.data; + if (strcmp(cei->state, "Bound") == 0) + bound = 1; + + if (bound || --maxwait < 0) { + if (didot) + putchar('\n'); + show_interface_msg(cei); + break; + } else { + didot = 1; + putchar('.'); + fflush(stdout); + } + imsg_free(&imsg); + sleep(1); + } + close(ctl_sock); + free(ibuf); + + return (0); +} + +void +show_interface_msg(struct ctl_engine_info *cei) +{ + struct timespec now, diff; + time_t d, h, m, s; + int i, has_pd = 0; + char buf[IF_NAMESIZE], *bufp; + char ntopbuf[INET6_ADDRSTRLEN]; + + bufp = if_indextoname(cei->if_index, buf); + printf("%s [%s]\n", bufp != NULL ? bufp : "unknown", cei->state); + + for (i = 0; i < MAX_IA; i++) { + if (cei->pds[i].prefix_len == 0) + continue; + has_pd = 1; + printf ("\tIA_PD %d: %s/%d\n", i, inet_ntop(AF_INET6, + &cei->pds[i], ntopbuf, INET6_ADDRSTRLEN), + cei->pds[i].prefix_len); + } + + if (has_pd) { + clock_gettime(CLOCK_MONOTONIC, &now); + timespecsub(&now, &cei->request_time, &diff); + s = cei->lease_time - diff.tv_sec; + if (s < 0) + s = 0; + + if ( s > 86400 ) { + d = s / 86400; + + /* round up */ + if (s - d * 86400 > 43200) + d++; + printf("\tlease %lld day%s\n", d, d > 1 ? "s" : ""); + } else if (s > 3600) { + h = s / 3600; + + /* round up */ + if (s - h * 3600 > 1800) + h++; + printf("\tlease %lld hour%s\n", h, h > 1 ? "s" : ""); + } else if (s > 60) { + m = s / 60; + + /* round up */ + if (s - m * 60 > 30) + m++; + printf("\tlease %lld minute%s\n", m, m > 1 ? "s" : ""); + } else + printf("\tlease %lld second%s\n", s, s > 1 ? "s" : ""); + + } +} -- 2.20.1