slaacctl.c revision 1.9
1/* $OpenBSD: slaacctl.c,v 1.9 2017/08/18 18:42:20 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 = 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 /* Parse command line. */ 90 if ((res = parse(argc, argv)) == NULL) 91 exit(1); 92 93 /* Connect to control socket. */ 94 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 95 err(1, "socket"); 96 97 memset(&sun, 0, sizeof(sun)); 98 sun.sun_family = AF_UNIX; 99 100 strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 101 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 102 err(1, "connect: %s", sockname); 103 104 if (pledge("stdio", NULL) == -1) 105 err(1, "pledge"); 106 107 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 108 err(1, NULL); 109 imsg_init(ibuf, ctl_sock); 110 done = 0; 111 112 /* Process user request. */ 113 switch (res->action) { 114 case LOG_VERBOSE: 115 verbose = 1; 116 /* FALLTHROUGH */ 117 case LOG_BRIEF: 118 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 119 &verbose, sizeof(verbose)); 120 printf("logging request sent.\n"); 121 done = 1; 122 break; 123 case SHOW_INTERFACE: 124 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE_INFO, 0, 0, -1, 125 &res->if_index, sizeof(res->if_index)); 126 break; 127 case SEND_SOLICITATION: 128 imsg_compose(ibuf, IMSG_CTL_SEND_SOLICITATION, 0, 0, -1, 129 &res->if_index, sizeof(res->if_index)); 130 done = 1; 131 break; 132 default: 133 usage(); 134 } 135 136 while (ibuf->w.queued) 137 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 138 err(1, "write error"); 139 140 while (!done) { 141 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 142 errx(1, "imsg_read error"); 143 if (n == 0) 144 errx(1, "pipe closed"); 145 146 while (!done) { 147 if ((n = imsg_get(ibuf, &imsg)) == -1) 148 errx(1, "imsg_get error"); 149 if (n == 0) 150 break; 151 152 switch (res->action) { 153 case SHOW_INTERFACE: 154 done = show_interface_msg(&imsg); 155 break; 156 default: 157 break; 158 } 159 160 imsg_free(&imsg); 161 } 162 } 163 close(ctl_sock); 164 free(ibuf); 165 166 return (0); 167} 168 169int 170show_interface_msg(struct imsg *imsg) 171{ 172 static int if_count = 0; 173 struct ctl_engine_info *cei; 174 struct ctl_engine_info_ra *cei_ra; 175 struct ctl_engine_info_ra_prefix *cei_ra_prefix; 176 struct ctl_engine_info_ra_rdns *cei_ra_rdns; 177 struct ctl_engine_info_ra_dnssl *cei_ra_dnssl; 178 struct ctl_engine_info_address_proposal *cei_addr_proposal; 179 struct ctl_engine_info_dfr_proposal *cei_dfr_proposal; 180 struct tm *t; 181 struct timespec now, diff; 182 char buf[IF_NAMESIZE], *bufp; 183 char hbuf[NI_MAXHOST], whenbuf[255]; 184 char ntopbuf[INET6_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:\n", bufp != NULL ? bufp : "unknown"); 195 printf("\t index: %3u ", cei->if_index); 196 printf("running: %3s ", cei->running ? "yes" : "no"); 197 printf("privacy: %3s\n", cei->autoconfprivacy ? "yes" : "no"); 198 printf("\tlladdr: %s\n", ether_ntoa(&cei->hw_address)); 199 if (getnameinfo((struct sockaddr *)&cei->ll_address, 200 cei->ll_address.sin6_len, hbuf, sizeof(hbuf), NULL, 0, 201 NI_NUMERICHOST | NI_NUMERICSERV)) 202 err(1, "cannot get link local address"); 203 printf("\t inet6: %s\n", hbuf); 204 break; 205 case IMSG_CTL_SHOW_INTERFACE_INFO_RA: 206 cei_ra = imsg->data; 207 208 if (getnameinfo((struct sockaddr *)&cei_ra->from, 209 cei_ra->from.sin6_len, hbuf, sizeof(hbuf), NULL, 0, 210 NI_NUMERICHOST | NI_NUMERICSERV)) 211 err(1, "cannot get router IP"); 212 213 if (clock_gettime(CLOCK_MONOTONIC, &now)) 214 err(1, "clock_gettime"); 215 216 timespecsub(&now, &cei_ra->uptime, &diff); 217 218 t = localtime(&cei_ra->when.tv_sec); 219 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 220 printf("\tRouter Advertisement from %s\n", hbuf); 221 printf("\t\treceived: %s; %llds ago\n", whenbuf, diff.tv_sec); 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 if (cei_ra_prefix->vltime == ND6_INFINITE_LIFETIME) 238 printf("\t\t\tvltime: %10s, ", "infinity"); 239 else 240 printf("\t\t\tvltime: %10u, ", cei_ra_prefix->vltime); 241 if (cei_ra_prefix->pltime == ND6_INFINITE_LIFETIME) 242 printf("pltime: %10s\n", "infinity"); 243 else 244 printf("pltime: %10u\n", cei_ra_prefix->pltime); 245 break; 246 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS: 247 cei_ra_rdns = imsg->data; 248 printf("\t\trdns: %s, lifetime: %u\n", inet_ntop(AF_INET6, 249 &cei_ra_rdns->rdns, ntopbuf, INET6_ADDRSTRLEN), 250 cei_ra_rdns->lifetime); 251 break; 252 case IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL: 253 cei_ra_dnssl = imsg->data; 254 printf("\t\tsearch: %s, lifetime: %u\n", cei_ra_dnssl->dnssl, 255 cei_ra_dnssl->lifetime); 256 break; 257 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS: 258 printf("\tAddress proposals\n"); 259 break; 260 case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL: 261 cei_addr_proposal = imsg->data; 262 263 if (getnameinfo((struct sockaddr *)&cei_addr_proposal->addr, 264 cei_addr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), 265 NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) 266 err(1, "cannot get router IP"); 267 268 printf("\t\tid: %4lld, state: %15s, privacy: %s\n", 269 cei_addr_proposal->id, cei_addr_proposal->state, 270 cei_addr_proposal->privacy ? "y" : "n"); 271 if (cei_addr_proposal->vltime == ND6_INFINITE_LIFETIME) 272 printf("\t\tvltime: %10s, ", "infinity"); 273 else 274 printf("\t\tvltime: %10u, ", cei_addr_proposal->vltime); 275 if (cei_addr_proposal->pltime == ND6_INFINITE_LIFETIME) 276 printf("pltime: %10s\n", "infinity"); 277 else 278 printf("pltime: %10u\n", cei_addr_proposal->pltime); 279 280 if (clock_gettime(CLOCK_MONOTONIC, &now)) 281 err(1, "clock_gettime"); 282 283 timespecsub(&now, &cei_addr_proposal->uptime, &diff); 284 285 t = localtime(&cei_addr_proposal->when.tv_sec); 286 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 287 printf("\t\tupdated: %s; %llds ago\n", whenbuf, diff.tv_sec); 288 printf("\t\t%s, %s/%u\n", hbuf, inet_ntop(AF_INET6, 289 &cei_addr_proposal->prefix, ntopbuf, INET6_ADDRSTRLEN), 290 cei_addr_proposal->prefix_len); 291 break; 292 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS: 293 printf("\tDefault router proposals\n"); 294 break; 295 case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL: 296 cei_dfr_proposal = imsg->data; 297 298 if (getnameinfo((struct sockaddr *)&cei_dfr_proposal->addr, 299 cei_dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf), 300 NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) 301 err(1, "cannot get router IP"); 302 303 printf("\t\tid: %4lld, state: %15s\n", 304 cei_dfr_proposal->id, cei_dfr_proposal->state); 305 printf("\t\trouter lifetime: %10u\n", 306 cei_dfr_proposal->router_lifetime); 307 printf("\t\tPreference: %s\n", cei_dfr_proposal->rpref); 308 if (clock_gettime(CLOCK_MONOTONIC, &now)) 309 err(1, "clock_gettime"); 310 311 timespecsub(&now, &cei_dfr_proposal->uptime, &diff); 312 313 t = localtime(&cei_dfr_proposal->when.tv_sec); 314 strftime(whenbuf, sizeof(whenbuf), "%F %T", t); 315 printf("\t\tupdated: %s; %llds ago\n", whenbuf, diff.tv_sec); 316 317 break; 318 case IMSG_CTL_END: 319 printf("\n"); 320 return (1); 321 default: 322 break; 323 } 324 325 return (0); 326} 327