udyfi.c (20505B)
1 /* 2 * MIT License 3 * 4 * Copyright (c) 2016-2023 Santtu Lakkala 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 #include <sys/cdefs.h> 25 #undef __BSD_VISIBLE 26 #define __BSD_VISIBLE 1 27 #include <sys/socket.h> 28 #include <sys/select.h> 29 #include <signal.h> 30 #include <setjmp.h> 31 #include <poll.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <netdb.h> 35 #include <string.h> 36 #include <stdio.h> 37 #include <errno.h> 38 #include <pwd.h> 39 #include <stdint.h> 40 #include <stdlib.h> 41 #include <stdbool.h> 42 #include <limits.h> 43 #ifdef USE_IFADDRS 44 #define __USE_MISC 45 #include <net/if.h> 46 #include <ifaddrs.h> 47 #endif 48 #include <time.h> 49 #if defined(USE_LIBTLS) 50 #include <tls.h> 51 #elif defined(USE_OPENSSL) 52 #undef USE_OPENSSL 53 #define USE_LIBTLS 54 #include "minitls.h" 55 #endif 56 #include "arg.h" 57 58 static jmp_buf terminate; 59 char *argv0; 60 61 #ifdef USE_LIBTLS 62 #define IF_SSL(...) __VA_ARGS__ 63 #else 64 #define IF_SSL(...) 65 #endif 66 67 #define MINUTES(x) ((x) * 60) 68 #define HOURS(x) (MINUTES(x) * 60) 69 #define DAYS(x) (HOURS(x) * 24) 70 #include "config.h" 71 72 static char **strsplit(char *s, int *c) 73 { 74 size_t n = 1; 75 char *r = s; 76 char *w = s; 77 char **rv = malloc((n + 1) * sizeof(*rv)); 78 enum { NONE, ERR, SQUOT = '\'', DQUOT = '"' } state = NONE; 79 80 rv[0] = s; 81 82 while (*r) { 83 switch (*r) { 84 case ' ': 85 if (state == NONE) { 86 *w++ = '\0'; 87 r++; 88 while (*r == ' ') 89 r++; 90 if (!*r) 91 continue; 92 rv = realloc(rv, (++n + 1) * sizeof(*rv)); 93 rv[n - 1] = w; 94 continue; 95 } 96 break; 97 98 case '\'': 99 case '"': 100 if (state == NONE) 101 state = *r; 102 else if ((char)state == *r) 103 state = NONE; 104 else 105 break; 106 107 r++; 108 continue; 109 110 case '\\': 111 if (state != SQUOT) { 112 if (!*++r) { 113 state = ERR; 114 continue; 115 } 116 } 117 break; 118 } 119 *w++ = *r++; 120 } 121 122 if (state != NONE) { 123 free(rv); 124 return NULL; 125 } 126 *w = '\0'; 127 rv[n] = NULL; 128 *c = n; 129 return rv; 130 } 131 132 static void sig_handler(int signum) 133 { 134 (void)signum; 135 longjmp(terminate, 0); 136 } 137 138 static void sighup_handler(int signum) 139 { 140 (void)signum; 141 } 142 143 static ssize_t http_get(const char *server, 144 const char *port, 145 const char *path, 146 const char * restrict headers, 147 const char *iface, 148 int *af, 149 char *buffer, 150 size_t bufsize 151 IF_SSL(, struct tls *ctx) 152 ) 153 { 154 struct addrinfo *res; 155 struct addrinfo *i; 156 struct addrinfo *k; 157 struct addrinfo hints = { .ai_family = *af, .ai_socktype = SOCK_STREAM }; 158 struct addrinfo *local = NULL; 159 #ifdef USE_IFADDRS 160 struct ifaddrs *addrs = NULL; 161 struct ifaddrs *j; 162 #endif 163 ssize_t r; 164 ssize_t s; 165 int sock; 166 167 if (iface) { 168 #if USE_IFADDRS 169 bool if_found = false; 170 if ((r = getifaddrs(&addrs))) 171 return -1; 172 for (j = addrs; j; j = j->ifa_next) { 173 if (!strcmp(j->ifa_name, iface)) { 174 if_found = true; 175 if (((j->ifa_flags & (IFF_UP | 176 IFF_BROADCAST | 177 IFF_LOOPBACK)) == 178 (IFF_UP | IFF_BROADCAST))) 179 break; 180 } 181 } 182 if (if_found && !j) { 183 freeifaddrs(addrs); 184 return -1; 185 } 186 187 if (!if_found) { 188 freeifaddrs(addrs); 189 addrs = NULL; 190 191 #endif 192 r = getaddrinfo(iface, NULL, &hints, &local); 193 if (r < 0) 194 return -1; 195 #if USE_IFADDRS 196 } 197 #endif 198 } 199 200 if ((r = getaddrinfo(server, port, &hints, &res))) { 201 #if USE_IFADDRS 202 if (addrs) 203 freeifaddrs(addrs); 204 #endif 205 if (local) 206 freeaddrinfo(local); 207 return -1; 208 } 209 210 for (i = res; i; i = i->ai_next) { 211 sock = socket(i->ai_family, i->ai_socktype, i->ai_protocol); 212 213 #if USE_IFADDRS 214 if (addrs) { 215 for (j = addrs; j; j = j->ifa_next) { 216 if (!strcmp(j->ifa_name, iface) && 217 (((j->ifa_flags & (IFF_UP | 218 IFF_BROADCAST | 219 IFF_LOOPBACK)) == 220 (IFF_UP | IFF_BROADCAST))) && 221 j->ifa_addr->sa_family == i->ai_family) 222 break; 223 } 224 if (j) { 225 if ((r = bind(sock, 226 j->ifa_addr, sizeof(struct sockaddr_storage)))) { 227 close(sock); 228 continue; 229 } 230 } 231 } else 232 #endif 233 if (local) { 234 for (k = local; k; k = k->ai_next) { 235 if (k->ai_family == i->ai_family && 236 !bind(sock, k->ai_addr, k->ai_addrlen)) 237 break; 238 } 239 if (!k) { 240 close(sock); 241 continue; 242 } 243 } 244 245 *af = i->ai_family; 246 if (!connect(sock, i->ai_addr, i->ai_addrlen)) 247 break; 248 close(sock); 249 } 250 251 freeaddrinfo(res); 252 #if USE_IFADDRS 253 if (addrs) 254 freeifaddrs(addrs); 255 #endif 256 if (local) 257 freeaddrinfo(local); 258 259 if (!i) 260 return -1; 261 262 if ((r = snprintf(buffer, bufsize, 263 "GET %s HTTP/1.0\r\nHost: %s\r\n%s\n", 264 path, server, headers ? headers : "")) >= (int)bufsize) { 265 close(sock); 266 return -1; 267 } 268 269 #ifdef USE_LIBTLS 270 if (ctx) { 271 if (tls_connect_socket(ctx, sock, server)) { 272 close(sock); 273 return -1; 274 } 275 276 if ((s = tls_write(ctx, buffer, r)) < r) { 277 tls_close(ctx); 278 tls_reset(ctx); 279 tls_configure(ctx, NULL); 280 close(sock); 281 return -1; 282 } 283 } else 284 #endif 285 if ((s = write(sock, buffer, r)) < r) { 286 close(sock); 287 return -1; 288 } 289 290 s = 0; 291 do { 292 #ifdef USE_LIBTLS 293 if (ctx) 294 r = tls_read(ctx, buffer + s, bufsize - s - 1); 295 else 296 #endif 297 r = read(sock, buffer + s, bufsize - s - 1); 298 if (r < 0) { 299 #ifdef USE_LIBTLS 300 if (ctx) { 301 if (r == TLS_WANT_POLLIN) { 302 poll(&(struct pollfd){ .fd = sock, .events = POLLIN }, 1, 0); 303 continue; 304 } 305 306 tls_close(ctx); 307 tls_reset(ctx); 308 tls_configure(ctx, NULL); 309 } 310 #endif 311 close(sock); 312 return -1; 313 } 314 s += r; 315 } while (r && s < (int)bufsize); 316 #ifdef USE_LIBTLS 317 if (ctx) { 318 tls_close(ctx); 319 tls_reset(ctx); 320 tls_configure(ctx, NULL); 321 } 322 #endif 323 close(sock); 324 buffer[s] = '\0'; 325 326 return s; 327 } 328 329 static char *add_header(char *buffer, char *buf_end, const char *name, const char *value) { 330 static const char sep[2] = ": "; 331 static const char end[2] = "\r\n"; 332 size_t nl; 333 size_t vl; 334 335 if (!buffer) 336 return NULL; 337 338 nl = strlen(name); 339 vl = strlen(value); 340 341 if (buffer + nl + vl + sizeof(sep) + sizeof(end) >= buf_end) 342 return NULL; 343 buffer = (char *)memcpy(buffer, name, nl) + nl; 344 buffer = (char *)memcpy(buffer, sep, sizeof(sep)) + sizeof(sep); 345 buffer = (char *)memcpy(buffer, value, vl) + vl; 346 buffer = (char *)memcpy(buffer, end, sizeof(end)) + sizeof(end); 347 *buffer = '\0'; 348 349 return buffer; 350 } 351 352 static int check_ip(const char *server, 353 const char *port, 354 const char *iface, 355 int af, 356 const char *ua, 357 char *ip_buffer, 358 size_t ip_size 359 IF_SSL(, struct tls *ctx) 360 ) 361 { 362 char header_buffer[1024]; 363 char buffer[1024]; 364 const char *ip; 365 size_t iplen; 366 367 if (!add_header(header_buffer, 1[&header_buffer], "User-Agent", ua)) 368 return -1; 369 370 if (http_get(server, port, "/", 371 header_buffer, 372 iface, 373 &af, 374 buffer, 375 sizeof(buffer) 376 IF_SSL(, ctx) 377 ) < 0) 378 return -1; 379 380 if ((ip = strstr(buffer, "Current IP Address: "))) 381 ip += sizeof("Current IP Address: ") - 1; 382 else if ((ip = strstr(buffer, "\r\n\r\n"))) 383 ip += sizeof("\r\n\r\n") - 1; 384 else 385 return -1; 386 387 switch (af) { 388 case AF_INET: 389 default: 390 iplen = strspn(ip, "0123456789."); 391 break; 392 case AF_INET6: 393 iplen = strspn(ip, "0123456789a-fA-F:"); 394 break; 395 } 396 if (ip[-1] == '\n' && ip[iplen]) 397 return -1; 398 if (snprintf(ip_buffer, ip_size, "%.*s", (int)iplen, ip) >= (int)ip_size) 399 return -1; 400 401 return 0; 402 } 403 404 static int auth_token(const char *user, 405 const char *password, 406 char *buffer, 407 size_t b_len) 408 { 409 static const char *base64 = 410 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 411 "abcdefghijklmnopqrstuvwxyz" 412 "0123456789+/"; 413 size_t ulen = strlen(user); 414 size_t plen = strlen(password); 415 size_t i; 416 size_t bits = 0; 417 uint32_t d = 0; 418 char *wp = buffer; 419 420 if ((ulen + plen + 3) / 3 * 4 >= b_len) 421 return -1; 422 423 for (i = 0; i < ulen; i++) { 424 d = (d << 8) | user[i]; 425 bits += 8; 426 while (bits >= 6) 427 *wp++ = base64[(d >> (bits -= 6)) & 0x3f]; 428 } 429 d = (d << 8) | ':'; 430 bits += 8; 431 for (i = 0; i < plen; i++) { 432 d = (d << 8) | password[i]; 433 bits += 8; 434 while (bits >= 6) 435 *wp++ = base64[(d >> (bits -= 6)) & 0x3f]; 436 } 437 438 if (bits) 439 *wp++ = base64[(d << (6 - bits)) & 0x3f]; 440 while ((wp - buffer) & 3) 441 *wp++ = '='; 442 *wp = '\0'; 443 444 return wp - buffer; 445 } 446 447 static const char *find_body(const char *response, 448 size_t len, size_t *blen) 449 { 450 size_t i; 451 452 for (i = 0; i < len - 1; i++) { 453 if (response[i] == '\n') { 454 if (response[i + 1] == '\n') { 455 *blen = len - i - 2; 456 return response + i + 2; 457 } else if (i < len - 2 && response[i + 1] == '\r' && 458 response[i + 2] == '\n') { 459 *blen = len - i - 3; 460 return response + i + 3; 461 } 462 } 463 } 464 465 return NULL; 466 } 467 468 enum update_status { 469 UP_BADAUTH, 470 UP_NOHOST, 471 UP_NOTFQDN, 472 UP_BADIP, 473 UP_NOCHG, 474 UP_GOOD, 475 UP_DNSERR, 476 UP_ABUSE, 477 UP_BADAGENT, 478 UP_911, 479 UP_UNKNOWN, 480 UP_REDIRECT, 481 UP_INTERNAL, 482 UP_NETWORK 483 }; 484 485 static const char *statusstr[] = { 486 "badauth", 487 "nohost", 488 "notfqdn", 489 "badip ", 490 "nochg", 491 "good ", 492 "dnserr", 493 "abuse", 494 "badagent", 495 "911" 496 }; 497 498 static unsigned short http_code(const char *buffer, const char *bend) 499 { 500 const char match[] = "HTTP/1."; 501 unsigned int rv = 0; 502 503 if (buffer + sizeof(match) >= bend || memcmp(buffer, match, sizeof(match) - 1)) 504 return 0; 505 buffer += sizeof(match); 506 if (buffer[-1] != '0' && buffer[-1] != '1') 507 return 0; 508 if (buffer >= bend || *buffer++ != ' ') 509 return 0; 510 for (; buffer < bend; buffer++) { 511 if (*buffer == ' ') 512 break; 513 if (*buffer >= '0' && *buffer <= '9') 514 rv = rv * 10 + (*buffer - '0'); 515 else 516 return 0; 517 518 if (rv > USHRT_MAX) 519 return 0; 520 } 521 522 return rv; 523 } 524 525 static int update_ip(const char *server, 526 const char *port, 527 const char *hosts, 528 const char *auth, 529 const char *iface, 530 int af, 531 const char *ua 532 IF_SSL(, struct tls *ctx) 533 ) 534 { 535 char buffer[1024]; 536 char path_buffer[1024]; 537 char header_buffer[1024]; 538 int r; 539 size_t bl; 540 const char *body; 541 unsigned short code; 542 char *bend = 1[&header_buffer]; 543 544 char *bpos = add_header(header_buffer, bend, "User-Agent", ua); 545 bpos = add_header(bpos, bend, "Authorization", auth); 546 547 if (!bpos) 548 return UP_INTERNAL; 549 550 r = snprintf(path_buffer, sizeof(path_buffer), 551 "/nic/update?hostname=%s", hosts); 552 if (r >= (int)sizeof(path_buffer)) 553 return UP_INTERNAL; 554 555 if ((r = http_get(server, port, path_buffer, 556 header_buffer, iface, &af, 557 buffer, sizeof(buffer) 558 IF_SSL(, ctx) 559 )) < 0) 560 return UP_NETWORK; 561 562 code = http_code(buffer, buffer + strlen(buffer)); 563 if (!code || code >= 500) 564 return UP_911; 565 if (code == 401) 566 return UP_BADAUTH; 567 if (code == 403) 568 return UP_NOHOST; 569 if (code > 400) 570 return UP_UNKNOWN; 571 if (code >= 300) 572 return UP_REDIRECT; 573 574 if ((body = find_body(buffer, r, 575 &bl))) { 576 for (r = 0; r < UP_UNKNOWN; r++) { 577 if (!strncmp(body, statusstr[r], 578 strlen(statusstr[r]))) 579 break; 580 } 581 } else { 582 r = UP_UNKNOWN; 583 } 584 585 return r; 586 } 587 588 static void usage(void) { 589 fprintf(stderr, 590 "Usage: %s " 591 "-u <username> " 592 "-p <password> " 593 "-f <passwordfile> " 594 "[-i <" 595 #ifdef USE_IFADDRS 596 "interface/" 597 #endif 598 "local address>] " 599 "[-U <username>] " 600 "[-c <checkip server>] " 601 "[-C <checkip port>] " 602 "[-d <dyndns server>] " 603 "[-D <dyndns port>] " 604 "[-F <config file>] " 605 "[-b] " 606 "[-P <pidfile>] " 607 IF_SSL( 608 "[-s] " 609 "[-S] " 610 "[-z] " 611 "[-Z] " 612 ) 613 "[-6] " 614 "[-4] " 615 "host[,host...]\n", 616 argv0); 617 } 618 619 static void write_pidfile(const char *pidfile, pid_t pid) 620 { 621 FILE *pdf = fopen(pidfile, "w"); 622 if (pdf) { 623 fprintf(pdf, "%ld\n", (long)pid); 624 fclose(pdf); 625 } 626 } 627 628 static void daemonize(const char *pidfile) { 629 pid_t pid; 630 if ((pid = fork())) { 631 if (pid < 0) 632 exit(EXIT_FAILURE); 633 if (pidfile) { 634 write_pidfile(pidfile, pid); 635 } 636 exit(EXIT_SUCCESS); 637 } 638 setsid(); 639 fclose(stdin); 640 fclose(stdout); 641 } 642 643 int main(int argc, char **argv) 644 { 645 const char *username = NULL; 646 const char * volatile pidfile = NULL; 647 const char *iface = NULL; 648 const char *dropuser = NULL; 649 const char *domains = NULL; 650 const char *ua = default_ua; 651 char password[256] = ""; 652 char authbuf[1024] = "Basic "; 653 int fd; 654 time_t next_refresh = 0; 655 time_t last_error = 0; 656 char ipbuf1[64]; 657 char ipbuf2[64] = ""; 658 char *ip = ipbuf1; 659 char *prev_ip = ipbuf2; 660 int background = 0; 661 int af = AF_UNSPEC; 662 volatile int ret = EXIT_SUCCESS; 663 FILE * volatile log = stderr; 664 const char *logfile = NULL; 665 char *arg; 666 sigset_t sigset_hup; 667 sigset_t sigset_dfl; 668 669 struct { 670 char **argv; 671 int argc; 672 char *arg; 673 } cfgfile = { 0 }; 674 675 #ifdef USE_LIBTLS 676 int port_set = 0; 677 int check_port_set = 0; 678 bool use_ssl = dyndns_ssl; 679 bool check_ssl = checkip_ssl; 680 struct tls * volatile ctx = NULL; 681 #endif 682 683 sigemptyset(&sigset_hup); 684 sigaddset(&sigset_hup, SIGHUP); 685 686 for (argv0 = *argv, argv++, argc--; 687 argc && argv[0][0] == '-' && argv[0][1]; 688 argc--, argv++) { 689 arg = &argv[0][1]; 690 691 cfgtoggle: 692 if (argv[0][1] == '-' && argv[0][1] == '\0') { 693 argv++; 694 argc--; 695 break; 696 } 697 698 while (*arg) { 699 switch (*arg++) { 700 case 'a': 701 ua = EARGF(usage()); 702 break; 703 case 'i': 704 iface = EARGF(usage()); 705 break; 706 case 'u': 707 username = EARGF(usage()); 708 break; 709 case 'U': 710 dropuser = EARGF(usage()); 711 break; 712 case 'p': { 713 char *pass = EARGF(usage()); 714 snprintf(password, sizeof(password), 715 "%s", pass); 716 memset(pass, 0, strlen(pass)); 717 break; 718 } 719 case 'F': { 720 FILE *f; 721 char *data = NULL; 722 size_t n = 0; 723 ssize_t r; 724 725 if (cfgfile.argv) { 726 fprintf(stderr, "Nested configuration files not supported\n"); 727 return EXIT_FAILURE; 728 } 729 if (!(f = fopen(EARGF(usage()), "r"))) { 730 fprintf(stderr, "Failed to open configuration file\n"); 731 return EXIT_FAILURE; 732 } 733 734 r = getline(&data, &n, f); 735 fclose(f); 736 737 if (r < 0) { 738 fprintf(stderr, "Failed to read configuration file\n"); 739 return EXIT_FAILURE; 740 } 741 742 while (r && (data[r - 1] == '\r' || data[r - 1] == '\n')) 743 r--; 744 data[r] = '\0'; 745 746 if (!r) { 747 free(data); 748 break; 749 } 750 751 cfgfile.argv = argv; 752 cfgfile.argc = argc; 753 cfgfile.arg = arg; 754 755 argv = strsplit(data, &argc); 756 if (!argv) { 757 fprintf(stderr, "Failed to parse configuration file\n"); 758 free(data); 759 return EXIT_FAILURE; 760 } 761 arg = argv[0]; 762 if (*arg != '-') 763 continue; 764 arg++; 765 goto cfgtoggle; 766 } 767 case 'f': 768 if ((fd = open(EARGF(usage()), O_RDONLY)) >= 0) { 769 int r = read(fd, password, sizeof(password) - 1); 770 close(fd); 771 772 if (r < 0) { 773 fprintf(stderr, "Failed to read password from file\n"); 774 return EXIT_FAILURE; 775 } 776 777 while (r && (password[r - 1] == '\n' || password[r - 1] == '\r')) 778 r--; 779 password[r] = '\0'; 780 } else { 781 fprintf(stderr, "Failed to open password file\n"); 782 return EXIT_FAILURE; 783 } 784 break; 785 case 'c': 786 checkip_service = EARGF(usage()); 787 break; 788 case '4': 789 af = AF_INET; 790 break; 791 case '6': 792 af = AF_INET6; 793 break; 794 case 'C': 795 checkip_port = EARGF(usage()); 796 IF_SSL(check_port_set = 1;) 797 break; 798 case 'd': 799 dyndns_service = EARGF(usage()); 800 break; 801 case 'D': 802 dyndns_port = EARGF(usage()); 803 IF_SSL(port_set = 1;) 804 break; 805 case 'b': 806 background = 1; 807 break; 808 case 'P': 809 pidfile = EARGF(usage()); 810 break; 811 case 'l': 812 logfile = EARGF(usage()); 813 break; 814 #ifdef USE_LIBTLS 815 case 's': 816 use_ssl = true; 817 break; 818 case 'S': 819 check_ssl = true; 820 break; 821 case 'z': 822 use_ssl = false; 823 break; 824 case 'Z': 825 check_ssl = false; 826 break; 827 #endif 828 default: 829 usage(); 830 return EXIT_FAILURE; 831 } 832 } 833 } 834 835 if (argc) 836 domains = argv[0]; 837 if (cfgfile.argv) { 838 argv = cfgfile.argv; 839 argc = cfgfile.argc; 840 arg = cfgfile.arg; 841 842 cfgfile.argv = NULL; 843 844 goto cfgtoggle; 845 } 846 847 #if defined(USE_LIBTLS) 848 if (use_ssl || check_ssl) { 849 ctx = tls_client(); 850 851 if (!ctx) { 852 fprintf(stderr, "SSL/TLS initialization failed.\n"); 853 return EXIT_FAILURE; 854 } 855 856 if (use_ssl && !port_set) 857 dyndns_port = "443"; 858 if (check_ssl && !check_port_set) 859 checkip_port = "443"; 860 } 861 #endif 862 863 if (!domains || !username) { 864 usage(); 865 return EXIT_FAILURE; 866 } 867 868 auth_token(username, password, authbuf + strlen(authbuf), sizeof(authbuf) - strlen(authbuf)); 869 memset(password, 0, sizeof(password)); 870 871 srand(time(NULL)); 872 873 if (logfile) 874 log = fopen(logfile, "a"); 875 876 if (background) 877 daemonize(pidfile); 878 else if (pidfile) 879 write_pidfile(pidfile, getpid()); 880 881 if (dropuser) { 882 struct passwd *ent = getpwnam(dropuser); 883 if (!ent) { 884 fprintf(log, "Failed to get user\n"); 885 ret = EXIT_FAILURE; 886 goto out; 887 } 888 889 if (setgid(ent->pw_gid) || 890 setuid(ent->pw_uid)) { 891 fprintf(log, "Failed to change user\n"); 892 ret = EXIT_FAILURE; 893 goto out; 894 } 895 } 896 897 fprintf(log, "udyfi started\n"); 898 899 if (setjmp(terminate)) 900 goto out; 901 902 signal(SIGINT, sig_handler); 903 signal(SIGTERM, sig_handler); 904 sigaction(SIGHUP, &(struct sigaction){ .sa_handler = sighup_handler }, NULL); 905 906 sigprocmask(SIG_BLOCK, &sigset_hup, &sigset_dfl); 907 908 for (;;) { 909 time_t now = time(NULL); 910 911 if (now >= last_error + error_fallback && 912 check_ip(checkip_service, checkip_port, iface, af, ua, 913 ip, sizeof(ipbuf1) 914 IF_SSL(, check_ssl ? ctx : NULL) 915 ) >= 0) { 916 char *tmp; 917 918 if ((strcmp(ip, prev_ip) || now > next_refresh)) { 919 switch (update_ip(dyndns_service, dyndns_port, 920 domains, 921 authbuf, iface, af, ua 922 IF_SSL(, use_ssl ? ctx : NULL) 923 )) { 924 case UP_BADAUTH: 925 fprintf(log, "FATAL: " 926 "Authentication error\n"); 927 ret = EXIT_FAILURE; 928 goto out; 929 case UP_NOHOST: 930 fprintf(log, "FATAL: " 931 "No hostnames specified\n"); 932 ret = EXIT_FAILURE; 933 goto out; 934 case UP_NOTFQDN: 935 fprintf(log, "FATAL: " 936 "Malformed hostnames\n"); 937 ret = EXIT_FAILURE; 938 goto out; 939 case UP_BADIP: 940 fprintf(log, "WARNING: " 941 "Server rejected our IP\n"); 942 break; 943 case UP_NOCHG: 944 fprintf(log, "IP %s refreshed\n", 945 ip); 946 break; 947 case UP_GOOD: 948 fprintf(log, "%s now point to %s\n", 949 domains, ip); 950 break; 951 case UP_911: 952 case UP_DNSERR: 953 fprintf(log, "WARNING: " 954 "Temporary service error\n"); 955 last_error = now; 956 goto retry; 957 case UP_ABUSE: 958 fprintf(log, "FATAL: " 959 "We are flagged as abuse\n"); 960 ret = EXIT_FAILURE; 961 goto out; 962 case UP_BADAGENT: 963 fprintf(log, "FATAL: " 964 "We are flagged as bad agent\n"); 965 ret = EXIT_FAILURE; 966 goto out; 967 case UP_UNKNOWN: 968 fprintf(log, "WARNING: " 969 "Unknown status reply\n"); 970 break; 971 case UP_REDIRECT: 972 fprintf(log, "FATAL: " 973 "Server send a redirection, configuration error?\n"); 974 ret = EXIT_FAILURE; 975 goto out; 976 case UP_INTERNAL: 977 fprintf(log, "FATAL: " 978 "Internal error, likely run " 979 "out of buffer\n"); 980 ret = EXIT_FAILURE; 981 goto out; 982 case UP_NETWORK: 983 fprintf(log, "WARNING: " 984 "Networking error\n"); 985 goto retry; 986 } 987 988 next_refresh = now + minimum_refresh + 989 rand() * minimum_refresh_rand / 990 RAND_MAX; 991 fprintf(log, "Next forced update at %s", 992 ctime(&next_refresh)); 993 fflush(log); 994 995 tmp = ip; 996 ip = prev_ip; 997 prev_ip = tmp; 998 } 999 } else { 1000 fprintf(log, "IP check failed.\n"); 1001 fflush(log); 1002 } 1003 1004 retry: 1005 pselect(0, NULL, NULL, NULL, &(struct timespec){ 1006 .tv_sec = (last_error + error_fallback < now ? 1007 check_interval + rand() * check_interval_rand / RAND_MAX : 1008 last_error + error_fallback - now + rand() * error_fallback_rand / RAND_MAX) 1009 }, &sigset_dfl); 1010 } 1011 1012 out: 1013 #ifdef USE_LIBTLS 1014 if (ctx) 1015 tls_free(ctx); 1016 #endif 1017 1018 if (pidfile) 1019 unlink(pidfile); 1020 1021 if (log != stderr) 1022 fclose(log); 1023 1024 return ret; 1025 }