dhcp6leasectl
authorflorian <florian@openbsd.org>
Thu, 6 Jun 2024 15:16:57 +0000 (15:16 +0000)
committerflorian <florian@openbsd.org>
Thu, 6 Jun 2024 15:16:57 +0000 (15:16 +0000)
usr.sbin/dhcp6leasectl/Makefile [new file with mode: 0644]
usr.sbin/dhcp6leasectl/dhcp6leasectl.8 [new file with mode: 0644]
usr.sbin/dhcp6leasectl/dhcp6leasectl.c [new file with mode: 0644]

diff --git a/usr.sbin/dhcp6leasectl/Makefile b/usr.sbin/dhcp6leasectl/Makefile
new file mode 100644 (file)
index 0000000..0af424a
--- /dev/null
@@ -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 <bsd.prog.mk>
diff --git a/usr.sbin/dhcp6leasectl/dhcp6leasectl.8 b/usr.sbin/dhcp6leasectl/dhcp6leasectl.8
new file mode 100644 (file)
index 0000000..f5ebd9a
--- /dev/null
@@ -0,0 +1,73 @@
+.\"    $OpenBSD: dhcp6leasectl.8,v 1.1 2024/06/06 15:16:57 florian Exp $
+.\"
+.\" Copyright (c) 2021 Florian Obser <florian@openbsd.org>
+.\" Copyright (c) 2016 Kenneth R Westerback <kwesterback@gmail.com>
+.\" Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+.\"
+.\" 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 (file)
index 0000000..9398612
--- /dev/null
@@ -0,0 +1,240 @@
+/*     $OpenBSD: dhcp6leasectl.c,v 1.1 2024/06/06 15:16:57 florian Exp $       */
+
+/*
+ * Copyright (c) 2021, 2024 Florian Obser <florian@openbsd.org>
+ * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <arpa/inet.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <imsg.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#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" : "");
+
+       }
+}