Annotation of embedaddon/dnsmasq/src/dnsmasq.c, revision 1.1
1.1 ! misho 1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
! 2:
! 3: This program is free software; you can redistribute it and/or modify
! 4: it under the terms of the GNU General Public License as published by
! 5: the Free Software Foundation; version 2 dated June, 1991, or
! 6: (at your option) version 3 dated 29 June, 2007.
! 7:
! 8: This program is distributed in the hope that it will be useful,
! 9: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 11: GNU General Public License for more details.
! 12:
! 13: You should have received a copy of the GNU General Public License
! 14: along with this program. If not, see <http://www.gnu.org/licenses/>.
! 15: */
! 16:
! 17: /* Declare static char *compiler_opts in config.h */
! 18: #define DNSMASQ_COMPILE_OPTS
! 19:
! 20: #include "dnsmasq.h"
! 21:
! 22: struct daemon *daemon;
! 23:
! 24: static volatile pid_t pid = 0;
! 25: static volatile int pipewrite;
! 26:
! 27: static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
! 28: static void check_dns_listeners(fd_set *set, time_t now);
! 29: static void sig_handler(int sig);
! 30: static void async_event(int pipe, time_t now);
! 31: static void fatal_event(struct event_desc *ev, char *msg);
! 32: static int read_event(int fd, struct event_desc *evp, char **msg);
! 33:
! 34: int main (int argc, char **argv)
! 35: {
! 36: int bind_fallback = 0;
! 37: time_t now;
! 38: struct sigaction sigact;
! 39: struct iname *if_tmp;
! 40: int piperead, pipefd[2], err_pipe[2];
! 41: struct passwd *ent_pw = NULL;
! 42: #if defined(HAVE_SCRIPT)
! 43: uid_t script_uid = 0;
! 44: gid_t script_gid = 0;
! 45: #endif
! 46: struct group *gp = NULL;
! 47: long i, max_fd = sysconf(_SC_OPEN_MAX);
! 48: char *baduser = NULL;
! 49: int log_err;
! 50: #if defined(HAVE_LINUX_NETWORK)
! 51: cap_user_header_t hdr = NULL;
! 52: cap_user_data_t data = NULL;
! 53: #endif
! 54: struct dhcp_context *context;
! 55:
! 56: #ifdef LOCALEDIR
! 57: setlocale(LC_ALL, "");
! 58: bindtextdomain("dnsmasq", LOCALEDIR);
! 59: textdomain("dnsmasq");
! 60: #endif
! 61:
! 62: sigact.sa_handler = sig_handler;
! 63: sigact.sa_flags = 0;
! 64: sigemptyset(&sigact.sa_mask);
! 65: sigaction(SIGUSR1, &sigact, NULL);
! 66: sigaction(SIGUSR2, &sigact, NULL);
! 67: sigaction(SIGHUP, &sigact, NULL);
! 68: sigaction(SIGTERM, &sigact, NULL);
! 69: sigaction(SIGALRM, &sigact, NULL);
! 70: sigaction(SIGCHLD, &sigact, NULL);
! 71:
! 72: /* ignore SIGPIPE */
! 73: sigact.sa_handler = SIG_IGN;
! 74: sigaction(SIGPIPE, &sigact, NULL);
! 75:
! 76: umask(022); /* known umask, create leases and pid files as 0644 */
! 77:
! 78: read_opts(argc, argv, compile_opts);
! 79:
! 80: if (daemon->edns_pktsz < PACKETSZ)
! 81: daemon->edns_pktsz = PACKETSZ;
! 82: daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
! 83: daemon->edns_pktsz : DNSMASQ_PACKETSZ;
! 84: daemon->packet = safe_malloc(daemon->packet_buff_sz);
! 85:
! 86: daemon->addrbuff = safe_malloc(ADDRSTRLEN);
! 87:
! 88:
! 89: #ifdef HAVE_DHCP
! 90: if (!daemon->lease_file)
! 91: {
! 92: if (daemon->dhcp || daemon->dhcp6)
! 93: daemon->lease_file = LEASEFILE;
! 94: }
! 95: #endif
! 96:
! 97: /* Close any file descriptors we inherited apart from std{in|out|err}
! 98:
! 99: Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
! 100: otherwise file descriptors we create can end up being 0, 1, or 2
! 101: and then get accidentally closed later when we make 0, 1, and 2
! 102: open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
! 103: but it's not guaranteed. By opening /dev/null three times, we
! 104: ensure that we're not using those fds for real stuff. */
! 105: for (i = 0; i < max_fd; i++)
! 106: if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
! 107: close(i);
! 108: else
! 109: open("/dev/null", O_RDWR);
! 110:
! 111: #ifndef HAVE_LINUX_NETWORK
! 112: # if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
! 113: if (!option_bool(OPT_NOWILD))
! 114: {
! 115: bind_fallback = 1;
! 116: set_option_bool(OPT_NOWILD);
! 117: }
! 118: # endif
! 119:
! 120: /* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
! 121: if (option_bool(OPT_CLEVERBIND))
! 122: {
! 123: bind_fallback = 1;
! 124: set_option_bool(OPT_NOWILD);
! 125: reset_option_bool(OPT_CLEVERBIND);
! 126: }
! 127: #endif
! 128:
! 129: #ifndef HAVE_TFTP
! 130: if (option_bool(OPT_TFTP))
! 131: die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
! 132: #endif
! 133:
! 134: #ifdef HAVE_CONNTRACK
! 135: if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
! 136: die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
! 137: #else
! 138: if (option_bool(OPT_CONNTRACK))
! 139: die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
! 140: #endif
! 141:
! 142: #ifdef HAVE_SOLARIS_NETWORK
! 143: if (daemon->max_logs != 0)
! 144: die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
! 145: #endif
! 146:
! 147: #ifdef __ANDROID__
! 148: if (daemon->max_logs != 0)
! 149: die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
! 150: #endif
! 151:
! 152: #ifndef HAVE_AUTH
! 153: if (daemon->authserver)
! 154: die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
! 155: #endif
! 156:
! 157: rand_init();
! 158:
! 159: now = dnsmasq_time();
! 160:
! 161: /* Create a serial at startup if not configured. */
! 162: if (daemon->authinterface && daemon->soa_sn == 0)
! 163: #ifdef HAVE_BROKEN_RTC
! 164: die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
! 165: #else
! 166: daemon->soa_sn = now;
! 167: #endif
! 168:
! 169: #ifdef HAVE_DHCP
! 170: if (daemon->dhcp || daemon->dhcp6)
! 171: {
! 172:
! 173: # ifdef HAVE_DHCP6
! 174: if (daemon->dhcp6)
! 175: {
! 176: daemon->doing_ra = option_bool(OPT_RA);
! 177:
! 178: for (context = daemon->dhcp6; context; context = context->next)
! 179: {
! 180: if (context->flags & CONTEXT_DHCP)
! 181: daemon->doing_dhcp6 = 1;
! 182: if (context->flags & CONTEXT_RA)
! 183: daemon->doing_ra = 1;
! 184: #ifndef HAVE_LINUX_NETWORK
! 185: if (context->flags & CONTEXT_TEMPLATE)
! 186: die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
! 187: #endif
! 188: }
! 189: }
! 190: # endif
! 191:
! 192: /* Note that order matters here, we must call lease_init before
! 193: creating any file descriptors which shouldn't be leaked
! 194: to the lease-script init process. We need to call common_init
! 195: before lease_init to allocate buffers it uses.*/
! 196: if (daemon->dhcp || daemon->doing_dhcp6)
! 197: {
! 198: dhcp_common_init();
! 199: lease_init(now);
! 200: }
! 201:
! 202: if (daemon->dhcp)
! 203: dhcp_init();
! 204:
! 205: # ifdef HAVE_DHCP6
! 206: if (daemon->doing_ra)
! 207: ra_init(now);
! 208:
! 209: if (daemon->doing_dhcp6)
! 210: dhcp6_init();
! 211: # endif
! 212: }
! 213:
! 214: #endif
! 215:
! 216: #ifdef HAVE_IPSET
! 217: if (daemon->ipsets)
! 218: ipset_init();
! 219: #endif
! 220:
! 221: #ifdef HAVE_LINUX_NETWORK
! 222: netlink_init();
! 223:
! 224: if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
! 225: die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
! 226: #endif
! 227:
! 228: if (!enumerate_interfaces())
! 229: die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
! 230:
! 231: if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
! 232: {
! 233: create_bound_listeners(1);
! 234:
! 235: if (!option_bool(OPT_CLEVERBIND))
! 236: for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
! 237: if (if_tmp->name && !if_tmp->used)
! 238: die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
! 239:
! 240: #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
! 241: /* after enumerate_interfaces() */
! 242: if (daemon->dhcp)
! 243: {
! 244: bindtodevice(daemon->dhcpfd);
! 245: if (daemon->enable_pxe)
! 246: bindtodevice(daemon->pxefd);
! 247: }
! 248: #endif
! 249:
! 250: #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
! 251: if (daemon->dhcp6)
! 252: bindtodevice(daemon->dhcp6fd);
! 253: #endif
! 254: }
! 255: else
! 256: create_wildcard_listeners();
! 257:
! 258: #ifdef HAVE_DHCP6
! 259: /* after enumerate_interfaces() */
! 260: if (daemon->doing_dhcp6 || daemon->doing_ra)
! 261: join_multicast(1);
! 262: #endif
! 263:
! 264: if (daemon->port != 0)
! 265: cache_init();
! 266:
! 267: if (option_bool(OPT_DBUS))
! 268: #ifdef HAVE_DBUS
! 269: {
! 270: char *err;
! 271: daemon->dbus = NULL;
! 272: daemon->watches = NULL;
! 273: if ((err = dbus_init()))
! 274: die(_("DBus error: %s"), err, EC_MISC);
! 275: }
! 276: #else
! 277: die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
! 278: #endif
! 279:
! 280: if (daemon->port != 0)
! 281: pre_allocate_sfds();
! 282:
! 283: #if defined(HAVE_SCRIPT)
! 284: /* Note getpwnam returns static storage */
! 285: if ((daemon->dhcp || daemon->dhcp6) &&
! 286: daemon->scriptuser &&
! 287: (daemon->lease_change_command || daemon->luascript))
! 288: {
! 289: if ((ent_pw = getpwnam(daemon->scriptuser)))
! 290: {
! 291: script_uid = ent_pw->pw_uid;
! 292: script_gid = ent_pw->pw_gid;
! 293: }
! 294: else
! 295: baduser = daemon->scriptuser;
! 296: }
! 297: #endif
! 298:
! 299: if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
! 300: baduser = daemon->username;
! 301: else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
! 302: baduser = daemon->groupname;
! 303:
! 304: if (baduser)
! 305: die(_("unknown user or group: %s"), baduser, EC_BADCONF);
! 306:
! 307: /* implement group defaults, "dip" if available, or group associated with uid */
! 308: if (!daemon->group_set && !gp)
! 309: {
! 310: if (!(gp = getgrnam(CHGRP)) && ent_pw)
! 311: gp = getgrgid(ent_pw->pw_gid);
! 312:
! 313: /* for error message */
! 314: if (gp)
! 315: daemon->groupname = gp->gr_name;
! 316: }
! 317:
! 318: #if defined(HAVE_LINUX_NETWORK)
! 319: /* determine capability API version here, while we can still
! 320: call safe_malloc */
! 321: if (ent_pw && ent_pw->pw_uid != 0)
! 322: {
! 323: int capsize = 1; /* for header version 1 */
! 324: hdr = safe_malloc(sizeof(*hdr));
! 325:
! 326: /* find version supported by kernel */
! 327: memset(hdr, 0, sizeof(*hdr));
! 328: capget(hdr, NULL);
! 329:
! 330: if (hdr->version != LINUX_CAPABILITY_VERSION_1)
! 331: {
! 332: /* if unknown version, use largest supported version (3) */
! 333: if (hdr->version != LINUX_CAPABILITY_VERSION_2)
! 334: hdr->version = LINUX_CAPABILITY_VERSION_3;
! 335: capsize = 2;
! 336: }
! 337:
! 338: data = safe_malloc(sizeof(*data) * capsize);
! 339: memset(data, 0, sizeof(*data) * capsize);
! 340: }
! 341: #endif
! 342:
! 343: /* Use a pipe to carry signals and other events back to the event loop
! 344: in a race-free manner and another to carry errors to daemon-invoking process */
! 345: safe_pipe(pipefd, 1);
! 346:
! 347: piperead = pipefd[0];
! 348: pipewrite = pipefd[1];
! 349: /* prime the pipe to load stuff first time. */
! 350: send_event(pipewrite, EVENT_RELOAD, 0, NULL);
! 351:
! 352: err_pipe[1] = -1;
! 353:
! 354: if (!option_bool(OPT_DEBUG))
! 355: {
! 356: /* The following code "daemonizes" the process.
! 357: See Stevens section 12.4 */
! 358:
! 359: if (chdir("/") != 0)
! 360: die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
! 361:
! 362: #ifndef NO_FORK
! 363: if (!option_bool(OPT_NO_FORK))
! 364: {
! 365: pid_t pid;
! 366:
! 367: /* pipe to carry errors back to original process.
! 368: When startup is complete we close this and the process terminates. */
! 369: safe_pipe(err_pipe, 0);
! 370:
! 371: if ((pid = fork()) == -1)
! 372: /* fd == -1 since we've not forked, never returns. */
! 373: send_event(-1, EVENT_FORK_ERR, errno, NULL);
! 374:
! 375: if (pid != 0)
! 376: {
! 377: struct event_desc ev;
! 378: char *msg;
! 379:
! 380: /* close our copy of write-end */
! 381: close(err_pipe[1]);
! 382:
! 383: /* check for errors after the fork */
! 384: if (read_event(err_pipe[0], &ev, &msg))
! 385: fatal_event(&ev, msg);
! 386:
! 387: _exit(EC_GOOD);
! 388: }
! 389:
! 390: close(err_pipe[0]);
! 391:
! 392: /* NO calls to die() from here on. */
! 393:
! 394: setsid();
! 395:
! 396: if ((pid = fork()) == -1)
! 397: send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
! 398:
! 399: if (pid != 0)
! 400: _exit(0);
! 401: }
! 402: #endif
! 403:
! 404: /* write pidfile _after_ forking ! */
! 405: if (daemon->runfile)
! 406: {
! 407: int fd, err = 0;
! 408:
! 409: sprintf(daemon->namebuff, "%d\n", (int) getpid());
! 410:
! 411: /* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
! 412: in a directory which is writable by the non-privileged user that dnsmasq runs as. This
! 413: allows the daemon to delete the file as part of its shutdown. This is a security hole to the
! 414: extent that an attacker running as the unprivileged user could replace the pidfile with a
! 415: symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
! 416:
! 417: The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
! 418: ensuring that the open() fails should there be any existing file (because the unlink() failed,
! 419: or an attacker exploited the race between unlink() and open()). This ensures that no symlink
! 420: attack can succeed.
! 421:
! 422: Any compromise of the non-privileged user still theoretically allows the pid-file to be
! 423: replaced whilst dnsmasq is running. The worst that could allow is that the usual
! 424: "shutdown dnsmasq" shell command could be tricked into stopping any other process.
! 425:
! 426: Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
! 427: failure to write the pid-file.
! 428: */
! 429:
! 430: unlink(daemon->runfile);
! 431:
! 432: if ((fd = open(daemon->runfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
! 433: {
! 434: /* only complain if started as root */
! 435: if (getuid() == 0)
! 436: err = 1;
! 437: }
! 438: else
! 439: {
! 440: if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
! 441: err = 1;
! 442:
! 443: while (!err && close(fd) == -1)
! 444: if (!retry_send())
! 445: err = 1;
! 446: }
! 447:
! 448: if (err)
! 449: {
! 450: send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
! 451: _exit(0);
! 452: }
! 453: }
! 454: }
! 455:
! 456: log_err = log_start(ent_pw, err_pipe[1]);
! 457:
! 458: if (!option_bool(OPT_DEBUG))
! 459: {
! 460: /* open stdout etc to /dev/null */
! 461: int nullfd = open("/dev/null", O_RDWR);
! 462: dup2(nullfd, STDOUT_FILENO);
! 463: dup2(nullfd, STDERR_FILENO);
! 464: dup2(nullfd, STDIN_FILENO);
! 465: close(nullfd);
! 466: }
! 467:
! 468: /* if we are to run scripts, we need to fork a helper before dropping root. */
! 469: daemon->helperfd = -1;
! 470: #ifdef HAVE_SCRIPT
! 471: if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
! 472: daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
! 473: #endif
! 474:
! 475: if (!option_bool(OPT_DEBUG) && getuid() == 0)
! 476: {
! 477: int bad_capabilities = 0;
! 478: gid_t dummy;
! 479:
! 480: /* remove all supplimentary groups */
! 481: if (gp &&
! 482: (setgroups(0, &dummy) == -1 ||
! 483: setgid(gp->gr_gid) == -1))
! 484: {
! 485: send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
! 486: _exit(0);
! 487: }
! 488:
! 489: if (ent_pw && ent_pw->pw_uid != 0)
! 490: {
! 491: #if defined(HAVE_LINUX_NETWORK)
! 492: /* On linux, we keep CAP_NETADMIN (for ARP-injection) and
! 493: CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
! 494: ports because of DAD, or we're doing it dynamically,
! 495: we need CAP_NET_BIND_SERVICE too. */
! 496: if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
! 497: data->effective = data->permitted = data->inheritable =
! 498: (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
! 499: (1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
! 500: else
! 501: data->effective = data->permitted = data->inheritable =
! 502: (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
! 503:
! 504: /* Tell kernel to not clear capabilities when dropping root */
! 505: if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
! 506: bad_capabilities = errno;
! 507:
! 508: #elif defined(HAVE_SOLARIS_NETWORK)
! 509: /* http://developers.sun.com/solaris/articles/program_privileges.html */
! 510: priv_set_t *priv_set;
! 511:
! 512: if (!(priv_set = priv_str_to_set("basic", ",", NULL)) ||
! 513: priv_addset(priv_set, PRIV_NET_ICMPACCESS) == -1 ||
! 514: priv_addset(priv_set, PRIV_SYS_NET_CONFIG) == -1)
! 515: bad_capabilities = errno;
! 516:
! 517: if (priv_set && bad_capabilities == 0)
! 518: {
! 519: priv_inverse(priv_set);
! 520:
! 521: if (setppriv(PRIV_OFF, PRIV_LIMIT, priv_set) == -1)
! 522: bad_capabilities = errno;
! 523: }
! 524:
! 525: if (priv_set)
! 526: priv_freeset(priv_set);
! 527:
! 528: #endif
! 529:
! 530: if (bad_capabilities != 0)
! 531: {
! 532: send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
! 533: _exit(0);
! 534: }
! 535:
! 536: /* finally drop root */
! 537: if (setuid(ent_pw->pw_uid) == -1)
! 538: {
! 539: send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
! 540: _exit(0);
! 541: }
! 542:
! 543: #ifdef HAVE_LINUX_NETWORK
! 544: if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
! 545: data->effective = data->permitted =
! 546: (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
! 547: else
! 548: data->effective = data->permitted =
! 549: (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
! 550: data->inheritable = 0;
! 551:
! 552: /* lose the setuid and setgid capbilities */
! 553: if (capset(hdr, data) == -1)
! 554: {
! 555: send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
! 556: _exit(0);
! 557: }
! 558: #endif
! 559:
! 560: }
! 561: }
! 562:
! 563: #ifdef HAVE_LINUX_NETWORK
! 564: if (option_bool(OPT_DEBUG))
! 565: prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
! 566: #endif
! 567:
! 568: #ifdef HAVE_TFTP
! 569: if (option_bool(OPT_TFTP))
! 570: {
! 571: DIR *dir;
! 572: struct tftp_prefix *p;
! 573:
! 574: if (daemon->tftp_prefix)
! 575: {
! 576: if (!((dir = opendir(daemon->tftp_prefix))))
! 577: {
! 578: send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
! 579: _exit(0);
! 580: }
! 581: closedir(dir);
! 582: }
! 583:
! 584: for (p = daemon->if_prefix; p; p = p->next)
! 585: {
! 586: if (!((dir = opendir(p->prefix))))
! 587: {
! 588: send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
! 589: _exit(0);
! 590: }
! 591: closedir(dir);
! 592: }
! 593: }
! 594: #endif
! 595:
! 596: if (daemon->port == 0)
! 597: my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
! 598: else if (daemon->cachesize != 0)
! 599: my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
! 600: else
! 601: my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
! 602:
! 603: my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
! 604:
! 605: #ifdef HAVE_DBUS
! 606: if (option_bool(OPT_DBUS))
! 607: {
! 608: if (daemon->dbus)
! 609: my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
! 610: else
! 611: my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
! 612: }
! 613: #endif
! 614:
! 615: if (log_err != 0)
! 616: my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
! 617: daemon->log_file, strerror(log_err));
! 618:
! 619: if (bind_fallback)
! 620: my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
! 621:
! 622: if (!option_bool(OPT_NOWILD))
! 623: for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
! 624: if (if_tmp->name && !if_tmp->used)
! 625: my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
! 626:
! 627: if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
! 628: {
! 629: if (daemon->resolv_files && !daemon->resolv_files->is_default)
! 630: my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
! 631: daemon->resolv_files = NULL;
! 632: if (!daemon->servers)
! 633: my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
! 634: }
! 635:
! 636: if (daemon->max_logs != 0)
! 637: my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
! 638:
! 639:
! 640: #ifdef HAVE_DHCP
! 641: for (context = daemon->dhcp; context; context = context->next)
! 642: log_context(AF_INET, context);
! 643:
! 644: # ifdef HAVE_DHCP6
! 645: for (context = daemon->dhcp6; context; context = context->next)
! 646: log_context(AF_INET6, context);
! 647:
! 648: if (daemon->doing_dhcp6 || daemon->doing_ra)
! 649: dhcp_construct_contexts(now);
! 650:
! 651: if (option_bool(OPT_RA))
! 652: my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
! 653: # endif
! 654:
! 655: /* after dhcp_contruct_contexts */
! 656: if (daemon->dhcp || daemon->doing_dhcp6)
! 657: lease_find_interfaces(now);
! 658: #endif
! 659:
! 660: #ifdef HAVE_TFTP
! 661: if (option_bool(OPT_TFTP))
! 662: {
! 663: #ifdef FD_SETSIZE
! 664: if (FD_SETSIZE < (unsigned)max_fd)
! 665: max_fd = FD_SETSIZE;
! 666: #endif
! 667:
! 668: my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
! 669: daemon->tftp_prefix ? _("root is ") : _("enabled"),
! 670: daemon->tftp_prefix ? daemon->tftp_prefix: "",
! 671: option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
! 672:
! 673: /* This is a guess, it assumes that for small limits,
! 674: disjoint files might be served, but for large limits,
! 675: a single file will be sent to may clients (the file only needs
! 676: one fd). */
! 677:
! 678: max_fd -= 30; /* use other than TFTP */
! 679:
! 680: if (max_fd < 0)
! 681: max_fd = 5;
! 682: else if (max_fd < 100)
! 683: max_fd = max_fd/2;
! 684: else
! 685: max_fd = max_fd - 20;
! 686:
! 687: /* if we have to use a limited range of ports,
! 688: that will limit the number of transfers */
! 689: if (daemon->start_tftp_port != 0 &&
! 690: daemon->end_tftp_port - daemon->start_tftp_port + 1 < max_fd)
! 691: max_fd = daemon->end_tftp_port - daemon->start_tftp_port + 1;
! 692:
! 693: if (daemon->tftp_max > max_fd)
! 694: {
! 695: daemon->tftp_max = max_fd;
! 696: my_syslog(MS_TFTP | LOG_WARNING,
! 697: _("restricting maximum simultaneous TFTP transfers to %d"),
! 698: daemon->tftp_max);
! 699: }
! 700: }
! 701: #endif
! 702:
! 703: /* finished start-up - release original process */
! 704: if (err_pipe[1] != -1)
! 705: close(err_pipe[1]);
! 706:
! 707: if (daemon->port != 0)
! 708: check_servers();
! 709:
! 710: pid = getpid();
! 711:
! 712: while (1)
! 713: {
! 714: int maxfd = -1;
! 715: struct timeval t, *tp = NULL;
! 716: fd_set rset, wset, eset;
! 717:
! 718: FD_ZERO(&rset);
! 719: FD_ZERO(&wset);
! 720: FD_ZERO(&eset);
! 721:
! 722: /* if we are out of resources, find how long we have to wait
! 723: for some to come free, we'll loop around then and restart
! 724: listening for queries */
! 725: if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)
! 726: {
! 727: t.tv_usec = 0;
! 728: tp = &t;
! 729: }
! 730:
! 731: /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
! 732: if (daemon->tftp_trans ||
! 733: (option_bool(OPT_DBUS) && !daemon->dbus))
! 734: {
! 735: t.tv_sec = 0;
! 736: t.tv_usec = 250000;
! 737: tp = &t;
! 738: }
! 739: /* Wake every second whilst waiting for DAD to complete */
! 740: else if (is_dad_listeners())
! 741: {
! 742: t.tv_sec = 1;
! 743: t.tv_usec = 0;
! 744: tp = &t;
! 745: }
! 746:
! 747: #ifdef HAVE_DBUS
! 748: set_dbus_listeners(&maxfd, &rset, &wset, &eset);
! 749: #endif
! 750:
! 751: #ifdef HAVE_DHCP
! 752: if (daemon->dhcp)
! 753: {
! 754: FD_SET(daemon->dhcpfd, &rset);
! 755: bump_maxfd(daemon->dhcpfd, &maxfd);
! 756: if (daemon->pxefd != -1)
! 757: {
! 758: FD_SET(daemon->pxefd, &rset);
! 759: bump_maxfd(daemon->pxefd, &maxfd);
! 760: }
! 761: }
! 762: #endif
! 763:
! 764: #ifdef HAVE_DHCP6
! 765: if (daemon->doing_dhcp6)
! 766: {
! 767: FD_SET(daemon->dhcp6fd, &rset);
! 768: bump_maxfd(daemon->dhcp6fd, &maxfd);
! 769: }
! 770:
! 771: if (daemon->doing_ra)
! 772: {
! 773: FD_SET(daemon->icmp6fd, &rset);
! 774: bump_maxfd(daemon->icmp6fd, &maxfd);
! 775: }
! 776: #endif
! 777:
! 778: #ifdef HAVE_LINUX_NETWORK
! 779: FD_SET(daemon->netlinkfd, &rset);
! 780: bump_maxfd(daemon->netlinkfd, &maxfd);
! 781: #endif
! 782:
! 783: FD_SET(piperead, &rset);
! 784: bump_maxfd(piperead, &maxfd);
! 785:
! 786: #ifdef HAVE_DHCP
! 787: # ifdef HAVE_SCRIPT
! 788: while (helper_buf_empty() && do_script_run(now));
! 789:
! 790: # ifdef HAVE_TFTP
! 791: while (helper_buf_empty() && do_tftp_script_run());
! 792: # endif
! 793:
! 794: if (!helper_buf_empty())
! 795: {
! 796: FD_SET(daemon->helperfd, &wset);
! 797: bump_maxfd(daemon->helperfd, &maxfd);
! 798: }
! 799: # else
! 800: /* need this for other side-effects */
! 801: while (do_script_run(now));
! 802:
! 803: # ifdef HAVE_TFTP
! 804: while (do_tftp_script_run());
! 805: # endif
! 806:
! 807: # endif
! 808: #endif
! 809:
! 810: /* must do this just before select(), when we know no
! 811: more calls to my_syslog() can occur */
! 812: set_log_writer(&wset, &maxfd);
! 813:
! 814: if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
! 815: {
! 816: /* otherwise undefined after error */
! 817: FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
! 818: }
! 819:
! 820: now = dnsmasq_time();
! 821:
! 822: check_log_writer(&wset);
! 823:
! 824: /* Check the interfaces to see if any have exited DAD state
! 825: and if so, bind the address. */
! 826: if (is_dad_listeners())
! 827: {
! 828: enumerate_interfaces();
! 829: /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
! 830: create_bound_listeners(0);
! 831: }
! 832:
! 833: #ifdef HAVE_LINUX_NETWORK
! 834: if (FD_ISSET(daemon->netlinkfd, &rset))
! 835: netlink_multicast(now);
! 836: #endif
! 837:
! 838: /* Check for changes to resolv files once per second max. */
! 839: /* Don't go silent for long periods if the clock goes backwards. */
! 840: if (daemon->last_resolv == 0 ||
! 841: difftime(now, daemon->last_resolv) > 1.0 ||
! 842: difftime(now, daemon->last_resolv) < -1.0)
! 843: {
! 844: /* poll_resolv doesn't need to reload first time through, since
! 845: that's queued anyway. */
! 846:
! 847: poll_resolv(0, daemon->last_resolv != 0, now);
! 848: daemon->last_resolv = now;
! 849: }
! 850:
! 851: if (FD_ISSET(piperead, &rset))
! 852: async_event(piperead, now);
! 853:
! 854: #ifdef HAVE_DBUS
! 855: /* if we didn't create a DBus connection, retry now. */
! 856: if (option_bool(OPT_DBUS) && !daemon->dbus)
! 857: {
! 858: char *err;
! 859: if ((err = dbus_init()))
! 860: my_syslog(LOG_WARNING, _("DBus error: %s"), err);
! 861: if (daemon->dbus)
! 862: my_syslog(LOG_INFO, _("connected to system DBus"));
! 863: }
! 864: check_dbus_listeners(&rset, &wset, &eset);
! 865: #endif
! 866:
! 867: check_dns_listeners(&rset, now);
! 868:
! 869: #ifdef HAVE_TFTP
! 870: check_tftp_listeners(&rset, now);
! 871: #endif
! 872:
! 873: #ifdef HAVE_DHCP
! 874: if (daemon->dhcp)
! 875: {
! 876: if (FD_ISSET(daemon->dhcpfd, &rset))
! 877: dhcp_packet(now, 0);
! 878: if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
! 879: dhcp_packet(now, 1);
! 880: }
! 881:
! 882: #ifdef HAVE_DHCP6
! 883: if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
! 884: dhcp6_packet(now);
! 885:
! 886: if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
! 887: icmp6_packet(now);
! 888: #endif
! 889:
! 890: # ifdef HAVE_SCRIPT
! 891: if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
! 892: helper_write();
! 893: # endif
! 894: #endif
! 895:
! 896: }
! 897: }
! 898:
! 899: static void sig_handler(int sig)
! 900: {
! 901: if (pid == 0)
! 902: {
! 903: /* ignore anything other than TERM during startup
! 904: and in helper proc. (helper ignore TERM too) */
! 905: if (sig == SIGTERM)
! 906: exit(EC_MISC);
! 907: }
! 908: else if (pid != getpid())
! 909: {
! 910: /* alarm is used to kill TCP children after a fixed time. */
! 911: if (sig == SIGALRM)
! 912: _exit(0);
! 913: }
! 914: else
! 915: {
! 916: /* master process */
! 917: int event, errsave = errno;
! 918:
! 919: if (sig == SIGHUP)
! 920: event = EVENT_RELOAD;
! 921: else if (sig == SIGCHLD)
! 922: event = EVENT_CHILD;
! 923: else if (sig == SIGALRM)
! 924: event = EVENT_ALARM;
! 925: else if (sig == SIGTERM)
! 926: event = EVENT_TERM;
! 927: else if (sig == SIGUSR1)
! 928: event = EVENT_DUMP;
! 929: else if (sig == SIGUSR2)
! 930: event = EVENT_REOPEN;
! 931: else
! 932: return;
! 933:
! 934: send_event(pipewrite, event, 0, NULL);
! 935: errno = errsave;
! 936: }
! 937: }
! 938:
! 939: /* now == 0 -> queue immediate callback */
! 940: void send_alarm(time_t event, time_t now)
! 941: {
! 942: if (now == 0 || event != 0)
! 943: {
! 944: /* alarm(0) or alarm(-ve) doesn't do what we want.... */
! 945: if ((now == 0 || difftime(event, now) <= 0.0))
! 946: send_event(pipewrite, EVENT_ALARM, 0, NULL);
! 947: else
! 948: alarm((unsigned)difftime(event, now));
! 949: }
! 950: }
! 951:
! 952: void send_event(int fd, int event, int data, char *msg)
! 953: {
! 954: struct event_desc ev;
! 955: struct iovec iov[2];
! 956:
! 957: ev.event = event;
! 958: ev.data = data;
! 959: ev.msg_sz = msg ? strlen(msg) : 0;
! 960:
! 961: iov[0].iov_base = &ev;
! 962: iov[0].iov_len = sizeof(ev);
! 963: iov[1].iov_base = msg;
! 964: iov[1].iov_len = ev.msg_sz;
! 965:
! 966: /* error pipe, debug mode. */
! 967: if (fd == -1)
! 968: fatal_event(&ev, msg);
! 969: else
! 970: /* pipe is non-blocking and struct event_desc is smaller than
! 971: PIPE_BUF, so this either fails or writes everything */
! 972: while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
! 973: }
! 974:
! 975: /* NOTE: the memory used to return msg is leaked: use msgs in events only
! 976: to describe fatal errors. */
! 977: static int read_event(int fd, struct event_desc *evp, char **msg)
! 978: {
! 979: char *buf;
! 980:
! 981: if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
! 982: return 0;
! 983:
! 984: *msg = NULL;
! 985:
! 986: if (evp->msg_sz != 0 &&
! 987: (buf = malloc(evp->msg_sz + 1)) &&
! 988: read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
! 989: {
! 990: buf[evp->msg_sz] = 0;
! 991: *msg = buf;
! 992: }
! 993:
! 994: return 1;
! 995: }
! 996:
! 997: static void fatal_event(struct event_desc *ev, char *msg)
! 998: {
! 999: errno = ev->data;
! 1000:
! 1001: switch (ev->event)
! 1002: {
! 1003: case EVENT_DIE:
! 1004: exit(0);
! 1005:
! 1006: case EVENT_FORK_ERR:
! 1007: die(_("cannot fork into background: %s"), NULL, EC_MISC);
! 1008:
! 1009: case EVENT_PIPE_ERR:
! 1010: die(_("failed to create helper: %s"), NULL, EC_MISC);
! 1011:
! 1012: case EVENT_CAP_ERR:
! 1013: die(_("setting capabilities failed: %s"), NULL, EC_MISC);
! 1014:
! 1015: case EVENT_USER_ERR:
! 1016: die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
! 1017:
! 1018: case EVENT_GROUP_ERR:
! 1019: die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
! 1020:
! 1021: case EVENT_PIDFILE:
! 1022: die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
! 1023:
! 1024: case EVENT_LOG_ERR:
! 1025: die(_("cannot open log %s: %s"), msg, EC_FILE);
! 1026:
! 1027: case EVENT_LUA_ERR:
! 1028: die(_("failed to load Lua script: %s"), msg, EC_MISC);
! 1029:
! 1030: case EVENT_TFTP_ERR:
! 1031: die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
! 1032: }
! 1033: }
! 1034:
! 1035: static void async_event(int pipe, time_t now)
! 1036: {
! 1037: pid_t p;
! 1038: struct event_desc ev;
! 1039: int i;
! 1040: char *msg;
! 1041:
! 1042: /* NOTE: the memory used to return msg is leaked: use msgs in events only
! 1043: to describe fatal errors. */
! 1044:
! 1045: if (read_event(pipe, &ev, &msg))
! 1046: switch (ev.event)
! 1047: {
! 1048: case EVENT_RELOAD:
! 1049: clear_cache_and_reload(now);
! 1050: if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
! 1051: {
! 1052: reload_servers(daemon->resolv_files->name);
! 1053: check_servers();
! 1054: }
! 1055: #ifdef HAVE_DHCP
! 1056: rerun_scripts();
! 1057: #endif
! 1058: break;
! 1059:
! 1060: case EVENT_DUMP:
! 1061: if (daemon->port != 0)
! 1062: dump_cache(now);
! 1063: break;
! 1064:
! 1065: case EVENT_ALARM:
! 1066: #ifdef HAVE_DHCP
! 1067: if (daemon->dhcp || daemon->doing_dhcp6)
! 1068: {
! 1069: lease_prune(NULL, now);
! 1070: lease_update_file(now);
! 1071: }
! 1072: #ifdef HAVE_DHCP6
! 1073: else if (daemon->doing_ra)
! 1074: /* Not doing DHCP, so no lease system, manage alarms for ra only */
! 1075: send_alarm(periodic_ra(now), now);
! 1076: #endif
! 1077: #endif
! 1078: break;
! 1079:
! 1080: case EVENT_CHILD:
! 1081: /* See Stevens 5.10 */
! 1082: while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
! 1083: if (p == -1)
! 1084: {
! 1085: if (errno != EINTR)
! 1086: break;
! 1087: }
! 1088: else
! 1089: for (i = 0 ; i < MAX_PROCS; i++)
! 1090: if (daemon->tcp_pids[i] == p)
! 1091: daemon->tcp_pids[i] = 0;
! 1092: break;
! 1093:
! 1094: case EVENT_KILLED:
! 1095: my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
! 1096: break;
! 1097:
! 1098: case EVENT_EXITED:
! 1099: my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
! 1100: break;
! 1101:
! 1102: case EVENT_EXEC_ERR:
! 1103: my_syslog(LOG_ERR, _("failed to execute %s: %s"),
! 1104: daemon->lease_change_command, strerror(ev.data));
! 1105: break;
! 1106:
! 1107: /* necessary for fatal errors in helper */
! 1108: case EVENT_USER_ERR:
! 1109: case EVENT_DIE:
! 1110: case EVENT_LUA_ERR:
! 1111: fatal_event(&ev, msg);
! 1112: break;
! 1113:
! 1114: case EVENT_REOPEN:
! 1115: /* Note: this may leave TCP-handling processes with the old file still open.
! 1116: Since any such process will die in CHILD_LIFETIME or probably much sooner,
! 1117: we leave them logging to the old file. */
! 1118: if (daemon->log_file != NULL)
! 1119: log_reopen(daemon->log_file);
! 1120: break;
! 1121:
! 1122: case EVENT_TERM:
! 1123: /* Knock all our children on the head. */
! 1124: for (i = 0; i < MAX_PROCS; i++)
! 1125: if (daemon->tcp_pids[i] != 0)
! 1126: kill(daemon->tcp_pids[i], SIGALRM);
! 1127:
! 1128: #if defined(HAVE_SCRIPT)
! 1129: /* handle pending lease transitions */
! 1130: if (daemon->helperfd != -1)
! 1131: {
! 1132: /* block in writes until all done */
! 1133: if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
! 1134: fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
! 1135: do {
! 1136: helper_write();
! 1137: } while (!helper_buf_empty() || do_script_run(now));
! 1138: close(daemon->helperfd);
! 1139: }
! 1140: #endif
! 1141:
! 1142: if (daemon->lease_stream)
! 1143: fclose(daemon->lease_stream);
! 1144:
! 1145: if (daemon->runfile)
! 1146: unlink(daemon->runfile);
! 1147:
! 1148: my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
! 1149: flush_log();
! 1150: exit(EC_GOOD);
! 1151: }
! 1152: }
! 1153:
! 1154: void poll_resolv(int force, int do_reload, time_t now)
! 1155: {
! 1156: struct resolvc *res, *latest;
! 1157: struct stat statbuf;
! 1158: time_t last_change = 0;
! 1159: /* There may be more than one possible file.
! 1160: Go through and find the one which changed _last_.
! 1161: Warn of any which can't be read. */
! 1162:
! 1163: if (daemon->port == 0 || option_bool(OPT_NO_POLL))
! 1164: return;
! 1165:
! 1166: for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
! 1167: if (stat(res->name, &statbuf) == -1)
! 1168: {
! 1169: if (force)
! 1170: {
! 1171: res->mtime = 0;
! 1172: continue;
! 1173: }
! 1174:
! 1175: if (!res->logged)
! 1176: my_syslog(LOG_WARNING, _("failed to access %s: %s"), res->name, strerror(errno));
! 1177: res->logged = 1;
! 1178:
! 1179: if (res->mtime != 0)
! 1180: {
! 1181: /* existing file evaporated, force selection of the latest
! 1182: file even if its mtime hasn't changed since we last looked */
! 1183: poll_resolv(1, do_reload, now);
! 1184: return;
! 1185: }
! 1186: }
! 1187: else
! 1188: {
! 1189: res->logged = 0;
! 1190: if (force || (statbuf.st_mtime != res->mtime))
! 1191: {
! 1192: res->mtime = statbuf.st_mtime;
! 1193: if (difftime(statbuf.st_mtime, last_change) > 0.0)
! 1194: {
! 1195: last_change = statbuf.st_mtime;
! 1196: latest = res;
! 1197: }
! 1198: }
! 1199: }
! 1200:
! 1201: if (latest)
! 1202: {
! 1203: static int warned = 0;
! 1204: if (reload_servers(latest->name))
! 1205: {
! 1206: my_syslog(LOG_INFO, _("reading %s"), latest->name);
! 1207: warned = 0;
! 1208: check_servers();
! 1209: if (option_bool(OPT_RELOAD) && do_reload)
! 1210: clear_cache_and_reload(now);
! 1211: }
! 1212: else
! 1213: {
! 1214: latest->mtime = 0;
! 1215: if (!warned)
! 1216: {
! 1217: my_syslog(LOG_WARNING, _("no servers found in %s, will retry"), latest->name);
! 1218: warned = 1;
! 1219: }
! 1220: }
! 1221: }
! 1222: }
! 1223:
! 1224: void clear_cache_and_reload(time_t now)
! 1225: {
! 1226: if (daemon->port != 0)
! 1227: cache_reload();
! 1228:
! 1229: #ifdef HAVE_DHCP
! 1230: if (daemon->dhcp || daemon->doing_dhcp6)
! 1231: {
! 1232: if (option_bool(OPT_ETHERS))
! 1233: dhcp_read_ethers();
! 1234: reread_dhcp();
! 1235: dhcp_update_configs(daemon->dhcp_conf);
! 1236: lease_update_from_configs();
! 1237: lease_update_file(now);
! 1238: lease_update_dns(1);
! 1239: }
! 1240: #ifdef HAVE_DHCP6
! 1241: else if (daemon->doing_ra)
! 1242: /* Not doing DHCP, so no lease system, manage
! 1243: alarms for ra only */
! 1244: send_alarm(periodic_ra(now), now);
! 1245: #endif
! 1246: #endif
! 1247: }
! 1248:
! 1249: static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
! 1250: {
! 1251: struct serverfd *serverfdp;
! 1252: struct listener *listener;
! 1253: int wait = 0, i;
! 1254:
! 1255: #ifdef HAVE_TFTP
! 1256: int tftp = 0;
! 1257: struct tftp_transfer *transfer;
! 1258: for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
! 1259: {
! 1260: tftp++;
! 1261: FD_SET(transfer->sockfd, set);
! 1262: bump_maxfd(transfer->sockfd, maxfdp);
! 1263: }
! 1264: #endif
! 1265:
! 1266: /* will we be able to get memory? */
! 1267: if (daemon->port != 0)
! 1268: get_new_frec(now, &wait);
! 1269:
! 1270: for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
! 1271: {
! 1272: FD_SET(serverfdp->fd, set);
! 1273: bump_maxfd(serverfdp->fd, maxfdp);
! 1274: }
! 1275:
! 1276: if (daemon->port != 0 && !daemon->osport)
! 1277: for (i = 0; i < RANDOM_SOCKS; i++)
! 1278: if (daemon->randomsocks[i].refcount != 0)
! 1279: {
! 1280: FD_SET(daemon->randomsocks[i].fd, set);
! 1281: bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
! 1282: }
! 1283:
! 1284: for (listener = daemon->listeners; listener; listener = listener->next)
! 1285: {
! 1286: /* only listen for queries if we have resources */
! 1287: if (listener->fd != -1 && wait == 0)
! 1288: {
! 1289: FD_SET(listener->fd, set);
! 1290: bump_maxfd(listener->fd, maxfdp);
! 1291: }
! 1292:
! 1293: /* death of a child goes through the select loop, so
! 1294: we don't need to explicitly arrange to wake up here */
! 1295: if (listener->tcpfd != -1)
! 1296: for (i = 0; i < MAX_PROCS; i++)
! 1297: if (daemon->tcp_pids[i] == 0)
! 1298: {
! 1299: FD_SET(listener->tcpfd, set);
! 1300: bump_maxfd(listener->tcpfd, maxfdp);
! 1301: break;
! 1302: }
! 1303:
! 1304: #ifdef HAVE_TFTP
! 1305: if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
! 1306: {
! 1307: FD_SET(listener->tftpfd, set);
! 1308: bump_maxfd(listener->tftpfd, maxfdp);
! 1309: }
! 1310: #endif
! 1311:
! 1312: }
! 1313:
! 1314: return wait;
! 1315: }
! 1316:
! 1317: static void check_dns_listeners(fd_set *set, time_t now)
! 1318: {
! 1319: struct serverfd *serverfdp;
! 1320: struct listener *listener;
! 1321: int i;
! 1322:
! 1323: for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
! 1324: if (FD_ISSET(serverfdp->fd, set))
! 1325: reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
! 1326:
! 1327: if (daemon->port != 0 && !daemon->osport)
! 1328: for (i = 0; i < RANDOM_SOCKS; i++)
! 1329: if (daemon->randomsocks[i].refcount != 0 &&
! 1330: FD_ISSET(daemon->randomsocks[i].fd, set))
! 1331: reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
! 1332:
! 1333: for (listener = daemon->listeners; listener; listener = listener->next)
! 1334: {
! 1335: if (listener->fd != -1 && FD_ISSET(listener->fd, set))
! 1336: receive_query(listener, now);
! 1337:
! 1338: #ifdef HAVE_TFTP
! 1339: if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
! 1340: tftp_request(listener, now);
! 1341: #endif
! 1342:
! 1343: if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
! 1344: {
! 1345: int confd, client_ok = 1;
! 1346: struct irec *iface = NULL;
! 1347: pid_t p;
! 1348: union mysockaddr tcp_addr;
! 1349: socklen_t tcp_len = sizeof(union mysockaddr);
! 1350:
! 1351: while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
! 1352:
! 1353: if (confd == -1)
! 1354: continue;
! 1355:
! 1356: if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
! 1357: {
! 1358: close(confd);
! 1359: continue;
! 1360: }
! 1361:
! 1362: if (option_bool(OPT_NOWILD))
! 1363: iface = listener->iface; /* May be NULL */
! 1364: else
! 1365: {
! 1366: int if_index;
! 1367: char intr_name[IF_NAMESIZE];
! 1368:
! 1369: /* In full wildcard mode, need to refresh interface list.
! 1370: This happens automagically in CLEVERBIND */
! 1371: if (!option_bool(OPT_CLEVERBIND))
! 1372: enumerate_interfaces();
! 1373:
! 1374: /* if we can find the arrival interface, check it's one that's allowed */
! 1375: if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
! 1376: indextoname(listener->tcpfd, if_index, intr_name))
! 1377: {
! 1378: struct all_addr addr;
! 1379: addr.addr.addr4 = tcp_addr.in.sin_addr;
! 1380: #ifdef HAVE_IPV6
! 1381: if (tcp_addr.sa.sa_family == AF_INET6)
! 1382: addr.addr.addr6 = tcp_addr.in6.sin6_addr;
! 1383: #endif
! 1384:
! 1385: for (iface = daemon->interfaces; iface; iface = iface->next)
! 1386: if (iface->index == if_index)
! 1387: break;
! 1388:
! 1389: if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
! 1390: client_ok = 0;
! 1391: }
! 1392:
! 1393: if (option_bool(OPT_CLEVERBIND))
! 1394: iface = listener->iface; /* May be NULL */
! 1395: else
! 1396: {
! 1397: /* Check for allowed interfaces when binding the wildcard address:
! 1398: we do this by looking for an interface with the same address as
! 1399: the local address of the TCP connection, then looking to see if that's
! 1400: an allowed interface. As a side effect, we get the netmask of the
! 1401: interface too, for localisation. */
! 1402:
! 1403: for (iface = daemon->interfaces; iface; iface = iface->next)
! 1404: if (sockaddr_isequal(&iface->addr, &tcp_addr))
! 1405: break;
! 1406:
! 1407: if (!iface)
! 1408: client_ok = 0;
! 1409: }
! 1410: }
! 1411:
! 1412: if (!client_ok)
! 1413: {
! 1414: shutdown(confd, SHUT_RDWR);
! 1415: close(confd);
! 1416: }
! 1417: #ifndef NO_FORK
! 1418: else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
! 1419: {
! 1420: if (p != -1)
! 1421: {
! 1422: int i;
! 1423: for (i = 0; i < MAX_PROCS; i++)
! 1424: if (daemon->tcp_pids[i] == 0)
! 1425: {
! 1426: daemon->tcp_pids[i] = p;
! 1427: break;
! 1428: }
! 1429: }
! 1430: close(confd);
! 1431: }
! 1432: #endif
! 1433: else
! 1434: {
! 1435: unsigned char *buff;
! 1436: struct server *s;
! 1437: int flags;
! 1438: struct in_addr netmask;
! 1439: int auth_dns;
! 1440:
! 1441: if (iface)
! 1442: {
! 1443: netmask = iface->netmask;
! 1444: auth_dns = iface->dns_auth;
! 1445: }
! 1446: else
! 1447: {
! 1448: netmask.s_addr = 0;
! 1449: auth_dns = 0;
! 1450: }
! 1451:
! 1452: #ifndef NO_FORK
! 1453: /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
! 1454: terminate the process. */
! 1455: if (!option_bool(OPT_DEBUG))
! 1456: alarm(CHILD_LIFETIME);
! 1457: #endif
! 1458:
! 1459: /* start with no upstream connections. */
! 1460: for (s = daemon->servers; s; s = s->next)
! 1461: s->tcpfd = -1;
! 1462:
! 1463: /* The connected socket inherits non-blocking
! 1464: attribute from the listening socket.
! 1465: Reset that here. */
! 1466: if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
! 1467: fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
! 1468:
! 1469: buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
! 1470:
! 1471: shutdown(confd, SHUT_RDWR);
! 1472: close(confd);
! 1473:
! 1474: if (buff)
! 1475: free(buff);
! 1476:
! 1477: for (s = daemon->servers; s; s = s->next)
! 1478: if (s->tcpfd != -1)
! 1479: {
! 1480: shutdown(s->tcpfd, SHUT_RDWR);
! 1481: close(s->tcpfd);
! 1482: }
! 1483: #ifndef NO_FORK
! 1484: if (!option_bool(OPT_DEBUG))
! 1485: {
! 1486: flush_log();
! 1487: _exit(0);
! 1488: }
! 1489: #endif
! 1490: }
! 1491: }
! 1492: }
! 1493: }
! 1494:
! 1495: #ifdef HAVE_DHCP
! 1496: int make_icmp_sock(void)
! 1497: {
! 1498: int fd;
! 1499: int zeroopt = 0;
! 1500:
! 1501: if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) != -1)
! 1502: {
! 1503: if (!fix_fd(fd) ||
! 1504: setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
! 1505: {
! 1506: close(fd);
! 1507: fd = -1;
! 1508: }
! 1509: }
! 1510:
! 1511: return fd;
! 1512: }
! 1513:
! 1514: int icmp_ping(struct in_addr addr)
! 1515: {
! 1516: /* Try and get an ICMP echo from a machine. */
! 1517:
! 1518: /* Note that whilst in the three second wait, we check for
! 1519: (and service) events on the DNS and TFTP sockets, (so doing that
! 1520: better not use any resources our caller has in use...)
! 1521: but we remain deaf to signals or further DHCP packets. */
! 1522:
! 1523: int fd;
! 1524: struct sockaddr_in saddr;
! 1525: struct {
! 1526: struct ip ip;
! 1527: struct icmp icmp;
! 1528: } packet;
! 1529: unsigned short id = rand16();
! 1530: unsigned int i, j;
! 1531: int gotreply = 0;
! 1532: time_t start, now;
! 1533:
! 1534: #if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
! 1535: if ((fd = make_icmp_sock()) == -1)
! 1536: return 0;
! 1537: #else
! 1538: int opt = 2000;
! 1539: fd = daemon->dhcp_icmp_fd;
! 1540: setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
! 1541: #endif
! 1542:
! 1543: saddr.sin_family = AF_INET;
! 1544: saddr.sin_port = 0;
! 1545: saddr.sin_addr = addr;
! 1546: #ifdef HAVE_SOCKADDR_SA_LEN
! 1547: saddr.sin_len = sizeof(struct sockaddr_in);
! 1548: #endif
! 1549:
! 1550: memset(&packet.icmp, 0, sizeof(packet.icmp));
! 1551: packet.icmp.icmp_type = ICMP_ECHO;
! 1552: packet.icmp.icmp_id = id;
! 1553: for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
! 1554: j += ((u16 *)&packet.icmp)[i];
! 1555: while (j>>16)
! 1556: j = (j & 0xffff) + (j >> 16);
! 1557: packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
! 1558:
! 1559: while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
! 1560: (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
! 1561: retry_send());
! 1562:
! 1563: for (now = start = dnsmasq_time();
! 1564: difftime(now, start) < (float)PING_WAIT;)
! 1565: {
! 1566: struct timeval tv;
! 1567: fd_set rset, wset;
! 1568: struct sockaddr_in faddr;
! 1569: int maxfd = fd;
! 1570: socklen_t len = sizeof(faddr);
! 1571:
! 1572: tv.tv_usec = 250000;
! 1573: tv.tv_sec = 0;
! 1574:
! 1575: FD_ZERO(&rset);
! 1576: FD_ZERO(&wset);
! 1577: FD_SET(fd, &rset);
! 1578: set_dns_listeners(now, &rset, &maxfd);
! 1579: set_log_writer(&wset, &maxfd);
! 1580:
! 1581: #ifdef HAVE_DHCP6
! 1582: if (daemon->doing_ra)
! 1583: {
! 1584: FD_SET(daemon->icmp6fd, &rset);
! 1585: bump_maxfd(daemon->icmp6fd, &maxfd);
! 1586: }
! 1587: #endif
! 1588:
! 1589: if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
! 1590: {
! 1591: FD_ZERO(&rset);
! 1592: FD_ZERO(&wset);
! 1593: }
! 1594:
! 1595: now = dnsmasq_time();
! 1596:
! 1597: check_log_writer(&wset);
! 1598: check_dns_listeners(&rset, now);
! 1599:
! 1600: #ifdef HAVE_DHCP6
! 1601: if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
! 1602: icmp6_packet(now);
! 1603: #endif
! 1604:
! 1605: #ifdef HAVE_TFTP
! 1606: check_tftp_listeners(&rset, now);
! 1607: #endif
! 1608:
! 1609: if (FD_ISSET(fd, &rset) &&
! 1610: recvfrom(fd, &packet, sizeof(packet), 0,
! 1611: (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
! 1612: saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
! 1613: packet.icmp.icmp_type == ICMP_ECHOREPLY &&
! 1614: packet.icmp.icmp_seq == 0 &&
! 1615: packet.icmp.icmp_id == id)
! 1616: {
! 1617: gotreply = 1;
! 1618: break;
! 1619: }
! 1620: }
! 1621:
! 1622: #if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
! 1623: close(fd);
! 1624: #else
! 1625: opt = 1;
! 1626: setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
! 1627: #endif
! 1628:
! 1629: return gotreply;
! 1630: }
! 1631: #endif
! 1632:
! 1633:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>