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 <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 len >>= 2; 475 switch (mask) { 476 case FSTAR: 477 if (memcmp(v1, v2, len) == 0) 478 return 1; 479 goto out; 480 case FEQUAL: 481 (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, 482 mask); 483 abort(); 484 default: 485 break; 486 } 487 488 for (size_t i = 0; i < len; i++) { 489 if (mask > 32) { 490 m = htonl((uint32_t)~0); 491 mask -= 32; 492 } else if (mask) { 493 m = htonl(MASK(mask)); 494 mask = 0; 495 } else 496 return 1; 497 if ((a1[i] & m) != (a2[i] & m)) 498 goto out; 499 } 500 return 1; 501 out: 502 if (debug > 1) { 503 char b1[256], b2[256]; 504 len <<= 2; 505 blhexdump(b1, sizeof(b1), "a1", v1, len); 506 blhexdump(b2, sizeof(b2), "a2", v2, len); 507 (*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__, 508 b1, b2, omask); 509 } 510 return 0; 511 } 512 513 /* 514 * Apply the mask to the given address 515 */ 516 static void 517 conf_apply_mask(void *v, size_t len, int mask) 518 { 519 uint32_t *a = v; 520 uint32_t m; 521 522 switch (mask) { 523 case FSTAR: 524 return; 525 case FEQUAL: 526 (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, 527 mask); 528 abort(); 529 default: 530 break; 531 } 532 len >>= 2; 533 534 for (size_t i = 0; i < len; i++) { 535 if (mask > 32) { 536 m = htonl((uint32_t)~0); 537 mask -= 32; 538 } else if (mask) { 539 m = htonl(MASK(mask)); 540 mask = 0; 541 } else 542 m = 0; 543 a[i] &= m; 544 } 545 } 546 547 /* 548 * apply the mask and the port to the address given 549 */ 550 static void 551 conf_addr_set(struct conf *c, const struct sockaddr_storage *ss) 552 { 553 struct sockaddr_in *sin; 554 struct sockaddr_in6 *sin6; 555 in_port_t *port; 556 void *addr; 557 size_t alen; 558 559 c->c_lmask = c->c_rmask; 560 c->c_ss = *ss; 561 562 if (c->c_ss.ss_family != c->c_family) { 563 (*lfun)(LOG_CRIT, "%s: Internal error: mismatched family " 564 "%u != %u", __func__, c->c_ss.ss_family, c->c_family); 565 abort(); 566 } 567 568 switch (c->c_ss.ss_family) { 569 case AF_INET: 570 sin = (void *)&c->c_ss; 571 port = &sin->sin_port; 572 addr = &sin->sin_addr; 573 alen = sizeof(sin->sin_addr); 574 break; 575 case AF_INET6: 576 sin6 = (void *)&c->c_ss; 577 port = &sin6->sin6_port; 578 addr = &sin6->sin6_addr; 579 alen = sizeof(sin6->sin6_addr); 580 break; 581 default: 582 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", 583 __func__, c->c_ss.ss_family); 584 abort(); 585 } 586 587 *port = htons((in_port_t)c->c_port); 588 conf_apply_mask(addr, alen, c->c_lmask); 589 if (c->c_lmask == FSTAR) 590 c->c_lmask = (int)(alen * 8); 591 if (debug) { 592 char buf[128]; 593 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&c->c_ss); 594 (*lfun)(LOG_DEBUG, "Applied address %s", buf); 595 } 596 } 597 598 /* 599 * Compared two addresses for equality applying the mask 600 */ 601 static int 602 conf_inet_eq(const void *v1, const void *v2, int mask) 603 { 604 const struct sockaddr *sa1 = v1; 605 const struct sockaddr *sa2 = v2; 606 size_t size; 607 608 if (sa1->sa_family != sa2->sa_family) 609 return 0; 610 611 switch (sa1->sa_family) { 612 case AF_INET: { 613 const struct sockaddr_in *s1 = v1; 614 const struct sockaddr_in *s2 = v2; 615 size = sizeof(s1->sin_addr); 616 v1 = &s1->sin_addr; 617 v2 = &s2->sin_addr; 618 break; 619 } 620 621 case AF_INET6: { 622 const struct sockaddr_in6 *s1 = v1; 623 const struct sockaddr_in6 *s2 = v2; 624 size = sizeof(s1->sin6_addr); 625 v1 = &s1->sin6_addr; 626 v2 = &s2->sin6_addr; 627 break; 628 } 629 630 default: 631 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", 632 __func__, sa1->sa_family); 633 abort(); 634 } 635 636 return conf_amask_eq(v1, v2, size, mask); 637 } 638 639 static int 640 conf_addr_in_interface(const struct sockaddr_storage *s1, 641 const struct sockaddr_storage *s2, int mask) 642 { 643 const char *name = SIF_NAME(s2); 644 const struct ifaddrs *ifa; 645 646 for (ifa = ifas; ifa; ifa = ifa->ifa_next) { 647 if ((ifa->ifa_flags & IFF_UP) == 0) 648 continue; 649 650 if (strcmp(ifa->ifa_name, name) != 0) 651 continue; 652 653 if (s1->ss_family != ifa->ifa_addr->sa_family) 654 continue; 655 656 bool eq; 657 switch (s1->ss_family) { 658 case AF_INET: 659 case AF_INET6: 660 eq = conf_inet_eq(ifa->ifa_addr, s1, mask); 661 break; 662 default: 663 (*lfun)(LOG_ERR, "Bad family %u", s1->ss_family); 664 continue; 665 } 666 if (eq) 667 return 1; 668 } 669 return 0; 670 } 671 672 static int 673 conf_addr_eq(const struct sockaddr_storage *s1, 674 const struct sockaddr_storage *s2, int mask) 675 { 676 switch (s2->ss_family) { 677 case 0: 678 return 1; 679 case AF_MAX: 680 return conf_addr_in_interface(s1, s2, mask); 681 case AF_INET: 682 case AF_INET6: 683 return conf_inet_eq(s1, s2, mask); 684 default: 685 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", 686 __func__, s1->ss_family); 687 abort(); 688 } 689 } 690 691 static int 692 conf_eq(const struct conf *c1, const struct conf *c2) 693 { 694 695 if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask)) 696 return 0; 697 698 #define CMP(a, b, f) \ 699 if ((a)->f != (b)->f && (b)->f != FSTAR && (b)->f != FEQUAL) { \ 700 if (debug > 1) \ 701 (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \ 702 __STRING(f), (a)->f, (b)->f); \ 703 return 0; \ 704 } 705 CMP(c1, c2, c_port); 706 CMP(c1, c2, c_proto); 707 CMP(c1, c2, c_family); 708 CMP(c1, c2, c_uid); 709 #undef CMP 710 return 1; 711 } 712 713 static const char * 714 conf_num(char *b, size_t l, int n) 715 { 716 switch (n) { 717 case FSTAR: 718 return "*"; 719 case FEQUAL: 720 return "="; 721 default: 722 snprintf(b, l, "%d", n); 723 return b; 724 } 725 } 726 727 static const char * 728 fmtname(const char *n) { 729 size_t l = strlen(rulename); 730 if (l == 0) 731 return "*"; 732 if (strncmp(n, rulename, l) == 0) { 733 if (n[l] != '\0') 734 return n + l; 735 else 736 return "*"; 737 } else if (!*n) 738 return "="; 739 else 740 return n; 741 } 742 743 static void 744 fmtport(char *b, size_t l, int port) 745 { 746 char buf[128]; 747 748 if (port == FSTAR) 749 return; 750 751 if (b[0] == '\0' || strcmp(b, "*") == 0) 752 snprintf(b, l, "%d", port); 753 else { 754 snprintf(buf, sizeof(buf), ":%d", port); 755 strlcat(b, buf, l); 756 } 757 } 758 759 static const char * 760 fmtmask(char *b, size_t l, int fam, int mask) 761 { 762 char buf[128]; 763 764 switch (mask) { 765 case FSTAR: 766 return ""; 767 case FEQUAL: 768 if (strcmp(b, "=") == 0) 769 return ""; 770 else { 771 strlcat(b, "/=", l); 772 return b; 773 } 774 default: 775 break; 776 } 777 778 switch (fam) { 779 case AF_INET: 780 if (mask == 32) 781 return ""; 782 break; 783 case AF_INET6: 784 if (mask == 128) 785 return ""; 786 break; 787 default: 788 break; 789 } 790 791 snprintf(buf, sizeof(buf), "/%d", mask); 792 strlcat(b, buf, l); 793 return b; 794 } 795 796 static const char * 797 conf_namemask(char *b, size_t l, const struct conf *c) 798 { 799 strlcpy(b, fmtname(c->c_name), l); 800 fmtmask(b, l, c->c_family, c->c_rmask); 801 return b; 802 } 803 804 const char * 805 conf_print(char *buf, size_t len, const char *pref, const char *delim, 806 const struct conf *c) 807 { 808 char ha[128], hb[32], b[5][64]; 809 int sp; 810 811 #define N(n, v) conf_num(b[n], sizeof(b[n]), (v)) 812 813 switch (c->c_ss.ss_family) { 814 case 0: 815 snprintf(ha, sizeof(ha), "*"); 816 break; 817 case AF_MAX: 818 snprintf(ha, sizeof(ha), "%s", SIF_NAME(&c->c_ss)); 819 break; 820 default: 821 sockaddr_snprintf(ha, sizeof(ha), "%a", (const void *)&c->c_ss); 822 break; 823 } 824 825 fmtmask(ha, sizeof(ha), c->c_family, c->c_lmask); 826 fmtport(ha, sizeof(ha), c->c_port); 827 828 sp = *delim == '\t' ? 20 : -1; 829 hb[0] = '\0'; 830 if (*delim) 831 snprintf(buf, len, "%s%*.*s%s%s%s" "%s%s%s%s" 832 "%s%s" "%s%s%s", 833 pref, sp, sp, ha, delim, N(0, c->c_proto), delim, 834 N(1, c->c_family), delim, N(2, c->c_uid), delim, 835 conf_namemask(hb, sizeof(hb), c), delim, 836 N(3, c->c_nfail), delim, N(4, c->c_duration)); 837 else 838 snprintf(buf, len, "%starget:%s, proto:%s, family:%s, " 839 "uid:%s, name:%s, nfail:%s, duration:%s", pref, 840 ha, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid), 841 conf_namemask(hb, sizeof(hb), c), 842 N(3, c->c_nfail), N(4, c->c_duration)); 843 return buf; 844 } 845 846 /* 847 * Apply the local config match to the result 848 */ 849 static void 850 conf_apply(struct conf *c, const struct conf *sc) 851 { 852 char buf[BUFSIZ]; 853 854 if (debug) { 855 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 856 conf_print(buf, sizeof(buf), "merge:\t", "", sc)); 857 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 858 conf_print(buf, sizeof(buf), "to:\t", "", c)); 859 } 860 memcpy(c->c_name, sc->c_name, CONFNAMESZ); 861 c->c_uid = sc->c_uid; 862 c->c_rmask = sc->c_rmask; 863 c->c_nfail = sc->c_nfail; 864 c->c_duration = sc->c_duration; 865 866 if (debug) 867 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 868 conf_print(buf, sizeof(buf), "result:\t", "", c)); 869 } 870 871 /* 872 * Merge a remote configuration to the result 873 */ 874 static void 875 conf_merge(struct conf *c, const struct conf *sc) 876 { 877 char buf[BUFSIZ]; 878 879 if (debug) { 880 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 881 conf_print(buf, sizeof(buf), "merge:\t", "", sc)); 882 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 883 conf_print(buf, sizeof(buf), "to:\t", "", c)); 884 } 885 886 if (sc->c_name[0]) 887 memcpy(c->c_name, sc->c_name, CONFNAMESZ); 888 if (sc->c_uid != FEQUAL) 889 c->c_uid = sc->c_uid; 890 if (sc->c_rmask != FEQUAL) 891 c->c_lmask = c->c_rmask = sc->c_rmask; 892 if (sc->c_nfail != FEQUAL) 893 c->c_nfail = sc->c_nfail; 894 if (sc->c_duration != FEQUAL) 895 c->c_duration = sc->c_duration; 896 if (debug) 897 (*lfun)(LOG_DEBUG, "%s: %s", __func__, 898 conf_print(buf, sizeof(buf), "result:\t", "", c)); 899 } 900 901 static void 902 confset_init(struct confset *cs) 903 { 904 cs->cs_c = NULL; 905 cs->cs_n = 0; 906 cs->cs_m = 0; 907 } 908 909 static int 910 confset_grow(struct confset *cs) 911 { 912 void *tc; 913 914 cs->cs_m += 10; 915 tc = realloc(cs->cs_c, cs->cs_m * sizeof(*cs->cs_c)); 916 if (tc == NULL) { 917 (*lfun)(LOG_ERR, "%s: Can't grow confset (%m)", __func__); 918 return -1; 919 } 920 cs->cs_c = tc; 921 return 0; 922 } 923 924 static struct conf * 925 confset_get(struct confset *cs) 926 { 927 return &cs->cs_c[cs->cs_n]; 928 } 929 930 static bool 931 confset_full(const struct confset *cs) 932 { 933 return cs->cs_n == cs->cs_m; 934 } 935 936 static void 937 confset_sort(struct confset *cs) 938 { 939 qsort(cs->cs_c, cs->cs_n, sizeof(*cs->cs_c), conf_sort); 940 } 941 942 static void 943 confset_add(struct confset *cs) 944 { 945 cs->cs_n++; 946 } 947 948 static void 949 confset_free(struct confset *cs) 950 { 951 free(cs->cs_c); 952 confset_init(cs); 953 } 954 955 static void 956 confset_replace(struct confset *dc, struct confset *sc) 957 { 958 struct confset tc; 959 tc = *dc; 960 *dc = *sc; 961 confset_init(sc); 962 confset_free(&tc); 963 } 964 965 static void 966 confset_list(const struct confset *cs, const char *msg, const char *where) 967 { 968 char buf[BUFSIZ]; 969 970 (*lfun)(LOG_DEBUG, "[%s]", msg); 971 (*lfun)(LOG_DEBUG, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration", 972 where); 973 for (size_t i = 0; i < cs->cs_n; i++) 974 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "", "\t", 975 &cs->cs_c[i])); 976 } 977 978 /* 979 * Match a configuration against the given list and apply the function 980 * to it, returning the matched entry number. 981 */ 982 static size_t 983 confset_match(const struct confset *cs, struct conf *c, 984 void (*fun)(struct conf *, const struct conf *)) 985 { 986 char buf[BUFSIZ]; 987 size_t i; 988 989 for (i = 0; i < cs->cs_n; i++) { 990 if (debug) 991 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), 992 "check:\t", "", &cs->cs_c[i])); 993 if (conf_eq(c, &cs->cs_c[i])) { 994 if (debug) 995 (*lfun)(LOG_DEBUG, "%s", 996 conf_print(buf, sizeof(buf), 997 "found:\t", "", &cs->cs_c[i])); 998 (*fun)(c, &cs->cs_c[i]); 999 break; 1000 } 1001 } 1002 return i; 1003 } 1004 1005 #ifdef AF_ROUTE 1006 static int 1007 conf_route_perm(int fd) { 1008 #if defined(RTM_IFANNOUNCE) && defined(SA_SIZE) 1009 /* 1010 * Send a routing message that is not supported to check for access 1011 * We expect EOPNOTSUPP for having access, since we are sending a 1012 * request the system does not understand and EACCES if we don't have 1013 * access. 1014 */ 1015 static struct sockaddr_in sin = { 1016 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 1017 .sin_len = sizeof(sin), 1018 #endif 1019 .sin_family = AF_INET, 1020 }; 1021 char buf[4096]; 1022 struct rt_msghdr *rtm = (void *)buf; 1023 char *cp = (char *)(rtm + 1); 1024 size_t l; 1025 1026 #define NEXTADDR(s) \ 1027 l = SA_SIZE(sizeof(*s)); memmove(cp, s, l); cp += l; 1028 memset(buf, 0, sizeof(buf)); 1029 rtm->rtm_type = RTM_IFANNOUNCE; 1030 rtm->rtm_flags = 0; 1031 rtm->rtm_addrs = RTA_DST|RTA_GATEWAY; 1032 rtm->rtm_version = RTM_VERSION; 1033 rtm->rtm_seq = 666; 1034 NEXTADDR(&sin); 1035 NEXTADDR(&sin); 1036 rtm->rtm_msglen = (u_short)((char *)cp - (char *)rtm); 1037 if (write(fd, rtm, rtm->rtm_msglen) != -1) { 1038 (*lfun)(LOG_ERR, "Writing to routing socket succeeded!"); 1039 return 0; 1040 } 1041 switch (errno) { 1042 case EACCES: 1043 return 0; 1044 case EOPNOTSUPP: 1045 return 1; 1046 default: 1047 (*lfun)(LOG_ERR, 1048 "Unexpected error writing to routing socket (%m)"); 1049 return 0; 1050 } 1051 #else 1052 return 0; 1053 #endif 1054 } 1055 #endif 1056 1057 static int 1058 conf_handle_inet(int fd, const void *lss, struct conf *cr) 1059 { 1060 char buf[BUFSIZ]; 1061 int proto; 1062 socklen_t slen = sizeof(proto); 1063 1064 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) { 1065 (*lfun)(LOG_ERR, "getsockopt failed (%m)"); 1066 return -1; 1067 } 1068 1069 if (debug) { 1070 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", lss); 1071 (*lfun)(LOG_DEBUG, "listening socket: %s", buf); 1072 } 1073 1074 switch (proto) { 1075 case SOCK_STREAM: 1076 cr->c_proto = IPPROTO_TCP; 1077 break; 1078 case SOCK_DGRAM: 1079 cr->c_proto = IPPROTO_UDP; 1080 break; 1081 default: 1082 (*lfun)(LOG_ERR, "unsupported protocol %d", proto); 1083 return -1; 1084 } 1085 return 0; 1086 } 1087 1088 const struct conf * 1089 conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss, 1090 struct conf *cr) 1091 { 1092 socklen_t slen; 1093 struct sockaddr_storage lss; 1094 size_t i; 1095 char buf[BUFSIZ]; 1096 1097 memset(cr, 0, sizeof(*cr)); 1098 slen = sizeof(lss); 1099 memset(&lss, 0, slen); 1100 if (getsockname(fd, (void *)&lss, &slen) == -1) { 1101 (*lfun)(LOG_ERR, "getsockname failed (%m)"); 1102 return NULL; 1103 } 1104 1105 switch (lss.ss_family) { 1106 case AF_INET: 1107 cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port); 1108 if (conf_handle_inet(fd, &lss, cr) == -1) 1109 return NULL; 1110 break; 1111 case AF_INET6: 1112 cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port); 1113 if (conf_handle_inet(fd, &lss, cr) == -1) 1114 return NULL; 1115 break; 1116 #ifdef AF_ROUTE 1117 case AF_ROUTE: 1118 if (!conf_route_perm(fd)) { 1119 (*lfun)(LOG_ERR, 1120 "permission denied to routing socket (%m)"); 1121 return NULL; 1122 } 1123 cr->c_proto = FSTAR; 1124 cr->c_port = FSTAR; 1125 memcpy(&lss, rss, sizeof(lss)); 1126 break; 1127 #endif 1128 default: 1129 (*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family); 1130 return NULL; 1131 } 1132 1133 cr->c_ss = lss; 1134 cr->c_lmask = FSTAR; 1135 cr->c_uid = (int)uid; 1136 cr->c_family = lss.ss_family; 1137 cr->c_name[0] = '\0'; 1138 cr->c_rmask = FSTAR; 1139 cr->c_nfail = FSTAR; 1140 cr->c_duration = FSTAR; 1141 1142 if (debug) 1143 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), 1144 "look:\t", "", cr)); 1145 1146 /* match the local config */ 1147 i = confset_match(&lconf, cr, conf_apply); 1148 if (i == lconf.cs_n) { 1149 if (debug) 1150 (*lfun)(LOG_DEBUG, "not found"); 1151 return NULL; 1152 } 1153 1154 conf_addr_set(cr, rss); 1155 /* match the remote config */ 1156 confset_match(&rconf, cr, conf_merge); 1157 /* to apply the mask */ 1158 conf_addr_set(cr, &cr->c_ss); 1159 1160 return cr; 1161 } 1162 1163 1164 void 1165 conf_parse(const char *f) 1166 { 1167 FILE *fp; 1168 char *line; 1169 size_t lineno, len; 1170 struct confset lc, rc, *cs; 1171 1172 if ((fp = fopen(f, "r")) == NULL) { 1173 (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f); 1174 return; 1175 } 1176 1177 lineno = 1; 1178 1179 confset_init(&rc); 1180 confset_init(&lc); 1181 cs = &lc; 1182 for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL; 1183 free(line)) 1184 { 1185 if (!*line) 1186 continue; 1187 if (strcmp(line, "[local]") == 0) { 1188 cs = &lc; 1189 continue; 1190 } 1191 if (strcmp(line, "[remote]") == 0) { 1192 cs = &rc; 1193 continue; 1194 } 1195 1196 if (confset_full(cs)) { 1197 if (confset_grow(cs) == -1) { 1198 confset_free(&lc); 1199 confset_free(&rc); 1200 fclose(fp); 1201 free(line); 1202 return; 1203 } 1204 } 1205 if (conf_parseline(f, lineno, line, confset_get(cs), 1206 cs == &lc) == -1) 1207 continue; 1208 confset_add(cs); 1209 } 1210 1211 fclose(fp); 1212 confset_sort(&lc); 1213 confset_sort(&rc); 1214 1215 confset_replace(&rconf, &rc); 1216 confset_replace(&lconf, &lc); 1217 1218 if (debug) { 1219 confset_list(&lconf, "local", "target"); 1220 confset_list(&rconf, "remote", "source"); 1221 } 1222 } 1223