1 /* $OpenBSD: ikectl.c,v 1.36 2024/11/21 13:38:14 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2007-2013 Reyk Floeter <reyk@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/socket.h> 24 #include <sys/queue.h> 25 #include <sys/un.h> 26 #include <sys/tree.h> 27 28 #include <err.h> 29 #include <errno.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <event.h> 35 36 #include "iked.h" 37 #include "parser.h" 38 39 __dead void usage(void); 40 41 struct imsgname { 42 int type; 43 char *name; 44 void (*func)(struct imsg *); 45 }; 46 47 struct imsgname *monitor_lookup(uint8_t); 48 int monitor(struct imsg *); 49 50 int show_string(struct imsg *); 51 int show_stats(struct imsg *, int); 52 53 int ca_opt(struct parse_result *); 54 55 struct imsgname imsgs[] = { 56 { IMSG_CTL_OK, "ok", NULL }, 57 { IMSG_CTL_FAIL, "fail", NULL }, 58 { IMSG_CTL_VERBOSE, "verbose", NULL }, 59 { IMSG_CTL_RELOAD, "reload", NULL }, 60 { IMSG_CTL_RESET, "reset", NULL }, 61 { IMSG_CTL_SHOW_SA, "show sa", NULL }, 62 { IMSG_CTL_SHOW_CERTSTORE, "show certstore", NULL }, 63 { 0, NULL, NULL } 64 65 }; 66 struct imsgname imsgunknown = { 67 -1, "<unknown>", NULL 68 }; 69 70 struct imsgbuf *ibuf; 71 72 __dead void 73 usage(void) 74 { 75 extern char *__progname; 76 77 fprintf(stderr, "usage: %s [-q] [-s socket] command [arg ...]\n", 78 __progname); 79 exit(1); 80 } 81 82 int 83 ca_opt(struct parse_result *res) 84 { 85 struct ca *ca; 86 size_t len; 87 char *p; 88 89 ca = ca_setup(res->caname, (res->action == CA_CREATE), 90 res->quiet, res->pass); 91 if (ca == NULL) 92 errx(1, "ca_setup failed"); 93 94 /* assume paths are relative to /etc if not absolute */ 95 if (res->path && (res->path[0] != '.') && (res->path[0] != '/')) { 96 len = 5 + strlen(res->path) + 1; 97 if ((p = malloc(len)) == NULL) 98 err(1, "malloc"); 99 snprintf(p, len, "/etc/%s", res->path); 100 free(res->path); 101 res->path = p; 102 } 103 104 switch (res->action) { 105 case CA_CREATE: 106 ca_create(ca); 107 break; 108 case CA_DELETE: 109 ca_delete(ca); 110 break; 111 case CA_INSTALL: 112 ca_install(ca, res->path); 113 break; 114 case CA_EXPORT: 115 ca_export(ca, NULL, res->peer, res->pass); 116 break; 117 case CA_CERT_CREATE: 118 case CA_SERVER: 119 case CA_CLIENT: 120 case CA_OCSP: 121 ca_certificate(ca, res->host, res->htype, res->action); 122 break; 123 case CA_CERT_DELETE: 124 ca_delkey(ca, res->host); 125 break; 126 case CA_CERT_INSTALL: 127 ca_cert_install(ca, res->host, res->path); 128 break; 129 case CA_CERT_EXPORT: 130 ca_export(ca, res->host, res->peer, res->pass); 131 break; 132 case CA_CERT_REVOKE: 133 ca_revoke(ca, res->host); 134 break; 135 case SHOW_CA_CERTIFICATES: 136 ca_show_certs(ca, res->host); 137 break; 138 case CA_KEY_CREATE: 139 ca_key_create(ca, res->host); 140 break; 141 case CA_KEY_DELETE: 142 ca_key_delete(ca, res->host); 143 break; 144 case CA_KEY_INSTALL: 145 ca_key_install(ca, res->host, res->path); 146 break; 147 case CA_KEY_IMPORT: 148 ca_key_import(ca, res->host, res->path); 149 break; 150 default: 151 break; 152 } 153 154 return (0); 155 } 156 157 int 158 main(int argc, char *argv[]) 159 { 160 struct sockaddr_un s_un; 161 struct parse_result *res; 162 struct imsg imsg; 163 int ctl_sock; 164 int done = 1; 165 int n; 166 int ch; 167 int v = 0; 168 int quiet = 0; 169 const char *sock = IKED_SOCKET; 170 171 while ((ch = getopt(argc, argv, "qs:")) != -1) { 172 switch (ch) { 173 case 'q': 174 quiet = 1; 175 break; 176 case 's': 177 sock = optarg; 178 break; 179 default: 180 usage(); 181 /* NOTREACHED */ 182 } 183 } 184 argc -= optind; 185 argv += optind; 186 187 /* parse options */ 188 if ((res = parse(argc, argv)) == NULL) 189 exit(1); 190 191 res->quiet = quiet; 192 193 switch (res->action) { 194 case CA_CREATE: 195 case CA_DELETE: 196 case CA_INSTALL: 197 case CA_EXPORT: 198 case CA_CERT_CREATE: 199 case CA_CLIENT: 200 case CA_SERVER: 201 case CA_OCSP: 202 case CA_CERT_DELETE: 203 case CA_CERT_INSTALL: 204 case CA_CERT_EXPORT: 205 case CA_CERT_REVOKE: 206 case SHOW_CA: 207 case SHOW_CA_CERTIFICATES: 208 case CA_KEY_CREATE: 209 case CA_KEY_DELETE: 210 case CA_KEY_INSTALL: 211 case CA_KEY_IMPORT: 212 if (pledge("stdio proc exec rpath wpath cpath fattr tty", NULL) 213 == -1) 214 err(1, "pledge"); 215 ca_opt(res); 216 break; 217 case NONE: 218 usage(); 219 break; 220 default: 221 goto connect; 222 } 223 224 return (0); 225 226 connect: 227 /* connect to iked control socket */ 228 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 229 err(1, "socket"); 230 231 bzero(&s_un, sizeof(s_un)); 232 s_un.sun_family = AF_UNIX; 233 strlcpy(s_un.sun_path, sock, sizeof(s_un.sun_path)); 234 reconnect: 235 if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { 236 /* Keep retrying if running in monitor mode */ 237 if (res->action == MONITOR && 238 (errno == ENOENT || errno == ECONNREFUSED)) { 239 usleep(100); 240 goto reconnect; 241 } 242 err(1, "connect: %s", sock); 243 } 244 245 if (pledge("stdio", NULL) == -1) 246 err(1, "pledge"); 247 248 if (res->ibuf != NULL) 249 ibuf = res->ibuf; 250 else 251 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 252 err(1, "malloc"); 253 if (imsgbuf_init(ibuf, ctl_sock) == -1) 254 err(1, "imsgbuf_init"); 255 256 /* process user request */ 257 switch (res->action) { 258 case RESETALL: 259 v = RESET_ALL; 260 break; 261 case RESETCA: 262 v = RESET_CA; 263 break; 264 case RESETPOLICY: 265 v = RESET_POLICY; 266 break; 267 case RESETSA: 268 v = RESET_SA; 269 break; 270 case RESETUSER: 271 v = RESET_USER; 272 break; 273 case LOG_VERBOSE: 274 v = 2; 275 break; 276 case LOG_BRIEF: 277 default: 278 v = 0; 279 break; 280 } 281 282 switch (res->action) { 283 case NONE: 284 usage(); 285 /* NOTREACHED */ 286 break; 287 case RESETALL: 288 case RESETCA: 289 case RESETPOLICY: 290 case RESETSA: 291 case RESETUSER: 292 imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v)); 293 printf("reset request sent.\n"); 294 break; 295 case LOAD: 296 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, 297 res->path, strlen(res->path)); 298 break; 299 case RESET_ID: 300 imsg_compose(ibuf, IMSG_CTL_RESET_ID, 0, 0, -1, 301 res->id, strlen(res->id)); 302 break; 303 case SHOW_SA: 304 imsg_compose(ibuf, IMSG_CTL_SHOW_SA, 0, 0, -1, NULL, 0); 305 done = 0; 306 break; 307 case SHOW_STATS: 308 imsg_compose(ibuf, IMSG_CTL_SHOW_STATS, 0, 0, -1, NULL, 0); 309 done = 0; 310 break; 311 case SHOW_CERTSTORE: 312 imsg_compose(ibuf, IMSG_CTL_SHOW_CERTSTORE, 0, 0, -1, NULL, 0); 313 done = 0; 314 break; 315 case RELOAD: 316 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 317 break; 318 case MONITOR: 319 imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0); 320 done = 0; 321 break; 322 case COUPLE: 323 imsg_compose(ibuf, IMSG_CTL_COUPLE, 0, 0, -1, NULL, 0); 324 break; 325 case DECOUPLE: 326 imsg_compose(ibuf, IMSG_CTL_DECOUPLE, 0, 0, -1, NULL, 0); 327 break; 328 case ACTIVE: 329 imsg_compose(ibuf, IMSG_CTL_ACTIVE, 0, 0, -1, NULL, 0); 330 break; 331 case PASSIVE: 332 imsg_compose(ibuf, IMSG_CTL_PASSIVE, 0, 0, -1, NULL, 0); 333 break; 334 case LOG_VERBOSE: 335 case LOG_BRIEF: 336 imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &v, sizeof(v)); 337 printf("logging request sent.\n"); 338 break; 339 default: 340 break; 341 } 342 343 if (imsgbuf_flush(ibuf) == -1) 344 err(1, "write error"); 345 346 while (!done) { 347 if ((n = imsgbuf_read(ibuf)) == -1) 348 err(1, "read error"); 349 if (n == 0) 350 errx(1, "pipe closed"); 351 352 while (!done) { 353 if ((n = imsg_get(ibuf, &imsg)) == -1) 354 errx(1, "imsg_get error"); 355 if (n == 0) 356 break; 357 switch (res->action) { 358 case MONITOR: 359 done = monitor(&imsg); 360 break; 361 case SHOW_STATS: 362 done = show_stats(&imsg, quiet); 363 break; 364 case SHOW_SA: 365 case SHOW_CERTSTORE: 366 done = show_string(&imsg); 367 break; 368 default: 369 break; 370 } 371 imsg_free(&imsg); 372 } 373 } 374 close(ctl_sock); 375 free(ibuf); 376 377 return (0); 378 } 379 380 struct imsgname * 381 monitor_lookup(uint8_t type) 382 { 383 int i; 384 385 for (i = 0; imsgs[i].name != NULL; i++) 386 if (imsgs[i].type == type) 387 return (&imsgs[i]); 388 return (&imsgunknown); 389 } 390 391 int 392 monitor(struct imsg *imsg) 393 { 394 time_t now; 395 int done = 0; 396 struct imsgname *imn; 397 398 now = time(NULL); 399 400 imn = monitor_lookup(imsg->hdr.type); 401 printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name, 402 imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid); 403 printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now)); 404 if (imn->type == -1) 405 done = 1; 406 if (imn->func != NULL) 407 (*imn->func)(imsg); 408 409 return (done); 410 } 411 412 int 413 show_string(struct imsg *imsg) 414 { 415 int done = 0; 416 417 switch (imsg->hdr.type) { 418 case IMSG_CTL_SHOW_SA: 419 case IMSG_CTL_SHOW_CERTSTORE: 420 break; 421 default: 422 return (done); 423 } 424 if (IMSG_DATA_SIZE(imsg) > 0) 425 printf("%s", (char *)imsg->data); 426 else 427 done = 1; 428 429 return (done); 430 } 431 432 static char * 433 plural(uint64_t n) 434 { 435 return (n != 1 ? "s" : ""); 436 } 437 438 /* 439 * Dump IKE statistics structure. 440 */ 441 int 442 show_stats(struct imsg *imsg, int quiet) 443 { 444 struct iked_stats *stat; 445 int done = 1; 446 447 if (IMSG_DATA_SIZE(imsg) != sizeof(*stat)) 448 return (done); 449 stat = imsg->data; 450 printf("ike:\n"); 451 #define p(f, m) if (stat->f || !quiet) \ 452 printf(m, stat->f, plural(stat->f)) 453 454 p(ikes_sa_created, "\t%llu IKE SA%s created\n"); 455 p(ikes_sa_established_total, "\t%llu IKE SA%s established\n"); 456 p(ikes_sa_established_current, "\t%llu IKE SA%s currently established\n"); 457 p(ikes_sa_established_failures, "\t%llu IKE SA%s failed to establish\n"); 458 p(ikes_sa_proposals_negotiate_failures, "\t%llu failed proposal negotiation%s\n"); 459 p(ikes_sa_rekeyed, "\t%llu IKE SA%s rekeyed\n"); 460 p(ikes_sa_removed, "\t%llu IKE SA%s removed\n"); 461 p(ikes_csa_created, "\t%llu Child SA%s created\n"); 462 p(ikes_csa_removed, "\t%llu Child SA%s removed\n"); 463 p(ikes_msg_sent, "\t%llu message%s sent\n"); 464 p(ikes_msg_send_failures, "\t%llu message%s could not be sent\n"); 465 p(ikes_msg_rcvd, "\t%llu message%s received\n"); 466 p(ikes_msg_rcvd_dropped, "\t%llu message%s dropped\n"); 467 p(ikes_msg_rcvd_busy, "\t%llu request%s dropped, response being worked on\n"); 468 p(ikes_retransmit_response, "\t%llu response%s retransmitted\n"); 469 p(ikes_retransmit_request, "\t%llu request%s retransmitted\n"); 470 p(ikes_retransmit_limit, "\t%llu request%s timed out\n"); 471 p(ikes_frag_sent, "\t%llu fragment%s sent\n"); 472 p(ikes_frag_send_failures, "\t%llu fragment%s could not be sent\n"); 473 p(ikes_frag_rcvd, "\t%llu fragment%s received\n"); 474 p(ikes_frag_rcvd_drop, "\t%llu fragment%s dropped\n"); 475 p(ikes_frag_reass_ok, "\t%llu fragment%s reassembled\n"); 476 p(ikes_frag_reass_drop, "\t%llu fragment%s could not be reassembled\n"); 477 p(ikes_update_addresses_sent, "\t%llu update addresses request%s sent\n"); 478 p(ikes_dpd_sent, "\t%llu dpd request%s sent\n"); 479 p(ikes_keepalive_sent, "\t%llu keepalive message%s sent\n"); 480 #undef p 481 return (done); 482 } 483