slaacctl.c revision 1.7
1/* $OpenBSD: slaacctl.c,v 1.7 2017/05/30 18:18:08 deraadt 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 34#include <err.h> 35#include <errno.h> 36#include <event.h> 37#include <imsg.h> 38#include <netdb.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43 44#include "slaacd.h" 45#include "frontend.h" 46#include "parser.h" 47 48__dead void usage(void); 49int show_interface_msg(struct imsg *); 50 51struct imsgbuf *ibuf; 52 53__dead void 54usage(void) 55{ 56 extern char *__progname; 57 58 fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 59 __progname); 60 exit(1); 61} 62 63int 64main(int argc, char *argv[]) 65{ 66 struct sockaddr_un sun; 67 struct parse_result *res; 68 struct imsg imsg; 69 int ctl_sock; 70 int done = 0; 71 int n, verbose = 0; 72 int ch; 73 char *sockname; 74 75 sockname = SLAACD_SOCKET; 76 while ((ch = getopt(argc, argv, "s:")) != -1) { 77 switch (ch) { 78 case 's': 79 sockname = optarg; 80 break; 81 default: 82 usage(); 83 } 84 } 85 argc -= optind; 86 argv += optind; 87 88 /* Parse command line. */ 89 if ((res = parse(argc, argv)) == NULL) 90 exit(1); 91 92 /* Connect to control socket. */ 93 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 94 err(1, "socket"); 95 96 memset(&sun, 0, sizeof(sun)); 97 sun.sun_family = AF_UNIX; 98 99 strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 100 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 101 err(1, "connect: %s", sockname); 102 103 if (pledge("stdio", NULL) == -1) 104 err(1, "pledge"); 105 106 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 107 err(1, NULL); 108 imsg_init(ibuf, ctl_sock); 109 done = 0; 110 111 /* Process user request. */ 112 switch (res->action) { 113 case LOG_VERBOSE: 114 verbose = 1; 115 /* FALLTHROUGH */ 116 case LOG_BRIEF: 117 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 118 &verbose, sizeof(verbose)); 119 printf("logging request sent.\n"); 120 done = 1; 121 break; 122 case SHOW_INTERFACE: 123 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE_INFO, 0, 0, -1, 124 &res->if_index, sizeof(res->if_index)); 125 break; 126 case SEND_SOLICITATION: 127 imsg_compose(ibuf, IMSG_CTL_SEND_SOLICITATION, 0, 0, -1, 128 &res->if_index, sizeof(res->if_index)); 129 done = 1; 130 break; 131 default: 132 usage(); 133 } 134 135 while (ibuf->w.queued) 136 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 137 err(1, "write error"); 138 139 while (!done) { 140 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 141 errx(1, "imsg_read error"); 142 if (n == 0) 143 errx(1, "pipe closed"); 144 145 while (!done) { 146 if ((n = imsg_get(ibuf, &imsg)) == -1) 147 errx(1, "imsg_get error"); 148 if (n == 0) 149 break; 150 151 switch (res->action) { 152 case SHOW_INTERFACE: 153 done = show_interface_msg(&imsg); 154 break; 155 default: 156 break; 157 } 158 159 imsg_free(&imsg); 160 } 161 } 162 close(ctl_sock); 163 free(ibuf); 164 165 return (0); 166} 167 168int 169show_interface_msg(struct imsg *imsg) 170{ 171 static int if_count = 0; 172 struct ctl_engine_info *cei; 173 struct ctl_engine_info_ra *cei_ra; 174 struct ctl_engine_info_ra_prefix *cei_ra_prefix; 175 struct ctl_engine_info_ra_rdns *cei_ra_rdns; 176 struct ctl_engine_info_ra_dnssl *cei_ra_dnssl; 177 struct ctl_engine_info_address_proposal *cei_addr_proposal; 178 struct ctl_engine_info_dfr_proposal *cei_dfr_proposal; 179 struct tm *t; 180 struct timespec now, diff; 181 char buf[IF_NAMESIZE], *bufp; 182 char hbuf[NI_MAXHOST], whenbuf[255]; 183 char ntopbuf[INET6_ADDRSTRLEN]; 184 185 switch (imsg->hdr.type) { 186 case IMSG_CTL_SHOW_INTERFACE_INFO: 187 cei = imsg->data; 188 189 if (if_count++ > 0) 190 printf("\n"); 191 192 bufp = if_indextoname(cei->if_index, buf); 193 printf("%s:\n", bufp != NULL ? bufp : "unknown"); 194 printf("\t index: %3u ", cei->if_index); 195 printf("running: %3s ", cei->running ? "yes" : "no"); 196 printf("privacy: %3s\n", cei->autoconfprivacy ? "yes" : "no"); 197 printf("\tlladdr: %s\n", ether_ntoa(&cei->hw_address)); 198 if (getnameinfo((struct sockaddr *)&cei->ll_address, 199 cei->ll_address.sin6_len, hbuf, sizeof(hbuf), NULL, 0, 200 NI_NUMERICHOST | NI_NUMERICSERV)) 201 err(1, "cannot get link local address"); 202 printf("\t inet6: %s\n", hbuf); 203 break; 204 case IMSG_CTL_SHOW_INTERFACE_INFO_RA: 205 cei_ra = imsg->data; 206 207 if (getnameinfo((struct sockaddr *)&cei_ra->from, 208 cei_ra->from.sin6_len, hbuf, sizeof(hbuf), NULL, 0, 209 NI_NUMERICHOST | NI_NUMERICSERV)) 210 err(1, "cannot get router IP"); 211 212 if (clock_gettime(CLOCK_MONOTONIC, &now)) 213 err(1, "clock_gettime"); 214 215 timespecsub(&now, &cei_ra->uptime, &diff); 216 217 t = localtime(&cei_ra->when.tv_sec); 218 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 219 printf("\tRouter Advertisement from %s\n", hbuf); 220 printf("\t\treceived: %s.%09ld; %lld.%09lds ago\n", 221 whenbuf, cei_ra->when.tv_nsec, diff.tv_sec, diff.tv_nsec); 222 printf("\t\tCur Hop Limit: %3u, M: %d, O: %d, Router Lifetime:" 223 " %5us\n", cei_ra->curhoplimit, cei_ra->managed ? 1: 0, 224 cei_ra->other ? 1 : 0, cei_ra->router_lifetime); 225 printf("\t\tDefault Router Preference: %s\n", cei_ra->rpref); 226 printf("\t\tReachable Time: %9ums, Retrans Timer: %9ums\n", 227 cei_ra->reachable_time, cei_ra->retrans_time); 228 break; 229 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX: 230 cei_ra_prefix = imsg->data; 231 printf("\t\tprefix: %s/%u\n", inet_ntop(AF_INET6, 232 &cei_ra_prefix->prefix, ntopbuf, INET6_ADDRSTRLEN), 233 cei_ra_prefix->prefix_len); 234 printf("\t\t\tOn-link: %d, Autonomous address-configuration: %d" 235 "\n", cei_ra_prefix->onlink ? 1 : 0, 236 cei_ra_prefix->autonomous ? 1 : 0); 237 printf("\t\t\tvltime: %9u, pltime: %9u\n", 238 cei_ra_prefix->vltime, cei_ra_prefix->pltime); 239 break; 240 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS: 241 cei_ra_rdns = imsg->data; 242 printf("\t\trdns: %s, lifetime: %u\n", inet_ntop(AF_INET6, 243 &cei_ra_rdns->rdns, ntopbuf, INET6_ADDRSTRLEN), 244 cei_ra_rdns->lifetime); 245 break; 246 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL: 247 cei_ra_dnssl = imsg->data; 248 printf("\t\tsearch: %s, lifetime: %u\n", cei_ra_dnssl->dnssl, 249 cei_ra_dnssl->lifetime); 250 break; 251 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS: 252 printf("\tAddress proposals\n"); 253 break; 254 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL: 255 cei_addr_proposal = imsg->data; 256 257 if (getnameinfo((struct sockaddr *)&cei_addr_proposal->addr, 258 cei_addr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), 259 NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) 260 err(1, "cannot get router IP"); 261 262 printf("\t\tid: %4lld, state: %15s, privacy: %s\n", 263 cei_addr_proposal->id, cei_addr_proposal->state, 264 cei_addr_proposal->privacy ? "y" : "n"); 265 printf("\t\tvltime: %10u, pltime: %10u\n", 266 cei_addr_proposal->vltime, cei_addr_proposal->pltime); 267 268 if (clock_gettime(CLOCK_MONOTONIC, &now)) 269 err(1, "clock_gettime"); 270 271 timespecsub(&now, &cei_addr_proposal->uptime, &diff); 272 273 t = localtime(&cei_addr_proposal->when.tv_sec); 274 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 275 printf("\t\tupdated: %s.%09ld; %lld.%09lds ago\n", 276 whenbuf, cei_addr_proposal->when.tv_nsec, diff.tv_sec, 277 diff.tv_nsec); 278 printf("\t\t%s, %s/%u\n", hbuf, inet_ntop(AF_INET6, 279 &cei_addr_proposal->prefix, ntopbuf, INET6_ADDRSTRLEN), 280 cei_addr_proposal->prefix_len); 281 break; 282 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS: 283 printf("\tDefault router proposals\n"); 284 break; 285 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL: 286 cei_dfr_proposal = imsg->data; 287 288 if (getnameinfo((struct sockaddr *)&cei_dfr_proposal->addr, 289 cei_dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), 290 NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) 291 err(1, "cannot get router IP"); 292 293 printf("\t\tid: %4lld, state: %15s\n", 294 cei_dfr_proposal->id, cei_dfr_proposal->state); 295 printf("\t\trouter lifetime: %10u\n", 296 cei_dfr_proposal->router_lifetime); 297 printf("\t\tPreference: %s\n", cei_dfr_proposal->rpref); 298 if (clock_gettime(CLOCK_MONOTONIC, &now)) 299 err(1, "clock_gettime"); 300 301 timespecsub(&now, &cei_dfr_proposal->uptime, &diff); 302 303 t = localtime(&cei_dfr_proposal->when.tv_sec); 304 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 305 printf("\t\tupdated: %s.%09ld; %lld.%09lds ago\n", 306 whenbuf, cei_dfr_proposal->when.tv_nsec, diff.tv_sec, 307 diff.tv_nsec); 308 309 break; 310 case IMSG_CTL_END: 311 printf("\n"); 312 return (1); 313 default: 314 break; 315 } 316 317 return (0); 318} 319