main.c revision 1.214
1/* $OpenBSD: main.c,v 1.214 2022/08/30 18:56:49 job Exp $ */ 2/* 3 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org> 4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20#include <sys/queue.h> 21#include <sys/socket.h> 22#include <sys/resource.h> 23#include <sys/statvfs.h> 24#include <sys/tree.h> 25#include <sys/wait.h> 26 27#include <assert.h> 28#include <ctype.h> 29#include <err.h> 30#include <errno.h> 31#include <dirent.h> 32#include <fcntl.h> 33#include <fnmatch.h> 34#include <poll.h> 35#include <pwd.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <signal.h> 39#include <string.h> 40#include <limits.h> 41#include <syslog.h> 42#include <unistd.h> 43#include <imsg.h> 44 45#include "extern.h" 46#include "version.h" 47 48const char *tals[TALSZ_MAX]; 49const char *taldescs[TALSZ_MAX]; 50unsigned int talrepocnt[TALSZ_MAX]; 51int talsz; 52 53size_t entity_queue; 54int timeout = 60*60; 55volatile sig_atomic_t killme; 56void suicide(int sig); 57 58static struct filepath_tree fpt = RB_INITIALIZER(&fpt); 59static struct msgbuf procq, rsyncq, httpq, rrdpq; 60static int cachefd, outdirfd; 61 62const char *bird_tablename = "ROAS"; 63 64int verbose; 65int noop; 66int filemode; 67int rrdpon = 1; 68int repo_timeout; 69 70struct skiplist skiplist = LIST_HEAD_INITIALIZER(skiplist); 71 72struct stats stats; 73 74/* 75 * Log a message to stderr if and only if "verbose" is non-zero. 76 * This uses the err(3) functionality. 77 */ 78void 79logx(const char *fmt, ...) 80{ 81 va_list ap; 82 83 if (verbose && fmt != NULL) { 84 va_start(ap, fmt); 85 vwarnx(fmt, ap); 86 va_end(ap); 87 } 88} 89 90time_t 91getmonotime(void) 92{ 93 struct timespec ts; 94 95 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 96 err(1, "clock_gettime"); 97 return (ts.tv_sec); 98} 99 100void 101entity_free(struct entity *ent) 102{ 103 if (ent == NULL) 104 return; 105 106 free(ent->path); 107 free(ent->file); 108 free(ent->data); 109 free(ent); 110} 111 112/* 113 * Read a queue entity from the descriptor. 114 * Matched by entity_buffer_req(). 115 * The pointer must be passed entity_free(). 116 */ 117void 118entity_read_req(struct ibuf *b, struct entity *ent) 119{ 120 io_read_buf(b, &ent->type, sizeof(ent->type)); 121 io_read_buf(b, &ent->location, sizeof(ent->location)); 122 io_read_buf(b, &ent->repoid, sizeof(ent->repoid)); 123 io_read_buf(b, &ent->talid, sizeof(ent->talid)); 124 io_read_str(b, &ent->path); 125 io_read_str(b, &ent->file); 126 io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz); 127} 128 129/* 130 * Write the queue entity. 131 * Matched by entity_read_req(). 132 */ 133static void 134entity_write_req(const struct entity *ent) 135{ 136 struct ibuf *b; 137 138 b = io_new_buffer(); 139 io_simple_buffer(b, &ent->type, sizeof(ent->type)); 140 io_simple_buffer(b, &ent->location, sizeof(ent->location)); 141 io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid)); 142 io_simple_buffer(b, &ent->talid, sizeof(ent->talid)); 143 io_str_buffer(b, ent->path); 144 io_str_buffer(b, ent->file); 145 io_buf_buffer(b, ent->data, ent->datasz); 146 io_close_buffer(&procq, b); 147} 148 149static void 150entity_write_repo(struct repo *rp) 151{ 152 struct ibuf *b; 153 enum rtype type = RTYPE_REPO; 154 enum location loc = DIR_UNKNOWN; 155 unsigned int repoid; 156 char *path, *altpath; 157 int talid = 0; 158 159 repoid = repo_id(rp); 160 path = repo_basedir(rp, 0); 161 altpath = repo_basedir(rp, 1); 162 b = io_new_buffer(); 163 io_simple_buffer(b, &type, sizeof(type)); 164 io_simple_buffer(b, &loc, sizeof(loc)); 165 io_simple_buffer(b, &repoid, sizeof(repoid)); 166 io_simple_buffer(b, &talid, sizeof(talid)); 167 io_str_buffer(b, path); 168 io_str_buffer(b, altpath); 169 io_buf_buffer(b, NULL, 0); 170 io_close_buffer(&procq, b); 171 free(path); 172 free(altpath); 173} 174 175/* 176 * Scan through all queued requests and see which ones are in the given 177 * repo, then flush those into the parser process. 178 */ 179void 180entityq_flush(struct entityq *q, struct repo *rp) 181{ 182 struct entity *p, *np; 183 184 entity_write_repo(rp); 185 186 TAILQ_FOREACH_SAFE(p, q, entries, np) { 187 entity_write_req(p); 188 TAILQ_REMOVE(q, p, entries); 189 entity_free(p); 190 } 191} 192 193/* 194 * Add the heap-allocated file to the queue for processing. 195 */ 196static void 197entityq_add(char *path, char *file, enum rtype type, enum location loc, 198 struct repo *rp, unsigned char *data, size_t datasz, int talid) 199{ 200 struct entity *p; 201 202 if ((p = calloc(1, sizeof(struct entity))) == NULL) 203 err(1, NULL); 204 205 p->type = type; 206 p->location = loc; 207 p->talid = talid; 208 p->path = path; 209 if (rp != NULL) 210 p->repoid = repo_id(rp); 211 p->file = file; 212 p->data = data; 213 p->datasz = (data != NULL) ? datasz : 0; 214 215 entity_queue++; 216 217 /* 218 * Write to the queue if there's no repo or the repo has already 219 * been loaded else enqueue it for later. 220 */ 221 222 if (rp == NULL || !repo_queued(rp, p)) { 223 entity_write_req(p); 224 entity_free(p); 225 } 226} 227 228static void 229rrdp_file_resp(unsigned int id, int ok) 230{ 231 enum rrdp_msg type = RRDP_FILE; 232 struct ibuf *b; 233 234 b = io_new_buffer(); 235 io_simple_buffer(b, &type, sizeof(type)); 236 io_simple_buffer(b, &id, sizeof(id)); 237 io_simple_buffer(b, &ok, sizeof(ok)); 238 io_close_buffer(&rrdpq, b); 239} 240 241void 242rrdp_fetch(unsigned int id, const char *uri, const char *local, 243 struct rrdp_session *s) 244{ 245 enum rrdp_msg type = RRDP_START; 246 struct ibuf *b; 247 248 b = io_new_buffer(); 249 io_simple_buffer(b, &type, sizeof(type)); 250 io_simple_buffer(b, &id, sizeof(id)); 251 io_str_buffer(b, local); 252 io_str_buffer(b, uri); 253 io_str_buffer(b, s->session_id); 254 io_simple_buffer(b, &s->serial, sizeof(s->serial)); 255 io_str_buffer(b, s->last_mod); 256 io_close_buffer(&rrdpq, b); 257} 258 259/* 260 * Request a repository sync via rsync URI to directory local. 261 */ 262void 263rsync_fetch(unsigned int id, const char *uri, const char *local, 264 const char *base) 265{ 266 struct ibuf *b; 267 268 b = io_new_buffer(); 269 io_simple_buffer(b, &id, sizeof(id)); 270 io_str_buffer(b, local); 271 io_str_buffer(b, base); 272 io_str_buffer(b, uri); 273 io_close_buffer(&rsyncq, b); 274} 275 276/* 277 * Request a file from a https uri, data is written to the file descriptor fd. 278 */ 279void 280http_fetch(unsigned int id, const char *uri, const char *last_mod, int fd) 281{ 282 struct ibuf *b; 283 284 b = io_new_buffer(); 285 io_simple_buffer(b, &id, sizeof(id)); 286 io_str_buffer(b, uri); 287 io_str_buffer(b, last_mod); 288 /* pass file as fd */ 289 b->fd = fd; 290 io_close_buffer(&httpq, b); 291} 292 293/* 294 * Request some XML file on behalf of the rrdp parser. 295 * Create a pipe and pass the pipe endpoints to the http and rrdp process. 296 */ 297static void 298rrdp_http_fetch(unsigned int id, const char *uri, const char *last_mod) 299{ 300 enum rrdp_msg type = RRDP_HTTP_INI; 301 struct ibuf *b; 302 int pi[2]; 303 304 if (pipe2(pi, O_CLOEXEC | O_NONBLOCK) == -1) 305 err(1, "pipe"); 306 307 b = io_new_buffer(); 308 io_simple_buffer(b, &type, sizeof(type)); 309 io_simple_buffer(b, &id, sizeof(id)); 310 b->fd = pi[0]; 311 io_close_buffer(&rrdpq, b); 312 313 http_fetch(id, uri, last_mod, pi[1]); 314} 315 316void 317rrdp_http_done(unsigned int id, enum http_result res, const char *last_mod) 318{ 319 enum rrdp_msg type = RRDP_HTTP_FIN; 320 struct ibuf *b; 321 322 /* RRDP request, relay response over to the rrdp process */ 323 b = io_new_buffer(); 324 io_simple_buffer(b, &type, sizeof(type)); 325 io_simple_buffer(b, &id, sizeof(id)); 326 io_simple_buffer(b, &res, sizeof(res)); 327 io_str_buffer(b, last_mod); 328 io_close_buffer(&rrdpq, b); 329} 330 331/* 332 * Add a file (CER, ROA, CRL) from an MFT file, RFC 6486. 333 * These are always relative to the directory in which "mft" sits. 334 */ 335static void 336queue_add_from_mft(const struct mft *mft, struct repo *rp) 337{ 338 size_t i; 339 const struct mftfile *f; 340 char *nfile, *npath = NULL; 341 342 for (i = 0; i < mft->filesz; i++) { 343 f = &mft->files[i]; 344 345 if (f->type == RTYPE_INVALID) 346 continue; 347 348 if (mft->path != NULL) 349 if ((npath = strdup(mft->path)) == NULL) 350 err(1, NULL); 351 if ((nfile = strdup(f->file)) == NULL) 352 err(1, NULL); 353 entityq_add(npath, nfile, f->type, f->location, rp, NULL, 0, 354 -1); 355 } 356} 357 358/* 359 * Add a local file to the queue of files to fetch. 360 */ 361static void 362queue_add_file(const char *file, enum rtype type, int talid) 363{ 364 unsigned char *buf = NULL; 365 char *nfile; 366 size_t len = 0; 367 368 if (!filemode || strncmp(file, "rsync://", strlen("rsync://")) != 0) { 369 buf = load_file(file, &len); 370 if (buf == NULL) 371 err(1, "%s", file); 372 } 373 374 if ((nfile = strdup(file)) == NULL) 375 err(1, NULL); 376 /* Not in a repository, so directly add to queue. */ 377 entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid); 378} 379 380/* 381 * Add URIs (CER) from a TAL file, RFC 8630. 382 */ 383static void 384queue_add_from_tal(struct tal *tal) 385{ 386 struct repo *repo; 387 unsigned char *data; 388 char *nfile; 389 390 assert(tal->urisz); 391 392 if ((taldescs[tal->id] = strdup(tal->descr)) == NULL) 393 err(1, NULL); 394 395 /* figure out the TA filename, must be done before repo lookup */ 396 nfile = strrchr(tal->uri[0], '/'); 397 assert(nfile != NULL); 398 if ((nfile = strdup(nfile + 1)) == NULL) 399 err(1, NULL); 400 401 /* Look up the repository. */ 402 repo = ta_lookup(tal->id, tal); 403 if (repo == NULL) { 404 free(nfile); 405 return; 406 } 407 408 /* steal the pkey from the tal structure */ 409 data = tal->pkey; 410 tal->pkey = NULL; 411 entityq_add(NULL, nfile, RTYPE_CER, DIR_VALID, repo, data, 412 tal->pkeysz, tal->id); 413} 414 415/* 416 * Add a manifest (MFT) found in an X509 certificate, RFC 6487. 417 */ 418static void 419queue_add_from_cert(const struct cert *cert) 420{ 421 struct repo *repo; 422 struct skiplistentry *sle; 423 char *nfile, *npath, *host; 424 const char *uri, *repouri, *file; 425 size_t repourisz; 426 427 LIST_FOREACH(sle, &skiplist, entry) { 428 if (strncmp(cert->repo, "rsync://", 8) != 0) 429 errx(1, "unexpected protocol"); 430 host = cert->repo + 8; 431 432 if (strncasecmp(host, sle->value, strcspn(host, "/")) == 0) { 433 warnx("skipping %s (listed in skiplist)", cert->repo); 434 return; 435 } 436 } 437 438 repo = repo_lookup(cert->talid, cert->repo, 439 rrdpon ? cert->notify : NULL); 440 if (repo == NULL) 441 return; 442 443 /* 444 * Figure out the cert filename and path by chopping up the 445 * MFT URI in the cert based on the repo base URI. 446 */ 447 uri = cert->mft; 448 repouri = repo_uri(repo); 449 repourisz = strlen(repouri); 450 if (strncmp(repouri, cert->mft, repourisz) != 0) { 451 warnx("%s: URI %s outside of repository", repouri, uri); 452 return; 453 } 454 uri += repourisz + 1; /* skip base and '/' */ 455 file = strrchr(uri, '/'); 456 if (file == NULL) { 457 npath = NULL; 458 if ((nfile = strdup(uri)) == NULL) 459 err(1, NULL); 460 } else { 461 if ((npath = strndup(uri, file - uri)) == NULL) 462 err(1, NULL); 463 if ((nfile = strdup(file + 1)) == NULL) 464 err(1, NULL); 465 } 466 467 entityq_add(npath, nfile, RTYPE_MFT, DIR_UNKNOWN, repo, NULL, 0, -1); 468} 469 470/* 471 * Process parsed content. 472 * For non-ROAs, we grok for more data. 473 * For ROAs, we want to extract the valid info. 474 * In all cases, we gather statistics. 475 */ 476static void 477entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree, 478 struct brk_tree *brktree, struct vap_tree *vaptree) 479{ 480 enum rtype type; 481 struct tal *tal; 482 struct cert *cert; 483 struct mft *mft; 484 struct roa *roa; 485 struct aspa *aspa; 486 char *file; 487 int c; 488 489 /* 490 * For most of these, we first read whether there's any content 491 * at all---this means that the syntactic parse failed (X509 492 * certificate, for example). 493 * We follow that up with whether the resources didn't parse. 494 */ 495 io_read_buf(b, &type, sizeof(type)); 496 io_read_str(b, &file); 497 498 /* in filemode messages can be ignored, only the accounting matters */ 499 if (filemode) 500 goto done; 501 502 if (filepath_add(&fpt, file) == 0) { 503 warnx("%s: File already visited", file); 504 goto done; 505 } 506 507 switch (type) { 508 case RTYPE_TAL: 509 st->tals++; 510 tal = tal_read(b); 511 queue_add_from_tal(tal); 512 tal_free(tal); 513 break; 514 case RTYPE_CER: 515 st->certs++; 516 io_read_buf(b, &c, sizeof(c)); 517 if (c == 0) { 518 st->certs_fail++; 519 break; 520 } 521 cert = cert_read(b); 522 switch (cert->purpose) { 523 case CERT_PURPOSE_CA: 524 queue_add_from_cert(cert); 525 break; 526 case CERT_PURPOSE_BGPSEC_ROUTER: 527 cert_insert_brks(brktree, cert); 528 st->brks++; 529 break; 530 default: 531 st->certs_fail++; 532 break; 533 } 534 cert_free(cert); 535 break; 536 case RTYPE_MFT: 537 st->mfts++; 538 io_read_buf(b, &c, sizeof(c)); 539 if (c == 0) { 540 st->mfts_fail++; 541 break; 542 } 543 mft = mft_read(b); 544 if (!mft->stale) 545 queue_add_from_mft(mft, repo_byid(mft->repoid)); 546 else 547 st->mfts_stale++; 548 mft_free(mft); 549 break; 550 case RTYPE_CRL: 551 st->crls++; 552 break; 553 case RTYPE_ROA: 554 st->roas++; 555 io_read_buf(b, &c, sizeof(c)); 556 if (c == 0) { 557 st->roas_fail++; 558 break; 559 } 560 roa = roa_read(b); 561 if (roa->valid) 562 roa_insert_vrps(tree, roa, &st->vrps, &st->uniqs); 563 else 564 st->roas_invalid++; 565 roa_free(roa); 566 break; 567 case RTYPE_GBR: 568 st->gbrs++; 569 break; 570 case RTYPE_FILE: 571 break; 572 case RTYPE_ASPA: 573 st->aspas++; 574 io_read_buf(b, &c, sizeof(c)); 575 if (c == 0) { 576 st->aspas_fail++; 577 break; 578 } 579 aspa = aspa_read(b); 580 if (aspa->valid) 581 aspa_insert_vaps(vaptree, aspa, &st->vaps, 582 &st->vaps_uniqs); 583 else 584 st->aspas_invalid++; 585 aspa_free(aspa); 586 break; 587 default: 588 errx(1, "unknown entity type %d", type); 589 } 590 591done: 592 free(file); 593 entity_queue--; 594} 595 596static void 597rrdp_process(struct ibuf *b) 598{ 599 enum rrdp_msg type; 600 enum publish_type pt; 601 struct rrdp_session s; 602 char *uri, *last_mod, *data; 603 char hash[SHA256_DIGEST_LENGTH]; 604 size_t dsz; 605 unsigned int id; 606 int ok; 607 608 io_read_buf(b, &type, sizeof(type)); 609 io_read_buf(b, &id, sizeof(id)); 610 611 switch (type) { 612 case RRDP_END: 613 io_read_buf(b, &ok, sizeof(ok)); 614 rrdp_finish(id, ok); 615 break; 616 case RRDP_HTTP_REQ: 617 io_read_str(b, &uri); 618 io_read_str(b, &last_mod); 619 rrdp_http_fetch(id, uri, last_mod); 620 break; 621 case RRDP_SESSION: 622 io_read_str(b, &s.session_id); 623 io_read_buf(b, &s.serial, sizeof(s.serial)); 624 io_read_str(b, &s.last_mod); 625 rrdp_save_state(id, &s); 626 free(s.session_id); 627 free(s.last_mod); 628 break; 629 case RRDP_FILE: 630 io_read_buf(b, &pt, sizeof(pt)); 631 if (pt != PUB_ADD) 632 io_read_buf(b, &hash, sizeof(hash)); 633 io_read_str(b, &uri); 634 io_read_buf_alloc(b, (void **)&data, &dsz); 635 636 ok = rrdp_handle_file(id, pt, uri, hash, sizeof(hash), 637 data, dsz); 638 rrdp_file_resp(id, ok); 639 640 free(uri); 641 free(data); 642 break; 643 case RRDP_CLEAR: 644 rrdp_clear(id); 645 break; 646 default: 647 errx(1, "unexpected rrdp response"); 648 } 649} 650 651/* 652 * Assign filenames ending in ".tal" in "/etc/rpki" into "tals", 653 * returning the number of files found and filled-in. 654 * This may be zero. 655 * Don't exceed "max" filenames. 656 */ 657static int 658tal_load_default(void) 659{ 660 static const char *confdir = "/etc/rpki"; 661 int s = 0; 662 char *path; 663 DIR *dirp; 664 struct dirent *dp; 665 666 dirp = opendir(confdir); 667 if (dirp == NULL) 668 err(1, "open %s", confdir); 669 while ((dp = readdir(dirp)) != NULL) { 670 if (fnmatch("*.tal", dp->d_name, FNM_PERIOD) == FNM_NOMATCH) 671 continue; 672 if (s >= TALSZ_MAX) 673 err(1, "too many tal files found in %s", 674 confdir); 675 if (asprintf(&path, "%s/%s", confdir, dp->d_name) == -1) 676 err(1, NULL); 677 tals[s++] = path; 678 } 679 closedir(dirp); 680 return s; 681} 682 683/* 684 * Load the list of FQDNs from the skiplist which are to be distrusted. 685 * Return 0 on success. 686 */ 687static void 688load_skiplist(const char *slf) 689{ 690 struct skiplistentry *sle; 691 FILE *fp; 692 char *line = NULL; 693 size_t linesize = 0, linelen; 694 695 if ((fp = fopen(slf, "r")) == NULL) { 696 if (errno == ENOENT && strcmp(slf, DEFAULT_SKIPLIST_FILE) == 0) 697 return; 698 err(1, "failed to open %s", slf); 699 } 700 701 while (getline(&line, &linesize, fp) != -1) { 702 /* just eat comment lines or empty lines*/ 703 if (line[0] == '#' || line[0] == '\n') 704 continue; 705 706 if (line[0] == ' ' || line[0] == '\t') 707 errx(1, "invalid entry in skiplist: %s", line); 708 709 /* 710 * Ignore anything after comment sign, whitespaces, 711 * also chop off LF or CR. 712 */ 713 linelen = strcspn(line, " #\r\n\t"); 714 line[linelen] = '\0'; 715 716 if (!valid_uri(line, linelen, NULL)) 717 errx(1, "invalid entry in skiplist: %s", line); 718 719 if ((sle = malloc(sizeof(struct skiplistentry))) == NULL) 720 err(1, NULL); 721 if ((sle->value = strdup(line)) == NULL) 722 err(1, NULL); 723 724 LIST_INSERT_HEAD(&skiplist, sle, entry); 725 stats.skiplistentries++; 726 } 727 728 fclose(fp); 729 free(line); 730} 731 732static void 733check_fs_size(int fd, const char *cachedir) 734{ 735 struct statvfs fs; 736 const long long minsize = 500 * 1024 * 1024; 737 const long long minnode = 300 * 1000; 738 739 if (fstatvfs(fd, &fs) == -1) 740 err(1, "statfs %s", cachedir); 741 742 if (fs.f_bavail < minsize / fs.f_frsize || 743 (fs.f_ffree > 0 && fs.f_favail < minnode)) { 744 fprintf(stderr, "WARNING: rpki-client may need more than " 745 "the available disk space\n" 746 "on the file-system holding %s.\n", cachedir); 747 fprintf(stderr, "available space: %lldkB, " 748 "suggested minimum %lldkB\n", 749 (long long)fs.f_bavail * fs.f_frsize / 1024, 750 minsize / 1024); 751 fprintf(stderr, "available inodes %lld, " 752 "suggested minimum %lld\n\n", 753 (long long)fs.f_favail, minnode); 754 fflush(stderr); 755 } 756} 757 758static pid_t 759process_start(const char *title, int *fd) 760{ 761 int fl = SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK; 762 pid_t pid; 763 int pair[2]; 764 765 if (socketpair(AF_UNIX, fl, 0, pair) == -1) 766 err(1, "socketpair"); 767 if ((pid = fork()) == -1) 768 err(1, "fork"); 769 770 if (pid == 0) { 771 setproctitle("%s", title); 772 /* change working directory to the cache directory */ 773 if (fchdir(cachefd) == -1) 774 err(1, "fchdir"); 775 if (!filemode && timeout > 0) 776 alarm(timeout); 777 close(pair[1]); 778 *fd = pair[0]; 779 } else { 780 close(pair[0]); 781 *fd = pair[1]; 782 } 783 return pid; 784} 785 786void 787suicide(int sig __attribute__((unused))) 788{ 789 killme = 1; 790} 791 792#define NPFD 4 793 794int 795main(int argc, char *argv[]) 796{ 797 int rc, c, i, st, proc, rsync, http, rrdp, hangup = 0; 798 pid_t pid, procpid, rsyncpid, httppid, rrdppid; 799 struct pollfd pfd[NPFD]; 800 struct msgbuf *queues[NPFD]; 801 struct ibuf *b, *httpbuf = NULL, *procbuf = NULL; 802 struct ibuf *rrdpbuf = NULL, *rsyncbuf = NULL; 803 char *rsync_prog = "openrsync"; 804 char *bind_addr = NULL; 805 const char *cachedir = NULL, *outputdir = NULL; 806 const char *errs, *name; 807 const char *skiplistfile = NULL; 808 struct vrp_tree vrps = RB_INITIALIZER(&vrps); 809 struct brk_tree brks = RB_INITIALIZER(&brks); 810 struct vap_tree vaps = RB_INITIALIZER(&vaps); 811 struct rusage ru; 812 struct timeval start_time, now_time; 813 814 gettimeofday(&start_time, NULL); 815 816 /* If started as root, priv-drop to _rpki-client */ 817 if (getuid() == 0) { 818 struct passwd *pw; 819 820 pw = getpwnam("_rpki-client"); 821 if (!pw) 822 errx(1, "no _rpki-client user to revoke to"); 823 if (setgroups(1, &pw->pw_gid) == -1 || 824 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || 825 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) 826 err(1, "unable to revoke privs"); 827 } 828 cachedir = RPKI_PATH_BASE_DIR; 829 outputdir = RPKI_PATH_OUT_DIR; 830 repo_timeout = timeout / 4; 831 skiplistfile = DEFAULT_SKIPLIST_FILE; 832 833 if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd " 834 "proc exec unveil", NULL) == -1) 835 err(1, "pledge"); 836 837 while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:S:t:T:vV")) != -1) 838 switch (c) { 839 case 'b': 840 bind_addr = optarg; 841 break; 842 case 'B': 843 outformats |= FORMAT_BIRD; 844 break; 845 case 'c': 846 outformats |= FORMAT_CSV; 847 break; 848 case 'd': 849 cachedir = optarg; 850 break; 851 case 'e': 852 rsync_prog = optarg; 853 break; 854 case 'f': 855 filemode = 1; 856 noop = 1; 857 break; 858 case 'j': 859 outformats |= FORMAT_JSON; 860 break; 861 case 'n': 862 noop = 1; 863 break; 864 case 'o': 865 outformats |= FORMAT_OPENBGPD; 866 break; 867 case 'R': 868 rrdpon = 0; 869 break; 870 case 'r': 871 rrdpon = 1; 872 break; 873 case 's': 874 timeout = strtonum(optarg, 0, 24*60*60, &errs); 875 if (errs) 876 errx(1, "-s: %s", errs); 877 if (timeout == 0) 878 repo_timeout = 24*60*60; 879 else 880 repo_timeout = timeout / 4; 881 break; 882 case 'S': 883 skiplistfile = optarg; 884 break; 885 case 't': 886 if (talsz >= TALSZ_MAX) 887 err(1, "too many tal files specified"); 888 tals[talsz++] = optarg; 889 break; 890 case 'T': 891 bird_tablename = optarg; 892 break; 893 case 'v': 894 verbose++; 895 break; 896 case 'V': 897 fprintf(stderr, "rpki-client %s\n", RPKI_VERSION); 898 return 0; 899 default: 900 goto usage; 901 } 902 903 argv += optind; 904 argc -= optind; 905 906 if (!filemode) { 907 if (argc == 1) 908 outputdir = argv[0]; 909 else if (argc > 1) 910 goto usage; 911 912 if (outputdir == NULL) { 913 warnx("output directory required"); 914 goto usage; 915 } 916 } else { 917 if (argc == 0) 918 goto usage; 919 outputdir = NULL; 920 } 921 922 if (cachedir == NULL) { 923 warnx("cache directory required"); 924 goto usage; 925 } 926 927 signal(SIGPIPE, SIG_IGN); 928 929 if ((cachefd = open(cachedir, O_RDONLY | O_DIRECTORY)) == -1) 930 err(1, "cache directory %s", cachedir); 931 if (outputdir != NULL) { 932 if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1) 933 err(1, "output directory %s", outputdir); 934 if (outformats == 0) 935 outformats = FORMAT_OPENBGPD; 936 } 937 938 check_fs_size(cachefd, cachedir); 939 940 if (talsz == 0) 941 talsz = tal_load_default(); 942 if (talsz == 0) 943 err(1, "no TAL files found in %s", "/etc/rpki"); 944 945 /* 946 * Create the file reader as a jailed child process. 947 * It will be responsible for reading all of the files (ROAs, 948 * manifests, certificates, etc.) and returning contents. 949 */ 950 951 procpid = process_start("parser", &proc); 952 if (procpid == 0) { 953 if (!filemode) 954 proc_parser(proc); 955 else 956 proc_filemode(proc); 957 } 958 959 /* 960 * Create a process that will do the rsync'ing. 961 * This process is responsible for making sure that all the 962 * repositories referenced by a certificate manifest (or the 963 * TAL) exists and has been downloaded. 964 */ 965 966 if (!noop) { 967 rsyncpid = process_start("rsync", &rsync); 968 if (rsyncpid == 0) { 969 close(proc); 970 proc_rsync(rsync_prog, bind_addr, rsync); 971 } 972 } else { 973 rsync = -1; 974 rsyncpid = -1; 975 } 976 977 /* 978 * Create a process that will fetch data via https. 979 * With every request the http process receives a file descriptor 980 * where the data should be written to. 981 */ 982 983 if (!noop && rrdpon) { 984 httppid = process_start("http", &http); 985 986 if (httppid == 0) { 987 close(proc); 988 close(rsync); 989 proc_http(bind_addr, http); 990 } 991 } else { 992 http = -1; 993 httppid = -1; 994 } 995 996 /* 997 * Create a process that will process RRDP. 998 * The rrdp process requires the http process to fetch the various 999 * XML files and does this via the main process. 1000 */ 1001 1002 if (!noop && rrdpon) { 1003 rrdppid = process_start("rrdp", &rrdp); 1004 if (rrdppid == 0) { 1005 close(proc); 1006 close(rsync); 1007 close(http); 1008 proc_rrdp(rrdp); 1009 } 1010 } else { 1011 rrdp = -1; 1012 rrdppid = -1; 1013 } 1014 1015 if (!filemode && timeout > 0) { 1016 /* 1017 * Commit suicide eventually 1018 * cron will normally start a new one 1019 */ 1020 alarm(timeout); 1021 signal(SIGALRM, suicide); 1022 } 1023 1024 if (pledge("stdio rpath wpath cpath fattr sendfd unveil", NULL) == -1) 1025 err(1, "pledge"); 1026 1027 msgbuf_init(&procq); 1028 msgbuf_init(&rsyncq); 1029 msgbuf_init(&httpq); 1030 msgbuf_init(&rrdpq); 1031 procq.fd = proc; 1032 rsyncq.fd = rsync; 1033 httpq.fd = http; 1034 rrdpq.fd = rrdp; 1035 1036 /* 1037 * The main process drives the top-down scan to leaf ROAs using 1038 * data downloaded by the rsync process and parsed by the 1039 * parsing process. 1040 */ 1041 1042 pfd[0].fd = proc; 1043 queues[0] = &procq; 1044 pfd[1].fd = rsync; 1045 queues[1] = &rsyncq; 1046 pfd[2].fd = http; 1047 queues[2] = &httpq; 1048 pfd[3].fd = rrdp; 1049 queues[3] = &rrdpq; 1050 1051 load_skiplist(skiplistfile); 1052 1053 /* 1054 * Prime the process with our TAL files. 1055 * These will (hopefully) contain links to manifests and we 1056 * can get the ball rolling. 1057 */ 1058 1059 for (i = 0; i < talsz; i++) 1060 queue_add_file(tals[i], RTYPE_TAL, i); 1061 1062 if (filemode) { 1063 while (*argv != NULL) 1064 queue_add_file(*argv++, RTYPE_FILE, 0); 1065 1066 if (unveil(cachedir, "r") == -1) 1067 err(1, "unveil cachedir"); 1068 } else { 1069 if (unveil(outputdir, "rwc") == -1) 1070 err(1, "unveil outputdir"); 1071 if (unveil(cachedir, "rwc") == -1) 1072 err(1, "unveil cachedir"); 1073 } 1074 if (pledge("stdio rpath wpath cpath fattr sendfd", NULL) == -1) 1075 err(1, "unveil"); 1076 1077 /* change working directory to the cache directory */ 1078 if (fchdir(cachefd) == -1) 1079 err(1, "fchdir"); 1080 1081 while (entity_queue > 0 && !killme) { 1082 int polltim; 1083 1084 for (i = 0; i < NPFD; i++) { 1085 pfd[i].events = POLLIN; 1086 if (queues[i]->queued) 1087 pfd[i].events |= POLLOUT; 1088 } 1089 1090 polltim = repo_check_timeout(INFTIM); 1091 1092 if ((c = poll(pfd, NPFD, polltim)) == -1) { 1093 if (errno == EINTR) 1094 continue; 1095 err(1, "poll"); 1096 } 1097 1098 for (i = 0; i < NPFD; i++) { 1099 if (pfd[i].revents & (POLLERR|POLLNVAL)) { 1100 warnx("poll[%d]: bad fd", i); 1101 hangup = 1; 1102 } 1103 if (pfd[i].revents & POLLHUP) 1104 hangup = 1; 1105 if (pfd[i].revents & POLLOUT) { 1106 switch (msgbuf_write(queues[i])) { 1107 case 0: 1108 warnx("write[%d]: " 1109 "connection closed", i); 1110 hangup = 1; 1111 break; 1112 case -1: 1113 warn("write[%d]", i); 1114 hangup = 1; 1115 break; 1116 } 1117 } 1118 } 1119 if (hangup) 1120 break; 1121 1122 /* 1123 * Check the rsync and http process. 1124 * This means that one of our modules has completed 1125 * downloading and we can flush the module requests into 1126 * the parser process. 1127 */ 1128 1129 if ((pfd[1].revents & POLLIN)) { 1130 b = io_buf_read(rsync, &rsyncbuf); 1131 if (b != NULL) { 1132 unsigned int id; 1133 int ok; 1134 1135 io_read_buf(b, &id, sizeof(id)); 1136 io_read_buf(b, &ok, sizeof(ok)); 1137 rsync_finish(id, ok); 1138 ibuf_free(b); 1139 } 1140 } 1141 1142 if ((pfd[2].revents & POLLIN)) { 1143 b = io_buf_read(http, &httpbuf); 1144 if (b != NULL) { 1145 unsigned int id; 1146 enum http_result res; 1147 char *last_mod; 1148 1149 io_read_buf(b, &id, sizeof(id)); 1150 io_read_buf(b, &res, sizeof(res)); 1151 io_read_str(b, &last_mod); 1152 http_finish(id, res, last_mod); 1153 free(last_mod); 1154 ibuf_free(b); 1155 } 1156 } 1157 1158 /* 1159 * Handle RRDP requests here. 1160 */ 1161 if ((pfd[3].revents & POLLIN)) { 1162 b = io_buf_read(rrdp, &rrdpbuf); 1163 if (b != NULL) { 1164 rrdp_process(b); 1165 ibuf_free(b); 1166 } 1167 } 1168 1169 /* 1170 * The parser has finished something for us. 1171 * Dequeue these one by one. 1172 */ 1173 1174 if ((pfd[0].revents & POLLIN)) { 1175 b = io_buf_read(proc, &procbuf); 1176 if (b != NULL) { 1177 entity_process(b, &stats, &vrps, &brks, &vaps); 1178 ibuf_free(b); 1179 } 1180 } 1181 } 1182 1183 signal(SIGALRM, SIG_DFL); 1184 if (killme) { 1185 syslog(LOG_CRIT|LOG_DAEMON, 1186 "excessive runtime (%d seconds), giving up", timeout); 1187 errx(1, "excessive runtime (%d seconds), giving up", timeout); 1188 } 1189 1190 /* 1191 * For clean-up, close the input for the parser and rsync 1192 * process. 1193 * This will cause them to exit, then we reap them. 1194 */ 1195 1196 close(proc); 1197 close(rsync); 1198 close(http); 1199 close(rrdp); 1200 1201 rc = 0; 1202 for (;;) { 1203 pid = waitpid(WAIT_ANY, &st, 0); 1204 if (pid == -1) { 1205 if (errno == EINTR) 1206 continue; 1207 if (errno == ECHILD) 1208 break; 1209 err(1, "wait"); 1210 } 1211 1212 if (pid == procpid) 1213 name = "parser"; 1214 else if (pid == rsyncpid) 1215 name = "rsync"; 1216 else if (pid == httppid) 1217 name = "http"; 1218 else if (pid == rrdppid) 1219 name = "rrdp"; 1220 else 1221 name = "unknown"; 1222 1223 if (WIFSIGNALED(st)) { 1224 warnx("%s terminated signal %d", name, WTERMSIG(st)); 1225 rc = 1; 1226 } else if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) { 1227 warnx("%s process exited abnormally", name); 1228 rc = 1; 1229 } 1230 } 1231 1232 /* processing did not finish because of error */ 1233 if (entity_queue != 0) 1234 errx(1, "not all files processed, giving up"); 1235 1236 /* if processing in filemode the process is done, no cleanup */ 1237 if (filemode) 1238 return rc; 1239 1240 logx("all files parsed: generating output"); 1241 1242 if (!noop) 1243 repo_cleanup(&fpt, cachefd); 1244 1245 gettimeofday(&now_time, NULL); 1246 timersub(&now_time, &start_time, &stats.elapsed_time); 1247 if (getrusage(RUSAGE_SELF, &ru) == 0) { 1248 stats.user_time = ru.ru_utime; 1249 stats.system_time = ru.ru_stime; 1250 } 1251 if (getrusage(RUSAGE_CHILDREN, &ru) == 0) { 1252 timeradd(&stats.user_time, &ru.ru_utime, &stats.user_time); 1253 timeradd(&stats.system_time, &ru.ru_stime, &stats.system_time); 1254 } 1255 1256 /* change working directory to the output directory */ 1257 if (fchdir(outdirfd) == -1) 1258 err(1, "fchdir output dir"); 1259 1260 if (outputfiles(&vrps, &brks, &vaps, &stats)) 1261 rc = 1; 1262 1263 printf("Processing time %lld seconds " 1264 "(%lld seconds user, %lld seconds system)\n", 1265 (long long)stats.elapsed_time.tv_sec, 1266 (long long)stats.user_time.tv_sec, 1267 (long long)stats.system_time.tv_sec); 1268 printf("Skiplist entries: %zu\n", stats.skiplistentries); 1269 printf("Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)\n", 1270 stats.roas, stats.roas_fail, stats.roas_invalid); 1271 printf("AS Provider Attestations: %zu (%zu failed parse, %zu invalid)\n", 1272 stats.aspas, stats.aspas_fail, stats.aspas_invalid); 1273 printf("BGPsec Router Certificates: %zu\n", stats.brks); 1274 printf("Certificates: %zu (%zu invalid)\n", 1275 stats.certs, stats.certs_fail); 1276 printf("Trust Anchor Locators: %zu (%zu invalid)\n", 1277 stats.tals, talsz - stats.tals); 1278 printf("Manifests: %zu (%zu failed parse, %zu stale)\n", 1279 stats.mfts, stats.mfts_fail, stats.mfts_stale); 1280 printf("Certificate revocation lists: %zu\n", stats.crls); 1281 printf("Ghostbuster records: %zu\n", stats.gbrs); 1282 printf("Repositories: %zu\n", stats.repos); 1283 printf("Cleanup: removed %zu files, %zu directories, %zu superfluous\n", 1284 stats.del_files, stats.del_dirs, stats.extra_files); 1285 printf("VRP Entries: %zu (%zu unique)\n", stats.vrps, stats.uniqs); 1286 printf("VAP Entries: %zu (%zu unique)\n", stats.vaps, stats.vaps_uniqs); 1287 1288 /* Memory cleanup. */ 1289 repo_free(); 1290 1291 return rc; 1292 1293usage: 1294 fprintf(stderr, 1295 "usage: rpki-client [-BcjnoRrVv] [-b sourceaddr] [-d cachedir]" 1296 " [-e rsync_prog]\n" 1297 " [-S skiplist] [-s timeout] [-T table] [-t tal]" 1298 " [outputdir]\n" 1299 " rpki-client [-Vv] [-d cachedir] [-j] [-t tal] -f file ..." 1300 "\n"); 1301 return 1; 1302} 1303