1 /* $NetBSD: conf.c,v 1.3 2022/11/18 16:01:00 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #ifdef HAVE_CONFIG_H 32 #include "config.h" 33 #endif 34 35 #include <sys/cdefs.h> 36 __RCSID("$NetBSD: conf.c,v 1.3 2022/11/18 16:01:00 christos Exp $"); 37 38 #include <stdio.h> 39 #ifdef HAVE_LIBUTIL_H 40 #include <libutil.h> 41 #endif 42 #ifdef HAVE_UTIL_H 43 #include <util.h> 44 #endif 45 #include <string.h> 46 #include <ctype.h> 47 #include <inttypes.h> 48 #include <netdb.h> 49 #include <unistd.h> 50 #include <pwd.h> 51 #include <syslog.h> 52 #include <errno.h> 53 #include <stdlib.h> 54 #include <limits.h> 55 #include <ifaddrs.h> 56 #include <arpa/inet.h> 57 #include <netinet/in.h> 58 #include <net/if.h> 59 #include <net/route.h> 60 #include <sys/socket.h> 61 62 #include "bl.h" 63 #include "internal.h" 64 #include "support.h" 65 #include "conf.h" 66 67 68 struct sockaddr_if { 69 uint8_t sif_len; 70 sa_family_t sif_family; 71 in_port_t sif_port; 72 char sif_name[16]; 73 }; 74 75 #define SIF_NAME(a) \ 76 ((const struct sockaddr_if *)(const void *)(a))->sif_name 77 78 static int conf_is_interface(const char *); 79 80 #define FSTAR -1 81 #define FEQUAL -2 82 83 static void 84 advance(char **p) 85 { 86 char *ep = *p; 87 while (*ep && !isspace((unsigned char)*ep)) 88 ep++; 89 while (*ep && isspace((unsigned char)*ep)) 90 *ep++ = '\0'; 91 *p = ep; 92 } 93 94 static int 95 conf_getnum(const char *f, size_t l, bool local, void *rp, const char *name, 96 const char *p) 97 { 98 int e; 99 intmax_t im; 100 int *r = rp; 101 102 if (strcmp(p, "*") == 0) { 103 *r = FSTAR; 104 return 0; 105 } 106 if (strcmp(p, "=") == 0) { 107 if (local) 108 goto out; 109 *r = FEQUAL; 110 return 0; 111 } 112 113 im = strtoi(p, NULL, 0, 0, INT_MAX, &e); 114 if (e == 0) { 115 *r = (int)im; 116 return 0; 117 } 118 119 if (f == NULL) 120 return -1; 121 (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number for %s [%s]", __func__, f, l, 122 name, p); 123 return -1; 124 out: 125 (*lfun)(LOG_ERR, "%s: %s, %zu: `=' for %s not allowed in local config", 126 __func__, f, l, name); 127 return -1; 128 129 } 130 131 static int 132 conf_getnfail(const char *f, size_t l, bool local, struct conf *c, 133 const char *p) 134 { 135 return conf_getnum(f, l, local, &c->c_nfail, "nfail", p); 136 } 137 138 static int 139 conf_getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p) 140 { 141 int e; 142 char *ep; 143 intmax_t tot, im; 144 145 tot = 0; 146 if (strcmp(p, "*") == 0) { 147 c->c_duration = FSTAR; 148 return 0; 149 } 150 if (strcmp(p, "=") == 0) { 151 if (local) 152 goto out; 153 c->c_duration = FEQUAL; 154 return 0; 155 } 156 again: 157 im = strtoi(p, &ep, 0, 0, INT_MAX, &e); 158 159 if (e == ENOTSUP) { 160 switch (*ep) { 161 case 'd': 162 im *= 24; 163 /*FALLTHROUGH*/ 164 case 'h': 165 im *= 60; 166 /*FALLTHROUGH*/ 167 case 'm': 168 im *= 60; 169 /*FALLTHROUGH*/ 170 case 's': 171 e = 0; 172 tot += im; 173 if (ep[1] != '\0') { 174 p = ep + 2; 175 goto again; 176 } 177 break; 178 } 179 } else 180 tot = im; 181 182 if (e == 0) { 183 c->c_duration = (int)tot; 184 return 0; 185 } 186 187 if (f == NULL) 188 return -1; 189 (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number [%s]", __func__, f, l, p); 190 return -1; 191 out: 192 (*lfun)(LOG_ERR, "%s: %s, %zu: `=' duration not allowed in local" 193 " config", __func__, f, l); 194 return -1; 195 196 } 197 198 static int 199 conf_getport(const char *f, size_t l, bool local, void *r, const char *p) 200 { 201 struct servent *sv; 202 203 // XXX: Pass in the proto instead 204 if ((sv = getservbyname(p, "tcp")) != NULL) { 205 *(int *)r = ntohs(sv->s_port); 206 return 0; 207 } 208 if ((sv = getservbyname(p, "udp")) != NULL) { 209 *(int *)r = ntohs(sv->s_port); 210 return 0; 211 } 212 213 return conf_getnum(f, l, local, r, "service", p); 214 } 215 216 static int 217 conf_getmask(const char *f, size_t l, bool local, const char **p, int *mask) 218 { 219 char *d; 220 const char *s = *p; 221 222 if ((d = strchr(s, ':')) != NULL) { 223 *d++ = '\0'; 224 *p = d; 225 } 226 if ((d = strchr(s, '/')) == NULL) { 227 *mask = FSTAR; 228 return 0; 229 } 230 231 *d++ = '\0'; 232 return conf_getnum(f, l, local, mask, "mask", d); 233 } 234 235 static int 236 conf_gethostport(const char *f, size_t l, bool local, struct conf *c, 237 const char *p) 238 { 239 char *d; // XXX: Ok to write to string. 240 in_port_t *port = NULL; 241 const char *pstr; 242 243 if (strcmp(p, "*") == 0) { 244 c->c_port = FSTAR; 245 c->c_lmask = FSTAR; 246 return 0; 247 } 248 249 if ((d = strchr(p, ']')) != NULL) { 250 *d++ = '\0'; 251 pstr = d; 252 p++; 253 } else 254 pstr = p; 255 256 if (conf_getmask(f, l, local, &pstr, &c->c_lmask) == -1) 257 goto out; 258 259 if (d) { 260 struct sockaddr_in6 *sin6 = (void *)&c->c_ss; 261 if (debug) 262 (*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p); 263 if (strcmp(p, "*") != 0) { 264 if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == -1) 265 goto out; 266 sin6->sin6_family = AF_INET6; 267 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 268 sin6->sin6_len = sizeof(*sin6); 269 #endif 270 port = &sin6->sin6_port; 271 } 272 } else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) { 273 if (pstr == p) 274 pstr = "*"; 275 struct sockaddr_in *sin = (void *)&c->c_ss; 276 struct sockaddr_if *sif = (void *)&c->c_ss; 277 if (debug) 278 (*lfun)(LOG_DEBUG, "%s: host4 %s", __func__, p); 279 if (strcmp(p, "*") != 0) { 280 if (conf_is_interface(p)) { 281 if (!local) 282 goto out2; 283 if (debug) 284 (*lfun)(LOG_DEBUG, "%s: interface %s", 285 __func__, p); 286 if (c->c_lmask != FSTAR) 287 goto out1; 288 sif->sif_family = AF_MAX; 289 strlcpy(sif->sif_name, p, 290 sizeof(sif->sif_name)); 291 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 292 sif->sif_len = sizeof(*sif); 293 #endif 294 port = &sif->sif_port; 295 } else if (inet_pton(AF_INET, p, &sin->sin_addr) != -1) 296 { 297 sin->sin_family = AF_INET; 298 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 299 sin->sin_len = sizeof(*sin); 300 #endif 301 port = &sin->sin_port; 302 } else 303 goto out; 304 } 305 } 306 307 if (conf_getport(f, l, local, &c->c_port, pstr) == -1) 308 return -1; 309 310 if (port && c->c_port != FSTAR && c->c_port != FEQUAL) 311 *port = htons((in_port_t)c->c_port); 312 return 0; 313 out: 314 (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, pstr); 315 return -1; 316 out1: 317 (*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with " 318 "interface [%s]", __func__, f, l, c->c_lmask, p); 319 return -1; 320 out2: 321 (*lfun)(LOG_ERR, "%s: %s, %zu: Interface spec does not make sense " 322 "with remote config [%s]", __func__, f, l, p); 323 return -1; 324 } 325 326 static int 327 conf_getproto(const char *f, size_t l, bool local __unused, struct conf *c, 328 const char *p) 329 { 330 if (strcmp(p, "stream") == 0) { 331 c->c_proto = IPPROTO_TCP; 332 return 0; 333 } 334 if (strcmp(p, "dgram") == 0) { 335 c->c_proto = IPPROTO_UDP; 336 return 0; 337 } 338 return conf_getnum(f, l, local, &c->c_proto, "protocol", p); 339 } 340 341 static int 342 conf_getfamily(const char *f, size_t l, bool local __unused, struct conf *c, 343 const char *p) 344 { 345 if (strncmp(p, "tcp", 3) == 0 || strncmp(p, "udp", 3) == 0) { 346 c->c_family = p[3] == '6' ? AF_INET6 : AF_INET; 347 return 0; 348 } 349 return conf_getnum(f, l, local, &c->c_family, "family", p); 350 } 351 352 static int 353 conf_getuid(const char *f, size_t l, bool local __unused, struct conf *c, 354 const char *p) 355 { 356 struct passwd *pw; 357 358 if ((pw = getpwnam(p)) != NULL) { 359 c->c_uid = (int)pw->pw_uid; 360 return 0; 361 } 362 363 return conf_getnum(f, l, local, &c->c_uid, "user", p); 364 } 365 366 367 static int 368 conf_getname(const char *f, size_t l, bool local, struct conf *c, 369 const char *p) 370 { 371 if (conf_getmask(f, l, local, &p, &c->c_rmask) == -1) 372 return -1; 373 374 if (strcmp(p, "*") == 0) { 375 strlcpy(c->c_name, rulename, CONFNAMESZ); 376 return 0; 377 } 378 379 if (strcmp(p, "=") == 0) { 380 if (local) 381 goto out; 382 c->c_name[0] = '\0'; 383 return 0; 384 } 385 386 snprintf(c->c_name, CONFNAMESZ, "%s%s", *p == '-' ? rulename : "", p); 387 return 0; 388 out: 389 (*lfun)(LOG_ERR, "%s: %s, %zu: `=' name not allowed in local" 390 " config", __func__, f, l); 391 return -1; 392 } 393 394 static int 395 getvalue(const char *f, size_t l, bool local, void *r, char **p, 396 int (*fun)(const char *, size_t, bool, struct conf *, const char *)) 397 { 398 char *ep = *p; 399 400 advance(p); 401 return (*fun)(f, l, local, r, ep); 402 } 403 404 405 static int 406 conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local) 407 { 408 int e; 409 410 while (*p && isspace((unsigned char)*p)) 411 p++; 412 413 memset(c, 0, sizeof(*c)); 414 e = getvalue(f, l, local, c, &p, conf_gethostport); 415 if (e) return -1; 416 e = getvalue(f, l, local, c, &p, conf_getproto); 417 if (e) return -1; 418 e = getvalue(f, l, local, c, &p, conf_getfamily); 419 if (e) return -1; 420 e = getvalue(f, l, local, c, &p, conf_getuid); 421 if (e) return -1; 422 e = getvalue(f, l, local, c, &p, conf_getname); 423 if (e) return -1; 424 e = getvalue(f, l, local, c, &p, conf_getnfail); 425 if (e) return -1; 426 e = getvalue(f, l, local, c, &p, conf_getsecs); 427 if (e) return -1; 428 429 return 0; 430 } 431 432 static int 433 conf_sort(const void *v1, const void *v2) 434 { 435 const struct conf *c1 = v1; 436 const struct conf *c2 = v2; 437 438 #define CMP(a, b, f) \ 439 if ((a)->f > (b)->f) return -1; \ 440 else if ((a)->f < (b)->f) return 1 441 442 CMP(c1, c2, c_ss.ss_family); 443 CMP(c1, c2, c_lmask); 444 CMP(c1, c2, c_port); 445 CMP(c1, c2, c_proto); 446 CMP(c1, c2, c_family); 447 CMP(c1, c2, c_rmask); 448 CMP(c1, c2, c_uid); 449 #undef CMP 450 return 0; 451 } 452 453 static int 454 conf_is_interface(const char *name) 455 { 456 const struct ifaddrs *ifa; 457 458 for (ifa = ifas; ifa; ifa = ifa->ifa_next) 459 if (strcmp(ifa->ifa_name, name) == 0) 460 return 1; 461 return 0; 462 } 463 464 #define MASK(m) ((uint32_t)~((1 << (32 - (m))) - 1)) 465 466 static int 467 conf_amask_eq(const void *v1, const void *v2, size_t len, int mask) 468 { 469 const uint32_t *a1 = v1; 470 const uint32_t *a2 = v2; 471 uint32_t m; 472 int omask = mask; 473 474 switch (mask) { 475 case FSTAR: 476 if (memcmp(v1, v2, len) == 0) 477 return 1; 478 goto out; 479 case FEQUAL: 480 (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, 481 mask); 482 abort(); 483 default: 484 break; 485 } 486 487 for (size_t i = 0; i < (len >> 2); i++) { 488 if (mask > 32) { 489 m = htonl((uint32_t)~0); 490 mask -= 32; 491 } else if (mask) { 492 m = htonl(MASK(mask)); 493 mask = 0; 494 } else 495 return 1; 496 if ((a1[i] & m) != (a2[i] & m)) 497 goto out; 498 } 499 return 1; 500 out: 501 if (debug > 1) { 502 char b1[256], b2[256]; 503 blhexdump(b1, sizeof(b1), "a1", v1, len); 504 blhexdump(b2, sizeof(b2), "a2", v2, len); 505 (*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__, 506 b1, b2, omask); 507 } 508 return 0; 509 } 510 511 /* 512 * Apply the mask to the given address 513 */ 514 static void 515 conf_apply_mask(void *v, size_t len, int mask) 516 { 517 uint32_t *a = v; 518 uint32_t m; 519 520 switch (mask) { 521 case FSTAR: 522 return; 523 case FEQUAL: 524 (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, 525 mask); 526 abort(); 527 default: 528 break; 529 } 530 len >>= 2; 531 532 for (size_t i = 0; i < len; i++) { 533 if (mask > 32) { 534 m = htonl((uint32_t)~0); 535 mask -= 32; 536 } else if (mask) { 537 m = htonl(MASK(mask)); 538 mask = 0; 539 } else 540 m = 0; 541 a[i] &= m; 542 } 543 } 544 545 /* 546 * apply the mask and the port to the address given 547 */ 548 static void 549 conf_addr_set(struct conf *c, const struct sockaddr_storage *ss) 550 { 551 struct sockaddr_in *sin; 552 struct sockaddr_in6 *sin6; 553 in_port_t *port; 554 void *addr; 555 size_t alen; 556 557 c->c_lmask = c->c_rmask; 558 c->c_ss = *ss; 559 560 if (c->c_ss.ss_family != c->c_family) { 561 (*lfun)(LOG_CRIT, "%s: Internal error: mismatched family " 562 "%u != %u", __func__, c->c_ss.ss_family, c->c_family); 563 abort(); 564 } 565 566 switch (c->c_ss.ss_family) { 567 case AF_INET: 568 sin = (void *)&c->c_ss; 569 port = &sin->sin_port; 570 addr = &sin->sin_addr; 571 alen = sizeof(sin->sin_addr); 572 break; 573 case AF_INET6: 574 sin6 = (void *)&c->c_ss; 575 port = &sin6->sin6_port; 576 addr = &sin6->sin6_addr; 577 alen = sizeof(sin6->sin6_addr); 578 break; 579 default: 580 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", 581 __func__, c->c_ss.ss_family); 582 abort(); 583 } 584 585 *port = htons((in_port_t)c->c_port); 586 conf_apply_mask(addr, alen, c->c_lmask); 587 if (c->c_lmask == FSTAR) 588 c->c_lmask = (int)(alen * 8); 589 if (debug) { 590 char buf[128]; 591 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&c->c_ss); 592 (*lfun)(LOG_DEBUG, "Applied address %s", buf); 593 } 594 } 595 596 /* 597 * Compared two addresses for equality applying the mask 598 */ 599 static int 600 conf_inet_eq(const void *v1, const void *v2, int mask) 601 { 602 const struct sockaddr *sa1 = v1; 603 const struct sockaddr *sa2 = v2; 604 size_t size; 605 606 if (sa1->sa_family != sa2->sa_family) 607 return 0; 608 609 switch (sa1->sa_family) { 610 case AF_INET: { 611 const struct sockaddr_in *s1 = v1; 612 const struct sockaddr_in *s2 = v2; 613 size = sizeof(s1->sin_addr); 614 v1 = &s1->sin_addr; 615 v2 = &s2->sin_addr; 616 break; 617 } 618 619 case AF_INET6: { 620 const struct sockaddr_in6 *s1 = v1; 621 const struct sockaddr_in6 *s2 = v2; 622 size = sizeof(s1->sin6_addr); 623 v1 = &s1->sin6_addr; 624 v2 = &s2->sin6_addr; 625 break; 626 } 627 628 default: 629 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", 630 __func__, sa1->sa_family); 631 abort(); 632 } 633 634 return conf_amask_eq(v1, v2, size, mask); 635 } 636 637 static int 638 conf_addr_in_interface(const struct sockaddr_storage *s1, 639 const struct sockaddr_storage *s2, int mask) 640 { 641 const char *name = SIF_NAME(s2); 642 const struct ifaddrs *ifa; 643 644 for (ifa = ifas; ifa; ifa = ifa->ifa_next) { 645 if ((ifa->ifa_flags & IFF_UP) == 0) 646 continue; 647 648 if (strcmp(ifa->ifa_name, name) != 0) 649 continue; 650 651 if (s1->ss_family != ifa->ifa_addr->sa_family) 652 continue; 653 654 bool eq; 655 switch (s1->ss_family) { 656 case AF_INET: 657 case AF_INET6: 658 eq = conf_inet_eq(ifa->ifa_addr, s1, mask); 659 break; 660 default: 661 (*lfun)(LOG_ERR, "Bad family %u", s1->ss_family); 662 continue; 663 } 664 if (eq) 665 return 1; 666 } 667 return 0; 668 } 669 670 static int 671 conf_addr_eq(const struct sockaddr_storage *s1, 672 const struct sockaddr_storage *s2, int mask) 673 { 674 switch (s2->ss_family) { 675 case 0: 676 return 1; 677 case AF_MAX: 678 return conf_addr_in_interface(s1, s2, mask); 679 case AF_INET: 680 case AF_INET6: 681 return conf_inet_eq(s1, s2, mask); 682 default: 683 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", 684 __func__, s1->ss_family); 685 abort(); 686 } 687 } 688 689 static int 690 conf_eq(const struct conf *c1, const struct conf *c2) 691 { 692 693 if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask)) 694 return 0; 695 696 #define CMP(a, b, f) \ 697 if ((a)->f != (b)->f && (b)->f != FSTAR && (b)->f != FEQUAL) { \ 698 if (debug > 1) \ 699 (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \ 700 __STRING(f), (a)->f, (b)->f); \ 701 return 0; \ 702 } 703 CMP(c1, c2, c_port); 704 CMP(c1, c2, c_proto); 705 CMP(c1, c2, c_family); 706 CMP(c1, c2, c_uid); 707 #undef CMP 708 return 1; 709 } 710 711 static const char * 712 conf_num(char *b, size_t l, int n) 713 { 714 switch (n) { 715 case FSTAR: 716 return "*"; 717 case FEQUAL: 718 return "="; 719 default: 720 snprintf(b, l, "%d", n); 721 return b; 722 } 723 } 724 725 static const char * 726 fmtname(const char *n) { 727 size_t l = strlen(rulename); 728 if (l == 0) 729 return "*"; 730 if (strncmp(n, rulename, l) == 0) { 731 if (n[l] != '\0') 732 return n + l; 733 else 734 return "*"; 735 } else if (!*n) 736 return "="; 737 else 738 return n; 739 } 740 741 static void 742 fmtport(char *b, size_t l, int port) 743 { 744 char buf[128]; 745 746 if (port == FSTAR) 747 return; 748 749 if (b[0] == '\0' || strcmp(b, "*") == 0) 750 snprintf(b, l, "%d", port); 751 else { 752 snprintf(buf, sizeof(buf), ":%d", port); 753 strlcat(b, buf, l); 754 } 755 } 756 757 static const char * 758 fmtmask(char *b, size_t l, int fam, int mask) 759 { 760 char buf[128]; 761 762 switch (mask) { 763 case FSTAR: 764 return ""; 765 case FEQUAL: 766 if (strcmp(b, "=") == 0) 767 return ""; 768 else { 769 strlcat(b, "/=", l); 770 return b; 771 } 772 default: 773 break; 774 } 775 776 switch (fam) { 777 case AF_INET: 778 if (mask == 32) 779 return ""; 780 break; 781 case AF_INET6: 782 if (mask == 128) 783 return ""; 784 break; 785 default: 786 break; 787 } 788 789 snprintf(buf, sizeof(buf), "/%d", mask); 790 strlcat(b, buf, l); 791 return b; 792 } 793 794 static const char * 795 conf_namemask(char *b, size_t l, const struct conf *c) 796 { 797 strlcpy(b, fmtname(c->c_name), l); 798 fmtmask(b, l, c->c_family, c->c_rmask); 799 return b; 800 } 801 802 const char * 803 conf_print(char *buf, size_t len, const char *pref, const char *delim, 804 const struct conf *c) 805 { 806 char ha[128], hb[32], b[5][64]; 807 int sp; 808 809 #define N(n, v) conf_num(b[n], sizeof(b[n]), (v)) 810 811 switch (c->c_ss.ss_family) { 812 case 0: 813 snprintf(ha, sizeof(ha), "*"); 814 break; 815 case AF_MAX: 816 snprintf(ha, sizeof(ha), "%s", SIF_NAME(&c->c_ss)); 817 break; 818 default: 819 sockaddr_snprintf(ha, sizeof(ha), "%a", (const void *)&c->c_ss); 820 break; 821 } 822 823 fmtmask(ha, sizeof(ha), c->c_family, c->c_lmask); 824 fmtport(ha, sizeof(ha), c->c_port); 825 826 sp = *delim == '\t' ? 20 : -1; 827 hb[0] = '\0'; 828 if (*delim) 829 snprintf(buf, len, "%s%*.*s%s%s%s" "%s%s%s%s" 830 "%s%s" "%s%s%s", 831 pref, sp, sp, ha, delim, N(0, c->c_proto), delim, 832 N(1, c->c_family), delim, N(2, c->c_uid), delim, 833 conf_namemask(hb, sizeof(hb), c), delim, 834 N(3, c->c_nfail), delim, N(4, c->c_duration)); 835 else 836 snprintf(buf, len, "%starget:%s, proto:%s, family:%s, " 837 "uid:%s, name:%s, nfail:%s, duration:%s", pref, 838 ha, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid), 839 conf_namemask(hb, sizeof(hb), c), 840 N(3, c->c_nfail), N(4, c->c_duration)); 841 return buf; 842 } 843 844 /* 845 * Apply the local config match to the result 846 */ 847 static void 848 conf_apply(struct conf *c, const struct conf *sc) 849 { 850 char buf[BUFSIZ]; 851 852 if (debug) { 853 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 854 conf_print(buf, sizeof(buf), "merge:\t", "", sc)); 855 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 856 conf_print(buf, sizeof(buf), "to:\t", "", c)); 857 } 858 memcpy(c->c_name, sc->c_name, CONFNAMESZ); 859 c->c_uid = sc->c_uid; 860 c->c_rmask = sc->c_rmask; 861 c->c_nfail = sc->c_nfail; 862 c->c_duration = sc->c_duration; 863 864 if (debug) 865 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 866 conf_print(buf, sizeof(buf), "result:\t", "", c)); 867 } 868 869 /* 870 * Merge a remote configuration to the result 871 */ 872 static void 873 conf_merge(struct conf *c, const struct conf *sc) 874 { 875 char buf[BUFSIZ]; 876 877 if (debug) { 878 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 879 conf_print(buf, sizeof(buf), "merge:\t", "", sc)); 880 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 881 conf_print(buf, sizeof(buf), "to:\t", "", c)); 882 } 883 884 if (sc->c_name[0]) 885 memcpy(c->c_name, sc->c_name, CONFNAMESZ); 886 if (sc->c_uid != FEQUAL) 887 c->c_uid = sc->c_uid; 888 if (sc->c_rmask != FEQUAL) 889 c->c_lmask = c->c_rmask = sc->c_rmask; 890 if (sc->c_nfail != FEQUAL) 891 c->c_nfail = sc->c_nfail; 892 if (sc->c_duration != FEQUAL) 893 c->c_duration = sc->c_duration; 894 if (debug) 895 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 896 conf_print(buf, sizeof(buf), "result:\t", "", c)); 897 } 898 899 static void 900 confset_init(struct confset *cs) 901 { 902 cs->cs_c = NULL; 903 cs->cs_n = 0; 904 cs->cs_m = 0; 905 } 906 907 static int 908 confset_grow(struct confset *cs) 909 { 910 void *tc; 911 912 cs->cs_m += 10; 913 tc = realloc(cs->cs_c, cs->cs_m * sizeof(*cs->cs_c)); 914 if (tc == NULL) { 915 (*lfun)(LOG_ERR, "%s: Can't grow confset (%m)", __func__); 916 return -1; 917 } 918 cs->cs_c = tc; 919 return 0; 920 } 921 922 static struct conf * 923 confset_get(struct confset *cs) 924 { 925 return &cs->cs_c[cs->cs_n]; 926 } 927 928 static bool 929 confset_full(const struct confset *cs) 930 { 931 return cs->cs_n == cs->cs_m; 932 } 933 934 static void 935 confset_sort(struct confset *cs) 936 { 937 qsort(cs->cs_c, cs->cs_n, sizeof(*cs->cs_c), conf_sort); 938 } 939 940 static void 941 confset_add(struct confset *cs) 942 { 943 cs->cs_n++; 944 } 945 946 static void 947 confset_free(struct confset *cs) 948 { 949 free(cs->cs_c); 950 confset_init(cs); 951 } 952 953 static void 954 confset_replace(struct confset *dc, struct confset *sc) 955 { 956 struct confset tc; 957 tc = *dc; 958 *dc = *sc; 959 confset_init(sc); 960 confset_free(&tc); 961 } 962 963 static void 964 confset_list(const struct confset *cs, const char *msg, const char *where) 965 { 966 char buf[BUFSIZ]; 967 968 (*lfun)(LOG_DEBUG, "[%s]", msg); 969 (*lfun)(LOG_DEBUG, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration", 970 where); 971 for (size_t i = 0; i < cs->cs_n; i++) 972 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "", "\t", 973 &cs->cs_c[i])); 974 } 975 976 /* 977 * Match a configuration against the given list and apply the function 978 * to it, returning the matched entry number. 979 */ 980 static size_t 981 confset_match(const struct confset *cs, struct conf *c, 982 void (*fun)(struct conf *, const struct conf *)) 983 { 984 char buf[BUFSIZ]; 985 size_t i; 986 987 for (i = 0; i < cs->cs_n; i++) { 988 if (debug) 989 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), 990 "check:\t", "", &cs->cs_c[i])); 991 if (conf_eq(c, &cs->cs_c[i])) { 992 if (debug) 993 (*lfun)(LOG_DEBUG, "%s", 994 conf_print(buf, sizeof(buf), 995 "found:\t", "", &cs->cs_c[i])); 996 (*fun)(c, &cs->cs_c[i]); 997 break; 998 } 999 } 1000 return i; 1001 } 1002 1003 #ifdef AF_ROUTE 1004 static int 1005 conf_route_perm(int fd) { 1006 #if defined(RTM_IFANNOUNCE) && defined(RT_ROUNDUP) 1007 /* 1008 * Send a routing message that is not supported to check for access 1009 * We expect EOPNOTSUPP for having access, since we are sending a 1010 * request the system does not understand and EACCES if we don't have 1011 * access. 1012 */ 1013 static struct sockaddr_in sin = { 1014 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 1015 .sin_len = sizeof(sin), 1016 #endif 1017 .sin_family = AF_INET, 1018 }; 1019 char buf[4096]; 1020 struct rt_msghdr *rtm = (void *)buf; 1021 char *cp = (char *)(rtm + 1); 1022 size_t l; 1023 1024 #define NEXTADDR(s) \ 1025 l = RT_ROUNDUP(sizeof(*s)); memmove(cp, s, l); cp += l; 1026 memset(buf, 0, sizeof(buf)); 1027 rtm->rtm_type = RTM_IFANNOUNCE; 1028 rtm->rtm_flags = 0; 1029 rtm->rtm_addrs = RTA_DST|RTA_GATEWAY; 1030 rtm->rtm_version = RTM_VERSION; 1031 rtm->rtm_seq = 666; 1032 NEXTADDR(&sin); 1033 NEXTADDR(&sin); 1034 rtm->rtm_msglen = (u_short)((char *)cp - (char *)rtm); 1035 if (write(fd, rtm, rtm->rtm_msglen) != -1) { 1036 (*lfun)(LOG_ERR, "Writing to routing socket succeeded!"); 1037 return 0; 1038 } 1039 switch (errno) { 1040 case EACCES: 1041 return 0; 1042 case EOPNOTSUPP: 1043 return 1; 1044 default: 1045 (*lfun)(LOG_ERR, 1046 "Unexpected error writing to routing socket (%m)"); 1047 return 0; 1048 } 1049 #else 1050 return 0; 1051 #endif 1052 } 1053 #endif 1054 1055 static int 1056 conf_handle_inet(int fd, const void *lss, struct conf *cr) 1057 { 1058 char buf[BUFSIZ]; 1059 int proto; 1060 socklen_t slen = sizeof(proto); 1061 1062 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) { 1063 (*lfun)(LOG_ERR, "getsockopt failed (%m)"); 1064 return -1; 1065 } 1066 1067 if (debug) { 1068 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", lss); 1069 (*lfun)(LOG_DEBUG, "listening socket: %s", buf); 1070 } 1071 1072 switch (proto) { 1073 case SOCK_STREAM: 1074 cr->c_proto = IPPROTO_TCP; 1075 break; 1076 case SOCK_DGRAM: 1077 cr->c_proto = IPPROTO_UDP; 1078 break; 1079 default: 1080 (*lfun)(LOG_ERR, "unsupported protocol %d", proto); 1081 return -1; 1082 } 1083 return 0; 1084 } 1085 1086 const struct conf * 1087 conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss, 1088 struct conf *cr) 1089 { 1090 socklen_t slen; 1091 struct sockaddr_storage lss; 1092 size_t i; 1093 char buf[BUFSIZ]; 1094 1095 memset(cr, 0, sizeof(*cr)); 1096 slen = sizeof(lss); 1097 memset(&lss, 0, slen); 1098 if (getsockname(fd, (void *)&lss, &slen) == -1) { 1099 (*lfun)(LOG_ERR, "getsockname failed (%m)"); 1100 return NULL; 1101 } 1102 1103 switch (lss.ss_family) { 1104 case AF_INET: 1105 cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port); 1106 if (conf_handle_inet(fd, &lss, cr) == -1) 1107 return NULL; 1108 break; 1109 case AF_INET6: 1110 cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port); 1111 if (conf_handle_inet(fd, &lss, cr) == -1) 1112 return NULL; 1113 break; 1114 #ifdef AF_ROUTE 1115 case AF_ROUTE: 1116 if (!conf_route_perm(fd)) { 1117 (*lfun)(LOG_ERR, 1118 "permission denied to routing socket (%m)"); 1119 return NULL; 1120 } 1121 cr->c_proto = FSTAR; 1122 cr->c_port = FSTAR; 1123 memcpy(&lss, rss, sizeof(lss)); 1124 break; 1125 #endif 1126 default: 1127 (*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family); 1128 return NULL; 1129 } 1130 1131 cr->c_ss = lss; 1132 cr->c_lmask = FSTAR; 1133 cr->c_uid = (int)uid; 1134 cr->c_family = lss.ss_family; 1135 cr->c_name[0] = '\0'; 1136 cr->c_rmask = FSTAR; 1137 cr->c_nfail = FSTAR; 1138 cr->c_duration = FSTAR; 1139 1140 if (debug) 1141 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), 1142 "look:\t", "", cr)); 1143 1144 /* match the local config */ 1145 i = confset_match(&lconf, cr, conf_apply); 1146 if (i == lconf.cs_n) { 1147 if (debug) 1148 (*lfun)(LOG_DEBUG, "not found"); 1149 return NULL; 1150 } 1151 1152 conf_addr_set(cr, rss); 1153 /* match the remote config */ 1154 confset_match(&rconf, cr, conf_merge); 1155 /* to apply the mask */ 1156 conf_addr_set(cr, &cr->c_ss); 1157 1158 return cr; 1159 } 1160 1161 1162 void 1163 conf_parse(const char *f) 1164 { 1165 FILE *fp; 1166 char *line; 1167 size_t lineno, len; 1168 struct confset lc, rc, *cs; 1169 1170 if ((fp = fopen(f, "r")) == NULL) { 1171 (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f); 1172 return; 1173 } 1174 1175 lineno = 1; 1176 1177 confset_init(&rc); 1178 confset_init(&lc); 1179 cs = &lc; 1180 for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL; 1181 free(line)) 1182 { 1183 if (!*line) 1184 continue; 1185 if (strcmp(line, "[local]") == 0) { 1186 cs = &lc; 1187 continue; 1188 } 1189 if (strcmp(line, "[remote]") == 0) { 1190 cs = &rc; 1191 continue; 1192 } 1193 1194 if (confset_full(cs)) { 1195 if (confset_grow(cs) == -1) { 1196 confset_free(&lc); 1197 confset_free(&rc); 1198 fclose(fp); 1199 free(line); 1200 return; 1201 } 1202 } 1203 if (conf_parseline(f, lineno, line, confset_get(cs), 1204 cs == &lc) == -1) 1205 continue; 1206 confset_add(cs); 1207 } 1208 1209 fclose(fp); 1210 confset_sort(&lc); 1211 confset_sort(&rc); 1212 1213 confset_replace(&rconf, &rc); 1214 confset_replace(&lconf, &lc); 1215 1216 if (debug) { 1217 confset_list(&lconf, "local", "target"); 1218 confset_list(&rconf, "remote", "source"); 1219 } 1220 } 1221