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

version 1.1.1.2, 2014/06/15 16:31:38 version 1.1.1.3, 2016/11/02 09:57:01
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2014 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 52  static void do_options(struct dhcp_context *context, Line 52  static void do_options(struct dhcp_context *context,
                        int null_term, int pxearch,                         int null_term, int pxearch,
                        unsigned char *uuid,                         unsigned char *uuid,
                        int vendor_class_len,                         int vendor_class_len,
                       time_t now);                       time_t now,
                        unsigned int lease_time,
                        unsigned short fuzz);
   
   
 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);   static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); 
Line 61  static void pxe_misc(struct dhcp_packet *mess, unsigne Line 63  static void pxe_misc(struct dhcp_packet *mess, unsigne
 static int prune_vendor_opts(struct dhcp_netid *netid);  static int prune_vendor_opts(struct dhcp_netid *netid);
 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);  static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
 struct dhcp_boot *find_boot(struct dhcp_netid *netid);  struct dhcp_boot *find_boot(struct dhcp_netid *netid);
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
       
 size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,  size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
                   size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)                    size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
Line 610  size_t dhcp_reply(struct dhcp_context *context, char * Line 612  size_t dhcp_reply(struct dhcp_context *context, char *
                               
               clear_packet(mess, end);                clear_packet(mess, end);
               do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),                 do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 
                         netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);                         netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
             }              }
         }          }
               
Line 803  size_t dhcp_reply(struct dhcp_context *context, char * Line 805  size_t dhcp_reply(struct dhcp_context *context, char *
             if (service->type == type)              if (service->type == type)
               break;                break;
                       
          if (!service || !service->basename)          for (; context; context = context->current)
            return 0;            if (match_netid(context->filter, tagif_netid, 1) &&
                 is_same_net(mess->ciaddr, context->start, context->netmask))
               break;
                       
             if (!service || !service->basename || !context)
               return 0;
                     
           clear_packet(mess, end);            clear_packet(mess, end);
                       
           mess->yiaddr = mess->ciaddr;            mess->yiaddr = mess->ciaddr;
Line 817  size_t dhcp_reply(struct dhcp_context *context, char * Line 824  size_t dhcp_reply(struct dhcp_context *context, char *
           else            else
             mess->siaddr = context->local;               mess->siaddr = context->local; 
                       
          snprintf((char *)mess->file, sizeof(mess->file), "%s.%d", service->basename, layer);          snprintf((char *)mess->file, sizeof(mess->file), 
                    strchr(service->basename, '.') ? "%s" :"%s.%d", 
                    service->basename, layer);
           
           option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);            option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
           option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));            option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
           pxe_misc(mess, end, uuid);            pxe_misc(mess, end, uuid);
Line 844  size_t dhcp_reply(struct dhcp_context *context, char * Line 854  size_t dhcp_reply(struct dhcp_context *context, char *
           if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))            if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
             {              {
               struct dhcp_context *tmp;                struct dhcp_context *tmp;
                 int workaround = 0;
                               
               for (tmp = context; tmp; tmp = tmp->current)                for (tmp = context; tmp; tmp = tmp->current)
                 if ((tmp->flags & CONTEXT_PROXY) &&                  if ((tmp->flags & CONTEXT_PROXY) &&
Line 853  size_t dhcp_reply(struct dhcp_context *context, char * Line 864  size_t dhcp_reply(struct dhcp_context *context, char *
               if (tmp)                if (tmp)
                 {                  {
                   struct dhcp_boot *boot;                    struct dhcp_boot *boot;
                                    int redirect4011 = 0;
 
                   if (tmp->netid.net)                    if (tmp->netid.net)
                     {                      {
                       tmp->netid.next = netid;                        tmp->netid.next = netid;
Line 871  size_t dhcp_reply(struct dhcp_context *context, char * Line 883  size_t dhcp_reply(struct dhcp_context *context, char *
                                       
                   clear_packet(mess, end);                    clear_packet(mess, end);
                                       
                  /* Provide the bootfile here, for gPXE, and in case we have no menu items                  /* Redirect EFI clients to port 4011 */
                     and set discovery_control = 8 */                  if (pxearch >= 6)
                  if (boot) 
                     {                      {
                         redirect4011 = 1;
                         mess->siaddr = tmp->local;
                       }
                     
                     /* Returns true if only one matching service is available. On port 4011, 
                        it also inserts the boot file and server name. */
                     workaround = pxe_uefi_workaround(pxearch, tagif_netid, mess, tmp->local, now, pxe);
                     
                     if (!workaround && boot)
                       {
                         /* Provide the bootfile here, for gPXE, and in case we have no menu items
                            and set discovery_control = 8 */
                       if (boot->next_server.s_addr)                         if (boot->next_server.s_addr) 
                         mess->siaddr = boot->next_server;                          mess->siaddr = boot->next_server;
                       else if (boot->tftp_sname)                         else if (boot->tftp_sname) 
Line 886  size_t dhcp_reply(struct dhcp_context *context, char * Line 909  size_t dhcp_reply(struct dhcp_context *context, char *
                                       
                   option_put(mess, end, OPTION_MESSAGE_TYPE, 1,                     option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
                              mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);                               mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
                  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));                  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
                   pxe_misc(mess, end, uuid);                    pxe_misc(mess, end, uuid);
                   prune_vendor_opts(tagif_netid);                    prune_vendor_opts(tagif_netid);
                  do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);                  if ((pxe && !workaround) || !redirect4011)
                                      do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
             
                   log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);                    log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
                   log_tags(tagif_netid, ntohl(mess->xid));                    log_tags(tagif_netid, ntohl(mess->xid));
                   return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);                             return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);         
Line 1042  size_t dhcp_reply(struct dhcp_context *context, char * Line 1066  size_t dhcp_reply(struct dhcp_context *context, char *
       option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));        option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
       option_put(mess, end, OPTION_LEASE_TIME, 4, time);        option_put(mess, end, OPTION_LEASE_TIME, 4, time);
       /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */        /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
       if (time != 0xffffffff)  
         {  
           option_put(mess, end, OPTION_T1, 4, (time/2));  
           option_put(mess, end, OPTION_T2, 4, (time*7)/8);  
         }  
       do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),         do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), 
                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
               
       return dhcp_packet_size(mess, agent_id, real_end);        return dhcp_packet_size(mess, agent_id, real_end);
               
Line 1306  size_t dhcp_reply(struct dhcp_context *context, char * Line 1325  size_t dhcp_reply(struct dhcp_context *context, char *
                       /* If the user-class option started as counted strings, the first byte will be zero. */                        /* If the user-class option started as counted strings, the first byte will be zero. */
                       if (len != 0 && ucp[0] == 0)                        if (len != 0 && ucp[0] == 0)
                         ucp++, len--;                          ucp++, len--;
                      lease_add_extradata(lease, ucp, len, 0);                      lease_add_extradata(lease, ucp, len, -1);
                     }                      }
                 }                  }
 #endif  #endif
Line 1367  size_t dhcp_reply(struct dhcp_context *context, char * Line 1386  size_t dhcp_reply(struct dhcp_context *context, char *
           option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);            option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
           option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));            option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
           option_put(mess, end, OPTION_LEASE_TIME, 4, time);            option_put(mess, end, OPTION_LEASE_TIME, 4, time);
           if (time != 0xffffffff)  
             {  
               while (fuzz > (time/16))  
                 fuzz = fuzz/2;   
               option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);  
               option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);  
             }  
           do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),             do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), 
                     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);                     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
         }          }
   
       return dhcp_packet_size(mess, agent_id, real_end);         return dhcp_packet_size(mess, agent_id, real_end); 
Line 1440  size_t dhcp_reply(struct dhcp_context *context, char * Line 1452  size_t dhcp_reply(struct dhcp_context *context, char *
         }          }
   
       do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),        do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
               
       *is_inform = 1; /* handle reply differently */        *is_inform = 1; /* handle reply differently */
       return dhcp_packet_size(mess, agent_id, real_end);         return dhcp_packet_size(mess, agent_id, real_end); 
Line 1980  static int prune_vendor_opts(struct dhcp_netid *netid) Line 1992  static int prune_vendor_opts(struct dhcp_netid *netid)
   return force;    return force;
 }  }
   
   
   /* Many UEFI PXE implementations have badly broken menu code.
      If there's exactly one relevant menu item, we abandon the menu system,
      and jamb the data direct into the DHCP file, siaddr and sname fields.
      Note that in this case, we have to assume that layer zero would be requested
      by the client PXE stack. */
   static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe)
   {
     struct pxe_service *service, *found;
   
     /* Only workaround UEFI archs. */
     if (pxe_arch < 6)
       return 0;
     
     for (found = NULL, service = daemon->pxe_services; service; service = service->next)
       if (pxe_arch == service->CSA && service->basename && match_netid(service->netid, netid, 1))
         {
           if (found)
             return 0; /* More than one relevant menu item */
             
           found = service;
         }
   
     if (!found)
       return 0; /* No relevant menu items. */
     
     if (!pxe)
        return 1;
     
     if (found->sname)
       {
         mess->siaddr = a_record_from_hosts(found->sname, now);
         snprintf((char *)mess->sname, sizeof(mess->sname), "%s", found->sname);
       }
     else 
       {
         if (found->server.s_addr != 0)
           mess->siaddr = found->server; 
         else
           mess->siaddr = local;
     
         inet_ntop(AF_INET, &mess->siaddr, (char *)mess->sname, INET_ADDRSTRLEN);
       }
     
     snprintf((char *)mess->file, sizeof(mess->file), 
              strchr(found->basename, '.') ? "%s" : "%s.0", found->basename);
     
     return 1;
   }
   
 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)  static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
 {  {
 #define NUM_OPTS 4    #define NUM_OPTS 4  
Line 2137  static void do_options(struct dhcp_context *context, Line 2199  static void do_options(struct dhcp_context *context,
                        int null_term, int pxe_arch,                         int null_term, int pxe_arch,
                        unsigned char *uuid,                         unsigned char *uuid,
                        int vendor_class_len,                         int vendor_class_len,
                       time_t now)                       time_t now,
                        unsigned int lease_time,
                        unsigned short fuzz)
 {  {
   struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;    struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
   struct dhcp_boot *boot;    struct dhcp_boot *boot;
Line 2261  static void do_options(struct dhcp_context *context, Line 2325  static void do_options(struct dhcp_context *context,
   /* rfc3011 says this doesn't need to be in the requested options list. */    /* rfc3011 says this doesn't need to be in the requested options list. */
   if (subnet_addr.s_addr)    if (subnet_addr.s_addr)
     option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));      option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
     
   if (lease_time != 0xffffffff)
     { 
       unsigned int t1val = lease_time/2; 
       unsigned int t2val = (lease_time*7)/8;
       unsigned int hval;
       
       /* If set by user, sanity check, so not longer than lease. */
       if ((opt = option_find2(OPTION_T1)))
         {
           hval = ntohl(*((unsigned int *)opt->val));
           if (hval < lease_time && hval > 2)
             t1val = hval;
         }
 
        if ((opt = option_find2(OPTION_T2)))
         {
           hval = ntohl(*((unsigned int *)opt->val));
           if (hval < lease_time && hval > 2)
             t2val = hval;
         }
           
        /* ensure T1 is still < T2 */
        if (t2val <= t1val)
          t1val = t2val - 1; 
 
        while (fuzz > (t1val/8))
          fuzz = fuzz/2;
          
        t1val -= fuzz;
        t2val -= fuzz;
        
        option_put(mess, end, OPTION_T1, 4, t1val);
        option_put(mess, end, OPTION_T2, 4, t2val);
     }
 
   /* replies to DHCPINFORM may not have a valid context */    /* replies to DHCPINFORM may not have a valid context */
   if (context)    if (context)
     {      {
Line 2356  static void do_options(struct dhcp_context *context, Line 2455  static void do_options(struct dhcp_context *context,
       if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))        if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
         continue;          continue;
               
      /* prohibit some used-internally options */      /* prohibit some used-internally options. T1 and T2 already handled. */
       if (optno == OPTION_CLIENT_FQDN ||        if (optno == OPTION_CLIENT_FQDN ||
           optno == OPTION_MAXMESSAGE ||            optno == OPTION_MAXMESSAGE ||
           optno == OPTION_OVERLOAD ||            optno == OPTION_OVERLOAD ||
           optno == OPTION_PAD ||            optno == OPTION_PAD ||
          optno == OPTION_END)          optno == OPTION_END ||
           optno == OPTION_T1 ||
           optno == OPTION_T2)
         continue;          continue;
   
       if (optno == OPTION_SNAME && done_server)        if (optno == OPTION_SNAME && done_server)
Line 2475  static void do_options(struct dhcp_context *context, Line 2576  static void do_options(struct dhcp_context *context,
   if (context && pxe_arch != -1)    if (context && pxe_arch != -1)
     {      {
       pxe_misc(mess, end, uuid);        pxe_misc(mess, end, uuid);
      config_opts = pxe_opts(pxe_arch, tagif, context->local, now);      if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
         config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
     }      }
   
   if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&    if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&

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


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