Annotation of embedaddon/dnsmasq/src/rfc3315.c, revision 1.1

1.1     ! misho       1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
        !             2: 
        !             3:    This program is free software; you can redistribute it and/or modify
        !             4:    it under the terms of the GNU General Public License as published by
        !             5:    the Free Software Foundation; version 2 dated June, 1991, or
        !             6:    (at your option) version 3 dated 29 June, 2007.
        !             7:  
        !             8:    This program is distributed in the hope that it will be useful,
        !             9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            11:    GNU General Public License for more details.
        !            12:      
        !            13:    You should have received a copy of the GNU General Public License
        !            14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
        !            15: */
        !            16: 
        !            17: 
        !            18: #include "dnsmasq.h"
        !            19: 
        !            20: #ifdef HAVE_DHCP6
        !            21: 
        !            22: struct state {
        !            23:   unsigned char *clid;
        !            24:   int clid_len, iaid, ia_type, interface, hostname_auth;
        !            25:   char *client_hostname, *hostname, *domain, *send_domain;
        !            26:   struct dhcp_context *context;
        !            27:   struct in6_addr *link_address;
        !            28:   unsigned int xid, fqdn_flags;
        !            29:   char *iface_name;
        !            30:   void *packet_options, *end;
        !            31:   struct dhcp_netid *tags, *context_tags;
        !            32: #ifdef OPTION6_PREFIX_CLASS
        !            33:   struct prefix_class *send_prefix_class;
        !            34: #endif
        !            35: };
        !            36: 
        !            37: static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context, 
        !            38:                             int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
        !            39: static int dhcp6_no_relay(int msg_type,  struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context, 
        !            40:                          int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
        !            41: static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
        !            42: static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
        !            43: 
        !            44: static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
        !            45: static void *opt6_next(void *opts, void *end);
        !            46: static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
        !            47: static void get_context_tag(struct state *state, struct dhcp_context *context);
        !            48: static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
        !            49: static int build_ia(struct state *state, int *t1cntr);
        !            50: static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
        !            51: #ifdef OPTION6_PREFIX_CLASS
        !            52: static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);
        !            53: #endif
        !            54: static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr);
        !            55: static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
        !            56: static int check_address(struct state *state, struct in6_addr *addr);
        !            57: static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time, 
        !            58:                        unsigned int *min_time, struct in6_addr *addr, int update_lease, time_t now);
        !            59: static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
        !            60: static int add_local_addrs(struct dhcp_context *context);
        !            61: struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context);
        !            62: static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep, 
        !            63:                            unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time);
        !            64: 
        !            65: #define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
        !            66: #define opt6_type(opt) (opt6_uint(opt, -4, 2))
        !            67: #define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
        !            68: 
        !            69: 
        !            70: unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
        !            71:                           struct in6_addr *fallback, size_t sz, int is_unicast, time_t now)
        !            72: {
        !            73:   struct dhcp_netid *relay_tags = NULL;
        !            74:   struct dhcp_vendor *vendor;
        !            75:   int msg_type;
        !            76:   
        !            77:   if (sz <= 4)
        !            78:     return 0;
        !            79:   
        !            80:   msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
        !            81:   
        !            82:   /* Mark these so we only match each at most once, to avoid tangled linked lists */
        !            83:   for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
        !            84:     vendor->netid.next = &vendor->netid;
        !            85:   
        !            86:   save_counter(0);
        !            87:   
        !            88:   if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, fallback, daemon->dhcp_packet.iov_base, sz, is_unicast, now))
        !            89:     return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
        !            90: 
        !            91:   return 0;
        !            92: }
        !            93: 
        !            94: /* This cost me blood to write, it will probably cost you blood to understand - srk. */
        !            95: static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
        !            96:                             int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now)
        !            97: {
        !            98:   void *end = inbuff + sz;
        !            99:   void *opts = inbuff + 34;
        !           100:   int msg_type = *((unsigned char *)inbuff);
        !           101:   unsigned char *outmsgtypep;
        !           102:   void *opt;
        !           103:   struct dhcp_vendor *vendor;
        !           104: 
        !           105:   /* if not an encaplsulated relayed message, just do the stuff */
        !           106:   if (msg_type != DHCP6RELAYFORW)
        !           107:     {
        !           108:       /* if link_address != NULL if points to the link address field of the 
        !           109:         innermost nested RELAYFORW message, which is where we find the
        !           110:         address of the network on which we can allocate an address.
        !           111:         Recalculate the available contexts using that information. */
        !           112:       
        !           113:       if (link_address)
        !           114:        {
        !           115:          struct dhcp_context *c;
        !           116:          context = NULL;
        !           117:           
        !           118:          if (!IN6_IS_ADDR_LOOPBACK(link_address) &&
        !           119:              !IN6_IS_ADDR_LINKLOCAL(link_address) &&
        !           120:              !IN6_IS_ADDR_MULTICAST(link_address))
        !           121:            for (c = daemon->dhcp6; c; c = c->next)
        !           122:              if ((c->flags & CONTEXT_DHCP) &&
        !           123:                  !(c->flags & CONTEXT_TEMPLATE) &&
        !           124:                  is_same_net6(link_address, &c->start6, c->prefix) &&
        !           125:                  is_same_net6(link_address, &c->end6, c->prefix))
        !           126:                {
        !           127:                  c->preferred = c->valid = 0xffffffff;
        !           128:                  c->current = context;
        !           129:                  context = c;
        !           130:                }
        !           131:          
        !           132:          if (!context)
        !           133:            {
        !           134:              inet_ntop(AF_INET6, link_address, daemon->addrbuff, ADDRSTRLEN); 
        !           135:              my_syslog(MS_DHCP | LOG_WARNING, 
        !           136:                        _("no address range available for DHCPv6 request from relay at %s"),
        !           137:                        daemon->addrbuff);
        !           138:              return 0;
        !           139:            }
        !           140:        }
        !           141: 
        !           142:       if (!context)
        !           143:        {
        !           144:          my_syslog(MS_DHCP | LOG_WARNING, 
        !           145:                    _("no address range available for DHCPv6 request via %s"), iface_name);
        !           146:          return 0;
        !           147:        }
        !           148: 
        !           149:       return dhcp6_no_relay(msg_type, link_address, *relay_tagsp, context, interface, iface_name, fallback, inbuff, sz, is_unicast, now);
        !           150:     }
        !           151: 
        !           152:   /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
        !           153:      which is               1   +    1   +    16      +     16     + 2 + 2 = 38 */
        !           154:   if (sz < 38)
        !           155:     return 0;
        !           156:   
        !           157:   /* copy header stuff into reply message and set type to reply */
        !           158:   outmsgtypep = put_opt6(inbuff, 34);
        !           159:   *outmsgtypep = DHCP6RELAYREPL;
        !           160: 
        !           161:   /* look for relay options and set tags if found. */
        !           162:   for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
        !           163:     {
        !           164:       int mopt;
        !           165:       
        !           166:       if (vendor->match_type == MATCH_SUBSCRIBER)
        !           167:        mopt = OPTION6_SUBSCRIBER_ID;
        !           168:       else if (vendor->match_type == MATCH_REMOTE)
        !           169:        mopt = OPTION6_REMOTE_ID; 
        !           170:       else
        !           171:        continue;
        !           172: 
        !           173:       if ((opt = opt6_find(opts, end, mopt, 1)) &&
        !           174:          vendor->len == opt6_len(opt) &&
        !           175:          memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 &&
        !           176:          vendor->netid.next != &vendor->netid)
        !           177:        {
        !           178:          vendor->netid.next = *relay_tagsp;
        !           179:          *relay_tagsp = &vendor->netid;
        !           180:          break;
        !           181:        }
        !           182:     }
        !           183:   
        !           184:   for (opt = opts; opt; opt = opt6_next(opt, end))
        !           185:     {
        !           186:       int o = new_opt6(opt6_type(opt));
        !           187:       if (opt6_type(opt) == OPTION6_RELAY_MSG)
        !           188:        {
        !           189:          struct in6_addr link_address;
        !           190:          /* the packet data is unaligned, copy to aligned storage */
        !           191:          memcpy(&link_address, inbuff + 2, IN6ADDRSZ); 
        !           192:          /* Not, zero is_unicast since that is now known to refer to the 
        !           193:             relayed packet, not the original sent by the client */
        !           194:          if (!dhcp6_maybe_relay(&link_address, relay_tagsp, context, interface, iface_name, fallback, opt6_ptr(opt, 0), opt6_len(opt), 0, now))
        !           195:            return 0;
        !           196:        }
        !           197:       else
        !           198:        put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
        !           199:       end_opt6(o);         
        !           200:     }
        !           201:   
        !           202:   return 1;
        !           203: }
        !           204: 
        !           205: static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context, 
        !           206:                          int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now)
        !           207: {
        !           208:   void *opt;
        !           209:   int i, o, o1, start_opts;
        !           210:   struct dhcp_opt *opt_cfg;
        !           211:   struct dhcp_netid *tagif;
        !           212:   struct dhcp_config *config = NULL;
        !           213:   struct dhcp_netid known_id, iface_id, v6_id;
        !           214:   unsigned char *outmsgtypep;
        !           215:   struct dhcp_vendor *vendor;
        !           216:   struct dhcp_context *context_tmp;
        !           217:   unsigned int ignore = 0;
        !           218:   struct state state;
        !           219: #ifdef OPTION6_PREFIX_CLASS
        !           220:   struct prefix_class *p;
        !           221:   int dump_all_prefix_classes = 0;
        !           222: #endif
        !           223: 
        !           224:   state.packet_options = inbuff + 4;
        !           225:   state.end = inbuff + sz;
        !           226:   state.clid = NULL;
        !           227:   state.clid_len = 0;
        !           228:   state.context_tags = NULL;
        !           229:   state.tags = tags;
        !           230:   state.link_address = link_address;
        !           231:   state.interface = interface;
        !           232:   state.domain = NULL;
        !           233:   state.send_domain = NULL;
        !           234:   state.context = context;
        !           235:   state.hostname_auth = 0;
        !           236:   state.hostname = NULL;
        !           237:   state.client_hostname = NULL;
        !           238:   state.iface_name = iface_name;
        !           239:   state.fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */
        !           240: #ifdef OPTION6_PREFIX_CLASS
        !           241:   state.send_prefix_class = NULL;
        !           242: #endif
        !           243: 
        !           244:   /* set tag with name == interface */
        !           245:   iface_id.net = iface_name;
        !           246:   iface_id.next = state.tags;
        !           247:   state.tags = &iface_id; 
        !           248: 
        !           249:   /* set tag "dhcpv6" */
        !           250:   v6_id.net = "dhcpv6";
        !           251:   v6_id.next = state.tags;
        !           252:   state.tags = &v6_id;
        !           253: 
        !           254:   /* copy over transaction-id, and save pointer to message type */
        !           255:   outmsgtypep = put_opt6(inbuff, 4);
        !           256:   start_opts = save_counter(-1);
        !           257:   state.xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
        !           258:    
        !           259:   /* We're going to be linking tags from all context we use. 
        !           260:      mark them as unused so we don't link one twice and break the list */
        !           261:   for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
        !           262:     {
        !           263:       context->netid.next = &context->netid;
        !           264: 
        !           265:       if (option_bool(OPT_LOG_OPTS))
        !           266:        {
        !           267:           inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN); 
        !           268:           inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN); 
        !           269:           if (context_tmp->flags & (CONTEXT_STATIC))
        !           270:             my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
        !           271:                       state.xid, daemon->dhcp_buff, context_tmp->prefix);
        !           272:           else
        !           273:             my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"), 
        !           274:                       state.xid, daemon->dhcp_buff, daemon->dhcp_buff2);
        !           275:        }
        !           276:     }
        !           277: 
        !           278:   if ((opt = opt6_find(state.packet_options, state.end, OPTION6_CLIENT_ID, 1)))
        !           279:     {
        !           280:       state.clid = opt6_ptr(opt, 0);
        !           281:       state.clid_len = opt6_len(opt);
        !           282:       o = new_opt6(OPTION6_CLIENT_ID);
        !           283:       put_opt6(state.clid, state.clid_len);
        !           284:       end_opt6(o);
        !           285:     }
        !           286:   else if (msg_type != DHCP6IREQ)
        !           287:     return 0;
        !           288: 
        !           289:   /* server-id must match except for SOLICIT and CONFIRM messages */
        !           290:   if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ &&
        !           291:       (!(opt = opt6_find(state.packet_options, state.end, OPTION6_SERVER_ID, 1)) ||
        !           292:        opt6_len(opt) != daemon->duid_len ||
        !           293:        memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
        !           294:     return 0;
        !           295:   
        !           296:   o = new_opt6(OPTION6_SERVER_ID);
        !           297:   put_opt6(daemon->duid, daemon->duid_len);
        !           298:   end_opt6(o);
        !           299: 
        !           300:   if (is_unicast &&
        !           301:       (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
        !           302:     
        !           303:     {  
        !           304:       o1 = new_opt6(OPTION6_STATUS_CODE);
        !           305:       put_opt6_short(DHCP6USEMULTI);
        !           306:       put_opt6_string("Use multicast");
        !           307:       end_opt6(o1);
        !           308:       return 1;
        !           309:     }
        !           310: 
        !           311:   /* match vendor and user class options */
        !           312:   for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
        !           313:     {
        !           314:       int mopt;
        !           315:       
        !           316:       if (vendor->match_type == MATCH_VENDOR)
        !           317:        mopt = OPTION6_VENDOR_CLASS;
        !           318:       else if (vendor->match_type == MATCH_USER)
        !           319:        mopt = OPTION6_USER_CLASS; 
        !           320:       else
        !           321:        continue;
        !           322: 
        !           323:       if ((opt = opt6_find(state.packet_options, state.end, mopt, 2)))
        !           324:        {
        !           325:          void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
        !           326:          int offset = 0;
        !           327:          
        !           328:          if (mopt == OPTION6_VENDOR_CLASS)
        !           329:            {
        !           330:              if (opt6_len(opt) < 4)
        !           331:                continue;
        !           332:              
        !           333:              if (vendor->enterprise != opt6_uint(opt, 0, 4))
        !           334:                continue;
        !           335:            
        !           336:              offset = 4;
        !           337:            }
        !           338:  
        !           339:          for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
        !           340:            for (i = 0; i <= (opt6_len(enc_opt) - vendor->len); i++)
        !           341:              if (memcmp(vendor->data, opt6_ptr(enc_opt, i), vendor->len) == 0)
        !           342:                {
        !           343:                  vendor->netid.next = state.tags;
        !           344:                  state.tags = &vendor->netid;
        !           345:                  break;
        !           346:                }
        !           347:        }
        !           348:     }
        !           349: 
        !           350:   if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state.packet_options, state.end, OPTION6_VENDOR_CLASS, 4)))
        !           351:     my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state.xid, opt6_uint(opt, 0, 4));
        !           352:   
        !           353:   /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
        !           354:      Otherwise assume the option is an array, and look for a matching element. 
        !           355:      If no data given, existance of the option is enough. This code handles 
        !           356:      V-I opts too. */
        !           357:   for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
        !           358:     {
        !           359:       int match = 0;
        !           360:       
        !           361:       if (opt_cfg->flags & DHOPT_RFC3925)
        !           362:        {
        !           363:          for (opt = opt6_find(state.packet_options, state.end, OPTION6_VENDOR_OPTS, 4);
        !           364:               opt;
        !           365:               opt = opt6_find(opt6_next(opt, state.end), state.end, OPTION6_VENDOR_OPTS, 4))
        !           366:            {
        !           367:              void *vopt;
        !           368:              void *vend = opt6_ptr(opt, opt6_len(opt));
        !           369:              
        !           370:              for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
        !           371:                   vopt;
        !           372:                   vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
        !           373:                if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
        !           374:                  break;
        !           375:            }
        !           376:          if (match)
        !           377:            break;
        !           378:        }
        !           379:       else
        !           380:        {
        !           381:          if (!(opt = opt6_find(state.packet_options, state.end, opt_cfg->opt, 1)))
        !           382:            continue;
        !           383:          
        !           384:          match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
        !           385:        } 
        !           386:   
        !           387:       if (match)
        !           388:        {
        !           389:          opt_cfg->netid->next = state.tags;
        !           390:          state.tags = opt_cfg->netid;
        !           391:        }
        !           392:     }
        !           393:   
        !           394:   if ((opt = opt6_find(state.packet_options, state.end, OPTION6_FQDN, 1)))
        !           395:     {
        !           396:       /* RFC4704 refers */
        !           397:        int len = opt6_len(opt) - 1;
        !           398:        
        !           399:        state.fqdn_flags = opt6_uint(opt, 0, 1);
        !           400:        
        !           401:        /* Always force update, since the client has no way to do it itself. */
        !           402:        if (!option_bool(OPT_FQDN_UPDATE) && !(state.fqdn_flags & 0x01))
        !           403:         state.fqdn_flags |= 0x03;
        !           404:  
        !           405:        state.fqdn_flags &= ~0x04;
        !           406: 
        !           407:        if (len != 0 && len < 255)
        !           408:         {
        !           409:           unsigned char *pp, *op = opt6_ptr(opt, 1);
        !           410:           char *pq = daemon->dhcp_buff;
        !           411:           
        !           412:           pp = op;
        !           413:           while (*op != 0 && ((op + (*op)) - pp) < len)
        !           414:             {
        !           415:               memcpy(pq, op+1, *op);
        !           416:               pq += *op;
        !           417:               op += (*op)+1;
        !           418:               *(pq++) = '.';
        !           419:             }
        !           420:           
        !           421:           if (pq != daemon->dhcp_buff)
        !           422:             pq--;
        !           423:           *pq = 0;
        !           424:           
        !           425:           if (legal_hostname(daemon->dhcp_buff))
        !           426:             {
        !           427:               state.client_hostname = daemon->dhcp_buff;
        !           428:               if (option_bool(OPT_LOG_OPTS))
        !           429:                 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state.xid, state.client_hostname); 
        !           430:             }
        !           431:         }
        !           432:     }   
        !           433:   
        !           434:   if (state.clid)
        !           435:     {
        !           436:       config = find_config6(daemon->dhcp_conf, context, state.clid, state.clid_len, NULL);
        !           437:       
        !           438:       if (have_config(config, CONFIG_NAME))
        !           439:        {
        !           440:          state.hostname = config->hostname;
        !           441:          state.domain = config->domain;
        !           442:          state.hostname_auth = 1;
        !           443:        }
        !           444:       else if (state.client_hostname)
        !           445:        {
        !           446:          state.domain = strip_hostname(state.client_hostname);
        !           447:          
        !           448:          if (strlen(state.client_hostname) != 0)
        !           449:            {
        !           450:              state.hostname = state.client_hostname;
        !           451:              if (!config)
        !           452:                {
        !           453:                  /* Search again now we have a hostname. 
        !           454:                     Only accept configs without CLID here, (it won't match)
        !           455:                     to avoid impersonation by name. */
        !           456:                  struct dhcp_config *new = find_config6(daemon->dhcp_conf, context, NULL, 0, state.hostname);
        !           457:                  if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
        !           458:                    config = new;
        !           459:                }
        !           460:            }
        !           461:        }
        !           462:     }
        !           463: 
        !           464:   if (config)
        !           465:     {
        !           466:       struct dhcp_netid_list *list;
        !           467:       
        !           468:       for (list = config->netid; list; list = list->next)
        !           469:         {
        !           470:           list->list->next = state.tags;
        !           471:           state.tags = list->list;
        !           472:         }
        !           473: 
        !           474:       /* set "known" tag for known hosts */
        !           475:       known_id.net = "known";
        !           476:       known_id.next = state.tags;
        !           477:       state.tags = &known_id;
        !           478: 
        !           479:       if (have_config(config, CONFIG_DISABLE))
        !           480:        ignore = 1;
        !           481:     }
        !           482: 
        !           483: #ifdef OPTION6_PREFIX_CLASS
        !           484:   /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
        !           485:   if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
        !           486:     {
        !           487:       void *oro;
        !           488:       
        !           489:       if ((oro = opt6_find(state.packet_options, state.end, OPTION6_ORO, 0)))
        !           490:        for (i = 0; i <  opt6_len(oro) - 1; i += 2)
        !           491:          if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
        !           492:            {
        !           493:              dump_all_prefix_classes = 1;
        !           494:              break;
        !           495:            }
        !           496:       
        !           497:       if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
        !           498:        /* Add the tags associated with prefix classes so we can use the DHCP ranges.
        !           499:           Not done for SOLICIT as we add them  one-at-time. */
        !           500:        for (p = daemon->prefix_classes; p ; p = p->next)
        !           501:          {
        !           502:            p->tag.next = state.tags;
        !           503:            state.tags = &p->tag;
        !           504:          }
        !           505:     }    
        !           506: #endif
        !           507: 
        !           508:   tagif = run_tag_if(state.tags);
        !           509:   
        !           510:   /* if all the netids in the ignore list are present, ignore this client */
        !           511:   if (daemon->dhcp_ignore)
        !           512:     {
        !           513:       struct dhcp_netid_list *id_list;
        !           514:      
        !           515:       for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
        !           516:        if (match_netid(id_list->list, tagif, 0))
        !           517:          ignore = 1;
        !           518:     }
        !           519:   
        !           520:   /* if all the netids in the ignore_name list are present, ignore client-supplied name */
        !           521:   if (!state.hostname_auth)
        !           522:     {
        !           523:        struct dhcp_netid_list *id_list;
        !           524:        
        !           525:        for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
        !           526:         if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
        !           527:           break;
        !           528:        if (id_list)
        !           529:         state.hostname = NULL;
        !           530:     }
        !           531:   
        !           532: 
        !           533:   switch (msg_type)
        !           534:     {
        !           535:     default:
        !           536:       return 0;
        !           537: 
        !           538: 
        !           539:     case DHCP6SOLICIT:
        !           540:       {
        !           541:        void *rapid_commit = opt6_find(state.packet_options, state.end, OPTION6_RAPID_COMMIT, 0);
        !           542:        int address_assigned = 0;
        !           543:        /* tags without all prefix-class tags */
        !           544:        struct dhcp_netid *solicit_tags = tagif;
        !           545:        struct dhcp_context *c;
        !           546: 
        !           547:        if (rapid_commit)
        !           548:          {
        !           549:            o = new_opt6(OPTION6_RAPID_COMMIT);
        !           550:            end_opt6(o);
        !           551:          }
        !           552: 
        !           553:        /* set reply message type */
        !           554:        *outmsgtypep = rapid_commit ? DHCP6REPLY : DHCP6ADVERTISE;
        !           555: 
        !           556:        log6_packet(&state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
        !           557:        
        !           558:        if (ignore)
        !           559:          return 0;
        !           560:        
        !           561:        /* reset USED bits in leases */
        !           562:        lease6_reset();
        !           563: 
        !           564:        /* Can use configured address max once per prefix */
        !           565:        for (c = context; c; c = c->current)
        !           566:          c->flags &= ~CONTEXT_CONF_USED;
        !           567: 
        !           568:        for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
        !           569:          {   
        !           570:            void *ia_option, *ia_end;
        !           571:            unsigned int min_time = 0xffffffff;
        !           572:            int t1cntr;
        !           573:            int ia_counter;
        !           574:            /* set unless we're sending a particular prefix-class, when we
        !           575:               want only dhcp-ranges with the correct tags set and not those without any tags. */
        !           576:            int plain_range = 1;
        !           577:            u32 lease_time, requested_time;
        !           578:            struct dhcp_lease *ltmp;
        !           579:            struct in6_addr *req_addr;
        !           580:            struct in6_addr addr;
        !           581: 
        !           582:            if (!check_ia(&state, opt, &ia_end, &ia_option))
        !           583:              continue;
        !           584:            
        !           585:            /* reset USED bits in contexts - one address per prefix per IAID */
        !           586:            for (c = context; c; c = c->current)
        !           587:              c->flags &= ~CONTEXT_USED;
        !           588: 
        !           589: #ifdef OPTION6_PREFIX_CLASS
        !           590:            if (daemon->prefix_classes && state.ia_type == OPTION6_IA_NA)
        !           591:              {
        !           592:                void *prefix_opt;
        !           593:                int prefix_class;
        !           594:                
        !           595:                if (dump_all_prefix_classes)
        !           596:                  /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
        !           597:                  plain_range = 0;
        !           598:                else 
        !           599:                  { 
        !           600:                    if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
        !           601:                      {
        !           602:                        
        !           603:                        prefix_class = opt6_uint(prefix_opt, 0, 2);
        !           604:                        
        !           605:                        for (p = daemon->prefix_classes; p ; p = p->next)
        !           606:                          if (p->class == prefix_class)
        !           607:                            break;
        !           608:                        
        !           609:                        if (!p)
        !           610:                          my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
        !           611:                        else
        !           612:                          {
        !           613:                            /* add tag to list, and exclude undecorated dhcp-ranges */
        !           614:                            p->tag.next = state.tags;
        !           615:                            solicit_tags = run_tag_if(&p->tag);
        !           616:                            plain_range = 0;
        !           617:                            state.send_prefix_class = p;
        !           618:                          }
        !           619:                      }
        !           620:                    else
        !           621:                      {
        !           622:                        /* client didn't ask for a prefix class, lets see if we can find one. */
        !           623:                        for (p = daemon->prefix_classes; p ; p = p->next)
        !           624:                          {
        !           625:                            p->tag.next = NULL;
        !           626:                            if (match_netid(&p->tag, solicit_tags, 1))
        !           627:                              break;
        !           628:                          }
        !           629:                        
        !           630:                        if (p)
        !           631:                          {
        !           632:                            plain_range = 0;
        !           633:                            state.send_prefix_class = p;
        !           634:                          }
        !           635:                      }
        !           636: 
        !           637:                    if (p && option_bool(OPT_LOG_OPTS))
        !           638:                      my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state.xid, p->class, p->tag.net); 
        !           639:                  }
        !           640:              }
        !           641: #endif
        !           642: 
        !           643:            o = build_ia(&state, &t1cntr);
        !           644: 
        !           645:            for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
        !           646:              {
        !           647:                req_addr = opt6_ptr(ia_option, 0);
        !           648:                requested_time = opt6_uint(ia_option, 16, 4);
        !           649:                
        !           650:                if ((c = address6_valid(context, req_addr, solicit_tags, plain_range)))
        !           651:                  {
        !           652:                    lease_time = c->lease_time;
        !           653:                    /* If the client asks for an address on the same network as a configured address, 
        !           654:                       offer the configured address instead, to make moving to newly-configured
        !           655:                       addresses automatic. */
        !           656:                    if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(&state, &addr))
        !           657:                      {
        !           658:                        req_addr = &addr;
        !           659:                        mark_config_used(c, &addr);
        !           660:                        if (have_config(config, CONFIG_TIME))
        !           661:                          lease_time = config->lease_time;
        !           662:                      }
        !           663:                    else if (!(c = address6_available(context, req_addr, solicit_tags, plain_range)))
        !           664:                      continue; /* not an address we're allowed */
        !           665:                    else if (!check_address(&state, req_addr))
        !           666:                      continue; /* address leased elsewhere */
        !           667:                    
        !           668:                    /* add address to output packet */
        !           669: #ifdef OPTION6_PREFIX_CLASS
        !           670:                    if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
        !           671:                      state.send_prefix_class = prefix_class_from_context(c);
        !           672: #endif             
        !           673:                    add_address(&state, c, lease_time, requested_time, &min_time, req_addr, rapid_commit != NULL, now);
        !           674:                    mark_context_used(&state, context, req_addr);
        !           675:                    get_context_tag(&state, c);
        !           676:                    address_assigned = 1;
        !           677:                  }
        !           678:              }
        !           679:            
        !           680:            /* Suggest configured address(es) */
        !           681:            for (c = context; c; c = c->current) 
        !           682:              if (!(c->flags & CONTEXT_CONF_USED) &&
        !           683:                  match_netid(c->filter, solicit_tags, plain_range) &&
        !           684:                  config_valid(config, c, &addr) && 
        !           685:                  check_address(&state, &addr))
        !           686:                {
        !           687:                  mark_config_used(context, &addr);
        !           688:                  if (have_config(config, CONFIG_TIME))
        !           689:                    lease_time = config->lease_time;
        !           690:                  else
        !           691:                    lease_time = c->lease_time;
        !           692:                  /* add address to output packet */
        !           693: #ifdef OPTION6_PREFIX_CLASS
        !           694:                  if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
        !           695:                    state.send_prefix_class = prefix_class_from_context(c);
        !           696: #endif
        !           697:                  add_address(&state, c, lease_time, lease_time, &min_time, &addr, rapid_commit != NULL, now);
        !           698:                  mark_context_used(&state, context, &addr);
        !           699:                  get_context_tag(&state, c);
        !           700:                  address_assigned = 1;
        !           701:                }
        !           702:            
        !           703:            /* return addresses for existing leases */
        !           704:            ltmp = NULL;
        !           705:            while ((ltmp = lease6_find_by_client(ltmp, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.clid, state.clid_len, state.iaid)))
        !           706:              {
        !           707:                req_addr = (struct in6_addr *)ltmp->hwaddr;
        !           708:                if ((c = address6_available(context, req_addr, solicit_tags, plain_range)))
        !           709:                  {
        !           710: #ifdef OPTION6_PREFIX_CLASS
        !           711:                    if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
        !           712:                      state.send_prefix_class = prefix_class_from_context(c);
        !           713: #endif
        !           714:                    add_address(&state, c, c->lease_time, c->lease_time, &min_time, req_addr, rapid_commit != NULL, now);
        !           715:                    mark_context_used(&state, context, req_addr);
        !           716:                    get_context_tag(&state, c);
        !           717:                    address_assigned = 1;
        !           718:                  }
        !           719:              }
        !           720:                           
        !           721:            /* Return addresses for all valid contexts which don't yet have one */
        !           722:            while ((c = address6_allocate(context, state.clid, state.clid_len, state.iaid, ia_counter, solicit_tags, plain_range, &addr)))
        !           723:              {
        !           724: #ifdef OPTION6_PREFIX_CLASS
        !           725:                if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
        !           726:                  state.send_prefix_class = prefix_class_from_context(c);
        !           727: #endif
        !           728:                add_address(&state, c, c->lease_time, c->lease_time, &min_time, &addr, rapid_commit != NULL, now);
        !           729:                mark_context_used(&state, context, &addr);
        !           730:                get_context_tag(&state, c);
        !           731:                address_assigned = 1;
        !           732:              }
        !           733:            
        !           734:            end_ia(t1cntr, min_time, 0);
        !           735:            end_opt6(o);        
        !           736:          }
        !           737: 
        !           738:        if (address_assigned) 
        !           739:          {
        !           740:            o1 = new_opt6(OPTION6_STATUS_CODE);
        !           741:            put_opt6_short(DHCP6SUCCESS);
        !           742:            put_opt6_string(_("success"));
        !           743:            end_opt6(o1);
        !           744:            
        !           745:            /* If --dhcp-authoritative is set, we can tell client not to wait for
        !           746:               other possible servers */
        !           747:            o = new_opt6(OPTION6_PREFERENCE);
        !           748:            put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
        !           749:            end_opt6(o);
        !           750:            tagif = add_options(&state, fallback, context);
        !           751:          }
        !           752:        else
        !           753:          { 
        !           754:            /* no address, return error */
        !           755:            o1 = new_opt6(OPTION6_STATUS_CODE);
        !           756:            put_opt6_short(DHCP6NOADDRS);
        !           757:            put_opt6_string(_("no addresses available"));
        !           758:            end_opt6(o1);
        !           759:            log6_packet(&state, "DHCPADVERTISE", NULL, _("no addresses available"));
        !           760:          }
        !           761: 
        !           762:        break;
        !           763:       }
        !           764:       
        !           765:     case DHCP6REQUEST:
        !           766:       {
        !           767:        int address_assigned = 0;
        !           768:        
        !           769:        /* set reply message type */
        !           770:        *outmsgtypep = DHCP6REPLY;
        !           771: 
        !           772:        log6_packet(&state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
        !           773:        
        !           774:        if (ignore)
        !           775:          return 0;
        !           776:        
        !           777:        for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
        !           778:          {   
        !           779:            void *ia_option, *ia_end;
        !           780:            unsigned int min_time = 0xffffffff;
        !           781:            int t1cntr;
        !           782:            
        !           783:             if (!check_ia(&state, opt, &ia_end, &ia_option))
        !           784:               continue;
        !           785:            
        !           786:            o = build_ia(&state, &t1cntr);
        !           787:              
        !           788:            for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
        !           789:              {
        !           790:                struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
        !           791:                u32 requested_time = opt6_uint(ia_option, 16, 4);
        !           792:                struct dhcp_context *dynamic, *c;
        !           793:                unsigned int lease_time;
        !           794:                struct in6_addr addr;
        !           795:                int config_ok = 0;
        !           796:                
        !           797:                if ((c = address6_valid(context, req_addr, tagif, 1)))
        !           798:                  config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
        !           799:                
        !           800:                if ((dynamic = address6_available(context, req_addr, tagif, 1)) || c)
        !           801:                  {
        !           802:                    if (!dynamic && !config_ok)
        !           803:                      {
        !           804:                        /* Static range, not configured. */
        !           805:                        o1 = new_opt6(OPTION6_STATUS_CODE);
        !           806:                        put_opt6_short(DHCP6UNSPEC);
        !           807:                        put_opt6_string(_("address unavailable"));
        !           808:                        end_opt6(o1);
        !           809:                      }
        !           810:                    else if (!check_address(&state, req_addr))
        !           811:                      {
        !           812:                        /* Address leased to another DUID/IAID */
        !           813:                        o1 = new_opt6(OPTION6_STATUS_CODE);
        !           814:                        put_opt6_short(DHCP6UNSPEC);
        !           815:                        put_opt6_string(_("address in use"));
        !           816:                        end_opt6(o1);
        !           817:                      } 
        !           818:                    else 
        !           819:                      {
        !           820:                        if (!dynamic)
        !           821:                          dynamic = c;
        !           822: 
        !           823:                        lease_time = dynamic->lease_time;
        !           824:                        
        !           825:                        if (config_ok && have_config(config, CONFIG_TIME))
        !           826:                          lease_time = config->lease_time;
        !           827: 
        !           828: #ifdef OPTION6_PREFIX_CLASS
        !           829:                        if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
        !           830:                          state.send_prefix_class = prefix_class_from_context(c);
        !           831: #endif
        !           832:                        add_address(&state, dynamic, lease_time, requested_time, &min_time, req_addr, 1, now);
        !           833:                        get_context_tag(&state, dynamic);
        !           834:                        address_assigned = 1;
        !           835:                      }
        !           836:                  }
        !           837:                else 
        !           838:                  {
        !           839:                    /* requested address not on the correct link */
        !           840:                    o1 = new_opt6(OPTION6_STATUS_CODE);
        !           841:                    put_opt6_short(DHCP6NOTONLINK);
        !           842:                    put_opt6_string(_("not on link"));
        !           843:                    end_opt6(o1);
        !           844:                  }
        !           845:              }
        !           846:         
        !           847:            end_ia(t1cntr, min_time, 0);
        !           848:            end_opt6(o);        
        !           849:          }
        !           850: 
        !           851:        if (address_assigned) 
        !           852:          {
        !           853:            o1 = new_opt6(OPTION6_STATUS_CODE);
        !           854:            put_opt6_short(DHCP6SUCCESS);
        !           855:            put_opt6_string(_("success"));
        !           856:            end_opt6(o1);
        !           857:          }
        !           858:        else
        !           859:          { 
        !           860:            /* no address, return error */
        !           861:            o1 = new_opt6(OPTION6_STATUS_CODE);
        !           862:            put_opt6_short(DHCP6NOADDRS);
        !           863:            put_opt6_string(_("no addresses available"));
        !           864:            end_opt6(o1);
        !           865:            log6_packet(&state, "DHCPREPLY", NULL, _("no addresses available"));
        !           866:          }
        !           867: 
        !           868:        tagif = add_options(&state, fallback, context);
        !           869:        break;
        !           870:       }
        !           871:       
        !           872:   
        !           873:     case DHCP6RENEW:
        !           874:       {
        !           875:        /* set reply message type */
        !           876:        *outmsgtypep = DHCP6REPLY;
        !           877:        
        !           878:        log6_packet(&state, "DHCPRENEW", NULL, NULL);
        !           879: 
        !           880:        for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
        !           881:          {
        !           882:            void *ia_option, *ia_end;
        !           883:            unsigned int min_time = 0xffffffff;
        !           884:            int t1cntr, iacntr;
        !           885:            
        !           886:            if (!check_ia(&state, opt, &ia_end, &ia_option))
        !           887:              continue;
        !           888:            
        !           889:            o = build_ia(&state, &t1cntr);
        !           890:            iacntr = save_counter(-1); 
        !           891:            
        !           892:            for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
        !           893:              {
        !           894:                struct dhcp_lease *lease = NULL;
        !           895:                struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
        !           896:                u32 requested_time = opt6_uint(ia_option, 16, 4);
        !           897:                unsigned int preferred_time = 0; /* in case renewal inappropriate */
        !           898:                unsigned int valid_time = 0;
        !           899:                char *message = NULL;
        !           900:                struct dhcp_context *this_context;
        !           901:                
        !           902:                if (!(lease = lease6_find(state.clid, state.clid_len,
        !           903:                                          state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, 
        !           904:                                          state.iaid, req_addr)))
        !           905:                  {
        !           906:                    /* If the server cannot find a client entry for the IA the server
        !           907:                       returns the IA containing no addresses with a Status Code option set
        !           908:                       to NoBinding in the Reply message. */
        !           909:                    save_counter(iacntr);
        !           910:                    t1cntr = 0;
        !           911:                    
        !           912:                    log6_packet(&state, "DHCPREPLY", req_addr, _("lease not found"));
        !           913:                    
        !           914:                    o1 = new_opt6(OPTION6_STATUS_CODE);
        !           915:                    put_opt6_short(DHCP6NOBINDING);
        !           916:                    put_opt6_string(_("no binding found"));
        !           917:                    end_opt6(o1);
        !           918:                    break;
        !           919:                  }
        !           920:                
        !           921:                
        !           922:                if ((this_context = address6_available(context, req_addr, tagif, 1)) ||
        !           923:                    (this_context = address6_valid(context, req_addr, tagif, 1)))
        !           924:                  {
        !           925:                    struct in6_addr addr;
        !           926:                    unsigned int lease_time;
        !           927: 
        !           928:                    get_context_tag(&state, this_context);
        !           929:                    
        !           930:                    if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
        !           931:                      lease_time = config->lease_time;
        !           932:                    else 
        !           933:                      lease_time = this_context->lease_time;
        !           934:                    
        !           935:                    calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time, requested_time); 
        !           936:                    
        !           937:                    lease_set_expires(lease, valid_time, now);
        !           938:                    if (state.ia_type == OPTION6_IA_NA && state.hostname)
        !           939:                      {
        !           940:                        char *addr_domain = get_domain6(req_addr);
        !           941:                        if (!state.send_domain)
        !           942:                          state.send_domain = addr_domain;
        !           943:                        lease_set_hostname(lease, state.hostname, state.hostname_auth, addr_domain, state.domain); 
        !           944:                        message = state.hostname;
        !           945:                      }
        !           946:                    
        !           947:                    
        !           948:                    if (preferred_time == 0)
        !           949:                      message = _("deprecated");
        !           950:                  }
        !           951:                else
        !           952:                  message = _("address invalid");
        !           953:                
        !           954:                log6_packet(&state, "DHCPREPLY", req_addr, message);    
        !           955:                
        !           956:                o1 =  new_opt6(OPTION6_IAADDR);
        !           957:                put_opt6(req_addr, sizeof(*req_addr));
        !           958:                put_opt6_long(preferred_time);
        !           959:                put_opt6_long(valid_time);
        !           960:                end_opt6(o1);
        !           961:              }
        !           962:            
        !           963:            end_ia(t1cntr, min_time, 1);
        !           964:            end_opt6(o);
        !           965:          }
        !           966:        
        !           967:        tagif = add_options(&state, fallback, context);
        !           968:        break;
        !           969:        
        !           970:       }
        !           971:       
        !           972:     case DHCP6CONFIRM:
        !           973:       {
        !           974:        /* set reply message type */
        !           975:        *outmsgtypep = DHCP6REPLY;
        !           976:        
        !           977:        log6_packet(&state, "DHCPCONFIRM", NULL, NULL);
        !           978:        
        !           979:        for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
        !           980:          {
        !           981:            void *ia_option, *ia_end;
        !           982:            
        !           983:            for (check_ia(&state, opt, &ia_end, &ia_option);
        !           984:                 ia_option;
        !           985:                 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
        !           986:              {
        !           987:                struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
        !           988:                
        !           989:                if (!address6_available(context, req_addr, tagif, 1))
        !           990:                  {
        !           991:                    o1 = new_opt6(OPTION6_STATUS_CODE);
        !           992:                    put_opt6_short(DHCP6NOTONLINK);
        !           993:                    put_opt6_string(_("confirm failed"));
        !           994:                    end_opt6(o1);
        !           995:                    return 1;
        !           996:                  }
        !           997: 
        !           998:                log6_packet(&state, "DHCPREPLY", req_addr, state.hostname);
        !           999:              }
        !          1000:          }      
        !          1001: 
        !          1002:        o1 = new_opt6(OPTION6_STATUS_CODE);
        !          1003:        put_opt6_short(DHCP6SUCCESS );
        !          1004:        put_opt6_string(_("all addresses still on link"));
        !          1005:        end_opt6(o1);
        !          1006:        break;
        !          1007:     }
        !          1008:       
        !          1009:     case DHCP6IREQ:
        !          1010:       {
        !          1011:        /* We can't discriminate contexts based on address, as we don't know it.
        !          1012:           If there is only one possible context, we can use its tags */
        !          1013:        if (context && context->netid.net && !context->current)
        !          1014:          {
        !          1015:            context->netid.next = NULL;
        !          1016:            state.context_tags =  &context->netid;
        !          1017:          }
        !          1018:        log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state.hostname);
        !          1019:        if (ignore)
        !          1020:          return 0;
        !          1021:        *outmsgtypep = DHCP6REPLY;
        !          1022:        tagif = add_options(&state, fallback, context);
        !          1023:        break;
        !          1024:       }
        !          1025:       
        !          1026:       
        !          1027:     case DHCP6RELEASE:
        !          1028:       {
        !          1029:        /* set reply message type */
        !          1030:        *outmsgtypep = DHCP6REPLY;
        !          1031: 
        !          1032:        log6_packet(&state, "DHCPRELEASE", NULL, NULL);
        !          1033: 
        !          1034:        for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
        !          1035:          {
        !          1036:            void *ia_option, *ia_end;
        !          1037:            int made_ia = 0;
        !          1038:                    
        !          1039:            for (check_ia(&state, opt, &ia_end, &ia_option);
        !          1040:                 ia_option;
        !          1041:                 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
        !          1042:              {
        !          1043:                struct dhcp_lease *lease;
        !          1044:                
        !          1045:                if ((lease = lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
        !          1046:                                         state.iaid, opt6_ptr(ia_option, 0))))
        !          1047:                  lease_prune(lease, now);
        !          1048:                else
        !          1049:                  {
        !          1050:                    if (!made_ia)
        !          1051:                      {
        !          1052:                        o = new_opt6(state.ia_type);
        !          1053:                        put_opt6_long(state.iaid);
        !          1054:                        if (state.ia_type == OPTION6_IA_NA)
        !          1055:                          {
        !          1056:                            put_opt6_long(0);
        !          1057:                            put_opt6_long(0)        !          1058:                          }
        !          1059:                        made_ia = 1;
        !          1060:                      }
        !          1061:                    
        !          1062:                    o1 = new_opt6(OPTION6_IAADDR);
        !          1063:                    put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
        !          1064:                    put_opt6_long(0);
        !          1065:                    put_opt6_long(0);
        !          1066:                    end_opt6(o1);
        !          1067:                  }
        !          1068:              }
        !          1069:            
        !          1070:            if (made_ia)
        !          1071:              {
        !          1072:                o1 = new_opt6(OPTION6_STATUS_CODE);
        !          1073:                put_opt6_short(DHCP6NOBINDING);
        !          1074:                put_opt6_string(_("no binding found"));
        !          1075:                end_opt6(o1);
        !          1076:                
        !          1077:                end_opt6(o);
        !          1078:              }
        !          1079:          }
        !          1080:        
        !          1081:        o1 = new_opt6(OPTION6_STATUS_CODE);
        !          1082:        put_opt6_short(DHCP6SUCCESS);
        !          1083:        put_opt6_string(_("release received"));
        !          1084:        end_opt6(o1);
        !          1085:        
        !          1086:        break;
        !          1087:       }
        !          1088: 
        !          1089:     case DHCP6DECLINE:
        !          1090:       {
        !          1091:        /* set reply message type */
        !          1092:        *outmsgtypep = DHCP6REPLY;
        !          1093:        
        !          1094:        log6_packet(&state, "DHCPDECLINE", NULL, NULL);
        !          1095: 
        !          1096:        for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
        !          1097:          {
        !          1098:            void *ia_option, *ia_end;
        !          1099:            int made_ia = 0;
        !          1100:                    
        !          1101:            for (check_ia(&state, opt, &ia_end, &ia_option);
        !          1102:                 ia_option;
        !          1103:                 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
        !          1104:              {
        !          1105:                struct dhcp_lease *lease;
        !          1106:                struct in6_addr *addrp = opt6_ptr(ia_option, 0);
        !          1107: 
        !          1108:                if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
        !          1109:                  {
        !          1110:                    prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
        !          1111:                    inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
        !          1112:                    my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), 
        !          1113:                              daemon->addrbuff, daemon->dhcp_buff3);
        !          1114:                    config->flags |= CONFIG_DECLINED;
        !          1115:                    config->decline_time = now;
        !          1116:                  }
        !          1117:                else
        !          1118:                  /* make sure this host gets a different address next time. */
        !          1119:                  for (; context; context = context->current)
        !          1120:                    context->addr_epoch++;
        !          1121:                
        !          1122:                if ((lease = lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
        !          1123:                                         state.iaid, opt6_ptr(ia_option, 0))))
        !          1124:                  lease_prune(lease, now);
        !          1125:                else
        !          1126:                  {
        !          1127:                    if (!made_ia)
        !          1128:                      {
        !          1129:                        o = new_opt6(state.ia_type);
        !          1130:                        put_opt6_long(state.iaid);
        !          1131:                        if (state.ia_type == OPTION6_IA_NA)
        !          1132:                          {
        !          1133:                            put_opt6_long(0);
        !          1134:                            put_opt6_long(0)        !          1135:                          }
        !          1136:                        made_ia = 1;
        !          1137:                      }
        !          1138:                    
        !          1139:                    o1 = new_opt6(OPTION6_IAADDR);
        !          1140:                    put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
        !          1141:                    put_opt6_long(0);
        !          1142:                    put_opt6_long(0);
        !          1143:                    end_opt6(o1);
        !          1144:                  }
        !          1145:              }
        !          1146:            
        !          1147:            if (made_ia)
        !          1148:              {
        !          1149:                o1 = new_opt6(OPTION6_STATUS_CODE);
        !          1150:                put_opt6_short(DHCP6NOBINDING);
        !          1151:                put_opt6_string(_("no binding found"));
        !          1152:                end_opt6(o1);
        !          1153:                
        !          1154:                end_opt6(o);
        !          1155:              }
        !          1156:            
        !          1157:          }
        !          1158:        break;
        !          1159:       }
        !          1160: 
        !          1161:     }
        !          1162:   
        !          1163:   log_tags(tagif, state.xid);
        !          1164:   
        !          1165:   if (option_bool(OPT_LOG_OPTS))
        !          1166:     log6_opts(0, state.xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
        !          1167:   
        !          1168:   return 1;
        !          1169: 
        !          1170: }
        !          1171: 
        !          1172: struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context)  
        !          1173: {
        !          1174:   void *oro;
        !          1175:   /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
        !          1176:   struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
        !          1177:   struct dhcp_opt *opt_cfg;
        !          1178:   int done_dns = 0, do_encap = 0;
        !          1179:   int i, o, o1;
        !          1180: 
        !          1181:   oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
        !          1182:   
        !          1183:   for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
        !          1184:     {
        !          1185:       /* netids match and not encapsulated? */
        !          1186:       if (!(opt_cfg->flags & DHOPT_TAGOK))
        !          1187:        continue;
        !          1188:       
        !          1189:       if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
        !          1190:        {
        !          1191:          for (i = 0; i <  opt6_len(oro) - 1; i += 2)
        !          1192:            if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
        !          1193:              break;
        !          1194:          
        !          1195:          /* option not requested */
        !          1196:          if (i >=  opt6_len(oro) - 1)
        !          1197:            continue;
        !          1198:        }
        !          1199:       
        !          1200:       if (opt_cfg->opt == OPTION6_DNS_SERVER)
        !          1201:        {
        !          1202:          done_dns = 1;
        !          1203:          if (opt_cfg->len == 0)
        !          1204:            continue;
        !          1205:        }
        !          1206:       
        !          1207:       o = new_opt6(opt_cfg->opt);
        !          1208:       if (opt_cfg->flags & DHOPT_ADDR6)
        !          1209:        {
        !          1210:          int j;
        !          1211:          struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
        !          1212:           for (j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
        !          1213:             {
        !          1214:               /* zero means "self" (but not in vendorclass options.) */
        !          1215:               if (IN6_IS_ADDR_UNSPECIFIED(a))
        !          1216:                 {
        !          1217:                  if (!add_local_addrs(context))
        !          1218:                    put_opt6(fallback, IN6ADDRSZ);
        !          1219:                }
        !          1220:               else
        !          1221:                 put_opt6(a, IN6ADDRSZ);
        !          1222:             }
        !          1223:        }
        !          1224:       else if (opt_cfg->val)
        !          1225:        put_opt6(opt_cfg->val, opt_cfg->len);
        !          1226:       end_opt6(o);
        !          1227:     }
        !          1228:   
        !          1229:   if (daemon->port == NAMESERVER_PORT && !done_dns && 
        !          1230:       (!IN6_IS_ADDR_UNSPECIFIED(&context->local6) ||
        !          1231:        !IN6_IS_ADDR_UNSPECIFIED(fallback)))
        !          1232:     {
        !          1233:       o = new_opt6(OPTION6_DNS_SERVER);
        !          1234:       if (!add_local_addrs(context))
        !          1235:        put_opt6(fallback, IN6ADDRSZ);
        !          1236:       end_opt6(o); 
        !          1237:     }
        !          1238:    
        !          1239:     /* handle vendor-identifying vendor-encapsulated options,
        !          1240:        dhcp-option = vi-encap:13,17,....... */
        !          1241:   for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
        !          1242:     opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
        !          1243:     
        !          1244:   if (oro)
        !          1245:     for (i = 0; i <  opt6_len(oro) - 1; i += 2)
        !          1246:       if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
        !          1247:        do_encap = 1;
        !          1248:   
        !          1249:   for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
        !          1250:     { 
        !          1251:       if (opt_cfg->flags & DHOPT_RFC3925)
        !          1252:        {
        !          1253:          int found = 0;
        !          1254:          struct dhcp_opt *oc;
        !          1255:          
        !          1256:          if (opt_cfg->flags & DHOPT_ENCAP_DONE)
        !          1257:            continue;
        !          1258:          
        !          1259:          for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
        !          1260:            {
        !          1261:              oc->flags &= ~DHOPT_ENCAP_MATCH;
        !          1262:              
        !          1263:              if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
        !          1264:                continue;
        !          1265:              
        !          1266:              oc->flags |= DHOPT_ENCAP_DONE;
        !          1267:              if (match_netid(oc->netid, tagif, 1))
        !          1268:                {
        !          1269:                  /* option requested/forced? */
        !          1270:                  if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
        !          1271:                    {
        !          1272:                      oc->flags |= DHOPT_ENCAP_MATCH;
        !          1273:                      found = 1;
        !          1274:                    }
        !          1275:                } 
        !          1276:            }
        !          1277:          
        !          1278:          if (found)
        !          1279:            { 
        !          1280:              o = new_opt6(OPTION6_VENDOR_OPTS);              
        !          1281:              put_opt6_long(opt_cfg->u.encap);  
        !          1282:             
        !          1283:              for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
        !          1284:                if (oc->flags & DHOPT_ENCAP_MATCH)
        !          1285:                  {
        !          1286:                    o1 = new_opt6(oc->opt);
        !          1287:                    put_opt6(oc->val, oc->len);
        !          1288:                    end_opt6(o1);
        !          1289:                  }
        !          1290:              end_opt6(o);
        !          1291:            }
        !          1292:        }
        !          1293:     }      
        !          1294: 
        !          1295: 
        !          1296:   if (state->hostname)
        !          1297:     {
        !          1298:       unsigned char *p;
        !          1299:       size_t len = strlen(state->hostname);
        !          1300:       
        !          1301:       if (state->send_domain)
        !          1302:        len += strlen(state->send_domain) + 1;
        !          1303: 
        !          1304:       o = new_opt6(OPTION6_FQDN);
        !          1305:       if ((p = expand(len + 3)))
        !          1306:        {
        !          1307:          *(p++) = state->fqdn_flags;
        !          1308:          p = do_rfc1035_name(p, state->hostname);
        !          1309:          if (state->send_domain)
        !          1310:            p = do_rfc1035_name(p, state->send_domain);
        !          1311:          *p = 0;
        !          1312:        }
        !          1313:       end_opt6(o);
        !          1314:     }
        !          1315: 
        !          1316: 
        !          1317:   /* logging */
        !          1318:   if (option_bool(OPT_LOG_OPTS) && oro)
        !          1319:     {
        !          1320:       char *q = daemon->namebuff;
        !          1321:       for (i = 0; i <  opt6_len(oro) - 1; i += 2)
        !          1322:        {
        !          1323:          char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
        !          1324:          q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
        !          1325:                        "%d%s%s%s", 
        !          1326:                        opt6_uint(oro, i, 2),
        !          1327:                        strlen(s) != 0 ? ":" : "",
        !          1328:                        s, 
        !          1329:                        (i > opt6_len(oro) - 3) ? "" : ", ");
        !          1330:          if ( i >  opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
        !          1331:            {
        !          1332:              q = daemon->namebuff;
        !          1333:              my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
        !          1334:            }
        !          1335:        }
        !          1336:     } 
        !          1337: 
        !          1338:   return tagif;
        !          1339: }
        !          1340:  
        !          1341: static int add_local_addrs(struct dhcp_context *context)
        !          1342: {
        !          1343:   int done = 0;
        !          1344:   
        !          1345:   for (; context; context = context->current)
        !          1346:     if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
        !          1347:       {
        !          1348:        /* squash duplicates */
        !          1349:        struct dhcp_context *c;
        !          1350:        for (c = context->current; c; c = c->current)
        !          1351:          if ((c->flags & CONTEXT_USED) &&
        !          1352:              IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
        !          1353:            break;
        !          1354:        
        !          1355:        if (!c)
        !          1356:          { 
        !          1357:            done = 1;
        !          1358:            put_opt6(&context->local6, IN6ADDRSZ);
        !          1359:          }
        !          1360:       }
        !          1361: 
        !          1362:   return done;
        !          1363: }
        !          1364: 
        !          1365: 
        !          1366: static void get_context_tag(struct state *state, struct dhcp_context *context)
        !          1367: {
        !          1368:   /* get tags from context if we've not used it before */
        !          1369:   if (context->netid.next == &context->netid && context->netid.net)
        !          1370:     {
        !          1371:       context->netid.next = state->context_tags;
        !          1372:       state->context_tags = &context->netid;
        !          1373:       if (!state->hostname_auth)
        !          1374:        {
        !          1375:          struct dhcp_netid_list *id_list;
        !          1376:          
        !          1377:          for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
        !          1378:            if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
        !          1379:              break;
        !          1380:          if (id_list)
        !          1381:            state->hostname = NULL;
        !          1382:        }
        !          1383:     }
        !          1384: } 
        !          1385: 
        !          1386: #ifdef OPTION6_PREFIX_CLASS
        !          1387: static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
        !          1388: {
        !          1389:   struct prefix_class *p;
        !          1390:   struct dhcp_netid *t;
        !          1391:   
        !          1392:   for (p = daemon->prefix_classes; p ; p = p->next)
        !          1393:     for (t = context->filter; t; t = t->next)
        !          1394:       if (strcmp(p->tag.net, t->net) == 0)
        !          1395:        return p;
        !          1396:   
        !          1397:  return NULL;
        !          1398: }
        !          1399: #endif
        !          1400: 
        !          1401: static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
        !          1402: {
        !          1403:   state->ia_type = opt6_type(opt);
        !          1404:   *ia_option = NULL;
        !          1405: 
        !          1406:   if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
        !          1407:     return 0;
        !          1408:   
        !          1409:   if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
        !          1410:     return 0;
        !          1411:            
        !          1412:   if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
        !          1413:     return 0;
        !          1414:   
        !          1415:   *endp = opt6_ptr(opt, opt6_len(opt));
        !          1416:   state->iaid = opt6_uint(opt, 0, 4);
        !          1417:   *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
        !          1418: 
        !          1419:   return 1;
        !          1420: }
        !          1421: 
        !          1422: 
        !          1423: static int build_ia(struct state *state, int *t1cntr)
        !          1424: {
        !          1425:   int  o = new_opt6(state->ia_type);
        !          1426:  
        !          1427:   put_opt6_long(state->iaid);
        !          1428:   *t1cntr = 0;
        !          1429:            
        !          1430:   if (state->ia_type == OPTION6_IA_NA)
        !          1431:     {
        !          1432:       /* save pointer */
        !          1433:       *t1cntr = save_counter(-1);
        !          1434:       /* so we can fill these in later */
        !          1435:       put_opt6_long(0);
        !          1436:       put_opt6_long(0)        !          1437:     }
        !          1438: 
        !          1439:   return o;
        !          1440: }
        !          1441: 
        !          1442: static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
        !          1443: {
        !          1444:   if (t1cntr != 0)
        !          1445:     {
        !          1446:       /* go back an fill in fields in IA_NA option */
        !          1447:       int sav = save_counter(t1cntr);
        !          1448:       unsigned int t1, t2, fuzz = 0;
        !          1449: 
        !          1450:       if (do_fuzz)
        !          1451:        {
        !          1452:          fuzz = rand16();
        !          1453:       
        !          1454:          while (fuzz > (min_time/16))
        !          1455:            fuzz = fuzz/2;
        !          1456:        }
        !          1457:       
        !          1458:       t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
        !          1459:       t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
        !          1460:       put_opt6_long(t1);
        !          1461:       put_opt6_long(t2);
        !          1462:       save_counter(sav);
        !          1463:     }  
        !          1464: }
        !          1465: 
        !          1466: static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time, 
        !          1467:                        unsigned int *min_time, struct in6_addr *addr, int do_update, time_t now)
        !          1468: {
        !          1469:   unsigned int valid_time, preferred_time;
        !          1470:   int o = new_opt6(OPTION6_IAADDR);
        !          1471:   struct dhcp_lease *lease;
        !          1472: 
        !          1473:   calculate_times(context, min_time, &valid_time, &preferred_time, lease_time, requested_time); 
        !          1474:   
        !          1475:   put_opt6(addr, sizeof(*addr));
        !          1476:   put_opt6_long(preferred_time);
        !          1477:   put_opt6_long(valid_time);               
        !          1478:   
        !          1479: #ifdef OPTION6_PREFIX_CLASS
        !          1480:   if (state->send_prefix_class)
        !          1481:     {
        !          1482:       int o1 = new_opt6(OPTION6_PREFIX_CLASS);
        !          1483:       put_opt6_short(state->send_prefix_class->class);
        !          1484:       end_opt6(o1);
        !          1485:     }
        !          1486: #endif
        !          1487: 
        !          1488:   end_opt6(o);
        !          1489:   
        !          1490:   if (do_update)
        !          1491:     update_leases(state, context, addr, valid_time, now);
        !          1492: 
        !          1493:   if ((lease = lease6_find_by_addr(addr, 128, 0)))
        !          1494:     lease->flags |= LEASE_USED;
        !          1495: 
        !          1496:   /* get tags from context if we've not used it before */
        !          1497:   if (context->netid.next == &context->netid && context->netid.net)
        !          1498:     {
        !          1499:       context->netid.next = state->context_tags;
        !          1500:       state->context_tags = &context->netid;
        !          1501:       
        !          1502:       if (!state->hostname_auth)
        !          1503:        {
        !          1504:          struct dhcp_netid_list *id_list;
        !          1505:          
        !          1506:          for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
        !          1507:            if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
        !          1508:              break;
        !          1509:          if (id_list)
        !          1510:            state->hostname = NULL;
        !          1511:        }
        !          1512:     }
        !          1513: 
        !          1514:   log6_packet(state, do_update ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
        !          1515: 
        !          1516: }
        !          1517: 
        !          1518: static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr)
        !          1519: {
        !          1520:   /* Mark that we have an address for this prefix. */
        !          1521: #ifdef OPTION6_PREFIX_CLASS
        !          1522:   for (; context; context = context->current)
        !          1523:     if (is_same_net6(addr, &context->start6, context->prefix) &&
        !          1524:        (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
        !          1525:       context->flags |= CONTEXT_USED;
        !          1526: #else
        !          1527:   (void)state; /* warning */
        !          1528:   for (; context; context = context->current)
        !          1529:     if (is_same_net6(addr, &context->start6, context->prefix))
        !          1530:       context->flags |= CONTEXT_USED;
        !          1531: #endif
        !          1532: }
        !          1533: 
        !          1534: static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
        !          1535: {
        !          1536:   for (; context; context = context->current)
        !          1537:     if (is_same_net6(addr, &context->start6, context->prefix))
        !          1538:       context->flags |= CONTEXT_CONF_USED;
        !          1539: }
        !          1540: 
        !          1541: /* make sure address not leased to another CLID/IAID */
        !          1542: static int check_address(struct state *state, struct in6_addr *addr)
        !          1543: { 
        !          1544:   struct dhcp_lease *lease;
        !          1545: 
        !          1546:   if (!(lease = lease6_find_by_addr(addr, 128, 0)))
        !          1547:     return 1;
        !          1548: 
        !          1549:   if (lease->clid_len != state->clid_len || 
        !          1550:       memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
        !          1551:       lease->hwaddr_type != state->iaid)
        !          1552:     return 0;
        !          1553: 
        !          1554:   return 1;
        !          1555: }
        !          1556: 
        !          1557: static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep, 
        !          1558:                            unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time)
        !          1559: {
        !          1560:   unsigned int preferred_time, valid_time;
        !          1561: 
        !          1562:   if (requested_time < 120u )
        !          1563:     requested_time = 120u; /* sanity */
        !          1564:   if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
        !          1565:     lease_time = requested_time;
        !          1566:                    
        !          1567:   valid_time = (context->valid < lease_time) ? context->valid : lease_time;
        !          1568:   preferred_time = (context->preferred < lease_time) ? context->preferred : lease_time;
        !          1569: 
        !          1570:   if (context->flags & CONTEXT_DEPRECATE)
        !          1571:     preferred_time = 0;
        !          1572: 
        !          1573:   if (preferred_time != 0 && preferred_time < *min_time)
        !          1574:     *min_time = preferred_time;
        !          1575:   
        !          1576:   if (valid_time != 0 && valid_time < *min_time)
        !          1577:     *min_time = valid_time;
        !          1578:   
        !          1579:   *valid_timep = valid_time;
        !          1580:   *preferred_timep = preferred_time;
        !          1581: }
        !          1582: 
        !          1583: static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
        !          1584: {
        !          1585:   struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
        !          1586:   struct dhcp_netid *tagif = run_tag_if(state->tags);
        !          1587: 
        !          1588:   if (!lease)
        !          1589:     lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
        !          1590:   
        !          1591:   if (lease)
        !          1592:     {
        !          1593:       lease_set_expires(lease, lease_time, now);
        !          1594:       lease_set_hwaddr(lease, NULL, state->clid, 0, state->iaid, state->clid_len, now, 0);
        !          1595:       lease_set_interface(lease, state->interface, now);
        !          1596:       if (state->hostname && state->ia_type == OPTION6_IA_NA)
        !          1597:        {
        !          1598:          char *addr_domain = get_domain6(addr);
        !          1599:          if (!state->send_domain)
        !          1600:            state->send_domain = addr_domain;
        !          1601:          lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
        !          1602:        }
        !          1603:       
        !          1604: #ifdef HAVE_SCRIPT
        !          1605:       if (daemon->lease_change_command)
        !          1606:        {
        !          1607:          void *class_opt;
        !          1608:          lease->flags |= LEASE_CHANGED;
        !          1609:          free(lease->extradata);
        !          1610:          lease->extradata = NULL;
        !          1611:          lease->extradata_size = lease->extradata_len = 0;
        !          1612:          lease->vendorclass_count = 0; 
        !          1613:          
        !          1614:          if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
        !          1615:            {
        !          1616:              void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
        !          1617:              lease->vendorclass_count++;
        !          1618:              /* send enterprise number first  */
        !          1619:              sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
        !          1620:              lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
        !          1621:              
        !          1622:              if (opt6_len(class_opt) >= 6) 
        !          1623:                for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
        !          1624:                  {
        !          1625:                    lease->vendorclass_count++;
        !          1626:                    lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
        !          1627:                  }
        !          1628:            }
        !          1629:          
        !          1630:          lease_add_extradata(lease, (unsigned char *)state->client_hostname, 
        !          1631:                              state->client_hostname ? strlen(state->client_hostname) : 0, 0);                          
        !          1632:          
        !          1633:          /* space-concat tag set */
        !          1634:          if (!tagif && !context->netid.net)
        !          1635:            lease_add_extradata(lease, NULL, 0, 0);
        !          1636:          else
        !          1637:            {
        !          1638:              if (context->netid.net)
        !          1639:                lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
        !          1640:              
        !          1641:              if (tagif)
        !          1642:                {
        !          1643:                  struct dhcp_netid *n;
        !          1644:                  for (n = tagif; n; n = n->next)
        !          1645:                    {
        !          1646:                      struct dhcp_netid *n1;
        !          1647:                      /* kill dupes */
        !          1648:                      for (n1 = n->next; n1; n1 = n1->next)
        !          1649:                        if (strcmp(n->net, n1->net) == 0)
        !          1650:                          break;
        !          1651:                      if (!n1)
        !          1652:                        lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0); 
        !          1653:                    }
        !          1654:                }
        !          1655:            }
        !          1656:          
        !          1657:          if (state->link_address)
        !          1658:            inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
        !          1659:          
        !          1660:          lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
        !          1661:          
        !          1662:          if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
        !          1663:            {
        !          1664:              void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
        !          1665:              for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
        !          1666:                lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
        !          1667:            }
        !          1668:        }
        !          1669: #endif 
        !          1670:       
        !          1671:     }
        !          1672: }
        !          1673:                          
        !          1674:                        
        !          1675:        
        !          1676: static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
        !          1677: {
        !          1678:   void *opt;
        !          1679:   char *desc = nest ? "nest" : "sent";
        !          1680:   
        !          1681:   if (start_opts == end_opts)
        !          1682:     return;
        !          1683:   
        !          1684:   for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
        !          1685:     {
        !          1686:       int type = opt6_type(opt);
        !          1687:       void *ia_options = NULL;
        !          1688:       char *optname;
        !          1689:       
        !          1690:       if (type == OPTION6_IA_NA)
        !          1691:        {
        !          1692:          sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
        !          1693:                  opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
        !          1694:          optname = "ia-na";
        !          1695:          ia_options = opt6_ptr(opt, 12);
        !          1696:        }
        !          1697:       else if (type == OPTION6_IA_TA)
        !          1698:        {
        !          1699:          sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
        !          1700:          optname = "ia-ta";
        !          1701:          ia_options = opt6_ptr(opt, 4);
        !          1702:        }
        !          1703:       else if (type == OPTION6_IAADDR)
        !          1704:        {
        !          1705:          inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
        !          1706:          sprintf(daemon->namebuff, "%s PL=%u VL=%u", 
        !          1707:                  daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
        !          1708:          optname = "iaaddr";
        !          1709:          ia_options = opt6_ptr(opt, 24);
        !          1710:        }
        !          1711: #ifdef OPTION6_PREFIX_CLASS
        !          1712:       else if (type == OPTION6_PREFIX_CLASS)
        !          1713:        {
        !          1714:          optname = "prefix-class";
        !          1715:          sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
        !          1716:        }
        !          1717: #endif
        !          1718:       else if (type == OPTION6_STATUS_CODE)
        !          1719:        {
        !          1720:          int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
        !          1721:          memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
        !          1722:          daemon->namebuff[len + opt6_len(opt) - 2] = 0;
        !          1723:          optname = "status";
        !          1724:        }
        !          1725:       else
        !          1726:        {
        !          1727:          /* account for flag byte on FQDN */
        !          1728:          int offset = type == OPTION6_FQDN ? 1 : 0;
        !          1729:          optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
        !          1730:        }
        !          1731:       
        !          1732:       my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s  %s", 
        !          1733:                xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
        !          1734:       
        !          1735:       if (ia_options)
        !          1736:        log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
        !          1737:     }
        !          1738: }               
        !          1739:  
        !          1740: static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
        !          1741: {
        !          1742:   int clid_len = state->clid_len;
        !          1743: 
        !          1744:   /* avoid buffer overflow */
        !          1745:   if (clid_len > 100)
        !          1746:     clid_len = 100;
        !          1747:   
        !          1748:   print_mac(daemon->namebuff, state->clid, clid_len);
        !          1749: 
        !          1750:   if (addr)
        !          1751:     {
        !          1752:       inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, 255);
        !          1753:       strcat(daemon->dhcp_buff2, " ");
        !          1754:     }
        !          1755:   else
        !          1756:     daemon->dhcp_buff2[0] = 0;
        !          1757: 
        !          1758:   if(option_bool(OPT_LOG_OPTS))
        !          1759:     my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
        !          1760:              state->xid, 
        !          1761:              type,
        !          1762:              state->iface_name, 
        !          1763:              daemon->dhcp_buff2,
        !          1764:              daemon->namebuff,
        !          1765:              string ? string : "");
        !          1766:   else
        !          1767:     my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
        !          1768:              type,
        !          1769:              state->iface_name, 
        !          1770:              daemon->dhcp_buff2,
        !          1771:              daemon->namebuff,
        !          1772:              string ? string : "");
        !          1773: }
        !          1774: 
        !          1775: static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
        !          1776: {
        !          1777:   u16 opt, opt_len;
        !          1778:   void *start;
        !          1779:   
        !          1780:   if (!opts)
        !          1781:     return NULL;
        !          1782:     
        !          1783:   while (1)
        !          1784:     {
        !          1785:       if (end - opts < 4) 
        !          1786:        return NULL;
        !          1787:       
        !          1788:       start = opts;
        !          1789:       GETSHORT(opt, opts);
        !          1790:       GETSHORT(opt_len, opts);
        !          1791:       
        !          1792:       if (opt_len > (end - opts))
        !          1793:        return NULL;
        !          1794:       
        !          1795:       if (opt == search && (opt_len >= minsize))
        !          1796:        return start;
        !          1797:       
        !          1798:       opts += opt_len;
        !          1799:     }
        !          1800: }
        !          1801: 
        !          1802: static void *opt6_next(void *opts, void *end)
        !          1803: {
        !          1804:   u16 opt_len;
        !          1805:   
        !          1806:   if (end - opts < 4) 
        !          1807:     return NULL;
        !          1808:   
        !          1809:   opts += 2;
        !          1810:   GETSHORT(opt_len, opts);
        !          1811:   
        !          1812:   if (opt_len >= (end - opts))
        !          1813:     return NULL;
        !          1814:   
        !          1815:   return opts + opt_len;
        !          1816: }
        !          1817: 
        !          1818: static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
        !          1819: {
        !          1820:   /* this worries about unaligned data and byte order */
        !          1821:   unsigned int ret = 0;
        !          1822:   int i;
        !          1823:   unsigned char *p = opt6_ptr(opt, offset);
        !          1824:   
        !          1825:   for (i = 0; i < size; i++)
        !          1826:     ret = (ret << 8) | *p++;
        !          1827:   
        !          1828:   return ret;
        !          1829: } 
        !          1830: 
        !          1831: #endif

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