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