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