Diff for /embedaddon/dnsmasq/src/dnsmasq.c between versions 1.1.1.1 and 1.1.1.3

version 1.1.1.1, 2013/07/29 19:37:40 version 1.1.1.3, 2016/11/02 09:57:01
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 24  struct daemon *daemon; Line 24  struct daemon *daemon;
 static volatile pid_t pid = 0;  static volatile pid_t pid = 0;
 static volatile int pipewrite;  static volatile int pipewrite;
   
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);static int set_dns_listeners(time_t now);
static void check_dns_listeners(fd_set *set, time_t now);static void check_dns_listeners(time_t now);
 static void sig_handler(int sig);  static void sig_handler(int sig);
 static void async_event(int pipe, time_t now);  static void async_event(int pipe, time_t now);
 static void fatal_event(struct event_desc *ev, char *msg);  static void fatal_event(struct event_desc *ev, char *msg);
 static int read_event(int fd, struct event_desc *evp, char **msg);  static int read_event(int fd, struct event_desc *evp, char **msg);
   static void poll_resolv(int force, int do_reload, time_t now);
   
 int main (int argc, char **argv)  int main (int argc, char **argv)
 {  {
Line 50  int main (int argc, char **argv) Line 51  int main (int argc, char **argv)
 #if defined(HAVE_LINUX_NETWORK)  #if defined(HAVE_LINUX_NETWORK)
   cap_user_header_t hdr = NULL;    cap_user_header_t hdr = NULL;
   cap_user_data_t data = NULL;    cap_user_data_t data = NULL;
     char *bound_device = NULL;
     int did_bind = 0;
 #endif   #endif 
   #if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
   struct dhcp_context *context;    struct dhcp_context *context;
     struct dhcp_relay *relay;
   #endif
   #ifdef HAVE_TFTP
     int tftp_prefix_missing = 0;
   #endif
   
 #ifdef LOCALEDIR  #ifdef LOCALEDIR
   setlocale(LC_ALL, "");    setlocale(LC_ALL, "");
Line 74  int main (int argc, char **argv) Line 83  int main (int argc, char **argv)
   sigaction(SIGPIPE, &sigact, NULL);    sigaction(SIGPIPE, &sigact, NULL);
   
   umask(022); /* known umask, create leases and pid files as 0644 */    umask(022); /* known umask, create leases and pid files as 0644 */
 
   rand_init(); /* Must precede read_opts() */
   
   read_opts(argc, argv, compile_opts);    read_opts(argc, argv, compile_opts);
     
   if (daemon->edns_pktsz < PACKETSZ)    if (daemon->edns_pktsz < PACKETSZ)
     daemon->edns_pktsz = PACKETSZ;      daemon->edns_pktsz = PACKETSZ;
   daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?   
     daemon->edns_pktsz : DNSMASQ_PACKETSZ;  
   daemon->packet = safe_malloc(daemon->packet_buff_sz);  
   
     /* Min buffer size: we check after adding each record, so there must be 
        memory for the largest packet, and the largest record so the
        min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
        This might be increased is EDNS packet size if greater than the minimum. */ 
     daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ;
     daemon->packet = safe_malloc(daemon->packet_buff_sz);
     
   daemon->addrbuff = safe_malloc(ADDRSTRLEN);    daemon->addrbuff = safe_malloc(ADDRSTRLEN);
     if (option_bool(OPT_EXTRALOG))
       daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
     
   #ifdef HAVE_DNSSEC
     if (option_bool(OPT_DNSSEC_VALID))
       {
         /* Note that both /000 and '.' are allowed within labels. These get
            represented in presentation format using NAME_ESCAPE as an escape
            character when in DNSSEC mode. 
            In theory, if all the characters in a name were /000 or
            '.' or NAME_ESCAPE then all would have to be escaped, so the 
            presentation format would be twice as long as the spec.
   
            daemon->namebuff was previously allocated by the option-reading
            code before we knew if we're in DNSSEC mode, so reallocate here. */
         free(daemon->namebuff);
         daemon->namebuff = safe_malloc(MAXDNAME * 2);
         daemon->keyname = safe_malloc(MAXDNAME * 2);
         daemon->workspacename = safe_malloc(MAXDNAME * 2);
       }
   #endif
   
 #ifdef HAVE_DHCP  #ifdef HAVE_DHCP
   if (!daemon->lease_file)    if (!daemon->lease_file)
Line 125  int main (int argc, char **argv) Line 160  int main (int argc, char **argv)
       reset_option_bool(OPT_CLEVERBIND);        reset_option_bool(OPT_CLEVERBIND);
     }      }
 #endif  #endif
   
   #ifndef HAVE_INOTIFY
     if (daemon->dynamic_dirs)
       die(_("dhcp-hostsdir, dhcp-optsdir and hostsdir are not supported on this platform"), NULL, EC_BADCONF);
   #endif
       
     if (option_bool(OPT_DNSSEC_VALID))
       {
   #ifdef HAVE_DNSSEC
         struct ds_config *ds;
   
         /* Must have at least a root trust anchor, or the DNSSEC code
            can loop forever. */
         for (ds = daemon->ds; ds; ds = ds->next)
           if (ds->name[0] == 0)
             break;
   
         if (!ds)
           die(_("no root trust anchor provided for DNSSEC"), NULL, EC_BADCONF);
         
         if (daemon->cachesize < CACHESIZ)
           die(_("cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
   #else 
         die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
   #endif
       }
   
 #ifndef HAVE_TFTP  #ifndef HAVE_TFTP
   if (option_bool(OPT_TFTP))    if (option_bool(OPT_TFTP))
     die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);      die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
Line 133  int main (int argc, char **argv) Line 194  int main (int argc, char **argv)
   
 #ifdef HAVE_CONNTRACK  #ifdef HAVE_CONNTRACK
   if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))    if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
    die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);     die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF); 
 #else  #else
   if (option_bool(OPT_CONNTRACK))    if (option_bool(OPT_CONNTRACK))
    die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);    die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
 #endif  #endif
   
 #ifdef HAVE_SOLARIS_NETWORK  #ifdef HAVE_SOLARIS_NETWORK
Line 154  int main (int argc, char **argv) Line 215  int main (int argc, char **argv)
     die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);      die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
 #endif  #endif
   
  rand_init();#ifndef HAVE_LOOP
    if (option_bool(OPT_LOOP_DETECT))
     die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
 #endif
 
   if (daemon->max_port != MAX_PORT && daemon->min_port == 0)
     daemon->min_port = 1024u;
 
   if (daemon->max_port < daemon->min_port)
     die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
 
   now = dnsmasq_time();    now = dnsmasq_time();
   
   /* Create a serial at startup if not configured. */    /* Create a serial at startup if not configured. */
Line 166  int main (int argc, char **argv) Line 236  int main (int argc, char **argv)
   daemon->soa_sn = now;    daemon->soa_sn = now;
 #endif  #endif
       
#ifdef HAVE_DHCP#ifdef HAVE_DHCP6
  if (daemon->dhcp || daemon->dhcp6)  if (daemon->dhcp6)
    {     {
       daemon->doing_ra = option_bool(OPT_RA);
               
#  ifdef HAVE_DHCP6      for (context = daemon->dhcp6; context; context = context->next)
      if (daemon->dhcp6) 
         {          {
          daemon->doing_ra = option_bool(OPT_RA);          if (context->flags & CONTEXT_DHCP)
                      daemon->doing_dhcp6 = 1;
          for (context = daemon->dhcp6; context; context = context->next)          if (context->flags & CONTEXT_RA)
            {            daemon->doing_ra = 1;
              if (context->flags & CONTEXT_DHCP)#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
                daemon->doing_dhcp6 = 1;          if (context->flags & CONTEXT_TEMPLATE)
              if (context->flags & CONTEXT_RA)            die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
                daemon->doing_ra = 1; 
#ifndef  HAVE_LINUX_NETWORK 
              if (context->flags & CONTEXT_TEMPLATE) 
                die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF); 
 #endif   #endif 
             }  
         }          }
#  endif    }
#endif
      /* Note that order matters here, we must call lease_init before  
         creating any file descriptors which shouldn't be leaked#ifdef HAVE_DHCP
         to the lease-script init process. We need to call common_init  /* Note that order matters here, we must call lease_init before
         before lease_init to allocate buffers it uses.*/     creating any file descriptors which shouldn't be leaked
      to the lease-script init process. We need to call common_init
      before lease_init to allocate buffers it uses.
      The script subsystem relies on DHCP buffers, hence the last two
      conditions below. */  
   if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || 
       daemon->relay6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP))
     {
       dhcp_common_init();
       if (daemon->dhcp || daemon->doing_dhcp6)        if (daemon->dhcp || daemon->doing_dhcp6)
        {        lease_init(now);
          dhcp_common_init();    }
          lease_init(now);  
        }  if (daemon->dhcp || daemon->relay4)
    dhcp_init();
      if (daemon->dhcp)  
        dhcp_init(); 
  
 #  ifdef HAVE_DHCP6  #  ifdef HAVE_DHCP6
      if (daemon->doing_ra)  if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
        ra_init(now);    ra_init(now);
        
      if (daemon->doing_dhcp6)  if (daemon->doing_dhcp6 || daemon->relay6)
        dhcp6_init();    dhcp6_init();
 #  endif  #  endif
     }  
   
 #endif  #endif
   
Line 218  int main (int argc, char **argv) Line 288  int main (int argc, char **argv)
     ipset_init();      ipset_init();
 #endif  #endif
   
#ifdef HAVE_LINUX_NETWORK#if  defined(HAVE_LINUX_NETWORK)
   netlink_init();    netlink_init();
  #elif defined(HAVE_BSD_NETWORK)
  if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))  route_init();
    die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF); 
 #endif  #endif
   
  if (!enumerate_interfaces())  if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
     die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
   
   if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
     die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);      die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
       
   if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))     if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND)) 
Line 239  int main (int argc, char **argv) Line 311  int main (int argc, char **argv)
   
 #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)  #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
       /* after enumerate_interfaces()  */        /* after enumerate_interfaces()  */
         bound_device = whichdevice();
         
       if (daemon->dhcp)        if (daemon->dhcp)
         {          {
          bindtodevice(daemon->dhcpfd);          if (!daemon->relay4 && bound_device)
          if (daemon->enable_pxe)            {
            bindtodevice(daemon->pxefd);              bindtodevice(bound_device, daemon->dhcpfd);
               did_bind = 1;
             }
           if (daemon->enable_pxe && bound_device)
             {
               bindtodevice(bound_device, daemon->pxefd);
               did_bind = 1;
             }
         }          }
 #endif  #endif
   
 #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)  #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
      if (daemon->dhcp6)      if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
        bindtodevice(daemon->dhcp6fd);        {
           bindtodevice(bound_device, daemon->dhcp6fd);
           did_bind = 1;
         }
 #endif  #endif
     }      }
   else     else 
Line 257  int main (int argc, char **argv) Line 341  int main (int argc, char **argv)
     
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
   /* after enumerate_interfaces() */    /* after enumerate_interfaces() */
  if (daemon->doing_dhcp6 || daemon->doing_ra)  if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
     join_multicast(1);      join_multicast(1);
   
     /* After netlink_init() and before create_helper() */
     lease_make_duid(now);
 #endif  #endif
       
   if (daemon->port != 0)    if (daemon->port != 0)
    cache_init();    {
          cache_init();
 
 #ifdef HAVE_DNSSEC
       blockdata_init();
 #endif
     }
 
 #ifdef HAVE_INOTIFY
   if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
     inotify_dnsmasq_init();
   else
     daemon->inotifyfd = -1;
 #endif
        
   if (option_bool(OPT_DBUS))    if (option_bool(OPT_DBUS))
 #ifdef HAVE_DBUS  #ifdef HAVE_DBUS
     {      {
Line 276  int main (int argc, char **argv) Line 376  int main (int argc, char **argv)
 #else  #else
   die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);    die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
 #endif  #endif
  
   if (daemon->port != 0)    if (daemon->port != 0)
     pre_allocate_sfds();      pre_allocate_sfds();
   
Line 303  int main (int argc, char **argv) Line 403  int main (int argc, char **argv)
   
   if (baduser)    if (baduser)
     die(_("unknown user or group: %s"), baduser, EC_BADCONF);      die(_("unknown user or group: %s"), baduser, EC_BADCONF);
   
   /* implement group defaults, "dip" if available, or group associated with uid */    /* implement group defaults, "dip" if available, or group associated with uid */
   if (!daemon->group_set && !gp)    if (!daemon->group_set && !gp)
     {      {
Line 347  int main (int argc, char **argv) Line 447  int main (int argc, char **argv)
   piperead = pipefd[0];    piperead = pipefd[0];
   pipewrite = pipefd[1];    pipewrite = pipefd[1];
   /* prime the pipe to load stuff first time. */    /* prime the pipe to load stuff first time. */
  send_event(pipewrite, EVENT_RELOAD, 0, NULL);   send_event(pipewrite, EVENT_INIT, 0, NULL); 
   
   err_pipe[1] = -1;    err_pipe[1] = -1;
       
Line 378  int main (int argc, char **argv) Line 478  int main (int argc, char **argv)
               char *msg;                char *msg;
   
               /* close our copy of write-end */                /* close our copy of write-end */
              close(err_pipe[1]);              while (retry_send(close(err_pipe[1])));
                               
               /* check for errors after the fork */                /* check for errors after the fork */
               if (read_event(err_pipe[0], &ev, &msg))                if (read_event(err_pipe[0], &ev, &msg))
Line 387  int main (int argc, char **argv) Line 487  int main (int argc, char **argv)
               _exit(EC_GOOD);                _exit(EC_GOOD);
             }               } 
                       
          close(err_pipe[0]);          while (retry_send(close(err_pipe[0])));
   
           /* NO calls to die() from here on. */            /* NO calls to die() from here on. */
                       
Line 439  int main (int argc, char **argv) Line 539  int main (int argc, char **argv)
             {              {
               if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))                if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
                 err = 1;                  err = 1;
                            else 
              while (!err && close(fd) == -1)                {
                if (!retry_send())                  while (retry_send(close(fd)));
                  err = 1;                  if (errno != 0)
                     err = 1;
                 }
             }              }
   
           if (err)            if (err)
Line 459  int main (int argc, char **argv) Line 561  int main (int argc, char **argv)
      {              {       
        /* open  stdout etc to /dev/null */         /* open  stdout etc to /dev/null */
        int nullfd = open("/dev/null", O_RDWR);         int nullfd = open("/dev/null", O_RDWR);
       dup2(nullfd, STDOUT_FILENO);       if (nullfd != -1)
       dup2(nullfd, STDERR_FILENO);         {
       dup2(nullfd, STDIN_FILENO);           dup2(nullfd, STDOUT_FILENO);
       close(nullfd);           dup2(nullfd, STDERR_FILENO);
            dup2(nullfd, STDIN_FILENO);
            close(nullfd);
          }
      }       }
         
    /* if we are to run scripts, we need to fork a helper before dropping root. */     /* if we are to run scripts, we need to fork a helper before dropping root. */
   daemon->helperfd = -1;    daemon->helperfd = -1;
 #ifdef HAVE_SCRIPT   #ifdef HAVE_SCRIPT 
  if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))  if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP)) && 
    daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);      (daemon->lease_change_command || daemon->luascript))
       daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
 #endif  #endif
   
   if (!option_bool(OPT_DEBUG) && getuid() == 0)       if (!option_bool(OPT_DEBUG) && getuid() == 0)   
Line 561  int main (int argc, char **argv) Line 667  int main (int argc, char **argv)
     }      }
       
 #ifdef HAVE_LINUX_NETWORK  #ifdef HAVE_LINUX_NETWORK
     free(hdr);
     free(data);
   if (option_bool(OPT_DEBUG))     if (option_bool(OPT_DEBUG)) 
     prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);      prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
 #endif  #endif
   
 #ifdef HAVE_TFTP  #ifdef HAVE_TFTP
      if (option_bool(OPT_TFTP))  if (option_bool(OPT_TFTP))
     {      {
       DIR *dir;        DIR *dir;
       struct tftp_prefix *p;        struct tftp_prefix *p;
Line 575  int main (int argc, char **argv) Line 683  int main (int argc, char **argv)
         {          {
           if (!((dir = opendir(daemon->tftp_prefix))))            if (!((dir = opendir(daemon->tftp_prefix))))
             {              {
              send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);              tftp_prefix_missing = 1;
              _exit(0);              if (!option_bool(OPT_TFTP_NO_FAIL))
                 {
                   send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
                   _exit(0);
                 }
             }              }
          closedir(dir);          else
             closedir(dir);
         }          }
   
       for (p = daemon->if_prefix; p; p = p->next)        for (p = daemon->if_prefix; p; p = p->next)
         {          {
             p->missing = 0;
           if (!((dir = opendir(p->prefix))))            if (!((dir = opendir(p->prefix))))
           {            {
             send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);              p->missing = 1;
             _exit(0);              if (!option_bool(OPT_TFTP_NO_FAIL))
           }                 {
          closedir(dir);                  send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
                   _exit(0);
                 }
             }
           else
             closedir(dir);
         }          }
     }      }
 #endif  #endif
Line 612  int main (int argc, char **argv) Line 731  int main (int argc, char **argv)
     }      }
 #endif  #endif
   
     if (option_bool(OPT_LOCAL_SERVICE))
       my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
     
   #ifdef HAVE_DNSSEC
     if (option_bool(OPT_DNSSEC_VALID))
       {
         int rc;
   
         /* Delay creating the timestamp file until here, after we've changed user, so that
            it has the correct owner to allow updating the mtime later. 
            This means we have to report fatal errors via the pipe. */
         if ((rc = setup_timestamp()) == -1)
           {
             send_event(err_pipe[1], EVENT_TIME_ERR, errno, daemon->timestamp_file);
             _exit(0);
           }
         
         my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
         
         if (option_bool(OPT_DNSSEC_TIME))
           my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
         
         if (rc == 1)
           my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
       }
   #endif
   
   if (log_err != 0)    if (log_err != 0)
     my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),       my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"), 
               daemon->log_file, strerror(log_err));                daemon->log_file, strerror(log_err));
  
   if (bind_fallback)    if (bind_fallback)
     my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));      my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
   
     if (option_bool(OPT_NOWILD))
       warn_bound_listeners();
   
     warn_int_names();
       
   if (!option_bool(OPT_NOWILD))     if (!option_bool(OPT_NOWILD)) 
     for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)      for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
Line 641  int main (int argc, char **argv) Line 792  int main (int argc, char **argv)
   for (context = daemon->dhcp; context; context = context->next)    for (context = daemon->dhcp; context; context = context->next)
     log_context(AF_INET, context);      log_context(AF_INET, context);
   
     for (relay = daemon->relay4; relay; relay = relay->next)
       log_relay(AF_INET, relay);
   
 #  ifdef HAVE_DHCP6  #  ifdef HAVE_DHCP6
   for (context = daemon->dhcp6; context; context = context->next)    for (context = daemon->dhcp6; context; context = context->next)
     log_context(AF_INET6, context);      log_context(AF_INET6, context);
   
     for (relay = daemon->relay6; relay; relay = relay->next)
       log_relay(AF_INET6, relay);
     
   if (daemon->doing_dhcp6 || daemon->doing_ra)    if (daemon->doing_dhcp6 || daemon->doing_ra)
     dhcp_construct_contexts(now);      dhcp_construct_contexts(now);
       
Line 652  int main (int argc, char **argv) Line 809  int main (int argc, char **argv)
     my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));      my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
 #  endif  #  endif
   
   #  ifdef HAVE_LINUX_NETWORK
     if (did_bind)
       my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
   #  endif
   
   /* after dhcp_contruct_contexts */    /* after dhcp_contruct_contexts */
   if (daemon->dhcp || daemon->doing_dhcp6)    if (daemon->dhcp || daemon->doing_dhcp6)
     lease_find_interfaces(now);      lease_find_interfaces(now);
 #endif  #endif
   
 #ifdef HAVE_TFTP  #ifdef HAVE_TFTP
        if (option_bool(OPT_TFTP))  if (option_bool(OPT_TFTP))
     {      {
#ifdef FD_SETSIZE      struct tftp_prefix *p;
      if (FD_SETSIZE < (unsigned)max_fd) 
        max_fd = FD_SETSIZE; 
#endif 
   
       my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",         my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s", 
                 daemon->tftp_prefix ? _("root is ") : _("enabled"),                  daemon->tftp_prefix ? _("root is ") : _("enabled"),
                 daemon->tftp_prefix ? daemon->tftp_prefix: "",                  daemon->tftp_prefix ? daemon->tftp_prefix: "",
                 option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");                  option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
      
       if (tftp_prefix_missing)
         my_syslog(MS_TFTP | LOG_WARNING, _("warning: %s inaccessible"), daemon->tftp_prefix);
 
       for (p = daemon->if_prefix; p; p = p->next)
         if (p->missing)
            my_syslog(MS_TFTP | LOG_WARNING, _("warning: TFTP directory %s inaccessible"), p->prefix);
 
       /* This is a guess, it assumes that for small limits,         /* This is a guess, it assumes that for small limits, 
          disjoint files might be served, but for large limits,            disjoint files might be served, but for large limits, 
          a single file will be sent to may clients (the file only needs           a single file will be sent to may clients (the file only needs
Line 702  int main (int argc, char **argv) Line 868  int main (int argc, char **argv)
   
   /* finished start-up - release original process */    /* finished start-up - release original process */
   if (err_pipe[1] != -1)    if (err_pipe[1] != -1)
    close(err_pipe[1]);    while (retry_send(close(err_pipe[1])));
       
   if (daemon->port != 0)    if (daemon->port != 0)
     check_servers();      check_servers();
       
   pid = getpid();    pid = getpid();
       
   #ifdef HAVE_INOTIFY
     /* Using inotify, have to select a resolv file at startup */
     poll_resolv(1, 0, now);
   #endif
     
   while (1)    while (1)
     {      {
      int maxfd = -1;      int t, timeout = -1;
      struct timeval t, *tp = NULL; 
      fd_set rset, wset, eset; 
               
      FD_ZERO(&rset);      poll_reset();
      FD_ZERO(&wset); 
      FD_ZERO(&eset); 
               
       /* if we are out of resources, find how long we have to wait        /* if we are out of resources, find how long we have to wait
          for some to come free, we'll loop around then and restart           for some to come free, we'll loop around then and restart
          listening for queries */           listening for queries */
      if ((t.tv_sec = set_dns_listeners(now, &rset, &maxfd)) != 0)      if ((t = set_dns_listeners(now)) != 0)
        {        timeout = t * 1000;
          t.tv_usec = 0; 
          tp = &t; 
        } 
   
       /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */        /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
       if (daemon->tftp_trans ||        if (daemon->tftp_trans ||
           (option_bool(OPT_DBUS) && !daemon->dbus))            (option_bool(OPT_DBUS) && !daemon->dbus))
        {        timeout = 250;
          t.tv_sec = 0;
          t.tv_usec = 250000; 
          tp = &t; 
        } 
       /* Wake every second whilst waiting for DAD to complete */        /* Wake every second whilst waiting for DAD to complete */
       else if (is_dad_listeners())        else if (is_dad_listeners())
        {        timeout = 1000;
          t.tv_sec = 1; 
          t.tv_usec = 0; 
          tp = &t; 
        } 
   
 #ifdef HAVE_DBUS  #ifdef HAVE_DBUS
      set_dbus_listeners(&maxfd, &rset, &wset, &eset);      set_dbus_listeners();
 #endif    #endif  
       
 #ifdef HAVE_DHCP  #ifdef HAVE_DHCP
      if (daemon->dhcp)      if (daemon->dhcp || daemon->relay4)
         {          {
          FD_SET(daemon->dhcpfd, &rset);          poll_listen(daemon->dhcpfd, POLLIN);
          bump_maxfd(daemon->dhcpfd, &maxfd); 
           if (daemon->pxefd != -1)            if (daemon->pxefd != -1)
            {            poll_listen(daemon->pxefd, POLLIN);
              FD_SET(daemon->pxefd, &rset); 
              bump_maxfd(daemon->pxefd, &maxfd); 
            } 
         }          }
 #endif  #endif
   
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
      if (daemon->doing_dhcp6)      if (daemon->doing_dhcp6 || daemon->relay6)
        {        poll_listen(daemon->dhcp6fd, POLLIN);
          FD_SET(daemon->dhcp6fd, &rset);        
          bump_maxfd(daemon->dhcp6fd, &maxfd); 
        } 
 
       if (daemon->doing_ra)        if (daemon->doing_ra)
        {        poll_listen(daemon->icmp6fd, POLLIN); 
          FD_SET(daemon->icmp6fd, &rset); 
          bump_maxfd(daemon->icmp6fd, &maxfd);  
        } 
 #endif  #endif
       
   #ifdef HAVE_INOTIFY
         if (daemon->inotifyfd != -1)
           poll_listen(daemon->inotifyfd, POLLIN);
   #endif
   
#ifdef HAVE_LINUX_NETWORK#if defined(HAVE_LINUX_NETWORK)
      FD_SET(daemon->netlinkfd, &rset);      poll_listen(daemon->netlinkfd, POLLIN);
      bump_maxfd(daemon->netlinkfd, &maxfd);#elif defined(HAVE_BSD_NETWORK)
       poll_listen(daemon->routefd, POLLIN);
 #endif  #endif
               
      FD_SET(piperead, &rset);      poll_listen(piperead, POLLIN);
      bump_maxfd(piperead, &maxfd); 
   
#ifdef HAVE_DHCP#ifdef HAVE_SCRIPT
#  ifdef HAVE_SCRIPT#    ifdef HAVE_DHCP
      while (helper_buf_empty() && do_script_run(now));      while (helper_buf_empty() && do_script_run(now)); 
 #    endif
   
         /* Refresh cache */
         if (option_bool(OPT_SCRIPT_ARP))
           find_mac(NULL, NULL, 0, now);
         while (helper_buf_empty() && do_arp_script_run());
   
 #    ifdef HAVE_TFTP  #    ifdef HAVE_TFTP
       while (helper_buf_empty() && do_tftp_script_run());        while (helper_buf_empty() && do_tftp_script_run());
 #    endif  #    endif
   
       if (!helper_buf_empty())        if (!helper_buf_empty())
        {        poll_listen(daemon->helperfd, POLLOUT);
          FD_SET(daemon->helperfd, &wset);#else
          bump_maxfd(daemon->helperfd, &maxfd); 
        } 
#  else 
       /* need this for other side-effects */        /* need this for other side-effects */
   #    ifdef HAVE_DHCP
       while (do_script_run(now));        while (do_script_run(now));
   #    endif
   
         while (do_arp_script_run());
   
 #    ifdef HAVE_TFTP   #    ifdef HAVE_TFTP 
       while (do_tftp_script_run());        while (do_tftp_script_run());
 #    endif  #    endif
   
 #  endif  
 #endif  #endif
   
         
       /* must do this just before select(), when we know no        /* must do this just before select(), when we know no
          more calls to my_syslog() can occur */           more calls to my_syslog() can occur */
      set_log_writer(&wset, &maxfd);      set_log_writer();
               
      if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)      if (do_poll(timeout) < 0)
        {        continue;
          /* otherwise undefined after error */      
          FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); 
        } 
 
       now = dnsmasq_time();        now = dnsmasq_time();
   
      check_log_writer(&wset);      check_log_writer(0);
      
       /* prime. */
       enumerate_interfaces(1);
 
       /* Check the interfaces to see if any have exited DAD state        /* Check the interfaces to see if any have exited DAD state
          and if so, bind the address. */           and if so, bind the address. */
       if (is_dad_listeners())        if (is_dad_listeners())
         {          {
          enumerate_interfaces();          enumerate_interfaces(0);
           /* NB, is_dad_listeners() == 1 --> we're binding interfaces */            /* NB, is_dad_listeners() == 1 --> we're binding interfaces */
           create_bound_listeners(0);            create_bound_listeners(0);
             warn_bound_listeners();
         }          }
   
#ifdef HAVE_LINUX_NETWORK#if defined(HAVE_LINUX_NETWORK)
      if (FD_ISSET(daemon->netlinkfd, &rset))      if (poll_check(daemon->netlinkfd, POLLIN))
        netlink_multicast(now);        netlink_multicast();
 #elif defined(HAVE_BSD_NETWORK)
       if (poll_check(daemon->routefd, POLLIN))
         route_sock();
 #endif  #endif
   
   #ifdef HAVE_INOTIFY
         if  (daemon->inotifyfd != -1 && poll_check(daemon->inotifyfd, POLLIN) && inotify_check(now))
           {
             if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
               poll_resolv(1, 1, now);
           }         
   #else
       /* Check for changes to resolv files once per second max. */        /* Check for changes to resolv files once per second max. */
       /* Don't go silent for long periods if the clock goes backwards. */        /* Don't go silent for long periods if the clock goes backwards. */
       if (daemon->last_resolv == 0 ||         if (daemon->last_resolv == 0 || 
Line 847  int main (int argc, char **argv) Line 1017  int main (int argc, char **argv)
           poll_resolv(0, daemon->last_resolv != 0, now);                      poll_resolv(0, daemon->last_resolv != 0, now);          
           daemon->last_resolv = now;            daemon->last_resolv = now;
         }          }
      #endif
      if (FD_ISSET(piperead, &rset))
       if (poll_check(piperead, POLLIN))
         async_event(piperead, now);          async_event(piperead, now);
               
 #ifdef HAVE_DBUS  #ifdef HAVE_DBUS
Line 861  int main (int argc, char **argv) Line 1032  int main (int argc, char **argv)
           if (daemon->dbus)            if (daemon->dbus)
             my_syslog(LOG_INFO, _("connected to system DBus"));              my_syslog(LOG_INFO, _("connected to system DBus"));
         }          }
      check_dbus_listeners(&rset, &wset, &eset);      check_dbus_listeners();
 #endif  #endif
               
      check_dns_listeners(&rset, now);      check_dns_listeners(now);
   
 #ifdef HAVE_TFTP  #ifdef HAVE_TFTP
      check_tftp_listeners(&rset, now);      check_tftp_listeners(now);
 #endif        #endif      
   
 #ifdef HAVE_DHCP  #ifdef HAVE_DHCP
      if (daemon->dhcp)      if (daemon->dhcp || daemon->relay4)
         {          {
          if (FD_ISSET(daemon->dhcpfd, &rset))          if (poll_check(daemon->dhcpfd, POLLIN))
             dhcp_packet(now, 0);              dhcp_packet(now, 0);
          if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))          if (daemon->pxefd != -1 && poll_check(daemon->pxefd, POLLIN))
             dhcp_packet(now, 1);              dhcp_packet(now, 1);
         }          }
   
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
      if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))      if ((daemon->doing_dhcp6 || daemon->relay6) && poll_check(daemon->dhcp6fd, POLLIN))
         dhcp6_packet(now);          dhcp6_packet(now);
   
      if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))      if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
         icmp6_packet(now);          icmp6_packet(now);
 #endif  #endif
   
 #  ifdef HAVE_SCRIPT  #  ifdef HAVE_SCRIPT
      if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))      if (daemon->helperfd != -1 && poll_check(daemon->helperfd, POLLOUT))
         helper_write();          helper_write();
 #  endif  #  endif
 #endif  #endif
Line 949  void send_alarm(time_t event, time_t now) Line 1120  void send_alarm(time_t event, time_t now)
     }      }
 }  }
   
   void queue_event(int event)
   {
     send_event(pipewrite, event, 0, NULL);
   }
   
 void send_event(int fd, int event, int data, char *msg)  void send_event(int fd, int event, int data, char *msg)
 {  {
   struct event_desc ev;    struct event_desc ev;
Line 1029  static void fatal_event(struct event_desc *ev, char *m Line 1205  static void fatal_event(struct event_desc *ev, char *m
   
     case EVENT_TFTP_ERR:      case EVENT_TFTP_ERR:
       die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);        die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
       
       case EVENT_TIME_ERR:
         die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
     }      }
 }         }       
               
Line 1036  static void async_event(int pipe, time_t now) Line 1215  static void async_event(int pipe, time_t now)
 {  {
   pid_t p;    pid_t p;
   struct event_desc ev;    struct event_desc ev;
  int i;  int i, check = 0;
   char *msg;    char *msg;
       
   /* NOTE: the memory used to return msg is leaked: use msgs in events only    /* NOTE: the memory used to return msg is leaked: use msgs in events only
Line 1046  static void async_event(int pipe, time_t now) Line 1225  static void async_event(int pipe, time_t now)
     switch (ev.event)      switch (ev.event)
       {        {
       case EVENT_RELOAD:        case EVENT_RELOAD:
   #ifdef HAVE_DNSSEC
           if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
             {
               my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
               reset_option_bool(OPT_DNSSEC_TIME);
             } 
   #endif
           /* fall through */
           
         case EVENT_INIT:
         clear_cache_and_reload(now);          clear_cache_and_reload(now);
        if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))        
         if (daemon->port != 0)
           {            {
            reload_servers(daemon->resolv_files->name);            if (daemon->resolv_files && option_bool(OPT_NO_POLL))
            check_servers();              {
                 reload_servers(daemon->resolv_files->name);
                 check = 1;
               }
 
             if (daemon->servers_file)
               {
                 read_servers_file();
                 check = 1;
               }
 
             if (check)
               check_servers();
           }            }
   
 #ifdef HAVE_DHCP  #ifdef HAVE_DHCP
         rerun_scripts();          rerun_scripts();
 #endif  #endif
Line 1118  static void async_event(int pipe, time_t now) Line 1321  static void async_event(int pipe, time_t now)
         if (daemon->log_file != NULL)          if (daemon->log_file != NULL)
           log_reopen(daemon->log_file);            log_reopen(daemon->log_file);
         break;          break;
        
       case EVENT_NEWADDR:
         newaddress(now);
         break;
 
       case EVENT_NEWROUTE:
         resend_query();
         /* Force re-reading resolv file right now, for luck. */
         poll_resolv(0, 1, now);
         break;
 
       case EVENT_TERM:        case EVENT_TERM:
         /* Knock all our children on the head. */          /* Knock all our children on the head. */
         for (i = 0; i < MAX_PROCS; i++)          for (i = 0; i < MAX_PROCS; i++)
           if (daemon->tcp_pids[i] != 0)            if (daemon->tcp_pids[i] != 0)
             kill(daemon->tcp_pids[i], SIGALRM);              kill(daemon->tcp_pids[i], SIGALRM);
                   
#if defined(HAVE_SCRIPT)#if defined(HAVE_SCRIPT) && defined(HAVE_DHCP)
         /* handle pending lease transitions */          /* handle pending lease transitions */
         if (daemon->helperfd != -1)          if (daemon->helperfd != -1)
           {            {
Line 1135  static void async_event(int pipe, time_t now) Line 1348  static void async_event(int pipe, time_t now)
             do {              do {
               helper_write();                helper_write();
             } while (!helper_buf_empty() || do_script_run(now));              } while (!helper_buf_empty() || do_script_run(now));
            close(daemon->helperfd);            while (retry_send(close(daemon->helperfd)));
           }            }
 #endif  #endif
                   
         if (daemon->lease_stream)          if (daemon->lease_stream)
           fclose(daemon->lease_stream);            fclose(daemon->lease_stream);
   
   #ifdef HAVE_DNSSEC
           /* update timestamp file on TERM if time is considered valid */
           if (daemon->back_to_the_future)
             {
                if (utime(daemon->timestamp_file, NULL) == -1)
                   my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
             }
   #endif
   
         if (daemon->runfile)          if (daemon->runfile)
           unlink(daemon->runfile);            unlink(daemon->runfile);
                   
Line 1151  static void async_event(int pipe, time_t now) Line 1373  static void async_event(int pipe, time_t now)
       }        }
 }  }
   
void poll_resolv(int force, int do_reload, time_t now)static void poll_resolv(int force, int do_reload, time_t now)
 {  {
   struct resolvc *res, *latest;    struct resolvc *res, *latest;
   struct stat statbuf;    struct stat statbuf;
Line 1223  void poll_resolv(int force, int do_reload, time_t now) Line 1445  void poll_resolv(int force, int do_reload, time_t now)
   
 void clear_cache_and_reload(time_t now)  void clear_cache_and_reload(time_t now)
 {  {
     (void)now;
   
   if (daemon->port != 0)    if (daemon->port != 0)
     cache_reload();      cache_reload();
       
Line 1232  void clear_cache_and_reload(time_t now) Line 1456  void clear_cache_and_reload(time_t now)
       if (option_bool(OPT_ETHERS))        if (option_bool(OPT_ETHERS))
         dhcp_read_ethers();          dhcp_read_ethers();
       reread_dhcp();        reread_dhcp();
   #ifdef HAVE_INOTIFY
         set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
   #endif
       dhcp_update_configs(daemon->dhcp_conf);        dhcp_update_configs(daemon->dhcp_conf);
       lease_update_from_configs();         lease_update_from_configs(); 
       lease_update_file(now);         lease_update_file(now); 
Line 1246  void clear_cache_and_reload(time_t now) Line 1473  void clear_cache_and_reload(time_t now)
 #endif  #endif
 }  }
   
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)static int set_dns_listeners(time_t now)
 {  {
   struct serverfd *serverfdp;    struct serverfd *serverfdp;
   struct listener *listener;    struct listener *listener;
Line 1258  static int set_dns_listeners(time_t now, fd_set *set,  Line 1485  static int set_dns_listeners(time_t now, fd_set *set, 
   for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)    for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
     {      {
       tftp++;        tftp++;
      FD_SET(transfer->sockfd, set);      poll_listen(transfer->sockfd, POLLIN);
      bump_maxfd(transfer->sockfd, maxfdp); 
     }      }
 #endif  #endif
       
   /* will we be able to get memory? */    /* will we be able to get memory? */
   if (daemon->port != 0)    if (daemon->port != 0)
    get_new_frec(now, &wait);    get_new_frec(now, &wait, 0);
       
   for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)    for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
    {    poll_listen(serverfdp->fd, POLLIN);
      FD_SET(serverfdp->fd, set);    
      bump_maxfd(serverfdp->fd, maxfdp); 
    } 
 
   if (daemon->port != 0 && !daemon->osport)    if (daemon->port != 0 && !daemon->osport)
     for (i = 0; i < RANDOM_SOCKS; i++)      for (i = 0; i < RANDOM_SOCKS; i++)
       if (daemon->randomsocks[i].refcount != 0)        if (daemon->randomsocks[i].refcount != 0)
        {        poll_listen(daemon->randomsocks[i].fd, POLLIN);
          FD_SET(daemon->randomsocks[i].fd, set);          
          bump_maxfd(daemon->randomsocks[i].fd, maxfdp); 
        } 
   
   for (listener = daemon->listeners; listener; listener = listener->next)    for (listener = daemon->listeners; listener; listener = listener->next)
     {      {
       /* only listen for queries if we have resources */        /* only listen for queries if we have resources */
       if (listener->fd != -1 && wait == 0)        if (listener->fd != -1 && wait == 0)
        {        poll_listen(listener->fd, POLLIN);
          FD_SET(listener->fd, set);        
          bump_maxfd(listener->fd, maxfdp); 
        } 
 
       /* death of a child goes through the select loop, so        /* death of a child goes through the select loop, so
          we don't need to explicitly arrange to wake up here */           we don't need to explicitly arrange to wake up here */
       if  (listener->tcpfd != -1)        if  (listener->tcpfd != -1)
         for (i = 0; i < MAX_PROCS; i++)          for (i = 0; i < MAX_PROCS; i++)
           if (daemon->tcp_pids[i] == 0)            if (daemon->tcp_pids[i] == 0)
             {              {
              FD_SET(listener->tcpfd, set);              poll_listen(listener->tcpfd, POLLIN);
              bump_maxfd(listener->tcpfd, maxfdp); 
               break;                break;
             }              }
   
 #ifdef HAVE_TFTP  #ifdef HAVE_TFTP
       if (tftp <= daemon->tftp_max && listener->tftpfd != -1)        if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
        {        poll_listen(listener->tftpfd, POLLIN);
          FD_SET(listener->tftpfd, set); 
          bump_maxfd(listener->tftpfd, maxfdp); 
        } 
 #endif  #endif
   
     }      }
Line 1314  static int set_dns_listeners(time_t now, fd_set *set,  Line 1527  static int set_dns_listeners(time_t now, fd_set *set, 
   return wait;    return wait;
 }  }
   
static void check_dns_listeners(fd_set *set, time_t now)static void check_dns_listeners(time_t now)
 {  {
   struct serverfd *serverfdp;    struct serverfd *serverfdp;
   struct listener *listener;    struct listener *listener;
   int i;    int i;
   
   for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)    for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
    if (FD_ISSET(serverfdp->fd, set))    if (poll_check(serverfdp->fd, POLLIN))
       reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);        reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
       
   if (daemon->port != 0 && !daemon->osport)    if (daemon->port != 0 && !daemon->osport)
     for (i = 0; i < RANDOM_SOCKS; i++)      for (i = 0; i < RANDOM_SOCKS; i++)
       if (daemon->randomsocks[i].refcount != 0 &&         if (daemon->randomsocks[i].refcount != 0 && 
          FD_ISSET(daemon->randomsocks[i].fd, set))          poll_check(daemon->randomsocks[i].fd, POLLIN))
         reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);          reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
       
   for (listener = daemon->listeners; listener; listener = listener->next)    for (listener = daemon->listeners; listener; listener = listener->next)
     {      {
      if (listener->fd != -1 && FD_ISSET(listener->fd, set))      if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
         receive_query(listener, now);           receive_query(listener, now); 
               
 #ifdef HAVE_TFTP       #ifdef HAVE_TFTP     
      if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))      if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN))
         tftp_request(listener, now);          tftp_request(listener, now);
 #endif  #endif
   
      if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))      if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
         {          {
           int confd, client_ok = 1;            int confd, client_ok = 1;
           struct irec *iface = NULL;            struct irec *iface = NULL;
Line 1352  static void check_dns_listeners(fd_set *set, time_t no Line 1565  static void check_dns_listeners(fd_set *set, time_t no
                       
           if (confd == -1)            if (confd == -1)
             continue;              continue;
          
           if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)            if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
             {              {
              close(confd);              while (retry_send(close(confd)));
               continue;                continue;
             }              }
             
             /* Make sure that the interface list is up-to-date.
                
                We do this here as we may need the results below, and
                the DNS code needs them for --interface-name stuff.
   
           if (option_bool(OPT_NOWILD))             Multiple calls to enumerate_interfaces() per select loop are
            iface = listener->iface; /* May be NULL */             inhibited, so calls to it in the child process (which doesn't select())
           else              have no effect. This avoids two processes reading from the same
             {             netlink fd and screwing the pooch entirely.
               int if_index;          */
               char intr_name[IF_NAMESIZE]; 
     
               /* In full wildcard mode, need to refresh interface list.          enumerate_interfaces(0);
                  This happens automagically in CLEVERBIND */          
               if (!option_bool(OPT_CLEVERBIND))          if (option_bool(OPT_NOWILD))
                 enumerate_interfaces();            iface = listener->iface; /* May be NULL */
                         else 
               /* if we can find the arrival interface, check it's one that's allowed */            {
               if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&              int if_index;
                   indextoname(listener->tcpfd, if_index, intr_name))              char intr_name[IF_NAMESIZE];
                 {              
                   struct all_addr addr;              /* if we can find the arrival interface, check it's one that's allowed */
                   addr.addr.addr4 = tcp_addr.in.sin_addr;              if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
                   indextoname(listener->tcpfd, if_index, intr_name))
                 {
                   struct all_addr addr;
                   addr.addr.addr4 = tcp_addr.in.sin_addr;
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
                   if (tcp_addr.sa.sa_family == AF_INET6)                  if (tcp_addr.sa.sa_family == AF_INET6)
                     addr.addr.addr6 = tcp_addr.in6.sin6_addr;                    addr.addr.addr6 = tcp_addr.in6.sin6_addr;
 #endif  #endif
                                     
                   for (iface = daemon->interfaces; iface; iface = iface->next)                  for (iface = daemon->interfaces; iface; iface = iface->next)
                     if (iface->index == if_index)                    if (iface->index == if_index)
                       break;                      break;
                                     
                   if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))                  if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
                     client_ok = 0;                    client_ok = 0;
                 }                }
                             
               if (option_bool(OPT_CLEVERBIND))              if (option_bool(OPT_CLEVERBIND))
                 iface = listener->iface; /* May be NULL */                iface = listener->iface; /* May be NULL */
               else              else
                 {                {
                    /* Check for allowed interfaces when binding the wildcard address:                  /* Check for allowed interfaces when binding the wildcard address:
                       we do this by looking for an interface with the same address as                      we do this by looking for an interface with the same address as 
                       the local address of the TCP connection, then looking to see if that's                     the local address of the TCP connection, then looking to see if that's
                       an allowed interface. As a side effect, we get the netmask of the                     an allowed interface. As a side effect, we get the netmask of the
                      interface too, for localisation. */                     interface too, for localisation. */
                                     
                   for (iface = daemon->interfaces; iface; iface = iface->next)                  for (iface = daemon->interfaces; iface; iface = iface->next)
                     if (sockaddr_isequal(&iface->addr, &tcp_addr))                    if (sockaddr_isequal(&iface->addr, &tcp_addr))
                       break;                      break;
                                     
                   if (!iface)                  if (!iface)
                     client_ok = 0;                    client_ok = 0;
                 }                }
             }            }
                            
           if (!client_ok)            if (!client_ok)
             {              {
               shutdown(confd, SHUT_RDWR);                shutdown(confd, SHUT_RDWR);
              close(confd);              while (retry_send(close(confd)));
             }              }
 #ifndef NO_FORK  #ifndef NO_FORK
           else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)            else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
Line 1427  static void check_dns_listeners(fd_set *set, time_t no Line 1648  static void check_dns_listeners(fd_set *set, time_t no
                         break;                          break;
                       }                        }
                 }                  }
              close(confd);              while (retry_send(close(confd)));
 
               /* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
               daemon->log_id += TCP_MAX_QUERIES;
             }              }
 #endif  #endif
           else            else
Line 1469  static void check_dns_listeners(fd_set *set, time_t no Line 1693  static void check_dns_listeners(fd_set *set, time_t no
               buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);                buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
                                 
               shutdown(confd, SHUT_RDWR);                shutdown(confd, SHUT_RDWR);
              close(confd);              while (retry_send(close(confd)));
                               
               if (buff)                if (buff)
                 free(buff);                  free(buff);
Line 1478  static void check_dns_listeners(fd_set *set, time_t no Line 1702  static void check_dns_listeners(fd_set *set, time_t no
                 if (s->tcpfd != -1)                  if (s->tcpfd != -1)
                   {                    {
                     shutdown(s->tcpfd, SHUT_RDWR);                      shutdown(s->tcpfd, SHUT_RDWR);
                    close(s->tcpfd);                    while (retry_send(close(s->tcpfd)));
                   }                    }
 #ifndef NO_FORK              #ifndef NO_FORK            
               if (!option_bool(OPT_DEBUG))                if (!option_bool(OPT_DEBUG))
Line 1520  int icmp_ping(struct in_addr addr) Line 1744  int icmp_ping(struct in_addr addr)
      better not use any resources our caller has in use...)       better not use any resources our caller has in use...)
      but we remain deaf to signals or further DHCP packets. */       but we remain deaf to signals or further DHCP packets. */
   
  int fd;  /* There can be a problem using dnsmasq_time() to end the loop, since
      it's not monotonic, and can go backwards if the system clock is
      tweaked, leading to the code getting stuck in this loop and
      ignoring DHCP requests. To fix this, we check to see if select returned
      as a result of a timeout rather than a socket becoming available. We
      only allow this to happen as many times as it takes to get to the wait time
      in quarter-second chunks. This provides a fallback way to end loop. */ 
 
   int fd, rc;
   struct sockaddr_in saddr;    struct sockaddr_in saddr;
   struct {     struct { 
     struct ip ip;      struct ip ip;
     struct icmp icmp;      struct icmp icmp;
   } packet;    } packet;
   unsigned short id = rand16();    unsigned short id = rand16();
  unsigned int i, j;  unsigned int i, j, timeout_count;
   int gotreply = 0;    int gotreply = 0;
   time_t start, now;    time_t start, now;
   
Line 1556  int icmp_ping(struct in_addr addr) Line 1788  int icmp_ping(struct in_addr addr)
     j = (j & 0xffff) + (j >> 16);        j = (j & 0xffff) + (j >> 16);  
   packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;    packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
       
  while (sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0,   while (retry_send(sendto(fd, (char *)&packet.icmp, sizeof(struct icmp), 0, 
                (struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&                           (struct sockaddr *)&saddr, sizeof(saddr))));
         retry_send()); 
       
  for (now = start = dnsmasq_time();   for (now = start = dnsmasq_time(), timeout_count = 0; 
       difftime(now, start) < (float)PING_WAIT;)       (difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT * 4);)
     {      {
       struct timeval tv;  
       fd_set rset, wset;  
       struct sockaddr_in faddr;        struct sockaddr_in faddr;
       int maxfd = fd;   
       socklen_t len = sizeof(faddr);        socklen_t len = sizeof(faddr);
               
      tv.tv_usec = 250000;      poll_reset();
      tv.tv_sec = 0;       poll_listen(fd, POLLIN);
       set_dns_listeners(now);
       set_log_writer();
               
       FD_ZERO(&rset);  
       FD_ZERO(&wset);  
       FD_SET(fd, &rset);  
       set_dns_listeners(now, &rset, &maxfd);  
       set_log_writer(&wset, &maxfd);  
         
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
       if (daemon->doing_ra)        if (daemon->doing_ra)
        {        poll_listen(daemon->icmp6fd, POLLIN); 
          FD_SET(daemon->icmp6fd, &rset); 
          bump_maxfd(daemon->icmp6fd, &maxfd);  
        } 
 #endif  #endif
               
      if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)      rc = do_poll(250);
        {      
          FD_ZERO(&rset);      if (rc < 0)
          FD_ZERO(&wset);        continue;
        }      else if (rc == 0)
         timeout_count++;
   
       now = dnsmasq_time();        now = dnsmasq_time();
   
      check_log_writer(&wset);      check_log_writer(0);
      check_dns_listeners(&rset, now);      check_dns_listeners(now);
   
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
      if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))      if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN))
         icmp6_packet(now);          icmp6_packet(now);
 #endif  #endif
               
 #ifdef HAVE_TFTP  #ifdef HAVE_TFTP
      check_tftp_listeners(&rset, now);      check_tftp_listeners(now);
 #endif  #endif
   
      if (FD_ISSET(fd, &rset) &&      if (poll_check(fd, POLLIN) &&
           recvfrom(fd, &packet, sizeof(packet), 0,            recvfrom(fd, &packet, sizeof(packet), 0,
                    (struct sockaddr *)&faddr, &len) == sizeof(packet) &&                     (struct sockaddr *)&faddr, &len) == sizeof(packet) &&
           saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&            saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
Line 1620  int icmp_ping(struct in_addr addr) Line 1842  int icmp_ping(struct in_addr addr)
     }      }
       
 #if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)  #if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
  close(fd);  while (retry_send(close(fd)));
 #else  #else
   opt = 1;    opt = 1;
   setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));    setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>