3 Parser for dhcpd config file... */
6 * Copyright (c) 2004-2013 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
25 * https://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
37 static unsigned char global_host_once
= 1;
38 static unsigned char dhcpv6_class_once
= 1;
40 static int parse_binding_value(struct parse
*cfile
,
41 struct binding_value
*value
);
44 trace_type_t
*trace_readconf_type
;
45 trace_type_t
*trace_readleases_type
;
47 void parse_trace_setup ()
49 trace_readconf_type
= trace_type_register ("readconf", (void *)0,
51 trace_conf_stop
, MDL
);
52 trace_readleases_type
= trace_type_register ("readleases", (void *)0,
54 trace_conf_stop
, MDL
);
58 /* conf-file :== parameters declarations END_OF_FILE
59 parameters :== <nil> | parameter | parameters parameter
60 declarations :== <nil> | declaration | declarations declaration */
62 isc_result_t
readconf ()
66 res
= read_conf_file (path_dhcpd_conf
, root_group
, ROOT_GROUP
, 0);
67 #if defined(LDAP_CONFIGURATION)
68 if (res
!= ISC_R_SUCCESS
)
71 return ldap_read_config ();
77 isc_result_t
read_conf_file (const char *filename
, struct group
*group
,
78 int group_type
, int leasep
)
91 ttype
= trace_readleases_type
;
93 ttype
= trace_readconf_type
;
95 /* If we're in playback, we need to snarf the contents of the
96 named file out of the playback file rather than trying to
98 if (trace_playback ()) {
101 status
= trace_get_file (ttype
, filename
, &tflen
, &dbuf
);
102 if (status
!= ISC_R_SUCCESS
)
106 /* What we get back is filename\0contents, where contents is
107 terminated just by the length. So we figure out the length
108 of the filename, and subtract that and the NUL from the
109 total length to get the length of the contents of the file.
110 We make fbuf a pointer to the contents of the file, and
111 leave dbuf as it is so we can free it later. */
112 tflen
= strlen (dbuf
);
113 ulen
= ulen
- tflen
- 1;
114 fbuf
= dbuf
+ tflen
+ 1;
119 if ((file
= open (filename
, O_RDONLY
)) < 0) {
121 log_error ("Can't open lease database %s: %m --",
123 log_error (" check for failed database %s!",
125 log_error ("Please read the dhcpd.leases manual%s",
127 log_fatal ("don't know what to do about this.");
129 log_fatal ("Can't open %s: %m", filename
);
133 cfile
= (struct parse
*)0;
134 #if defined (TRACING)
135 flen
= lseek (file
, (off_t
)0, SEEK_END
);
138 log_fatal ("Can't lseek on %s: %m", filename
);
140 if (lseek (file
, (off_t
)0, SEEK_SET
) < 0)
142 /* Can't handle files greater than 2^31-1. */
143 if (flen
> 0x7FFFFFFFUL
)
144 log_fatal ("%s: file is too long to buffer.", filename
);
147 /* Allocate a buffer that will be what's written to the tracefile,
148 and also will be what we parse from. */
149 tflen
= strlen (filename
);
150 dbuf
= dmalloc (ulen
+ tflen
+ 1, MDL
);
152 log_fatal ("No memory for %s (%d bytes)",
155 /* Copy the name into the beginning, nul-terminated. */
156 strcpy (dbuf
, filename
);
158 /* Load the file in after the NUL. */
159 fbuf
= dbuf
+ tflen
+ 1;
160 result
= read (file
, fbuf
, ulen
);
162 log_fatal ("Can't read in %s: %m", filename
);
164 log_fatal ("%s: short read of %d bytes instead of %d.",
165 filename
, ulen
, result
);
168 /* If we're recording, write out the filename and file contents. */
170 trace_write_packet (ttype
, ulen
+ tflen
+ 1, dbuf
, MDL
);
171 status
= new_parse(&cfile
, -1, fbuf
, ulen
, filename
, 0); /* XXX */
173 status
= new_parse(&cfile
, file
, NULL
, 0, filename
, 0);
175 if (status
!= ISC_R_SUCCESS
|| cfile
== NULL
)
179 status
= lease_file_subparse (cfile
);
181 status
= conf_file_subparse (cfile
, group
, group_type
);
183 #if defined (TRACING)
189 #if defined (TRACING)
190 void trace_conf_input (trace_type_t
*ttype
, unsigned len
, char *data
)
195 struct parse
*cfile
= (struct parse
*)0;
196 static int postconf_initialized
;
197 static int leaseconf_initialized
;
200 /* Do what's done above, except that we don't have to read in the
201 data, because it's already been read for us. */
202 tflen
= strlen (data
);
203 flen
= len
- tflen
- 1;
204 fbuf
= data
+ tflen
+ 1;
206 /* If we're recording, write out the filename and file contents. */
208 trace_write_packet (ttype
, len
, data
, MDL
);
210 status
= new_parse(&cfile
, -1, fbuf
, flen
, data
, 0);
211 if (status
== ISC_R_SUCCESS
|| cfile
!= NULL
) {
212 if (ttype
== trace_readleases_type
)
213 lease_file_subparse (cfile
);
215 conf_file_subparse (cfile
, root_group
, ROOT_GROUP
);
219 /* Postconfiguration needs to be done after the config file
221 if (!postconf_initialized
&& ttype
== trace_readconf_type
) {
222 postconf_initialization (0);
223 postconf_initialized
= 1;
226 if (!leaseconf_initialized
&& ttype
== trace_readleases_type
) {
228 leaseconf_initialized
= 1;
233 void trace_conf_stop (trace_type_t
*ttype
) { }
236 /* conf-file :== parameters declarations END_OF_FILE
237 parameters :== <nil> | parameter | parameters parameter
238 declarations :== <nil> | declaration | declarations declaration */
240 isc_result_t
conf_file_subparse (struct parse
*cfile
, struct group
*group
,
244 enum dhcp_token token
;
249 token
= peek_token (&val
, (unsigned *)0, cfile
);
250 if (token
== END_OF_FILE
)
252 declaration
= parse_statement (cfile
, group
, group_type
,
253 (struct host_decl
*)0,
256 skip_token(&val
, (unsigned *)0, cfile
);
258 status
= cfile
->warnings_occurred
? DHCP_R_BADPARSE
: ISC_R_SUCCESS
;
262 /* lease-file :== lease-declarations END_OF_FILE
263 lease-statements :== <nil>
265 | lease-declarations lease-declaration */
267 isc_result_t
lease_file_subparse (struct parse
*cfile
)
270 enum dhcp_token token
;
274 token
= next_token (&val
, (unsigned *)0, cfile
);
275 if (token
== END_OF_FILE
)
277 if (token
== LEASE
) {
278 struct lease
*lease
= (struct lease
*)0;
279 if (parse_lease_declaration (&lease
, cfile
)) {
281 lease_dereference (&lease
, MDL
);
284 "possibly corrupt lease file");
285 } else if (token
== IA_NA
) {
286 parse_ia_na_declaration(cfile
);
287 } else if (token
== IA_TA
) {
288 parse_ia_ta_declaration(cfile
);
289 } else if (token
== IA_PD
) {
290 parse_ia_pd_declaration(cfile
);
291 } else if (token
== CLASS
) {
292 parse_class_declaration(0, cfile
, root_group
,
294 } else if (token
== SUBCLASS
) {
295 parse_class_declaration(0, cfile
, root_group
,
296 CLASS_TYPE_SUBCLASS
);
297 } else if (token
== HOST
) {
298 parse_host_declaration (cfile
, root_group
);
299 } else if (token
== GROUP
) {
300 parse_group_declaration (cfile
, root_group
);
301 #if defined (FAILOVER_PROTOCOL)
302 } else if (token
== FAILOVER
) {
303 parse_failover_state_declaration
304 (cfile
, (dhcp_failover_state_t
*)0);
307 } else if (token
== SERVER_DUID
) {
308 parse_server_duid(cfile
);
311 log_error ("Corrupt lease file - possible data loss!");
312 skip_to_semi (cfile
);
317 status
= cfile
->warnings_occurred
? DHCP_R_BADPARSE
: ISC_R_SUCCESS
;
321 /* statement :== parameter | declaration
323 parameter :== DEFAULT_LEASE_TIME lease_time
324 | MAX_LEASE_TIME lease_time
325 | DYNAMIC_BOOTP_LEASE_CUTOFF date
326 | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
327 | BOOT_UNKNOWN_CLIENTS boolean
328 | ONE_LEASE_PER_CLIENT boolean
329 | GET_LEASE_HOSTNAMES boolean
330 | USE_HOST_DECL_NAME boolean
331 | NEXT_SERVER ip-addr-or-hostname SEMI
333 | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
334 | FILENAME string-parameter
335 | SERVER_NAME string-parameter
337 | fixed-address-parameter
338 | ALLOW allow-deny-keyword
339 | DENY allow-deny-keyword
340 | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
344 declaration :== host-declaration
346 | shared-network-declaration
348 | VENDOR_CLASS class-declaration
349 | USER_CLASS class-declaration
350 | RANGE address-range-declaration */
352 int parse_statement (cfile
, group
, type
, host_decl
, declaration
)
356 struct host_decl
*host_decl
;
359 enum dhcp_token token
;
361 struct shared_network
*share
;
363 struct hardware hardware
;
364 struct executable_statement
*et
, *ep
;
365 struct option
*option
= NULL
;
366 struct option_cache
*cache
;
372 token
= peek_token (&val
, (unsigned *)0, cfile
);
376 skip_token(&val
, (unsigned *)0, cfile
);
377 token
= next_token (&val
, (unsigned *)0, cfile
);
378 if (token
!= STRING
) {
379 parse_warn (cfile
, "filename string expected.");
380 skip_to_semi (cfile
);
382 status
= read_conf_file (val
, group
, type
, 0);
383 if (status
!= ISC_R_SUCCESS
)
384 parse_warn (cfile
, "%s: bad parse.", val
);
390 skip_token(&val
, (unsigned *)0, cfile
);
391 if (type
!= HOST_DECL
&& type
!= CLASS_DECL
) {
392 if (global_host_once
&&
393 (type
== SUBNET_DECL
|| type
== SHARED_NET_DECL
)) {
394 global_host_once
= 0;
395 log_error("WARNING: Host declarations are "
396 "global. They are not limited to "
397 "the scope you declared them in.");
400 parse_host_declaration (cfile
, group
);
403 "host declarations not allowed here.");
404 skip_to_semi (cfile
);
409 skip_token(&val
, (unsigned *)0, cfile
);
410 if (type
!= HOST_DECL
&& type
!= CLASS_DECL
)
411 parse_group_declaration (cfile
, group
);
414 "group declarations not allowed here.");
415 skip_to_semi (cfile
);
420 skip_token(&val
, (unsigned *)0, cfile
);
421 if (type
== SHARED_NET_DECL
||
423 type
== SUBNET_DECL
||
424 type
== CLASS_DECL
) {
425 parse_warn (cfile
, "shared-network parameters not %s.",
427 skip_to_semi (cfile
);
431 parse_shared_net_declaration (cfile
, group
);
436 skip_token(&val
, (unsigned *)0, cfile
);
437 if (type
== HOST_DECL
|| type
== SUBNET_DECL
||
438 type
== CLASS_DECL
) {
440 "subnet declarations not allowed here.");
441 skip_to_semi (cfile
);
445 /* If we're in a subnet declaration, just do the parse. */
446 if (group
->shared_network
!= NULL
) {
447 if (token
== SUBNET
) {
448 parse_subnet_declaration(cfile
,
449 group
->shared_network
);
451 parse_subnet6_declaration(cfile
,
452 group
->shared_network
);
458 * Otherwise, cons up a fake shared network structure
459 * and populate it with the lone subnet...because the
460 * intention most likely is to refer to the entire link
461 * by shorthand, any configuration inside the subnet is
462 * actually placed in the shared-network's group.
466 status
= shared_network_allocate (&share
, MDL
);
467 if (status
!= ISC_R_SUCCESS
)
468 log_fatal ("Can't allocate shared subnet: %s",
469 isc_result_totext (status
));
470 if (!clone_group (&share
-> group
, group
, MDL
))
471 log_fatal ("Can't allocate group for shared net");
472 shared_network_reference (&share
-> group
-> shared_network
,
476 * This is an implicit shared network, not explicit in
479 share
->flags
|= SHARED_IMPLICIT
;
481 if (token
== SUBNET
) {
482 parse_subnet_declaration(cfile
, share
);
484 parse_subnet6_declaration(cfile
, share
);
487 /* share -> subnets is the subnet we just parsed. */
488 if (share
->subnets
) {
489 interface_reference(&share
->interface
,
490 share
->subnets
->interface
,
493 /* Make the shared network name from network number. */
494 if (token
== SUBNET
) {
495 n
= piaddrmask(&share
->subnets
->net
,
496 &share
->subnets
->netmask
);
498 n
= piaddrcidr(&share
->subnets
->net
,
499 share
->subnets
->prefix_len
);
502 share
->name
= strdup(n
);
504 if (share
->name
== NULL
)
505 log_fatal("Out of memory allocating default "
506 "shared network name (\"%s\").", n
);
508 /* Copy the authoritative parameter from the subnet,
509 since there is no opportunity to declare it here. */
510 share
->group
->authoritative
=
511 share
->subnets
->group
->authoritative
;
512 enter_shared_network(share
);
514 shared_network_dereference(&share
, MDL
);
518 skip_token(&val
, (unsigned *)0, cfile
);
519 if (type
== CLASS_DECL
) {
521 "class declarations not allowed here.");
522 skip_to_semi (cfile
);
525 parse_class_declaration(NULL
, cfile
, group
, CLASS_TYPE_VENDOR
);
529 skip_token(&val
, (unsigned *)0, cfile
);
530 if (type
== CLASS_DECL
) {
532 "class declarations not allowed here.");
533 skip_to_semi (cfile
);
536 parse_class_declaration(NULL
, cfile
, group
, CLASS_TYPE_USER
);
540 skip_token(&val
, (unsigned *)0, cfile
);
541 if (type
== CLASS_DECL
) {
543 "class declarations not allowed here.");
544 skip_to_semi (cfile
);
547 parse_class_declaration(NULL
, cfile
, group
, CLASS_TYPE_CLASS
);
551 skip_token(&val
, (unsigned *)0, cfile
);
552 if (type
== CLASS_DECL
) {
554 "class declarations not allowed here.");
555 skip_to_semi (cfile
);
558 parse_class_declaration(NULL
, cfile
, group
,
559 CLASS_TYPE_SUBCLASS
);
563 skip_token(&val
, (unsigned *)0, cfile
);
564 memset (&hardware
, 0, sizeof hardware
);
565 if (host_decl
&& memcmp(&hardware
, &(host_decl
->interface
),
566 sizeof(hardware
)) != 0) {
567 parse_warn(cfile
, "Host %s hardware address already "
568 "configured.", host_decl
->name
);
572 parse_hardware_param (cfile
, &hardware
);
574 host_decl
-> interface
= hardware
;
576 parse_warn (cfile
, "hardware address parameter %s",
577 "not allowed here.");
582 skip_token(&val
, NULL
, cfile
);
584 if (parse_fixed_addr_param(&cache
, cfile
, token
)) {
586 if (host_decl
->fixed_addr
) {
587 option_cache_dereference(&cache
, MDL
);
589 "Only one fixed address "
590 "declaration per host.");
592 host_decl
->fixed_addr
= cache
;
596 "fixed-address parameter not "
598 option_cache_dereference(&cache
, MDL
);
604 skip_token(&val
, (unsigned *)0, cfile
);
605 if (type
== POOL_DECL
) {
606 parse_warn (cfile
, "pool declared within pool.");
608 } else if (type
!= SUBNET_DECL
&& type
!= SHARED_NET_DECL
) {
609 parse_warn (cfile
, "pool declared outside of network");
612 parse_pool_statement (cfile
, group
, type
);
617 skip_token(&val
, (unsigned *)0, cfile
);
618 if (type
!= SUBNET_DECL
|| !group
-> subnet
) {
620 "range declaration not allowed here.");
621 skip_to_semi (cfile
);
624 parse_address_range (cfile
, group
, type
, (struct pool
*)0,
630 skip_token(NULL
, NULL
, cfile
);
631 if ((type
!= SUBNET_DECL
) || (group
->subnet
== NULL
)) {
633 "range6 declaration not allowed here.");
637 parse_address_range6(cfile
, group
);
641 skip_token(NULL
, NULL
, cfile
);
642 if ((type
!= SUBNET_DECL
) || (group
->subnet
== NULL
)) {
644 "prefix6 declaration not allowed here.");
648 parse_prefix6(cfile
, group
);
652 skip_token(&val
, NULL
, cfile
);
655 "fixed-prefix6 declaration not "
660 parse_fixed_prefix6(cfile
, host_decl
);
666 skip_token(&val
, (unsigned *)0, cfile
);
667 token
= next_token (&val
, (unsigned *)0, cfile
);
670 group
-> authoritative
= 0;
673 parse_warn (cfile
, "expecting assertion");
674 skip_to_semi (cfile
);
679 skip_token(&val
, (unsigned *)0, cfile
);
680 group
-> authoritative
= 1;
682 if (type
== HOST_DECL
)
683 parse_warn (cfile
, "authority makes no sense here.");
687 /* "server-identifier" is a special hack, equivalent to
688 "option dhcp-server-identifier". */
689 case SERVER_IDENTIFIER
:
690 code
= DHO_DHCP_SERVER_IDENTIFIER
;
691 if (!option_code_hash_lookup(&option
, dhcp_universe
.code_hash
,
693 log_fatal("Server identifier not in hash (%s:%d).",
695 skip_token(&val
, (unsigned *)0, cfile
);
699 skip_token(&val
, (unsigned *)0, cfile
);
700 token
= peek_token (&val
, (unsigned *)0, cfile
);
701 if (token
== SPACE
) {
702 if (type
!= ROOT_GROUP
) {
704 "option space definitions %s",
705 "may not be scoped.");
706 skip_to_semi (cfile
);
709 parse_option_space_decl (cfile
);
714 status
= parse_option_name(cfile
, 1, &known
, &option
);
715 if (status
== ISC_R_SUCCESS
) {
716 token
= peek_token (&val
, (unsigned *)0, cfile
);
718 if (type
!= ROOT_GROUP
) {
720 "option definitions%s",
721 " may not be scoped.");
722 skip_to_semi (cfile
);
723 option_dereference(&option
, MDL
);
726 skip_token(&val
, (unsigned *)0, cfile
);
729 * If the option was known, remove it from the
730 * code and name hashes before redefining it.
733 option_name_hash_delete(
734 option
->universe
->name_hash
,
735 option
->name
, 0, MDL
);
736 option_code_hash_delete(
737 option
->universe
->code_hash
,
738 &option
->code
, 0, MDL
);
741 parse_option_code_definition(cfile
, option
);
742 option_dereference(&option
, MDL
);
746 /* If this wasn't an option code definition, don't
747 allow an unknown option. */
749 parse_warn (cfile
, "unknown option %s.%s",
750 option
-> universe
-> name
,
752 skip_to_semi (cfile
);
753 option_dereference(&option
, MDL
);
758 et
= (struct executable_statement
*)0;
759 if (!parse_option_statement
760 (&et
, cfile
, 1, option
,
761 supersede_option_statement
))
763 option_dereference(&option
, MDL
);
764 goto insert_statement
;
771 if (type
!= ROOT_GROUP
&& type
!= SHARED_NET_DECL
) {
772 parse_warn (cfile
, "failover peers may only be %s",
773 "defined in shared-network");
774 log_error ("declarations and the outer scope.");
775 skip_to_semi (cfile
);
778 token
= next_token (&val
, (unsigned *)0, cfile
);
779 #if defined (FAILOVER_PROTOCOL)
780 parse_failover_peer (cfile
, group
, type
);
782 parse_warn (cfile
, "No failover support.");
783 skip_to_semi (cfile
);
789 parse_server_duid_conf(cfile
);
794 et
= (struct executable_statement
*)0;
796 if (!parse_executable_statement (&et
, cfile
, &lose
,
801 "expecting a declaration");
804 "expecting a parameter %s",
806 skip_to_semi (cfile
);
813 if (group
-> statements
) {
816 /* If this set of statements is only referenced
817 by this group, just add the current statement
818 to the end of the chain. */
819 for (ep
= group
-> statements
; ep
-> next
;
821 if (ep
-> refcnt
> 1) /* XXX */
824 executable_statement_reference (&ep
-> next
,
826 executable_statement_dereference (&et
, MDL
);
830 /* Otherwise, make a parent chain, and put the
831 current group statements first and the new
832 statement in the next pointer. */
833 ep
= (struct executable_statement
*)0;
834 if (!executable_statement_allocate (&ep
, MDL
))
835 log_fatal ("No memory for statements.");
836 ep
-> op
= statements_statement
;
837 executable_statement_reference (&ep
-> data
.statements
,
840 executable_statement_reference (&ep
-> next
, et
, MDL
);
841 executable_statement_dereference (&group
-> statements
,
843 executable_statement_reference (&group
-> statements
,
845 executable_statement_dereference (&ep
, MDL
);
847 executable_statement_reference (&group
-> statements
,
850 executable_statement_dereference (&et
, MDL
);
857 #if defined (FAILOVER_PROTOCOL)
858 void parse_failover_peer (cfile
, group
, type
)
863 enum dhcp_token token
;
865 dhcp_failover_state_t
*peer
;
870 unsigned hba_len
= sizeof hba
;
872 struct expression
*expr
;
874 dhcp_failover_config_t
*cp
;
876 token
= next_token (&val
, (unsigned *)0, cfile
);
878 parse_warn (cfile
, "expecting \"peer\"");
879 skip_to_semi (cfile
);
883 token
= next_token (&val
, (unsigned *)0, cfile
);
884 if (is_identifier (token
) || token
== STRING
) {
885 name
= dmalloc (strlen (val
) + 1, MDL
);
887 log_fatal ("no memory for peer name %s", name
);
890 parse_warn (cfile
, "expecting failover peer name.");
891 skip_to_semi (cfile
);
895 /* See if there's a peer declaration by this name. */
896 peer
= (dhcp_failover_state_t
*)0;
897 find_failover_peer (&peer
, name
, MDL
);
899 token
= next_token (&val
, (unsigned *)0, cfile
);
902 if (type
!= SHARED_NET_DECL
)
903 parse_warn (cfile
, "failover peer reference not %s",
904 "in shared-network declaration");
907 parse_warn (cfile
, "reference to unknown%s%s",
908 " failover peer ", name
);
911 dhcp_failover_state_reference
912 (&group
-> shared_network
-> failover_peer
,
915 dhcp_failover_state_dereference (&peer
, MDL
);
917 } else if (token
== STATE
) {
919 parse_warn (cfile
, "state declaration for unknown%s%s",
920 " failover peer ", name
);
923 parse_failover_state_declaration (cfile
, peer
);
924 dhcp_failover_state_dereference (&peer
, MDL
);
926 } else if (token
!= LBRACE
) {
927 parse_warn (cfile
, "expecting left brace");
928 skip_to_semi (cfile
);
931 /* Make sure this isn't a redeclaration. */
933 parse_warn (cfile
, "redeclaration of failover peer %s", name
);
934 skip_to_rbrace (cfile
, 1);
935 dhcp_failover_state_dereference (&peer
, MDL
);
939 status
= dhcp_failover_state_allocate (&peer
, MDL
);
940 if (status
!= ISC_R_SUCCESS
)
941 log_fatal ("Can't allocate failover peer %s: %s",
942 name
, isc_result_totext (status
));
950 token
= next_token (&val
, (unsigned *)0, cfile
);
956 peer
-> i_am
= primary
;
960 peer
-> i_am
= secondary
;
963 "secondary may not define %s",
964 "load balance settings.");
968 cp
= &peer
-> partner
;
972 expr
= (struct expression
*)0;
973 if (!parse_ip_addr_or_hostname (&expr
, cfile
, 0)) {
974 skip_to_rbrace (cfile
, 1);
975 dhcp_failover_state_dereference (&peer
, MDL
);
978 option_cache (&cp
-> address
,
979 (struct data_string
*)0, expr
,
980 (struct option
*)0, MDL
);
981 expression_dereference (&expr
, MDL
);
985 token
= next_token (&val
, (unsigned *)0, cfile
);
986 if (token
!= NUMBER
) {
987 parse_warn (cfile
, "expecting number");
988 skip_to_rbrace (cfile
, 1);
990 cp
-> port
= atoi (val
);
993 case MAX_LEASE_MISBALANCE
:
994 tp
= &peer
->max_lease_misbalance
;
997 case MAX_LEASE_OWNERSHIP
:
998 tp
= &peer
->max_lease_ownership
;
1002 tp
= &peer
->max_balance
;
1006 tp
= &peer
->min_balance
;
1009 case AUTO_PARTNER_DOWN
:
1010 tp
= &peer
->auto_partner_down
;
1013 case MAX_RESPONSE_DELAY
:
1014 tp
= &cp
-> max_response_delay
;
1016 token
= next_token (&val
, (unsigned *)0, cfile
);
1017 if (token
!= NUMBER
) {
1018 parse_warn (cfile
, "expecting number.");
1019 skip_to_rbrace (cfile
, 1);
1020 dhcp_failover_state_dereference (&peer
, MDL
);
1026 case MAX_UNACKED_UPDATES
:
1027 tp
= &cp
-> max_flying_updates
;
1036 if (peer
-> i_am
== secondary
)
1038 "secondary may not define %s",
1039 "load balance settings.");
1040 if (!parse_numeric_aggregate (cfile
, hba
, &hba_len
,
1042 skip_to_rbrace (cfile
, 1);
1043 dhcp_failover_state_dereference (&peer
, MDL
);
1046 if (hba_len
!= 32) {
1048 "HBA must be exactly 32 bytes.");
1052 peer
-> hba
= dmalloc (32, MDL
);
1054 dfree (peer
-> name
, MDL
);
1057 memcpy (peer
-> hba
, hba
, 32);
1061 token
= next_token (&val
, (unsigned *)0, cfile
);
1062 if (peer
-> i_am
== secondary
)
1064 "secondary may not define %s",
1065 "load balance settings.");
1066 if (token
!= NUMBER
) {
1067 parse_warn (cfile
, "expecting number");
1068 skip_to_rbrace (cfile
, 1);
1069 dhcp_failover_state_dereference (&peer
, MDL
);
1074 parse_warn (cfile
, "split must be < 256");
1076 memset (hba
, 0, sizeof hba
);
1077 for (i
= 0; i
< split
; i
++) {
1079 hba
[i
/ 8] |= (1 << (i
& 7));
1086 token
= next_token (&val
, (unsigned *)0, cfile
);
1087 if (token
!= BALANCE
) {
1088 parse_warn (cfile
, "expecting 'balance'");
1090 skip_to_rbrace (cfile
, 1);
1093 token
= next_token (&val
, (unsigned *)0, cfile
);
1094 if (token
!= TOKEN_MAX
) {
1095 parse_warn (cfile
, "expecting 'max'");
1098 token
= next_token (&val
, (unsigned *)0, cfile
);
1099 if (token
!= SECONDS
) {
1100 parse_warn (cfile
, "expecting 'secs'");
1103 token
= next_token (&val
, (unsigned *)0, cfile
);
1104 if (token
!= NUMBER
) {
1105 parse_warn (cfile
, "expecting number");
1108 peer
-> load_balance_max_secs
= atoi (val
);
1113 "invalid statement in peer declaration");
1114 skip_to_rbrace (cfile
, 1);
1115 dhcp_failover_state_dereference (&peer
, MDL
);
1118 if (token
!= RBRACE
&& !parse_semi (cfile
)) {
1119 skip_to_rbrace (cfile
, 1);
1120 dhcp_failover_state_dereference (&peer
, MDL
);
1123 } while (token
!= RBRACE
);
1125 /* me.address can be null; the failover link initiate code tries to
1126 * derive a reasonable address to use.
1128 if (!peer
-> partner
.address
)
1129 parse_warn (cfile
, "peer address may not be omitted");
1132 peer
->me
.port
= DEFAULT_FAILOVER_PORT
;
1133 if (!peer
->partner
.port
)
1134 peer
->partner
.port
= DEFAULT_FAILOVER_PORT
;
1136 if (peer
-> i_am
== primary
) {
1139 "primary failover server must have hba or split.");
1140 } else if (!peer
-> mclt
) {
1142 "primary failover server must have mclt.");
1146 if (!peer
->max_lease_misbalance
)
1147 peer
->max_lease_misbalance
= DEFAULT_MAX_LEASE_MISBALANCE
;
1148 if (!peer
->max_lease_ownership
)
1149 peer
->max_lease_ownership
= DEFAULT_MAX_LEASE_OWNERSHIP
;
1150 if (!peer
->max_balance
)
1151 peer
->max_balance
= DEFAULT_MAX_BALANCE_TIME
;
1152 if (!peer
->min_balance
)
1153 peer
->min_balance
= DEFAULT_MIN_BALANCE_TIME
;
1154 if (!peer
->me
.max_flying_updates
)
1155 peer
->me
.max_flying_updates
= DEFAULT_MAX_FLYING_UPDATES
;
1156 if (!peer
->me
.max_response_delay
)
1157 peer
->me
.max_response_delay
= DEFAULT_MAX_RESPONSE_DELAY
;
1159 if (type
== SHARED_NET_DECL
)
1160 group
->shared_network
->failover_peer
= peer
;
1162 /* Set the initial state. */
1163 if (peer
-> i_am
== primary
) {
1164 peer
-> me
.state
= recover
;
1165 peer
-> me
.stos
= cur_time
;
1166 peer
-> partner
.state
= unknown_state
;
1167 peer
-> partner
.stos
= cur_time
;
1169 peer
-> me
.state
= recover
;
1170 peer
-> me
.stos
= cur_time
;
1171 peer
-> partner
.state
= unknown_state
;
1172 peer
-> partner
.stos
= cur_time
;
1175 status
= enter_failover_peer (peer
);
1176 if (status
!= ISC_R_SUCCESS
)
1177 parse_warn (cfile
, "failover peer %s: %s",
1178 peer
-> name
, isc_result_totext (status
));
1179 dhcp_failover_state_dereference (&peer
, MDL
);
1182 void parse_failover_state_declaration (struct parse
*cfile
,
1183 dhcp_failover_state_t
*peer
)
1185 enum dhcp_token token
;
1188 dhcp_failover_state_t
*state
;
1189 dhcp_failover_config_t
*cp
;
1192 token
= next_token (&val
, (unsigned *)0, cfile
);
1193 if (token
!= PEER
) {
1194 parse_warn (cfile
, "expecting \"peer\"");
1195 skip_to_semi (cfile
);
1199 token
= next_token (&val
, (unsigned *)0, cfile
);
1200 if (is_identifier (token
) || token
== STRING
) {
1201 name
= dmalloc (strlen (val
) + 1, MDL
);
1203 log_fatal ("failover peer name %s: no memory",
1207 parse_warn (cfile
, "expecting failover peer name.");
1208 skip_to_semi (cfile
);
1212 /* See if there's a peer declaration by this name. */
1213 state
= (dhcp_failover_state_t
*)0;
1214 find_failover_peer (&state
, name
, MDL
);
1216 parse_warn (cfile
, "unknown failover peer: %s", name
);
1217 skip_to_semi (cfile
);
1221 token
= next_token (&val
, (unsigned *)0, cfile
);
1222 if (token
!= STATE
) {
1223 parse_warn (cfile
, "expecting 'state'");
1225 skip_to_semi (cfile
);
1229 state
= (dhcp_failover_state_t
*)0;
1230 dhcp_failover_state_reference (&state
, peer
, MDL
);
1232 token
= next_token (&val
, (unsigned *)0, cfile
);
1233 if (token
!= LBRACE
) {
1234 parse_warn (cfile
, "expecting left brace");
1236 skip_to_semi (cfile
);
1237 dhcp_failover_state_dereference (&state
, MDL
);
1241 token
= next_token (&val
, (unsigned *)0, cfile
);
1248 token
= next_token (&val
, (unsigned *)0, cfile
);
1249 if (token
!= STATE
) {
1250 parse_warn (cfile
, "expecting 'state'");
1253 parse_failover_state (cfile
,
1254 &cp
-> state
, &cp
-> stos
);
1258 cp
= &state
-> partner
;
1262 if (state
-> i_am
== primary
) {
1264 "mclt not valid for primary");
1267 token
= next_token (&val
, (unsigned *)0, cfile
);
1268 if (token
!= NUMBER
) {
1269 parse_warn (cfile
, "expecting a number.");
1272 state
-> mclt
= atoi (val
);
1277 parse_warn (cfile
, "expecting state setting.");
1279 skip_to_rbrace (cfile
, 1);
1280 dhcp_failover_state_dereference (&state
, MDL
);
1283 } while (token
!= RBRACE
);
1284 dhcp_failover_state_dereference (&state
, MDL
);
1287 void parse_failover_state (cfile
, state
, stos
)
1288 struct parse
*cfile
;
1289 enum failover_state
*state
;
1292 enum dhcp_token token
;
1294 enum failover_state state_in
;
1297 token
= next_token (&val
, (unsigned *)0, cfile
);
1300 state_in
= unknown_state
;
1304 state_in
= partner_down
;
1311 case COMMUNICATIONS_INTERRUPTED
:
1312 state_in
= communications_interrupted
;
1316 state_in
= conflict_done
;
1319 case RESOLUTION_INTERRUPTED
:
1320 state_in
= resolution_interrupted
;
1323 case POTENTIAL_CONFLICT
:
1324 state_in
= potential_conflict
;
1332 state_in
= recover_wait
;
1336 state_in
= recover_done
;
1340 state_in
= shut_down
;
1352 parse_warn (cfile
, "unknown failover state");
1353 skip_to_semi (cfile
);
1357 token
= next_token (&val
, (unsigned *)0, cfile
);
1358 if (token
== SEMI
) {
1362 parse_warn (cfile
, "expecting \"at\"");
1363 skip_to_semi (cfile
);
1367 stos_in
= parse_date (cfile
);
1372 /* Now that we've apparently gotten a clean parse, we
1373 can trust that this is a state that was fully committed to
1374 disk, so we can install it. */
1378 #endif /* defined (FAILOVER_PROTOCOL) */
1380 /* Permit_list_match returns 1 if every element of the permit list in lhs
1381 also appears in rhs. Note that this doesn't by itself mean that the
1382 two lists are equal - to check for equality, permit_list_match has to
1383 return 1 with (list1, list2) and with (list2, list1). */
1385 int permit_list_match (struct permit
*lhs
, struct permit
*rhs
)
1387 struct permit
*plp
, *prp
;
1394 for (plp
= lhs
; plp
; plp
= plp
-> next
) {
1396 for (prp
= rhs
; prp
; prp
= prp
-> next
) {
1397 if (prp
-> type
== plp
-> type
&&
1398 (prp
-> type
!= permit_class
||
1399 prp
-> class == plp
-> class)) {
1410 void parse_pool_statement (cfile
, group
, type
)
1411 struct parse
*cfile
;
1412 struct group
*group
;
1415 enum dhcp_token token
;
1418 struct pool
*pool
, **p
, *pp
;
1419 struct permit
*permit
;
1420 struct permit
**permit_head
;
1421 int declaration
= 0;
1422 isc_result_t status
;
1423 struct lease
*lpchain
= (struct lease
*)0, *lp
;
1427 pool
= (struct pool
*)0;
1428 status
= pool_allocate (&pool
, MDL
);
1429 if (status
!= ISC_R_SUCCESS
)
1430 log_fatal ("no memory for pool: %s",
1431 isc_result_totext (status
));
1433 if (type
== SUBNET_DECL
)
1434 shared_network_reference (&pool
-> shared_network
,
1435 group
-> subnet
-> shared_network
,
1437 else if (type
== SHARED_NET_DECL
)
1438 shared_network_reference (&pool
-> shared_network
,
1439 group
-> shared_network
, MDL
);
1441 parse_warn(cfile
, "Dynamic pools are only valid inside "
1442 "subnet or shared-network statements.");
1443 skip_to_semi(cfile
);
1447 if (pool
->shared_network
== NULL
||
1448 !clone_group(&pool
->group
, pool
->shared_network
->group
, MDL
))
1449 log_fatal("can't clone pool group.");
1451 #if defined (FAILOVER_PROTOCOL)
1452 /* Inherit the failover peer from the shared network. */
1453 if (pool
-> shared_network
-> failover_peer
)
1454 dhcp_failover_state_reference
1455 (&pool
-> failover_peer
,
1456 pool
-> shared_network
-> failover_peer
, MDL
);
1459 if (!parse_lbrace (cfile
)) {
1460 pool_dereference (&pool
, MDL
);
1465 token
= peek_token (&val
, (unsigned *)0, cfile
);
1468 skip_token(&val
, (unsigned *)0, cfile
);
1469 token
= next_token (&val
, (unsigned *)0, cfile
);
1470 if (token
!= FAILOVER
||
1471 (token
= next_token (&val
, (unsigned *)0,
1474 "expecting \"failover peer\".");
1475 skip_to_semi (cfile
);
1478 #if defined (FAILOVER_PROTOCOL)
1479 if (pool
-> failover_peer
)
1480 dhcp_failover_state_dereference
1481 (&pool
-> failover_peer
, MDL
);
1485 #if defined (FAILOVER_PROTOCOL)
1487 skip_token(&val
, (unsigned *)0, cfile
);
1488 token
= next_token (&val
, (unsigned *)0, cfile
);
1489 if (token
!= PEER
) {
1490 parse_warn (cfile
, "expecting 'peer'.");
1491 skip_to_semi (cfile
);
1494 token
= next_token (&val
, (unsigned *)0, cfile
);
1495 if (token
!= STRING
) {
1496 parse_warn (cfile
, "expecting string.");
1497 skip_to_semi (cfile
);
1500 if (pool
-> failover_peer
)
1501 dhcp_failover_state_dereference
1502 (&pool
-> failover_peer
, MDL
);
1503 status
= find_failover_peer (&pool
-> failover_peer
,
1505 if (status
!= ISC_R_SUCCESS
)
1507 "failover peer %s: %s", val
,
1508 isc_result_totext (status
));
1510 pool
-> failover_peer
-> pool_count
++;
1516 skip_token(&val
, (unsigned *)0, cfile
);
1517 parse_address_range (cfile
, group
, type
,
1521 permit_head
= &pool
-> permit_list
;
1522 /* remember the clause which leads to get_permit */
1525 permit
= new_permit (MDL
);
1527 log_fatal ("no memory for permit");
1528 skip_token(&val
, (unsigned *)0, cfile
);
1529 token
= next_token (&val
, (unsigned *)0, cfile
);
1532 permit
-> type
= permit_unknown_clients
;
1534 if (next_token (&val
, (unsigned *)0,
1535 cfile
) != CLIENTS
) {
1537 "expecting \"clients\"");
1538 skip_to_semi (cfile
);
1539 free_permit (permit
, MDL
);
1545 permit
-> type
= permit_known_clients
;
1548 case UNKNOWN_CLIENTS
:
1549 permit
-> type
= permit_unknown_clients
;
1553 permit
-> type
= permit_known_clients
;
1557 permit
-> type
= permit_authenticated_clients
;
1560 case UNAUTHENTICATED
:
1562 permit_unauthenticated_clients
;
1566 permit
-> type
= permit_all_clients
;
1571 permit
-> type
= permit_dynamic_bootp_clients
;
1572 if (next_token (&val
, (unsigned *)0,
1573 cfile
) != TOKEN_BOOTP
) {
1575 "expecting \"bootp\"");
1576 skip_to_semi (cfile
);
1577 free_permit (permit
, MDL
);
1583 if (next_token (&val
, (unsigned *)0,
1585 parse_warn (cfile
, "expecting \"of\"");
1586 skip_to_semi (cfile
);
1587 free_permit (permit
, MDL
);
1590 if (next_token (&val
, (unsigned *)0,
1593 "expecting class name.");
1594 skip_to_semi (cfile
);
1595 free_permit (permit
, MDL
);
1598 permit
-> type
= permit_class
;
1599 permit
-> class = (struct class *)0;
1600 find_class (&permit
-> class, val
, MDL
);
1601 if (!permit
-> class)
1603 "no such class: %s", val
);
1607 if (pool
->valid_from
|| pool
->valid_until
) {
1609 "duplicate \"after\" clause.");
1610 skip_to_semi(cfile
);
1611 free_permit(permit
, MDL
);
1614 t
= parse_date_core(cfile
);
1615 permit
->type
= permit_after
;
1618 pool
->valid_from
= t
;
1620 pool
->valid_until
= t
;
1625 parse_warn (cfile
, "expecting permit type.");
1626 skip_to_semi (cfile
);
1629 while (*permit_head
)
1630 permit_head
= &((*permit_head
) -> next
);
1631 *permit_head
= permit
;
1636 permit_head
= &pool
-> prohibit_list
;
1637 /* remember the clause which leads to get_permit */
1642 skip_token(&val
, (unsigned *)0, cfile
);
1648 * We can get to END_OF_FILE if, for instance,
1649 * the parse_statement() reads all available tokens
1650 * and leaves us at the end.
1652 parse_warn(cfile
, "unexpected end of file");
1656 declaration
= parse_statement (cfile
, pool
-> group
,
1658 (struct host_decl
*)0,
1664 /* See if there's already a pool into which we can merge this one. */
1665 for (pp
= pool
-> shared_network
-> pools
; pp
; pp
= pp
-> next
) {
1666 if (pp
-> group
-> statements
!= pool
-> group
-> statements
)
1668 #if defined (FAILOVER_PROTOCOL)
1669 if (pool
-> failover_peer
!= pp
-> failover_peer
)
1672 if (!permit_list_match (pp
-> permit_list
,
1673 pool
-> permit_list
) ||
1674 !permit_list_match (pool
-> permit_list
,
1675 pp
-> permit_list
) ||
1676 !permit_list_match (pp
-> prohibit_list
,
1677 pool
-> prohibit_list
) ||
1678 !permit_list_match (pool
-> prohibit_list
,
1679 pp
-> prohibit_list
))
1682 /* Okay, we can merge these two pools. All we have to
1683 do is fix up the leases, which all point to their pool. */
1684 for (lp
= lpchain
; lp
; lp
= lp
-> next
) {
1685 pool_dereference (&lp
-> pool
, MDL
);
1686 pool_reference (&lp
-> pool
, pp
, MDL
);
1691 /* If we didn't succeed in merging this pool into another, put
1694 p
= &pool
-> shared_network
-> pools
;
1695 for (; *p
; p
= &((*p
) -> next
))
1697 pool_reference (p
, pool
, MDL
);
1700 /* Don't allow a pool declaration with no addresses, since it is
1701 probably a configuration error. */
1703 parse_warn (cfile
, "Pool declaration with no address range.");
1704 log_error ("Pool declarations must always contain at least");
1705 log_error ("one range statement.");
1709 /* Dereference the lease chain. */
1710 lp
= (struct lease
*)0;
1712 lease_reference (&lp
, lpchain
, MDL
);
1713 lease_dereference (&lpchain
, MDL
);
1715 lease_reference (&lpchain
, lp
-> next
, MDL
);
1716 lease_dereference (&lp
-> next
, MDL
);
1717 lease_dereference (&lp
, MDL
);
1720 pool_dereference (&pool
, MDL
);
1723 /* Expect a left brace; if there isn't one, skip over the rest of the
1724 statement and return zero; otherwise, return 1. */
1726 int parse_lbrace (cfile
)
1727 struct parse
*cfile
;
1729 enum dhcp_token token
;
1732 token
= next_token (&val
, (unsigned *)0, cfile
);
1733 if (token
!= LBRACE
) {
1734 parse_warn (cfile
, "expecting left brace.");
1735 skip_to_semi (cfile
);
1742 /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
1744 void parse_host_declaration (cfile
, group
)
1745 struct parse
*cfile
;
1746 struct group
*group
;
1749 enum dhcp_token token
;
1750 struct host_decl
*host
;
1752 int declaration
= 0;
1755 isc_result_t status
;
1757 struct option
*option
;
1758 struct expression
*expr
= NULL
;
1760 name
= parse_host_name (cfile
);
1762 parse_warn (cfile
, "expecting a name for host declaration.");
1763 skip_to_semi (cfile
);
1767 host
= (struct host_decl
*)0;
1768 status
= host_allocate (&host
, MDL
);
1769 if (status
!= ISC_R_SUCCESS
)
1770 log_fatal ("can't allocate host decl struct %s: %s",
1771 name
, isc_result_totext (status
));
1772 host
-> name
= name
;
1773 if (!clone_group (&host
-> group
, group
, MDL
)) {
1774 log_fatal ("can't clone group for host %s", name
);
1776 host_dereference (&host
, MDL
);
1780 if (!parse_lbrace (cfile
))
1784 token
= peek_token (&val
, (unsigned *)0, cfile
);
1785 if (token
== RBRACE
) {
1786 skip_token(&val
, (unsigned *)0, cfile
);
1789 if (token
== END_OF_FILE
) {
1790 skip_token(&val
, (unsigned *)0, cfile
);
1791 parse_warn (cfile
, "unexpected end of file");
1794 /* If the host declaration was created by the server,
1795 remember to save it. */
1796 if (token
== DYNAMIC
) {
1798 skip_token(&val
, (unsigned *)0, cfile
);
1799 if (!parse_semi (cfile
))
1803 /* If the host declaration was created by the server,
1804 remember to save it. */
1805 if (token
== TOKEN_DELETED
) {
1807 skip_token(&val
, (unsigned *)0, cfile
);
1808 if (!parse_semi (cfile
))
1813 if (token
== GROUP
) {
1814 struct group_object
*go
;
1815 skip_token(&val
, (unsigned *)0, cfile
);
1816 token
= next_token (&val
, (unsigned *)0, cfile
);
1817 if (token
!= STRING
&& !is_identifier (token
)) {
1819 "expecting string or identifier.");
1820 skip_to_rbrace (cfile
, 1);
1823 go
= (struct group_object
*)0;
1824 if (!group_hash_lookup (&go
, group_name_hash
,
1825 val
, strlen (val
), MDL
)) {
1826 parse_warn (cfile
, "unknown group %s in host %s",
1829 if (host
-> named_group
)
1830 group_object_dereference
1831 (&host
-> named_group
, MDL
);
1832 group_object_reference (&host
-> named_group
,
1834 group_object_dereference (&go
, MDL
);
1836 if (!parse_semi (cfile
))
1843 unsigned char *t
= 0;
1846 skip_token(&val
, (unsigned *)0, cfile
);
1847 data_string_forget (&host
-> client_identifier
, MDL
);
1849 if (host
->client_identifier
.len
!= 0) {
1850 parse_warn(cfile
, "Host %s already has a "
1851 "client identifier.",
1856 /* See if it's a string or a cshl. */
1857 token
= peek_token (&val
, (unsigned *)0, cfile
);
1858 if (token
== STRING
) {
1859 skip_token(&val
, &len
, cfile
);
1861 host
-> client_identifier
.terminated
= 1;
1864 t
= parse_numeric_aggregate
1866 (unsigned char *)0, &len
, ':', 16, 8);
1869 "expecting hex list.");
1870 skip_to_semi (cfile
);
1872 s
= (const char *)t
;
1874 if (!buffer_allocate
1875 (&host
-> client_identifier
.buffer
,
1876 len
+ host
-> client_identifier
.terminated
, MDL
))
1877 log_fatal ("no memory for uid for host %s.",
1879 host
-> client_identifier
.data
=
1880 host
-> client_identifier
.buffer
-> data
;
1881 host
-> client_identifier
.len
= len
;
1882 memcpy (host
-> client_identifier
.buffer
-> data
, s
,
1883 len
+ host
-> client_identifier
.terminated
);
1887 if (!parse_semi (cfile
))
1892 if (token
== HOST_IDENTIFIER
) {
1893 if (host
->host_id_option
!= NULL
) {
1895 "only one host-identifier allowed "
1897 skip_to_rbrace(cfile
, 1);
1900 skip_token(&val
, NULL
, cfile
);
1901 token
= next_token(&val
, NULL
, cfile
);
1902 if (token
!= OPTION
) {
1904 "host-identifier must be an option");
1905 skip_to_rbrace(cfile
, 1);
1910 status
= parse_option_name(cfile
, 1, &known
, &option
);
1911 if ((status
!= ISC_R_SUCCESS
) || (option
== NULL
)) {
1915 parse_warn(cfile
, "unknown option %s.%s",
1916 option
->universe
->name
,
1918 skip_to_rbrace(cfile
, 1);
1922 if (! parse_option_data(&expr
, cfile
, 1, option
)) {
1923 skip_to_rbrace(cfile
, 1);
1924 option_dereference(&option
, MDL
);
1928 if (!parse_semi(cfile
)) {
1929 skip_to_rbrace(cfile
, 1);
1930 expression_dereference(&expr
, MDL
);
1931 option_dereference(&option
, MDL
);
1935 option_reference(&host
->host_id_option
, option
, MDL
);
1936 option_dereference(&option
, MDL
);
1937 data_string_copy(&host
->host_id
,
1938 &expr
->data
.const_data
, MDL
);
1939 expression_dereference(&expr
, MDL
);
1943 declaration
= parse_statement(cfile
, host
->group
, HOST_DECL
,
1948 struct host_decl
*hp
= (struct host_decl
*)0;
1949 if (host_hash_lookup (&hp
, host_name_hash
,
1950 (unsigned char *)host
-> name
,
1951 strlen (host
-> name
), MDL
)) {
1952 delete_host (hp
, 0);
1953 host_dereference (&hp
, MDL
);
1956 if (host
-> named_group
&& host
-> named_group
-> group
) {
1957 if (host
-> group
-> statements
||
1958 (host
-> group
-> authoritative
!=
1959 host
-> named_group
-> group
-> authoritative
)) {
1960 if (host
-> group
-> next
)
1961 group_dereference (&host
-> group
-> next
,
1963 group_reference (&host
-> group
-> next
,
1964 host
-> named_group
-> group
,
1967 group_dereference (&host
-> group
, MDL
);
1968 group_reference (&host
-> group
,
1969 host
-> named_group
-> group
,
1975 host
-> flags
|= HOST_DECL_DYNAMIC
;
1977 host
-> flags
|= HOST_DECL_STATIC
;
1979 status
= enter_host (host
, dynamicp
, 0);
1980 if (status
!= ISC_R_SUCCESS
)
1981 parse_warn (cfile
, "host %s: %s", host
-> name
,
1982 isc_result_totext (status
));
1984 host_dereference (&host
, MDL
);
1987 /* class-declaration :== STRING LBRACE parameters declarations RBRACE
1990 int parse_class_declaration (cp
, cfile
, group
, type
)
1992 struct parse
*cfile
;
1993 struct group
*group
;
1997 enum dhcp_token token
;
1998 struct class *class = (struct class *)0, *pc
= (struct class *)0;
1999 int declaration
= 0;
2001 struct data_string data
;
2004 struct executable_statement
*stmt
= (struct executable_statement
*)0;
2006 isc_result_t status
= ISC_R_FAILURE
;
2007 int matchedonce
= 0;
2008 int submatchedonce
= 0;
2011 if (dhcpv6_class_once
&& local_family
== AF_INET6
) {
2012 dhcpv6_class_once
= 0;
2013 log_error("WARNING: class declarations are not supported "
2017 token
= next_token (&val
, (unsigned *)0, cfile
);
2018 if (token
!= STRING
) {
2019 parse_warn (cfile
, "Expecting class name");
2020 skip_to_semi (cfile
);
2024 /* See if there's already a class with the specified name. */
2025 find_class (&pc
, val
, MDL
);
2027 /* If it is a class, we're updating it. If it's any of the other
2028 * types (subclass, vendor or user class), the named class is a
2029 * reference to the parent class so its mandatory.
2031 if (pc
&& (type
== CLASS_TYPE_CLASS
)) {
2032 class_reference(&class, pc
, MDL
);
2034 class_dereference(&pc
, MDL
);
2035 } else if (!pc
&& (type
!= CLASS_TYPE_CLASS
)) {
2036 parse_warn(cfile
, "no class named %s", val
);
2037 skip_to_semi(cfile
);
2041 /* The old vendor-class and user-class declarations had an implicit
2042 match. We don't do the implicit match anymore. Instead, for
2043 backward compatibility, we have an implicit-vendor-class and an
2044 implicit-user-class. vendor-class and user-class declarations
2045 are turned into subclasses of the implicit classes, and the
2046 submatch expression of the implicit classes extracts the contents of
2047 the vendor class or user class. */
2048 if ((type
== CLASS_TYPE_VENDOR
) || (type
== CLASS_TYPE_USER
)) {
2049 data
.len
= strlen (val
);
2050 data
.buffer
= (struct buffer
*)0;
2051 if (!buffer_allocate (&data
.buffer
, data
.len
+ 1, MDL
))
2052 log_fatal ("no memory for class name.");
2053 data
.data
= &data
.buffer
-> data
[0];
2054 data
.terminated
= 1;
2056 tname
= type
? "implicit-vendor-class" : "implicit-user-class";
2057 } else if (type
== CLASS_TYPE_CLASS
) {
2060 tname
= (const char *)0;
2064 name
= dmalloc (strlen (tname
) + 1, MDL
);
2066 log_fatal ("No memory for class name %s.", tname
);
2071 /* If this is a straight subclass, parse the hash string. */
2072 if (type
== CLASS_TYPE_SUBCLASS
) {
2073 token
= peek_token (&val
, (unsigned *)0, cfile
);
2074 if (token
== STRING
) {
2075 skip_token(&val
, &data
.len
, cfile
);
2076 data
.buffer
= (struct buffer
*)0;
2077 if (!buffer_allocate (&data
.buffer
,
2078 data
.len
+ 1, MDL
)) {
2080 class_dereference (&pc
, MDL
);
2084 data
.terminated
= 1;
2085 data
.data
= &data
.buffer
-> data
[0];
2086 memcpy ((char *)data
.buffer
-> data
, val
,
2088 } else if (token
== NUMBER_OR_NAME
|| token
== NUMBER
) {
2089 memset (&data
, 0, sizeof data
);
2090 if (!parse_cshl (&data
, cfile
)) {
2092 class_dereference (&pc
, MDL
);
2096 parse_warn (cfile
, "Expecting string or hex list.");
2098 class_dereference (&pc
, MDL
);
2103 /* See if there's already a class in the hash table matching the
2105 if (type
!= CLASS_TYPE_CLASS
)
2106 class_hash_lookup (&class, pc
-> hash
,
2107 (const char *)data
.data
, data
.len
, MDL
);
2109 /* If we didn't find an existing class, allocate a new one. */
2111 /* Allocate the class structure... */
2112 status
= class_allocate (&class, MDL
);
2114 group_reference (&class -> group
, pc
-> group
, MDL
);
2115 class_reference (&class -> superclass
, pc
, MDL
);
2116 class -> lease_limit
= pc
-> lease_limit
;
2117 if (class -> lease_limit
) {
2118 class -> billed_leases
=
2119 dmalloc (class -> lease_limit
*
2120 sizeof (struct lease
*), MDL
);
2121 if (!class -> billed_leases
)
2122 log_fatal ("no memory for billing");
2123 memset (class -> billed_leases
, 0,
2124 (class -> lease_limit
*
2125 sizeof (struct lease
*)));
2127 data_string_copy (&class -> hash_string
, &data
, MDL
);
2129 !class_new_hash (&pc
->hash
, SCLASS_HASH_SIZE
, MDL
))
2130 log_fatal ("No memory for subclass hash.");
2131 class_hash_add (pc
-> hash
,
2132 (const char *)class -> hash_string
.data
,
2133 class -> hash_string
.len
,
2134 (void *)class, MDL
);
2137 group_dereference(&class->group
, MDL
);
2138 if (!clone_group (&class -> group
, group
, MDL
))
2139 log_fatal ("no memory to clone class group.");
2142 /* If this is an implicit vendor or user class, add a
2143 statement that causes the vendor or user class ID to
2144 be sent back in the reply. */
2145 if (type
== CLASS_TYPE_VENDOR
|| type
== CLASS_TYPE_USER
) {
2146 stmt
= (struct executable_statement
*)0;
2147 if (!executable_statement_allocate (&stmt
, MDL
))
2148 log_fatal ("no memory for class statement.");
2149 stmt
-> op
= supersede_option_statement
;
2150 if (option_cache_allocate (&stmt
-> data
.option
,
2152 stmt
-> data
.option
-> data
= data
;
2153 code
= (type
== CLASS_TYPE_VENDOR
)
2154 ? DHO_VENDOR_CLASS_IDENTIFIER
2156 option_code_hash_lookup(
2157 &stmt
->data
.option
->option
,
2158 dhcp_universe
.code_hash
,
2161 class -> statements
= stmt
;
2164 /* Save the name, if there is one. */
2165 if (class->name
!= NULL
)
2166 dfree(class->name
, MDL
);
2170 if (type
!= CLASS_TYPE_CLASS
)
2171 data_string_forget(&data
, MDL
);
2173 /* Spawned classes don't have to have their own settings. */
2174 if (class -> superclass
) {
2175 token
= peek_token (&val
, (unsigned *)0, cfile
);
2176 if (token
== SEMI
) {
2177 skip_token(&val
, (unsigned *)0, cfile
);
2179 status
= class_reference (cp
, class, MDL
);
2180 class_dereference (&class, MDL
);
2182 class_dereference (&pc
, MDL
);
2183 return cp
? (status
== ISC_R_SUCCESS
) : 1;
2185 /* Give the subclass its own group. */
2186 if (!clone_group (&class -> group
, class -> group
, MDL
))
2187 log_fatal ("can't clone class group.");
2191 if (!parse_lbrace (cfile
)) {
2192 class_dereference (&class, MDL
);
2194 class_dereference (&pc
, MDL
);
2199 token
= peek_token (&val
, (unsigned *)0, cfile
);
2200 if (token
== RBRACE
) {
2201 skip_token(&val
, (unsigned *)0, cfile
);
2203 } else if (token
== END_OF_FILE
) {
2204 skip_token(&val
, (unsigned *)0, cfile
);
2205 parse_warn (cfile
, "unexpected end of file");
2207 } else if (token
== DYNAMIC
) {
2208 class->flags
|= CLASS_DECL_DYNAMIC
;
2209 skip_token(&val
, (unsigned *)0, cfile
);
2210 if (!parse_semi (cfile
))
2213 } else if (token
== TOKEN_DELETED
) {
2214 class->flags
|= CLASS_DECL_DELETED
;
2215 skip_token(&val
, (unsigned *)0, cfile
);
2216 if (!parse_semi (cfile
))
2219 } else if (token
== MATCH
) {
2222 "invalid match in subclass.");
2223 skip_to_semi (cfile
);
2226 skip_token(&val
, (unsigned *)0, cfile
);
2227 token
= peek_token (&val
, (unsigned *)0, cfile
);
2230 skip_token(&val
, (unsigned *)0, cfile
);
2232 parse_warn(cfile
, "A class may only have "
2233 "one 'match if' clause.");
2234 skip_to_semi(cfile
);
2239 expression_dereference(&class->expr
, MDL
);
2240 if (!parse_boolean_expression (&class->expr
, cfile
,
2244 "expecting boolean expr.");
2245 skip_to_semi (cfile
);
2248 #if defined (DEBUG_EXPRESSION_PARSE)
2249 print_expression ("class match",
2254 } else if (token
== SPAWN
) {
2255 skip_token(&val
, (unsigned *)0, cfile
);
2258 "invalid spawn in subclass.");
2259 skip_to_semi (cfile
);
2262 class -> spawning
= 1;
2263 token
= next_token (&val
, (unsigned *)0, cfile
);
2264 if (token
!= WITH
) {
2266 "expecting with after spawn");
2267 skip_to_semi (cfile
);
2271 if (submatchedonce
) {
2273 "can't override existing %s.",
2275 skip_to_semi (cfile
);
2279 if (class->submatch
)
2280 expression_dereference(&class->submatch
, MDL
);
2281 if (!parse_data_expression (&class -> submatch
,
2285 "expecting data expr.");
2286 skip_to_semi (cfile
);
2289 #if defined (DEBUG_EXPRESSION_PARSE)
2290 print_expression ("class submatch",
2295 } else if (token
== LEASE
) {
2296 skip_token(&val
, (unsigned *)0, cfile
);
2297 token
= next_token (&val
, (unsigned *)0, cfile
);
2298 if (token
!= LIMIT
) {
2299 parse_warn (cfile
, "expecting \"limit\"");
2301 skip_to_semi (cfile
);
2304 token
= next_token (&val
, (unsigned *)0, cfile
);
2305 if (token
!= NUMBER
) {
2306 parse_warn (cfile
, "expecting a number");
2308 skip_to_semi (cfile
);
2311 class -> lease_limit
= atoi (val
);
2312 if (class->billed_leases
)
2313 dfree(class->billed_leases
, MDL
);
2314 class -> billed_leases
=
2315 dmalloc (class -> lease_limit
*
2316 sizeof (struct lease
*), MDL
);
2317 if (!class -> billed_leases
)
2318 log_fatal ("no memory for billed leases.");
2319 memset (class -> billed_leases
, 0,
2320 (class -> lease_limit
*
2321 sizeof (struct lease
*)));
2322 have_billing_classes
= 1;
2325 declaration
= parse_statement (cfile
, class -> group
,
2327 (struct host_decl
*)0,
2332 if (class->flags
& CLASS_DECL_DELETED
) {
2333 if (type
== CLASS_TYPE_CLASS
) {
2334 struct class *theclass
= NULL
;
2336 status
= find_class(&theclass
, class->name
, MDL
);
2337 if (status
== ISC_R_SUCCESS
) {
2338 delete_class(theclass
, 0);
2339 class_dereference(&theclass
, MDL
);
2342 class_hash_delete(pc
->hash
,
2343 (char *)class->hash_string
.data
,
2344 class->hash_string
.len
, MDL
);
2346 } else if (type
== CLASS_TYPE_CLASS
&& new) {
2347 if (!collections
-> classes
)
2348 class_reference (&collections
-> classes
, class, MDL
);
2351 for (c
= collections
-> classes
;
2352 c
-> nic
; c
= c
-> nic
)
2354 class_reference (&c
-> nic
, class, MDL
);
2358 if (cp
) /* should always be 0??? */
2359 status
= class_reference (cp
, class, MDL
);
2360 class_dereference (&class, MDL
);
2362 class_dereference (&pc
, MDL
);
2363 return cp
? (status
== ISC_R_SUCCESS
) : 1;
2366 /* shared-network-declaration :==
2367 hostname LBRACE declarations parameters RBRACE */
2369 void parse_shared_net_declaration (cfile
, group
)
2370 struct parse
*cfile
;
2371 struct group
*group
;
2374 enum dhcp_token token
;
2375 struct shared_network
*share
;
2377 int declaration
= 0;
2378 isc_result_t status
;
2380 share
= (struct shared_network
*)0;
2381 status
= shared_network_allocate (&share
, MDL
);
2382 if (status
!= ISC_R_SUCCESS
)
2383 log_fatal ("Can't allocate shared subnet: %s",
2384 isc_result_totext (status
));
2385 if (clone_group (&share
-> group
, group
, MDL
) == 0) {
2386 log_fatal ("Can't clone group for shared net");
2388 shared_network_reference (&share
-> group
-> shared_network
,
2391 /* Get the name of the shared network... */
2392 token
= peek_token (&val
, (unsigned *)0, cfile
);
2393 if (token
== STRING
) {
2394 skip_token(&val
, (unsigned *)0, cfile
);
2397 parse_warn (cfile
, "zero-length shared network name");
2398 val
= "<no-name-given>";
2400 name
= dmalloc (strlen (val
) + 1, MDL
);
2402 log_fatal ("no memory for shared network name");
2405 name
= parse_host_name (cfile
);
2408 "expecting a name for shared-network");
2409 skip_to_semi (cfile
);
2410 shared_network_dereference (&share
, MDL
);
2414 share
-> name
= name
;
2416 if (!parse_lbrace (cfile
)) {
2417 shared_network_dereference (&share
, MDL
);
2422 token
= peek_token (&val
, (unsigned *)0, cfile
);
2423 if (token
== RBRACE
) {
2424 skip_token(&val
, (unsigned *)0, cfile
);
2425 if (!share
-> subnets
)
2427 "empty shared-network decl");
2429 enter_shared_network (share
);
2430 shared_network_dereference (&share
, MDL
);
2432 } else if (token
== END_OF_FILE
) {
2433 skip_token(&val
, (unsigned *)0, cfile
);
2434 parse_warn (cfile
, "unexpected end of file");
2436 } else if (token
== INTERFACE
) {
2437 skip_token(&val
, (unsigned *)0, cfile
);
2438 token
= next_token (&val
, (unsigned *)0, cfile
);
2439 new_shared_network_interface (cfile
, share
, val
);
2440 if (!parse_semi (cfile
))
2445 declaration
= parse_statement (cfile
, share
-> group
,
2447 (struct host_decl
*)0,
2450 shared_network_dereference (&share
, MDL
);
2455 common_subnet_parsing(struct parse
*cfile
,
2456 struct shared_network
*share
,
2457 struct subnet
*subnet
) {
2458 enum dhcp_token token
;
2459 struct subnet
*t
, *u
;
2461 int declaration
= 0;
2463 enter_subnet(subnet
);
2465 if (!parse_lbrace(cfile
)) {
2466 subnet_dereference(&subnet
, MDL
);
2471 token
= peek_token(&val
, NULL
, cfile
);
2472 if (token
== RBRACE
) {
2473 skip_token(&val
, NULL
, cfile
);
2475 } else if (token
== END_OF_FILE
) {
2476 skip_token(&val
, NULL
, cfile
);
2477 parse_warn (cfile
, "unexpected end of file");
2479 } else if (token
== INTERFACE
) {
2480 skip_token(&val
, NULL
, cfile
);
2481 token
= next_token(&val
, NULL
, cfile
);
2482 new_shared_network_interface(cfile
, share
, val
);
2483 if (!parse_semi(cfile
))
2487 declaration
= parse_statement(cfile
, subnet
->group
,
2493 /* Add the subnet to the list of subnets in this shared net. */
2494 if (share
->subnets
== NULL
) {
2495 subnet_reference(&share
->subnets
, subnet
, MDL
);
2498 for (t
= share
->subnets
; t
->next_sibling
; t
= t
->next_sibling
) {
2499 if (subnet_inner_than(subnet
, t
, 0)) {
2500 subnet_reference(&subnet
->next_sibling
, t
, MDL
);
2502 subnet_dereference(&u
->next_sibling
,
2504 subnet_reference(&u
->next_sibling
,
2507 subnet_dereference(&share
->subnets
,
2509 subnet_reference(&share
->subnets
,
2512 subnet_dereference(&subnet
, MDL
);
2517 subnet_reference(&t
->next_sibling
, subnet
, MDL
);
2519 subnet_dereference(&subnet
, MDL
);
2523 /* subnet-declaration :==
2524 net NETMASK netmask RBRACE parameters declarations LBRACE */
2526 void parse_subnet_declaration (cfile
, share
)
2527 struct parse
*cfile
;
2528 struct shared_network
*share
;
2531 enum dhcp_token token
;
2532 struct subnet
*subnet
;
2534 unsigned char addr
[4];
2535 unsigned len
= sizeof addr
;
2536 isc_result_t status
;
2538 subnet
= (struct subnet
*)0;
2539 status
= subnet_allocate (&subnet
, MDL
);
2540 if (status
!= ISC_R_SUCCESS
)
2541 log_fatal ("Allocation of new subnet failed: %s",
2542 isc_result_totext (status
));
2543 shared_network_reference (&subnet
-> shared_network
, share
, MDL
);
2546 * If our parent shared network was implicitly created by the software,
2547 * and not explicitly configured by the user, then we actually put all
2548 * configuration scope in the parent (the shared network and subnet
2549 * share the same {}-level scope).
2551 * Otherwise, we clone the parent group and continue as normal.
2553 if (share
->flags
& SHARED_IMPLICIT
) {
2554 group_reference(&subnet
->group
, share
->group
, MDL
);
2556 if (!clone_group(&subnet
->group
, share
->group
, MDL
)) {
2557 log_fatal("Allocation of group for new subnet failed.");
2560 subnet_reference (&subnet
-> group
-> subnet
, subnet
, MDL
);
2562 /* Get the network number... */
2563 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8)) {
2564 subnet_dereference (&subnet
, MDL
);
2567 memcpy (iaddr
.iabuf
, addr
, len
);
2569 subnet
-> net
= iaddr
;
2571 token
= next_token (&val
, (unsigned *)0, cfile
);
2572 if (token
!= NETMASK
) {
2573 parse_warn (cfile
, "Expecting netmask");
2574 skip_to_semi (cfile
);
2578 /* Get the netmask... */
2579 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8)) {
2580 subnet_dereference (&subnet
, MDL
);
2583 memcpy (iaddr
.iabuf
, addr
, len
);
2585 subnet
-> netmask
= iaddr
;
2587 /* Validate the network number/netmask pair. */
2588 if (host_addr (subnet
-> net
, subnet
-> netmask
)) {
2591 maskstr
= strdup (piaddr (subnet
-> netmask
));
2593 "subnet %s netmask %s: bad subnet number/mask combination.",
2594 piaddr (subnet
-> net
), maskstr
);
2596 subnet_dereference (&subnet
, MDL
);
2597 skip_to_semi (cfile
);
2601 common_subnet_parsing(cfile
, share
, subnet
);
2604 /* subnet6-declaration :==
2605 net / bits RBRACE parameters declarations LBRACE */
2608 parse_subnet6_declaration(struct parse
*cfile
, struct shared_network
*share
) {
2609 #if !defined(DHCPv6)
2610 parse_warn(cfile
, "No DHCPv6 support.");
2611 skip_to_semi(cfile
);
2612 #else /* defined(DHCPv6) */
2613 struct subnet
*subnet
;
2614 isc_result_t status
;
2615 enum dhcp_token token
;
2619 const static int mask
[] = { 0x00, 0x80, 0xC0, 0xE0,
2620 0xF0, 0xF8, 0xFC, 0xFE };
2623 if (local_family
!= AF_INET6
) {
2624 parse_warn(cfile
, "subnet6 statement is only supported "
2626 skip_to_semi(cfile
);
2631 status
= subnet_allocate(&subnet
, MDL
);
2632 if (status
!= ISC_R_SUCCESS
) {
2633 log_fatal("Allocation of new subnet failed: %s",
2634 isc_result_totext(status
));
2636 shared_network_reference(&subnet
->shared_network
, share
, MDL
);
2639 * If our parent shared network was implicitly created by the software,
2640 * and not explicitly configured by the user, then we actually put all
2641 * configuration scope in the parent (the shared network and subnet
2642 * share the same {}-level scope).
2644 * Otherwise, we clone the parent group and continue as normal.
2646 if (share
->flags
& SHARED_IMPLICIT
) {
2647 group_reference(&subnet
->group
, share
->group
, MDL
);
2649 if (!clone_group(&subnet
->group
, share
->group
, MDL
)) {
2650 log_fatal("Allocation of group for new subnet failed.");
2653 subnet_reference(&subnet
->group
->subnet
, subnet
, MDL
);
2655 if (!parse_ip6_addr(cfile
, &subnet
->net
)) {
2656 subnet_dereference(&subnet
, MDL
);
2660 token
= next_token(&val
, NULL
, cfile
);
2661 if (token
!= SLASH
) {
2662 parse_warn(cfile
, "Expecting a '/'.");
2663 skip_to_semi(cfile
);
2667 token
= next_token(&val
, NULL
, cfile
);
2668 if (token
!= NUMBER
) {
2669 parse_warn(cfile
, "Expecting a number.");
2670 skip_to_semi(cfile
);
2674 subnet
->prefix_len
= strtol(val
, &endp
, 10);
2675 if ((subnet
->prefix_len
< 0) ||
2676 (subnet
->prefix_len
> 128) ||
2678 parse_warn(cfile
, "Expecting a number between 0 and 128.");
2679 skip_to_semi(cfile
);
2683 if (!is_cidr_mask_valid(&subnet
->net
, subnet
->prefix_len
)) {
2684 parse_warn(cfile
, "New subnet mask too short.");
2685 skip_to_semi(cfile
);
2692 subnet
->netmask
.len
= 16;
2693 ofs
= subnet
->prefix_len
/ 8;
2694 if (ofs
< subnet
->netmask
.len
) {
2695 subnet
->netmask
.iabuf
[ofs
] = mask
[subnet
->prefix_len
% 8];
2697 while (--ofs
>= 0) {
2698 subnet
->netmask
.iabuf
[ofs
] = 0xFF;
2701 /* Validate the network number/netmask pair. */
2702 iaddr
= subnet_number(subnet
->net
, subnet
->netmask
);
2703 if (memcmp(&iaddr
, &subnet
->net
, 16) != 0) {
2705 "subnet %s/%d: prefix not long enough for address.",
2706 piaddr(subnet
->net
), subnet
->prefix_len
);
2707 subnet_dereference(&subnet
, MDL
);
2708 skip_to_semi(cfile
);
2712 if (!common_subnet_parsing(cfile
, share
, subnet
)) {
2715 #endif /* defined(DHCPv6) */
2718 /* group-declaration :== RBRACE parameters declarations LBRACE */
2720 void parse_group_declaration (cfile
, group
)
2721 struct parse
*cfile
;
2722 struct group
*group
;
2725 enum dhcp_token token
;
2727 int declaration
= 0;
2728 struct group_object
*t
= NULL
;
2729 isc_result_t status
;
2736 if (!clone_group(&g
, group
, MDL
))
2737 log_fatal("no memory for explicit group.");
2739 token
= peek_token(&val
, NULL
, cfile
);
2740 if (is_identifier (token
) || token
== STRING
) {
2741 skip_token(&val
, NULL
, cfile
);
2743 name
= dmalloc(strlen(val
) + 1, MDL
);
2745 log_fatal("no memory for group decl name %s", val
);
2749 if (!parse_lbrace(cfile
)) {
2750 group_dereference(&g
, MDL
);
2755 token
= peek_token(&val
, NULL
, cfile
);
2756 if (token
== RBRACE
) {
2757 skip_token(&val
, NULL
, cfile
);
2759 } else if (token
== END_OF_FILE
) {
2760 skip_token(&val
, NULL
, cfile
);
2761 parse_warn(cfile
, "unexpected end of file");
2763 } else if (token
== TOKEN_DELETED
) {
2764 skip_token(&val
, NULL
, cfile
);
2767 } else if (token
== DYNAMIC
) {
2768 skip_token(&val
, NULL
, cfile
);
2771 } else if (token
== STATIC
) {
2772 skip_token(&val
, NULL
, cfile
);
2776 declaration
= parse_statement(cfile
, g
, GROUP_DECL
,
2782 if (group_name_hash
) {
2784 if (group_hash_lookup(&t
, group_name_hash
,
2786 strlen(name
), MDL
)) {
2792 status
= group_object_allocate(&t
, MDL
);
2793 if (status
!= ISC_R_SUCCESS
)
2794 log_fatal("no memory for group decl %s: %s",
2795 val
, isc_result_totext(status
));
2796 group_reference(&t
->group
, g
, MDL
);
2798 /* no need to include deletedp as it's handled above */
2799 t
->flags
= ((staticp
? GROUP_OBJECT_STATIC
: 0) |
2800 (dynamicp
? GROUP_OBJECT_DYNAMIC
: 0));
2801 supersede_group(t
, 0);
2804 group_object_dereference(&t
, MDL
);
2808 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
2809 ip-addrs-or-hostnames :== ip-addr-or-hostname
2810 | ip-addrs-or-hostnames ip-addr-or-hostname */
2813 parse_fixed_addr_param(struct option_cache
**oc
,
2814 struct parse
*cfile
,
2815 enum dhcp_token type
) {
2818 enum dhcp_token token
;
2819 struct expression
*expr
= NULL
;
2820 struct expression
*tmp
, *new;
2825 if (type
== FIXED_ADDR
) {
2826 parse_ok
= parse_ip_addr_or_hostname(&tmp
, cfile
, 1);
2828 /* INSIST(type == FIXED_ADDR6); */
2829 parse_ok
= parse_ip6_addr_expr(&tmp
, cfile
);
2834 status
= make_concat(&new, expr
, tmp
);
2835 expression_dereference(&expr
, MDL
);
2836 expression_dereference(&tmp
, MDL
);
2846 expression_dereference (&expr
, MDL
);
2850 token
= peek_token(&val
, NULL
, cfile
);
2851 if (token
== COMMA
) {
2852 token
= next_token(&val
, NULL
, cfile
);
2854 } while (token
== COMMA
);
2856 if (!parse_semi(cfile
)) {
2858 expression_dereference (&expr
, MDL
);
2863 status
= option_cache(oc
, NULL
, expr
, NULL
, MDL
);
2864 expression_dereference(&expr
, MDL
);
2868 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
2870 lease_parameters :== <nil>
2872 | lease_parameters lease_parameter
2874 lease_parameter :== STARTS date
2877 | HARDWARE hardware-parameter
2878 | UID hex_numbers SEMI
2879 | HOSTNAME hostname SEMI
2880 | CLIENT_HOSTNAME hostname SEMI
2881 | CLASS identifier SEMI
2882 | DYNAMIC_BOOTP SEMI */
2884 int parse_lease_declaration (struct lease
**lp
, struct parse
*cfile
)
2887 enum dhcp_token token
;
2888 unsigned char addr
[4];
2889 unsigned len
= sizeof addr
;
2893 struct lease
*lease
;
2894 struct executable_statement
*on
;
2897 int noequal
, newbinding
;
2898 struct binding
*binding
;
2899 struct binding_value
*nv
;
2900 isc_result_t status
;
2901 struct option_cache
*oc
;
2903 binding_state_t new_state
;
2904 unsigned buflen
= 0;
2905 struct class *class;
2907 lease
= (struct lease
*)0;
2908 status
= lease_allocate (&lease
, MDL
);
2909 if (status
!= ISC_R_SUCCESS
)
2912 /* Get the address for which the lease has been issued. */
2913 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8)) {
2914 lease_dereference (&lease
, MDL
);
2917 memcpy (lease
-> ip_addr
.iabuf
, addr
, len
);
2918 lease
-> ip_addr
.len
= len
;
2920 if (!parse_lbrace (cfile
)) {
2921 lease_dereference (&lease
, MDL
);
2926 token
= next_token (&val
, (unsigned *)0, cfile
);
2927 if (token
== RBRACE
)
2929 else if (token
== END_OF_FILE
) {
2930 parse_warn (cfile
, "unexpected end of file");
2933 strncpy (tbuf
, val
, sizeof tbuf
);
2934 tbuf
[(sizeof tbuf
) - 1] = 0;
2936 /* Parse any of the times associated with the lease. */
2945 t
= parse_date (cfile
);
2949 lease
-> starts
= t
;
2977 default: /* for gcc, we'll never get here. */
2978 log_fatal ("Impossible error at %s:%d.", MDL
);
2983 /* Colon-separated hexadecimal octets... */
2986 token
= peek_token (&val
, (unsigned *)0, cfile
);
2987 if (token
== STRING
) {
2988 unsigned char *tuid
;
2989 skip_token(&val
, &buflen
, cfile
);
2990 if (buflen
< sizeof lease
-> uid_buf
) {
2991 tuid
= lease
-> uid_buf
;
2993 sizeof lease
-> uid_buf
;
2995 tuid
= ((unsigned char *)
2996 dmalloc (buflen
, MDL
));
2998 log_error ("no space for uid");
2999 lease_dereference (&lease
,
3003 lease
-> uid_max
= buflen
;
3005 lease
-> uid_len
= buflen
;
3006 memcpy (tuid
, val
, lease
-> uid_len
);
3007 lease
-> uid
= tuid
;
3010 lease
-> uid
= (parse_numeric_aggregate
3011 (cfile
, (unsigned char *)0,
3012 &buflen
, ':', 16, 8));
3013 if (!lease
-> uid
) {
3014 lease_dereference (&lease
, MDL
);
3017 lease
-> uid_len
= buflen
;
3018 lease
-> uid_max
= buflen
;
3019 if (lease
-> uid_len
== 0) {
3020 lease
-> uid
= (unsigned char *)0;
3021 parse_warn (cfile
, "zero-length uid");
3028 if (!lease
-> uid
) {
3029 log_fatal ("No memory for lease uid");
3035 token
= next_token (&val
, (unsigned *)0, cfile
);
3036 if (!is_identifier (token
)) {
3038 skip_to_rbrace (cfile
, 1);
3039 lease_dereference (&lease
, MDL
);
3043 /* for now, we aren't using this. */
3048 parse_hardware_param (cfile
,
3049 &lease
-> hardware_addr
);
3052 case TOKEN_RESERVED
:
3054 lease
->flags
|= RESERVED_LEASE
;
3060 lease
-> flags
|= BOOTP_LEASE
;
3064 /* XXX: Reverse compatibility? */
3065 case TOKEN_ABANDONED
:
3067 lease
-> binding_state
= FTS_ABANDONED
;
3068 lease
-> next_binding_state
= FTS_ABANDONED
;
3074 token
= next_token (&val
, (unsigned *)0, cfile
);
3075 if (token
!= BINDING
) {
3076 parse_warn (cfile
, "expecting 'binding'");
3077 skip_to_semi (cfile
);
3080 goto do_binding_state
;
3084 token
= next_token(&val
, NULL
, cfile
);
3085 if (token
!= BINDING
) {
3086 parse_warn(cfile
, "expecting 'binding'");
3087 skip_to_semi(cfile
);
3090 goto do_binding_state
;
3096 token
= next_token (&val
, (unsigned *)0, cfile
);
3097 if (token
!= STATE
) {
3098 parse_warn (cfile
, "expecting 'state'");
3099 skip_to_semi (cfile
);
3102 token
= next_token (&val
, (unsigned *)0, cfile
);
3104 case TOKEN_ABANDONED
:
3105 new_state
= FTS_ABANDONED
;
3108 new_state
= FTS_FREE
;
3111 new_state
= FTS_ACTIVE
;
3114 new_state
= FTS_EXPIRED
;
3116 case TOKEN_RELEASED
:
3117 new_state
= FTS_RELEASED
;
3120 new_state
= FTS_RESET
;
3123 new_state
= FTS_BACKUP
;
3126 /* RESERVED and BOOTP states preserved for
3127 * compatibleness with older versions.
3129 case TOKEN_RESERVED
:
3130 new_state
= FTS_ACTIVE
;
3131 lease
->flags
|= RESERVED_LEASE
;
3134 new_state
= FTS_ACTIVE
;
3135 lease
->flags
|= BOOTP_LEASE
;
3140 "%s: expecting a binding state.",
3142 skip_to_semi (cfile
);
3146 if (seenbit
== 256) {
3147 lease
-> binding_state
= new_state
;
3150 * Apply default/conservative next/rewind
3151 * binding states if they haven't been set
3152 * yet. These defaults will be over-ridden if
3153 * they are set later in parsing.
3155 if (!(seenmask
& 128))
3156 lease
->next_binding_state
= new_state
;
3158 /* The most conservative rewind state. */
3159 if (!(seenmask
& 512))
3160 lease
->rewind_binding_state
= new_state
;
3161 } else if (seenbit
== 128)
3162 lease
-> next_binding_state
= new_state
;
3163 else if (seenbit
== 512)
3164 lease
->rewind_binding_state
= new_state
;
3166 log_fatal("Impossible condition at %s:%d.",
3172 case CLIENT_HOSTNAME
:
3174 token
= peek_token (&val
, (unsigned *)0, cfile
);
3175 if (token
== STRING
) {
3176 if (!parse_string (cfile
,
3177 &lease
-> client_hostname
,
3179 lease_dereference (&lease
, MDL
);
3183 lease
-> client_hostname
=
3184 parse_host_name (cfile
);
3185 if (lease
-> client_hostname
)
3189 "expecting a hostname.");
3190 skip_to_semi (cfile
);
3191 lease_dereference (&lease
, MDL
);
3199 class = (struct class *)0;
3200 token
= next_token (&val
, (unsigned *)0, cfile
);
3201 if (token
== CLASS
) {
3202 token
= next_token (&val
,
3203 (unsigned *)0, cfile
);
3204 if (token
!= STRING
) {
3205 parse_warn (cfile
, "expecting string");
3207 skip_to_semi (cfile
);
3211 if (lease
-> billing_class
)
3212 class_dereference (&lease
-> billing_class
,
3214 find_class (&class, val
, MDL
);
3217 "unknown class %s", val
);
3219 } else if (token
== SUBCLASS
) {
3220 if (lease
-> billing_class
)
3221 class_dereference (&lease
-> billing_class
,
3223 parse_class_declaration(&class, cfile
, NULL
,
3224 CLASS_TYPE_SUBCLASS
);
3226 parse_warn (cfile
, "expecting \"class\"");
3228 skip_to_semi (cfile
);
3231 class_reference (&lease
-> billing_class
,
3233 class_dereference (&class, MDL
);
3238 on
= (struct executable_statement
*)0;
3240 if (!parse_on_statement (&on
, cfile
, &lose
)) {
3241 skip_to_rbrace (cfile
, 1);
3242 lease_dereference (&lease
, MDL
);
3246 if ((on
-> data
.on
.evtypes
& ON_EXPIRY
) &&
3247 on
-> data
.on
.statements
) {
3249 executable_statement_reference
3250 (&lease
-> on_expiry
,
3251 on
-> data
.on
.statements
, MDL
);
3253 if ((on
-> data
.on
.evtypes
& ON_RELEASE
) &&
3254 on
-> data
.on
.statements
) {
3256 executable_statement_reference
3257 (&lease
-> on_release
,
3258 on
-> data
.on
.statements
, MDL
);
3260 executable_statement_dereference (&on
, MDL
);
3267 oc
= (struct option_cache
*)0;
3268 if (parse_option_decl (&oc
, cfile
)) {
3269 if (oc
-> option
-> universe
!=
3272 "agent option expected.");
3273 option_cache_dereference (&oc
, MDL
);
3276 if (!lease
-> agent_options
&&
3277 !(option_chain_head_allocate
3278 (&lease
-> agent_options
, MDL
))) {
3279 log_error ("no memory to stash agent option");
3282 for (p
= &lease
-> agent_options
-> first
;
3283 *p
; p
= &((*p
) -> cdr
))
3286 option_cache_reference (((struct option_cache
**)
3287 &((*p
) -> car
)), oc
, MDL
);
3288 option_cache_dereference (&oc
, MDL
);
3295 token
= next_token (&val
, (unsigned *)0, cfile
);
3296 if (token
!= NAME
&& token
!= NUMBER_OR_NAME
) {
3298 "%s can't be a variable name",
3301 skip_to_semi (cfile
);
3302 lease_dereference (&lease
, MDL
);
3309 binding
= find_binding (lease
-> scope
, val
);
3311 binding
= (struct binding
*)0;
3314 if (!lease
-> scope
)
3315 if (!(binding_scope_allocate
3316 (&lease
-> scope
, MDL
)))
3317 log_fatal ("no memory for scope");
3318 binding
= dmalloc (sizeof *binding
, MDL
);
3320 log_fatal ("No memory for lease %s.",
3322 memset (binding
, 0, sizeof *binding
);
3324 dmalloc (strlen (val
) + 1, MDL
);
3325 if (!binding
-> name
)
3326 log_fatal ("No memory for binding %s.",
3328 strcpy (binding
-> name
, val
);
3335 if (!binding_value_allocate(&nv
, MDL
))
3336 log_fatal("no memory for binding value.");
3339 token
= next_token (&val
, (unsigned *)0, cfile
);
3340 if (token
!= EQUAL
) {
3342 "expecting '=' in set statement.");
3347 if (!parse_binding_value(cfile
, nv
)) {
3348 binding_value_dereference(&nv
, MDL
);
3349 lease_dereference(&lease
, MDL
);
3354 binding_value_reference(&binding
->value
,
3356 binding
->next
= lease
->scope
->bindings
;
3357 lease
->scope
->bindings
= binding
;
3359 binding_value_dereference(&binding
->value
, MDL
);
3360 binding_value_reference(&binding
->value
,
3364 binding_value_dereference(&nv
, MDL
);
3370 if (!strcasecmp (val
, "ddns-fwd-name")) {
3374 } else if (!strcasecmp (val
, "ddns-rev-name")) {
3379 parse_warn(cfile
, "Unexpected configuration "
3381 skip_to_semi (cfile
);
3383 lease_dereference (&lease
, MDL
);
3387 if (seenmask
& seenbit
) {
3389 "Too many %s parameters in lease %s\n",
3390 tbuf
, piaddr (lease
-> ip_addr
));
3392 seenmask
|= seenbit
;
3396 /* If no binding state is specified, make one up. */
3397 if (!(seenmask
& 256)) {
3398 if (lease
-> ends
> cur_time
||
3399 lease
-> on_expiry
|| lease
-> on_release
)
3400 lease
-> binding_state
= FTS_ACTIVE
;
3401 #if defined (FAILOVER_PROTOCOL)
3402 else if (lease
-> pool
&& lease
-> pool
-> failover_peer
)
3403 lease
-> binding_state
= FTS_EXPIRED
;
3406 lease
-> binding_state
= FTS_FREE
;
3407 if (lease
-> binding_state
== FTS_ACTIVE
) {
3408 #if defined (FAILOVER_PROTOCOL)
3409 if (lease
-> pool
&& lease
-> pool
-> failover_peer
)
3410 lease
-> next_binding_state
= FTS_EXPIRED
;
3413 lease
-> next_binding_state
= FTS_FREE
;
3415 lease
-> next_binding_state
= lease
-> binding_state
;
3417 /* The most conservative rewind state implies no rewind. */
3418 lease
->rewind_binding_state
= lease
->binding_state
;
3421 if (!(seenmask
& 65536))
3422 lease
-> tstp
= lease
-> ends
;
3424 lease_reference (lp
, lease
, MDL
);
3425 lease_dereference (&lease
, MDL
);
3429 /* Parse the right side of a 'binding value'.
3431 * set foo = "bar"; is a string
3432 * set foo = false; is a boolean
3433 * set foo = %31; is a numeric value.
3436 parse_binding_value(struct parse
*cfile
, struct binding_value
*value
)
3438 struct data_string
*data
;
3444 if ((cfile
== NULL
) || (value
== NULL
))
3445 log_fatal("Invalid arguments at %s:%d.", MDL
);
3447 token
= peek_token(&val
, NULL
, cfile
);
3448 if (token
== STRING
) {
3449 skip_token(&val
, &buflen
, cfile
);
3451 value
->type
= binding_data
;
3452 value
->value
.data
.len
= buflen
;
3454 data
= &value
->value
.data
;
3456 if (!buffer_allocate(&data
->buffer
, buflen
+ 1, MDL
))
3457 log_fatal ("No memory for binding.");
3459 memcpy(data
->buffer
->data
, val
, buflen
+ 1);
3461 data
->data
= data
->buffer
->data
;
3462 data
->terminated
= 1;
3463 } else if (token
== NUMBER_OR_NAME
) {
3464 value
->type
= binding_data
;
3466 data
= &value
->value
.data
;
3467 s
= parse_numeric_aggregate(cfile
, NULL
, &data
->len
,
3470 skip_to_semi(cfile
);
3475 if (!buffer_allocate(&data
->buffer
, data
->len
+ 1,
3477 log_fatal("No memory for binding.");
3479 memcpy(data
->buffer
->data
, s
, data
->len
);
3480 data
->data
= data
->buffer
->data
;
3484 } else if (token
== PERCENT
) {
3485 skip_token(&val
, NULL
, cfile
);
3486 token
= next_token(&val
, NULL
, cfile
);
3487 if (token
!= NUMBER
) {
3488 parse_warn(cfile
, "expecting decimal number.");
3490 skip_to_semi(cfile
);
3493 value
->type
= binding_numeric
;
3494 value
->value
.intval
= atol(val
);
3495 } else if (token
== NAME
) {
3496 token
= next_token(&val
, NULL
, cfile
);
3497 value
->type
= binding_boolean
;
3498 if (!strcasecmp(val
, "true"))
3499 value
->value
.boolean
= 1;
3500 else if (!strcasecmp(val
, "false"))
3501 value
->value
.boolean
= 0;
3503 parse_warn(cfile
, "expecting true or false");
3505 skip_to_semi(cfile
);
3509 parse_warn (cfile
, "expecting a constant value.");
3511 skip_to_semi (cfile
);
3518 /* address-range-declaration :== ip-address ip-address SEMI
3519 | DYNAMIC_BOOTP ip-address ip-address SEMI */
3521 void parse_address_range (cfile
, group
, type
, inpool
, lpchain
)
3522 struct parse
*cfile
;
3523 struct group
*group
;
3525 struct pool
*inpool
;
3526 struct lease
**lpchain
;
3528 struct iaddr low
, high
, net
;
3529 unsigned char addr
[4];
3530 unsigned len
= sizeof addr
;
3531 enum dhcp_token token
;
3534 struct subnet
*subnet
;
3535 struct shared_network
*share
;
3537 isc_result_t status
;
3539 if ((token
= peek_token (&val
,
3540 (unsigned *)0, cfile
)) == DYNAMIC_BOOTP
) {
3541 skip_token(&val
, (unsigned *)0, cfile
);
3545 /* Get the bottom address in the range... */
3546 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8))
3548 memcpy (low
.iabuf
, addr
, len
);
3551 /* Only one address? */
3552 token
= peek_token (&val
, (unsigned *)0, cfile
);
3556 /* Get the top address in the range... */
3557 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8))
3559 memcpy (high
.iabuf
, addr
, len
);
3563 token
= next_token (&val
, (unsigned *)0, cfile
);
3564 if (token
!= SEMI
) {
3565 parse_warn (cfile
, "semicolon expected.");
3566 skip_to_semi (cfile
);
3570 if (type
== SUBNET_DECL
) {
3571 subnet
= group
-> subnet
;
3572 share
= subnet
-> shared_network
;
3574 share
= group
-> shared_network
;
3575 for (subnet
= share
-> subnets
;
3576 subnet
; subnet
= subnet
-> next_sibling
) {
3577 net
= subnet_number (low
, subnet
-> netmask
);
3578 if (addr_eq (net
, subnet
-> net
))
3582 parse_warn (cfile
, "address range not on network %s",
3583 group
-> shared_network
-> name
);
3584 log_error ("Be sure to place pool statement after %s",
3585 "related subnet declarations.");
3591 struct pool
*last
= (struct pool
*)0;
3593 /* If we're permitting dynamic bootp for this range,
3594 then look for a pool with an empty prohibit list and
3595 a permit list with one entry that permits all clients. */
3596 for (pool
= share
-> pools
; pool
; pool
= pool
-> next
) {
3597 if ((!dynamic
&& !pool
-> permit_list
&&
3598 pool
-> prohibit_list
&&
3599 !pool
-> prohibit_list
-> next
&&
3600 (pool
-> prohibit_list
-> type
==
3601 permit_dynamic_bootp_clients
)) ||
3602 (dynamic
&& !pool
-> prohibit_list
&&
3603 pool
-> permit_list
&&
3604 !pool
-> permit_list
-> next
&&
3605 (pool
-> permit_list
-> type
==
3606 permit_all_clients
))) {
3612 /* If we didn't get a pool, make one. */
3615 status
= pool_allocate (&pool
, MDL
);
3616 if (status
!= ISC_R_SUCCESS
)
3617 log_fatal ("no memory for ad-hoc pool: %s",
3618 isc_result_totext (status
));
3619 p
= new_permit (MDL
);
3621 log_fatal ("no memory for ad-hoc permit.");
3623 /* Dynamic pools permit all clients. Otherwise
3624 we prohibit BOOTP clients. */
3626 p
-> type
= permit_all_clients
;
3627 pool
-> permit_list
= p
;
3629 p
-> type
= permit_dynamic_bootp_clients
;
3630 pool
-> prohibit_list
= p
;
3634 pool_reference (&last
-> next
, pool
, MDL
);
3636 pool_reference (&share
-> pools
, pool
, MDL
);
3637 shared_network_reference (&pool
-> shared_network
,
3639 if (!clone_group (&pool
-> group
, share
-> group
, MDL
))
3640 log_fatal ("no memory for anon pool group.");
3642 pool
= (struct pool
*)0;
3644 pool_reference (&pool
, last
, MDL
);
3646 pool_reference (&pool
, share
-> pools
, MDL
);
3649 pool
= (struct pool
*)0;
3650 pool_reference (&pool
, inpool
, MDL
);
3653 #if defined (FAILOVER_PROTOCOL)
3654 if (pool
-> failover_peer
&& dynamic
) {
3655 /* Doctor, do you think I'm overly sensitive
3656 about getting bug reports I can't fix? */
3657 parse_warn (cfile
, "dynamic-bootp flag is %s",
3658 "not permitted for address");
3659 log_error ("range declarations where there is a failover");
3660 log_error ("peer in scope. If you wish to declare an");
3661 log_error ("address range from which dynamic bootp leases");
3662 log_error ("can be allocated, please declare it within a");
3663 log_error ("pool declaration that also contains the \"no");
3664 log_error ("failover\" statement. The failover protocol");
3665 log_error ("itself does not permit dynamic bootp - this");
3666 log_error ("is not a limitation specific to the ISC DHCP");
3667 log_error ("server. Please don't ask me to defend this");
3668 log_error ("until you have read and really tried %s",
3670 log_error ("the failover protocol specification.");
3672 /* We don't actually bomb at this point - instead,
3673 we let parse_lease_file notice the error and
3674 bomb at that point - it's easier. */
3676 #endif /* FAILOVER_PROTOCOL */
3678 /* Create the new address range... */
3679 new_address_range (cfile
, low
, high
, subnet
, pool
, lpchain
);
3680 pool_dereference (&pool
, MDL
);
3685 add_ipv6_pool_to_subnet(struct subnet
*subnet
, u_int16_t type
,
3686 struct iaddr
*lo_addr
, int bits
, int units
) {
3687 struct ipv6_pool
*pool
;
3688 struct shared_network
*share
;
3689 struct in6_addr tmp_in6_addr
;
3691 struct ipv6_pool
**tmp
;
3693 share
= subnet
->shared_network
;
3698 if (lo_addr
->len
!= sizeof(tmp_in6_addr
)) {
3699 log_fatal("Internal error: Attempt to add non-IPv6 address "
3700 "to IPv6 shared network.");
3702 memcpy(&tmp_in6_addr
, lo_addr
->iabuf
, sizeof(tmp_in6_addr
));
3704 if (ipv6_pool_allocate(&pool
, type
, &tmp_in6_addr
,
3705 bits
, units
, MDL
) != ISC_R_SUCCESS
) {
3706 log_fatal("Out of memory");
3710 * Add to our global IPv6 pool set.
3712 if (add_ipv6_pool(pool
) != ISC_R_SUCCESS
) {
3713 log_fatal ("Out of memory");
3717 * Link the pool to its network.
3719 pool
->subnet
= NULL
;
3720 subnet_reference(&pool
->subnet
, subnet
, MDL
);
3721 pool
->shared_network
= NULL
;
3722 shared_network_reference(&pool
->shared_network
, share
, MDL
);
3725 * Increase our array size for ipv6_pools in the shared_network.
3727 if (share
->ipv6_pools
== NULL
) {
3731 while (share
->ipv6_pools
[num_pools
] != NULL
) {
3735 tmp
= dmalloc(sizeof(struct ipv6_pool
*) * (num_pools
+ 2), MDL
);
3737 log_fatal("Out of memory");
3739 if (num_pools
> 0) {
3740 memcpy(tmp
, share
->ipv6_pools
,
3741 sizeof(struct ipv6_pool
*) * num_pools
);
3743 if (share
->ipv6_pools
!= NULL
) {
3744 dfree(share
->ipv6_pools
, MDL
);
3746 share
->ipv6_pools
= tmp
;
3749 * Record this pool in our array of pools for this shared network.
3751 ipv6_pool_reference(&share
->ipv6_pools
[num_pools
], pool
, MDL
);
3752 share
->ipv6_pools
[num_pools
+1] = NULL
;
3755 /* address-range6-declaration :== ip-address6 ip-address6 SEMI
3756 | ip-address6 SLASH number SEMI
3757 | ip-address6 [SLASH number] TEMPORARY SEMI */
3760 parse_address_range6(struct parse
*cfile
, struct group
*group
) {
3761 struct iaddr lo
, hi
;
3763 enum dhcp_token token
;
3765 struct iaddrcidrnetlist
*nets
;
3766 struct iaddrcidrnetlist
*p
;
3767 u_int16_t type
= D6O_IA_NA
;
3769 if (local_family
!= AF_INET6
) {
3770 parse_warn(cfile
, "range6 statement is only supported "
3772 skip_to_semi(cfile
);
3776 /* This is enforced by the caller, this is just a sanity check. */
3777 if (group
->subnet
== NULL
)
3778 log_fatal("Impossible condition at %s:%d.", MDL
);
3781 * Read starting address.
3783 if (!parse_ip6_addr(cfile
, &lo
)) {
3788 * See if we we're using range or CIDR notation or TEMPORARY
3790 token
= peek_token(&val
, NULL
, cfile
);
3791 if (token
== SLASH
) {
3793 * '/' means CIDR notation, so read the bits we want.
3795 skip_token(NULL
, NULL
, cfile
);
3796 token
= next_token(&val
, NULL
, cfile
);
3797 if (token
!= NUMBER
) {
3798 parse_warn(cfile
, "expecting number");
3799 skip_to_semi(cfile
);
3803 if ((bits
< 0) || (bits
> 128)) {
3804 parse_warn(cfile
, "networks have 0 to 128 bits");
3805 skip_to_semi(cfile
);
3808 if (!is_cidr_mask_valid(&lo
, bits
)) {
3809 parse_warn(cfile
, "network mask too short");
3810 skip_to_semi(cfile
);
3815 * can be temporary (RFC 4941 like)
3817 token
= peek_token(&val
, NULL
, cfile
);
3818 if (token
== TEMPORARY
) {
3820 parse_warn(cfile
, "temporary mask too short");
3822 parse_warn(cfile
, "temporary singleton?");
3823 skip_token(NULL
, NULL
, cfile
);
3827 add_ipv6_pool_to_subnet(group
->subnet
, type
, &lo
,
3830 } else if (token
== TEMPORARY
) {
3832 * temporary (RFC 4941)
3835 skip_token(NULL
, NULL
, cfile
);
3837 if (!is_cidr_mask_valid(&lo
, bits
)) {
3838 parse_warn(cfile
, "network mask too short");
3839 skip_to_semi(cfile
);
3843 add_ipv6_pool_to_subnet(group
->subnet
, type
, &lo
,
3847 * No '/', so we are looking for the end address of
3850 if (!parse_ip6_addr(cfile
, &hi
)) {
3855 * Convert our range to a set of CIDR networks.
3858 if (range2cidr(&nets
, &lo
, &hi
) != ISC_R_SUCCESS
) {
3859 log_fatal("Error converting range to CIDR networks");
3862 for (p
=nets
; p
!= NULL
; p
=p
->next
) {
3863 add_ipv6_pool_to_subnet(group
->subnet
, type
,
3864 &p
->cidrnet
.lo_addr
,
3865 p
->cidrnet
.bits
, 128);
3868 free_iaddrcidrnetlist(&nets
);
3871 token
= next_token(NULL
, NULL
, cfile
);
3872 if (token
!= SEMI
) {
3873 parse_warn(cfile
, "semicolon expected.");
3874 skip_to_semi(cfile
);
3879 /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
3882 parse_prefix6(struct parse
*cfile
, struct group
*group
) {
3883 struct iaddr lo
, hi
;
3885 enum dhcp_token token
;
3887 struct iaddrcidrnetlist
*nets
;
3888 struct iaddrcidrnetlist
*p
;
3890 if (local_family
!= AF_INET6
) {
3891 parse_warn(cfile
, "prefix6 statement is only supported "
3893 skip_to_semi(cfile
);
3897 /* This is enforced by the caller, so it's just a sanity check. */
3898 if (group
->subnet
== NULL
)
3899 log_fatal("Impossible condition at %s:%d.", MDL
);
3902 * Read starting and ending address.
3904 if (!parse_ip6_addr(cfile
, &lo
)) {
3907 if (!parse_ip6_addr(cfile
, &hi
)) {
3912 * Next is '/' number ';'.
3914 token
= next_token(NULL
, NULL
, cfile
);
3915 if (token
!= SLASH
) {
3916 parse_warn(cfile
, "expecting '/'");
3918 skip_to_semi(cfile
);
3921 token
= next_token(&val
, NULL
, cfile
);
3922 if (token
!= NUMBER
) {
3923 parse_warn(cfile
, "expecting number");
3925 skip_to_semi(cfile
);
3929 if ((bits
<= 0) || (bits
>= 128)) {
3930 parse_warn(cfile
, "networks have 0 to 128 bits (exclusive)");
3933 if (!is_cidr_mask_valid(&lo
, bits
) ||
3934 !is_cidr_mask_valid(&hi
, bits
)) {
3935 parse_warn(cfile
, "network mask too short");
3938 token
= next_token(NULL
, NULL
, cfile
);
3939 if (token
!= SEMI
) {
3940 parse_warn(cfile
, "semicolon expected.");
3941 skip_to_semi(cfile
);
3946 * Convert our range to a set of CIDR networks.
3949 if (range2cidr(&nets
, &lo
, &hi
) != ISC_R_SUCCESS
) {
3950 log_fatal("Error converting prefix to CIDR");
3953 for (p
= nets
; p
!= NULL
; p
= p
->next
) {
3954 /* Normalize and check. */
3955 if (p
->cidrnet
.bits
== 128) {
3956 p
->cidrnet
.bits
= bits
;
3958 if (p
->cidrnet
.bits
> bits
) {
3959 parse_warn(cfile
, "impossible mask length");
3962 add_ipv6_pool_to_subnet(group
->subnet
, D6O_IA_PD
,
3963 &p
->cidrnet
.lo_addr
,
3964 p
->cidrnet
.bits
, bits
);
3967 free_iaddrcidrnetlist(&nets
);
3970 /* fixed-prefix6 :== ip6-address SLASH number SEMI */
3973 parse_fixed_prefix6(struct parse
*cfile
, struct host_decl
*host_decl
) {
3974 struct iaddrcidrnetlist
*ia
, **h
;
3975 enum dhcp_token token
;
3979 * Get the head of the fixed-prefix list.
3981 h
= &host_decl
->fixed_prefix
;
3986 while (*h
!= NULL
) {
3991 * Allocate a new iaddrcidrnetlist structure.
3993 ia
= dmalloc(sizeof(*ia
), MDL
);
3995 log_fatal("Out of memory");
4001 if (!parse_ip6_addr(cfile
, &ia
->cidrnet
.lo_addr
)) {
4005 token
= next_token(NULL
, NULL
, cfile
);
4006 if (token
!= SLASH
) {
4008 parse_warn(cfile
, "expecting '/'");
4010 skip_to_semi(cfile
);
4013 token
= next_token(&val
, NULL
, cfile
);
4014 if (token
!= NUMBER
) {
4016 parse_warn(cfile
, "expecting number");
4018 skip_to_semi(cfile
);
4021 token
= next_token(NULL
, NULL
, cfile
);
4022 if (token
!= SEMI
) {
4024 parse_warn(cfile
, "semicolon expected.");
4025 skip_to_semi(cfile
);
4032 ia
->cidrnet
.bits
= atoi(val
);
4033 if ((ia
->cidrnet
.bits
< 0) || (ia
->cidrnet
.bits
> 128)) {
4035 parse_warn(cfile
, "networks have 0 to 128 bits");
4038 if (!is_cidr_mask_valid(&ia
->cidrnet
.lo_addr
, ia
->cidrnet
.bits
)) {
4040 parse_warn(cfile
, "network mask too short");
4052 /* allow-deny-keyword :== BOOTP
4055 | UNKNOWN_CLIENTS */
4057 int parse_allow_deny (oc
, cfile
, flag
)
4058 struct option_cache
**oc
;
4059 struct parse
*cfile
;
4062 enum dhcp_token token
;
4064 unsigned char rf
= flag
;
4066 struct option
*option
= NULL
;
4067 struct expression
*data
= (struct expression
*)0;
4070 if (!make_const_data (&data
, &rf
, 1, 0, 1, MDL
))
4073 token
= next_token (&val
, (unsigned *)0, cfile
);
4076 code
= SV_ALLOW_BOOTP
;
4080 code
= SV_ALLOW_BOOTING
;
4084 code
= SV_DYNAMIC_BOOTP
;
4087 case UNKNOWN_CLIENTS
:
4088 code
= SV_BOOT_UNKNOWN_CLIENTS
;
4092 code
= SV_DUPLICATES
;
4099 case CLIENT_UPDATES
:
4100 code
= SV_CLIENT_UPDATES
;
4104 code
= SV_LEASEQUERY
;
4108 parse_warn (cfile
, "expecting allow/deny key");
4109 skip_to_semi (cfile
);
4112 /* Reference on option is passed to option cache. */
4113 if (!option_code_hash_lookup(&option
, server_universe
.code_hash
,
4115 log_fatal("Unable to find server option %u (%s:%d).",
4117 status
= option_cache(oc
, NULL
, data
, option
, MDL
);
4118 expression_dereference (&data
, MDL
);
4124 parse_ia_na_declaration(struct parse
*cfile
) {
4125 #if !defined(DHCPv6)
4126 parse_warn(cfile
, "No DHCPv6 support.");
4127 skip_to_semi(cfile
);
4128 #else /* defined(DHCPv6) */
4129 enum dhcp_token token
;
4132 struct ia_xx
*old_ia
;
4136 binding_state_t state
;
4140 struct iasubopt
*iaaddr
;
4141 struct ipv6_pool
*pool
;
4142 char addr_buf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
4143 isc_boolean_t newbinding
;
4144 struct binding_scope
*scope
=NULL
;
4145 struct binding
*bnd
;
4146 struct binding_value
*nv
=NULL
;
4148 if (local_family
!= AF_INET6
) {
4149 parse_warn(cfile
, "IA_NA is only supported in DHCPv6 mode.");
4150 skip_to_semi(cfile
);
4154 token
= next_token(&val
, &len
, cfile
);
4155 if (token
!= STRING
) {
4156 parse_warn(cfile
, "corrupt lease file; "
4157 "expecting an iaid+ia_na string");
4158 skip_to_semi(cfile
);
4162 parse_warn(cfile
, "corrupt lease file; "
4163 "iaid+ia_na string too short");
4164 skip_to_semi(cfile
);
4168 memcpy(&iaid
, val
, 4);
4170 if (ia_allocate(&ia
, iaid
, val
+4, len
-4, MDL
) != ISC_R_SUCCESS
) {
4171 log_fatal("Out of memory.");
4173 ia
->ia_type
= D6O_IA_NA
;
4175 token
= next_token(&val
, NULL
, cfile
);
4176 if (token
!= LBRACE
) {
4177 parse_warn(cfile
, "corrupt lease file; expecting left brace");
4178 skip_to_semi(cfile
);
4183 token
= next_token(&val
, NULL
, cfile
);
4184 if (token
== RBRACE
) break;
4186 if (token
== CLTT
) {
4187 ia
->cltt
= parse_date (cfile
);
4191 if (token
!= IAADDR
) {
4192 parse_warn(cfile
, "corrupt lease file; "
4193 "expecting IAADDR or right brace");
4194 skip_to_semi(cfile
);
4198 if (!parse_ip6_addr(cfile
, &iaddr
)) {
4199 parse_warn(cfile
, "corrupt lease file; "
4200 "expecting IPv6 address");
4201 skip_to_semi(cfile
);
4205 token
= next_token(&val
, NULL
, cfile
);
4206 if (token
!= LBRACE
) {
4207 parse_warn(cfile
, "corrupt lease file; "
4208 "expecting left brace");
4209 skip_to_semi(cfile
);
4217 token
= next_token(&val
, NULL
, cfile
);
4218 if (token
== RBRACE
) break;
4221 /* Lease binding state. */
4223 token
= next_token(&val
, NULL
, cfile
);
4224 if (token
!= STATE
) {
4225 parse_warn(cfile
, "corrupt lease file; "
4227 skip_to_semi(cfile
);
4230 token
= next_token(&val
, NULL
, cfile
);
4232 case TOKEN_ABANDONED
:
4233 state
= FTS_ABANDONED
;
4242 state
= FTS_EXPIRED
;
4244 case TOKEN_RELEASED
:
4245 state
= FTS_RELEASED
;
4253 skip_to_semi(cfile
);
4257 token
= next_token(&val
, NULL
, cfile
);
4258 if (token
!= SEMI
) {
4259 parse_warn(cfile
, "corrupt lease file; "
4265 /* Lease preferred lifetime. */
4266 case PREFERRED_LIFE
:
4267 token
= next_token(&val
, NULL
, cfile
);
4268 if (token
!= NUMBER
) {
4269 parse_warn(cfile
, "%s is not a valid "
4272 skip_to_semi(cfile
);
4275 prefer
= atoi (val
);
4278 * Currently we peek for the semi-colon to
4279 * allow processing of older lease files that
4280 * don't have the semi-colon. Eventually we
4281 * should remove the peeking code.
4283 token
= peek_token(&val
, NULL
, cfile
);
4284 if (token
== SEMI
) {
4285 skip_token(&val
, NULL
, cfile
);
4288 "corrupt lease file; "
4289 "expecting semicolon.");
4293 /* Lease valid lifetime. */
4295 token
= next_token(&val
, NULL
, cfile
);
4296 if (token
!= NUMBER
) {
4297 parse_warn(cfile
, "%s is not a valid "
4300 skip_to_semi(cfile
);
4306 * Currently we peek for the semi-colon to
4307 * allow processing of older lease files that
4308 * don't have the semi-colon. Eventually we
4309 * should remove the peeking code.
4311 token
= peek_token(&val
, NULL
, cfile
);
4312 if (token
== SEMI
) {
4313 skip_token(&val
, NULL
, cfile
);
4316 "corrupt lease file; "
4317 "expecting semicolon.");
4321 /* Lease expiration time. */
4323 end_time
= parse_date(cfile
);
4326 /* Lease binding scopes. */
4328 token
= next_token(&val
, NULL
, cfile
);
4329 if ((token
!= NAME
) &&
4330 (token
!= NUMBER_OR_NAME
)) {
4331 parse_warn(cfile
, "%s is not a valid "
4334 skip_to_semi(cfile
);
4339 bnd
= find_binding(scope
, val
);
4341 if (!binding_scope_allocate(&scope
,
4343 log_fatal("Out of memory for "
4352 bnd
= dmalloc(sizeof(*bnd
),
4355 log_fatal("No memory for "
4359 bnd
->name
= dmalloc(strlen(val
) + 1,
4361 if (bnd
->name
== NULL
) {
4362 log_fatal("No memory for "
4365 strcpy(bnd
->name
, val
);
4367 newbinding
= ISC_TRUE
;
4369 newbinding
= ISC_FALSE
;
4372 if (!binding_value_allocate(&nv
, MDL
)) {
4373 log_fatal("no memory for binding "
4377 token
= next_token(NULL
, NULL
, cfile
);
4378 if (token
!= EQUAL
) {
4379 parse_warn(cfile
, "expecting '=' in "
4384 if (!parse_binding_value(cfile
, nv
)) {
4386 binding_value_dereference(&nv
, MDL
);
4387 binding_scope_dereference(&scope
, MDL
);
4392 binding_value_reference(&bnd
->value
,
4394 bnd
->next
= scope
->bindings
;
4395 scope
->bindings
= bnd
;
4397 binding_value_dereference(&bnd
->value
,
4399 binding_value_reference(&bnd
->value
,
4403 binding_value_dereference(&nv
, MDL
);
4408 parse_warn(cfile
, "corrupt lease file; "
4409 "expecting ia_na contents, "
4411 skip_to_semi(cfile
);
4416 if (state
== FTS_LAST
+1) {
4417 parse_warn(cfile
, "corrupt lease file; "
4418 "missing state in iaaddr");
4421 if (end_time
== -1) {
4422 parse_warn(cfile
, "corrupt lease file; "
4423 "missing end time in iaaddr");
4428 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
4429 log_fatal("Out of memory.");
4431 memcpy(&iaaddr
->addr
, iaddr
.iabuf
, sizeof(iaaddr
->addr
));
4433 iaaddr
->state
= state
;
4434 iaaddr
->prefer
= prefer
;
4435 iaaddr
->valid
= valid
;
4436 if (iaaddr
->state
== FTS_RELEASED
)
4437 iaaddr
->hard_lifetime_end_time
= end_time
;
4439 if (scope
!= NULL
) {
4440 binding_scope_reference(&iaaddr
->scope
, scope
, MDL
);
4441 binding_scope_dereference(&scope
, MDL
);
4444 /* find the pool this address is in */
4446 if (find_ipv6_pool(&pool
, D6O_IA_NA
,
4447 &iaaddr
->addr
) != ISC_R_SUCCESS
) {
4448 inet_ntop(AF_INET6
, &iaaddr
->addr
,
4449 addr_buf
, sizeof(addr_buf
));
4450 parse_warn(cfile
, "no pool found for address %s",
4455 /* remove old information */
4456 if (cleanup_lease6(ia_na_active
, pool
,
4457 iaaddr
, ia
) != ISC_R_SUCCESS
) {
4458 inet_ntop(AF_INET6
, &iaaddr
->addr
,
4459 addr_buf
, sizeof(addr_buf
));
4460 parse_warn(cfile
, "duplicate na lease for address %s",
4465 * if we like the lease we add it to our various structues
4466 * otherwise we leave it and it will get cleaned when we
4467 * do the iasubopt_dereference.
4469 if ((state
== FTS_ACTIVE
) || (state
== FTS_ABANDONED
)) {
4470 ia_add_iasubopt(ia
, iaaddr
, MDL
);
4471 ia_reference(&iaaddr
->ia
, ia
, MDL
);
4472 add_lease6(pool
, iaaddr
, end_time
);
4475 iasubopt_dereference(&iaaddr
, MDL
);
4476 ipv6_pool_dereference(&pool
, MDL
);
4480 * If we have an existing record for this IA_NA, remove it.
4483 if (ia_hash_lookup(&old_ia
, ia_na_active
,
4484 (unsigned char *)ia
->iaid_duid
.data
,
4485 ia
->iaid_duid
.len
, MDL
)) {
4486 ia_hash_delete(ia_na_active
,
4487 (unsigned char *)ia
->iaid_duid
.data
,
4488 ia
->iaid_duid
.len
, MDL
);
4489 ia_dereference(&old_ia
, MDL
);
4493 * If we have addresses, add this, otherwise don't bother.
4495 if (ia
->num_iasubopt
> 0) {
4496 ia_hash_add(ia_na_active
,
4497 (unsigned char *)ia
->iaid_duid
.data
,
4498 ia
->iaid_duid
.len
, ia
, MDL
);
4500 ia_dereference(&ia
, MDL
);
4501 #endif /* defined(DHCPv6) */
4505 parse_ia_ta_declaration(struct parse
*cfile
) {
4506 #if !defined(DHCPv6)
4507 parse_warn(cfile
, "No DHCPv6 support.");
4508 skip_to_semi(cfile
);
4509 #else /* defined(DHCPv6) */
4510 enum dhcp_token token
;
4513 struct ia_xx
*old_ia
;
4517 binding_state_t state
;
4521 struct iasubopt
*iaaddr
;
4522 struct ipv6_pool
*pool
;
4523 char addr_buf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
4524 isc_boolean_t newbinding
;
4525 struct binding_scope
*scope
=NULL
;
4526 struct binding
*bnd
;
4527 struct binding_value
*nv
=NULL
;
4529 if (local_family
!= AF_INET6
) {
4530 parse_warn(cfile
, "IA_TA is only supported in DHCPv6 mode.");
4531 skip_to_semi(cfile
);
4535 token
= next_token(&val
, &len
, cfile
);
4536 if (token
!= STRING
) {
4537 parse_warn(cfile
, "corrupt lease file; "
4538 "expecting an iaid+ia_ta string");
4539 skip_to_semi(cfile
);
4543 parse_warn(cfile
, "corrupt lease file; "
4544 "iaid+ia_ta string too short");
4545 skip_to_semi(cfile
);
4549 memcpy(&iaid
, val
, 4);
4551 if (ia_allocate(&ia
, iaid
, val
+4, len
-4, MDL
) != ISC_R_SUCCESS
) {
4552 log_fatal("Out of memory.");
4554 ia
->ia_type
= D6O_IA_TA
;
4556 token
= next_token(&val
, NULL
, cfile
);
4557 if (token
!= LBRACE
) {
4558 parse_warn(cfile
, "corrupt lease file; expecting left brace");
4559 skip_to_semi(cfile
);
4564 token
= next_token(&val
, NULL
, cfile
);
4565 if (token
== RBRACE
) break;
4567 if (token
== CLTT
) {
4568 ia
->cltt
= parse_date (cfile
);
4572 if (token
!= IAADDR
) {
4573 parse_warn(cfile
, "corrupt lease file; "
4574 "expecting IAADDR or right brace");
4575 skip_to_semi(cfile
);
4579 if (!parse_ip6_addr(cfile
, &iaddr
)) {
4580 parse_warn(cfile
, "corrupt lease file; "
4581 "expecting IPv6 address");
4582 skip_to_semi(cfile
);
4586 token
= next_token(&val
, NULL
, cfile
);
4587 if (token
!= LBRACE
) {
4588 parse_warn(cfile
, "corrupt lease file; "
4589 "expecting left brace");
4590 skip_to_semi(cfile
);
4598 token
= next_token(&val
, NULL
, cfile
);
4599 if (token
== RBRACE
) break;
4602 /* Lease binding state. */
4604 token
= next_token(&val
, NULL
, cfile
);
4605 if (token
!= STATE
) {
4606 parse_warn(cfile
, "corrupt lease file; "
4608 skip_to_semi(cfile
);
4611 token
= next_token(&val
, NULL
, cfile
);
4613 case TOKEN_ABANDONED
:
4614 state
= FTS_ABANDONED
;
4623 state
= FTS_EXPIRED
;
4625 case TOKEN_RELEASED
:
4626 state
= FTS_RELEASED
;
4634 skip_to_semi(cfile
);
4638 token
= next_token(&val
, NULL
, cfile
);
4639 if (token
!= SEMI
) {
4640 parse_warn(cfile
, "corrupt lease file; "
4646 /* Lease preferred lifetime. */
4647 case PREFERRED_LIFE
:
4648 token
= next_token(&val
, NULL
, cfile
);
4649 if (token
!= NUMBER
) {
4650 parse_warn(cfile
, "%s is not a valid "
4653 skip_to_semi(cfile
);
4656 prefer
= atoi (val
);
4659 * Currently we peek for the semi-colon to
4660 * allow processing of older lease files that
4661 * don't have the semi-colon. Eventually we
4662 * should remove the peeking code.
4664 token
= peek_token(&val
, NULL
, cfile
);
4665 if (token
== SEMI
) {
4666 skip_token(&val
, NULL
, cfile
);
4669 "corrupt lease file; "
4670 "expecting semicolon.");
4674 /* Lease valid lifetime. */
4676 token
= next_token(&val
, NULL
, cfile
);
4677 if (token
!= NUMBER
) {
4678 parse_warn(cfile
, "%s is not a valid "
4681 skip_to_semi(cfile
);
4687 * Currently we peek for the semi-colon to
4688 * allow processing of older lease files that
4689 * don't have the semi-colon. Eventually we
4690 * should remove the peeking code.
4692 token
= peek_token(&val
, NULL
, cfile
);
4693 if (token
== SEMI
) {
4694 skip_token(&val
, NULL
, cfile
);
4697 "corrupt lease file; "
4698 "expecting semicolon.");
4702 /* Lease expiration time. */
4704 end_time
= parse_date(cfile
);
4707 /* Lease binding scopes. */
4709 token
= next_token(&val
, NULL
, cfile
);
4710 if ((token
!= NAME
) &&
4711 (token
!= NUMBER_OR_NAME
)) {
4712 parse_warn(cfile
, "%s is not a valid "
4715 skip_to_semi(cfile
);
4720 bnd
= find_binding(scope
, val
);
4722 if (!binding_scope_allocate(&scope
,
4724 log_fatal("Out of memory for "
4733 bnd
= dmalloc(sizeof(*bnd
),
4736 log_fatal("No memory for "
4740 bnd
->name
= dmalloc(strlen(val
) + 1,
4742 if (bnd
->name
== NULL
) {
4743 log_fatal("No memory for "
4746 strcpy(bnd
->name
, val
);
4748 newbinding
= ISC_TRUE
;
4750 newbinding
= ISC_FALSE
;
4753 if (!binding_value_allocate(&nv
, MDL
)) {
4754 log_fatal("no memory for binding "
4758 token
= next_token(NULL
, NULL
, cfile
);
4759 if (token
!= EQUAL
) {
4760 parse_warn(cfile
, "expecting '=' in "
4765 if (!parse_binding_value(cfile
, nv
)) {
4767 binding_value_dereference(&nv
, MDL
);
4768 binding_scope_dereference(&scope
, MDL
);
4773 binding_value_reference(&bnd
->value
,
4775 bnd
->next
= scope
->bindings
;
4776 scope
->bindings
= bnd
;
4778 binding_value_dereference(&bnd
->value
,
4780 binding_value_reference(&bnd
->value
,
4784 binding_value_dereference(&nv
, MDL
);
4789 parse_warn(cfile
, "corrupt lease file; "
4790 "expecting ia_ta contents, "
4792 skip_to_semi(cfile
);
4797 if (state
== FTS_LAST
+1) {
4798 parse_warn(cfile
, "corrupt lease file; "
4799 "missing state in iaaddr");
4802 if (end_time
== -1) {
4803 parse_warn(cfile
, "corrupt lease file; "
4804 "missing end time in iaaddr");
4809 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
4810 log_fatal("Out of memory.");
4812 memcpy(&iaaddr
->addr
, iaddr
.iabuf
, sizeof(iaaddr
->addr
));
4814 iaaddr
->state
= state
;
4815 iaaddr
->prefer
= prefer
;
4816 iaaddr
->valid
= valid
;
4817 if (iaaddr
->state
== FTS_RELEASED
)
4818 iaaddr
->hard_lifetime_end_time
= end_time
;
4820 if (scope
!= NULL
) {
4821 binding_scope_reference(&iaaddr
->scope
, scope
, MDL
);
4822 binding_scope_dereference(&scope
, MDL
);
4825 /* find the pool this address is in */
4827 if (find_ipv6_pool(&pool
, D6O_IA_TA
,
4828 &iaaddr
->addr
) != ISC_R_SUCCESS
) {
4829 inet_ntop(AF_INET6
, &iaaddr
->addr
,
4830 addr_buf
, sizeof(addr_buf
));
4831 parse_warn(cfile
, "no pool found for address %s",
4836 /* remove old information */
4837 if (cleanup_lease6(ia_ta_active
, pool
,
4838 iaaddr
, ia
) != ISC_R_SUCCESS
) {
4839 inet_ntop(AF_INET6
, &iaaddr
->addr
,
4840 addr_buf
, sizeof(addr_buf
));
4841 parse_warn(cfile
, "duplicate ta lease for address %s",
4846 * if we like the lease we add it to our various structues
4847 * otherwise we leave it and it will get cleaned when we
4848 * do the iasubopt_dereference.
4850 if ((state
== FTS_ACTIVE
) || (state
== FTS_ABANDONED
)) {
4851 ia_add_iasubopt(ia
, iaaddr
, MDL
);
4852 ia_reference(&iaaddr
->ia
, ia
, MDL
);
4853 add_lease6(pool
, iaaddr
, end_time
);
4856 ipv6_pool_dereference(&pool
, MDL
);
4857 iasubopt_dereference(&iaaddr
, MDL
);
4861 * If we have an existing record for this IA_TA, remove it.
4864 if (ia_hash_lookup(&old_ia
, ia_ta_active
,
4865 (unsigned char *)ia
->iaid_duid
.data
,
4866 ia
->iaid_duid
.len
, MDL
)) {
4867 ia_hash_delete(ia_ta_active
,
4868 (unsigned char *)ia
->iaid_duid
.data
,
4869 ia
->iaid_duid
.len
, MDL
);
4870 ia_dereference(&old_ia
, MDL
);
4874 * If we have addresses, add this, otherwise don't bother.
4876 if (ia
->num_iasubopt
> 0) {
4877 ia_hash_add(ia_ta_active
,
4878 (unsigned char *)ia
->iaid_duid
.data
,
4879 ia
->iaid_duid
.len
, ia
, MDL
);
4881 ia_dereference(&ia
, MDL
);
4882 #endif /* defined(DHCPv6) */
4886 parse_ia_pd_declaration(struct parse
*cfile
) {
4887 #if !defined(DHCPv6)
4888 parse_warn(cfile
, "No DHCPv6 support.");
4889 skip_to_semi(cfile
);
4890 #else /* defined(DHCPv6) */
4891 enum dhcp_token token
;
4894 struct ia_xx
*old_ia
;
4899 binding_state_t state
;
4903 struct iasubopt
*iapref
;
4904 struct ipv6_pool
*pool
;
4905 char addr_buf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
4906 isc_boolean_t newbinding
;
4907 struct binding_scope
*scope
=NULL
;
4908 struct binding
*bnd
;
4909 struct binding_value
*nv
=NULL
;
4911 if (local_family
!= AF_INET6
) {
4912 parse_warn(cfile
, "IA_PD is only supported in DHCPv6 mode.");
4913 skip_to_semi(cfile
);
4917 token
= next_token(&val
, &len
, cfile
);
4918 if (token
!= STRING
) {
4919 parse_warn(cfile
, "corrupt lease file; "
4920 "expecting an iaid+ia_pd string");
4921 skip_to_semi(cfile
);
4925 parse_warn(cfile
, "corrupt lease file; "
4926 "iaid+ia_pd string too short");
4927 skip_to_semi(cfile
);
4931 memcpy(&iaid
, val
, 4);
4933 if (ia_allocate(&ia
, iaid
, val
+4, len
-4, MDL
) != ISC_R_SUCCESS
) {
4934 log_fatal("Out of memory.");
4936 ia
->ia_type
= D6O_IA_PD
;
4938 token
= next_token(&val
, NULL
, cfile
);
4939 if (token
!= LBRACE
) {
4940 parse_warn(cfile
, "corrupt lease file; expecting left brace");
4941 skip_to_semi(cfile
);
4946 token
= next_token(&val
, NULL
, cfile
);
4947 if (token
== RBRACE
) break;
4949 if (token
== CLTT
) {
4950 ia
->cltt
= parse_date (cfile
);
4954 if (token
!= IAPREFIX
) {
4955 parse_warn(cfile
, "corrupt lease file; expecting "
4956 "IAPREFIX or right brace");
4957 skip_to_semi(cfile
);
4961 if (!parse_ip6_prefix(cfile
, &iaddr
, &plen
)) {
4962 parse_warn(cfile
, "corrupt lease file; "
4963 "expecting IPv6 prefix");
4964 skip_to_semi(cfile
);
4968 token
= next_token(&val
, NULL
, cfile
);
4969 if (token
!= LBRACE
) {
4970 parse_warn(cfile
, "corrupt lease file; "
4971 "expecting left brace");
4972 skip_to_semi(cfile
);
4980 token
= next_token(&val
, NULL
, cfile
);
4981 if (token
== RBRACE
) break;
4984 /* Prefix binding state. */
4986 token
= next_token(&val
, NULL
, cfile
);
4987 if (token
!= STATE
) {
4988 parse_warn(cfile
, "corrupt lease file; "
4990 skip_to_semi(cfile
);
4993 token
= next_token(&val
, NULL
, cfile
);
4995 case TOKEN_ABANDONED
:
4996 state
= FTS_ABANDONED
;
5005 state
= FTS_EXPIRED
;
5007 case TOKEN_RELEASED
:
5008 state
= FTS_RELEASED
;
5016 skip_to_semi(cfile
);
5020 token
= next_token(&val
, NULL
, cfile
);
5021 if (token
!= SEMI
) {
5022 parse_warn(cfile
, "corrupt lease file; "
5028 /* Lease preferred lifetime. */
5029 case PREFERRED_LIFE
:
5030 token
= next_token(&val
, NULL
, cfile
);
5031 if (token
!= NUMBER
) {
5032 parse_warn(cfile
, "%s is not a valid "
5035 skip_to_semi(cfile
);
5038 prefer
= atoi (val
);
5041 * Currently we peek for the semi-colon to
5042 * allow processing of older lease files that
5043 * don't have the semi-colon. Eventually we
5044 * should remove the peeking code.
5046 token
= peek_token(&val
, NULL
, cfile
);
5047 if (token
== SEMI
) {
5048 skip_token(&val
, NULL
, cfile
);
5051 "corrupt lease file; "
5052 "expecting semicolon.");
5056 /* Lease valid lifetime. */
5058 token
= next_token(&val
, NULL
, cfile
);
5059 if (token
!= NUMBER
) {
5060 parse_warn(cfile
, "%s is not a valid "
5063 skip_to_semi(cfile
);
5069 * Currently we peek for the semi-colon to
5070 * allow processing of older lease files that
5071 * don't have the semi-colon. Eventually we
5072 * should remove the peeking code.
5074 token
= peek_token(&val
, NULL
, cfile
);
5075 if (token
== SEMI
) {
5076 skip_token(&val
, NULL
, cfile
);
5079 "corrupt lease file; "
5080 "expecting semicolon.");
5084 /* Prefix expiration time. */
5086 end_time
= parse_date(cfile
);
5089 /* Prefix binding scopes. */
5091 token
= next_token(&val
, NULL
, cfile
);
5092 if ((token
!= NAME
) &&
5093 (token
!= NUMBER_OR_NAME
)) {
5094 parse_warn(cfile
, "%s is not a valid "
5097 skip_to_semi(cfile
);
5102 bnd
= find_binding(scope
, val
);
5104 if (!binding_scope_allocate(&scope
,
5106 log_fatal("Out of memory for "
5115 bnd
= dmalloc(sizeof(*bnd
),
5118 log_fatal("No memory for "
5122 bnd
->name
= dmalloc(strlen(val
) + 1,
5124 if (bnd
->name
== NULL
) {
5125 log_fatal("No memory for "
5128 strcpy(bnd
->name
, val
);
5130 newbinding
= ISC_TRUE
;
5132 newbinding
= ISC_FALSE
;
5135 if (!binding_value_allocate(&nv
, MDL
)) {
5136 log_fatal("no memory for binding "
5140 token
= next_token(NULL
, NULL
, cfile
);
5141 if (token
!= EQUAL
) {
5142 parse_warn(cfile
, "expecting '=' in "
5147 if (!parse_binding_value(cfile
, nv
)) {
5149 binding_value_dereference(&nv
, MDL
);
5150 binding_scope_dereference(&scope
, MDL
);
5155 binding_value_reference(&bnd
->value
,
5157 bnd
->next
= scope
->bindings
;
5158 scope
->bindings
= bnd
;
5160 binding_value_dereference(&bnd
->value
,
5162 binding_value_reference(&bnd
->value
,
5166 binding_value_dereference(&nv
, MDL
);
5171 parse_warn(cfile
, "corrupt lease file; "
5172 "expecting ia_pd contents, "
5174 skip_to_semi(cfile
);
5179 if (state
== FTS_LAST
+1) {
5180 parse_warn(cfile
, "corrupt lease file; "
5181 "missing state in iaprefix");
5184 if (end_time
== -1) {
5185 parse_warn(cfile
, "corrupt lease file; "
5186 "missing end time in iaprefix");
5191 if (iasubopt_allocate(&iapref
, MDL
) != ISC_R_SUCCESS
) {
5192 log_fatal("Out of memory.");
5194 memcpy(&iapref
->addr
, iaddr
.iabuf
, sizeof(iapref
->addr
));
5195 iapref
->plen
= plen
;
5196 iapref
->state
= state
;
5197 iapref
->prefer
= prefer
;
5198 iapref
->valid
= valid
;
5199 if (iapref
->state
== FTS_RELEASED
)
5200 iapref
->hard_lifetime_end_time
= end_time
;
5202 if (scope
!= NULL
) {
5203 binding_scope_reference(&iapref
->scope
, scope
, MDL
);
5204 binding_scope_dereference(&scope
, MDL
);
5207 /* find the pool this address is in */
5209 if (find_ipv6_pool(&pool
, D6O_IA_PD
,
5210 &iapref
->addr
) != ISC_R_SUCCESS
) {
5211 inet_ntop(AF_INET6
, &iapref
->addr
,
5212 addr_buf
, sizeof(addr_buf
));
5213 parse_warn(cfile
, "no pool found for address %s",
5218 /* remove old information */
5219 if (cleanup_lease6(ia_pd_active
, pool
,
5220 iapref
, ia
) != ISC_R_SUCCESS
) {
5221 inet_ntop(AF_INET6
, &iapref
->addr
,
5222 addr_buf
, sizeof(addr_buf
));
5223 parse_warn(cfile
, "duplicate pd lease for address %s",
5228 * if we like the lease we add it to our various structues
5229 * otherwise we leave it and it will get cleaned when we
5230 * do the iasubopt_dereference.
5232 if ((state
== FTS_ACTIVE
) || (state
== FTS_ABANDONED
)) {
5233 ia_add_iasubopt(ia
, iapref
, MDL
);
5234 ia_reference(&iapref
->ia
, ia
, MDL
);
5235 add_lease6(pool
, iapref
, end_time
);
5238 ipv6_pool_dereference(&pool
, MDL
);
5239 iasubopt_dereference(&iapref
, MDL
);
5243 * If we have an existing record for this IA_PD, remove it.
5246 if (ia_hash_lookup(&old_ia
, ia_pd_active
,
5247 (unsigned char *)ia
->iaid_duid
.data
,
5248 ia
->iaid_duid
.len
, MDL
)) {
5249 ia_hash_delete(ia_pd_active
,
5250 (unsigned char *)ia
->iaid_duid
.data
,
5251 ia
->iaid_duid
.len
, MDL
);
5252 ia_dereference(&old_ia
, MDL
);
5256 * If we have prefixes, add this, otherwise don't bother.
5258 if (ia
->num_iasubopt
> 0) {
5259 ia_hash_add(ia_pd_active
,
5260 (unsigned char *)ia
->iaid_duid
.data
,
5261 ia
->iaid_duid
.len
, ia
, MDL
);
5263 ia_dereference(&ia
, MDL
);
5264 #endif /* defined(DHCPv6) */
5269 * When we parse a server-duid statement in a lease file, we are
5270 * looking at the saved server DUID from a previous run. In this case
5271 * we expect it to be followed by the binary representation of the
5272 * DUID stored in a string:
5274 * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
5277 parse_server_duid(struct parse
*cfile
) {
5278 enum dhcp_token token
;
5281 struct data_string duid
;
5283 token
= next_token(&val
, &len
, cfile
);
5284 if (token
!= STRING
) {
5285 parse_warn(cfile
, "corrupt lease file; expecting a DUID");
5286 skip_to_semi(cfile
);
5290 memset(&duid
, 0, sizeof(duid
));
5292 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
5293 log_fatal("Out of memory storing DUID");
5295 duid
.data
= (unsigned char *)duid
.buffer
->data
;
5296 memcpy(duid
.buffer
->data
, val
, len
);
5298 set_server_duid(&duid
);
5300 data_string_forget(&duid
, MDL
);
5302 token
= next_token(&val
, &len
, cfile
);
5303 if (token
!= SEMI
) {
5304 parse_warn(cfile
, "corrupt lease file; expecting a semicolon");
5305 skip_to_semi(cfile
);
5311 * When we parse a server-duid statement in a config file, we will
5312 * have the type of the server DUID to generate, and possibly the
5313 * actual value defined.
5316 * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
5318 * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
5319 * server-duid en 2495 "enterprise-specific-identifier-1234";
5322 parse_server_duid_conf(struct parse
*cfile
) {
5323 enum dhcp_token token
;
5326 u_int32_t enterprise_number
;
5328 struct data_string ll_addr
;
5330 struct data_string duid
;
5334 * Consume the SERVER_DUID token.
5336 skip_token(NULL
, NULL
, cfile
);
5339 * Obtain the DUID type.
5341 token
= next_token(&val
, NULL
, cfile
);
5344 * Enterprise is the easiest - enterprise number and raw data
5349 * Get enterprise number and identifier.
5351 token
= next_token(&val
, NULL
, cfile
);
5352 if (token
!= NUMBER
) {
5353 parse_warn(cfile
, "enterprise number expected");
5354 skip_to_semi(cfile
);
5357 enterprise_number
= atoi(val
);
5359 token
= next_token(&val
, &len
, cfile
);
5360 if (token
!= STRING
) {
5361 parse_warn(cfile
, "identifier expected");
5362 skip_to_semi(cfile
);
5369 memset(&duid
, 0, sizeof(duid
));
5370 duid
.len
= 2 + 4 + len
;
5371 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
5372 log_fatal("Out of memory storing DUID");
5374 duid
.data
= (unsigned char *)duid
.buffer
->data
;
5375 putUShort(duid
.buffer
->data
, DUID_EN
);
5376 putULong(duid
.buffer
->data
+ 2, enterprise_number
);
5377 memcpy(duid
.buffer
->data
+ 6, val
, len
);
5379 set_server_duid(&duid
);
5380 data_string_forget(&duid
, MDL
);
5384 * Next easiest is the link-layer DUID. It consists only of
5385 * the LL directive, or optionally the specific value to use.
5387 * If we have LL only, then we set the type. If we have the
5388 * value, then we set the actual DUID.
5390 else if (token
== LL
) {
5391 if (peek_token(NULL
, NULL
, cfile
) == SEMI
) {
5392 set_server_duid_type(DUID_LL
);
5395 * Get our hardware type and address.
5397 token
= next_token(NULL
, NULL
, cfile
);
5400 ll_type
= HTYPE_ETHER
;
5403 ll_type
= HTYPE_IEEE802
;
5406 ll_type
= HTYPE_FDDI
;
5409 parse_warn(cfile
, "hardware type expected");
5410 skip_to_semi(cfile
);
5413 memset(&ll_addr
, 0, sizeof(ll_addr
));
5414 if (!parse_cshl(&ll_addr
, cfile
)) {
5421 memset(&duid
, 0, sizeof(duid
));
5422 duid
.len
= 2 + 2 + ll_addr
.len
;
5423 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
5424 log_fatal("Out of memory storing DUID");
5426 duid
.data
= (unsigned char *)duid
.buffer
->data
;
5427 putUShort(duid
.buffer
->data
, DUID_LL
);
5428 putULong(duid
.buffer
->data
+ 2, ll_type
);
5429 memcpy(duid
.buffer
->data
+ 4,
5430 ll_addr
.data
, ll_addr
.len
);
5432 set_server_duid(&duid
);
5433 data_string_forget(&duid
, MDL
);
5434 data_string_forget(&ll_addr
, MDL
);
5439 * Finally the link-layer DUID plus time. It consists only of
5440 * the LLT directive, or optionally the specific value to use.
5442 * If we have LLT only, then we set the type. If we have the
5443 * value, then we set the actual DUID.
5445 else if (token
== LLT
) {
5446 if (peek_token(NULL
, NULL
, cfile
) == SEMI
) {
5447 set_server_duid_type(DUID_LLT
);
5450 * Get our hardware type, timestamp, and address.
5452 token
= next_token(NULL
, NULL
, cfile
);
5455 ll_type
= HTYPE_ETHER
;
5458 ll_type
= HTYPE_IEEE802
;
5461 ll_type
= HTYPE_FDDI
;
5464 parse_warn(cfile
, "hardware type expected");
5465 skip_to_semi(cfile
);
5469 token
= next_token(&val
, NULL
, cfile
);
5470 if (token
!= NUMBER
) {
5471 parse_warn(cfile
, "timestamp expected");
5472 skip_to_semi(cfile
);
5475 llt_time
= atoi(val
);
5477 memset(&ll_addr
, 0, sizeof(ll_addr
));
5478 if (!parse_cshl(&ll_addr
, cfile
)) {
5485 memset(&duid
, 0, sizeof(duid
));
5486 duid
.len
= 2 + 2 + 4 + ll_addr
.len
;
5487 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
5488 log_fatal("Out of memory storing DUID");
5490 duid
.data
= (unsigned char *)duid
.buffer
->data
;
5491 putUShort(duid
.buffer
->data
, DUID_LLT
);
5492 putULong(duid
.buffer
->data
+ 2, ll_type
);
5493 putULong(duid
.buffer
->data
+ 4, llt_time
);
5494 memcpy(duid
.buffer
->data
+ 8,
5495 ll_addr
.data
, ll_addr
.len
);
5497 set_server_duid(&duid
);
5498 data_string_forget(&duid
, MDL
);
5499 data_string_forget(&ll_addr
, MDL
);
5504 * If users want they can use a number for DUID types.
5505 * This is useful for supporting future, not-yet-defined
5508 * In this case, they have to put in the complete value.
5510 * This also works for existing DUID types of course.
5512 else if (token
== NUMBER
) {
5513 duid_type_num
= atoi(val
);
5515 token
= next_token(&val
, &len
, cfile
);
5516 if (token
!= STRING
) {
5517 parse_warn(cfile
, "identifier expected");
5518 skip_to_semi(cfile
);
5525 memset(&duid
, 0, sizeof(duid
));
5527 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
5528 log_fatal("Out of memory storing DUID");
5530 duid
.data
= (unsigned char *)duid
.buffer
->data
;
5531 putUShort(duid
.buffer
->data
, duid_type_num
);
5532 memcpy(duid
.buffer
->data
+ 2, val
, len
);
5534 set_server_duid(&duid
);
5535 data_string_forget(&duid
, MDL
);
5539 * Anything else is an error.
5542 parse_warn(cfile
, "DUID type of LLT, EN, or LL expected");
5543 skip_to_semi(cfile
);
5548 * Finally consume our trailing semicolon.
5550 token
= next_token(NULL
, NULL
, cfile
);
5551 if (token
!= SEMI
) {
5552 parse_warn(cfile
, "semicolon expected");
5553 skip_to_semi(cfile
);