1/* $OpenBSD: slaacctl.c,v 1.23 2022/03/21 16:25:47 florian Exp $ */ 2 3/* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21#include <sys/types.h> 22#include <sys/queue.h> 23#include <sys/socket.h> 24#include <sys/un.h> 25#include <arpa/inet.h> 26 27#include <net/if.h> 28#include <net/if_media.h> 29#include <net/if_types.h> 30 31#include <netinet/in.h> 32#include <netinet/if_ether.h> 33#include <netinet6/nd6.h> 34 35#include <err.h> 36#include <errno.h> 37#include <event.h> 38#include <imsg.h> 39#include <netdb.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <unistd.h> 44 45#include "slaacd.h" 46#include "frontend.h" 47#include "parser.h" 48 49__dead void usage(void); 50int show_interface_msg(struct imsg *); 51 52struct imsgbuf *ibuf; 53 54__dead void 55usage(void) 56{ 57 extern char *__progname; 58 59 fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 60 __progname); 61 exit(1); 62} 63 64int 65main(int argc, char *argv[]) 66{ 67 struct sockaddr_un sun; 68 struct parse_result *res; 69 struct imsg imsg; 70 int ctl_sock; 71 int done = 0; 72 int n, verbose = 0; 73 int ch; 74 char *sockname; 75 76 sockname = _PATH_SLAACD_SOCKET; 77 while ((ch = getopt(argc, argv, "s:")) != -1) { 78 switch (ch) { 79 case 's': 80 sockname = optarg; 81 break; 82 default: 83 usage(); 84 } 85 } 86 argc -= optind; 87 argv += optind; 88 89 if (pledge("stdio unix", NULL) == -1) 90 err(1, "pledge"); 91 92 /* Parse command line. */ 93 if ((res = parse(argc, argv)) == NULL) 94 exit(1); 95 96 /* Connect to control socket. */ 97 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 98 err(1, "socket"); 99 100 memset(&sun, 0, sizeof(sun)); 101 sun.sun_family = AF_UNIX; 102 strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 103 104 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 105 err(1, "connect: %s", sockname); 106 107 if (pledge("stdio", NULL) == -1) 108 err(1, "pledge"); 109 110 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 111 err(1, NULL); 112 imsg_init(ibuf, ctl_sock); 113 done = 0; 114 115 /* Process user request. */ 116 switch (res->action) { 117 case LOG_VERBOSE: 118 verbose = 1; 119 /* FALLTHROUGH */ 120 case LOG_BRIEF: 121 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 122 &verbose, sizeof(verbose)); 123 printf("logging request sent.\n"); 124 done = 1; 125 break; 126 case SHOW_INTERFACE: 127 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE_INFO, 0, 0, -1, 128 &res->if_index, sizeof(res->if_index)); 129 break; 130 case SEND_SOLICITATION: 131 imsg_compose(ibuf, IMSG_CTL_SEND_SOLICITATION, 0, 0, -1, 132 &res->if_index, sizeof(res->if_index)); 133 done = 1; 134 break; 135 default: 136 usage(); 137 } 138 139 while (ibuf->w.queued) 140 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 141 err(1, "write error"); 142 143 while (!done) { 144 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 145 errx(1, "imsg_read error"); 146 if (n == 0) 147 errx(1, "pipe closed"); 148 149 while (!done) { 150 if ((n = imsg_get(ibuf, &imsg)) == -1) 151 errx(1, "imsg_get error"); 152 if (n == 0) 153 break; 154 155 switch (res->action) { 156 case SHOW_INTERFACE: 157 done = show_interface_msg(&imsg); 158 break; 159 default: 160 break; 161 } 162 163 imsg_free(&imsg); 164 } 165 } 166 close(ctl_sock); 167 free(ibuf); 168 169 return (0); 170} 171 172int 173show_interface_msg(struct imsg *imsg) 174{ 175 static int if_count = 0; 176 struct ctl_engine_info *cei; 177 struct ctl_engine_info_ra *cei_ra; 178 struct ctl_engine_info_ra_prefix *cei_ra_prefix; 179 struct ctl_engine_info_ra_rdns *cei_ra_rdns; 180 struct ctl_engine_info_address_proposal *cei_addr_proposal; 181 struct ctl_engine_info_dfr_proposal *cei_dfr_proposal; 182 struct ctl_engine_info_rdns_proposal *cei_rdns_proposal; 183 struct tm *t; 184 struct timespec now, diff; 185 int i; 186 char buf[IF_NAMESIZE], *bufp; 187 char hbuf[NI_MAXHOST], whenbuf[255]; 188 char ntopbuf[INET6_ADDRSTRLEN]; 189 190 switch (imsg->hdr.type) { 191 case IMSG_CTL_SHOW_INTERFACE_INFO: 192 cei = imsg->data; 193 194 if (if_count++ > 0) 195 printf("\n"); 196 197 bufp = if_indextoname(cei->if_index, buf); 198 printf("%s:\n", bufp != NULL ? bufp : "unknown"); 199 printf("\t index: %3u ", cei->if_index); 200 printf("running: %3s ", cei->running ? "yes" : "no"); 201 printf("temporary: %3s\n", cei->temporary ? "yes" : 202 "no"); 203 printf("\tlladdr: %s\n", ether_ntoa(&cei->hw_address)); 204 if (getnameinfo((struct sockaddr *)&cei->ll_address, 205 cei->ll_address.sin6_len, hbuf, sizeof(hbuf), NULL, 0, 206 NI_NUMERICHOST | NI_NUMERICSERV)) 207 err(1, "cannot get link local address"); 208 printf("\t inet6: %s\n", hbuf); 209 break; 210 case IMSG_CTL_SHOW_INTERFACE_INFO_RA: 211 cei_ra = imsg->data; 212 213 if (getnameinfo((struct sockaddr *)&cei_ra->from, 214 cei_ra->from.sin6_len, hbuf, sizeof(hbuf), NULL, 0, 215 NI_NUMERICHOST | NI_NUMERICSERV)) 216 err(1, "cannot get router IP"); 217 218 if (clock_gettime(CLOCK_MONOTONIC, &now)) 219 err(1, "clock_gettime"); 220 221 timespecsub(&now, &cei_ra->uptime, &diff); 222 223 t = localtime(&cei_ra->when.tv_sec); 224 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 225 printf("\tRouter Advertisement from %s\n", hbuf); 226 printf("\t\treceived: %s; %llds ago\n", whenbuf, diff.tv_sec); 227 printf("\t\tCur Hop Limit: %3u, M: %d, O: %d, Router Lifetime:" 228 " %5us\n", cei_ra->curhoplimit, cei_ra->managed ? 1: 0, 229 cei_ra->other ? 1 : 0, cei_ra->router_lifetime); 230 printf("\t\tDefault Router Preference: %s\n", cei_ra->rpref); 231 printf("\t\tReachable Time: %9ums, Retrans Timer: %9ums\n", 232 cei_ra->reachable_time, cei_ra->retrans_time); 233 if (cei_ra->mtu) 234 printf("\t\tMTU: %u bytes\n", cei_ra->mtu); 235 break; 236 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX: 237 cei_ra_prefix = imsg->data; 238 printf("\t\tprefix: %s/%u\n", inet_ntop(AF_INET6, 239 &cei_ra_prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), 240 cei_ra_prefix->prefix_len); 241 printf("\t\t\tOn-link: %d, Autonomous address-configuration: %d" 242 "\n", cei_ra_prefix->onlink ? 1 : 0, 243 cei_ra_prefix->autonomous ? 1 : 0); 244 if (cei_ra_prefix->vltime == ND6_INFINITE_LIFETIME) 245 printf("\t\t\tvltime: %10s, ", "infinity"); 246 else 247 printf("\t\t\tvltime: %10u, ", cei_ra_prefix->vltime); 248 if (cei_ra_prefix->pltime == ND6_INFINITE_LIFETIME) 249 printf("pltime: %10s\n", "infinity"); 250 else 251 printf("pltime: %10u\n", cei_ra_prefix->pltime); 252 break; 253 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS: 254 cei_ra_rdns = imsg->data; 255 printf("\t\trdns: %s, lifetime: %u\n", inet_ntop(AF_INET6, 256 &cei_ra_rdns->rdns, ntopbuf, INET6_ADDRSTRLEN), 257 cei_ra_rdns->lifetime); 258 break; 259 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS: 260 printf("\tAddress proposals\n"); 261 break; 262 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL: 263 cei_addr_proposal = imsg->data; 264 265 if (getnameinfo((struct sockaddr *)&cei_addr_proposal->addr, 266 cei_addr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), 267 NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) 268 err(1, "cannot get proposal IP"); 269 270 printf("\t\tid: %4lld, state: %15s, temporary: %s\n", 271 cei_addr_proposal->id, cei_addr_proposal->state, 272 cei_addr_proposal->temporary ? "y" : "n"); 273 274 if (clock_gettime(CLOCK_MONOTONIC, &now)) 275 err(1, "clock_gettime"); 276 277 timespecsub(&now, &cei_addr_proposal->uptime, &diff); 278 279 if (cei_addr_proposal->vltime == ND6_INFINITE_LIFETIME) 280 printf("\t\tvltime: %10s, ", "infinity"); 281 else 282 printf("\t\tvltime: %10u, ", cei_addr_proposal->vltime); 283 if (cei_addr_proposal->pltime == ND6_INFINITE_LIFETIME) 284 printf("pltime: %10s", "infinity"); 285 else 286 printf("pltime: %10u", cei_addr_proposal->pltime); 287 if (cei_addr_proposal->next_timeout != 0) 288 printf(", timeout: %10llds\n", 289 cei_addr_proposal->next_timeout - diff.tv_sec); 290 else 291 printf("\n"); 292 293 t = localtime(&cei_addr_proposal->when.tv_sec); 294 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 295 printf("\t\tupdated: %s; %llds ago\n", whenbuf, diff.tv_sec); 296 printf("\t\t%s, %s/%u\n", hbuf, inet_ntop(AF_INET6, 297 &cei_addr_proposal->prefix, ntopbuf, INET6_ADDRSTRLEN), 298 cei_addr_proposal->prefix_len); 299 break; 300 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS: 301 printf("\tDefault router proposals\n"); 302 break; 303 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL: 304 cei_dfr_proposal = imsg->data; 305 306 if (getnameinfo((struct sockaddr *)&cei_dfr_proposal->addr, 307 cei_dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), 308 NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) 309 err(1, "cannot get router IP"); 310 311 printf("\t\tid: %4lld, state: %15s\n", 312 cei_dfr_proposal->id, cei_dfr_proposal->state); 313 printf("\t\trouter: %s\n", hbuf); 314 printf("\t\trouter lifetime: %10u\n", 315 cei_dfr_proposal->router_lifetime); 316 printf("\t\tPreference: %s\n", cei_dfr_proposal->rpref); 317 if (clock_gettime(CLOCK_MONOTONIC, &now)) 318 err(1, "clock_gettime"); 319 320 timespecsub(&now, &cei_dfr_proposal->uptime, &diff); 321 322 t = localtime(&cei_dfr_proposal->when.tv_sec); 323 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 324 printf("\t\tupdated: %s; %llds ago", whenbuf, diff.tv_sec); 325 if (cei_dfr_proposal->next_timeout != 0) 326 printf(", timeout: %10llds\n", 327 cei_dfr_proposal->next_timeout - diff.tv_sec); 328 else 329 printf("\n"); 330 331 break; 332 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSALS: 333 printf("\trDNS proposals\n"); 334 break; 335 case IMSG_CTL_SHOW_INTERFACE_INFO_RDNS_PROPOSAL: 336 cei_rdns_proposal = imsg->data; 337 338 if (getnameinfo((struct sockaddr *)&cei_rdns_proposal->from, 339 cei_rdns_proposal->from.sin6_len, hbuf, sizeof(hbuf), 340 NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) 341 err(1, "cannot get router IP"); 342 343 printf("\t\tid: %4lld, state: %15s\n", 344 cei_rdns_proposal->id, cei_rdns_proposal->state); 345 printf("\t\trouter: %s\n", hbuf); 346 printf("\t\trdns lifetime: %10u\n", 347 cei_rdns_proposal->rdns_lifetime); 348 printf("\t\trdns:\n"); 349 for (i = 0; i < cei_rdns_proposal->rdns_count; i++) { 350 printf("\t\t\t%s\n", inet_ntop(AF_INET6, 351 &cei_rdns_proposal->rdns[i], ntopbuf, 352 INET6_ADDRSTRLEN)); 353 } 354 355 if (clock_gettime(CLOCK_MONOTONIC, &now)) 356 err(1, "clock_gettime"); 357 358 timespecsub(&now, &cei_rdns_proposal->uptime, &diff); 359 360 t = localtime(&cei_rdns_proposal->when.tv_sec); 361 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 362 printf("\t\tupdated: %s; %llds ago", whenbuf, diff.tv_sec); 363 if (cei_rdns_proposal->next_timeout != 0) 364 printf(", timeout: %10llds\n", 365 cei_rdns_proposal->next_timeout - diff.tv_sec); 366 else 367 printf("\n"); 368 369 break; 370 case IMSG_CTL_END: 371 return (1); 372 default: 373 break; 374 } 375 376 return (0); 377} 378