Diff for /embedaddon/dnsmasq/src/rfc3315.c between versions 1.1.1.4 and 1.1.1.5

version 1.1.1.4, 2021/03/17 00:56:46 version 1.1.1.5, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley/* dnsmasq is Copyright (c) 2000-2022 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 33  struct state { Line 33  struct state {
   unsigned int mac_len, mac_type;    unsigned int mac_len, mac_type;
 };  };
   
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz, 
                              struct in6_addr *client_addr, int is_unicast, time_t now);                               struct in6_addr *client_addr, int is_unicast, time_t now);
static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now);
 static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);  static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
 static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);  static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
 static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);  static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
Line 104  unsigned short dhcp6_reply(struct dhcp_context *contex Line 104  unsigned short dhcp6_reply(struct dhcp_context *contex
 }  }
   
 /* This cost me blood to write, it will probably cost you blood to understand - srk. */  /* This cost me blood to write, it will probably cost you blood to understand - srk. */
static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz, 
                              struct in6_addr *client_addr, int is_unicast, time_t now)                               struct in6_addr *client_addr, int is_unicast, time_t now)
 {  {
   void *end = inbuff + sz;    void *end = inbuff + sz;
   void *opts = inbuff + 34;    void *opts = inbuff + 34;
  int msg_type = *((unsigned char *)inbuff);  int msg_type = *inbuff;
   unsigned char *outmsgtypep;    unsigned char *outmsgtypep;
   void *opt;    void *opt;
   struct dhcp_vendor *vendor;    struct dhcp_vendor *vendor;
Line 259  static int dhcp6_maybe_relay(struct state *state, void Line 259  static int dhcp6_maybe_relay(struct state *state, void
   return 1;    return 1;
 }  }
   
static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now)static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now)
 {  {
   void *opt;    void *opt;
  int i, o, o1, start_opts;  int i, o, o1, start_opts, start_msg;
   struct dhcp_opt *opt_cfg;    struct dhcp_opt *opt_cfg;
   struct dhcp_netid *tagif;    struct dhcp_netid *tagif;
   struct dhcp_config *config = NULL;    struct dhcp_config *config = NULL;
   struct dhcp_netid known_id, iface_id, v6_id;    struct dhcp_netid known_id, iface_id, v6_id;
  unsigned char *outmsgtypep;  unsigned char outmsgtype;
   struct dhcp_vendor *vendor;    struct dhcp_vendor *vendor;
   struct dhcp_context *context_tmp;    struct dhcp_context *context_tmp;
   struct dhcp_mac *mac_opt;    struct dhcp_mac *mac_opt;
Line 296  static int dhcp6_no_relay(struct state *state, int msg Line 296  static int dhcp6_no_relay(struct state *state, int msg
   v6_id.next = state->tags;    v6_id.next = state->tags;
   state->tags = &v6_id;    state->tags = &v6_id;
   
  /* copy over transaction-id, and save pointer to message type */  start_msg = save_counter(-1);
  if (!(outmsgtypep = put_opt6(inbuff, 4)))  /* copy over transaction-id */
   if (!put_opt6(inbuff, 4))
     return 0;      return 0;
   start_opts = save_counter(-1);    start_opts = save_counter(-1);
  state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;  state->xid = inbuff[3] | inbuff[2] << 8 | inbuff[1] << 16;
       
   /* We're going to be linking tags from all context we use.     /* We're going to be linking tags from all context we use. 
      mark them as unused so we don't link one twice and break the list */       mark them as unused so we don't link one twice and break the list */
   for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)    for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
Line 347  static int dhcp6_no_relay(struct state *state, int msg Line 348  static int dhcp6_no_relay(struct state *state, int msg
       (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))        (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
           
     {        {  
      *outmsgtypep = DHCP6REPLY;      outmsgtype = DHCP6REPLY;
       o1 = new_opt6(OPTION6_STATUS_CODE);        o1 = new_opt6(OPTION6_STATUS_CODE);
       put_opt6_short(DHCP6USEMULTI);        put_opt6_short(DHCP6USEMULTI);
       put_opt6_string("Use multicast");        put_opt6_string("Use multicast");
       end_opt6(o1);        end_opt6(o1);
      return 1;      goto done;
     }      }
   
   /* match vendor and user class options */    /* match vendor and user class options */
Line 619  static int dhcp6_no_relay(struct state *state, int msg Line 620  static int dhcp6_no_relay(struct state *state, int msg
         struct dhcp_netid *solicit_tags;          struct dhcp_netid *solicit_tags;
         struct dhcp_context *c;          struct dhcp_context *c;
                   
        *outmsgtypep = DHCP6ADVERTISE;        outmsgtype = DHCP6ADVERTISE;
                   
         if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))          if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
           {            {
            *outmsgtypep = DHCP6REPLY;            outmsgtype = DHCP6REPLY;
             state->lease_allocate = 1;              state->lease_allocate = 1;
             o = new_opt6(OPTION6_RAPID_COMMIT);              o = new_opt6(OPTION6_RAPID_COMMIT);
             end_opt6(o);              end_opt6(o);
Line 809  static int dhcp6_no_relay(struct state *state, int msg Line 810  static int dhcp6_no_relay(struct state *state, int msg
         int start = save_counter(-1);          int start = save_counter(-1);
   
         /* set reply message type */          /* set reply message type */
        *outmsgtypep = DHCP6REPLY;        outmsgtype = DHCP6REPLY;
         state->lease_allocate = 1;          state->lease_allocate = 1;
   
         log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);          log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
Line 919  static int dhcp6_no_relay(struct state *state, int msg Line 920  static int dhcp6_no_relay(struct state *state, int msg
               
       
     case DHCP6RENEW:      case DHCP6RENEW:
       case DHCP6REBIND:
       {        {
           int address_assigned = 0;
   
         /* set reply message type */          /* set reply message type */
        *outmsgtypep = DHCP6REPLY;        outmsgtype = DHCP6REPLY;
                   
        log6_quiet(state, "DHCPRENEW", NULL, NULL);        log6_quiet(state, msg_type == DHCP6RENEW ? "DHCPRENEW" : "DHCPREBIND", NULL, NULL);
   
         for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))          for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
           {            {
Line 952  static int dhcp6_no_relay(struct state *state, int msg Line 956  static int dhcp6_no_relay(struct state *state, int msg
                                           state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,                                             state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, 
                                           state->iaid, &req_addr)))                                            state->iaid, &req_addr)))
                   {                    {
                    /* If the server cannot find a client entry for the IA the server                    if (msg_type == DHCP6REBIND)
                       returns the IA containing no addresses with a Status Code option set                      {
                       to NoBinding in the Reply message. */                        /* When rebinding, we can create a lease if it doesn't exist. */
                    save_counter(iacntr);                        lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
                    t1cntr = 0;                        if (lease)
                                              lease_set_iaid(lease, state->iaid);
                    log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));                        else
                                              break;
                    o1 = new_opt6(OPTION6_STATUS_CODE);                      }
                    put_opt6_short(DHCP6NOBINDING);                    else
                    put_opt6_string(_("no binding found"));                      {
                    end_opt6(o1);                        /* If the server cannot find a client entry for the IA the server
                           returns the IA containing no addresses with a Status Code option set
                    preferred_time = valid_time = 0;                           to NoBinding in the Reply message. */
                    break;                        save_counter(iacntr);
                         t1cntr = 0;
                         
                         log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
                         
                         o1 = new_opt6(OPTION6_STATUS_CODE);
                         put_opt6_short(DHCP6NOBINDING);
                         put_opt6_string(_("no binding found"));
                         end_opt6(o1);
                         
                         preferred_time = valid_time = 0;
                         break;
                       }
                   }                    }
                                   
                   
                 if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||                  if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
                     (this_context = address6_valid(state->context, &req_addr, tagif, 1)))                      (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
                   {                    {
Line 1000  static int dhcp6_no_relay(struct state *state, int msg Line 1015  static int dhcp6_no_relay(struct state *state, int msg
                                           
                     if (preferred_time == 0)                      if (preferred_time == 0)
                       message = _("deprecated");                        message = _("deprecated");
   
                       address_assigned = 1;
                   }                    }
                 else                  else
                   {                    {
Line 1022  static int dhcp6_no_relay(struct state *state, int msg Line 1039  static int dhcp6_no_relay(struct state *state, int msg
             end_ia(t1cntr, min_time, 1);              end_ia(t1cntr, min_time, 1);
             end_opt6(o);              end_opt6(o);
           }            }
   
           if (!address_assigned && msg_type == DHCP6REBIND)
             { 
               /* can't create lease for any address, return error */
               o1 = new_opt6(OPTION6_STATUS_CODE);
               put_opt6_short(DHCP6NOADDRS);
               put_opt6_string(_("no addresses available"));
               end_opt6(o1);
             }
                   
         tagif = add_options(state, 0);          tagif = add_options(state, 0);
         break;          break;
           
       }        }
               
     case DHCP6CONFIRM:      case DHCP6CONFIRM:
Line 1033  static int dhcp6_no_relay(struct state *state, int msg Line 1058  static int dhcp6_no_relay(struct state *state, int msg
         int good_addr = 0;          int good_addr = 0;
   
         /* set reply message type */          /* set reply message type */
        *outmsgtypep = DHCP6REPLY;        outmsgtype = DHCP6REPLY;
                   
         log6_quiet(state, "DHCPCONFIRM", NULL, NULL);          log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
                   
Line 1097  static int dhcp6_no_relay(struct state *state, int msg Line 1122  static int dhcp6_no_relay(struct state *state, int msg
         log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);          log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
         if (ignore)          if (ignore)
           return 0;            return 0;
        *outmsgtypep = DHCP6REPLY;        outmsgtype = DHCP6REPLY;
         tagif = add_options(state, 1);          tagif = add_options(state, 1);
         break;          break;
       }        }
Line 1106  static int dhcp6_no_relay(struct state *state, int msg Line 1131  static int dhcp6_no_relay(struct state *state, int msg
     case DHCP6RELEASE:      case DHCP6RELEASE:
       {        {
         /* set reply message type */          /* set reply message type */
        *outmsgtypep = DHCP6REPLY;        outmsgtype = DHCP6REPLY;
   
         log6_quiet(state, "DHCPRELEASE", NULL, NULL);          log6_quiet(state, "DHCPRELEASE", NULL, NULL);
   
Line 1171  static int dhcp6_no_relay(struct state *state, int msg Line 1196  static int dhcp6_no_relay(struct state *state, int msg
     case DHCP6DECLINE:      case DHCP6DECLINE:
       {        {
         /* set reply message type */          /* set reply message type */
        *outmsgtypep = DHCP6REPLY;        outmsgtype = DHCP6REPLY;
                   
         log6_quiet(state, "DHCPDECLINE", NULL, NULL);          log6_quiet(state, "DHCPDECLINE", NULL, NULL);
   
Line 1251  static int dhcp6_no_relay(struct state *state, int msg Line 1276  static int dhcp6_no_relay(struct state *state, int msg
       }        }
   
     }      }
  
   log_tags(tagif, state->xid);    log_tags(tagif, state->xid);
   
    done:
     /* Fill in the message type. Note that we store the offset,
        not a direct pointer, since the packet memory may have been 
        reallocated. */
     ((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype;
   
   log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));    log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
       
   return 1;    return 1;
Line 1849  static void update_leases(struct state *state, struct  Line 1881  static void update_leases(struct state *state, struct 
 #ifdef HAVE_SCRIPT  #ifdef HAVE_SCRIPT
       if (daemon->lease_change_command)        if (daemon->lease_change_command)
         {          {
          void *class_opt;          void *opt;
           
           lease->flags |= LEASE_CHANGED;            lease->flags |= LEASE_CHANGED;
           free(lease->extradata);            free(lease->extradata);
           lease->extradata = NULL;            lease->extradata = NULL;
           lease->extradata_size = lease->extradata_len = 0;            lease->extradata_size = lease->extradata_len = 0;
           lease->vendorclass_count = 0;             lease->vendorclass_count = 0; 
                       
          if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))          if ((opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
             {              {
              void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));              void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
               lease->vendorclass_count++;                lease->vendorclass_count++;
               /* send enterprise number first  */                /* send enterprise number first  */
              sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));              sprintf(daemon->dhcp_buff2, "%u", opt6_uint(opt, 0, 4));
               lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);                lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
                               
              if (opt6_len(class_opt) >= 6)               if (opt6_len(opt) >= 6) 
                for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))                for (enc_opt = opt6_ptr(opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
                   {                    {
                     lease->vendorclass_count++;                      lease->vendorclass_count++;
                     lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);                      lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
Line 1875  static void update_leases(struct state *state, struct  Line 1908  static void update_leases(struct state *state, struct 
           lease_add_extradata(lease, (unsigned char *)state->client_hostname,             lease_add_extradata(lease, (unsigned char *)state->client_hostname, 
                               state->client_hostname ? strlen(state->client_hostname) : 0, 0);                                                          state->client_hostname ? strlen(state->client_hostname) : 0, 0);                          
                       
             /* DNSMASQ_REQUESTED_OPTIONS */
             if ((opt = opt6_find(state->packet_options, state->end, OPTION6_ORO, 2)))
               {
                 int i, len = opt6_len(opt)/2;
                 u16 *rop = opt6_ptr(opt, 0);
                 
                 for (i = 0; i < len; i++)
                   lease_add_extradata(lease, (unsigned char *)daemon->namebuff,
                                       sprintf(daemon->namebuff, "%u", ntohs(rop[i])), (i + 1) == len ? 0 : ',');
               }
             else
               lease_add_extradata(lease, NULL, 0, 0);
   
             if ((opt = opt6_find(state->packet_options, state->end, OPTION6_MUD_URL, 1)))
               lease_add_extradata(lease, opt6_ptr(opt, 0), opt6_len(opt), 0);
             else
               lease_add_extradata(lease, NULL, 0, 0);
   
           /* space-concat tag set */            /* space-concat tag set */
           if (!tagif && !context->netid.net)            if (!tagif && !context->netid.net)
             lease_add_extradata(lease, NULL, 0, 0);              lease_add_extradata(lease, NULL, 0, 0);
Line 1904  static void update_leases(struct state *state, struct  Line 1955  static void update_leases(struct state *state, struct 
                       
           lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);            lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
                       
          if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))          if ((opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
             {              {
              void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));              void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
              for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))              for (enc_opt = opt6_ptr(opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
                 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);                  lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
             }              }
         }          }
Line 2076  static unsigned int opt6_uint(unsigned char *opt, int  Line 2127  static unsigned int opt6_uint(unsigned char *opt, int 
   return ret;    return ret;
 }   } 
   
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, int relay_upstream6(int iface_index, ssize_t sz, 
                     struct in6_addr *peer_address, u32 scope_id, time_t now)                    struct in6_addr *peer_address, u32 scope_id, time_t now)
 {  {
   /* ->local is same value for all relays on ->current chain */  
     
   union all_addr from;  
   unsigned char *header;    unsigned char *header;
   unsigned char *inbuff = daemon->dhcp_packet.iov_base;    unsigned char *inbuff = daemon->dhcp_packet.iov_base;
   int msg_type = *inbuff;    int msg_type = *inbuff;
  int hopcount;  int hopcount, o;
   struct in6_addr multicast;    struct in6_addr multicast;
   unsigned int maclen, mactype;    unsigned int maclen, mactype;
   unsigned char mac[DHCP_CHADDR_MAX];    unsigned char mac[DHCP_CHADDR_MAX];
     struct dhcp_relay *relay;
     
     for (relay = daemon->relay6; relay; relay = relay->next)
       if (relay->iface_index != 0 && relay->iface_index == iface_index)
         break;
   
     /* No relay config. */
     if (!relay)
       return 0;
     
   inet_pton(AF_INET6, ALL_SERVERS, &multicast);    inet_pton(AF_INET6, ALL_SERVERS, &multicast);
   get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);    get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
  
  /* source address == relay address */ 
  from.addr6 = relay->local.addr6; 
     
   /* Get hop count from nested relayed message */     /* Get hop count from nested relayed message */ 
   if (msg_type == DHCP6RELAYFORW)    if (msg_type == DHCP6RELAYFORW)
     hopcount = *((unsigned char *)inbuff+1) + 1;      hopcount = *((unsigned char *)inbuff+1) + 1;
   else    else
     hopcount = 0;      hopcount = 0;
   
   /* RFC 3315 HOP_COUNT_LIMIT */  
   if (hopcount > 32)  
     return;  
   
   reset_counter();    reset_counter();
   
  if ((header = put_opt6(NULL, 34)))  /* RFC 3315 HOP_COUNT_LIMIT */
   if (hopcount > 32 || !(header = put_opt6(NULL, 34)))
     return 1;
   
   header[0] = DHCP6RELAYFORW;
   header[1] = hopcount;
   memcpy(&header[18], peer_address, IN6ADDRSZ);
   
   /* RFC-6939 */
   if (maclen != 0)
     {      {
      int o;      o = new_opt6(OPTION6_CLIENT_MAC);
      put_opt6_short(mactype);
      header[0] = DHCP6RELAYFORW;      put_opt6(mac, maclen);
      header[1] = hopcount; 
      memcpy(&header[2],  &relay->local.addr6, IN6ADDRSZ); 
      memcpy(&header[18], peer_address, IN6ADDRSZ); 
  
      /* RFC-6939 */ 
      if (maclen != 0) 
        { 
          o = new_opt6(OPTION6_CLIENT_MAC); 
          put_opt6_short(mactype); 
          put_opt6(mac, maclen); 
          end_opt6(o); 
        } 
       
      o = new_opt6(OPTION6_RELAY_MSG); 
      put_opt6(inbuff, sz); 
       end_opt6(o);        end_opt6(o);
          }
      for (; relay; relay = relay->current)  
        {  o = new_opt6(OPTION6_RELAY_MSG);
          union mysockaddr to;  put_opt6(inbuff, sz);
            end_opt6(o);
          to.sa.sa_family = AF_INET6;  
          to.in6.sin6_addr = relay->server.addr6;  for (; relay; relay = relay->next)
          to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);    if (relay->iface_index != 0 && relay->iface_index == iface_index)
          to.in6.sin6_flowinfo = 0;      {
          to.in6.sin6_scope_id = 0;        union mysockaddr to;
   
          if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))        memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
            {        
              int multicast_iface;        to.sa.sa_family = AF_INET6;
              if (!relay->interface || strchr(relay->interface, '*') ||        to.in6.sin6_addr = relay->server.addr6;
                  (multicast_iface = if_nametoindex(relay->interface)) == 0 ||        to.in6.sin6_port = htons(relay->port);
                  setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)        to.in6.sin6_flowinfo = 0;
                my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));        to.in6.sin6_scope_id = 0;
            }        
                        if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
          send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);          {
                      int multicast_iface;
          if (option_bool(OPT_LOG_OPTS))            if (!relay->interface || strchr(relay->interface, '*') ||
            {                (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
              inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);                setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
              inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);              {
              my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);                my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast DHCP relay via interface %s"), relay->interface);
            }                continue;
               }
           }
         
 #ifdef HAVE_DUMPFILE
         dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, &to, daemon->dhcp6fd);
 #endif
   
          /* Save this for replies */        while (retry_send(sendto(daemon->dhcp6fd, (void *)daemon->outpacket.iov_base, save_counter(-1),
          relay->iface_index = scope_id;                                 0, (struct sockaddr *)&to, sa_len(&to))));
        }        
    }        if (option_bool(OPT_LOG_OPTS))
           {
             inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
             if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
               snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface);
             else
               inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
             my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff);
           }
         
       }
   
   return 1;
 }  }
   
unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
 {  {
   struct dhcp_relay *relay;    struct dhcp_relay *relay;
   struct in6_addr link;    struct in6_addr link;
Line 2196  unsigned short relay_reply6(struct sockaddr_in6 *peer, Line 2258  unsigned short relay_reply6(struct sockaddr_in6 *peer,
             put_opt6(opt6_ptr(opt, 0), opt6_len(opt));              put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
             memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);               memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ); 
             peer->sin6_scope_id = relay->iface_index;              peer->sin6_scope_id = relay->iface_index;
            return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
             if (encap_type == DHCP6RELAYREPL)
               {
                 peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
                 return 1;
               }
 
             peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT);
             
 #ifdef HAVE_SCRIPT
             if (daemon->lease_change_command && encap_type == DHCP6REPLY)
               {
                 /* decapsulate relayed message */
                 opts = opt6_ptr(opt, 4);
                 end = opt6_ptr(opt, opt6_len(opt));
 
                 for (opt = opts; opt; opt = opt6_next(opt, end))
                   if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12) 
                     {
                       void *ia_opts = opt6_ptr(opt, 12);
                       void *ia_end = opt6_ptr(opt, opt6_len(opt));
                       void *ia_opt;
                       
                       for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end))
                         /* valid lifetime must not be zero. */
                         if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0)
                           {
                             if (daemon->free_snoops ||
                                 (daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
                               {
                                 struct snoop_record *snoop = daemon->free_snoops;
                                 
                                 daemon->free_snoops = snoop->next;
                                 snoop->client = peer->sin6_addr;
                                 snoop->prefix_len = opt6_uint(ia_opt, 8, 1); 
                                 memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ); 
                                 snoop->next = relay->snoop_records;
                                 relay->snoop_records = snoop;
                               }
                           }
                     }
               }
 #endif          
             return 1;
           }            }
         
     }      }
     
     return 0;
   }
   
   #ifdef HAVE_SCRIPT
   int do_snoop_script_run(void)
   {
     struct dhcp_relay *relay;
     struct snoop_record *snoop;
     
     for (relay = daemon->relay6; relay; relay = relay->next)
       if ((snoop = relay->snoop_records))
         {
           relay->snoop_records = snoop->next;
           snoop->next = daemon->free_snoops;
           daemon->free_snoops = snoop;
           
           queue_relay_snoop(&snoop->client, relay->iface_index, &snoop->prefix, snoop->prefix_len);
           return 1;
         }
     
   return 0;    return 0;
 }  }
   #endif
   
 #endif  #endif

Removed from v.1.1.1.4  
changed lines
  Added in v.1.1.1.5


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