Annotation of embedaddon/dhcp/client/dhc6.c, revision 1.1.1.1
1.1 misho 1: /* dhc6.c - DHCPv6 client routines. */
2:
3: /*
1.1.1.1 ! misho 4: * Copyright (c) 2012 by Internet Systems Consortium, Inc. ("ISC")
1.1 misho 5: * Copyright (c) 2006-2010 by Internet Systems Consortium, Inc. ("ISC")
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: *
19: * Internet Systems Consortium, Inc.
20: * 950 Charter Street
21: * Redwood City, CA 94063
22: * <info@isc.org>
23: * https://www.isc.org/
24: */
25:
26: #include "dhcpd.h"
27:
28: #ifdef DHCPv6
29:
30: struct sockaddr_in6 DHCPv6DestAddr;
31:
32: /*
33: * Option definition structures that are used by the software - declared
34: * here once and assigned at startup to save lookups.
35: */
36: struct option *clientid_option = NULL;
37: struct option *elapsed_option = NULL;
38: struct option *ia_na_option = NULL;
39: struct option *ia_ta_option = NULL;
40: struct option *ia_pd_option = NULL;
41: struct option *iaaddr_option = NULL;
42: struct option *iaprefix_option = NULL;
43: struct option *oro_option = NULL;
44: struct option *irt_option = NULL;
45:
46: static struct dhc6_lease *dhc6_dup_lease(struct dhc6_lease *lease,
47: const char *file, int line);
48: static struct dhc6_ia *dhc6_dup_ia(struct dhc6_ia *ia,
49: const char *file, int line);
50: static struct dhc6_addr *dhc6_dup_addr(struct dhc6_addr *addr,
51: const char *file, int line);
52: static void dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line);
53: static isc_result_t dhc6_parse_ia_na(struct dhc6_ia **pia,
54: struct packet *packet,
55: struct option_state *options);
56: static isc_result_t dhc6_parse_ia_ta(struct dhc6_ia **pia,
57: struct packet *packet,
58: struct option_state *options);
59: static isc_result_t dhc6_parse_ia_pd(struct dhc6_ia **pia,
60: struct packet *packet,
61: struct option_state *options);
62: static isc_result_t dhc6_parse_addrs(struct dhc6_addr **paddr,
63: struct packet *packet,
64: struct option_state *options);
65: static isc_result_t dhc6_parse_prefixes(struct dhc6_addr **ppref,
66: struct packet *packet,
67: struct option_state *options);
68: static struct dhc6_ia *find_ia(struct dhc6_ia *head,
69: u_int16_t type, const char *id);
70: static struct dhc6_addr *find_addr(struct dhc6_addr *head,
71: struct iaddr *address);
72: static struct dhc6_addr *find_pref(struct dhc6_addr *head,
73: struct iaddr *prefix, u_int8_t plen);
74: void init_handler(struct packet *packet, struct client_state *client);
75: void info_request_handler(struct packet *packet, struct client_state *client);
76: void rapid_commit_handler(struct packet *packet, struct client_state *client);
77: void do_init6(void *input);
78: void do_info_request6(void *input);
79: void do_confirm6(void *input);
80: void reply_handler(struct packet *packet, struct client_state *client);
81: static isc_result_t dhc6_add_ia_na(struct client_state *client,
82: struct data_string *packet,
83: struct dhc6_lease *lease,
84: u_int8_t message);
85: static isc_result_t dhc6_add_ia_ta(struct client_state *client,
86: struct data_string *packet,
87: struct dhc6_lease *lease,
88: u_int8_t message);
89: static isc_result_t dhc6_add_ia_pd(struct client_state *client,
90: struct data_string *packet,
91: struct dhc6_lease *lease,
92: u_int8_t message);
93: static isc_boolean_t stopping_finished(void);
94: static void dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst);
95: void do_select6(void *input);
96: void do_refresh6(void *input);
97: static void do_release6(void *input);
98: static void start_bound(struct client_state *client);
99: static void start_informed(struct client_state *client);
100: void informed_handler(struct packet *packet, struct client_state *client);
101: void bound_handler(struct packet *packet, struct client_state *client);
102: void start_renew6(void *input);
103: void start_rebind6(void *input);
104: void do_depref(void *input);
105: void do_expire(void *input);
106: static void make_client6_options(struct client_state *client,
107: struct option_state **op,
108: struct dhc6_lease *lease, u_int8_t message);
109: static void script_write_params6(struct client_state *client,
110: const char *prefix,
111: struct option_state *options);
112: static isc_boolean_t active_prefix(struct client_state *client);
113:
114: static int check_timing6(struct client_state *client, u_int8_t msg_type,
115: char *msg_str, struct dhc6_lease *lease,
116: struct data_string *ds);
117:
118: extern int onetry;
119: extern int stateless;
120:
121: /*
122: * The "best" default DUID, since we cannot predict any information
123: * about the system (such as whether or not the hardware addresses are
124: * integrated into the motherboard or similar), is the "LLT", link local
125: * plus time, DUID. For real stateless "LL" is better.
126: *
127: * Once generated, this duid is stored into the state database, and
128: * retained across restarts.
129: *
130: * For the time being, there is probably a different state database for
131: * every daemon, so this winds up being a per-interface identifier...which
132: * is not how it is intended. Upcoming rearchitecting the client should
133: * address this "one daemon model."
134: */
135: void
136: form_duid(struct data_string *duid, const char *file, int line)
137: {
138: struct interface_info *ip;
139: int len;
140:
141: /* For now, just use the first interface on the list. */
142: ip = interfaces;
143:
144: if (ip == NULL)
145: log_fatal("Impossible condition at %s:%d.", MDL);
146:
147: if ((ip->hw_address.hlen == 0) ||
148: (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
149: log_fatal("Impossible hardware address length at %s:%d.", MDL);
150:
151: /*
152: * 2 bytes for the 'duid type' field.
153: * 2 bytes for the 'htype' field.
154: * (not stateless) 4 bytes for the 'current time'.
155: * enough bytes for the hardware address (note that hw_address has
156: * the 'htype' on byte zero).
157: */
158: len = 4 + (ip->hw_address.hlen - 1);
159: if (!stateless)
160: len += 4;
161: if (!buffer_allocate(&duid->buffer, len, MDL))
162: log_fatal("no memory for default DUID!");
163: duid->data = duid->buffer->data;
164: duid->len = len;
165:
166: /* Basic Link Local Address type of DUID. */
167: if (!stateless) {
168: putUShort(duid->buffer->data, DUID_LLT);
169: putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
170: putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
171: memcpy(duid->buffer->data + 8, ip->hw_address.hbuf + 1,
172: ip->hw_address.hlen - 1);
173: } else {
174: putUShort(duid->buffer->data, DUID_LL);
175: putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
176: memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
177: ip->hw_address.hlen - 1);
178: }
179: }
180:
181: /*
182: * Assign DHCPv6 port numbers as a client.
183: */
184: void
185: dhcpv6_client_assignments(void)
186: {
187: struct servent *ent;
188: unsigned code;
189:
190: if (path_dhclient_pid == NULL)
191: path_dhclient_pid = _PATH_DHCLIENT6_PID;
192: if (path_dhclient_db == NULL)
193: path_dhclient_db = _PATH_DHCLIENT6_DB;
194:
195: if (local_port == 0) {
196: ent = getservbyname("dhcpv6-client", "udp");
197: if (ent == NULL)
198: local_port = htons(546);
199: else
200: local_port = ent->s_port;
201: }
202:
203: if (remote_port == 0) {
204: ent = getservbyname("dhcpv6-server", "udp");
205: if (ent == NULL)
206: remote_port = htons(547);
207: else
208: remote_port = ent->s_port;
209: }
210:
211: memset(&DHCPv6DestAddr, 0, sizeof(DHCPv6DestAddr));
212: DHCPv6DestAddr.sin6_family = AF_INET6;
213: DHCPv6DestAddr.sin6_port = remote_port;
214: inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
215: &DHCPv6DestAddr.sin6_addr);
216:
217: code = D6O_CLIENTID;
218: if (!option_code_hash_lookup(&clientid_option,
219: dhcpv6_universe.code_hash, &code, 0, MDL))
220: log_fatal("Unable to find the CLIENTID option definition.");
221:
222: code = D6O_ELAPSED_TIME;
223: if (!option_code_hash_lookup(&elapsed_option,
224: dhcpv6_universe.code_hash, &code, 0, MDL))
225: log_fatal("Unable to find the ELAPSED_TIME option definition.");
226:
227: code = D6O_IA_NA;
228: if (!option_code_hash_lookup(&ia_na_option, dhcpv6_universe.code_hash,
229: &code, 0, MDL))
230: log_fatal("Unable to find the IA_NA option definition.");
231:
232: code = D6O_IA_TA;
233: if (!option_code_hash_lookup(&ia_ta_option, dhcpv6_universe.code_hash,
234: &code, 0, MDL))
235: log_fatal("Unable to find the IA_TA option definition.");
236:
237: code = D6O_IA_PD;
238: if (!option_code_hash_lookup(&ia_pd_option, dhcpv6_universe.code_hash,
239: &code, 0, MDL))
240: log_fatal("Unable to find the IA_PD option definition.");
241:
242: code = D6O_IAADDR;
243: if (!option_code_hash_lookup(&iaaddr_option, dhcpv6_universe.code_hash,
244: &code, 0, MDL))
245: log_fatal("Unable to find the IAADDR option definition.");
246:
247: code = D6O_IAPREFIX;
248: if (!option_code_hash_lookup(&iaprefix_option,
249: dhcpv6_universe.code_hash,
250: &code, 0, MDL))
251: log_fatal("Unable to find the IAPREFIX option definition.");
252:
253: code = D6O_ORO;
254: if (!option_code_hash_lookup(&oro_option, dhcpv6_universe.code_hash,
255: &code, 0, MDL))
256: log_fatal("Unable to find the ORO option definition.");
257:
258: code = D6O_INFORMATION_REFRESH_TIME;
259: if (!option_code_hash_lookup(&irt_option, dhcpv6_universe.code_hash,
260: &code, 0, MDL))
261: log_fatal("Unable to find the IRT option definition.");
262:
263: #ifndef __CYGWIN32__ /* XXX */
264: endservent();
265: #endif
266: }
267:
268: /*
269: * Instead of implementing RFC3315 RAND (section 14) as a float "between"
270: * -0.1 and 0.1 non-inclusive, we implement it as an integer.
271: *
272: * The result is expected to follow this table:
273: *
274: * split range answer
275: * - ERROR - base <= 0
276: * 0 1 0..0 1 <= base <= 10
277: * 1 3 -1..1 11 <= base <= 20
278: * 2 5 -2..2 21 <= base <= 30
279: * 3 7 -3..3 31 <= base <= 40
280: * ...
281: *
282: * XXX: For this to make sense, we really need to do timing on a
283: * XXX: usec scale...we currently can assume zero for any value less than
284: * XXX: 11, which are very common in early stages of transmission for most
285: * XXX: messages.
286: */
287: static TIME
288: dhc6_rand(TIME base)
289: {
290: TIME rval;
291: TIME range;
292: TIME split;
293:
294: /*
295: * A zero or less timeout is a bad thing...we don't want to
296: * DHCP-flood anyone.
297: */
298: if (base <= 0)
299: log_fatal("Impossible condition at %s:%d.", MDL);
300:
301: /*
302: * The first thing we do is count how many random integers we want
303: * in either direction (best thought of as the maximum negative
304: * integer, as we will subtract this potentially from a random 0).
305: */
306: split = (base - 1) / 10;
307:
308: /* Don't bother with the rest of the math if we know we'll get 0. */
309: if (split == 0)
310: return 0;
311:
312: /*
313: * Then we count the total number of integers in this set. This
314: * is twice the number of integers in positive and negative
315: * directions, plus zero (-1, 0, 1 is 3, -2..2 adds 2 to 5, so forth).
316: */
317: range = (split * 2) + 1;
318:
319: /* Take a random number from [0..(range-1)]. */
320: rval = random();
321: rval %= range;
322:
323: /* Offset it to uncover potential negative values. */
324: rval -= split;
325:
326: return rval;
327: }
328:
329: /* Initialize message exchange timers (set RT from Initial-RT). */
330: static void
331: dhc6_retrans_init(struct client_state *client)
332: {
333: int xid;
334:
335: /* Initialize timers. */
336: client->txcount = 0;
337: client->RT = client->IRT + dhc6_rand(client->IRT);
338:
339: /* Generate a new random 24-bit transaction ID for this exchange. */
340:
341: #if (RAND_MAX >= 0x00ffffff)
342: xid = random();
343: #elif (RAND_MAX >= 0x0000ffff)
344: xid = (random() << 16) ^ random();
345: #elif (RAND_MAX >= 0x000000ff)
346: xid = (random() << 16) ^ (random() << 8) ^ random();
347: #else
348: # error "Random number generator of less than 8 bits not supported."
349: #endif
350:
351: client->dhcpv6_transaction_id[0] = (xid >> 16) & 0xff;
352: client->dhcpv6_transaction_id[1] = (xid >> 8) & 0xff;
353: client->dhcpv6_transaction_id[2] = xid & 0xff;
354: }
355:
356: /* Advance the DHCPv6 retransmission state once. */
357: static void
358: dhc6_retrans_advance(struct client_state *client)
359: {
360: struct timeval elapsed;
361:
362: /* elapsed = cur - start */
363: elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
364: elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
365: if (elapsed.tv_usec < 0) {
366: elapsed.tv_sec -= 1;
367: elapsed.tv_usec += 1000000;
368: }
369: /* retrans_advance is called after consuming client->RT. */
370: /* elapsed += RT */
371: elapsed.tv_sec += client->RT / 100;
372: elapsed.tv_usec += (client->RT % 100) * 10000;
373: if (elapsed.tv_usec >= 1000000) {
374: elapsed.tv_sec += 1;
375: elapsed.tv_usec -= 1000000;
376: }
377:
378: /*
379: * RT for each subsequent message transmission is based on the previous
380: * value of RT:
381: *
382: * RT = 2*RTprev + RAND*RTprev
383: */
384: client->RT += client->RT + dhc6_rand(client->RT);
385:
386: /*
387: * MRT specifies an upper bound on the value of RT (disregarding the
388: * randomization added by the use of RAND). If MRT has a value of 0,
389: * there is no upper limit on the value of RT. Otherwise:
390: *
391: * if (RT > MRT)
392: * RT = MRT + RAND*MRT
393: */
394: if ((client->MRT != 0) && (client->RT > client->MRT))
395: client->RT = client->MRT + dhc6_rand(client->MRT);
396:
397: /*
398: * Further, if there's an MRD, we should wake up upon reaching
399: * the MRD rather than at some point after it.
400: */
401: if (client->MRD == 0) {
402: /* Done. */
403: client->txcount++;
404: return;
405: }
406: /* elapsed += client->RT */
407: elapsed.tv_sec += client->RT / 100;
408: elapsed.tv_usec += (client->RT % 100) * 10000;
409: if (elapsed.tv_usec >= 1000000) {
410: elapsed.tv_sec += 1;
411: elapsed.tv_usec -= 1000000;
412: }
413: if (elapsed.tv_sec >= client->MRD) {
414: /*
415: * wake at RT + cur = start + MRD
416: */
417: client->RT = client->MRD +
418: (client->start_time.tv_sec - cur_tv.tv_sec);
419: client->RT = client->RT * 100 +
420: (client->start_time.tv_usec - cur_tv.tv_usec) / 10000;
421: }
422: client->txcount++;
423: }
424:
425: /* Quick validation of DHCPv6 ADVERTISE packet contents. */
426: static int
427: valid_reply(struct packet *packet, struct client_state *client)
428: {
429: struct data_string sid, cid;
430: struct option_cache *oc;
431: int rval = ISC_TRUE;
432:
433: memset(&sid, 0, sizeof(sid));
434: memset(&cid, 0, sizeof(cid));
435:
436: if (!lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID)) {
437: log_error("Response without a server identifier received.");
438: rval = ISC_FALSE;
439: }
440:
441: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID);
442: if (!oc ||
443: !evaluate_option_cache(&sid, packet, NULL, client, packet->options,
444: client->sent_options, &global_scope, oc,
445: MDL)) {
446: log_error("Response without a client identifier.");
447: rval = ISC_FALSE;
448: }
449:
450: oc = lookup_option(&dhcpv6_universe, client->sent_options,
451: D6O_CLIENTID);
452: if (!oc ||
453: !evaluate_option_cache(&cid, packet, NULL, client,
454: client->sent_options, NULL, &global_scope,
455: oc, MDL)) {
456: log_error("Local client identifier is missing!");
457: rval = ISC_FALSE;
458: }
459:
460: if (sid.len == 0 ||
461: sid.len != cid.len ||
462: memcmp(sid.data, cid.data, sid.len)) {
463: log_error("Advertise with matching transaction ID, but "
464: "mismatching client id.");
465: rval = ISC_FALSE;
466: }
467:
468: return rval;
469: }
470:
471: /*
472: * Create a complete copy of a DHCPv6 lease structure.
473: */
474: static struct dhc6_lease *
475: dhc6_dup_lease(struct dhc6_lease *lease, const char *file, int line)
476: {
477: struct dhc6_lease *copy;
478: struct dhc6_ia **insert_ia, *ia;
479:
480: copy = dmalloc(sizeof(*copy), file, line);
481: if (copy == NULL) {
482: log_error("Out of memory for v6 lease structure.");
483: return NULL;
484: }
485:
486: data_string_copy(©->server_id, &lease->server_id, file, line);
487: copy->pref = lease->pref;
488:
489: memcpy(copy->dhcpv6_transaction_id, lease->dhcpv6_transaction_id,
490: sizeof(copy->dhcpv6_transaction_id));
491:
492: option_state_reference(©->options, lease->options, file, line);
493:
494: insert_ia = ©->bindings;
495: for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
496: *insert_ia = dhc6_dup_ia(ia, file, line);
497:
498: if (*insert_ia == NULL) {
499: dhc6_lease_destroy(©, file, line);
500: return NULL;
501: }
502:
503: insert_ia = &(*insert_ia)->next;
504: }
505:
506: return copy;
507: }
508:
509: /*
510: * Duplicate an IA structure.
511: */
512: static struct dhc6_ia *
513: dhc6_dup_ia(struct dhc6_ia *ia, const char *file, int line)
514: {
515: struct dhc6_ia *copy;
516: struct dhc6_addr **insert_addr, *addr;
517:
518: copy = dmalloc(sizeof(*ia), file, line);
519:
520: memcpy(copy->iaid, ia->iaid, sizeof(copy->iaid));
521:
522: copy->ia_type = ia->ia_type;
523: copy->starts = ia->starts;
524: copy->renew = ia->renew;
525: copy->rebind = ia->rebind;
526:
527: insert_addr = ©->addrs;
528: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
529: *insert_addr = dhc6_dup_addr(addr, file, line);
530:
531: if (*insert_addr == NULL) {
532: dhc6_ia_destroy(©, file, line);
533: return NULL;
534: }
535:
536: insert_addr = &(*insert_addr)->next;
537: }
538:
539: if (ia->options != NULL)
540: option_state_reference(©->options, ia->options,
541: file, line);
542:
543: return copy;
544: }
545:
546: /*
547: * Duplicate an IAADDR or IAPREFIX structure.
548: */
549: static struct dhc6_addr *
550: dhc6_dup_addr(struct dhc6_addr *addr, const char *file, int line)
551: {
552: struct dhc6_addr *copy;
553:
554: copy = dmalloc(sizeof(*addr), file, line);
555:
556: if (copy == NULL)
557: return NULL;
558:
559: memcpy(©->address, &addr->address, sizeof(copy->address));
560:
561: copy->plen = addr->plen;
562: copy->flags = addr->flags;
563: copy->starts = addr->starts;
564: copy->preferred_life = addr->preferred_life;
565: copy->max_life = addr->max_life;
566:
567: if (addr->options != NULL)
568: option_state_reference(©->options, addr->options,
569: file, line);
570:
571: return copy;
572: }
573:
574: /*
575: * Form a DHCPv6 lease structure based upon packet contents. Creates and
576: * populates IA's and any IAADDR/IAPREFIX's they contain.
577: * Parsed options are deleted in order to not save them in the lease file.
578: */
579: static struct dhc6_lease *
580: dhc6_leaseify(struct packet *packet)
581: {
582: struct data_string ds;
583: struct dhc6_lease *lease;
584: struct option_cache *oc;
585:
586: lease = dmalloc(sizeof(*lease), MDL);
587: if (lease == NULL) {
588: log_error("Out of memory for v6 lease structure.");
589: return NULL;
590: }
591:
592: memcpy(lease->dhcpv6_transaction_id, packet->dhcpv6_transaction_id, 3);
593: option_state_reference(&lease->options, packet->options, MDL);
594:
595: memset(&ds, 0, sizeof(ds));
596:
597: /* Determine preference (default zero). */
598: oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
599: if (oc &&
600: evaluate_option_cache(&ds, packet, NULL, NULL, lease->options,
601: NULL, &global_scope, oc, MDL)) {
602: if (ds.len != 1) {
603: log_error("Invalid length of DHCPv6 Preference option "
604: "(%d != 1)", ds.len);
605: data_string_forget(&ds, MDL);
606: dhc6_lease_destroy(&lease, MDL);
607: return NULL;
608: } else {
609: lease->pref = ds.data[0];
610: log_debug("RCV: X-- Preference %u.",
611: (unsigned)lease->pref);
612: }
613:
614: data_string_forget(&ds, MDL);
615: }
616: delete_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
617:
618: /*
619: * Dig into recursive DHCPv6 pockets for IA_NA and contained IAADDR
620: * options.
621: */
622: if (dhc6_parse_ia_na(&lease->bindings, packet,
623: lease->options) != ISC_R_SUCCESS) {
624: /* Error conditions are logged by the caller. */
625: dhc6_lease_destroy(&lease, MDL);
626: return NULL;
627: }
628: /*
629: * Dig into recursive DHCPv6 pockets for IA_TA and contained IAADDR
630: * options.
631: */
632: if (dhc6_parse_ia_ta(&lease->bindings, packet,
633: lease->options) != ISC_R_SUCCESS) {
634: /* Error conditions are logged by the caller. */
635: dhc6_lease_destroy(&lease, MDL);
636: return NULL;
637: }
638: /*
639: * Dig into recursive DHCPv6 pockets for IA_PD and contained IAPREFIX
640: * options.
641: */
642: if (dhc6_parse_ia_pd(&lease->bindings, packet,
643: lease->options) != ISC_R_SUCCESS) {
644: /* Error conditions are logged by the caller. */
645: dhc6_lease_destroy(&lease, MDL);
646: return NULL;
647: }
648:
649: /*
650: * This is last because in the future we may want to make a different
651: * key based upon additional information from the packet (we may need
652: * to allow multiple leases in one client state per server, but we're
653: * not sure based on what additional keys now).
654: */
655: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
656: if (!evaluate_option_cache(&lease->server_id, packet, NULL, NULL,
657: lease->options, NULL, &global_scope,
658: oc, MDL) ||
659: lease->server_id.len == 0) {
660: /* This should be impossible due to validation checks earlier.
661: */
662: log_error("Invalid SERVERID option cache.");
663: dhc6_lease_destroy(&lease, MDL);
664: return NULL;
665: } else {
666: log_debug("RCV: X-- Server ID: %s",
667: print_hex_1(lease->server_id.len,
668: lease->server_id.data, 52));
669: }
670:
671: return lease;
672: }
673:
674: static isc_result_t
675: dhc6_parse_ia_na(struct dhc6_ia **pia, struct packet *packet,
676: struct option_state *options)
677: {
678: struct data_string ds;
679: struct dhc6_ia *ia;
680: struct option_cache *oc;
681: isc_result_t result;
682:
683: memset(&ds, 0, sizeof(ds));
684:
685: oc = lookup_option(&dhcpv6_universe, options, D6O_IA_NA);
686: for ( ; oc != NULL ; oc = oc->next) {
687: ia = dmalloc(sizeof(*ia), MDL);
688: if (ia == NULL) {
689: log_error("Out of memory allocating IA_NA structure.");
690: return ISC_R_NOMEMORY;
691: } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
692: options, NULL,
693: &global_scope, oc, MDL) &&
694: ds.len >= 12) {
695: memcpy(ia->iaid, ds.data, 4);
696: ia->ia_type = D6O_IA_NA;
697: ia->starts = cur_time;
698: ia->renew = getULong(ds.data + 4);
699: ia->rebind = getULong(ds.data + 8);
700:
701: log_debug("RCV: X-- IA_NA %s",
702: print_hex_1(4, ia->iaid, 59));
703: /* XXX: This should be the printed time I think. */
704: log_debug("RCV: | X-- starts %u",
705: (unsigned)ia->starts);
706: log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
707: log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
708:
709: /*
710: * RFC3315 section 22.4, discard IA_NA's that
711: * have t1 greater than t2, and both not zero.
712: * Since RFC3315 defines this behaviour, it is not
713: * an error - just normal operation.
714: *
715: * Note that RFC3315 says we MUST honor these values
716: * if they are not zero. So insane values are
717: * totally OK.
718: */
719: if ((ia->renew > 0) && (ia->rebind > 0) &&
720: (ia->renew > ia->rebind)) {
721: log_debug("RCV: | !-- INVALID renew/rebind "
722: "times, IA_NA discarded.");
723: dfree(ia, MDL);
724: data_string_forget(&ds, MDL);
725: continue;
726: }
727:
728: if (ds.len > 12) {
729: log_debug("RCV: | X-- [Options]");
730:
731: if (!option_state_allocate(&ia->options,
732: MDL)) {
733: log_error("Out of memory allocating "
734: "IA_NA option state.");
735: dfree(ia, MDL);
736: data_string_forget(&ds, MDL);
737: return ISC_R_NOMEMORY;
738: }
739:
740: if (!parse_option_buffer(ia->options,
741: ds.data + 12,
742: ds.len - 12,
743: &dhcpv6_universe)) {
744: log_error("Corrupt IA_NA options.");
745: option_state_dereference(&ia->options,
746: MDL);
747: dfree(ia, MDL);
748: data_string_forget(&ds, MDL);
749: return ISC_R_BADPARSE;
750: }
751: }
752: data_string_forget(&ds, MDL);
753:
754: if (ia->options != NULL) {
755: result = dhc6_parse_addrs(&ia->addrs, packet,
756: ia->options);
757: if (result != ISC_R_SUCCESS) {
758: option_state_dereference(&ia->options,
759: MDL);
760: dfree(ia, MDL);
761: return result;
762: }
763: }
764:
765: while (*pia != NULL)
766: pia = &(*pia)->next;
767: *pia = ia;
768: pia = &ia->next;
769: } else {
770: log_error("Invalid IA_NA option cache.");
771: dfree(ia, MDL);
772: if (ds.len != 0)
773: data_string_forget(&ds, MDL);
774: return ISC_R_UNEXPECTED;
775: }
776: }
777: delete_option(&dhcpv6_universe, options, D6O_IA_NA);
778:
779: return ISC_R_SUCCESS;
780: }
781:
782: static isc_result_t
783: dhc6_parse_ia_ta(struct dhc6_ia **pia, struct packet *packet,
784: struct option_state *options)
785: {
786: struct data_string ds;
787: struct dhc6_ia *ia;
788: struct option_cache *oc;
789: isc_result_t result;
790:
791: memset(&ds, 0, sizeof(ds));
792:
793: oc = lookup_option(&dhcpv6_universe, options, D6O_IA_TA);
794: for ( ; oc != NULL ; oc = oc->next) {
795: ia = dmalloc(sizeof(*ia), MDL);
796: if (ia == NULL) {
797: log_error("Out of memory allocating IA_TA structure.");
798: return ISC_R_NOMEMORY;
799: } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
800: options, NULL,
801: &global_scope, oc, MDL) &&
802: ds.len >= 4) {
803: memcpy(ia->iaid, ds.data, 4);
804: ia->ia_type = D6O_IA_TA;
805: ia->starts = cur_time;
806:
807: log_debug("RCV: X-- IA_TA %s",
808: print_hex_1(4, ia->iaid, 59));
809: /* XXX: This should be the printed time I think. */
810: log_debug("RCV: | X-- starts %u",
811: (unsigned)ia->starts);
812:
813: if (ds.len > 4) {
814: log_debug("RCV: | X-- [Options]");
815:
816: if (!option_state_allocate(&ia->options,
817: MDL)) {
818: log_error("Out of memory allocating "
819: "IA_TA option state.");
820: dfree(ia, MDL);
821: data_string_forget(&ds, MDL);
822: return ISC_R_NOMEMORY;
823: }
824:
825: if (!parse_option_buffer(ia->options,
826: ds.data + 4,
827: ds.len - 4,
828: &dhcpv6_universe)) {
829: log_error("Corrupt IA_TA options.");
830: option_state_dereference(&ia->options,
831: MDL);
832: dfree(ia, MDL);
833: data_string_forget(&ds, MDL);
834: return ISC_R_BADPARSE;
835: }
836: }
837: data_string_forget(&ds, MDL);
838:
839: if (ia->options != NULL) {
840: result = dhc6_parse_addrs(&ia->addrs, packet,
841: ia->options);
842: if (result != ISC_R_SUCCESS) {
843: option_state_dereference(&ia->options,
844: MDL);
845: dfree(ia, MDL);
846: return result;
847: }
848: }
849:
850: while (*pia != NULL)
851: pia = &(*pia)->next;
852: *pia = ia;
853: pia = &ia->next;
854: } else {
855: log_error("Invalid IA_TA option cache.");
856: dfree(ia, MDL);
857: if (ds.len != 0)
858: data_string_forget(&ds, MDL);
859: return ISC_R_UNEXPECTED;
860: }
861: }
862: delete_option(&dhcpv6_universe, options, D6O_IA_TA);
863:
864: return ISC_R_SUCCESS;
865: }
866:
867: static isc_result_t
868: dhc6_parse_ia_pd(struct dhc6_ia **pia, struct packet *packet,
869: struct option_state *options)
870: {
871: struct data_string ds;
872: struct dhc6_ia *ia;
873: struct option_cache *oc;
874: isc_result_t result;
875:
876: memset(&ds, 0, sizeof(ds));
877:
878: oc = lookup_option(&dhcpv6_universe, options, D6O_IA_PD);
879: for ( ; oc != NULL ; oc = oc->next) {
880: ia = dmalloc(sizeof(*ia), MDL);
881: if (ia == NULL) {
882: log_error("Out of memory allocating IA_PD structure.");
883: return ISC_R_NOMEMORY;
884: } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
885: options, NULL,
886: &global_scope, oc, MDL) &&
887: ds.len >= 12) {
888: memcpy(ia->iaid, ds.data, 4);
889: ia->ia_type = D6O_IA_PD;
890: ia->starts = cur_time;
891: ia->renew = getULong(ds.data + 4);
892: ia->rebind = getULong(ds.data + 8);
893:
894: log_debug("RCV: X-- IA_PD %s",
895: print_hex_1(4, ia->iaid, 59));
896: /* XXX: This should be the printed time I think. */
897: log_debug("RCV: | X-- starts %u",
898: (unsigned)ia->starts);
899: log_debug("RCV: | X-- t1 - renew +%u", ia->renew);
900: log_debug("RCV: | X-- t2 - rebind +%u", ia->rebind);
901:
902: /*
903: * RFC3633 section 9, discard IA_PD's that
904: * have t1 greater than t2, and both not zero.
905: * Since RFC3633 defines this behaviour, it is not
906: * an error - just normal operation.
907: */
908: if ((ia->renew > 0) && (ia->rebind > 0) &&
909: (ia->renew > ia->rebind)) {
910: log_debug("RCV: | !-- INVALID renew/rebind "
911: "times, IA_PD discarded.");
912: dfree(ia, MDL);
913: data_string_forget(&ds, MDL);
914: continue;
915: }
916:
917: if (ds.len > 12) {
918: log_debug("RCV: | X-- [Options]");
919:
920: if (!option_state_allocate(&ia->options,
921: MDL)) {
922: log_error("Out of memory allocating "
923: "IA_PD option state.");
924: dfree(ia, MDL);
925: data_string_forget(&ds, MDL);
926: return ISC_R_NOMEMORY;
927: }
928:
929: if (!parse_option_buffer(ia->options,
930: ds.data + 12,
931: ds.len - 12,
932: &dhcpv6_universe)) {
933: log_error("Corrupt IA_PD options.");
934: option_state_dereference(&ia->options,
935: MDL);
936: dfree(ia, MDL);
937: data_string_forget(&ds, MDL);
938: return ISC_R_BADPARSE;
939: }
940: }
941: data_string_forget(&ds, MDL);
942:
943: if (ia->options != NULL) {
944: result = dhc6_parse_prefixes(&ia->addrs,
945: packet,
946: ia->options);
947: if (result != ISC_R_SUCCESS) {
948: option_state_dereference(&ia->options,
949: MDL);
950: dfree(ia, MDL);
951: return result;
952: }
953: }
954:
955: while (*pia != NULL)
956: pia = &(*pia)->next;
957: *pia = ia;
958: pia = &ia->next;
959: } else {
960: log_error("Invalid IA_PD option cache.");
961: dfree(ia, MDL);
962: if (ds.len != 0)
963: data_string_forget(&ds, MDL);
964: return ISC_R_UNEXPECTED;
965: }
966: }
967: delete_option(&dhcpv6_universe, options, D6O_IA_PD);
968:
969: return ISC_R_SUCCESS;
970: }
971:
972:
973: static isc_result_t
974: dhc6_parse_addrs(struct dhc6_addr **paddr, struct packet *packet,
975: struct option_state *options)
976: {
977: struct data_string ds;
978: struct option_cache *oc;
979: struct dhc6_addr *addr;
980:
981: memset(&ds, 0, sizeof(ds));
982:
983: oc = lookup_option(&dhcpv6_universe, options, D6O_IAADDR);
984: for ( ; oc != NULL ; oc = oc->next) {
985: addr = dmalloc(sizeof(*addr), MDL);
986: if (addr == NULL) {
987: log_error("Out of memory allocating "
988: "address structure.");
989: return ISC_R_NOMEMORY;
990: } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
991: options, NULL, &global_scope,
992: oc, MDL) &&
993: (ds.len >= 24)) {
994:
995: addr->address.len = 16;
996: memcpy(addr->address.iabuf, ds.data, 16);
997: addr->starts = cur_time;
998: addr->preferred_life = getULong(ds.data + 16);
999: addr->max_life = getULong(ds.data + 20);
1000:
1001: log_debug("RCV: | | X-- IAADDR %s",
1002: piaddr(addr->address));
1003: log_debug("RCV: | | | X-- Preferred lifetime %u.",
1004: addr->preferred_life);
1005: log_debug("RCV: | | | X-- Max lifetime %u.",
1006: addr->max_life);
1007:
1008: /*
1009: * RFC 3315 section 22.6 says we must discard
1010: * addresses whose pref is later than valid.
1011: */
1012: if ((addr->preferred_life > addr->max_life)) {
1013: log_debug("RCV: | | | !-- INVALID lifetimes, "
1014: "IAADDR discarded. Check your "
1015: "server configuration.");
1016: dfree(addr, MDL);
1017: data_string_forget(&ds, MDL);
1018: continue;
1019: }
1020:
1021: /*
1022: * Fortunately this is the last recursion in the
1023: * protocol.
1024: */
1025: if (ds.len > 24) {
1026: if (!option_state_allocate(&addr->options,
1027: MDL)) {
1028: log_error("Out of memory allocating "
1029: "IAADDR option state.");
1030: dfree(addr, MDL);
1031: data_string_forget(&ds, MDL);
1032: return ISC_R_NOMEMORY;
1033: }
1034:
1035: if (!parse_option_buffer(addr->options,
1036: ds.data + 24,
1037: ds.len - 24,
1038: &dhcpv6_universe)) {
1039: log_error("Corrupt IAADDR options.");
1040: option_state_dereference(&addr->options,
1041: MDL);
1042: dfree(addr, MDL);
1043: data_string_forget(&ds, MDL);
1044: return ISC_R_BADPARSE;
1045: }
1046: }
1047:
1048: if (addr->options != NULL)
1049: log_debug("RCV: | | | X-- "
1050: "[Options]");
1051:
1052: data_string_forget(&ds, MDL);
1053:
1054: *paddr = addr;
1055: paddr = &addr->next;
1056: } else {
1057: log_error("Invalid IAADDR option cache.");
1058: dfree(addr, MDL);
1059: if (ds.len != 0)
1060: data_string_forget(&ds, MDL);
1061: return ISC_R_UNEXPECTED;
1062: }
1063: }
1064: delete_option(&dhcpv6_universe, options, D6O_IAADDR);
1065:
1066: return ISC_R_SUCCESS;
1067: }
1068:
1069: static isc_result_t
1070: dhc6_parse_prefixes(struct dhc6_addr **ppfx, struct packet *packet,
1071: struct option_state *options)
1072: {
1073: struct data_string ds;
1074: struct option_cache *oc;
1075: struct dhc6_addr *pfx;
1076:
1077: memset(&ds, 0, sizeof(ds));
1078:
1079: oc = lookup_option(&dhcpv6_universe, options, D6O_IAPREFIX);
1080: for ( ; oc != NULL ; oc = oc->next) {
1081: pfx = dmalloc(sizeof(*pfx), MDL);
1082: if (pfx == NULL) {
1083: log_error("Out of memory allocating "
1084: "prefix structure.");
1085: return ISC_R_NOMEMORY;
1086: } else if (evaluate_option_cache(&ds, packet, NULL, NULL,
1087: options, NULL, &global_scope,
1088: oc, MDL) &&
1089: (ds.len >= 25)) {
1090:
1091: pfx->preferred_life = getULong(ds.data);
1092: pfx->max_life = getULong(ds.data + 4);
1093: pfx->plen = getUChar(ds.data + 8);
1094: pfx->address.len = 16;
1095: memcpy(pfx->address.iabuf, ds.data + 9, 16);
1096: pfx->starts = cur_time;
1097:
1098: log_debug("RCV: | | X-- IAPREFIX %s/%d",
1099: piaddr(pfx->address), (int)pfx->plen);
1100: log_debug("RCV: | | | X-- Preferred lifetime %u.",
1101: pfx->preferred_life);
1102: log_debug("RCV: | | | X-- Max lifetime %u.",
1103: pfx->max_life);
1104:
1105: /* Sanity check over the prefix length */
1106: if ((pfx->plen < 4) || (pfx->plen > 128)) {
1107: log_debug("RCV: | | | !-- INVALID prefix "
1108: "length, IAPREFIX discarded. "
1109: "Check your server configuration.");
1110: dfree(pfx, MDL);
1111: data_string_forget(&ds, MDL);
1112: continue;
1113: }
1114: /*
1115: * RFC 3633 section 10 says we must discard
1116: * prefixes whose pref is later than valid.
1117: */
1118: if ((pfx->preferred_life > pfx->max_life)) {
1119: log_debug("RCV: | | | !-- INVALID lifetimes, "
1120: "IAPREFIX discarded. Check your "
1121: "server configuration.");
1122: dfree(pfx, MDL);
1123: data_string_forget(&ds, MDL);
1124: continue;
1125: }
1126:
1127: /*
1128: * Fortunately this is the last recursion in the
1129: * protocol.
1130: */
1131: if (ds.len > 25) {
1132: if (!option_state_allocate(&pfx->options,
1133: MDL)) {
1134: log_error("Out of memory allocating "
1135: "IAPREFIX option state.");
1136: dfree(pfx, MDL);
1137: data_string_forget(&ds, MDL);
1138: return ISC_R_NOMEMORY;
1139: }
1140:
1141: if (!parse_option_buffer(pfx->options,
1142: ds.data + 25,
1143: ds.len - 25,
1144: &dhcpv6_universe)) {
1145: log_error("Corrupt IAPREFIX options.");
1146: option_state_dereference(&pfx->options,
1147: MDL);
1148: dfree(pfx, MDL);
1149: data_string_forget(&ds, MDL);
1150: return ISC_R_BADPARSE;
1151: }
1152: }
1153:
1154: if (pfx->options != NULL)
1155: log_debug("RCV: | | | X-- "
1156: "[Options]");
1157:
1158: data_string_forget(&ds, MDL);
1159:
1160: *ppfx = pfx;
1161: ppfx = &pfx->next;
1162: } else {
1163: log_error("Invalid IAPREFIX option cache.");
1164: dfree(pfx, MDL);
1165: if (ds.len != 0)
1166: data_string_forget(&ds, MDL);
1167: return ISC_R_UNEXPECTED;
1168: }
1169: }
1170: delete_option(&dhcpv6_universe, options, D6O_IAPREFIX);
1171:
1172: return ISC_R_SUCCESS;
1173: }
1174:
1175: /* Clean up a lease object, deallocate all its parts, and set it to NULL. */
1176: void
1177: dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line)
1178: {
1179: struct dhc6_ia *ia, *nia;
1180: struct dhc6_lease *lease;
1181:
1182: if (src == NULL || *src == NULL) {
1183: log_error("Attempt to destroy null lease.");
1184: return;
1185: }
1186: lease = *src;
1187:
1188: if (lease->server_id.len != 0)
1189: data_string_forget(&lease->server_id, file, line);
1190:
1191: for (ia = lease->bindings ; ia != NULL ; ia = nia) {
1192: nia = ia->next;
1193:
1194: dhc6_ia_destroy(&ia, file, line);
1195: }
1196:
1197: if (lease->options != NULL)
1198: option_state_dereference(&lease->options, file, line);
1199:
1200: dfree(lease, file, line);
1201: *src = NULL;
1202: }
1203:
1204: /*
1205: * Traverse the addresses list, and destroy their contents, and NULL the
1206: * list pointer.
1207: */
1208: static void
1209: dhc6_ia_destroy(struct dhc6_ia **src, const char *file, int line)
1210: {
1211: struct dhc6_addr *addr, *naddr;
1212: struct dhc6_ia *ia;
1213:
1214: if (src == NULL || *src == NULL) {
1215: log_error("Attempt to destroy null IA.");
1216: return;
1217: }
1218: ia = *src;
1219:
1220: for (addr = ia->addrs ; addr != NULL ; addr = naddr) {
1221: naddr = addr->next;
1222:
1223: if (addr->options != NULL)
1224: option_state_dereference(&addr->options, file, line);
1225:
1226: dfree(addr, file, line);
1227: }
1228:
1229: if (ia->options != NULL)
1230: option_state_dereference(&ia->options, file, line);
1231:
1232: dfree(ia, file, line);
1233: *src = NULL;
1234: }
1235:
1236: /*
1237: * For a given lease, insert it into the tail of the lease list. Upon
1238: * finding a duplicate by server id, remove it and take over its position.
1239: */
1240: static void
1241: insert_lease(struct dhc6_lease **head, struct dhc6_lease *new)
1242: {
1243: while (*head != NULL) {
1244: if ((*head)->server_id.len == new->server_id.len &&
1245: memcmp((*head)->server_id.data, new->server_id.data,
1246: new->server_id.len) == 0) {
1247: new->next = (*head)->next;
1248: dhc6_lease_destroy(head, MDL);
1249: break;
1250: }
1251:
1252: head= &(*head)->next;
1253: }
1254:
1255: *head = new;
1256: return;
1257: }
1258:
1259: /*
1260: * Not really clear what to do here yet.
1261: */
1262: static int
1263: dhc6_score_lease(struct client_state *client, struct dhc6_lease *lease)
1264: {
1265: struct dhc6_ia *ia;
1266: struct dhc6_addr *addr;
1267: struct option **req;
1268: int i;
1269:
1270: if (lease->score)
1271: return lease->score;
1272:
1273: lease->score = 1;
1274:
1275: /* If this lease lacks a required option, dump it. */
1276: /* XXX: we should be able to cache the failure... */
1277: req = client->config->required_options;
1278: if (req != NULL) {
1279: for (i = 0 ; req[i] != NULL ; i++) {
1280: if (lookup_option(&dhcpv6_universe, lease->options,
1281: req[i]->code) == NULL) {
1282: lease->score = 0;
1283: return lease->score;
1284: }
1285: }
1286: }
1287:
1288: /* If this lease contains a requested option, improve its score. */
1289: req = client->config->requested_options;
1290: if (req != NULL) {
1291: for (i = 0 ; req[i] != NULL ; i++) {
1292: if (lookup_option(&dhcpv6_universe, lease->options,
1293: req[i]->code) != NULL)
1294: lease->score++;
1295: }
1296: }
1297:
1298: for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
1299: lease->score += 50;
1300:
1301: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
1302: lease->score += 100;
1303: }
1304: }
1305:
1306: return lease->score;
1307: }
1308:
1309: /*
1310: * start_init6() kicks off the process, transmitting a packet and
1311: * scheduling a retransmission event.
1312: */
1313: void
1314: start_init6(struct client_state *client)
1315: {
1316: struct timeval tv;
1317:
1318: log_debug("PRC: Soliciting for leases (INIT).");
1319: client->state = S_INIT;
1320:
1321: /* Initialize timers, RFC3315 section 17.1.2. */
1322: client->IRT = SOL_TIMEOUT * 100;
1323: client->MRT = SOL_MAX_RT * 100;
1324: client->MRC = 0;
1325: /* Default is 0 (no max) but -1 changes this. */
1326: if (!onetry)
1327: client->MRD = 0;
1328: else
1329: client->MRD = client->config->timeout;
1330:
1331: dhc6_retrans_init(client);
1332:
1333: /*
1334: * RFC3315 section 17.1.2 goes out of its way:
1335: * Also, the first RT MUST be selected to be strictly greater than IRT
1336: * by choosing RAND to be strictly greater than 0.
1337: */
1338: /* if RAND < 0 then RAND = -RAND */
1339: if (client->RT <= client->IRT)
1340: client->RT = client->IRT + (client->IRT - client->RT);
1341: /* if RAND == 0 then RAND = 1 */
1342: if (client->RT <= client->IRT)
1343: client->RT = client->IRT + 1;
1344:
1345: client->v6_handler = init_handler;
1346:
1347: /*
1348: * RFC3315 section 17.1.2 says we MUST start the first packet
1349: * between 0 and SOL_MAX_DELAY seconds. The good news is
1350: * SOL_MAX_DELAY is 1.
1351: */
1352: tv.tv_sec = cur_tv.tv_sec;
1353: tv.tv_usec = cur_tv.tv_usec;
1354: tv.tv_usec += (random() % (SOL_MAX_DELAY * 100)) * 10000;
1355: if (tv.tv_usec >= 1000000) {
1356: tv.tv_sec += 1;
1357: tv.tv_usec -= 1000000;
1358: }
1359: add_timeout(&tv, do_init6, client, NULL, NULL);
1360:
1361: if (nowait)
1362: go_daemon();
1363: }
1364:
1365: /*
1366: * start_info_request6() kicks off the process, transmitting an info
1367: * request packet and scheduling a retransmission event.
1368: */
1369: void
1370: start_info_request6(struct client_state *client)
1371: {
1372: struct timeval tv;
1373:
1374: log_debug("PRC: Requesting information (INIT).");
1375: client->state = S_INIT;
1376:
1377: /* Initialize timers, RFC3315 section 18.1.5. */
1378: client->IRT = INF_TIMEOUT * 100;
1379: client->MRT = INF_MAX_RT * 100;
1380: client->MRC = 0;
1381: /* Default is 0 (no max) but -1 changes this. */
1382: if (!onetry)
1383: client->MRD = 0;
1384: else
1385: client->MRD = client->config->timeout;
1386:
1387: dhc6_retrans_init(client);
1388:
1389: client->v6_handler = info_request_handler;
1390:
1391: /*
1392: * RFC3315 section 18.1.5 says we MUST start the first packet
1393: * between 0 and INF_MAX_DELAY seconds. The good news is
1394: * INF_MAX_DELAY is 1.
1395: */
1396: tv.tv_sec = cur_tv.tv_sec;
1397: tv.tv_usec = cur_tv.tv_usec;
1398: tv.tv_usec += (random() % (INF_MAX_DELAY * 100)) * 10000;
1399: if (tv.tv_usec >= 1000000) {
1400: tv.tv_sec += 1;
1401: tv.tv_usec -= 1000000;
1402: }
1403: add_timeout(&tv, do_info_request6, client, NULL, NULL);
1404:
1405: if (nowait)
1406: go_daemon();
1407: }
1408:
1409: /*
1410: * start_confirm6() kicks off an "init-reboot" version of the process, at
1411: * startup to find out if old bindings are 'fair' and at runtime whenever
1412: * a link cycles state we'll eventually want to do this.
1413: */
1414: void
1415: start_confirm6(struct client_state *client)
1416: {
1417: struct timeval tv;
1418:
1419: /* If there is no active lease, there is nothing to check. */
1420: if ((client->active_lease == NULL) ||
1421: !active_prefix(client) ||
1422: client->active_lease->released) {
1423: start_init6(client);
1424: return;
1425: }
1426:
1427: log_debug("PRC: Confirming active lease (INIT-REBOOT).");
1428: client->state = S_REBOOTING;
1429:
1430: /* Initialize timers, RFC3315 section 17.1.3. */
1431: client->IRT = CNF_TIMEOUT * 100;
1432: client->MRT = CNF_MAX_RT * 100;
1433: client->MRC = 0;
1434: client->MRD = CNF_MAX_RD;
1435:
1436: dhc6_retrans_init(client);
1437:
1438: client->v6_handler = reply_handler;
1439:
1440: /*
1441: * RFC3315 section 18.1.2 says we MUST start the first packet
1442: * between 0 and CNF_MAX_DELAY seconds. The good news is
1443: * CNF_MAX_DELAY is 1.
1444: */
1445: tv.tv_sec = cur_tv.tv_sec;
1446: tv.tv_usec = cur_tv.tv_usec;
1447: tv.tv_usec += (random() % (CNF_MAX_DELAY * 100)) * 10000;
1448: if (tv.tv_usec >= 1000000) {
1449: tv.tv_sec += 1;
1450: tv.tv_usec -= 1000000;
1451: }
1452: if (wanted_ia_pd != 0) {
1453: client->state = S_REBINDING;
1454: client->refresh_type = DHCPV6_REBIND;
1455: add_timeout(&tv, do_refresh6, client, NULL, NULL);
1456: } else
1457: add_timeout(&tv, do_confirm6, client, NULL, NULL);
1458: }
1459:
1460: /*
1461: * check_timing6() check on the timing for sending a v6 message
1462: * and then do the basic initialization for a v6 message.
1463: */
1464: #define CHK_TIM_SUCCESS 0
1465: #define CHK_TIM_MRC_EXCEEDED 1
1466: #define CHK_TIM_MRD_EXCEEDED 2
1467: #define CHK_TIM_ALLOC_FAILURE 3
1468:
1469: int
1470: check_timing6 (struct client_state *client, u_int8_t msg_type,
1471: char *msg_str, struct dhc6_lease *lease,
1472: struct data_string *ds)
1473: {
1474: struct timeval elapsed;
1475:
1476: /*
1477: * Start_time starts at the first transmission.
1478: */
1479: if (client->txcount == 0) {
1480: client->start_time.tv_sec = cur_tv.tv_sec;
1481: client->start_time.tv_usec = cur_tv.tv_usec;
1482: } else if ((client->MRC != 0) && (client->txcount > client->MRC)) {
1483: log_info("Max retransmission count exceeded.");
1484: return(CHK_TIM_MRC_EXCEEDED);
1485: }
1486:
1487: /* elapsed = cur - start */
1488: elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
1489: elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
1490: if (elapsed.tv_usec < 0) {
1491: elapsed.tv_sec -= 1;
1492: elapsed.tv_usec += 1000000;
1493: }
1494:
1495: /* Check if finished (-1 argument). */
1496: if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
1497: log_info("Max retransmission duration exceeded.");
1498: return(CHK_TIM_MRD_EXCEEDED);
1499: }
1500:
1501: memset(ds, 0, sizeof(*ds));
1502: if (!buffer_allocate(&(ds->buffer), 4, MDL)) {
1503: log_error("Unable to allocate memory for %s.", msg_str);
1504: return(CHK_TIM_ALLOC_FAILURE);
1505: }
1506: ds->data = ds->buffer->data;
1507: ds->len = 4;
1508:
1509: ds->buffer->data[0] = msg_type;
1510: memcpy(ds->buffer->data + 1, client->dhcpv6_transaction_id, 3);
1511:
1512: /* Form an elapsed option. */
1513: /* Maximum value is 65535 1/100s coded as 0xffff. */
1514: if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
1515: ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
1516: client->elapsed = 0xffff;
1517: } else {
1518: client->elapsed = elapsed.tv_sec * 100;
1519: client->elapsed += elapsed.tv_usec / 10000;
1520: }
1521:
1522: if (client->elapsed == 0)
1523: log_debug("XMT: Forming %s, 0 ms elapsed.", msg_str);
1524: else
1525: log_debug("XMT: Forming %s, %u0 ms elapsed.", msg_str,
1526: (unsigned)client->elapsed);
1527:
1528: client->elapsed = htons(client->elapsed);
1529:
1530: make_client6_options(client, &client->sent_options, lease, msg_type);
1531:
1532: return(CHK_TIM_SUCCESS);
1533: }
1534:
1535: /*
1536: * do_init6() marshals and transmits a solicit.
1537: */
1538: void
1539: do_init6(void *input)
1540: {
1541: struct client_state *client;
1542: struct dhc6_ia *old_ia;
1543: struct dhc6_addr *old_addr;
1544: struct data_string ds;
1545: struct data_string ia;
1546: struct data_string addr;
1547: struct timeval tv;
1548: u_int32_t t1, t2;
1549: int i, idx, len, send_ret;
1550:
1551: client = input;
1552:
1553: /*
1554: * In RFC3315 section 17.1.2, the retransmission timer is
1555: * used as the selecting timer.
1556: */
1557: if (client->advertised_leases != NULL) {
1558: start_selecting6(client);
1559: return;
1560: }
1561:
1562: switch(check_timing6(client, DHCPV6_SOLICIT, "Solicit", NULL, &ds)) {
1563: case CHK_TIM_MRC_EXCEEDED:
1564: case CHK_TIM_ALLOC_FAILURE:
1565: return;
1566: case CHK_TIM_MRD_EXCEEDED:
1567: client->state = S_STOPPED;
1568: if (client->active_lease != NULL) {
1569: dhc6_lease_destroy(&client->active_lease, MDL);
1570: client->active_lease = NULL;
1571: }
1572: /* Stop if and only if this is the last client. */
1573: if (stopping_finished())
1574: exit(2);
1575: return;
1576: }
1577:
1578: /*
1579: * Fetch any configured 'sent' options (includes DUID) in wire format.
1580: */
1581: dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
1582: NULL, client->sent_options, &global_scope,
1583: &dhcpv6_universe);
1584:
1585: /* Use a specific handler with rapid-commit. */
1586: if (lookup_option(&dhcpv6_universe, client->sent_options,
1587: D6O_RAPID_COMMIT) != NULL) {
1588: client->v6_handler = rapid_commit_handler;
1589: }
1590:
1591: /* Append IA_NA. */
1592: for (i = 0; i < wanted_ia_na; i++) {
1593: /*
1594: * XXX: maybe the IA_NA('s) should be put into the sent_options
1595: * cache. They'd have to be pulled down as they also contain
1596: * different option caches in the same universe...
1597: */
1598: memset(&ia, 0, sizeof(ia));
1599: if (!buffer_allocate(&ia.buffer, 12, MDL)) {
1600: log_error("Unable to allocate memory for IA_NA.");
1601: data_string_forget(&ds, MDL);
1602: return;
1603: }
1604: ia.data = ia.buffer->data;
1605: ia.len = 12;
1606:
1607: /*
1608: * A simple IAID is the last 4 bytes
1609: * of the hardware address.
1610: */
1611: if (client->interface->hw_address.hlen > 4) {
1612: idx = client->interface->hw_address.hlen - 4;
1613: len = 4;
1614: } else {
1615: idx = 0;
1616: len = client->interface->hw_address.hlen;
1617: }
1618: memcpy(ia.buffer->data,
1619: client->interface->hw_address.hbuf + idx,
1620: len);
1621: if (i)
1622: ia.buffer->data[3] += i;
1623:
1624: t1 = client->config->requested_lease / 2;
1625: t2 = t1 + (t1 / 2);
1626: putULong(ia.buffer->data + 4, t1);
1627: putULong(ia.buffer->data + 8, t2);
1628:
1629: log_debug("XMT: X-- IA_NA %s",
1630: print_hex_1(4, ia.buffer->data, 55));
1631: log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
1632: log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
1633:
1634: if ((client->active_lease != NULL) &&
1635: ((old_ia = find_ia(client->active_lease->bindings,
1636: D6O_IA_NA,
1637: (char *)ia.buffer->data)) != NULL)) {
1638: /*
1639: * For each address in the old IA_NA,
1640: * request a binding.
1641: */
1642: memset(&addr, 0, sizeof(addr));
1643: for (old_addr = old_ia->addrs ; old_addr != NULL ;
1644: old_addr = old_addr->next) {
1645: if (old_addr->address.len != 16) {
1646: log_error("Invalid IPv6 address "
1647: "length %d. "
1648: "Ignoring. (%s:%d)",
1649: old_addr->address.len,
1650: MDL);
1651: continue;
1652: }
1653:
1654: if (!buffer_allocate(&addr.buffer, 24, MDL)) {
1655: log_error("Unable to allocate memory "
1656: "for IAADDR.");
1657: data_string_forget(&ia, MDL);
1658: data_string_forget(&ds, MDL);
1659: return;
1660: }
1661: addr.data = addr.buffer->data;
1662: addr.len = 24;
1663:
1664: memcpy(addr.buffer->data,
1665: old_addr->address.iabuf,
1666: 16);
1667:
1668: t1 = client->config->requested_lease;
1669: t2 = t1 + (t1 / 2);
1670: putULong(addr.buffer->data + 16, t1);
1671: putULong(addr.buffer->data + 20, t2);
1672:
1673: log_debug("XMT: | X-- Request address %s.",
1674: piaddr(old_addr->address));
1675: log_debug("XMT: | | X-- Request "
1676: "preferred in +%u",
1677: (unsigned)t1);
1678: log_debug("XMT: | | X-- Request valid "
1679: "in +%u",
1680: (unsigned)t2);
1681:
1682: append_option(&ia, &dhcpv6_universe,
1683: iaaddr_option,
1684: &addr);
1685:
1686: data_string_forget(&addr, MDL);
1687: }
1688: }
1689:
1690: append_option(&ds, &dhcpv6_universe, ia_na_option, &ia);
1691: data_string_forget(&ia, MDL);
1692: }
1693:
1694: /* Append IA_TA. */
1695: for (i = 0; i < wanted_ia_ta; i++) {
1696: /*
1697: * XXX: maybe the IA_TA('s) should be put into the sent_options
1698: * cache. They'd have to be pulled down as they also contain
1699: * different option caches in the same universe...
1700: */
1701: memset(&ia, 0, sizeof(ia));
1702: if (!buffer_allocate(&ia.buffer, 4, MDL)) {
1703: log_error("Unable to allocate memory for IA_TA.");
1704: data_string_forget(&ds, MDL);
1705: return;
1706: }
1707: ia.data = ia.buffer->data;
1708: ia.len = 4;
1709:
1710: /*
1711: * A simple IAID is the last 4 bytes
1712: * of the hardware address.
1713: */
1714: if (client->interface->hw_address.hlen > 4) {
1715: idx = client->interface->hw_address.hlen - 4;
1716: len = 4;
1717: } else {
1718: idx = 0;
1719: len = client->interface->hw_address.hlen;
1720: }
1721: memcpy(ia.buffer->data,
1722: client->interface->hw_address.hbuf + idx,
1723: len);
1724: if (i)
1725: ia.buffer->data[3] += i;
1726:
1727: log_debug("XMT: X-- IA_TA %s",
1728: print_hex_1(4, ia.buffer->data, 55));
1729:
1730: if ((client->active_lease != NULL) &&
1731: ((old_ia = find_ia(client->active_lease->bindings,
1732: D6O_IA_TA,
1733: (char *)ia.buffer->data)) != NULL)) {
1734: /*
1735: * For each address in the old IA_TA,
1736: * request a binding.
1737: */
1738: memset(&addr, 0, sizeof(addr));
1739: for (old_addr = old_ia->addrs ; old_addr != NULL ;
1740: old_addr = old_addr->next) {
1741: if (old_addr->address.len != 16) {
1742: log_error("Invalid IPv6 address "
1743: "length %d. "
1744: "Ignoring. (%s:%d)",
1745: old_addr->address.len,
1746: MDL);
1747: continue;
1748: }
1749:
1750: if (!buffer_allocate(&addr.buffer, 24, MDL)) {
1751: log_error("Unable to allocate memory "
1752: "for IAADDR.");
1753: data_string_forget(&ia, MDL);
1754: data_string_forget(&ds, MDL);
1755: return;
1756: }
1757: addr.data = addr.buffer->data;
1758: addr.len = 24;
1759:
1760: memcpy(addr.buffer->data,
1761: old_addr->address.iabuf,
1762: 16);
1763:
1764: t1 = client->config->requested_lease;
1765: t2 = t1 + (t1 / 2);
1766: putULong(addr.buffer->data + 16, t1);
1767: putULong(addr.buffer->data + 20, t2);
1768:
1769: log_debug("XMT: | X-- Request address %s.",
1770: piaddr(old_addr->address));
1771: log_debug("XMT: | | X-- Request "
1772: "preferred in +%u",
1773: (unsigned)t1);
1774: log_debug("XMT: | | X-- Request valid "
1775: "in +%u",
1776: (unsigned)t2);
1777:
1778: append_option(&ia, &dhcpv6_universe,
1779: iaaddr_option,
1780: &addr);
1781:
1782: data_string_forget(&addr, MDL);
1783: }
1784: }
1785:
1786: append_option(&ds, &dhcpv6_universe, ia_ta_option, &ia);
1787: data_string_forget(&ia, MDL);
1788: }
1789:
1790: /* Append IA_PD. */
1791: for (i = 0; i < wanted_ia_pd; i++) {
1792: /*
1793: * XXX: maybe the IA_PD('s) should be put into the sent_options
1794: * cache. They'd have to be pulled down as they also contain
1795: * different option caches in the same universe...
1796: */
1797: memset(&ia, 0, sizeof(ia));
1798: if (!buffer_allocate(&ia.buffer, 12, MDL)) {
1799: log_error("Unable to allocate memory for IA_PD.");
1800: data_string_forget(&ds, MDL);
1801: return;
1802: }
1803: ia.data = ia.buffer->data;
1804: ia.len = 12;
1805:
1806: /*
1807: * A simple IAID is the last 4 bytes
1808: * of the hardware address.
1809: */
1810: if (client->interface->hw_address.hlen > 4) {
1811: idx = client->interface->hw_address.hlen - 4;
1812: len = 4;
1813: } else {
1814: idx = 0;
1815: len = client->interface->hw_address.hlen;
1816: }
1817: memcpy(ia.buffer->data,
1818: client->interface->hw_address.hbuf + idx,
1819: len);
1820: if (i)
1821: ia.buffer->data[3] += i;
1822:
1823: t1 = client->config->requested_lease / 2;
1824: t2 = t1 + (t1 / 2);
1825: putULong(ia.buffer->data + 4, t1);
1826: putULong(ia.buffer->data + 8, t2);
1827:
1828: log_debug("XMT: X-- IA_PD %s",
1829: print_hex_1(4, ia.buffer->data, 55));
1830: log_debug("XMT: | X-- Request renew in +%u", (unsigned)t1);
1831: log_debug("XMT: | X-- Request rebind in +%u", (unsigned)t2);
1832:
1833: if ((client->active_lease != NULL) &&
1834: ((old_ia = find_ia(client->active_lease->bindings,
1835: D6O_IA_PD,
1836: (char *)ia.buffer->data)) != NULL)) {
1837: /*
1838: * For each prefix in the old IA_PD,
1839: * request a binding.
1840: */
1841: memset(&addr, 0, sizeof(addr));
1842: for (old_addr = old_ia->addrs ; old_addr != NULL ;
1843: old_addr = old_addr->next) {
1844: if (old_addr->address.len != 16) {
1845: log_error("Invalid IPv6 prefix, "
1846: "Ignoring. (%s:%d)",
1847: MDL);
1848: continue;
1849: }
1850:
1851: if (!buffer_allocate(&addr.buffer, 25, MDL)) {
1852: log_error("Unable to allocate memory "
1853: "for IAPREFIX.");
1854: data_string_forget(&ia, MDL);
1855: data_string_forget(&ds, MDL);
1856: return;
1857: }
1858: addr.data = addr.buffer->data;
1859: addr.len = 25;
1860:
1861: t1 = client->config->requested_lease;
1862: t2 = t1 + (t1 / 2);
1863: putULong(addr.buffer->data, t1);
1864: putULong(addr.buffer->data + 4, t2);
1865:
1866: putUChar(addr.buffer->data + 8,
1867: old_addr->plen);
1868: memcpy(addr.buffer->data + 9,
1869: old_addr->address.iabuf,
1870: 16);
1871:
1872: log_debug("XMT: | X-- Request prefix %s/%u.",
1873: piaddr(old_addr->address),
1874: (unsigned) old_addr->plen);
1875: log_debug("XMT: | | X-- Request "
1876: "preferred in +%u",
1877: (unsigned)t1);
1878: log_debug("XMT: | | X-- Request valid "
1879: "in +%u",
1880: (unsigned)t2);
1881:
1882: append_option(&ia, &dhcpv6_universe,
1883: iaprefix_option,
1884: &addr);
1885:
1886: data_string_forget(&addr, MDL);
1887: }
1888: }
1889:
1890: append_option(&ds, &dhcpv6_universe, ia_pd_option, &ia);
1891: data_string_forget(&ia, MDL);
1892: }
1893:
1894: /* Transmit and wait. */
1895:
1896: log_info("XMT: Solicit on %s, interval %ld0ms.",
1897: client->name ? client->name : client->interface->name,
1898: (long int)client->RT);
1899:
1900: send_ret = send_packet6(client->interface,
1901: ds.data, ds.len, &DHCPv6DestAddr);
1902: if (send_ret != ds.len) {
1903: log_error("dhc6: send_packet6() sent %d of %d bytes",
1904: send_ret, ds.len);
1905: }
1906:
1907: data_string_forget(&ds, MDL);
1908:
1909: /* Wait RT */
1910: tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
1911: tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
1912: if (tv.tv_usec >= 1000000) {
1913: tv.tv_sec += 1;
1914: tv.tv_usec -= 1000000;
1915: }
1916: add_timeout(&tv, do_init6, client, NULL, NULL);
1917:
1918: dhc6_retrans_advance(client);
1919: }
1920:
1921: /* do_info_request6() marshals and transmits an information-request. */
1922: void
1923: do_info_request6(void *input)
1924: {
1925: struct client_state *client;
1926: struct data_string ds;
1927: struct timeval tv;
1928: int send_ret;
1929:
1930: client = input;
1931:
1932: switch(check_timing6(client, DHCPV6_INFORMATION_REQUEST,
1933: "Info-Request", NULL, &ds)) {
1934: case CHK_TIM_MRC_EXCEEDED:
1935: case CHK_TIM_ALLOC_FAILURE:
1936: return;
1937: case CHK_TIM_MRD_EXCEEDED:
1938: exit(2);
1939: case CHK_TIM_SUCCESS:
1940: break;
1941: }
1942:
1943: /* Fetch any configured 'sent' options (includes DUID) in wire format.
1944: */
1945: dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
1946: NULL, client->sent_options, &global_scope,
1947: &dhcpv6_universe);
1948:
1949: /* Transmit and wait. */
1950:
1951: log_info("XMT: Info-Request on %s, interval %ld0ms.",
1952: client->name ? client->name : client->interface->name,
1953: (long int)client->RT);
1954:
1955: send_ret = send_packet6(client->interface,
1956: ds.data, ds.len, &DHCPv6DestAddr);
1957: if (send_ret != ds.len) {
1958: log_error("dhc6: send_packet6() sent %d of %d bytes",
1959: send_ret, ds.len);
1960: }
1961:
1962: data_string_forget(&ds, MDL);
1963:
1964: /* Wait RT */
1965: tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
1966: tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
1967: if (tv.tv_usec >= 1000000) {
1968: tv.tv_sec += 1;
1969: tv.tv_usec -= 1000000;
1970: }
1971: add_timeout(&tv, do_info_request6, client, NULL, NULL);
1972:
1973: dhc6_retrans_advance(client);
1974: }
1975:
1976: /* do_confirm6() creates a Confirm packet and transmits it. This function
1977: * is called on every timeout to (re)transmit.
1978: */
1979: void
1980: do_confirm6(void *input)
1981: {
1982: struct client_state *client;
1983: struct data_string ds;
1984: int send_ret;
1985: struct timeval tv;
1986:
1987: client = input;
1988:
1989: if (client->active_lease == NULL)
1990: log_fatal("Impossible condition at %s:%d.", MDL);
1991:
1992: /* In section 17.1.3, it is said:
1993: *
1994: * If the client receives no responses before the message
1995: * transmission process terminates, as described in section 14,
1996: * the client SHOULD continue to use any IP addresses, using the
1997: * last known lifetimes for those addresses, and SHOULD continue
1998: * to use any other previously obtained configuration parameters.
1999: *
2000: * So if confirm times out, we go active.
2001: *
2002: * XXX: Should we reduce all IA's t1 to 0, so that we renew and
2003: * stick there until we get a reply?
2004: */
2005:
2006: switch(check_timing6(client, DHCPV6_CONFIRM, "Confirm",
2007: client->active_lease, &ds)) {
2008: case CHK_TIM_MRC_EXCEEDED:
2009: case CHK_TIM_MRD_EXCEEDED:
2010: start_bound(client);
2011: return;
2012: case CHK_TIM_ALLOC_FAILURE:
2013: return;
2014: case CHK_TIM_SUCCESS:
2015: break;
2016: }
2017:
2018: /* Fetch any configured 'sent' options (includes DUID') in wire format.
2019: */
2020: dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
2021: client->sent_options, &global_scope,
2022: &dhcpv6_universe);
2023:
2024: /* Append IA's. */
2025: if (wanted_ia_na &&
2026: dhc6_add_ia_na(client, &ds, client->active_lease,
2027: DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
2028: data_string_forget(&ds, MDL);
2029: return;
2030: }
2031: if (wanted_ia_ta &&
2032: dhc6_add_ia_ta(client, &ds, client->active_lease,
2033: DHCPV6_CONFIRM) != ISC_R_SUCCESS) {
2034: data_string_forget(&ds, MDL);
2035: return;
2036: }
2037:
2038: /* Transmit and wait. */
2039:
2040: log_info("XMT: Confirm on %s, interval %ld0ms.",
2041: client->name ? client->name : client->interface->name,
2042: (long int)client->RT);
2043:
2044: send_ret = send_packet6(client->interface, ds.data, ds.len,
2045: &DHCPv6DestAddr);
2046: if (send_ret != ds.len) {
2047: log_error("dhc6: sendpacket6() sent %d of %d bytes",
2048: send_ret, ds.len);
2049: }
2050:
2051: data_string_forget(&ds, MDL);
2052:
2053: /* Wait RT */
2054: tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
2055: tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
2056: if (tv.tv_usec >= 1000000) {
2057: tv.tv_sec += 1;
2058: tv.tv_usec -= 1000000;
2059: }
2060: add_timeout(&tv, do_confirm6, client, NULL, NULL);
2061:
2062: dhc6_retrans_advance(client);
2063: }
2064:
2065: /*
2066: * Release addresses.
2067: */
2068: void
2069: start_release6(struct client_state *client)
2070: {
2071: /* Cancel any pending transmissions */
2072: cancel_timeout(do_confirm6, client);
2073: cancel_timeout(do_select6, client);
2074: cancel_timeout(do_refresh6, client);
2075: cancel_timeout(do_release6, client);
2076: client->state = S_STOPPED;
2077:
2078: /*
2079: * It is written: "The client MUST NOT use any of the addresses it
2080: * is releasing as the source address in the Release message or in
2081: * any subsequently transmitted message." So unconfigure now.
2082: */
2083: unconfigure6(client, "RELEASE6");
2084:
2085: /* Note this in the lease file. */
2086: if (client->active_lease == NULL)
2087: return;
2088: client->active_lease->released = ISC_TRUE;
2089: write_client6_lease(client, client->active_lease, 0, 1);
2090:
2091: /* Set timers per RFC3315 section 18.1.6. */
2092: client->IRT = REL_TIMEOUT * 100;
2093: client->MRT = 0;
2094: client->MRC = REL_MAX_RC;
2095: client->MRD = 0;
2096:
2097: dhc6_retrans_init(client);
2098: client->v6_handler = reply_handler;
2099:
2100: do_release6(client);
2101: }
2102: /*
2103: * do_release6() creates a Release packet and transmits it.
2104: */
2105: static void
2106: do_release6(void *input)
2107: {
2108: struct client_state *client;
2109: struct data_string ds;
2110: int send_ret;
2111: struct timeval tv;
2112:
2113: client = input;
2114:
2115: if ((client->active_lease == NULL) || !active_prefix(client))
2116: return;
2117:
2118: switch(check_timing6(client, DHCPV6_RELEASE, "Release",
2119: client->active_lease, &ds)) {
2120: case CHK_TIM_MRC_EXCEEDED:
2121: case CHK_TIM_ALLOC_FAILURE:
2122: case CHK_TIM_MRD_EXCEEDED:
2123: goto release_done;
2124: case CHK_TIM_SUCCESS:
2125: break;
2126: }
2127:
2128: /*
2129: * Don't use unicast as we don't know if we still have an
2130: * available address with enough scope.
2131: */
2132:
2133: dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
2134: client->sent_options, &global_scope,
2135: &dhcpv6_universe);
2136:
2137: /* Append IA's (but don't release temporary addresses). */
2138: if (wanted_ia_na &&
2139: dhc6_add_ia_na(client, &ds, client->active_lease,
2140: DHCPV6_RELEASE) != ISC_R_SUCCESS) {
2141: data_string_forget(&ds, MDL);
2142: goto release_done;
2143: }
2144: if (wanted_ia_pd &&
2145: dhc6_add_ia_pd(client, &ds, client->active_lease,
2146: DHCPV6_RELEASE) != ISC_R_SUCCESS) {
2147: data_string_forget(&ds, MDL);
2148: goto release_done;
2149: }
2150:
2151: /* Transmit and wait. */
2152: log_info("XMT: Release on %s, interval %ld0ms.",
2153: client->name ? client->name : client->interface->name,
2154: (long int)client->RT);
2155:
2156: send_ret = send_packet6(client->interface, ds.data, ds.len,
2157: &DHCPv6DestAddr);
2158: if (send_ret != ds.len) {
2159: log_error("dhc6: sendpacket6() sent %d of %d bytes",
2160: send_ret, ds.len);
2161: }
2162:
2163: data_string_forget(&ds, MDL);
2164:
2165: /* Wait RT */
2166: tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
2167: tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
2168: if (tv.tv_usec >= 1000000) {
2169: tv.tv_sec += 1;
2170: tv.tv_usec -= 1000000;
2171: }
2172: add_timeout(&tv, do_release6, client, NULL, NULL);
2173: dhc6_retrans_advance(client);
2174: return;
2175:
2176: release_done:
2177: dhc6_lease_destroy(&client->active_lease, MDL);
2178: client->active_lease = NULL;
2179: if (stopping_finished())
2180: exit(0);
2181: }
2182:
2183: /* status_log() just puts a status code into displayable form and logs it
2184: * to info level.
2185: */
2186: static void
2187: status_log(int code, const char *scope, const char *additional, int len)
2188: {
2189: const char *msg = NULL;
2190:
2191: switch(code) {
2192: case STATUS_Success:
2193: msg = "Success";
2194: break;
2195:
2196: case STATUS_UnspecFail:
2197: msg = "UnspecFail";
2198: break;
2199:
2200: case STATUS_NoAddrsAvail:
2201: msg = "NoAddrsAvail";
2202: break;
2203:
2204: case STATUS_NoBinding:
2205: msg = "NoBinding";
2206: break;
2207:
2208: case STATUS_NotOnLink:
2209: msg = "NotOnLink";
2210: break;
2211:
2212: case STATUS_UseMulticast:
2213: msg = "UseMulticast";
2214: break;
2215:
2216: case STATUS_NoPrefixAvail:
2217: msg = "NoPrefixAvail";
2218: break;
2219:
2220: default:
2221: msg = "UNKNOWN";
2222: break;
2223: }
2224:
2225: if (len > 0)
2226: log_info("%s status code %s: %s", scope, msg,
2227: print_hex_1(len,
2228: (const unsigned char *)additional, 50));
2229: else
2230: log_info("%s status code %s.", scope, msg);
2231: }
2232:
2233: /* Acquire a status code.
2234: */
2235: static isc_result_t
2236: dhc6_get_status_code(struct option_state *options, unsigned *code,
2237: struct data_string *msg)
2238: {
2239: struct option_cache *oc;
2240: struct data_string ds;
2241: isc_result_t rval = ISC_R_SUCCESS;
2242:
2243: if ((options == NULL) || (code == NULL))
2244: return ISC_R_INVALIDARG;
2245:
2246: if ((msg != NULL) && (msg->len != 0))
2247: return ISC_R_INVALIDARG;
2248:
2249: memset(&ds, 0, sizeof(ds));
2250:
2251: /* Assume success if there is no option. */
2252: *code = STATUS_Success;
2253:
2254: oc = lookup_option(&dhcpv6_universe, options, D6O_STATUS_CODE);
2255: if ((oc != NULL) &&
2256: evaluate_option_cache(&ds, NULL, NULL, NULL, options,
2257: NULL, &global_scope, oc, MDL)) {
2258: if (ds.len < 2) {
2259: log_error("Invalid status code length %d.", ds.len);
2260: rval = ISC_R_FORMERR;
2261: } else
2262: *code = getUShort(ds.data);
2263:
2264: if ((msg != NULL) && (ds.len > 2)) {
2265: data_string_copy(msg, &ds, MDL);
2266: msg->data += 2;
2267: msg->len -= 2;
2268: }
2269:
2270: data_string_forget(&ds, MDL);
2271: return rval;
2272: }
2273:
2274: return ISC_R_NOTFOUND;
2275: }
2276:
2277: /* Look at status codes in an advertise, and reform the return value.
2278: */
2279: static isc_result_t
2280: dhc6_check_status(isc_result_t rval, struct option_state *options,
2281: const char *scope, unsigned *code)
2282: {
2283: struct data_string msg;
2284: isc_result_t status;
2285:
2286: if ((scope == NULL) || (code == NULL))
2287: return ISC_R_INVALIDARG;
2288:
2289: /* If we don't find a code, we assume success. */
2290: *code = STATUS_Success;
2291:
2292: /* If there is no options cache, then there is no code. */
2293: if (options != NULL) {
2294: memset(&msg, 0, sizeof(msg));
2295: status = dhc6_get_status_code(options, code, &msg);
2296:
2297: if (status == ISC_R_SUCCESS) {
2298: status_log(*code, scope, (char *)msg.data, msg.len);
2299: data_string_forget(&msg, MDL);
2300:
2301: if (*code != STATUS_Success)
2302: rval = ISC_R_FAILURE;
2303:
2304: } else if (status != ISC_R_NOTFOUND)
2305: rval = status;
2306: }
2307:
2308: return rval;
2309: }
2310:
2311: /* Look in the packet, any IA's, and any IAADDR's within those IA's to find
2312: * status code options that are not SUCCESS.
2313: */
2314: static isc_result_t
2315: dhc6_check_advertise(struct dhc6_lease *lease)
2316: {
2317: struct dhc6_ia *ia;
2318: struct dhc6_addr *addr;
2319: isc_result_t rval = ISC_R_SUCCESS;
2320: int have_addrs = ISC_FALSE;
2321: unsigned code;
2322: const char *scope;
2323:
2324: rval = dhc6_check_status(rval, lease->options, "message", &code);
2325:
2326: for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
2327: switch (ia->ia_type) {
2328: case D6O_IA_NA:
2329: scope = "IA_NA";
2330: break;
2331: case D6O_IA_TA:
2332: scope = "IA_TA";
2333: break;
2334: case D6O_IA_PD:
2335: scope = "IA_PD";
2336: break;
2337: default:
2338: log_error("dhc6_check_advertise: no type.");
2339: return ISC_R_FAILURE;
2340: }
2341: rval = dhc6_check_status(rval, ia->options, scope, &code);
2342:
2343: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
2344: if (ia->ia_type != D6O_IA_PD)
2345: scope = "IAADDR";
2346: else
2347: scope = "IAPREFIX";
2348: rval = dhc6_check_status(rval, addr->options,
2349: scope, &code);
2350: have_addrs = ISC_TRUE;
2351: }
2352: }
2353:
2354: if (have_addrs != ISC_TRUE)
2355: rval = ISC_R_ADDRNOTAVAIL;
2356:
2357: return rval;
2358: }
2359:
2360: /* status code <-> action matrix for the client in INIT state
2361: * (rapid/commit). Returns always false as no action is defined.
2362: */
2363: static isc_boolean_t
2364: dhc6_init_action(struct client_state *client, isc_result_t *rvalp,
2365: unsigned code)
2366: {
2367: if (rvalp == NULL)
2368: log_fatal("Impossible condition at %s:%d.", MDL);
2369:
2370: if (client == NULL) {
2371: *rvalp = ISC_R_INVALIDARG;
2372: return ISC_FALSE;
2373: }
2374:
2375: if (*rvalp == ISC_R_SUCCESS)
2376: return ISC_FALSE;
2377:
2378: /* No possible action in any case... */
2379: return ISC_FALSE;
2380: }
2381:
2382: /* status code <-> action matrix for the client in SELECT state
2383: * (request/reply). Returns true if action was taken (and the
2384: * packet should be ignored), or false if no action was taken.
2385: */
2386: static isc_boolean_t
2387: dhc6_select_action(struct client_state *client, isc_result_t *rvalp,
2388: unsigned code)
2389: {
2390: struct dhc6_lease *lease;
2391: isc_result_t rval;
2392:
2393: if (rvalp == NULL)
2394: log_fatal("Impossible condition at %s:%d.", MDL);
2395:
2396: if (client == NULL) {
2397: *rvalp = ISC_R_INVALIDARG;
2398: return ISC_FALSE;
2399: }
2400: rval = *rvalp;
2401:
2402: if (rval == ISC_R_SUCCESS)
2403: return ISC_FALSE;
2404:
2405: switch (code) {
2406: /* We may have an earlier failure status code (so no
2407: * success rval), and a success code now. This
2408: * doesn't upgrade the rval to success, but it does
2409: * mean we take no action here.
2410: */
2411: case STATUS_Success:
2412: /* Gimpy server, or possibly an attacker. */
2413: case STATUS_NoBinding:
2414: case STATUS_UseMulticast:
2415: /* Take no action. */
2416: return ISC_FALSE;
2417:
2418: /* If the server can't deal with us, either try the
2419: * next advertised server, or continue retrying if there
2420: * weren't any.
2421: */
2422: default:
2423: case STATUS_UnspecFail:
2424: if (client->advertised_leases != NULL) {
2425: dhc6_lease_destroy(&client->selected_lease, MDL);
2426: client->selected_lease = NULL;
2427:
2428: start_selecting6(client);
2429:
2430: break;
2431: } else /* Take no action - continue to retry. */
2432: return ISC_FALSE;
2433:
2434: /* If the server has no addresses, try other servers if
2435: * we got some, otherwise go to INIT to hope for more
2436: * servers.
2437: */
2438: case STATUS_NoAddrsAvail:
2439: case STATUS_NoPrefixAvail:
2440: if (client->state == S_REBOOTING)
2441: return ISC_FALSE;
2442:
2443: if (client->selected_lease == NULL)
2444: log_fatal("Impossible case at %s:%d.", MDL);
2445:
2446: dhc6_lease_destroy(&client->selected_lease, MDL);
2447: client->selected_lease = NULL;
2448:
2449: if (client->advertised_leases != NULL)
2450: start_selecting6(client);
2451: else
2452: start_init6(client);
2453:
2454: break;
2455:
2456: /* If we got a NotOnLink from a Confirm, then we're not
2457: * on link. Kill the old-active binding and start over.
2458: *
2459: * If we got a NotOnLink from our Request, something weird
2460: * happened. Start over from scratch anyway.
2461: */
2462: case STATUS_NotOnLink:
2463: if (client->state == S_REBOOTING) {
2464: if (client->active_lease == NULL)
2465: log_fatal("Impossible case at %s:%d.", MDL);
2466:
2467: dhc6_lease_destroy(&client->active_lease, MDL);
2468: } else {
2469: if (client->selected_lease == NULL)
2470: log_fatal("Impossible case at %s:%d.", MDL);
2471:
2472: dhc6_lease_destroy(&client->selected_lease, MDL);
2473: client->selected_lease = NULL;
2474:
2475: while (client->advertised_leases != NULL) {
2476: lease = client->advertised_leases;
2477: client->advertised_leases = lease->next;
2478:
2479: dhc6_lease_destroy(&lease, MDL);
2480: }
2481: }
2482:
2483: start_init6(client);
2484: break;
2485: }
2486:
2487: return ISC_TRUE;
2488: }
2489:
2490: static void
2491: dhc6_withdraw_lease(struct client_state *client)
2492: {
2493: struct dhc6_ia *ia;
2494: struct dhc6_addr *addr;
2495:
2496: if ((client == NULL) || (client->active_lease == NULL))
2497: return;
2498:
2499: for (ia = client->active_lease->bindings ; ia != NULL ;
2500: ia = ia->next) {
2501: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
2502: addr->max_life = addr->preferred_life = 0;
2503: }
2504: }
2505:
2506: /* Perform expiry. */
2507: do_expire(client);
2508: }
2509:
2510: /* status code <-> action matrix for the client in BOUND state
2511: * (request/reply). Returns true if action was taken (and the
2512: * packet should be ignored), or false if no action was taken.
2513: */
2514: static isc_boolean_t
2515: dhc6_reply_action(struct client_state *client, isc_result_t *rvalp,
2516: unsigned code)
2517: {
2518: isc_result_t rval;
2519:
2520: if (rvalp == NULL)
2521: log_fatal("Impossible condition at %s:%d.", MDL);
2522:
2523: if (client == NULL) {
2524: *rvalp = ISC_R_INVALIDARG;
2525: return ISC_FALSE;
2526: }
2527: rval = *rvalp;
2528:
2529: if (rval == ISC_R_SUCCESS)
2530: return ISC_FALSE;
2531:
2532: switch (code) {
2533: /* It's possible an earlier status code set rval to a failure
2534: * code, and we've encountered a later success.
2535: */
2536: case STATUS_Success:
2537: /* In "refreshes" (where we get replies), we probably
2538: * still have a valid lease. So "take no action" and
2539: * the upper levels will keep retrying until the lease
2540: * expires (or we rebind).
2541: */
2542: case STATUS_UnspecFail:
2543: /* For unknown codes...it's a soft (retryable) error. */
2544: default:
2545: return ISC_FALSE;
2546:
2547: /* The server is telling us to use a multicast address, so
2548: * we have to delete the unicast option from the active
2549: * lease, then allow retransmission to occur normally.
2550: * (XXX: It might be preferable in this case to retransmit
2551: * sooner than the current interval, but for now we don't.)
2552: */
2553: case STATUS_UseMulticast:
2554: if (client->active_lease != NULL)
2555: delete_option(&dhcp_universe,
2556: client->active_lease->options,
2557: D6O_UNICAST);
2558: return ISC_FALSE;
2559:
2560: /* "When the client receives a NotOnLink status from the
2561: * server in response to a Request, the client can either
2562: * re-issue the Request without specifying any addresses
2563: * or restart the DHCP server discovery process."
2564: *
2565: * This is strange. If competing server evaluation is
2566: * useful (and therefore in the protocol), then why would
2567: * a client's first reaction be to request from the same
2568: * server on a different link? Surely you'd want to
2569: * re-evaluate your server selection.
2570: *
2571: * Well, I guess that's the answer.
2572: */
2573: case STATUS_NotOnLink:
2574: /* In this case, we need to rescind all current active
2575: * bindings (just 'expire' them all normally, if early).
2576: * They're no use to us on the wrong link. Then head back
2577: * to init, redo server selection and get new addresses.
2578: */
2579: dhc6_withdraw_lease(client);
2580: break;
2581:
2582: /* "If the status code is NoAddrsAvail, the client has
2583: * received no usable addresses in the IA and may choose
2584: * to try obtaining addresses for the IA from another
2585: * server."
2586: */
2587: case STATUS_NoAddrsAvail:
2588: case STATUS_NoPrefixAvail:
2589: /* Head back to init, keeping any active bindings (!). */
2590: start_init6(client);
2591: break;
2592:
2593: /* - sends a Request message if the IA contained a Status
2594: * Code option with the NoBinding status (and does not
2595: * send any additional Renew/Rebind messages)
2596: */
2597: case STATUS_NoBinding:
2598: if (client->advertised_leases != NULL)
2599: log_fatal("Impossible condition at %s:%d.", MDL);
2600:
2601: client->advertised_leases =
2602: dhc6_dup_lease(client->active_lease, MDL);
2603: start_selecting6(client);
2604: break;
2605: }
2606:
2607: return ISC_TRUE;
2608: }
2609:
2610: /* status code <-> action matrix for the client in STOPPED state
2611: * (release/decline). Returns true if action was taken (and the
2612: * packet should be ignored), or false if no action was taken.
2613: * NoBinding is translated into Success.
2614: */
2615: static isc_boolean_t
2616: dhc6_stop_action(struct client_state *client, isc_result_t *rvalp,
2617: unsigned code)
2618: {
2619: isc_result_t rval;
2620:
2621: if (rvalp == NULL)
2622: log_fatal("Impossible condition at %s:%d.", MDL);
2623:
2624: if (client == NULL) {
2625: *rvalp = ISC_R_INVALIDARG;
2626: return ISC_FALSE;
2627: }
2628: rval = *rvalp;
2629:
2630: if (rval == ISC_R_SUCCESS)
2631: return ISC_FALSE;
2632:
2633: switch (code) {
2634: /* It's possible an earlier status code set rval to a failure
2635: * code, and we've encountered a later success.
2636: */
2637: case STATUS_Success:
2638: /* For unknown codes...it's a soft (retryable) error. */
2639: case STATUS_UnspecFail:
2640: default:
2641: return ISC_FALSE;
2642:
2643: /* NoBinding is not an error */
2644: case STATUS_NoBinding:
2645: if (rval == ISC_R_FAILURE)
2646: *rvalp = ISC_R_SUCCESS;
2647: return ISC_FALSE;
2648:
2649: /* Should not happen */
2650: case STATUS_NoAddrsAvail:
2651: case STATUS_NoPrefixAvail:
2652: break;
2653:
2654: /* Give up on it */
2655: case STATUS_NotOnLink:
2656: break;
2657:
2658: /* The server is telling us to use a multicast address, so
2659: * we have to delete the unicast option from the active
2660: * lease, then allow retransmission to occur normally.
2661: * (XXX: It might be preferable in this case to retransmit
2662: * sooner than the current interval, but for now we don't.)
2663: */
2664: case STATUS_UseMulticast:
2665: if (client->active_lease != NULL)
2666: delete_option(&dhcp_universe,
2667: client->active_lease->options,
2668: D6O_UNICAST);
2669: return ISC_FALSE;
2670: }
2671:
2672: return ISC_TRUE;
2673: }
2674:
2675: /* Look at a new and old lease, and make sure the new information is not
2676: * losing us any state.
2677: */
2678: static isc_result_t
2679: dhc6_check_reply(struct client_state *client, struct dhc6_lease *new)
2680: {
2681: isc_boolean_t (*action)(struct client_state *,
2682: isc_result_t *, unsigned);
2683: struct dhc6_ia *ia;
2684: struct dhc6_addr *addr;
2685: isc_result_t rval = ISC_R_SUCCESS;
2686: unsigned code;
2687: const char *scope;
2688: int nscore, sscore;
2689:
2690: if ((client == NULL) || (new == NULL))
2691: return ISC_R_INVALIDARG;
2692:
2693: switch (client->state) {
2694: case S_INIT:
2695: action = dhc6_init_action;
2696: break;
2697:
2698: case S_SELECTING:
2699: case S_REBOOTING:
2700: action = dhc6_select_action;
2701: break;
2702:
2703: case S_RENEWING:
2704: case S_REBINDING:
2705: action = dhc6_reply_action;
2706: break;
2707:
2708: case S_STOPPED:
2709: action = dhc6_stop_action;
2710: break;
2711:
2712: default:
2713: log_fatal("Impossible condition at %s:%d.", MDL);
2714: return ISC_R_CANCELED;
2715: }
2716:
2717: /* If there is a code to extract, and if there is some
2718: * action to take based on that code, then take the action
2719: * and do not continue.
2720: */
2721: rval = dhc6_check_status(rval, new->options, "message", &code);
2722: if (action(client, &rval, code))
2723: return ISC_R_CANCELED;
2724:
2725: for (ia = new->bindings ; ia != NULL ; ia = ia->next) {
2726: switch (ia->ia_type) {
2727: case D6O_IA_NA:
2728: scope = "IA_NA";
2729: break;
2730: case D6O_IA_TA:
2731: scope = "IA_TA";
2732: break;
2733: case D6O_IA_PD:
2734: scope = "IA_PD";
2735: break;
2736: default:
2737: log_error("dhc6_check_reply: no type.");
2738: return ISC_R_INVALIDARG;
2739: }
2740: rval = dhc6_check_status(rval, ia->options,
2741: scope, &code);
2742: if (action(client, &rval, code))
2743: return ISC_R_CANCELED;
2744:
2745: for (addr = ia->addrs ; addr != NULL ;
2746: addr = addr->next) {
2747: if (ia->ia_type != D6O_IA_PD)
2748: scope = "IAADDR";
2749: else
2750: scope = "IAPREFIX";
2751: rval = dhc6_check_status(rval, addr->options,
2752: scope, &code);
2753: if (action(client, &rval, code))
2754: return ISC_R_CANCELED;
2755: }
2756: }
2757:
2758: /* A Confirm->Reply is unsuitable for comparison to the old lease. */
2759: if (client->state == S_REBOOTING)
2760: return rval;
2761:
2762: /* No old lease in rapid-commit. */
2763: if (client->state == S_INIT)
2764: return rval;
2765:
2766: switch (client->state) {
2767: case S_SELECTING:
2768: /* Compare the new lease with the selected lease to make
2769: * sure there is no risky business.
2770: */
2771: nscore = dhc6_score_lease(client, new);
2772: sscore = dhc6_score_lease(client, client->selected_lease);
2773: if ((client->advertised_leases != NULL) &&
2774: (nscore < (sscore / 2))) {
2775: /* XXX: An attacker might reply this way to make
2776: * XXX: sure we latch onto their configuration.
2777: * XXX: We might want to ignore the packet and
2778: * XXX: schedule re-selection at the next timeout?
2779: */
2780: log_error("PRC: BAIT AND SWITCH detected. Score of "
2781: "supplied lease (%d) is substantially "
2782: "smaller than the advertised score (%d). "
2783: "Trying other servers.",
2784: nscore, sscore);
2785:
2786: dhc6_lease_destroy(&client->selected_lease, MDL);
2787: client->selected_lease = NULL;
2788:
2789: start_selecting6(client);
2790:
2791: return ISC_R_CANCELED;
2792: }
2793: break;
2794:
2795: case S_RENEWING:
2796: case S_REBINDING:
2797: /* This leaves one RFC3315 status check unimplemented:
2798: *
2799: * - sends a Renew/Rebind if the IA is not in the Reply
2800: * message
2801: *
2802: * We rely on the scheduling system to note that the IA has
2803: * not left Renewal/Rebinding/whatever since it still carries
2804: * old times from the last successful binding. So this is
2805: * implemented actually, just not explicitly.
2806: */
2807: break;
2808:
2809: case S_STOPPED:
2810: /* Nothing critical to do at this stage. */
2811: break;
2812:
2813: default:
2814: log_fatal("REALLY impossible condition at %s:%d.", MDL);
2815: return ISC_R_CANCELED;
2816: }
2817:
2818: return rval;
2819: }
2820:
2821: /* While in init state, we only collect advertisements. If there happens
2822: * to be an advertisement with a preference option of 255, that's an
2823: * automatic exit. Otherwise, we collect advertisements until our timeout
2824: * expires (client->RT).
2825: */
2826: void
2827: init_handler(struct packet *packet, struct client_state *client)
2828: {
2829: struct dhc6_lease *lease;
2830:
2831: /* In INIT state, we send solicits, we only expect to get
2832: * advertises (rapid commit has its own handler).
2833: */
2834: if (packet->dhcpv6_msg_type != DHCPV6_ADVERTISE)
2835: return;
2836:
2837: /* RFC3315 section 15.3 validation (same as 15.10 since we
2838: * always include a client id).
2839: */
2840: if (!valid_reply(packet, client)) {
2841: log_error("Invalid Advertise - rejecting.");
2842: return;
2843: }
2844:
2845: lease = dhc6_leaseify(packet);
2846:
2847: if (dhc6_check_advertise(lease) != ISC_R_SUCCESS) {
2848: log_debug("PRC: Lease failed to satisfy.");
2849: dhc6_lease_destroy(&lease, MDL);
2850: return;
2851: }
2852:
2853: insert_lease(&client->advertised_leases, lease);
2854:
2855: /* According to RFC3315 section 17.1.2, the client MUST wait for
2856: * the first RT before selecting a lease. But on the 400th RT,
2857: * we dont' want to wait the full timeout if we finally get an
2858: * advertise. We could probably wait a second, but ohwell,
2859: * RFC3315 doesn't say so.
2860: *
2861: * If the lease is highest possible preference, 255, RFC3315 claims
2862: * we should continue immediately even on the first RT. We probably
2863: * should not if the advertise contains less than one IA and address.
2864: */
2865: if ((client->txcount > 1) ||
2866: ((lease->pref == 255) &&
2867: (dhc6_score_lease(client, lease) > 150))) {
2868: log_debug("RCV: Advertisement immediately selected.");
2869: cancel_timeout(do_init6, client);
2870: start_selecting6(client);
2871: } else
2872: log_debug("RCV: Advertisement recorded.");
2873: }
2874:
2875: /* info_request_handler() accepts a Reply to an Info-request.
2876: */
2877: void
2878: info_request_handler(struct packet *packet, struct client_state *client)
2879: {
2880: isc_result_t check_status;
2881: unsigned code;
2882:
2883: if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
2884: return;
2885:
2886: /* RFC3315 section 15.10 validation (same as 15.3 since we
2887: * always include a client id).
2888: */
2889: if (!valid_reply(packet, client)) {
2890: log_error("Invalid Reply - rejecting.");
2891: return;
2892: }
2893:
2894: check_status = dhc6_check_status(ISC_R_SUCCESS, packet->options,
2895: "message", &code);
2896: if (check_status != ISC_R_SUCCESS) {
2897: /* If no action was taken, but there is an error, then
2898: * we wait for a retransmission.
2899: */
2900: if (check_status != ISC_R_CANCELED)
2901: return;
2902: }
2903:
2904: /* We're done retransmitting at this point. */
2905: cancel_timeout(do_info_request6, client);
2906:
2907: /* Action was taken, so now that we've torn down our scheduled
2908: * retransmissions, return.
2909: */
2910: if (check_status == ISC_R_CANCELED)
2911: return;
2912:
2913: /* Cleanup if a previous attempt to go bound failed. */
2914: if (client->old_lease != NULL) {
2915: dhc6_lease_destroy(&client->old_lease, MDL);
2916: client->old_lease = NULL;
2917: }
2918:
2919: /* Cache options in the active_lease. */
2920: if (client->active_lease != NULL)
2921: client->old_lease = client->active_lease;
2922: client->active_lease = dmalloc(sizeof(struct dhc6_lease), MDL);
2923: if (client->active_lease == NULL)
2924: log_fatal("Out of memory for v6 lease structure.");
2925: option_state_reference(&client->active_lease->options,
2926: packet->options, MDL);
2927:
2928: start_informed(client);
2929: }
2930:
2931: /* Specific version of init_handler() for rapid-commit.
2932: */
2933: void
2934: rapid_commit_handler(struct packet *packet, struct client_state *client)
2935: {
2936: struct dhc6_lease *lease;
2937: isc_result_t check_status;
2938:
2939: /* On ADVERTISE just fall back to the init_handler().
2940: */
2941: if (packet->dhcpv6_msg_type == DHCPV6_ADVERTISE) {
2942: init_handler(packet, client);
2943: return;
2944: } else if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
2945: return;
2946:
2947: /* RFC3315 section 15.10 validation (same as 15.3 since we
2948: * always include a client id).
2949: */
2950: if (!valid_reply(packet, client)) {
2951: log_error("Invalid Reply - rejecting.");
2952: return;
2953: }
2954:
2955: /* A rapid-commit option MUST be here. */
2956: if (lookup_option(&dhcpv6_universe, packet->options,
2957: D6O_RAPID_COMMIT) == 0) {
2958: log_error("Reply without Rapid-Commit - rejecting.");
2959: return;
2960: }
2961:
2962: lease = dhc6_leaseify(packet);
2963:
2964: /* This is an out of memory condition...hopefully a temporary
2965: * problem. Returning now makes us try to retransmit later.
2966: */
2967: if (lease == NULL)
2968: return;
2969:
2970: check_status = dhc6_check_reply(client, lease);
2971: if (check_status != ISC_R_SUCCESS) {
2972: dhc6_lease_destroy(&lease, MDL);
2973: return;
2974: }
2975:
2976: /* Jump to the selecting state. */
2977: cancel_timeout(do_init6, client);
2978: client->state = S_SELECTING;
2979:
2980: /* Merge any bindings in the active lease (if there is one) into
2981: * the new active lease.
2982: */
2983: dhc6_merge_lease(client->active_lease, lease);
2984:
2985: /* Cleanup if a previous attempt to go bound failed. */
2986: if (client->old_lease != NULL) {
2987: dhc6_lease_destroy(&client->old_lease, MDL);
2988: client->old_lease = NULL;
2989: }
2990:
2991: /* Make this lease active and BIND to it. */
2992: if (client->active_lease != NULL)
2993: client->old_lease = client->active_lease;
2994: client->active_lease = lease;
2995:
2996: /* We're done with the ADVERTISEd leases, if any. */
2997: while(client->advertised_leases != NULL) {
2998: lease = client->advertised_leases;
2999: client->advertised_leases = lease->next;
3000:
3001: dhc6_lease_destroy(&lease, MDL);
3002: }
3003:
3004: start_bound(client);
3005: }
3006:
3007: /* Find the 'best' lease in the cache of advertised leases (usually). From
3008: * RFC3315 Section 17.1.3:
3009: *
3010: * Upon receipt of one or more valid Advertise messages, the client
3011: * selects one or more Advertise messages based upon the following
3012: * criteria.
3013: *
3014: * - Those Advertise messages with the highest server preference value
3015: * are preferred over all other Advertise messages.
3016: *
3017: * - Within a group of Advertise messages with the same server
3018: * preference value, a client MAY select those servers whose
3019: * Advertise messages advertise information of interest to the
3020: * client. For example, the client may choose a server that returned
3021: * an advertisement with configuration options of interest to the
3022: * client.
3023: *
3024: * - The client MAY choose a less-preferred server if that server has a
3025: * better set of advertised parameters, such as the available
3026: * addresses advertised in IAs.
3027: *
3028: * Note that the first and third contradict each other. The third should
3029: * probably be taken to mean that the client should prefer answers that
3030: * offer bindings, even if that violates the preference rule.
3031: *
3032: * The above also isn't deterministic where there are ties. So the final
3033: * tiebreaker we add, if all other values are equal, is to compare the
3034: * server identifiers and to select the numerically lower one.
3035: */
3036: static struct dhc6_lease *
3037: dhc6_best_lease(struct client_state *client, struct dhc6_lease **head)
3038: {
3039: struct dhc6_lease **rpos, *rval, **candp, *cand;
3040: int cscore, rscore;
3041:
3042: if (head == NULL || *head == NULL)
3043: return NULL;
3044:
3045: rpos = head;
3046: rval = *rpos;
3047: rscore = dhc6_score_lease(client, rval);
3048: candp = &rval->next;
3049: cand = *candp;
3050:
3051: log_debug("PRC: Considering best lease.");
3052: log_debug("PRC: X-- Initial candidate %s (s: %d, p: %u).",
3053: print_hex_1(rval->server_id.len,
3054: rval->server_id.data, 48),
3055: rscore, (unsigned)rval->pref);
3056:
3057: for (; cand != NULL ; candp = &cand->next, cand = *candp) {
3058: cscore = dhc6_score_lease(client, cand);
3059:
3060: log_debug("PRC: X-- Candidate %s (s: %d, p: %u).",
3061: print_hex_1(cand->server_id.len,
3062: cand->server_id.data, 48),
3063: cscore, (unsigned)cand->pref);
3064:
3065: /* Above you'll find quoted RFC3315 Section 17.1.3.
3066: *
3067: * The third clause tells us to give up on leases that
3068: * have no bindings even if their preference is better.
3069: * So where our 'selected' lease's score is less than 150
3070: * (1 ia + 1 addr), choose any candidate >= 150.
3071: *
3072: * The first clause tells us to make preference the primary
3073: * deciding factor. So if it's lower, reject, if it's
3074: * higher, select.
3075: *
3076: * The second clause tells us where the preference is
3077: * equal, we should use 'our judgement' of what we like
3078: * to see in an advertisement primarily.
3079: *
3080: * But there can still be a tie. To make this deterministic,
3081: * we compare the server identifiers and select the binary
3082: * lowest.
3083: *
3084: * Since server id's are unique in this list, there is
3085: * no further tie to break.
3086: */
3087: if ((rscore < 150) && (cscore >= 150)) {
3088: log_debug("PRC: | X-- Selected, has bindings.");
3089: } else if (cand->pref < rval->pref) {
3090: log_debug("PRC: | X-- Rejected, lower preference.");
3091: continue;
3092: } else if (cand->pref > rval->pref) {
3093: log_debug("PRC: | X-- Selected, higher preference.");
3094: } else if (cscore > rscore) {
3095: log_debug("PRC: | X-- Selected, equal preference, "
3096: "higher score.");
3097: } else if (cscore < rscore) {
3098: log_debug("PRC: | X-- Rejected, equal preference, "
3099: "lower score.");
3100: continue;
3101: } else if ((cand->server_id.len < rval->server_id.len) ||
3102: ((cand->server_id.len == rval->server_id.len) &&
3103: (memcmp(cand->server_id.data,
3104: rval->server_id.data,
3105: cand->server_id.len) < 0))) {
3106: log_debug("PRC: | X-- Selected, equal preference, "
3107: "equal score, binary lesser server ID.");
3108: } else {
3109: log_debug("PRC: | X-- Rejected, equal preference, "
3110: "equal score, binary greater server ID.");
3111: continue;
3112: }
3113:
3114: rpos = candp;
3115: rval = cand;
3116: rscore = cscore;
3117: }
3118:
3119: /* Remove the selected lease from the chain. */
3120: *rpos = rval->next;
3121:
3122: return rval;
3123: }
3124:
3125: /* Select a lease out of the advertised leases and setup state to try and
3126: * acquire that lease.
3127: */
3128: void
3129: start_selecting6(struct client_state *client)
3130: {
3131: struct dhc6_lease *lease;
3132:
3133: if (client->advertised_leases == NULL) {
3134: log_error("Can not enter DHCPv6 SELECTING state with no "
3135: "leases to select from!");
3136: return;
3137: }
3138:
3139: log_debug("PRC: Selecting best advertised lease.");
3140: client->state = S_SELECTING;
3141:
3142: lease = dhc6_best_lease(client, &client->advertised_leases);
3143:
3144: if (lease == NULL)
3145: log_fatal("Impossible error at %s:%d.", MDL);
3146:
3147: client->selected_lease = lease;
3148:
3149: /* Set timers per RFC3315 section 18.1.1. */
3150: client->IRT = REQ_TIMEOUT * 100;
3151: client->MRT = REQ_MAX_RT * 100;
3152: client->MRC = REQ_MAX_RC;
3153: client->MRD = 0;
3154:
3155: dhc6_retrans_init(client);
3156:
3157: client->v6_handler = reply_handler;
3158:
3159: /* ("re")transmit the first packet. */
3160: do_select6(client);
3161: }
3162:
3163: /* Transmit a Request to select a lease offered in Advertisements. In
3164: * the event of failure, either move on to the next-best advertised lease,
3165: * or head back to INIT state if there are none.
3166: */
3167: void
3168: do_select6(void *input)
3169: {
3170: struct client_state *client;
3171: struct dhc6_lease *lease;
3172: struct data_string ds;
3173: struct timeval tv;
3174: int send_ret;
3175:
3176: client = input;
3177:
3178: /* 'lease' is fewer characters to type. */
3179: lease = client->selected_lease;
3180: if (lease == NULL || lease->bindings == NULL) {
3181: log_error("Illegal to attempt selection without selecting "
3182: "a lease.");
3183: return;
3184: }
3185:
3186: switch(check_timing6(client, DHCPV6_REQUEST, "Request", lease, &ds)) {
3187: case CHK_TIM_MRC_EXCEEDED:
3188: case CHK_TIM_MRD_EXCEEDED:
3189: log_debug("PRC: Lease %s failed.",
3190: print_hex_1(lease->server_id.len,
3191: lease->server_id.data, 56));
3192:
3193: /* Get rid of the lease that timed/counted out. */
3194: dhc6_lease_destroy(&lease, MDL);
3195: client->selected_lease = NULL;
3196:
3197: /* If there are more leases great. If not, get more. */
3198: if (client->advertised_leases != NULL)
3199: start_selecting6(client);
3200: else
3201: start_init6(client);
3202: return;
3203: case CHK_TIM_ALLOC_FAILURE:
3204: return;
3205: case CHK_TIM_SUCCESS:
3206: break;
3207: }
3208:
3209: /* Now make a packet that looks suspiciously like the one we
3210: * got from the server. But different.
3211: *
3212: * XXX: I guess IAID is supposed to be something the client
3213: * indicates and uses as a key to its internal state. It is
3214: * kind of odd to ask the server for IA's whose IAID the client
3215: * did not manufacture. We first need a formal dhclient.conf
3216: * construct for the iaid, then we can delve into this matter
3217: * more properly. In the time being, this will work.
3218: */
3219:
3220: /* Fetch any configured 'sent' options (includes DUID) in wire format.
3221: */
3222: dhcpv6_universe.encapsulate(&ds, NULL, NULL, client,
3223: NULL, client->sent_options, &global_scope,
3224: &dhcpv6_universe);
3225:
3226: /* Now append any IA's, and within them any IAADDR/IAPREFIXs. */
3227: if (wanted_ia_na &&
3228: dhc6_add_ia_na(client, &ds, lease,
3229: DHCPV6_REQUEST) != ISC_R_SUCCESS) {
3230: data_string_forget(&ds, MDL);
3231: return;
3232: }
3233: if (wanted_ia_ta &&
3234: dhc6_add_ia_ta(client, &ds, lease,
3235: DHCPV6_REQUEST) != ISC_R_SUCCESS) {
3236: data_string_forget(&ds, MDL);
3237: return;
3238: }
3239: if (wanted_ia_pd &&
3240: dhc6_add_ia_pd(client, &ds, lease,
3241: DHCPV6_REQUEST) != ISC_R_SUCCESS) {
3242: data_string_forget(&ds, MDL);
3243: return;
3244: }
3245:
3246: log_info("XMT: Request on %s, interval %ld0ms.",
3247: client->name ? client->name : client->interface->name,
3248: (long int)client->RT);
3249:
3250: send_ret = send_packet6(client->interface,
3251: ds.data, ds.len, &DHCPv6DestAddr);
3252: if (send_ret != ds.len) {
3253: log_error("dhc6: send_packet6() sent %d of %d bytes",
3254: send_ret, ds.len);
3255: }
3256:
3257: data_string_forget(&ds, MDL);
3258:
3259: /* Wait RT */
3260: tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
3261: tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
3262: if (tv.tv_usec >= 1000000) {
3263: tv.tv_sec += 1;
3264: tv.tv_usec -= 1000000;
3265: }
3266: add_timeout(&tv, do_select6, client, NULL, NULL);
3267:
3268: dhc6_retrans_advance(client);
3269: }
3270:
3271: /* For each IA_NA in the lease, for each address in the IA_NA,
3272: * append that information onto the packet-so-far.
3273: */
3274: static isc_result_t
3275: dhc6_add_ia_na(struct client_state *client, struct data_string *packet,
3276: struct dhc6_lease *lease, u_int8_t message)
3277: {
3278: struct data_string iads;
3279: struct data_string addrds;
3280: struct dhc6_addr *addr;
3281: struct dhc6_ia *ia;
3282: isc_result_t rval = ISC_R_SUCCESS;
3283: TIME t1, t2;
3284:
3285: memset(&iads, 0, sizeof(iads));
3286: memset(&addrds, 0, sizeof(addrds));
3287: for (ia = lease->bindings;
3288: ia != NULL && rval == ISC_R_SUCCESS;
3289: ia = ia->next) {
3290: if (ia->ia_type != D6O_IA_NA)
3291: continue;
3292:
3293: if (!buffer_allocate(&iads.buffer, 12, MDL)) {
3294: log_error("Unable to allocate memory for IA_NA.");
3295: rval = ISC_R_NOMEMORY;
3296: break;
3297: }
3298:
3299: /* Copy the IAID into the packet buffer. */
3300: memcpy(iads.buffer->data, ia->iaid, 4);
3301: iads.data = iads.buffer->data;
3302: iads.len = 12;
3303:
3304: switch (message) {
3305: case DHCPV6_REQUEST:
3306: case DHCPV6_RENEW:
3307: case DHCPV6_REBIND:
3308:
3309: t1 = client->config->requested_lease / 2;
3310: t2 = t1 + (t1 / 2);
3311: #if MAX_TIME > 0xffffffff
3312: if (t1 > 0xffffffff)
3313: t1 = 0xffffffff;
3314: if (t2 > 0xffffffff)
3315: t2 = 0xffffffff;
3316: #endif
3317: putULong(iads.buffer->data + 4, t1);
3318: putULong(iads.buffer->data + 8, t2);
3319:
3320: log_debug("XMT: X-- IA_NA %s",
3321: print_hex_1(4, iads.data, 59));
3322: log_debug("XMT: | X-- Requested renew +%u",
3323: (unsigned) t1);
3324: log_debug("XMT: | X-- Requested rebind +%u",
3325: (unsigned) t2);
3326: break;
3327:
3328: case DHCPV6_CONFIRM:
3329: case DHCPV6_RELEASE:
3330: case DHCPV6_DECLINE:
3331: /* Set t1 and t2 to zero; server will ignore them */
3332: memset(iads.buffer->data + 4, 0, 8);
3333: log_debug("XMT: X-- IA_NA %s",
3334: print_hex_1(4, iads.buffer->data, 55));
3335:
3336: break;
3337:
3338: default:
3339: log_fatal("Impossible condition at %s:%d.", MDL);
3340: }
3341:
3342: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3343: /*
3344: * Do not confirm expired addresses, do not request
3345: * expired addresses (but we keep them around for
3346: * solicit).
3347: */
3348: if (addr->flags & DHC6_ADDR_EXPIRED)
3349: continue;
3350:
3351: if (addr->address.len != 16) {
3352: log_error("Illegal IPv6 address length (%d), "
3353: "ignoring. (%s:%d)",
3354: addr->address.len, MDL);
3355: continue;
3356: }
3357:
3358: if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
3359: log_error("Unable to allocate memory for "
3360: "IAADDR.");
3361: rval = ISC_R_NOMEMORY;
3362: break;
3363: }
3364:
3365: addrds.data = addrds.buffer->data;
3366: addrds.len = 24;
3367:
3368: /* Copy the address into the packet buffer. */
3369: memcpy(addrds.buffer->data, addr->address.iabuf, 16);
3370:
3371: /* Copy in additional information as appropriate */
3372: switch (message) {
3373: case DHCPV6_REQUEST:
3374: case DHCPV6_RENEW:
3375: case DHCPV6_REBIND:
3376: t1 = client->config->requested_lease;
3377: t2 = t1 + 300;
3378: putULong(addrds.buffer->data + 16, t1);
3379: putULong(addrds.buffer->data + 20, t2);
3380:
3381: log_debug("XMT: | | X-- IAADDR %s",
3382: piaddr(addr->address));
3383: log_debug("XMT: | | | X-- Preferred "
3384: "lifetime +%u", (unsigned)t1);
3385: log_debug("XMT: | | | X-- Max lifetime +%u",
3386: (unsigned)t2);
3387:
3388: break;
3389:
3390: case DHCPV6_CONFIRM:
3391: /*
3392: * Set preferred and max life to zero,
3393: * per 17.1.3.
3394: */
3395: memset(addrds.buffer->data + 16, 0, 8);
3396: log_debug("XMT: | X-- Confirm Address %s",
3397: piaddr(addr->address));
3398: break;
3399:
3400: case DHCPV6_RELEASE:
3401: /* Preferred and max life are irrelevant */
3402: memset(addrds.buffer->data + 16, 0, 8);
3403: log_debug("XMT: | X-- Release Address %s",
3404: piaddr(addr->address));
3405: break;
3406:
3407: case DHCPV6_DECLINE:
3408: /* Preferred and max life are irrelevant */
3409: memset(addrds.buffer->data + 16, 0, 8);
3410: log_debug("XMT: | X-- Decline Address %s",
3411: piaddr(addr->address));
3412: break;
3413:
3414: default:
3415: log_fatal("Impossible condition at %s:%d.",
3416: MDL);
3417: }
3418:
3419: append_option(&iads, &dhcpv6_universe, iaaddr_option,
3420: &addrds);
3421: data_string_forget(&addrds, MDL);
3422: }
3423:
3424: /*
3425: * It doesn't make sense to make a request without an
3426: * address.
3427: */
3428: if (ia->addrs == NULL) {
3429: log_debug("!!!: V IA_NA has no IAADDRs - removed.");
3430: rval = ISC_R_FAILURE;
3431: } else if (rval == ISC_R_SUCCESS) {
3432: log_debug("XMT: V IA_NA appended.");
3433: append_option(packet, &dhcpv6_universe, ia_na_option,
3434: &iads);
3435: }
3436:
3437: data_string_forget(&iads, MDL);
3438: }
3439:
3440: return rval;
3441: }
3442:
3443: /* For each IA_TA in the lease, for each address in the IA_TA,
3444: * append that information onto the packet-so-far.
3445: */
3446: static isc_result_t
3447: dhc6_add_ia_ta(struct client_state *client, struct data_string *packet,
3448: struct dhc6_lease *lease, u_int8_t message)
3449: {
3450: struct data_string iads;
3451: struct data_string addrds;
3452: struct dhc6_addr *addr;
3453: struct dhc6_ia *ia;
3454: isc_result_t rval = ISC_R_SUCCESS;
3455: TIME t1, t2;
3456:
3457: memset(&iads, 0, sizeof(iads));
3458: memset(&addrds, 0, sizeof(addrds));
3459: for (ia = lease->bindings;
3460: ia != NULL && rval == ISC_R_SUCCESS;
3461: ia = ia->next) {
3462: if (ia->ia_type != D6O_IA_TA)
3463: continue;
3464:
3465: if (!buffer_allocate(&iads.buffer, 4, MDL)) {
3466: log_error("Unable to allocate memory for IA_TA.");
3467: rval = ISC_R_NOMEMORY;
3468: break;
3469: }
3470:
3471: /* Copy the IAID into the packet buffer. */
3472: memcpy(iads.buffer->data, ia->iaid, 4);
3473: iads.data = iads.buffer->data;
3474: iads.len = 4;
3475:
3476: log_debug("XMT: X-- IA_TA %s",
3477: print_hex_1(4, iads.buffer->data, 55));
3478:
3479: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3480: /*
3481: * Do not confirm expired addresses, do not request
3482: * expired addresses (but we keep them around for
3483: * solicit).
3484: */
3485: if (addr->flags & DHC6_ADDR_EXPIRED)
3486: continue;
3487:
3488: if (addr->address.len != 16) {
3489: log_error("Illegal IPv6 address length (%d), "
3490: "ignoring. (%s:%d)",
3491: addr->address.len, MDL);
3492: continue;
3493: }
3494:
3495: if (!buffer_allocate(&addrds.buffer, 24, MDL)) {
3496: log_error("Unable to allocate memory for "
3497: "IAADDR.");
3498: rval = ISC_R_NOMEMORY;
3499: break;
3500: }
3501:
3502: addrds.data = addrds.buffer->data;
3503: addrds.len = 24;
3504:
3505: /* Copy the address into the packet buffer. */
3506: memcpy(addrds.buffer->data, addr->address.iabuf, 16);
3507:
3508: /* Copy in additional information as appropriate */
3509: switch (message) {
3510: case DHCPV6_REQUEST:
3511: case DHCPV6_RENEW:
3512: case DHCPV6_REBIND:
3513: t1 = client->config->requested_lease;
3514: t2 = t1 + 300;
3515: putULong(addrds.buffer->data + 16, t1);
3516: putULong(addrds.buffer->data + 20, t2);
3517:
3518: log_debug("XMT: | | X-- IAADDR %s",
3519: piaddr(addr->address));
3520: log_debug("XMT: | | | X-- Preferred "
3521: "lifetime +%u", (unsigned)t1);
3522: log_debug("XMT: | | | X-- Max lifetime +%u",
3523: (unsigned)t2);
3524:
3525: break;
3526:
3527: case DHCPV6_CONFIRM:
3528: /*
3529: * Set preferred and max life to zero,
3530: * per 17.1.3.
3531: */
3532: memset(addrds.buffer->data + 16, 0, 8);
3533: log_debug("XMT: | X-- Confirm Address %s",
3534: piaddr(addr->address));
3535: break;
3536:
3537: case DHCPV6_RELEASE:
3538: /* Preferred and max life are irrelevant */
3539: memset(addrds.buffer->data + 16, 0, 8);
3540: log_debug("XMT: | X-- Release Address %s",
3541: piaddr(addr->address));
3542: break;
3543:
3544: default:
3545: log_fatal("Impossible condition at %s:%d.",
3546: MDL);
3547: }
3548:
3549: append_option(&iads, &dhcpv6_universe, iaaddr_option,
3550: &addrds);
3551: data_string_forget(&addrds, MDL);
3552: }
3553:
3554: /*
3555: * It doesn't make sense to make a request without an
3556: * address.
3557: */
3558: if (ia->addrs == NULL) {
3559: log_debug("!!!: V IA_TA has no IAADDRs - removed.");
3560: rval = ISC_R_FAILURE;
3561: } else if (rval == ISC_R_SUCCESS) {
3562: log_debug("XMT: V IA_TA appended.");
3563: append_option(packet, &dhcpv6_universe, ia_ta_option,
3564: &iads);
3565: }
3566:
3567: data_string_forget(&iads, MDL);
3568: }
3569:
3570: return rval;
3571: }
3572:
3573: /* For each IA_PD in the lease, for each prefix in the IA_PD,
3574: * append that information onto the packet-so-far.
3575: */
3576: static isc_result_t
3577: dhc6_add_ia_pd(struct client_state *client, struct data_string *packet,
3578: struct dhc6_lease *lease, u_int8_t message)
3579: {
3580: struct data_string iads;
3581: struct data_string prefds;
3582: struct dhc6_addr *pref;
3583: struct dhc6_ia *ia;
3584: isc_result_t rval = ISC_R_SUCCESS;
3585: TIME t1, t2;
3586:
3587: memset(&iads, 0, sizeof(iads));
3588: memset(&prefds, 0, sizeof(prefds));
3589: for (ia = lease->bindings;
3590: ia != NULL && rval == ISC_R_SUCCESS;
3591: ia = ia->next) {
3592: if (ia->ia_type != D6O_IA_PD)
3593: continue;
3594:
3595: if (!buffer_allocate(&iads.buffer, 12, MDL)) {
3596: log_error("Unable to allocate memory for IA_PD.");
3597: rval = ISC_R_NOMEMORY;
3598: break;
3599: }
3600:
3601: /* Copy the IAID into the packet buffer. */
3602: memcpy(iads.buffer->data, ia->iaid, 4);
3603: iads.data = iads.buffer->data;
3604: iads.len = 12;
3605:
3606: switch (message) {
3607: case DHCPV6_REQUEST:
3608: case DHCPV6_RENEW:
3609: case DHCPV6_REBIND:
3610:
3611: t1 = client->config->requested_lease / 2;
3612: t2 = t1 + (t1 / 2);
3613: #if MAX_TIME > 0xffffffff
3614: if (t1 > 0xffffffff)
3615: t1 = 0xffffffff;
3616: if (t2 > 0xffffffff)
3617: t2 = 0xffffffff;
3618: #endif
3619: putULong(iads.buffer->data + 4, t1);
3620: putULong(iads.buffer->data + 8, t2);
3621:
3622: log_debug("XMT: X-- IA_PD %s",
3623: print_hex_1(4, iads.data, 59));
3624: log_debug("XMT: | X-- Requested renew +%u",
3625: (unsigned) t1);
3626: log_debug("XMT: | X-- Requested rebind +%u",
3627: (unsigned) t2);
3628: break;
3629:
3630: case DHCPV6_RELEASE:
3631: /* Set t1 and t2 to zero; server will ignore them */
3632: memset(iads.buffer->data + 4, 0, 8);
3633: log_debug("XMT: X-- IA_PD %s",
3634: print_hex_1(4, iads.buffer->data, 55));
3635:
3636: break;
3637:
3638: default:
3639: log_fatal("Impossible condition at %s:%d.", MDL);
3640: }
3641:
3642: for (pref = ia->addrs ; pref != NULL ; pref = pref->next) {
3643: /*
3644: * Do not confirm expired prefixes, do not request
3645: * expired prefixes (but we keep them around for
3646: * solicit).
3647: */
3648: if (pref->flags & DHC6_ADDR_EXPIRED)
3649: continue;
3650:
3651: if (pref->address.len != 16) {
3652: log_error("Illegal IPv6 prefix "
3653: "ignoring. (%s:%d)",
3654: MDL);
3655: continue;
3656: }
3657:
3658: if (pref->plen == 0) {
3659: log_info("Null IPv6 prefix, "
3660: "ignoring. (%s:%d)",
3661: MDL);
3662: }
3663:
3664: if (!buffer_allocate(&prefds.buffer, 25, MDL)) {
3665: log_error("Unable to allocate memory for "
3666: "IAPREFIX.");
3667: rval = ISC_R_NOMEMORY;
3668: break;
3669: }
3670:
3671: prefds.data = prefds.buffer->data;
3672: prefds.len = 25;
3673:
3674: /* Copy the prefix into the packet buffer. */
3675: putUChar(prefds.buffer->data + 8, pref->plen);
3676: memcpy(prefds.buffer->data + 9,
3677: pref->address.iabuf,
3678: 16);
3679:
3680: /* Copy in additional information as appropriate */
3681: switch (message) {
3682: case DHCPV6_REQUEST:
3683: case DHCPV6_RENEW:
3684: case DHCPV6_REBIND:
3685: t1 = client->config->requested_lease;
3686: t2 = t1 + 300;
3687: putULong(prefds.buffer->data, t1);
3688: putULong(prefds.buffer->data + 4, t2);
3689:
3690: log_debug("XMT: | | X-- IAPREFIX %s/%u",
3691: piaddr(pref->address),
3692: (unsigned) pref->plen);
3693: log_debug("XMT: | | | X-- Preferred "
3694: "lifetime +%u", (unsigned)t1);
3695: log_debug("XMT: | | | X-- Max lifetime +%u",
3696: (unsigned)t2);
3697:
3698: break;
3699:
3700: case DHCPV6_RELEASE:
3701: /* Preferred and max life are irrelevant */
3702: memset(prefds.buffer->data, 0, 8);
3703: log_debug("XMT: | X-- Release Prefix %s/%u",
3704: piaddr(pref->address),
3705: (unsigned) pref->plen);
3706: break;
3707:
3708: default:
3709: log_fatal("Impossible condition at %s:%d.",
3710: MDL);
3711: }
3712:
3713: append_option(&iads, &dhcpv6_universe,
3714: iaprefix_option, &prefds);
3715: data_string_forget(&prefds, MDL);
3716: }
3717:
3718: /*
3719: * It doesn't make sense to make a request without an
3720: * address.
3721: */
3722: if (ia->addrs == NULL) {
3723: log_debug("!!!: V IA_PD has no IAPREFIXs - removed.");
3724: rval = ISC_R_FAILURE;
3725: } else if (rval == ISC_R_SUCCESS) {
3726: log_debug("XMT: V IA_PD appended.");
3727: append_option(packet, &dhcpv6_universe,
3728: ia_pd_option, &iads);
3729: }
3730:
3731: data_string_forget(&iads, MDL);
3732: }
3733:
3734: return rval;
3735: }
3736:
3737: /* stopping_finished() checks if there is a remaining work to do.
3738: */
3739: static isc_boolean_t
3740: stopping_finished(void)
3741: {
3742: struct interface_info *ip;
3743: struct client_state *client;
3744:
3745: for (ip = interfaces; ip; ip = ip -> next) {
3746: for (client = ip -> client; client; client = client -> next) {
3747: if (client->state != S_STOPPED)
3748: return ISC_FALSE;
3749: if (client->active_lease != NULL)
3750: return ISC_FALSE;
3751: }
3752: }
3753: return ISC_TRUE;
3754: }
3755:
3756: /* reply_handler() accepts a Reply while we're attempting Select or Renew or
3757: * Rebind. Basically any Reply packet.
3758: */
3759: void
3760: reply_handler(struct packet *packet, struct client_state *client)
3761: {
3762: struct dhc6_lease *lease;
3763: isc_result_t check_status;
3764:
3765: if (packet->dhcpv6_msg_type != DHCPV6_REPLY)
3766: return;
3767:
3768: /* RFC3315 section 15.10 validation (same as 15.3 since we
3769: * always include a client id).
3770: */
3771: if (!valid_reply(packet, client)) {
3772: log_error("Invalid Reply - rejecting.");
3773: return;
3774: }
3775:
3776: lease = dhc6_leaseify(packet);
3777:
3778: /* This is an out of memory condition...hopefully a temporary
3779: * problem. Returning now makes us try to retransmit later.
3780: */
3781: if (lease == NULL)
3782: return;
3783:
3784: check_status = dhc6_check_reply(client, lease);
3785: if (check_status != ISC_R_SUCCESS) {
3786: dhc6_lease_destroy(&lease, MDL);
3787:
3788: /* If no action was taken, but there is an error, then
3789: * we wait for a retransmission.
3790: */
3791: if (check_status != ISC_R_CANCELED)
3792: return;
3793: }
3794:
3795: /* We're done retransmitting at this point. */
3796: cancel_timeout(do_confirm6, client);
3797: cancel_timeout(do_select6, client);
3798: cancel_timeout(do_refresh6, client);
3799: cancel_timeout(do_release6, client);
3800:
3801: /* If this is in response to a Release/Decline, clean up and return. */
3802: if (client->state == S_STOPPED) {
3803: if (client->active_lease == NULL)
3804: return;
3805:
3806: dhc6_lease_destroy(&client->active_lease, MDL);
3807: client->active_lease = NULL;
3808: /* We should never wait for nothing!? */
3809: if (stopping_finished())
3810: exit(0);
3811: return;
3812: }
3813:
3814: /* Action was taken, so now that we've torn down our scheduled
3815: * retransmissions, return.
3816: */
3817: if (check_status == ISC_R_CANCELED)
3818: return;
3819:
3820: if (client->selected_lease != NULL) {
3821: dhc6_lease_destroy(&client->selected_lease, MDL);
3822: client->selected_lease = NULL;
3823: }
3824:
3825: /* If this is in response to a confirm, we use the lease we've
3826: * already got, not the reply we were sent.
3827: */
3828: if (client->state == S_REBOOTING) {
3829: if (client->active_lease == NULL)
3830: log_fatal("Impossible condition at %s:%d.", MDL);
3831:
3832: dhc6_lease_destroy(&lease, MDL);
3833: start_bound(client);
3834: return;
3835: }
3836:
3837: /* Merge any bindings in the active lease (if there is one) into
3838: * the new active lease.
3839: */
3840: dhc6_merge_lease(client->active_lease, lease);
3841:
3842: /* Cleanup if a previous attempt to go bound failed. */
3843: if (client->old_lease != NULL) {
3844: dhc6_lease_destroy(&client->old_lease, MDL);
3845: client->old_lease = NULL;
3846: }
3847:
3848: /* Make this lease active and BIND to it. */
3849: if (client->active_lease != NULL)
3850: client->old_lease = client->active_lease;
3851: client->active_lease = lease;
3852:
3853: /* We're done with the ADVERTISEd leases, if any. */
3854: while(client->advertised_leases != NULL) {
3855: lease = client->advertised_leases;
3856: client->advertised_leases = lease->next;
3857:
3858: dhc6_lease_destroy(&lease, MDL);
3859: }
3860:
3861: start_bound(client);
3862: }
3863:
3864: /* DHCPv6 packets are a little sillier than they needed to be - the root
3865: * packet contains options, then IA's which contain options, then within
3866: * that IAADDR's which contain options.
3867: *
3868: * To sort this out at dhclient-script time (which fetches config parameters
3869: * in environment variables), start_bound() iterates over each IAADDR, and
3870: * calls this function to marshall an environment variable set that includes
3871: * the most-specific option values related to that IAADDR in particular.
3872: *
3873: * To achieve this, we load environment variables for the root options space,
3874: * then the IA, then the IAADDR. Any duplicate option names will be
3875: * over-written by the later versions.
3876: */
3877: static void
3878: dhc6_marshall_values(const char *prefix, struct client_state *client,
3879: struct dhc6_lease *lease, struct dhc6_ia *ia,
3880: struct dhc6_addr *addr)
3881: {
3882: /* Option cache contents, in descending order of
3883: * scope.
3884: */
3885: if ((lease != NULL) && (lease->options != NULL))
3886: script_write_params6(client, prefix, lease->options);
3887: if ((ia != NULL) && (ia->options != NULL))
3888: script_write_params6(client, prefix, ia->options);
3889: if ((addr != NULL) && (addr->options != NULL))
3890: script_write_params6(client, prefix, addr->options);
3891:
3892: /* addr fields. */
3893: if (addr != NULL) {
3894: if ((ia != NULL) && (ia->ia_type == D6O_IA_PD)) {
3895: client_envadd(client, prefix,
3896: "ip6_prefix", "%s/%u",
3897: piaddr(addr->address),
3898: (unsigned) addr->plen);
3899: } else {
3900: /* Current practice is that all subnets are /64's, but
3901: * some suspect this may not be permanent.
3902: */
3903: client_envadd(client, prefix, "ip6_prefixlen",
3904: "%d", 64);
3905: client_envadd(client, prefix, "ip6_address",
3906: "%s", piaddr(addr->address));
3907: }
3908: if ((ia != NULL) && (ia->ia_type == D6O_IA_TA)) {
3909: client_envadd(client, prefix,
3910: "ip6_type", "temporary");
3911: }
3912: client_envadd(client, prefix, "life_starts", "%d",
3913: (int)(addr->starts));
3914: client_envadd(client, prefix, "preferred_life", "%d",
3915: (int)(addr->preferred_life));
3916: client_envadd(client, prefix, "max_life", "%d",
3917: (int)(addr->max_life));
3918: }
3919:
3920: /* ia fields. */
3921: if (ia != NULL) {
3922: client_envadd(client, prefix, "iaid", "%s",
3923: print_hex_1(4, ia->iaid, 12));
3924: client_envadd(client, prefix, "starts", "%d",
3925: (int)(ia->starts));
3926: client_envadd(client, prefix, "renew", "%u", ia->renew);
3927: client_envadd(client, prefix, "rebind", "%u", ia->rebind);
3928: }
3929: }
3930:
3931: /* Look at where the client's active lease is sitting. If it's looking to
3932: * time out on renew, rebind, depref, or expiration, do those things.
3933: */
3934: static void
3935: dhc6_check_times(struct client_state *client)
3936: {
3937: struct dhc6_lease *lease;
3938: struct dhc6_ia *ia;
3939: struct dhc6_addr *addr;
3940: TIME renew=MAX_TIME, rebind=MAX_TIME, depref=MAX_TIME,
3941: lo_expire=MAX_TIME, hi_expire=0, tmp;
3942: int has_addrs = ISC_FALSE;
3943: struct timeval tv;
3944:
3945: lease = client->active_lease;
3946:
3947: /* Bit spammy. We should probably keep record of scheduled
3948: * events instead.
3949: */
3950: cancel_timeout(start_renew6, client);
3951: cancel_timeout(start_rebind6, client);
3952: cancel_timeout(do_depref, client);
3953: cancel_timeout(do_expire, client);
3954:
3955: for(ia = lease->bindings ; ia != NULL ; ia = ia->next) {
3956: TIME this_ia_lo_expire, this_ia_hi_expire, use_expire;
3957:
3958: this_ia_lo_expire = MAX_TIME;
3959: this_ia_hi_expire = 0;
3960:
3961: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
3962: if(!(addr->flags & DHC6_ADDR_DEPREFFED)) {
3963: if (addr->preferred_life == 0xffffffff)
3964: tmp = MAX_TIME;
3965: else
3966: tmp = addr->starts +
3967: addr->preferred_life;
3968:
3969: if (tmp < depref)
3970: depref = tmp;
3971: }
3972:
3973: if (!(addr->flags & DHC6_ADDR_EXPIRED)) {
3974: /* Find EPOCH-relative expiration. */
3975: if (addr->max_life == 0xffffffff)
3976: tmp = MAX_TIME;
3977: else
3978: tmp = addr->starts + addr->max_life;
3979:
3980: /* Make the times ia->starts relative. */
3981: tmp -= ia->starts;
3982:
3983: if (tmp > this_ia_hi_expire)
3984: this_ia_hi_expire = tmp;
3985: if (tmp < this_ia_lo_expire)
3986: this_ia_lo_expire = tmp;
3987:
3988: has_addrs = ISC_TRUE;
3989: }
3990: }
3991:
3992: /* These times are ia->starts relative. */
3993: if (this_ia_lo_expire <= (this_ia_hi_expire / 2))
3994: use_expire = this_ia_hi_expire;
3995: else
3996: use_expire = this_ia_lo_expire;
3997:
3998: /*
3999: * If the auto-selected expiration time is "infinite", or
4000: * zero, assert a reasonable default.
4001: */
4002: if ((use_expire == MAX_TIME) || (use_expire <= 1))
4003: use_expire = client->config->requested_lease / 2;
4004: else
4005: use_expire /= 2;
4006:
4007: /* Don't renew/rebind temporary addresses. */
4008: if (ia->ia_type != D6O_IA_TA) {
4009:
4010: if (ia->renew == 0) {
4011: tmp = ia->starts + use_expire;
4012: } else if (ia->renew == 0xffffffff)
4013: tmp = MAX_TIME;
4014: else
4015: tmp = ia->starts + ia->renew;
4016:
4017: if (tmp < renew)
4018: renew = tmp;
4019:
4020: if (ia->rebind == 0) {
4021: /* Set rebind to 3/4 expiration interval. */
4022: tmp = ia->starts;
4023: tmp += use_expire + (use_expire / 2);
1.1.1.1 ! misho 4024: } else if (ia->rebind == 0xffffffff)
1.1 misho 4025: tmp = MAX_TIME;
4026: else
4027: tmp = ia->starts + ia->rebind;
4028:
4029: if (tmp < rebind)
4030: rebind = tmp;
4031: }
4032:
4033: /*
4034: * Return expiration ranges to EPOCH relative for event
4035: * scheduling (add_timeout()).
4036: */
4037: this_ia_hi_expire += ia->starts;
4038: this_ia_lo_expire += ia->starts;
4039:
4040: if (this_ia_hi_expire > hi_expire)
4041: hi_expire = this_ia_hi_expire;
4042: if (this_ia_lo_expire < lo_expire)
4043: lo_expire = this_ia_lo_expire;
4044: }
4045:
4046: /* If there are no addresses, give up, go to INIT.
4047: * Note that if an address is unexpired with a date in the past,
4048: * we're scheduling an expiration event to ocurr in the past. We
4049: * could probably optimize this to expire now (but then there's
4050: * recursion).
4051: *
4052: * In the future, we may decide that we're done here, or to
4053: * schedule a future request (using 4-pkt info-request model).
4054: */
4055: if (has_addrs == ISC_FALSE) {
4056: dhc6_lease_destroy(&client->active_lease, MDL);
4057: client->active_lease = NULL;
4058:
4059: /* Go back to the beginning. */
4060: start_init6(client);
4061: return;
4062: }
4063:
4064: switch(client->state) {
4065: case S_BOUND:
4066: /* We'd like to hit renewing, but if rebinding has already
4067: * passed (time warp), head straight there.
4068: */
4069: if ((rebind > cur_time) && (renew < rebind)) {
4070: log_debug("PRC: Renewal event scheduled in %d seconds, "
4071: "to run for %u seconds.",
4072: (int)(renew - cur_time),
4073: (unsigned)(rebind - renew));
4074: client->next_MRD = rebind;
4075: tv.tv_sec = renew;
4076: tv.tv_usec = 0;
4077: add_timeout(&tv, start_renew6, client, NULL, NULL);
4078:
4079: break;
4080: }
4081: /* FALL THROUGH */
4082: case S_RENEWING:
4083: /* While actively renewing, MRD is bounded by the time
4084: * we stop renewing and start rebinding. This helps us
4085: * process the state change on time.
4086: */
4087: client->MRD = rebind - cur_time;
4088: if (rebind != MAX_TIME) {
4089: log_debug("PRC: Rebind event scheduled in %d seconds, "
4090: "to run for %d seconds.",
4091: (int)(rebind - cur_time),
4092: (int)(hi_expire - rebind));
4093: client->next_MRD = hi_expire;
4094: tv.tv_sec = rebind;
4095: tv.tv_usec = 0;
4096: add_timeout(&tv, start_rebind6, client, NULL, NULL);
4097: }
4098: break;
4099:
4100: case S_REBINDING:
4101: /* For now, we rebind up until the last lease expires. In
4102: * the future, we might want to start SOLICITing when we've
4103: * depreffed an address.
4104: */
4105: client->MRD = hi_expire - cur_time;
4106: break;
4107:
4108: default:
4109: log_fatal("Impossible condition at %s:%d.", MDL);
4110: }
4111:
4112: /* Separately, set a time at which we will depref and expire
4113: * leases. This might happen with multiple addresses while we
4114: * keep trying to refresh.
4115: */
4116: if (depref != MAX_TIME) {
4117: log_debug("PRC: Depreference scheduled in %d seconds.",
4118: (int)(depref - cur_time));
4119: tv.tv_sec = depref;
4120: tv.tv_usec = 0;
4121: add_timeout(&tv, do_depref, client, NULL, NULL);
4122: }
4123: if (lo_expire != MAX_TIME) {
4124: log_debug("PRC: Expiration scheduled in %d seconds.",
4125: (int)(lo_expire - cur_time));
4126: tv.tv_sec = lo_expire;
4127: tv.tv_usec = 0;
4128: add_timeout(&tv, do_expire, client, NULL, NULL);
4129: }
4130: }
4131:
4132: /* In a given IA chain, find the IA with the same type and 'iaid'. */
4133: static struct dhc6_ia *
4134: find_ia(struct dhc6_ia *head, u_int16_t type, const char *id)
4135: {
4136: struct dhc6_ia *ia;
4137:
4138: for (ia = head ; ia != NULL ; ia = ia->next) {
4139: if (ia->ia_type != type)
4140: continue;
4141: if (memcmp(ia->iaid, id, 4) == 0)
4142: return ia;
4143: }
4144:
4145: return NULL;
4146: }
4147:
4148: /* In a given address chain, find a matching address. */
4149: static struct dhc6_addr *
4150: find_addr(struct dhc6_addr *head, struct iaddr *address)
4151: {
4152: struct dhc6_addr *addr;
4153:
4154: for (addr = head ; addr != NULL ; addr = addr->next) {
4155: if ((addr->address.len == address->len) &&
4156: (memcmp(addr->address.iabuf, address->iabuf,
4157: address->len) == 0))
4158: return addr;
4159: }
4160:
4161: return NULL;
4162: }
4163:
4164: /* In a given prefix chain, find a matching prefix. */
4165: static struct dhc6_addr *
4166: find_pref(struct dhc6_addr *head, struct iaddr *prefix, u_int8_t plen)
4167: {
4168: struct dhc6_addr *pref;
4169:
4170: for (pref = head ; pref != NULL ; pref = pref->next) {
4171: if ((pref->address.len == prefix->len) &&
4172: (pref->plen == plen) &&
4173: (memcmp(pref->address.iabuf, prefix->iabuf,
4174: prefix->len) == 0))
4175: return pref;
4176: }
4177:
4178: return NULL;
4179: }
4180:
4181: /* Merge the bindings from the source lease into the destination lease
4182: * structure, where they are missing. We have to copy the stateful
4183: * objects rather than move them over, because later code needs to be
4184: * able to compare new versus old if they contain any bindings.
4185: */
4186: static void
4187: dhc6_merge_lease(struct dhc6_lease *src, struct dhc6_lease *dst)
4188: {
4189: struct dhc6_ia *sia, *dia, *tia;
4190: struct dhc6_addr *saddr, *daddr, *taddr;
4191: int changes = 0;
4192:
4193: if ((dst == NULL) || (src == NULL))
4194: return;
4195:
4196: for (sia = src->bindings ; sia != NULL ; sia = sia->next) {
4197: dia = find_ia(dst->bindings, sia->ia_type, (char *)sia->iaid);
4198:
4199: if (dia == NULL) {
4200: tia = dhc6_dup_ia(sia, MDL);
4201:
4202: if (tia == NULL)
4203: log_fatal("Out of memory merging lease - "
4204: "Unable to continue without losing "
4205: "state! (%s:%d)", MDL);
4206:
4207: /* XXX: consider sorting? */
4208: tia->next = dst->bindings;
4209: dst->bindings = tia;
4210: changes = 1;
4211: } else {
4212: for (saddr = sia->addrs ; saddr != NULL ;
4213: saddr = saddr->next) {
4214: if (sia->ia_type != D6O_IA_PD)
4215: daddr = find_addr(dia->addrs,
4216: &saddr->address);
4217: else
4218: daddr = find_pref(dia->addrs,
4219: &saddr->address,
4220: saddr->plen);
4221:
4222: if (daddr == NULL) {
4223: taddr = dhc6_dup_addr(saddr, MDL);
4224:
4225: if (taddr == NULL)
4226: log_fatal("Out of memory "
4227: "merging lease - "
4228: "Unable to continue "
4229: "without losing "
4230: "state! (%s:%d)",
4231: MDL);
4232:
4233: /* XXX: consider sorting? */
4234: taddr->next = dia->addrs;
4235: dia->addrs = taddr;
4236: changes = 1;
4237: }
4238: }
4239: }
4240: }
4241:
4242: /* If we made changes, reset the score to 0 so it is recalculated. */
4243: if (changes)
4244: dst->score = 0;
4245: }
4246:
4247: /* We've either finished selecting or succeeded in Renew or Rebinding our
4248: * lease. In all cases we got a Reply. Give dhclient-script a tickle
4249: * to inform it about the new values, and then lay in wait for the next
4250: * event.
4251: */
4252: static void
4253: start_bound(struct client_state *client)
4254: {
4255: struct dhc6_ia *ia, *oldia;
4256: struct dhc6_addr *addr, *oldaddr;
4257: struct dhc6_lease *lease, *old;
4258: const char *reason;
4259: TIME dns_update_offset = 1;
4260:
4261: lease = client->active_lease;
4262: if (lease == NULL) {
4263: log_error("Cannot enter bound state unless an active lease "
4264: "is selected.");
4265: return;
4266: }
4267: lease->released = ISC_FALSE;
4268: old = client->old_lease;
4269:
4270: client->v6_handler = bound_handler;
4271:
4272: switch (client->state) {
4273: case S_SELECTING:
4274: case S_REBOOTING: /* Pretend we got bound. */
4275: reason = "BOUND6";
4276: break;
4277:
4278: case S_RENEWING:
4279: reason = "RENEW6";
4280: break;
4281:
4282: case S_REBINDING:
4283: reason = "REBIND6";
4284: break;
4285:
4286: default:
4287: log_fatal("Impossible condition at %s:%d.", MDL);
4288: /* Silence compiler warnings. */
4289: return;
4290: }
4291:
4292: log_debug("PRC: Bound to lease %s.",
4293: print_hex_1(client->active_lease->server_id.len,
4294: client->active_lease->server_id.data, 55));
4295: client->state = S_BOUND;
4296:
4297: write_client6_lease(client, lease, 0, 1);
4298:
4299: oldia = NULL;
4300: for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
4301: if (old != NULL)
4302: oldia = find_ia(old->bindings,
4303: ia->ia_type,
4304: (char *)ia->iaid);
4305: else
4306: oldia = NULL;
4307:
4308: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
4309: if (oldia != NULL) {
4310: if (ia->ia_type != D6O_IA_PD)
4311: oldaddr = find_addr(oldia->addrs,
4312: &addr->address);
4313: else
4314: oldaddr = find_pref(oldia->addrs,
4315: &addr->address,
4316: addr->plen);
4317: } else
4318: oldaddr = NULL;
4319:
4320: if ((oldaddr == NULL) && (ia->ia_type == D6O_IA_NA))
4321: dhclient_schedule_updates(client,
4322: &addr->address,
4323: dns_update_offset++);
4324:
4325: /* Shell out to setup the new binding. */
4326: script_init(client, reason, NULL);
4327:
4328: if (old != NULL)
4329: dhc6_marshall_values("old_", client, old,
4330: oldia, oldaddr);
4331: dhc6_marshall_values("new_", client, lease, ia, addr);
4332:
4333: script_go(client);
4334: }
4335:
4336: /* XXX: maybe we should loop on the old values instead? */
4337: if (ia->addrs == NULL) {
4338: script_init(client, reason, NULL);
4339:
4340: if (old != NULL)
4341: dhc6_marshall_values("old_", client, old,
4342: oldia,
4343: oldia != NULL ?
4344: oldia->addrs : NULL);
4345:
4346: dhc6_marshall_values("new_", client, lease, ia,
4347: NULL);
4348:
4349: script_go(client);
4350: }
4351: }
4352:
4353: /* XXX: maybe we should loop on the old values instead? */
4354: if (lease->bindings == NULL) {
4355: script_init(client, reason, NULL);
4356:
4357: if (old != NULL)
4358: dhc6_marshall_values("old_", client, old,
4359: old->bindings,
4360: (old->bindings != NULL) ?
4361: old->bindings->addrs : NULL);
4362:
4363: dhc6_marshall_values("new_", client, lease, NULL, NULL);
4364:
4365: script_go(client);
4366: }
4367:
4368: go_daemon();
4369:
4370: if (client->old_lease != NULL) {
4371: dhc6_lease_destroy(&client->old_lease, MDL);
4372: client->old_lease = NULL;
4373: }
4374:
4375: /* Schedule events. */
4376: dhc6_check_times(client);
4377: }
4378:
4379: /* While bound, ignore packets. In the future we'll want to answer
4380: * Reconfigure-Request messages and the like.
4381: */
4382: void
4383: bound_handler(struct packet *packet, struct client_state *client)
4384: {
4385: log_debug("RCV: Input packets are ignored once bound.");
4386: }
4387:
4388: /* start_renew6() gets us all ready to go to start transmitting Renew packets.
4389: * Note that client->next_MRD must be set before entering this function -
4390: * it must be set to the time at which the client should start Rebinding.
4391: */
4392: void
4393: start_renew6(void *input)
4394: {
4395: struct client_state *client;
4396:
4397: client = (struct client_state *)input;
4398:
4399: log_info("PRC: Renewing lease on %s.",
4400: client->name ? client->name : client->interface->name);
4401: client->state = S_RENEWING;
4402:
4403: client->v6_handler = reply_handler;
4404:
4405: /* Times per RFC3315 section 18.1.3. */
4406: client->IRT = REN_TIMEOUT * 100;
4407: client->MRT = REN_MAX_RT * 100;
4408: client->MRC = 0;
4409: /* MRD is special in renew - we need to set it by checking timer
4410: * state.
4411: */
4412: client->MRD = client->next_MRD - cur_time;
4413:
4414: dhc6_retrans_init(client);
4415:
4416: client->refresh_type = DHCPV6_RENEW;
4417: do_refresh6(client);
4418: }
4419:
4420: /* do_refresh6() transmits one DHCPv6 packet, be it a Renew or Rebind, and
4421: * gives the retransmission state a bump for the next time. Note that
4422: * client->refresh_type must be set before entering this function.
4423: */
4424: void
4425: do_refresh6(void *input)
4426: {
4427: struct option_cache *oc;
4428: struct sockaddr_in6 unicast, *dest_addr = &DHCPv6DestAddr;
4429: struct data_string ds;
4430: struct client_state *client;
4431: struct dhc6_lease *lease;
4432: struct timeval elapsed, tv;
4433: int send_ret;
4434:
4435: client = (struct client_state *)input;
4436: memset(&ds, 0, sizeof(ds));
4437:
4438: lease = client->active_lease;
4439: if (lease == NULL) {
4440: log_error("Cannot renew without an active binding.");
4441: return;
4442: }
4443:
4444: /* Ensure we're emitting a valid message type. */
4445: switch (client->refresh_type) {
4446: case DHCPV6_RENEW:
4447: case DHCPV6_REBIND:
4448: break;
4449:
4450: default:
4451: log_fatal("Internal inconsistency (%d) at %s:%d.",
4452: client->refresh_type, MDL);
4453: }
4454:
4455: /*
4456: * Start_time starts at the first transmission.
4457: */
4458: if (client->txcount == 0) {
4459: client->start_time.tv_sec = cur_tv.tv_sec;
4460: client->start_time.tv_usec = cur_tv.tv_usec;
4461: }
4462:
4463: /* elapsed = cur - start */
4464: elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
4465: elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
4466: if (elapsed.tv_usec < 0) {
4467: elapsed.tv_sec -= 1;
4468: elapsed.tv_usec += 1000000;
4469: }
4470: if (((client->MRC != 0) && (client->txcount > client->MRC)) ||
4471: ((client->MRD != 0) && (elapsed.tv_sec >= client->MRD))) {
4472: /* We're done. Move on to the next phase, if any. */
4473: dhc6_check_times(client);
4474: return;
4475: }
4476:
4477: /*
4478: * Check whether the server has sent a unicast option; if so, we can
4479: * use the address it specified for RENEWs.
4480: */
4481: oc = lookup_option(&dhcpv6_universe, lease->options, D6O_UNICAST);
4482: if (oc && evaluate_option_cache(&ds, NULL, NULL, NULL,
4483: lease->options, NULL, &global_scope,
4484: oc, MDL)) {
4485: if (ds.len < 16) {
4486: log_error("Invalid unicast option length %d.", ds.len);
4487: } else {
4488: memset(&unicast, 0, sizeof(DHCPv6DestAddr));
4489: unicast.sin6_family = AF_INET6;
4490: unicast.sin6_port = remote_port;
4491: memcpy(&unicast.sin6_addr, ds.data, 16);
4492: if (client->refresh_type == DHCPV6_RENEW) {
4493: dest_addr = &unicast;
4494: }
4495: }
4496:
4497: data_string_forget(&ds, MDL);
4498: }
4499:
4500: /* Commence forming a renew packet. */
4501: memset(&ds, 0, sizeof(ds));
4502: if (!buffer_allocate(&ds.buffer, 4, MDL)) {
4503: log_error("Unable to allocate memory for packet.");
4504: return;
4505: }
4506: ds.data = ds.buffer->data;
4507: ds.len = 4;
4508:
4509: ds.buffer->data[0] = client->refresh_type;
4510: memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
4511:
4512: /* Form an elapsed option. */
4513: /* Maximum value is 65535 1/100s coded as 0xffff. */
4514: if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
4515: ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
4516: client->elapsed = 0xffff;
4517: } else {
4518: client->elapsed = elapsed.tv_sec * 100;
4519: client->elapsed += elapsed.tv_usec / 10000;
4520: }
4521:
4522: if (client->elapsed == 0)
4523: log_debug("XMT: Forming %s, 0 ms elapsed.",
4524: dhcpv6_type_names[client->refresh_type]);
4525: else
4526: log_debug("XMT: Forming %s, %u0 ms elapsed.",
4527: dhcpv6_type_names[client->refresh_type],
4528: (unsigned)client->elapsed);
4529:
4530: client->elapsed = htons(client->elapsed);
4531:
4532: make_client6_options(client, &client->sent_options, lease,
4533: client->refresh_type);
4534:
4535: /* Put in any options from the sent cache. */
4536: dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
4537: client->sent_options, &global_scope,
4538: &dhcpv6_universe);
4539:
4540: /* Append IA's */
4541: if (wanted_ia_na &&
4542: dhc6_add_ia_na(client, &ds, lease,
4543: client->refresh_type) != ISC_R_SUCCESS) {
4544: data_string_forget(&ds, MDL);
4545: return;
4546: }
4547: if (wanted_ia_pd &&
4548: dhc6_add_ia_pd(client, &ds, lease,
4549: client->refresh_type) != ISC_R_SUCCESS) {
4550: data_string_forget(&ds, MDL);
4551: return;
4552: }
4553:
4554: log_info("XMT: %s on %s, interval %ld0ms.",
4555: dhcpv6_type_names[client->refresh_type],
4556: client->name ? client->name : client->interface->name,
4557: (long int)client->RT);
4558:
4559: send_ret = send_packet6(client->interface, ds.data, ds.len, dest_addr);
4560:
4561: if (send_ret != ds.len) {
4562: log_error("dhc6: send_packet6() sent %d of %d bytes",
4563: send_ret, ds.len);
4564: }
4565:
4566: data_string_forget(&ds, MDL);
4567:
4568: /* Wait RT */
4569: tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
4570: tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
4571: if (tv.tv_usec >= 1000000) {
4572: tv.tv_sec += 1;
4573: tv.tv_usec -= 1000000;
4574: }
4575: add_timeout(&tv, do_refresh6, client, NULL, NULL);
4576:
4577: dhc6_retrans_advance(client);
4578: }
4579:
4580: /* start_rebind6() gets us all set up to go and rebind a lease. Note that
4581: * client->next_MRD must be set before entering this function. In this case,
4582: * MRD must be set to the maximum time any address in the packet will
4583: * expire.
4584: */
4585: void
4586: start_rebind6(void *input)
4587: {
4588: struct client_state *client;
4589:
4590: client = (struct client_state *)input;
4591:
4592: log_info("PRC: Rebinding lease on %s.",
4593: client->name ? client->name : client->interface->name);
4594: client->state = S_REBINDING;
4595:
4596: client->v6_handler = reply_handler;
4597:
4598: /* Times per RFC3315 section 18.1.4. */
4599: client->IRT = REB_TIMEOUT * 100;
4600: client->MRT = REB_MAX_RT * 100;
4601: client->MRC = 0;
4602: /* MRD is special in rebind - it's determined by the timer
4603: * state.
4604: */
4605: client->MRD = client->next_MRD - cur_time;
4606:
4607: dhc6_retrans_init(client);
4608:
4609: client->refresh_type = DHCPV6_REBIND;
4610: do_refresh6(client);
4611: }
4612:
4613: /* do_depref() runs through a given lease's addresses, for each that has
4614: * not yet been depreffed, shells out to the dhclient-script to inform it
4615: * of the status change. The dhclient-script should then do...something...
4616: * to encourage applications to move off the address and onto one of the
4617: * remaining 'preferred' addresses.
4618: */
4619: void
4620: do_depref(void *input)
4621: {
4622: struct client_state *client;
4623: struct dhc6_lease *lease;
4624: struct dhc6_ia *ia;
4625: struct dhc6_addr *addr;
4626:
4627: client = (struct client_state *)input;
4628:
4629: lease = client->active_lease;
4630: if (lease == NULL)
4631: return;
4632:
4633: for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
4634: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
4635: if (addr->flags & DHC6_ADDR_DEPREFFED)
4636: continue;
4637:
4638: if (addr->starts + addr->preferred_life <= cur_time) {
4639: script_init(client, "DEPREF6", NULL);
4640: dhc6_marshall_values("cur_", client, lease,
4641: ia, addr);
4642: script_go(client);
4643:
4644: addr->flags |= DHC6_ADDR_DEPREFFED;
4645:
4646: if (ia->ia_type != D6O_IA_PD)
4647: log_info("PRC: Address %s depreferred.",
4648: piaddr(addr->address));
4649: else
4650: log_info("PRC: Prefix %s/%u depreferred.",
4651: piaddr(addr->address),
4652: (unsigned) addr->plen);
4653:
4654: /* Remove DDNS bindings at depref time. */
4655: if ((ia->ia_type == D6O_IA_NA) &&
4656: client->config->do_forward_update)
4657: client_dns_update(client, 0, 0,
4658: &addr->address);
4659: }
4660: }
4661: }
4662:
4663: dhc6_check_times(client);
4664: }
4665:
4666: /* do_expire() searches through all the addresses on a given lease, and
4667: * expires/removes any addresses that are no longer valid.
4668: */
4669: void
4670: do_expire(void *input)
4671: {
4672: struct client_state *client;
4673: struct dhc6_lease *lease;
4674: struct dhc6_ia *ia;
4675: struct dhc6_addr *addr;
4676: int has_addrs = ISC_FALSE;
4677:
4678: client = (struct client_state *)input;
4679:
4680: lease = client->active_lease;
4681: if (lease == NULL)
4682: return;
4683:
4684: for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
4685: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
4686: if (addr->flags & DHC6_ADDR_EXPIRED)
4687: continue;
4688:
4689: if (addr->starts + addr->max_life <= cur_time) {
4690: script_init(client, "EXPIRE6", NULL);
4691: dhc6_marshall_values("old_", client, lease,
4692: ia, addr);
4693: script_go(client);
4694:
4695: addr->flags |= DHC6_ADDR_EXPIRED;
4696:
4697: if (ia->ia_type != D6O_IA_PD)
4698: log_info("PRC: Address %s expired.",
4699: piaddr(addr->address));
4700: else
4701: log_info("PRC: Prefix %s/%u expired.",
4702: piaddr(addr->address),
4703: (unsigned) addr->plen);
4704:
4705: /* We remove DNS records at depref time, but
4706: * it is possible that we might get here
4707: * without depreffing.
4708: */
4709: if ((ia->ia_type == D6O_IA_NA) &&
4710: client->config->do_forward_update &&
4711: !(addr->flags & DHC6_ADDR_DEPREFFED))
4712: client_dns_update(client, 0, 0,
4713: &addr->address);
4714:
4715: continue;
4716: }
4717:
4718: has_addrs = ISC_TRUE;
4719: }
4720: }
4721:
4722: /* Clean up empty leases. */
4723: if (has_addrs == ISC_FALSE) {
4724: log_info("PRC: Bound lease is devoid of active addresses."
4725: " Re-initializing.");
4726:
4727: dhc6_lease_destroy(&lease, MDL);
4728: client->active_lease = NULL;
4729:
4730: start_init6(client);
4731: return;
4732: }
4733:
4734: /* Schedule the next run through. */
4735: dhc6_check_times(client);
4736: }
4737:
4738: /*
4739: * Run client script to unconfigure interface.
4740: * Called with reason STOP6 when dhclient -x is run, or with reason
4741: * RELEASE6 when server has replied to a Release message.
4742: * Stateless is a special case.
4743: */
4744: void
4745: unconfigure6(struct client_state *client, const char *reason)
4746: {
4747: struct dhc6_ia *ia;
4748: struct dhc6_addr *addr;
4749:
4750: if (stateless) {
4751: script_init(client, reason, NULL);
4752: if (client->active_lease != NULL)
4753: script_write_params6(client, "old_",
4754: client->active_lease->options);
4755: script_go(client);
4756: return;
4757: }
4758:
4759: if (client->active_lease == NULL)
4760: return;
4761:
4762: for (ia = client->active_lease->bindings ; ia != NULL ; ia = ia->next) {
4763: if (ia->ia_type == D6O_IA_TA)
4764: continue;
4765:
4766: for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
4767: script_init(client, reason, NULL);
4768: dhc6_marshall_values("old_", client,
4769: client->active_lease, ia, addr);
4770: script_go(client);
4771:
4772: if ((ia->ia_type == D6O_IA_NA) &&
4773: client->config->do_forward_update)
4774: client_dns_update(client, 0, 0, &addr->address);
4775: }
4776: }
4777: }
4778:
4779: void
4780: refresh_info_request6(void *input)
4781: {
4782: struct client_state *client;
4783:
4784: client = (struct client_state *)input;
4785: start_info_request6(client);
4786: }
4787:
4788: /* Timeout for Information-Request (using the IRT option).
4789: */
4790: static void
4791: dhc6_check_irt(struct client_state *client)
4792: {
4793: struct option **req;
4794: struct option_cache *oc;
4795: TIME expire = MAX_TIME;
4796: struct timeval tv;
4797: int i;
4798: isc_boolean_t found = ISC_FALSE;
4799:
4800: cancel_timeout(refresh_info_request6, client);
4801:
4802: req = client->config->requested_options;
4803: for (i = 0; req[i] != NULL; i++) {
4804: if (req[i] == irt_option) {
4805: found = ISC_TRUE;
4806: break;
4807: }
4808: }
4809: /* Simply return gives a endless loop waiting for nothing. */
4810: if (!found)
4811: exit(0);
4812:
4813: oc = lookup_option(&dhcpv6_universe, client->active_lease->options,
4814: D6O_INFORMATION_REFRESH_TIME);
4815: if (oc != NULL) {
4816: struct data_string irt;
4817:
4818: memset(&irt, 0, sizeof(irt));
4819: if (!evaluate_option_cache(&irt, NULL, NULL, client,
4820: client->active_lease->options,
4821: NULL, &global_scope, oc, MDL) ||
4822: (irt.len < 4)) {
4823: log_error("Can't evaluate IRT.");
4824: } else {
4825: expire = getULong(irt.data);
4826: if (expire < IRT_MINIMUM)
4827: expire = IRT_MINIMUM;
4828: if (expire == 0xffffffff)
4829: expire = MAX_TIME;
4830: }
4831: data_string_forget(&irt, MDL);
4832: } else
4833: expire = IRT_DEFAULT;
4834:
4835: if (expire != MAX_TIME) {
4836: log_debug("PRC: Refresh event scheduled in %u seconds.",
4837: (unsigned) expire);
4838: tv.tv_sec = cur_time + expire;
4839: tv.tv_usec = 0;
4840: add_timeout(&tv, refresh_info_request6, client, NULL, NULL);
4841: }
4842: }
4843:
4844: /* We got a Reply. Give dhclient-script a tickle to inform it about
4845: * the new values, and then lay in wait for the next event.
4846: */
4847: static void
4848: start_informed(struct client_state *client)
4849: {
4850: client->v6_handler = informed_handler;
4851:
4852: log_debug("PRC: Done.");
4853:
4854: client->state = S_BOUND;
4855:
4856: script_init(client, "RENEW6", NULL);
4857: if (client->old_lease != NULL)
4858: script_write_params6(client, "old_",
4859: client->old_lease->options);
4860: script_write_params6(client, "new_", client->active_lease->options);
4861: script_go(client);
4862:
4863: go_daemon();
4864:
4865: if (client->old_lease != NULL) {
4866: dhc6_lease_destroy(&client->old_lease, MDL);
4867: client->old_lease = NULL;
4868: }
4869:
4870: /* Schedule events. */
4871: dhc6_check_irt(client);
4872: }
4873:
4874: /* While informed, ignore packets.
4875: */
4876: void
4877: informed_handler(struct packet *packet, struct client_state *client)
4878: {
4879: log_debug("RCV: Input packets are ignored once bound.");
4880: }
4881:
4882: /* make_client6_options() fetches option caches relevant to the client's
4883: * scope and places them into the sent_options cache. This cache is later
4884: * used to populate DHCPv6 output packets with options.
4885: */
4886: static void
4887: make_client6_options(struct client_state *client, struct option_state **op,
4888: struct dhc6_lease *lease, u_int8_t message)
4889: {
4890: struct option_cache *oc;
4891: struct option **req;
4892: struct buffer *buffer;
4893: int buflen, i, oro_len;
4894:
4895: if ((op == NULL) || (client == NULL))
4896: return;
4897:
4898: if (*op)
4899: option_state_dereference(op, MDL);
4900:
4901: /* Create a cache to carry options to transmission. */
4902: option_state_allocate(op, MDL);
4903:
4904: /* Create and store an 'elapsed time' option in the cache. */
4905: oc = NULL;
4906: if (option_cache_allocate(&oc, MDL)) {
4907: const unsigned char *cdata;
4908:
4909: cdata = (unsigned char *)&client->elapsed;
4910:
4911: if (make_const_data(&oc->expression, cdata, 2, 0, 0, MDL)) {
4912: option_reference(&oc->option, elapsed_option, MDL);
4913: save_option(&dhcpv6_universe, *op, oc);
4914: }
4915:
4916: option_cache_dereference(&oc, MDL);
4917: }
4918:
4919: /* Bring in any configured options to send. */
4920: if (client->config->on_transmission)
4921: execute_statements_in_scope(NULL, NULL, NULL, client,
4922: lease ? lease->options : NULL,
4923: *op, &global_scope,
4924: client->config->on_transmission,
4925: NULL);
4926:
4927: /* Rapid-commit is only for SOLICITs. */
4928: if (message != DHCPV6_SOLICIT)
4929: delete_option(&dhcpv6_universe, *op, D6O_RAPID_COMMIT);
4930:
4931: /* See if the user configured a DUID in a relevant scope. If not,
4932: * introduce our default manufactured id.
4933: */
4934: if ((oc = lookup_option(&dhcpv6_universe, *op,
4935: D6O_CLIENTID)) == NULL) {
4936: if (!option_cache(&oc, &default_duid, NULL, clientid_option,
4937: MDL))
4938: log_fatal("Failure assembling a DUID.");
4939:
4940: save_option(&dhcpv6_universe, *op, oc);
4941: option_cache_dereference(&oc, MDL);
4942: }
4943:
4944: /* In cases where we're responding to a single server, put the
4945: * server's id in the response.
4946: *
4947: * Note that lease is NULL for SOLICIT or INFO request messages,
4948: * and otherwise MUST be present.
4949: */
4950: if (lease == NULL) {
4951: if ((message != DHCPV6_SOLICIT) &&
4952: (message != DHCPV6_INFORMATION_REQUEST))
4953: log_fatal("Impossible condition at %s:%d.", MDL);
4954: } else if ((message != DHCPV6_REBIND) &&
4955: (message != DHCPV6_CONFIRM)) {
4956: oc = lookup_option(&dhcpv6_universe, lease->options,
4957: D6O_SERVERID);
4958: if (oc != NULL)
4959: save_option(&dhcpv6_universe, *op, oc);
4960: }
4961:
4962: /* 'send dhcp6.oro foo;' syntax we used in 4.0.0a1/a2 has been
4963: * deprecated by adjustments to the 'request' syntax also used for
4964: * DHCPv4.
4965: */
4966: if (lookup_option(&dhcpv6_universe, *op, D6O_ORO) != NULL)
4967: log_error("'send dhcp6.oro' syntax is deprecated, please "
4968: "use the 'request' syntax (\"man dhclient.conf\").");
4969:
4970: /* Construct and store an ORO (Option Request Option). It is a
4971: * fatal error to fail to send an ORO (of at least zero length).
4972: *
4973: * Discussion: RFC3315 appears to be inconsistent in its statements
4974: * of whether or not the ORO is mandatory. In section 18.1.1
4975: * ("Creation and Transmission of Request Messages"):
4976: *
4977: * The client MUST include an Option Request option (see section
4978: * 22.7) to indicate the options the client is interested in
4979: * receiving. The client MAY include options with data values as
4980: * hints to the server about parameter values the client would like
4981: * to have returned.
4982: *
4983: * This MUST is missing from the creation/transmission of other
4984: * messages (such as Renew and Rebind), and the section 22.7 ("Option
4985: * Request Option" format and definition):
4986: *
4987: * A client MAY include an Option Request option in a Solicit,
4988: * Request, Renew, Rebind, Confirm or Information-request message to
4989: * inform the server about options the client wants the server to
4990: * send to the client. A server MAY include an Option Request
4991: * option in a Reconfigure option to indicate which options the
4992: * client should request from the server.
4993: *
4994: * seems to relax the requirement from MUST to MAY (and still other
4995: * language in RFC3315 supports this).
4996: *
4997: * In lieu of a clarification of RFC3315, we will conform with the
4998: * MUST. Instead of an absent ORO, we will if there are no options
4999: * to request supply an empty ORO. Theoretically, an absent ORO is
5000: * difficult to interpret (does the client want all options or no
5001: * options?). A zero-length ORO is intuitively clear: requesting
5002: * nothing.
5003: */
5004: buffer = NULL;
5005: oro_len = 0;
5006: buflen = 32;
5007: if (!buffer_allocate(&buffer, buflen, MDL))
5008: log_fatal("Out of memory constructing DHCPv6 ORO.");
5009: req = client->config->requested_options;
5010: if (req != NULL) {
5011: for (i = 0 ; req[i] != NULL ; i++) {
5012: if (buflen == oro_len) {
5013: struct buffer *tmpbuf = NULL;
5014:
5015: buflen += 32;
5016:
5017: /* Shell game. */
5018: buffer_reference(&tmpbuf, buffer, MDL);
5019: buffer_dereference(&buffer, MDL);
5020:
5021: if (!buffer_allocate(&buffer, buflen, MDL))
5022: log_fatal("Out of memory resizing "
5023: "DHCPv6 ORO buffer.");
5024:
5025: memcpy(buffer->data, tmpbuf->data, oro_len);
5026:
5027: buffer_dereference(&tmpbuf, MDL);
5028: }
5029:
5030: if (req[i]->universe == &dhcpv6_universe) {
5031: /* Append the code to the ORO. */
5032: putUShort(buffer->data + oro_len,
5033: req[i]->code);
5034: oro_len += 2;
5035: }
5036: }
5037: }
5038:
5039: oc = NULL;
5040: if (make_const_option_cache(&oc, &buffer, NULL, oro_len,
5041: oro_option, MDL)) {
5042: save_option(&dhcpv6_universe, *op, oc);
5043: } else {
5044: log_fatal("Unable to create ORO option cache.");
5045: }
5046:
5047: /*
5048: * Note: make_const_option_cache() consumes the buffer, we do not
5049: * need to dereference it (XXX).
5050: */
5051: option_cache_dereference(&oc, MDL);
5052: }
5053:
5054: /* A clone of the DHCPv4 script_write_params() minus the DHCPv4-specific
5055: * filename, server-name, etc specifics.
5056: *
5057: * Simply, store all values present in all universes of the option state
5058: * (probably derived from a DHCPv6 packet) into environment variables
5059: * named after the option names (and universe names) but with the 'prefix'
5060: * prepended.
5061: *
5062: * Later, dhclient-script may compare for example "new_time_servers" and
5063: * "old_time_servers" for differences, and only upon detecting a change
5064: * bother to rewrite ntp.conf and restart it. Or something along those
5065: * generic lines.
5066: */
5067: static void
5068: script_write_params6(struct client_state *client, const char *prefix,
5069: struct option_state *options)
5070: {
5071: struct envadd_state es;
5072: int i;
5073:
5074: if (options == NULL)
5075: return;
5076:
5077: es.client = client;
5078: es.prefix = prefix;
5079:
5080: for (i = 0 ; i < options->universe_count ; i++) {
5081: option_space_foreach(NULL, NULL, client, NULL, options,
5082: &global_scope, universes[i], &es,
5083: client_option_envadd);
5084: }
5085: }
5086:
5087: /*
5088: * Check if there is something not fully defined in the active lease.
5089: */
5090: static isc_boolean_t
5091: active_prefix(struct client_state *client)
5092: {
5093: struct dhc6_lease *lease;
5094: struct dhc6_ia *ia;
5095: struct dhc6_addr *pref;
5096: char zeros[16];
5097:
5098: lease = client->active_lease;
5099: if (lease == NULL)
5100: return ISC_FALSE;
5101: memset(zeros, 0, 16);
5102: for (ia = lease->bindings; ia != NULL; ia = ia->next) {
5103: if (ia->ia_type != D6O_IA_PD)
5104: continue;
5105: for (pref = ia->addrs; pref != NULL; pref = pref->next) {
5106: if (pref->plen == 0)
5107: return ISC_FALSE;
5108: if (pref->address.len != 16)
5109: return ISC_FALSE;
5110: if (memcmp(pref->address.iabuf, zeros, 16) == 0)
5111: return ISC_FALSE;
5112: }
5113: }
5114: return ISC_TRUE;
5115: }
5116: #endif /* DHCPv6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>