1 /* $OpenBSD: dhcpleasectl.c,v 1.3 2021/03/23 17:46:20 florian Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 7 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/un.h> 26 #include <arpa/inet.h> 27 28 #include <net/if.h> 29 #include <net/if_media.h> 30 #include <net/if_types.h> 31 32 #include <netinet/in.h> 33 #include <netinet/if_ether.h> 34 #include <netinet6/nd6.h> 35 36 #include <err.h> 37 #include <errno.h> 38 #include <event.h> 39 #include <imsg.h> 40 #include <netdb.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "dhcpleased.h" 47 #include "frontend.h" 48 #include "parser.h" 49 50 __dead void usage(void); 51 int show_interface_msg(struct imsg *); 52 53 struct imsgbuf *ibuf; 54 55 __dead void 56 usage(void) 57 { 58 extern char *__progname; 59 60 fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 61 __progname); 62 exit(1); 63 } 64 65 int 66 main(int argc, char *argv[]) 67 { 68 struct sockaddr_un sun; 69 struct parse_result *res; 70 struct imsg imsg; 71 int ctl_sock; 72 int done = 0; 73 int n, verbose = 0; 74 int ch; 75 char *sockname; 76 77 sockname = _PATH_DHCPLEASED_SOCKET; 78 while ((ch = getopt(argc, argv, "s:")) != -1) { 79 switch (ch) { 80 case 's': 81 sockname = optarg; 82 break; 83 default: 84 usage(); 85 } 86 } 87 argc -= optind; 88 argv += optind; 89 90 if (pledge("stdio unix", NULL) == -1) 91 err(1, "pledge"); 92 93 /* Parse command line. */ 94 if ((res = parse(argc, argv)) == NULL) 95 exit(1); 96 97 /* Connect to control socket. */ 98 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 99 err(1, "socket"); 100 101 memset(&sun, 0, sizeof(sun)); 102 sun.sun_family = AF_UNIX; 103 strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 104 105 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 106 err(1, "connect: %s", sockname); 107 108 if (pledge("stdio", NULL) == -1) 109 err(1, "pledge"); 110 111 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 112 err(1, NULL); 113 imsg_init(ibuf, ctl_sock); 114 done = 0; 115 116 /* Process user request. */ 117 switch (res->action) { 118 case LOG_VERBOSE: 119 verbose = 1; 120 /* FALLTHROUGH */ 121 case LOG_BRIEF: 122 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 123 &verbose, sizeof(verbose)); 124 printf("logging request sent.\n"); 125 done = 1; 126 break; 127 case SHOW_INTERFACE: 128 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE_INFO, 0, 0, -1, 129 &res->if_index, sizeof(res->if_index)); 130 break; 131 case SEND_REQUEST: 132 imsg_compose(ibuf, IMSG_CTL_SEND_REQUEST, 0, 0, -1, 133 &res->if_index, sizeof(res->if_index)); 134 done = 1; 135 break; 136 default: 137 usage(); 138 } 139 140 while (ibuf->w.queued) 141 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 142 err(1, "write error"); 143 144 while (!done) { 145 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 146 errx(1, "imsg_read error"); 147 if (n == 0) 148 errx(1, "pipe closed"); 149 150 while (!done) { 151 if ((n = imsg_get(ibuf, &imsg)) == -1) 152 errx(1, "imsg_get error"); 153 if (n == 0) 154 break; 155 156 switch (res->action) { 157 case SHOW_INTERFACE: 158 done = show_interface_msg(&imsg); 159 break; 160 default: 161 break; 162 } 163 164 imsg_free(&imsg); 165 } 166 } 167 close(ctl_sock); 168 free(ibuf); 169 170 return (0); 171 } 172 173 int 174 show_interface_msg(struct imsg *imsg) 175 { 176 static int if_count = 0; 177 struct ctl_engine_info *cei; 178 struct timespec now, diff; 179 time_t y, d, h, m, s; 180 int i; 181 char buf[IF_NAMESIZE], *bufp; 182 char ipbuf[INET_ADDRSTRLEN]; 183 char maskbuf[INET_ADDRSTRLEN]; 184 char routerbuf[INET_ADDRSTRLEN]; 185 186 switch (imsg->hdr.type) { 187 case IMSG_CTL_SHOW_INTERFACE_INFO: 188 cei = imsg->data; 189 190 if (if_count++ > 0) 191 printf("\n"); 192 193 bufp = if_indextoname(cei->if_index, buf); 194 printf("%s [%s]:\n", bufp != NULL ? bufp : "unknown", 195 cei->state); 196 memset(ipbuf, 0, sizeof(ipbuf)); 197 if (cei->server_identifier.s_addr != INADDR_ANY) { 198 if (inet_ntop(AF_INET, &cei->server_identifier, ipbuf, 199 sizeof(ipbuf)) == NULL) 200 ipbuf[0] = '\0'; 201 } else if (cei->dhcp_server.s_addr != INADDR_ANY) { 202 if (inet_ntop(AF_INET, &cei->dhcp_server, ipbuf, 203 sizeof(ipbuf)) == NULL) 204 ipbuf[0] = '\0'; 205 } 206 if (ipbuf[0] != '\0') 207 printf("\tserver: %s\n", ipbuf); 208 if (cei->requested_ip.s_addr != INADDR_ANY) { 209 clock_gettime(CLOCK_MONOTONIC, &now); 210 timespecsub(&now, &cei->request_time, &diff); 211 memset(ipbuf, 0, sizeof(ipbuf)); 212 memset(maskbuf, 0, sizeof(maskbuf)); 213 memset(routerbuf, 0, sizeof(routerbuf)); 214 if (inet_ntop(AF_INET, &cei->requested_ip, ipbuf, 215 sizeof(ipbuf)) == NULL) 216 ipbuf[0] = '\0'; 217 if (inet_ntop(AF_INET, &cei->mask, maskbuf, 218 sizeof(maskbuf)) == NULL) 219 maskbuf[0] = '\0'; 220 if (inet_ntop(AF_INET, &cei->router, routerbuf, 221 sizeof(routerbuf)) == NULL) 222 routerbuf[0] = '\0'; 223 printf("\t IP: %s/%s\n", ipbuf, maskbuf); 224 if (cei->router.s_addr != INADDR_ANY) 225 printf("\trouter: %s\n", routerbuf); 226 if (cei->nameservers[0].s_addr != INADDR_ANY) { 227 printf("\t DNS:"); 228 for (i = 0; i < MAX_RDNS_COUNT && 229 cei->nameservers[i].s_addr != INADDR_ANY; 230 i++) { 231 if (inet_ntop(AF_INET, 232 &cei->nameservers[i], ipbuf, 233 sizeof(ipbuf)) == NULL) 234 continue; 235 printf(" %s", ipbuf); 236 } 237 printf("\n"); 238 } 239 s = cei->lease_time - diff.tv_sec; 240 if (s < 0) 241 s = 0; 242 y = s / 31556926; s -= y * 31556926; 243 d = s / 86400; s -= d * 86400; 244 h = s / 3600; s -= h * 3600; 245 m = s / 60; s -= m * 60; 246 247 printf("\t lease: "); 248 if (y > 0) 249 printf("%lldy ", y); 250 if (d > 0) 251 printf("%lldd ", d); 252 if (h > 0) 253 printf("%lldh ", h); 254 if (m > 0) 255 printf("%lldm ", m); 256 if (s > 0) 257 printf("%llds ", s); 258 printf("\n"); 259 } 260 break; 261 case IMSG_CTL_END: 262 return (1); 263 default: 264 break; 265 } 266 267 return (0); 268 } 269