3 Parser for dhcpd config file... */
6 * Copyright (c) 2004-2017 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/
29 /*! \file server/confpars.c */
33 static unsigned char global_host_once
= 1;
35 static int parse_binding_value(struct parse
*cfile
,
36 struct binding_value
*value
);
38 static void parse_authoring_byte_order (struct parse
*cfile
);
39 static void parse_lease_id_format (struct parse
*cfile
);
41 static int parse_iaid_duid(struct parse
*cfile
, struct ia_xx
** ia
,
42 u_int32_t
*iaid
, const char* file
, int line
);
46 trace_type_t
*trace_readconf_type
;
47 trace_type_t
*trace_readleases_type
;
49 void parse_trace_setup ()
51 trace_readconf_type
= trace_type_register ("readconf", (void *)0,
53 trace_conf_stop
, MDL
);
54 trace_readleases_type
= trace_type_register ("readleases", (void *)0,
56 trace_conf_stop
, MDL
);
60 /* conf-file :== parameters declarations END_OF_FILE
61 parameters :== <nil> | parameter | parameters parameter
62 declarations :== <nil> | declaration | declarations declaration */
64 isc_result_t
readconf ()
68 res
= read_conf_file (path_dhcpd_conf
, root_group
, ROOT_GROUP
, 0);
69 #if defined(LDAP_CONFIGURATION)
70 if (res
!= ISC_R_SUCCESS
)
73 return ldap_read_config ();
79 isc_result_t
read_conf_file (const char *filename
, struct group
*group
,
80 int group_type
, int leasep
)
93 ttype
= trace_readleases_type
;
95 ttype
= trace_readconf_type
;
97 /* If we're in playback, we need to snarf the contents of the
98 named file out of the playback file rather than trying to
100 if (trace_playback ()) {
103 status
= trace_get_file (ttype
, filename
, &tflen
, &dbuf
);
104 if (status
!= ISC_R_SUCCESS
)
108 /* What we get back is filename\0contents, where contents is
109 terminated just by the length. So we figure out the length
110 of the filename, and subtract that and the NUL from the
111 total length to get the length of the contents of the file.
112 We make fbuf a pointer to the contents of the file, and
113 leave dbuf as it is so we can free it later. */
114 tflen
= strlen (dbuf
);
115 ulen
= ulen
- tflen
- 1;
116 fbuf
= dbuf
+ tflen
+ 1;
121 if ((file
= open (filename
, O_RDONLY
)) < 0) {
123 log_error ("Can't open lease database %s: %m --",
125 log_error (" check for failed database %s!",
127 log_error ("Please read the dhcpd.leases manual%s",
129 log_fatal ("don't know what to do about this.");
131 log_fatal ("Can't open %s: %m", filename
);
135 cfile
= (struct parse
*)0;
136 #if defined (TRACING)
137 flen
= lseek (file
, (off_t
)0, SEEK_END
);
140 log_fatal ("Can't lseek on %s: %m", filename
);
142 if (lseek (file
, (off_t
)0, SEEK_SET
) < 0)
144 /* Can't handle files greater than 2^31-1. */
145 if (flen
> 0x7FFFFFFFUL
)
146 log_fatal ("%s: file is too long to buffer.", filename
);
149 /* Allocate a buffer that will be what's written to the tracefile,
150 and also will be what we parse from. */
151 tflen
= strlen (filename
);
152 dbuf
= dmalloc (ulen
+ tflen
+ 1, MDL
);
154 log_fatal ("No memory for %s (%d bytes)",
157 /* Copy the name into the beginning, nul-terminated. */
158 strcpy (dbuf
, filename
);
160 /* Load the file in after the NUL. */
161 fbuf
= dbuf
+ tflen
+ 1;
162 result
= read (file
, fbuf
, ulen
);
164 log_fatal ("Can't read in %s: %m", filename
);
166 log_fatal ("%s: short read of %d bytes instead of %d.",
167 filename
, ulen
, result
);
170 /* If we're recording, write out the filename and file contents. */
172 trace_write_packet (ttype
, ulen
+ tflen
+ 1, dbuf
, MDL
);
173 status
= new_parse(&cfile
, -1, fbuf
, ulen
, filename
, 0); /* XXX */
175 status
= new_parse(&cfile
, file
, NULL
, 0, filename
, 0);
177 if (status
!= ISC_R_SUCCESS
|| cfile
== NULL
)
181 status
= lease_file_subparse (cfile
);
183 status
= conf_file_subparse (cfile
, group
, group_type
);
185 #if defined (TRACING)
191 #if defined (TRACING)
192 void trace_conf_input (trace_type_t
*ttype
, unsigned len
, char *data
)
197 struct parse
*cfile
= (struct parse
*)0;
198 static int postconf_initialized
;
199 static int leaseconf_initialized
;
202 /* Do what's done above, except that we don't have to read in the
203 data, because it's already been read for us. */
204 tflen
= strlen (data
);
205 flen
= len
- tflen
- 1;
206 fbuf
= data
+ tflen
+ 1;
208 /* If we're recording, write out the filename and file contents. */
210 trace_write_packet (ttype
, len
, data
, MDL
);
212 status
= new_parse(&cfile
, -1, fbuf
, flen
, data
, 0);
213 if (status
== ISC_R_SUCCESS
|| cfile
!= NULL
) {
214 if (ttype
== trace_readleases_type
)
215 lease_file_subparse (cfile
);
217 conf_file_subparse (cfile
, root_group
, ROOT_GROUP
);
221 /* Postconfiguration needs to be done after the config file
223 if (!postconf_initialized
&& ttype
== trace_readconf_type
) {
224 postconf_initialization (0);
225 postconf_initialized
= 1;
228 if (!leaseconf_initialized
&& ttype
== trace_readleases_type
) {
230 leaseconf_initialized
= 1;
235 void trace_conf_stop (trace_type_t
*ttype
) { }
238 /* conf-file :== parameters declarations END_OF_FILE
239 parameters :== <nil> | parameter | parameters parameter
240 declarations :== <nil> | declaration | declarations declaration */
242 isc_result_t
conf_file_subparse (struct parse
*cfile
, struct group
*group
,
246 enum dhcp_token token
;
251 token
= peek_token (&val
, (unsigned *)0, cfile
);
252 if (token
== END_OF_FILE
)
254 declaration
= parse_statement (cfile
, group
, group_type
,
255 (struct host_decl
*)0,
258 skip_token(&val
, (unsigned *)0, cfile
);
260 status
= cfile
->warnings_occurred
? DHCP_R_BADPARSE
: ISC_R_SUCCESS
;
264 /* lease-file :== lease-declarations END_OF_FILE
265 lease-statements :== <nil>
267 | lease-declarations lease-declaration */
269 isc_result_t
lease_file_subparse (struct parse
*cfile
)
272 enum dhcp_token token
;
276 token
= next_token (&val
, (unsigned *)0, cfile
);
277 if (token
== END_OF_FILE
)
279 if (token
== LEASE
) {
280 struct lease
*lease
= (struct lease
*)0;
281 if (parse_lease_declaration (&lease
, cfile
)) {
283 lease_dereference (&lease
, MDL
);
286 "possibly corrupt lease file");
287 } else if (token
== IA_NA
) {
288 parse_ia_na_declaration(cfile
);
289 } else if (token
== IA_TA
) {
290 parse_ia_ta_declaration(cfile
);
291 } else if (token
== IA_PD
) {
292 parse_ia_pd_declaration(cfile
);
293 } else if (token
== CLASS
) {
294 parse_class_declaration(0, cfile
, root_group
,
296 } else if (token
== SUBCLASS
) {
297 parse_class_declaration(0, cfile
, root_group
,
298 CLASS_TYPE_SUBCLASS
);
299 } else if (token
== HOST
) {
300 parse_host_declaration (cfile
, root_group
);
301 } else if (token
== GROUP
) {
302 parse_group_declaration (cfile
, root_group
);
303 #if defined (FAILOVER_PROTOCOL)
304 } else if (token
== FAILOVER
) {
305 parse_failover_state_declaration
306 (cfile
, (dhcp_failover_state_t
*)0);
309 } else if (token
== SERVER_DUID
) {
310 parse_server_duid(cfile
);
312 } else if (token
== AUTHORING_BYTE_ORDER
) {
313 parse_authoring_byte_order(cfile
);
315 log_error ("Corrupt lease file - possible data loss!");
316 skip_to_semi (cfile
);
321 status
= cfile
->warnings_occurred
? DHCP_R_BADPARSE
: ISC_R_SUCCESS
;
325 /* statement :== parameter | declaration
327 parameter :== DEFAULT_LEASE_TIME lease_time
328 | MAX_LEASE_TIME lease_time
329 | DYNAMIC_BOOTP_LEASE_CUTOFF date
330 | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
331 | BOOT_UNKNOWN_CLIENTS boolean
332 | ONE_LEASE_PER_CLIENT boolean
333 | GET_LEASE_HOSTNAMES boolean
334 | USE_HOST_DECL_NAME boolean
335 | NEXT_SERVER ip-addr-or-hostname SEMI
337 | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
338 | FILENAME string-parameter
339 | SERVER_NAME string-parameter
341 | fixed-address-parameter
342 | ALLOW allow-deny-keyword
343 | DENY allow-deny-keyword
344 | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
348 declaration :== host-declaration
350 | shared-network-declaration
352 | VENDOR_CLASS class-declaration
353 | USER_CLASS class-declaration
354 | RANGE address-range-declaration */
356 int parse_statement (cfile
, group
, type
, host_decl
, declaration
)
360 struct host_decl
*host_decl
;
363 enum dhcp_token token
;
365 struct shared_network
*share
;
367 struct hardware hardware
;
368 struct executable_statement
*et
, *ep
;
369 struct option
*option
= NULL
;
370 struct option_cache
*cache
;
376 token
= peek_token (&val
, (unsigned *)0, cfile
);
380 skip_token(&val
, (unsigned *)0, cfile
);
381 token
= next_token (&val
, (unsigned *)0, cfile
);
382 if (token
!= STRING
) {
383 parse_warn (cfile
, "filename string expected.");
384 skip_to_semi (cfile
);
386 status
= read_conf_file (val
, group
, type
, 0);
387 if (status
!= ISC_R_SUCCESS
)
388 parse_warn (cfile
, "%s: bad parse.", val
);
394 skip_token(&val
, (unsigned *)0, cfile
);
395 if (type
!= HOST_DECL
&& type
!= CLASS_DECL
) {
396 if (global_host_once
&&
397 (type
== SUBNET_DECL
|| type
== SHARED_NET_DECL
)) {
398 global_host_once
= 0;
399 log_error("WARNING: Host declarations are "
400 "global. They are not limited to "
401 "the scope you declared them in.");
404 parse_host_declaration (cfile
, group
);
407 "host declarations not allowed here.");
408 skip_to_semi (cfile
);
413 skip_token(&val
, (unsigned *)0, cfile
);
414 if (type
!= HOST_DECL
&& type
!= CLASS_DECL
)
415 parse_group_declaration (cfile
, group
);
418 "group declarations not allowed here.");
419 skip_to_semi (cfile
);
424 skip_token(&val
, (unsigned *)0, cfile
);
425 if (type
== SHARED_NET_DECL
||
427 type
== SUBNET_DECL
||
428 type
== CLASS_DECL
) {
429 parse_warn (cfile
, "shared-network parameters not %s.",
431 skip_to_semi (cfile
);
435 parse_shared_net_declaration (cfile
, group
);
440 skip_token(&val
, (unsigned *)0, cfile
);
441 if (type
== HOST_DECL
|| type
== SUBNET_DECL
||
442 type
== CLASS_DECL
) {
444 "subnet declarations not allowed here.");
445 skip_to_semi (cfile
);
449 /* If we're in a subnet declaration, just do the parse. */
450 if (group
->shared_network
!= NULL
) {
451 if (token
== SUBNET
) {
452 parse_subnet_declaration(cfile
,
453 group
->shared_network
);
455 parse_subnet6_declaration(cfile
,
456 group
->shared_network
);
462 * Otherwise, cons up a fake shared network structure
463 * and populate it with the lone subnet...because the
464 * intention most likely is to refer to the entire link
465 * by shorthand, any configuration inside the subnet is
466 * actually placed in the shared-network's group.
470 status
= shared_network_allocate (&share
, MDL
);
471 if (status
!= ISC_R_SUCCESS
)
472 log_fatal ("Can't allocate shared subnet: %s",
473 isc_result_totext (status
));
474 if (!clone_group (&share
-> group
, group
, MDL
))
475 log_fatal ("Can't allocate group for shared net");
476 shared_network_reference (&share
-> group
-> shared_network
,
480 * This is an implicit shared network, not explicit in
483 share
->flags
|= SHARED_IMPLICIT
;
485 if (token
== SUBNET
) {
486 parse_subnet_declaration(cfile
, share
);
488 parse_subnet6_declaration(cfile
, share
);
491 /* share -> subnets is the subnet we just parsed. */
492 if (share
->subnets
) {
493 interface_reference(&share
->interface
,
494 share
->subnets
->interface
,
497 /* Make the shared network name from network number. */
498 if (token
== SUBNET
) {
499 n
= piaddrmask(&share
->subnets
->net
,
500 &share
->subnets
->netmask
);
502 n
= piaddrcidr(&share
->subnets
->net
,
503 share
->subnets
->prefix_len
);
506 share
->name
= strdup(n
);
508 if (share
->name
== NULL
)
509 log_fatal("Out of memory allocating default "
510 "shared network name (\"%s\").", n
);
512 /* Copy the authoritative parameter from the subnet,
513 since there is no opportunity to declare it here. */
514 share
->group
->authoritative
=
515 share
->subnets
->group
->authoritative
;
516 enter_shared_network(share
);
518 shared_network_dereference(&share
, MDL
);
522 skip_token(&val
, (unsigned *)0, cfile
);
523 if (type
== CLASS_DECL
) {
525 "class declarations not allowed here.");
526 skip_to_semi (cfile
);
529 parse_class_declaration(NULL
, cfile
, group
, CLASS_TYPE_VENDOR
);
533 skip_token(&val
, (unsigned *)0, cfile
);
534 if (type
== CLASS_DECL
) {
536 "class declarations not allowed here.");
537 skip_to_semi (cfile
);
540 parse_class_declaration(NULL
, cfile
, group
, CLASS_TYPE_USER
);
544 skip_token(&val
, (unsigned *)0, cfile
);
545 if (type
== CLASS_DECL
) {
547 "class declarations not allowed here.");
548 skip_to_semi (cfile
);
551 parse_class_declaration(NULL
, cfile
, group
, CLASS_TYPE_CLASS
);
555 skip_token(&val
, (unsigned *)0, cfile
);
556 if (type
== CLASS_DECL
) {
558 "class declarations not allowed here.");
559 skip_to_semi (cfile
);
562 parse_class_declaration(NULL
, cfile
, group
,
563 CLASS_TYPE_SUBCLASS
);
567 skip_token(&val
, (unsigned *)0, cfile
);
568 memset (&hardware
, 0, sizeof hardware
);
569 if (host_decl
&& memcmp(&hardware
, &(host_decl
->interface
),
570 sizeof(hardware
)) != 0) {
571 parse_warn(cfile
, "Host %s hardware address already "
572 "configured.", host_decl
->name
);
576 parse_hardware_param (cfile
, &hardware
);
578 host_decl
-> interface
= hardware
;
580 parse_warn (cfile
, "hardware address parameter %s",
581 "not allowed here.");
586 skip_token(&val
, NULL
, cfile
);
588 if (parse_fixed_addr_param(&cache
, cfile
, token
)) {
590 if (host_decl
->fixed_addr
) {
591 option_cache_dereference(&cache
, MDL
);
593 "Only one fixed address "
594 "declaration per host.");
596 host_decl
->fixed_addr
= cache
;
600 "fixed-address parameter not "
602 option_cache_dereference(&cache
, MDL
);
608 skip_token(&val
, (unsigned *)0, cfile
);
609 if (type
== POOL_DECL
) {
610 parse_warn (cfile
, "pool declared within pool.");
612 } else if (type
!= SUBNET_DECL
&& type
!= SHARED_NET_DECL
) {
613 parse_warn (cfile
, "pool declared outside of network");
616 parse_pool_statement (cfile
, group
, type
);
621 skip_token(&val
, (unsigned *)0, cfile
);
622 if (type
!= SUBNET_DECL
|| !group
-> subnet
) {
624 "range declaration not allowed here.");
625 skip_to_semi (cfile
);
628 parse_address_range (cfile
, group
, type
, (struct pool
*)0,
634 skip_token(NULL
, NULL
, cfile
);
635 if ((type
!= SUBNET_DECL
) || (group
->subnet
== NULL
)) {
637 "range6 declaration not allowed here.");
641 parse_address_range6(cfile
, group
, NULL
);
645 skip_token(NULL
, NULL
, cfile
);
646 if ((type
!= SUBNET_DECL
) || (group
->subnet
== NULL
)) {
648 "prefix6 declaration not allowed here.");
652 parse_prefix6(cfile
, group
, NULL
);
656 skip_token(&val
, NULL
, cfile
);
659 "fixed-prefix6 declaration not "
664 parse_fixed_prefix6(cfile
, host_decl
);
668 skip_token(&val
, NULL
, cfile
);
669 if (type
== POOL_DECL
) {
670 parse_warn (cfile
, "pool6 declared within pool.");
672 } else if (type
!= SUBNET_DECL
) {
673 parse_warn (cfile
, "pool6 declared outside of network");
676 parse_pool6_statement (cfile
, group
, type
);
683 skip_token(&val
, (unsigned *)0, cfile
);
684 token
= next_token (&val
, (unsigned *)0, cfile
);
687 group
-> authoritative
= 0;
690 parse_warn (cfile
, "expecting assertion");
691 skip_to_semi (cfile
);
696 skip_token(&val
, (unsigned *)0, cfile
);
697 group
-> authoritative
= 1;
699 if (type
== HOST_DECL
)
700 parse_warn (cfile
, "authority makes no sense here.");
704 /* "server-identifier" is a special hack, equivalent to
705 "option dhcp-server-identifier". */
706 case SERVER_IDENTIFIER
:
707 code
= DHO_DHCP_SERVER_IDENTIFIER
;
708 if (!option_code_hash_lookup(&option
, dhcp_universe
.code_hash
,
710 log_fatal("Server identifier not in hash (%s:%d).",
712 skip_token(&val
, (unsigned *)0, cfile
);
716 skip_token(&val
, (unsigned *)0, cfile
);
717 token
= peek_token (&val
, (unsigned *)0, cfile
);
718 if (token
== SPACE
) {
719 if (type
!= ROOT_GROUP
) {
721 "option space definitions %s",
722 "may not be scoped.");
723 skip_to_semi (cfile
);
726 parse_option_space_decl (cfile
);
731 status
= parse_option_name(cfile
, 1, &known
, &option
);
732 if (status
== ISC_R_SUCCESS
) {
733 token
= peek_token (&val
, (unsigned *)0, cfile
);
735 if (type
!= ROOT_GROUP
) {
737 "option definitions%s",
738 " may not be scoped.");
739 skip_to_semi (cfile
);
740 option_dereference(&option
, MDL
);
743 skip_token(&val
, (unsigned *)0, cfile
);
746 * If the option was known, remove it from the
747 * code and name hashes before redefining it.
750 option_name_hash_delete(
751 option
->universe
->name_hash
,
752 option
->name
, 0, MDL
);
753 option_code_hash_delete(
754 option
->universe
->code_hash
,
755 &option
->code
, 0, MDL
);
758 parse_option_code_definition(cfile
, option
);
759 option_dereference(&option
, MDL
);
763 /* If this wasn't an option code definition, don't
764 allow an unknown option. */
766 parse_warn (cfile
, "unknown option %s.%s",
767 option
-> universe
-> name
,
769 skip_to_semi (cfile
);
770 option_dereference(&option
, MDL
);
775 et
= (struct executable_statement
*)0;
776 if (!parse_option_statement
777 (&et
, cfile
, 1, option
,
778 supersede_option_statement
))
780 option_dereference(&option
, MDL
);
781 goto insert_statement
;
788 if (type
!= ROOT_GROUP
&& type
!= SHARED_NET_DECL
) {
789 parse_warn (cfile
, "failover peers may only be %s",
790 "defined in shared-network");
791 log_error ("declarations and the outer scope.");
792 skip_to_semi (cfile
);
795 token
= next_token (&val
, (unsigned *)0, cfile
);
796 #if defined (FAILOVER_PROTOCOL)
797 parse_failover_peer (cfile
, group
, type
);
799 parse_warn (cfile
, "No failover support.");
800 skip_to_semi (cfile
);
806 parse_server_duid_conf(cfile
);
810 case LEASE_ID_FORMAT
:
811 token
= next_token (&val
, (unsigned *)0, cfile
);
812 parse_lease_id_format(cfile
);
816 et
= (struct executable_statement
*)0;
818 if (!parse_executable_statement (&et
, cfile
, &lose
,
823 "expecting a declaration");
826 "expecting a parameter %s",
828 skip_to_semi (cfile
);
835 if (group
-> statements
) {
838 /* If this set of statements is only referenced
839 by this group, just add the current statement
840 to the end of the chain. */
841 for (ep
= group
-> statements
; ep
-> next
;
843 if (ep
-> refcnt
> 1) /* XXX */
846 executable_statement_reference (&ep
-> next
,
848 executable_statement_dereference (&et
, MDL
);
852 /* Otherwise, make a parent chain, and put the
853 current group statements first and the new
854 statement in the next pointer. */
855 ep
= (struct executable_statement
*)0;
856 if (!executable_statement_allocate (&ep
, MDL
))
857 log_fatal ("No memory for statements.");
858 ep
-> op
= statements_statement
;
859 executable_statement_reference (&ep
-> data
.statements
,
862 executable_statement_reference (&ep
-> next
, et
, MDL
);
863 executable_statement_dereference (&group
-> statements
,
865 executable_statement_reference (&group
-> statements
,
867 executable_statement_dereference (&ep
, MDL
);
869 executable_statement_reference (&group
-> statements
,
872 executable_statement_dereference (&et
, MDL
);
879 #if defined (FAILOVER_PROTOCOL)
880 void parse_failover_peer (cfile
, group
, type
)
885 enum dhcp_token token
;
887 dhcp_failover_state_t
*peer
;
892 unsigned hba_len
= sizeof hba
;
894 struct expression
*expr
;
896 dhcp_failover_config_t
*cp
;
898 token
= next_token (&val
, (unsigned *)0, cfile
);
900 parse_warn (cfile
, "expecting \"peer\"");
901 skip_to_semi (cfile
);
905 token
= next_token (&val
, (unsigned *)0, cfile
);
906 if (is_identifier (token
) || token
== STRING
) {
907 name
= dmalloc (strlen (val
) + 1, MDL
);
909 log_fatal ("no memory for peer name %s", name
);
912 parse_warn (cfile
, "expecting failover peer name.");
913 skip_to_semi (cfile
);
917 /* See if there's a peer declaration by this name. */
918 peer
= (dhcp_failover_state_t
*)0;
919 find_failover_peer (&peer
, name
, MDL
);
921 token
= next_token (&val
, (unsigned *)0, cfile
);
923 if (type
!= SHARED_NET_DECL
)
924 parse_warn (cfile
, "failover peer reference not %s",
925 "in shared-network declaration");
928 parse_warn (cfile
, "reference to unknown%s%s",
929 " failover peer ", name
);
933 dhcp_failover_state_reference
934 (&group
-> shared_network
-> failover_peer
,
937 dhcp_failover_state_dereference (&peer
, MDL
);
940 } else if (token
== STATE
) {
942 parse_warn (cfile
, "state declaration for unknown%s%s",
943 " failover peer ", name
);
947 parse_failover_state_declaration (cfile
, peer
);
948 dhcp_failover_state_dereference (&peer
, MDL
);
951 } else if (token
!= LBRACE
) {
952 parse_warn (cfile
, "expecting left brace");
953 skip_to_semi (cfile
);
956 /* Make sure this isn't a redeclaration. */
958 parse_warn (cfile
, "redeclaration of failover peer %s", name
);
959 skip_to_rbrace (cfile
, 1);
960 dhcp_failover_state_dereference (&peer
, MDL
);
965 status
= dhcp_failover_state_allocate (&peer
, MDL
);
966 if (status
!= ISC_R_SUCCESS
)
967 log_fatal ("Can't allocate failover peer %s: %s",
968 name
, isc_result_totext (status
));
976 token
= next_token (&val
, (unsigned *)0, cfile
);
982 peer
-> i_am
= primary
;
986 peer
-> i_am
= secondary
;
989 "secondary may not define %s",
990 "load balance settings.");
994 cp
= &peer
-> partner
;
998 expr
= (struct expression
*)0;
999 if (!parse_ip_addr_or_hostname (&expr
, cfile
, 0)) {
1000 skip_to_rbrace (cfile
, 1);
1001 dhcp_failover_state_dereference (&peer
, MDL
);
1004 option_cache (&cp
-> address
,
1005 (struct data_string
*)0, expr
,
1006 (struct option
*)0, MDL
);
1007 expression_dereference (&expr
, MDL
);
1011 token
= next_token (&val
, (unsigned *)0, cfile
);
1012 if (token
!= NUMBER
) {
1013 parse_warn (cfile
, "expecting number");
1014 skip_to_rbrace (cfile
, 1);
1016 cp
-> port
= atoi (val
);
1019 case MAX_LEASE_MISBALANCE
:
1020 tp
= &peer
->max_lease_misbalance
;
1023 case MAX_LEASE_OWNERSHIP
:
1024 tp
= &peer
->max_lease_ownership
;
1028 tp
= &peer
->max_balance
;
1032 tp
= &peer
->min_balance
;
1035 case AUTO_PARTNER_DOWN
:
1036 tp
= &peer
->auto_partner_down
;
1039 case MAX_RESPONSE_DELAY
:
1040 tp
= &cp
-> max_response_delay
;
1042 token
= next_token (&val
, (unsigned *)0, cfile
);
1043 if (token
!= NUMBER
) {
1044 parse_warn (cfile
, "expecting number.");
1045 skip_to_rbrace (cfile
, 1);
1046 dhcp_failover_state_dereference (&peer
, MDL
);
1052 case MAX_UNACKED_UPDATES
:
1053 tp
= &cp
-> max_flying_updates
;
1062 if (peer
-> i_am
== secondary
)
1064 "secondary may not define %s",
1065 "load balance settings.");
1066 if (!parse_numeric_aggregate (cfile
, hba
, &hba_len
,
1068 skip_to_rbrace (cfile
, 1);
1069 dhcp_failover_state_dereference (&peer
, MDL
);
1072 if (hba_len
!= 32) {
1074 "HBA must be exactly 32 bytes.");
1078 peer
-> hba
= dmalloc (32, MDL
);
1080 dfree (peer
-> name
, MDL
);
1083 memcpy (peer
-> hba
, hba
, 32);
1087 token
= next_token (&val
, (unsigned *)0, cfile
);
1088 if (peer
-> i_am
== secondary
)
1090 "secondary may not define %s",
1091 "load balance settings.");
1092 if (token
!= NUMBER
) {
1093 parse_warn (cfile
, "expecting number");
1094 skip_to_rbrace (cfile
, 1);
1095 dhcp_failover_state_dereference (&peer
, MDL
);
1100 parse_warn (cfile
, "split must be between "
1101 "0 and 256, inclusive");
1103 memset (hba
, 0, sizeof hba
);
1104 for (i
= 0; i
< split
; i
++) {
1106 hba
[i
/ 8] |= (1 << (i
& 7));
1113 token
= next_token (&val
, (unsigned *)0, cfile
);
1114 if (token
!= BALANCE
) {
1115 parse_warn (cfile
, "expecting 'balance'");
1117 skip_to_rbrace (cfile
, 1);
1120 token
= next_token (&val
, (unsigned *)0, cfile
);
1121 if (token
!= TOKEN_MAX
) {
1122 parse_warn (cfile
, "expecting 'max'");
1125 token
= next_token (&val
, (unsigned *)0, cfile
);
1126 if (token
!= SECONDS
) {
1127 parse_warn (cfile
, "expecting 'secs'");
1130 token
= next_token (&val
, (unsigned *)0, cfile
);
1131 if (token
!= NUMBER
) {
1132 parse_warn (cfile
, "expecting number");
1135 peer
-> load_balance_max_secs
= atoi (val
);
1140 "invalid statement in peer declaration");
1141 skip_to_rbrace (cfile
, 1);
1142 dhcp_failover_state_dereference (&peer
, MDL
);
1145 if (token
!= RBRACE
&& !parse_semi (cfile
)) {
1146 skip_to_rbrace (cfile
, 1);
1147 dhcp_failover_state_dereference (&peer
, MDL
);
1150 } while (token
!= RBRACE
);
1152 /* me.address can be null; the failover link initiate code tries to
1153 * derive a reasonable address to use.
1155 if (!peer
-> partner
.address
)
1156 parse_warn (cfile
, "peer address may not be omitted");
1159 peer
->me
.port
= DEFAULT_FAILOVER_PORT
;
1160 if (!peer
->partner
.port
)
1161 peer
->partner
.port
= DEFAULT_FAILOVER_PORT
;
1163 if (peer
-> i_am
== primary
) {
1166 "primary failover server must have hba or split.");
1167 } else if (!peer
-> mclt
) {
1169 "primary failover server must have mclt.");
1173 if (!peer
->max_lease_misbalance
)
1174 peer
->max_lease_misbalance
= DEFAULT_MAX_LEASE_MISBALANCE
;
1175 if (!peer
->max_lease_ownership
)
1176 peer
->max_lease_ownership
= DEFAULT_MAX_LEASE_OWNERSHIP
;
1177 if (!peer
->max_balance
)
1178 peer
->max_balance
= DEFAULT_MAX_BALANCE_TIME
;
1179 if (!peer
->min_balance
)
1180 peer
->min_balance
= DEFAULT_MIN_BALANCE_TIME
;
1181 if (!peer
->me
.max_flying_updates
)
1182 peer
->me
.max_flying_updates
= DEFAULT_MAX_FLYING_UPDATES
;
1183 if (!peer
->me
.max_response_delay
)
1184 peer
->me
.max_response_delay
= DEFAULT_MAX_RESPONSE_DELAY
;
1186 if (type
== SHARED_NET_DECL
)
1187 group
->shared_network
->failover_peer
= peer
;
1189 /* Set the initial state. */
1190 peer
->me
.state
= recover
;
1191 peer
->me
.stos
= cur_time
;
1192 peer
->partner
.state
= unknown_state
;
1193 peer
->partner
.stos
= cur_time
;
1195 status
= enter_failover_peer (peer
);
1196 if (status
!= ISC_R_SUCCESS
)
1197 parse_warn (cfile
, "failover peer %s: %s",
1198 peer
-> name
, isc_result_totext (status
));
1199 dhcp_failover_state_dereference (&peer
, MDL
);
1202 void parse_failover_state_declaration (struct parse
*cfile
,
1203 dhcp_failover_state_t
*peer
)
1205 enum dhcp_token token
;
1208 dhcp_failover_state_t
*state
;
1209 dhcp_failover_config_t
*cp
;
1212 token
= next_token (&val
, (unsigned *)0, cfile
);
1213 if (token
!= PEER
) {
1214 parse_warn (cfile
, "expecting \"peer\"");
1215 skip_to_semi (cfile
);
1219 token
= next_token (&val
, (unsigned *)0, cfile
);
1220 if (is_identifier (token
) || token
== STRING
) {
1221 name
= dmalloc (strlen (val
) + 1, MDL
);
1223 log_fatal ("failover peer name %s: no memory",
1227 parse_warn (cfile
, "expecting failover peer name.");
1228 skip_to_semi (cfile
);
1232 /* See if there's a peer declaration by this name. */
1233 state
= (dhcp_failover_state_t
*)0;
1234 find_failover_peer (&state
, name
, MDL
);
1236 parse_warn (cfile
, "unknown failover peer: %s", name
);
1237 skip_to_semi (cfile
);
1241 token
= next_token (&val
, (unsigned *)0, cfile
);
1242 if (token
!= STATE
) {
1243 parse_warn (cfile
, "expecting 'state'");
1245 skip_to_semi (cfile
);
1249 state
= (dhcp_failover_state_t
*)0;
1250 dhcp_failover_state_reference (&state
, peer
, MDL
);
1252 token
= next_token (&val
, (unsigned *)0, cfile
);
1253 if (token
!= LBRACE
) {
1254 parse_warn (cfile
, "expecting left brace");
1256 skip_to_semi (cfile
);
1257 dhcp_failover_state_dereference (&state
, MDL
);
1261 token
= next_token (&val
, (unsigned *)0, cfile
);
1268 token
= next_token (&val
, (unsigned *)0, cfile
);
1269 if (token
!= STATE
) {
1270 parse_warn (cfile
, "expecting 'state'");
1273 parse_failover_state (cfile
,
1274 &cp
-> state
, &cp
-> stos
);
1278 cp
= &state
-> partner
;
1282 if (state
-> i_am
== primary
) {
1284 "mclt not valid for primary");
1287 token
= next_token (&val
, (unsigned *)0, cfile
);
1288 if (token
!= NUMBER
) {
1289 parse_warn (cfile
, "expecting a number.");
1292 state
-> mclt
= atoi (val
);
1297 parse_warn (cfile
, "expecting state setting.");
1299 skip_to_rbrace (cfile
, 1);
1300 dhcp_failover_state_dereference (&state
, MDL
);
1303 } while (token
!= RBRACE
);
1304 dhcp_failover_state_dereference (&state
, MDL
);
1307 void parse_failover_state (cfile
, state
, stos
)
1308 struct parse
*cfile
;
1309 enum failover_state
*state
;
1312 enum dhcp_token token
;
1314 enum failover_state state_in
;
1317 token
= next_token (&val
, (unsigned *)0, cfile
);
1320 state_in
= unknown_state
;
1324 state_in
= partner_down
;
1331 case COMMUNICATIONS_INTERRUPTED
:
1332 state_in
= communications_interrupted
;
1336 state_in
= conflict_done
;
1339 case RESOLUTION_INTERRUPTED
:
1340 state_in
= resolution_interrupted
;
1343 case POTENTIAL_CONFLICT
:
1344 state_in
= potential_conflict
;
1352 state_in
= recover_wait
;
1356 state_in
= recover_done
;
1360 state_in
= shut_down
;
1372 parse_warn (cfile
, "unknown failover state");
1373 skip_to_semi (cfile
);
1377 token
= next_token (&val
, (unsigned *)0, cfile
);
1378 if (token
== SEMI
) {
1382 parse_warn (cfile
, "expecting \"at\"");
1383 skip_to_semi (cfile
);
1387 stos_in
= parse_date (cfile
);
1392 /* Now that we've apparently gotten a clean parse, we
1393 can trust that this is a state that was fully committed to
1394 disk, so we can install it. */
1398 #endif /* defined (FAILOVER_PROTOCOL) */
1401 * \brief Parses an authoring-byte-order statement
1403 * A valid statement looks like this:
1405 * authoring-byte-order :==
1406 * PARSE_BYTE_ORDER TOKEN_LITTLE_ENDIAN | TOKEN_BIG_ENDIAN ;
1408 * If the global, authoring_byte_order is not zero, then either the statement
1409 * has already been parsed or the function, parse_byte_order_uint32, has
1410 * been called which set it to the default. In either case, this is invalid
1411 * so we'll log it and bail.
1413 * If the value is different from the current server's byte order, then we'll
1414 * log that fact and set authoring_byte_order to given value. This causes all
1415 * invocations of the function, parse_byte_order_uint32, to perform byte-order
1416 * conversion before returning the value.
1418 * \param cfile the current parse file
1421 void parse_authoring_byte_order (struct parse
*cfile
)
1423 enum dhcp_token token
;
1427 /* Either we've seen it already or it's after the first lease */
1428 if (authoring_byte_order
!= 0) {
1430 "authoring-byte-order specified too late.\n"
1431 "It must occur before the first lease in file\n");
1432 skip_to_semi (cfile
);
1436 token
= next_token(&val
, (unsigned *)0, cfile
);
1438 case TOKEN_LITTLE_ENDIAN
:
1439 authoring_byte_order
= LITTLE_ENDIAN
;
1441 case TOKEN_BIG_ENDIAN
:
1442 authoring_byte_order
= BIG_ENDIAN
;
1445 parse_warn(cfile
, "authoring-byte-order is invalid: "
1446 " it must be big-endian or little-endian.");
1447 skip_to_semi(cfile
);
1451 if (authoring_byte_order
!= DHCP_BYTE_ORDER
) {
1452 log_error ("WARNING: Lease file authored using different"
1453 " byte order, will attempt to convert");
1456 token
= next_token(&val
, &len
, cfile
);
1457 if (token
!= SEMI
) {
1458 parse_warn(cfile
, "corrupt lease file; expecting a semicolon");
1459 skip_to_semi(cfile
);
1465 * \brief Parses a lease-id-format statement
1467 * A valid statement looks like this:
1469 * lease-id-format :==
1470 * LEASE_ID_FORMAT TOKEN_OCTAL | TOKEN_HEX ;
1472 * This function is used to parse the lease-id-format statement. It sets the
1473 * global variable, lease_id_format.
1475 * \param cfile the current parse file
1478 void parse_lease_id_format (struct parse
*cfile
)
1480 enum dhcp_token token
;
1484 token
= next_token(&val
, NULL
, cfile
);
1487 lease_id_format
= TOKEN_OCTAL
;
1490 lease_id_format
= TOKEN_HEX
;
1493 parse_warn(cfile
, "lease-id-format is invalid: "
1494 " it must be octal or hex.");
1495 skip_to_semi(cfile
);
1499 log_debug("lease_id_format is: %s",
1500 lease_id_format
== TOKEN_OCTAL
? "octal" : "hex");
1502 token
= next_token(&val
, &len
, cfile
);
1503 if (token
!= SEMI
) {
1504 parse_warn(cfile
, "corrupt lease file; expecting a semicolon");
1505 skip_to_semi(cfile
);
1512 * \brief Parse allow and deny statements
1514 * This function handles the common processing code for permit and deny
1515 * statements in the parse_pool_statement and parse_pool6_statement functions.
1516 * It reads in the configuration and constructs a new permit structure that it
1517 * attachs to the permit_head passed in from the caller.
1519 * The allow or deny token should already be consumed, this function expects
1520 * one of the following:
1525 * authenticated clients;
1526 * unauthenticated clients;
1528 * dynamic bootp clients;
1529 * members of <class name>;
1532 * \param[in] cfile = the configuration file being parsed
1533 * \param[in] permit_head = the head of the permit list (permit or prohibit)
1534 * to which to attach the newly created permit structure
1535 * \param[in] is_allow = 1 if this is being invoked for an allow statement
1536 * = 0 if this is being invoked for a deny statement
1537 * \param[in] valid_from = pointers to the time values from the enclosing pool
1538 * \param[in] valid_until or pond structure. One of them will be filled in if
1539 * the configuration includes an "after" clause
1542 void get_permit(cfile
, permit_head
, is_allow
, valid_from
, valid_until
)
1543 struct parse
*cfile
;
1544 struct permit
**permit_head
;
1546 TIME
*valid_from
, *valid_until
;
1548 enum dhcp_token token
;
1549 struct permit
*permit
;
1551 int need_clients
= 1;
1554 /* Create our permit structure */
1555 permit
= new_permit(MDL
);
1557 log_fatal ("no memory for permit");
1559 token
= next_token(&val
, NULL
, cfile
);
1562 permit
->type
= permit_unknown_clients
;
1567 permit
->type
= permit_known_clients
;
1570 case UNKNOWN_CLIENTS
:
1572 permit
->type
= permit_unknown_clients
;
1576 permit
->type
= permit_known_clients
;
1580 permit
->type
= permit_authenticated_clients
;
1583 case UNAUTHENTICATED
:
1584 permit
->type
= permit_unauthenticated_clients
;
1588 permit
->type
= permit_all_clients
;
1592 permit
->type
= permit_dynamic_bootp_clients
;
1593 if (next_token (&val
, NULL
, cfile
) != TOKEN_BOOTP
) {
1594 parse_warn (cfile
, "expecting \"bootp\"");
1595 skip_to_semi (cfile
);
1596 free_permit (permit
, MDL
);
1603 if (next_token (&val
, NULL
, cfile
) != OF
) {
1604 parse_warn (cfile
, "expecting \"of\"");
1605 skip_to_semi (cfile
);
1606 free_permit (permit
, MDL
);
1609 if (next_token (&val
, NULL
, cfile
) != STRING
) {
1610 parse_warn (cfile
, "expecting class name.");
1611 skip_to_semi (cfile
);
1612 free_permit (permit
, MDL
);
1615 permit
->type
= permit_class
;
1616 permit
->class = NULL
;
1617 find_class(&permit
->class, val
, MDL
);
1619 parse_warn(cfile
, "no such class: %s", val
);
1624 if (*valid_from
|| *valid_until
) {
1625 parse_warn(cfile
, "duplicate \"after\" clause.");
1626 skip_to_semi(cfile
);
1627 free_permit(permit
, MDL
);
1630 t
= parse_date_core(cfile
);
1631 permit
->type
= permit_after
;
1641 parse_warn (cfile
, "expecting permit type.");
1642 skip_to_semi (cfile
);
1643 free_permit (permit
, MDL
);
1648 * The need_clients flag is set if we are expecting the
1651 if ((need_clients
!= 0) &&
1652 (next_token (&val
, NULL
, cfile
) != CLIENTS
)) {
1653 parse_warn (cfile
, "expecting \"clients\"");
1654 skip_to_semi (cfile
);
1655 free_permit (permit
, MDL
);
1659 while (*permit_head
)
1660 permit_head
= &((*permit_head
)->next
);
1661 *permit_head
= permit
;
1667 /* Permit_list_match returns 1 if every element of the permit list in lhs
1668 also appears in rhs. Note that this doesn't by itself mean that the
1669 two lists are equal - to check for equality, permit_list_match has to
1670 return 1 with (list1, list2) and with (list2, list1). */
1672 int permit_list_match (struct permit
*lhs
, struct permit
*rhs
)
1674 struct permit
*plp
, *prp
;
1681 for (plp
= lhs
; plp
; plp
= plp
-> next
) {
1683 for (prp
= rhs
; prp
; prp
= prp
-> next
) {
1684 if (prp
-> type
== plp
-> type
&&
1685 (prp
-> type
!= permit_class
||
1686 prp
-> class == plp
-> class)) {
1699 * \brief Parse a pool statement
1701 * Pool statements are used to group declarations and permit & deny information
1702 * with a specific address range. They must be declared within a shared network
1703 * or subnet and there may be multiple pools withing a shared network or subnet.
1704 * Each pool may have a different set of permit or deny options.
1706 * \param[in] cfile = the configuration file being parsed
1707 * \param[in] group = the group structure for this pool
1708 * \param[in] type = the type of the enclosing statement. This must be
1709 * SHARED_NET_DECL or SUBNET_DECL for this function.
1712 * void - This function either parses the statement and updates the structures
1713 * or it generates an error message and possible halts the program if
1714 * it encounters a problem.
1716 void parse_pool_statement (cfile
, group
, type
)
1717 struct parse
*cfile
;
1718 struct group
*group
;
1721 enum dhcp_token token
;
1724 struct pool
*pool
, **p
, *pp
;
1725 int declaration
= 0;
1726 isc_result_t status
;
1727 struct lease
*lpchain
= NULL
, *lp
;
1730 status
= pool_allocate(&pool
, MDL
);
1731 if (status
!= ISC_R_SUCCESS
)
1732 log_fatal ("no memory for pool: %s",
1733 isc_result_totext (status
));
1735 if (type
== SUBNET_DECL
)
1736 shared_network_reference(&pool
->shared_network
,
1737 group
->subnet
->shared_network
,
1739 else if (type
== SHARED_NET_DECL
)
1740 shared_network_reference(&pool
->shared_network
,
1741 group
->shared_network
, MDL
);
1743 parse_warn(cfile
, "Dynamic pools are only valid inside "
1744 "subnet or shared-network statements.");
1745 skip_to_semi(cfile
);
1749 if (pool
->shared_network
== NULL
||
1750 !clone_group(&pool
->group
, pool
->shared_network
->group
, MDL
))
1751 log_fatal("can't clone pool group.");
1753 #if defined (FAILOVER_PROTOCOL)
1754 /* Inherit the failover peer from the shared network. */
1755 if (pool
->shared_network
->failover_peer
)
1756 dhcp_failover_state_reference
1757 (&pool
->failover_peer
,
1758 pool
->shared_network
->failover_peer
, MDL
);
1761 if (!parse_lbrace(cfile
)) {
1762 pool_dereference(&pool
, MDL
);
1767 token
= peek_token(&val
, NULL
, cfile
);
1770 skip_token(&val
, NULL
, cfile
);
1771 token
= next_token(&val
, NULL
, cfile
);
1772 if (token
!= FAILOVER
||
1773 (token
= next_token(&val
, NULL
, cfile
)) != PEER
) {
1775 "expecting \"failover peer\".");
1776 skip_to_semi(cfile
);
1779 #if defined (FAILOVER_PROTOCOL)
1780 if (pool
->failover_peer
)
1781 dhcp_failover_state_dereference
1782 (&pool
->failover_peer
, MDL
);
1786 #if defined (FAILOVER_PROTOCOL)
1788 skip_token(&val
, NULL
, cfile
);
1789 token
= next_token (&val
, NULL
, cfile
);
1790 if (token
!= PEER
) {
1791 parse_warn(cfile
, "expecting 'peer'.");
1792 skip_to_semi(cfile
);
1795 token
= next_token(&val
, NULL
, cfile
);
1796 if (token
!= STRING
) {
1797 parse_warn(cfile
, "expecting string.");
1798 skip_to_semi(cfile
);
1801 if (pool
->failover_peer
)
1802 dhcp_failover_state_dereference
1803 (&pool
->failover_peer
, MDL
);
1804 status
= find_failover_peer(&pool
->failover_peer
,
1806 if (status
!= ISC_R_SUCCESS
)
1808 "failover peer %s: %s", val
,
1809 isc_result_totext (status
));
1811 pool
->failover_peer
->pool_count
++;
1817 skip_token(&val
, NULL
, cfile
);
1818 parse_address_range (cfile
, group
, type
,
1822 skip_token(&val
, NULL
, cfile
);
1823 get_permit(cfile
, &pool
->permit_list
, 1,
1824 &pool
->valid_from
, &pool
->valid_until
);
1828 skip_token(&val
, NULL
, cfile
);
1829 get_permit(cfile
, &pool
->prohibit_list
, 0,
1830 &pool
->valid_from
, &pool
->valid_until
);
1834 skip_token(&val
, NULL
, cfile
);
1840 * We can get to END_OF_FILE if, for instance,
1841 * the parse_statement() reads all available tokens
1842 * and leaves us at the end.
1844 parse_warn(cfile
, "unexpected end of file");
1848 declaration
= parse_statement(cfile
, pool
->group
,
1855 /* See if there's already a pool into which we can merge this one. */
1856 for (pp
= pool
->shared_network
->pools
; pp
; pp
= pp
->next
) {
1857 if (pp
->group
->statements
!= pool
->group
->statements
)
1859 #if defined (FAILOVER_PROTOCOL)
1860 if (pool
->failover_peer
!= pp
->failover_peer
)
1863 if (!permit_list_match(pp
->permit_list
,
1864 pool
->permit_list
) ||
1865 !permit_list_match(pool
->permit_list
,
1867 !permit_list_match(pp
->prohibit_list
,
1868 pool
->prohibit_list
) ||
1869 !permit_list_match(pool
->prohibit_list
,
1873 /* Okay, we can merge these two pools. All we have to
1874 do is fix up the leases, which all point to their pool. */
1875 for (lp
= lpchain
; lp
; lp
= lp
->next
) {
1876 pool_dereference(&lp
->pool
, MDL
);
1877 pool_reference(&lp
->pool
, pp
, MDL
);
1880 #if defined (BINARY_LEASES)
1881 /* If we are doing binary leases we also need to add the
1882 * addresses in for leasechain allocation.
1884 pp
->lease_count
+= pool
->lease_count
;
1890 /* If we didn't succeed in merging this pool into another, put
1893 p
= &pool
->shared_network
->pools
;
1894 for (; *p
; p
= &((*p
)->next
))
1896 pool_reference(p
, pool
, MDL
);
1899 /* Don't allow a pool declaration with no addresses, since it is
1900 probably a configuration error. */
1902 parse_warn(cfile
, "Pool declaration with no address range.");
1903 log_error("Pool declarations must always contain at least");
1904 log_error("one range statement.");
1908 /* Dereference the lease chain. */
1911 lease_reference(&lp
, lpchain
, MDL
);
1912 lease_dereference(&lpchain
, MDL
);
1914 lease_reference(&lpchain
, lp
->next
, MDL
);
1915 lease_dereference(&lp
->next
, MDL
);
1916 lease_dereference(&lp
, MDL
);
1919 pool_dereference(&pool
, MDL
);
1922 /* Expect a left brace; if there isn't one, skip over the rest of the
1923 statement and return zero; otherwise, return 1. */
1925 int parse_lbrace (cfile
)
1926 struct parse
*cfile
;
1928 enum dhcp_token token
;
1931 token
= next_token (&val
, (unsigned *)0, cfile
);
1932 if (token
!= LBRACE
) {
1933 parse_warn (cfile
, "expecting left brace.");
1934 skip_to_semi (cfile
);
1941 /* host-declaration :== hostname RBRACE parameters declarations LBRACE */
1943 void parse_host_declaration (cfile
, group
)
1944 struct parse
*cfile
;
1945 struct group
*group
;
1948 enum dhcp_token token
;
1949 struct host_decl
*host
;
1951 int declaration
= 0;
1954 isc_result_t status
;
1956 struct option
*option
;
1957 struct expression
*expr
= NULL
;
1959 name
= parse_host_name (cfile
);
1961 parse_warn (cfile
, "expecting a name for host declaration.");
1962 skip_to_semi (cfile
);
1966 host
= (struct host_decl
*)0;
1967 status
= host_allocate (&host
, MDL
);
1968 if (status
!= ISC_R_SUCCESS
)
1969 log_fatal ("can't allocate host decl struct %s: %s",
1970 name
, isc_result_totext (status
));
1971 host
-> name
= name
;
1972 if (!clone_group (&host
-> group
, group
, MDL
)) {
1973 log_fatal ("can't clone group for host %s", name
);
1975 host_dereference (&host
, MDL
);
1979 if (!parse_lbrace (cfile
))
1983 token
= peek_token (&val
, (unsigned *)0, cfile
);
1984 if (token
== RBRACE
) {
1985 skip_token(&val
, (unsigned *)0, cfile
);
1988 if (token
== END_OF_FILE
) {
1989 skip_token(&val
, (unsigned *)0, cfile
);
1990 parse_warn (cfile
, "unexpected end of file");
1993 /* If the host declaration was created by the server,
1994 remember to save it. */
1995 if (token
== DYNAMIC
) {
1997 skip_token(&val
, (unsigned *)0, cfile
);
1998 if (!parse_semi (cfile
))
2002 /* If the host declaration was created by the server,
2003 remember to save it. */
2004 if (token
== TOKEN_DELETED
) {
2006 skip_token(&val
, (unsigned *)0, cfile
);
2007 if (!parse_semi (cfile
))
2012 if (token
== GROUP
) {
2013 struct group_object
*go
;
2014 skip_token(&val
, (unsigned *)0, cfile
);
2015 token
= next_token (&val
, (unsigned *)0, cfile
);
2016 if (token
!= STRING
&& !is_identifier (token
)) {
2018 "expecting string or identifier.");
2019 skip_to_rbrace (cfile
, 1);
2022 go
= (struct group_object
*)0;
2023 if (!group_hash_lookup (&go
, group_name_hash
,
2024 val
, strlen (val
), MDL
)) {
2025 parse_warn (cfile
, "unknown group %s in host %s",
2028 if (host
-> named_group
)
2029 group_object_dereference
2030 (&host
-> named_group
, MDL
);
2031 group_object_reference (&host
-> named_group
,
2033 group_object_dereference (&go
, MDL
);
2035 if (!parse_semi (cfile
))
2042 unsigned char *t
= 0;
2045 skip_token(&val
, (unsigned *)0, cfile
);
2046 data_string_forget (&host
-> client_identifier
, MDL
);
2048 if (host
->client_identifier
.len
!= 0) {
2049 parse_warn(cfile
, "Host %s already has a "
2050 "client identifier.",
2055 /* See if it's a string or a cshl. */
2056 token
= peek_token (&val
, (unsigned *)0, cfile
);
2057 if (token
== STRING
) {
2058 skip_token(&val
, &len
, cfile
);
2060 host
-> client_identifier
.terminated
= 1;
2063 t
= parse_numeric_aggregate
2065 (unsigned char *)0, &len
, ':', 16, 8);
2068 "expecting hex list.");
2069 skip_to_semi (cfile
);
2071 s
= (const char *)t
;
2073 if (!buffer_allocate
2074 (&host
-> client_identifier
.buffer
,
2075 len
+ host
-> client_identifier
.terminated
, MDL
))
2076 log_fatal ("no memory for uid for host %s.",
2078 host
-> client_identifier
.data
=
2079 host
-> client_identifier
.buffer
-> data
;
2080 host
-> client_identifier
.len
= len
;
2081 memcpy (host
-> client_identifier
.buffer
-> data
, s
,
2082 len
+ host
-> client_identifier
.terminated
);
2086 if (!parse_semi (cfile
))
2091 if (token
== HOST_IDENTIFIER
) {
2092 if (host
->host_id_option
!= NULL
) {
2094 "only one host-identifier allowed "
2096 skip_to_rbrace(cfile
, 1);
2099 skip_token(&val
, NULL
, cfile
);
2100 token
= next_token(&val
, NULL
, cfile
);
2101 if (token
== V6RELOPT
) {
2102 token
= next_token(&val
, NULL
, cfile
);
2103 if (token
!= NUMBER
) {
2105 "host-identifier v6relopt "
2106 "must have a number");
2107 skip_to_rbrace(cfile
, 1);
2110 host
->relays
= atoi(val
);
2111 if (host
->relays
< 0) {
2113 "host-identifier v6relopt "
2114 "must have a number >= 0");
2115 skip_to_rbrace(cfile
, 1);
2118 } else if (token
!= OPTION
) {
2120 "host-identifier must be an option"
2122 skip_to_rbrace(cfile
, 1);
2127 status
= parse_option_name(cfile
, 1, &known
, &option
);
2128 if ((status
!= ISC_R_SUCCESS
) || (option
== NULL
)) {
2132 parse_warn(cfile
, "unknown option %s.%s",
2133 option
->universe
->name
,
2135 skip_to_rbrace(cfile
, 1);
2139 if (! parse_option_data(&expr
, cfile
, 1, option
)) {
2140 skip_to_rbrace(cfile
, 1);
2141 option_dereference(&option
, MDL
);
2145 if (!parse_semi(cfile
)) {
2146 skip_to_rbrace(cfile
, 1);
2147 expression_dereference(&expr
, MDL
);
2148 option_dereference(&option
, MDL
);
2152 option_reference(&host
->host_id_option
, option
, MDL
);
2153 option_dereference(&option
, MDL
);
2154 data_string_copy(&host
->host_id
,
2155 &expr
->data
.const_data
, MDL
);
2156 expression_dereference(&expr
, MDL
);
2160 declaration
= parse_statement(cfile
, host
->group
, HOST_DECL
,
2165 struct host_decl
*hp
= (struct host_decl
*)0;
2166 if (host_hash_lookup (&hp
, host_name_hash
,
2167 (unsigned char *)host
-> name
,
2168 strlen (host
-> name
), MDL
)) {
2169 delete_host (hp
, 0);
2170 host_dereference (&hp
, MDL
);
2173 if (host
-> named_group
&& host
-> named_group
-> group
) {
2174 if (host
-> group
-> statements
||
2175 (host
-> group
-> authoritative
!=
2176 host
-> named_group
-> group
-> authoritative
)) {
2177 if (host
-> group
-> next
)
2178 group_dereference (&host
-> group
-> next
,
2180 group_reference (&host
-> group
-> next
,
2181 host
-> named_group
-> group
,
2184 group_dereference (&host
-> group
, MDL
);
2185 group_reference (&host
-> group
,
2186 host
-> named_group
-> group
,
2192 host
-> flags
|= HOST_DECL_DYNAMIC
;
2194 host
-> flags
|= HOST_DECL_STATIC
;
2196 status
= enter_host (host
, dynamicp
, 0);
2197 if (status
!= ISC_R_SUCCESS
)
2198 parse_warn (cfile
, "host %s: %s", host
-> name
,
2199 isc_result_totext (status
));
2201 host_dereference (&host
, MDL
);
2204 /* class-declaration :== STRING LBRACE parameters declarations RBRACE
2207 int parse_class_declaration (cp
, cfile
, group
, type
)
2209 struct parse
*cfile
;
2210 struct group
*group
;
2214 enum dhcp_token token
;
2215 struct class *class = NULL
, *pc
= NULL
;
2216 int declaration
= 0;
2218 struct data_string data
;
2221 struct executable_statement
*stmt
= NULL
;
2223 isc_result_t status
= ISC_R_FAILURE
;
2224 int matchedonce
= 0;
2225 int submatchedonce
= 0;
2228 token
= next_token (&val
, NULL
, cfile
);
2229 if (token
!= STRING
) {
2230 parse_warn (cfile
, "Expecting class name");
2231 skip_to_semi (cfile
);
2235 /* See if there's already a class with the specified name. */
2236 find_class (&pc
, val
, MDL
);
2238 /* If it is a class, we're updating it. If it's any of the other
2239 * types (subclass, vendor or user class), the named class is a
2240 * reference to the parent class so its mandatory.
2242 if (pc
&& (type
== CLASS_TYPE_CLASS
)) {
2243 class_reference(&class, pc
, MDL
);
2245 class_dereference(&pc
, MDL
);
2246 } else if (!pc
&& (type
!= CLASS_TYPE_CLASS
)) {
2247 parse_warn(cfile
, "no class named %s", val
);
2248 skip_to_semi(cfile
);
2252 /* The old vendor-class and user-class declarations had an implicit
2253 match. We don't do the implicit match anymore. Instead, for
2254 backward compatibility, we have an implicit-vendor-class and an
2255 implicit-user-class. vendor-class and user-class declarations
2256 are turned into subclasses of the implicit classes, and the
2257 submatch expression of the implicit classes extracts the contents of
2258 the vendor class or user class. */
2259 if ((type
== CLASS_TYPE_VENDOR
) || (type
== CLASS_TYPE_USER
)) {
2260 data
.len
= strlen (val
);
2262 if (!buffer_allocate (&data
.buffer
, data
.len
+ 1, MDL
))
2263 log_fatal ("no memory for class name.");
2264 data
.data
= &data
.buffer
-> data
[0];
2265 data
.terminated
= 1;
2267 tname
= (type
== CLASS_TYPE_VENDOR
) ?
2268 "implicit-vendor-class" : "implicit-user-class";
2270 } else if (type
== CLASS_TYPE_CLASS
) {
2277 name
= dmalloc (strlen (tname
) + 1, MDL
);
2279 log_fatal ("No memory for class name %s.", tname
);
2280 strcpy (name
, tname
);
2284 /* If this is a straight subclass, parse the hash string. */
2285 if (type
== CLASS_TYPE_SUBCLASS
) {
2286 token
= peek_token (&val
, NULL
, cfile
);
2287 if (token
== STRING
) {
2288 skip_token(&val
, &data
.len
, cfile
);
2291 if (!buffer_allocate (&data
.buffer
,
2292 data
.len
+ 1, MDL
)) {
2294 class_dereference (&pc
, MDL
);
2298 data
.terminated
= 1;
2299 data
.data
= &data
.buffer
-> data
[0];
2300 memcpy ((char *)data
.buffer
-> data
, val
,
2302 } else if (token
== NUMBER_OR_NAME
|| token
== NUMBER
) {
2303 memset (&data
, 0, sizeof data
);
2304 if (!parse_cshl (&data
, cfile
)) {
2306 class_dereference (&pc
, MDL
);
2310 parse_warn (cfile
, "Expecting string or hex list.");
2312 class_dereference (&pc
, MDL
);
2317 /* See if there's already a class in the hash table matching the
2319 if (type
!= CLASS_TYPE_CLASS
)
2320 class_hash_lookup (&class, pc
-> hash
,
2321 (const char *)data
.data
, data
.len
, MDL
);
2323 /* If we didn't find an existing class, allocate a new one. */
2325 /* Allocate the class structure... */
2326 if (type
== CLASS_TYPE_SUBCLASS
) {
2327 status
= subclass_allocate (&class, MDL
);
2329 status
= class_allocate (&class, MDL
);
2332 group_reference (&class -> group
, pc
-> group
, MDL
);
2333 class_reference (&class -> superclass
, pc
, MDL
);
2334 class -> lease_limit
= pc
-> lease_limit
;
2335 if (class -> lease_limit
) {
2336 class -> billed_leases
=
2337 dmalloc (class -> lease_limit
*
2338 sizeof (struct lease
*), MDL
);
2339 if (!class -> billed_leases
)
2340 log_fatal ("no memory for billing");
2341 memset (class -> billed_leases
, 0,
2342 (class -> lease_limit
*
2343 sizeof (struct lease
*)));
2345 data_string_copy (&class -> hash_string
, &data
, MDL
);
2347 !class_new_hash (&pc
->hash
, SCLASS_HASH_SIZE
, MDL
))
2348 log_fatal ("No memory for subclass hash.");
2349 class_hash_add (pc
-> hash
,
2350 (const char *)class -> hash_string
.data
,
2351 class -> hash_string
.len
,
2352 (void *)class, MDL
);
2355 group_dereference(&class->group
, MDL
);
2356 if (!clone_group (&class -> group
, group
, MDL
))
2357 log_fatal ("no memory to clone class group.");
2360 /* If this is an implicit vendor or user class, add a
2361 statement that causes the vendor or user class ID to
2362 be sent back in the reply. */
2363 if (type
== CLASS_TYPE_VENDOR
|| type
== CLASS_TYPE_USER
) {
2365 if (!executable_statement_allocate (&stmt
, MDL
))
2366 log_fatal ("no memory for class statement.");
2367 stmt
-> op
= supersede_option_statement
;
2368 if (option_cache_allocate (&stmt
-> data
.option
,
2370 stmt
-> data
.option
-> data
= data
;
2371 code
= (type
== CLASS_TYPE_VENDOR
)
2372 ? DHO_VENDOR_CLASS_IDENTIFIER
2374 option_code_hash_lookup(
2375 &stmt
->data
.option
->option
,
2376 dhcp_universe
.code_hash
,
2379 class -> statements
= stmt
;
2382 /* Save the name, if there is one. */
2383 if (class->name
!= NULL
)
2384 dfree(class->name
, MDL
);
2388 if (type
!= CLASS_TYPE_CLASS
)
2389 data_string_forget(&data
, MDL
);
2391 /* Spawned classes don't have to have their own settings. */
2392 if (class -> superclass
) {
2393 token
= peek_token (&val
, NULL
, cfile
);
2394 if (token
== SEMI
) {
2395 skip_token(&val
, NULL
, cfile
);
2398 status
= class_reference (cp
, class, MDL
);
2399 class_dereference (&class, MDL
);
2401 class_dereference (&pc
, MDL
);
2402 return cp
? (status
== ISC_R_SUCCESS
) : 1;
2404 /* Give the subclass its own group. */
2405 if (!clone_group (&class -> group
, class -> group
, MDL
))
2406 log_fatal ("can't clone class group.");
2410 if (!parse_lbrace (cfile
)) {
2411 class_dereference (&class, MDL
);
2413 class_dereference (&pc
, MDL
);
2418 token
= peek_token (&val
, NULL
, cfile
);
2419 if (token
== RBRACE
) {
2420 skip_token(&val
, NULL
, cfile
);
2422 } else if (token
== END_OF_FILE
) {
2423 skip_token(&val
, NULL
, cfile
);
2424 parse_warn (cfile
, "unexpected end of file");
2426 } else if (token
== DYNAMIC
) {
2427 class->flags
|= CLASS_DECL_DYNAMIC
;
2428 skip_token(&val
, NULL
, cfile
);
2429 if (!parse_semi (cfile
))
2432 } else if (token
== TOKEN_DELETED
) {
2433 class->flags
|= CLASS_DECL_DELETED
;
2434 skip_token(&val
, NULL
, cfile
);
2435 if (!parse_semi (cfile
))
2438 } else if (token
== MATCH
) {
2441 "invalid match in subclass.");
2442 skip_to_semi (cfile
);
2445 skip_token(&val
, NULL
, cfile
);
2446 token
= peek_token (&val
, NULL
, cfile
);
2449 skip_token(&val
, NULL
, cfile
);
2451 parse_warn(cfile
, "A class may only have "
2452 "one 'match if' clause.");
2453 skip_to_semi(cfile
);
2458 expression_dereference(&class->expr
, MDL
);
2459 if (!parse_boolean_expression (&class->expr
, cfile
,
2463 "expecting boolean expr.");
2464 skip_to_semi (cfile
);
2467 #if defined (DEBUG_EXPRESSION_PARSE)
2468 print_expression ("class match",
2473 } else if (token
== SPAWN
) {
2474 skip_token(&val
, NULL
, cfile
);
2477 "invalid spawn in subclass.");
2478 skip_to_semi (cfile
);
2481 class -> spawning
= 1;
2482 token
= next_token (&val
, NULL
, cfile
);
2483 if (token
!= WITH
) {
2485 "expecting with after spawn");
2486 skip_to_semi (cfile
);
2490 if (submatchedonce
) {
2492 "can't override existing %s.",
2494 skip_to_semi (cfile
);
2498 if (class->submatch
)
2499 expression_dereference(&class->submatch
, MDL
);
2500 if (!parse_data_expression (&class -> submatch
,
2504 "expecting data expr.");
2505 skip_to_semi (cfile
);
2508 #if defined (DEBUG_EXPRESSION_PARSE)
2509 print_expression ("class submatch",
2514 } else if (token
== LEASE
) {
2515 skip_token(&val
, NULL
, cfile
);
2516 token
= next_token (&val
, NULL
, cfile
);
2517 if (token
!= LIMIT
) {
2518 parse_warn (cfile
, "expecting \"limit\"");
2520 skip_to_semi (cfile
);
2523 token
= next_token (&val
, NULL
, cfile
);
2524 if (token
!= NUMBER
) {
2525 parse_warn (cfile
, "expecting a number");
2527 skip_to_semi (cfile
);
2530 class -> lease_limit
= atoi (val
);
2531 if (class->billed_leases
)
2532 dfree(class->billed_leases
, MDL
);
2533 class -> billed_leases
=
2534 dmalloc (class -> lease_limit
*
2535 sizeof (struct lease
*), MDL
);
2536 if (!class -> billed_leases
)
2537 log_fatal ("no memory for billed leases.");
2538 memset (class -> billed_leases
, 0,
2539 (class -> lease_limit
*
2540 sizeof (struct lease
*)));
2541 have_billing_classes
= 1;
2544 declaration
= parse_statement (cfile
, class -> group
,
2550 if (class->flags
& CLASS_DECL_DELETED
) {
2551 if (type
== CLASS_TYPE_CLASS
) {
2552 struct class *theclass
= NULL
;
2554 status
= find_class(&theclass
, class->name
, MDL
);
2555 if (status
== ISC_R_SUCCESS
) {
2556 delete_class(theclass
, 0);
2557 class_dereference(&theclass
, MDL
);
2560 class_hash_delete(pc
->hash
,
2561 (char *)class->hash_string
.data
,
2562 class->hash_string
.len
, MDL
);
2564 } else if (type
== CLASS_TYPE_CLASS
&& new) {
2565 if (!collections
-> classes
)
2566 class_reference (&collections
-> classes
, class, MDL
);
2569 for (c
= collections
-> classes
;
2570 c
-> nic
; c
= c
-> nic
)
2572 class_reference (&c
-> nic
, class, MDL
);
2576 if (cp
) /* should always be 0??? */
2577 status
= class_reference (cp
, class, MDL
);
2578 class_dereference (&class, MDL
);
2580 class_dereference (&pc
, MDL
);
2581 return cp
? (status
== ISC_R_SUCCESS
) : 1;
2584 /* shared-network-declaration :==
2585 hostname LBRACE declarations parameters RBRACE */
2587 void parse_shared_net_declaration (cfile
, group
)
2588 struct parse
*cfile
;
2589 struct group
*group
;
2592 enum dhcp_token token
;
2593 struct shared_network
*share
;
2595 int declaration
= 0;
2596 isc_result_t status
;
2598 share
= (struct shared_network
*)0;
2599 status
= shared_network_allocate (&share
, MDL
);
2600 if (status
!= ISC_R_SUCCESS
)
2601 log_fatal ("Can't allocate shared subnet: %s",
2602 isc_result_totext (status
));
2603 if (clone_group (&share
-> group
, group
, MDL
) == 0) {
2604 log_fatal ("Can't clone group for shared net");
2606 shared_network_reference (&share
-> group
-> shared_network
,
2609 /* Get the name of the shared network... */
2610 token
= peek_token (&val
, (unsigned *)0, cfile
);
2611 if (token
== STRING
) {
2612 skip_token(&val
, (unsigned *)0, cfile
);
2615 parse_warn (cfile
, "zero-length shared network name");
2616 val
= "<no-name-given>";
2618 name
= dmalloc (strlen (val
) + 1, MDL
);
2620 log_fatal ("no memory for shared network name");
2623 name
= parse_host_name (cfile
);
2626 "expecting a name for shared-network");
2627 skip_to_semi (cfile
);
2628 shared_network_dereference (&share
, MDL
);
2632 share
-> name
= name
;
2634 if (!parse_lbrace (cfile
)) {
2635 shared_network_dereference (&share
, MDL
);
2640 token
= peek_token (&val
, (unsigned *)0, cfile
);
2641 if (token
== RBRACE
) {
2642 skip_token(&val
, (unsigned *)0, cfile
);
2643 if (!share
-> subnets
)
2645 "empty shared-network decl");
2647 enter_shared_network (share
);
2648 shared_network_dereference (&share
, MDL
);
2650 } else if (token
== END_OF_FILE
) {
2651 skip_token(&val
, (unsigned *)0, cfile
);
2652 parse_warn (cfile
, "unexpected end of file");
2654 } else if (token
== INTERFACE
) {
2655 skip_token(&val
, (unsigned *)0, cfile
);
2656 token
= next_token (&val
, (unsigned *)0, cfile
);
2657 new_shared_network_interface (cfile
, share
, val
);
2658 if (!parse_semi (cfile
))
2663 declaration
= parse_statement (cfile
, share
-> group
,
2665 (struct host_decl
*)0,
2668 shared_network_dereference (&share
, MDL
);
2673 common_subnet_parsing(struct parse
*cfile
,
2674 struct shared_network
*share
,
2675 struct subnet
*subnet
) {
2676 enum dhcp_token token
;
2677 struct subnet
*t
, *u
;
2679 int declaration
= 0;
2681 enter_subnet(subnet
);
2683 if (!parse_lbrace(cfile
)) {
2684 subnet_dereference(&subnet
, MDL
);
2689 token
= peek_token(&val
, NULL
, cfile
);
2690 if (token
== RBRACE
) {
2691 skip_token(&val
, NULL
, cfile
);
2693 } else if (token
== END_OF_FILE
) {
2694 skip_token(&val
, NULL
, cfile
);
2695 parse_warn (cfile
, "unexpected end of file");
2697 } else if (token
== INTERFACE
) {
2698 skip_token(&val
, NULL
, cfile
);
2699 token
= next_token(&val
, NULL
, cfile
);
2700 new_shared_network_interface(cfile
, share
, val
);
2701 if (!parse_semi(cfile
))
2705 declaration
= parse_statement(cfile
, subnet
->group
,
2711 /* Add the subnet to the list of subnets in this shared net. */
2712 if (share
->subnets
== NULL
) {
2713 subnet_reference(&share
->subnets
, subnet
, MDL
);
2716 for (t
= share
->subnets
; t
->next_sibling
; t
= t
->next_sibling
) {
2717 if (subnet_inner_than(subnet
, t
, 0)) {
2718 subnet_reference(&subnet
->next_sibling
, t
, MDL
);
2720 subnet_dereference(&u
->next_sibling
,
2722 subnet_reference(&u
->next_sibling
,
2725 subnet_dereference(&share
->subnets
,
2727 subnet_reference(&share
->subnets
,
2730 subnet_dereference(&subnet
, MDL
);
2735 subnet_reference(&t
->next_sibling
, subnet
, MDL
);
2737 subnet_dereference(&subnet
, MDL
);
2741 /* subnet-declaration :==
2742 net NETMASK netmask RBRACE parameters declarations LBRACE */
2744 void parse_subnet_declaration (cfile
, share
)
2745 struct parse
*cfile
;
2746 struct shared_network
*share
;
2749 enum dhcp_token token
;
2750 struct subnet
*subnet
;
2752 unsigned char addr
[4];
2753 unsigned len
= sizeof addr
;
2754 isc_result_t status
;
2756 subnet
= (struct subnet
*)0;
2757 status
= subnet_allocate (&subnet
, MDL
);
2758 if (status
!= ISC_R_SUCCESS
)
2759 log_fatal ("Allocation of new subnet failed: %s",
2760 isc_result_totext (status
));
2761 shared_network_reference (&subnet
-> shared_network
, share
, MDL
);
2764 * If our parent shared network was implicitly created by the software,
2765 * and not explicitly configured by the user, then we actually put all
2766 * configuration scope in the parent (the shared network and subnet
2767 * share the same {}-level scope).
2769 * Otherwise, we clone the parent group and continue as normal.
2771 if (share
->flags
& SHARED_IMPLICIT
) {
2772 group_reference(&subnet
->group
, share
->group
, MDL
);
2774 if (!clone_group(&subnet
->group
, share
->group
, MDL
)) {
2775 log_fatal("Allocation of group for new subnet failed.");
2778 subnet_reference (&subnet
-> group
-> subnet
, subnet
, MDL
);
2780 /* Get the network number... */
2781 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8)) {
2782 subnet_dereference (&subnet
, MDL
);
2785 memcpy (iaddr
.iabuf
, addr
, len
);
2787 subnet
-> net
= iaddr
;
2789 token
= next_token (&val
, (unsigned *)0, cfile
);
2790 if (token
!= NETMASK
) {
2791 parse_warn (cfile
, "Expecting netmask");
2792 skip_to_semi (cfile
);
2796 /* Get the netmask... */
2797 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8)) {
2798 subnet_dereference (&subnet
, MDL
);
2801 memcpy (iaddr
.iabuf
, addr
, len
);
2803 subnet
-> netmask
= iaddr
;
2805 /* Validate the network number/netmask pair. */
2806 if (host_addr (subnet
-> net
, subnet
-> netmask
)) {
2809 /* dup it, since piaddr is re-entrant */
2810 maskstr
= strdup (piaddr (subnet
-> netmask
));
2811 if (maskstr
== NULL
) {
2812 log_fatal("Allocation of subnet maskstr failed: %s",
2813 piaddr (subnet
-> net
));
2817 "subnet %s netmask %s: bad subnet number/mask combination.",
2818 piaddr (subnet
-> net
), maskstr
);
2820 subnet_dereference (&subnet
, MDL
);
2821 skip_to_semi (cfile
);
2825 common_subnet_parsing(cfile
, share
, subnet
);
2828 /* subnet6-declaration :==
2829 net / bits RBRACE parameters declarations LBRACE */
2832 parse_subnet6_declaration(struct parse
*cfile
, struct shared_network
*share
) {
2833 #if !defined(DHCPv6)
2834 parse_warn(cfile
, "No DHCPv6 support.");
2835 skip_to_semi(cfile
);
2836 #else /* defined(DHCPv6) */
2837 struct subnet
*subnet
;
2838 isc_result_t status
;
2839 enum dhcp_token token
;
2843 const static int mask
[] = { 0x00, 0x80, 0xC0, 0xE0,
2844 0xF0, 0xF8, 0xFC, 0xFE };
2847 #if defined(DHCP4o6)
2848 if ((local_family
!= AF_INET6
) && !dhcpv4_over_dhcpv6
) {
2849 parse_warn(cfile
, "subnet6 statement is only supported "
2850 "in DHCPv6 and DHCPv4o6 modes.");
2851 skip_to_semi(cfile
);
2854 #else /* defined(DHCP4o6) */
2855 if (local_family
!= AF_INET6
) {
2856 parse_warn(cfile
, "subnet6 statement is only supported "
2858 skip_to_semi(cfile
);
2861 #endif /* !defined(DHCP4o6) */
2864 status
= subnet_allocate(&subnet
, MDL
);
2865 if (status
!= ISC_R_SUCCESS
) {
2866 log_fatal("Allocation of new subnet failed: %s",
2867 isc_result_totext(status
));
2869 shared_network_reference(&subnet
->shared_network
, share
, MDL
);
2872 * If our parent shared network was implicitly created by the software,
2873 * and not explicitly configured by the user, then we actually put all
2874 * configuration scope in the parent (the shared network and subnet
2875 * share the same {}-level scope).
2877 * Otherwise, we clone the parent group and continue as normal.
2879 if (share
->flags
& SHARED_IMPLICIT
) {
2880 group_reference(&subnet
->group
, share
->group
, MDL
);
2882 if (!clone_group(&subnet
->group
, share
->group
, MDL
)) {
2883 log_fatal("Allocation of group for new subnet failed.");
2886 subnet_reference(&subnet
->group
->subnet
, subnet
, MDL
);
2888 if (!parse_ip6_addr(cfile
, &subnet
->net
)) {
2889 subnet_dereference(&subnet
, MDL
);
2893 token
= next_token(&val
, NULL
, cfile
);
2894 if (token
!= SLASH
) {
2895 parse_warn(cfile
, "Expecting a '/'.");
2896 skip_to_semi(cfile
);
2900 token
= next_token(&val
, NULL
, cfile
);
2901 if (token
!= NUMBER
) {
2902 parse_warn(cfile
, "Expecting a number.");
2903 skip_to_semi(cfile
);
2907 subnet
->prefix_len
= strtol(val
, &endp
, 10);
2908 if ((subnet
->prefix_len
< 0) ||
2909 (subnet
->prefix_len
> 128) ||
2911 parse_warn(cfile
, "Expecting a number between 0 and 128.");
2912 skip_to_semi(cfile
);
2916 if (!is_cidr_mask_valid(&subnet
->net
, subnet
->prefix_len
)) {
2917 parse_warn(cfile
, "New subnet mask too short.");
2918 skip_to_semi(cfile
);
2925 subnet
->netmask
.len
= 16;
2926 ofs
= subnet
->prefix_len
/ 8;
2927 if (ofs
< subnet
->netmask
.len
) {
2928 subnet
->netmask
.iabuf
[ofs
] = mask
[subnet
->prefix_len
% 8];
2930 while (--ofs
>= 0) {
2931 subnet
->netmask
.iabuf
[ofs
] = 0xFF;
2934 /* Validate the network number/netmask pair. */
2935 iaddr
= subnet_number(subnet
->net
, subnet
->netmask
);
2936 if (memcmp(&iaddr
, &subnet
->net
, 16) != 0) {
2938 "subnet %s/%d: prefix not long enough for address.",
2939 piaddr(subnet
->net
), subnet
->prefix_len
);
2940 subnet_dereference(&subnet
, MDL
);
2941 skip_to_semi(cfile
);
2945 if (!common_subnet_parsing(cfile
, share
, subnet
)) {
2948 #endif /* defined(DHCPv6) */
2951 /* group-declaration :== RBRACE parameters declarations LBRACE */
2953 void parse_group_declaration (cfile
, group
)
2954 struct parse
*cfile
;
2955 struct group
*group
;
2958 enum dhcp_token token
;
2960 int declaration
= 0;
2961 struct group_object
*t
= NULL
;
2962 isc_result_t status
;
2969 if (!clone_group(&g
, group
, MDL
))
2970 log_fatal("no memory for explicit group.");
2972 token
= peek_token(&val
, NULL
, cfile
);
2973 if (is_identifier (token
) || token
== STRING
) {
2974 skip_token(&val
, NULL
, cfile
);
2976 name
= dmalloc(strlen(val
) + 1, MDL
);
2978 log_fatal("no memory for group decl name %s", val
);
2982 if (!parse_lbrace(cfile
)) {
2983 group_dereference(&g
, MDL
);
2988 token
= peek_token(&val
, NULL
, cfile
);
2989 if (token
== RBRACE
) {
2990 skip_token(&val
, NULL
, cfile
);
2992 } else if (token
== END_OF_FILE
) {
2993 skip_token(&val
, NULL
, cfile
);
2994 parse_warn(cfile
, "unexpected end of file");
2996 } else if (token
== TOKEN_DELETED
) {
2997 skip_token(&val
, NULL
, cfile
);
3000 } else if (token
== DYNAMIC
) {
3001 skip_token(&val
, NULL
, cfile
);
3004 } else if (token
== STATIC
) {
3005 skip_token(&val
, NULL
, cfile
);
3009 declaration
= parse_statement(cfile
, g
, GROUP_DECL
,
3015 if (group_name_hash
) {
3017 if (group_hash_lookup(&t
, group_name_hash
,
3019 strlen(name
), MDL
)) {
3025 status
= group_object_allocate(&t
, MDL
);
3026 if (status
!= ISC_R_SUCCESS
)
3027 log_fatal("no memory for group decl %s: %s",
3028 val
, isc_result_totext(status
));
3029 group_reference(&t
->group
, g
, MDL
);
3031 /* no need to include deletedp as it's handled above */
3032 t
->flags
= ((staticp
? GROUP_OBJECT_STATIC
: 0) |
3033 (dynamicp
? GROUP_OBJECT_DYNAMIC
: 0));
3034 supersede_group(t
, 0);
3037 group_object_dereference(&t
, MDL
);
3041 /* fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
3042 ip-addrs-or-hostnames :== ip-addr-or-hostname
3043 | ip-addrs-or-hostnames ip-addr-or-hostname */
3046 parse_fixed_addr_param(struct option_cache
**oc
,
3047 struct parse
*cfile
,
3048 enum dhcp_token type
) {
3051 enum dhcp_token token
;
3052 struct expression
*expr
= NULL
;
3053 struct expression
*tmp
, *new;
3058 if (type
== FIXED_ADDR
) {
3059 parse_ok
= parse_ip_addr_or_hostname(&tmp
, cfile
, 1);
3061 /* INSIST(type == FIXED_ADDR6); */
3062 parse_ok
= parse_ip6_addr_expr(&tmp
, cfile
);
3067 status
= make_concat(&new, expr
, tmp
);
3068 expression_dereference(&expr
, MDL
);
3069 expression_dereference(&tmp
, MDL
);
3079 expression_dereference (&expr
, MDL
);
3083 token
= peek_token(&val
, NULL
, cfile
);
3084 if (token
== COMMA
) {
3085 token
= next_token(&val
, NULL
, cfile
);
3087 } while (token
== COMMA
);
3089 if (!parse_semi(cfile
)) {
3091 expression_dereference (&expr
, MDL
);
3096 status
= option_cache(oc
, NULL
, expr
, NULL
, MDL
);
3097 expression_dereference(&expr
, MDL
);
3101 /* lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
3103 lease_parameters :== <nil>
3105 | lease_parameters lease_parameter
3107 lease_parameter :== STARTS date
3110 | HARDWARE hardware-parameter
3111 | UID hex_numbers SEMI
3112 | HOSTNAME hostname SEMI
3113 | CLIENT_HOSTNAME hostname SEMI
3114 | CLASS identifier SEMI
3115 | DYNAMIC_BOOTP SEMI */
3117 int parse_lease_declaration (struct lease
**lp
, struct parse
*cfile
)
3120 enum dhcp_token token
;
3121 unsigned char addr
[4];
3122 unsigned len
= sizeof addr
;
3126 struct lease
*lease
;
3127 struct executable_statement
*on
;
3130 int noequal
, newbinding
;
3131 struct binding
*binding
;
3132 struct binding_value
*nv
;
3133 isc_result_t status
;
3134 struct option_cache
*oc
;
3136 binding_state_t new_state
;
3137 unsigned buflen
= 0;
3138 struct class *class;
3140 lease
= (struct lease
*)0;
3141 status
= lease_allocate (&lease
, MDL
);
3142 if (status
!= ISC_R_SUCCESS
)
3145 /* Get the address for which the lease has been issued. */
3146 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8)) {
3147 lease_dereference (&lease
, MDL
);
3150 memcpy (lease
-> ip_addr
.iabuf
, addr
, len
);
3151 lease
-> ip_addr
.len
= len
;
3153 if (!parse_lbrace (cfile
)) {
3154 lease_dereference (&lease
, MDL
);
3159 token
= next_token (&val
, (unsigned *)0, cfile
);
3160 if (token
== RBRACE
)
3162 else if (token
== END_OF_FILE
) {
3163 parse_warn (cfile
, "unexpected end of file");
3166 strncpy (tbuf
, val
, sizeof tbuf
);
3167 tbuf
[(sizeof tbuf
) - 1] = 0;
3169 /* Parse any of the times associated with the lease. */
3178 t
= parse_date (cfile
);
3182 lease
-> starts
= t
;
3210 default: /* for gcc, we'll never get here. */
3211 log_fatal ("Impossible error at %s:%d.", MDL
);
3216 /* Colon-separated hexadecimal octets... */
3219 token
= peek_token (&val
, (unsigned *)0, cfile
);
3220 if (token
== STRING
) {
3221 unsigned char *tuid
;
3222 skip_token(&val
, &buflen
, cfile
);
3223 if (buflen
< sizeof lease
-> uid_buf
) {
3224 tuid
= lease
-> uid_buf
;
3226 sizeof lease
-> uid_buf
;
3228 tuid
= ((unsigned char *)
3229 dmalloc (buflen
, MDL
));
3231 log_error ("no space for uid");
3232 lease_dereference (&lease
,
3236 lease
-> uid_max
= buflen
;
3238 lease
-> uid_len
= buflen
;
3239 memcpy (tuid
, val
, lease
-> uid_len
);
3240 lease
-> uid
= tuid
;
3243 lease
-> uid
= (parse_numeric_aggregate
3244 (cfile
, (unsigned char *)0,
3245 &buflen
, ':', 16, 8));
3246 if (!lease
-> uid
) {
3247 lease_dereference (&lease
, MDL
);
3250 lease
-> uid_len
= buflen
;
3251 lease
-> uid_max
= buflen
;
3252 if (lease
-> uid_len
== 0) {
3253 lease
-> uid
= (unsigned char *)0;
3254 parse_warn (cfile
, "zero-length uid");
3261 if (!lease
-> uid
) {
3262 log_fatal ("No memory for lease uid");
3268 token
= next_token (&val
, (unsigned *)0, cfile
);
3269 if (!is_identifier (token
)) {
3271 skip_to_rbrace (cfile
, 1);
3272 lease_dereference (&lease
, MDL
);
3276 /* for now, we aren't using this. */
3281 parse_hardware_param (cfile
,
3282 &lease
-> hardware_addr
);
3285 case TOKEN_RESERVED
:
3287 lease
->flags
|= RESERVED_LEASE
;
3293 lease
-> flags
|= BOOTP_LEASE
;
3297 /* XXX: Reverse compatibility? */
3298 case TOKEN_ABANDONED
:
3300 lease
-> binding_state
= FTS_ABANDONED
;
3301 lease
-> next_binding_state
= FTS_ABANDONED
;
3307 token
= next_token (&val
, (unsigned *)0, cfile
);
3308 if (token
!= BINDING
) {
3309 parse_warn (cfile
, "expecting 'binding'");
3310 skip_to_semi (cfile
);
3313 goto do_binding_state
;
3317 token
= next_token(&val
, NULL
, cfile
);
3318 if (token
!= BINDING
) {
3319 parse_warn(cfile
, "expecting 'binding'");
3320 skip_to_semi(cfile
);
3323 goto do_binding_state
;
3329 token
= next_token (&val
, (unsigned *)0, cfile
);
3330 if (token
!= STATE
) {
3331 parse_warn (cfile
, "expecting 'state'");
3332 skip_to_semi (cfile
);
3335 token
= next_token (&val
, (unsigned *)0, cfile
);
3337 case TOKEN_ABANDONED
:
3338 new_state
= FTS_ABANDONED
;
3341 new_state
= FTS_FREE
;
3344 new_state
= FTS_ACTIVE
;
3347 new_state
= FTS_EXPIRED
;
3349 case TOKEN_RELEASED
:
3350 new_state
= FTS_RELEASED
;
3353 new_state
= FTS_RESET
;
3356 new_state
= FTS_BACKUP
;
3359 /* RESERVED and BOOTP states preserved for
3360 * compatibleness with older versions.
3362 case TOKEN_RESERVED
:
3363 new_state
= FTS_ACTIVE
;
3364 lease
->flags
|= RESERVED_LEASE
;
3367 new_state
= FTS_ACTIVE
;
3368 lease
->flags
|= BOOTP_LEASE
;
3373 "%s: expecting a binding state.",
3375 skip_to_semi (cfile
);
3379 if (seenbit
== 256) {
3380 lease
-> binding_state
= new_state
;
3383 * Apply default/conservative next/rewind
3384 * binding states if they haven't been set
3385 * yet. These defaults will be over-ridden if
3386 * they are set later in parsing.
3388 if (!(seenmask
& 128))
3389 lease
->next_binding_state
= new_state
;
3391 /* The most conservative rewind state. */
3392 if (!(seenmask
& 512))
3393 lease
->rewind_binding_state
= new_state
;
3394 } else if (seenbit
== 128)
3395 lease
-> next_binding_state
= new_state
;
3396 else if (seenbit
== 512)
3397 lease
->rewind_binding_state
= new_state
;
3399 log_fatal("Impossible condition at %s:%d.",
3405 case CLIENT_HOSTNAME
:
3407 token
= peek_token (&val
, (unsigned *)0, cfile
);
3408 if (token
== STRING
) {
3409 if (!parse_string (cfile
,
3410 &lease
-> client_hostname
,
3412 lease_dereference (&lease
, MDL
);
3416 lease
-> client_hostname
=
3417 parse_host_name (cfile
);
3418 if (lease
-> client_hostname
)
3422 "expecting a hostname.");
3423 skip_to_semi (cfile
);
3424 lease_dereference (&lease
, MDL
);
3432 class = (struct class *)0;
3433 token
= next_token (&val
, (unsigned *)0, cfile
);
3434 if (token
== CLASS
) {
3435 token
= next_token (&val
,
3436 (unsigned *)0, cfile
);
3437 if (token
!= STRING
) {
3438 parse_warn (cfile
, "expecting string");
3440 skip_to_semi (cfile
);
3444 if (lease
-> billing_class
)
3445 class_dereference (&lease
-> billing_class
,
3447 find_class (&class, val
, MDL
);
3450 "unknown class %s", val
);
3452 } else if (token
== SUBCLASS
) {
3453 if (lease
-> billing_class
)
3454 class_dereference (&lease
-> billing_class
,
3456 parse_class_declaration(&class, cfile
, NULL
,
3457 CLASS_TYPE_SUBCLASS
);
3459 parse_warn (cfile
, "expecting \"class\"");
3461 skip_to_semi (cfile
);
3464 class_reference (&lease
-> billing_class
,
3466 class_dereference (&class, MDL
);
3471 on
= (struct executable_statement
*)0;
3473 if (!parse_on_statement (&on
, cfile
, &lose
)) {
3474 skip_to_rbrace (cfile
, 1);
3475 lease_dereference (&lease
, MDL
);
3479 if ((on
->data
.on
.evtypes
& ON_EXPIRY
) &&
3480 on
->data
.on
.statements
) {
3482 executable_statement_reference
3483 (&lease
->on_star
.on_expiry
,
3484 on
->data
.on
.statements
, MDL
);
3486 if ((on
->data
.on
.evtypes
& ON_RELEASE
) &&
3487 on
->data
.on
.statements
) {
3489 executable_statement_reference
3490 (&lease
->on_star
.on_release
,
3491 on
->data
.on
.statements
, MDL
);
3493 executable_statement_dereference (&on
, MDL
);
3500 oc
= (struct option_cache
*)0;
3501 if (parse_option_decl (&oc
, cfile
)) {
3502 if (oc
-> option
-> universe
!=
3505 "agent option expected.");
3506 option_cache_dereference (&oc
, MDL
);
3509 if (!lease
-> agent_options
&&
3510 !(option_chain_head_allocate
3511 (&lease
-> agent_options
, MDL
))) {
3512 log_error ("no memory to stash agent option");
3515 for (p
= &lease
-> agent_options
-> first
;
3516 *p
; p
= &((*p
) -> cdr
))
3519 option_cache_reference (((struct option_cache
**)
3520 &((*p
) -> car
)), oc
, MDL
);
3521 option_cache_dereference (&oc
, MDL
);
3528 token
= next_token (&val
, (unsigned *)0, cfile
);
3529 if (token
!= NAME
&& token
!= NUMBER_OR_NAME
) {
3531 "%s can't be a variable name",
3534 skip_to_semi (cfile
);
3535 lease_dereference (&lease
, MDL
);
3542 binding
= find_binding (lease
-> scope
, val
);
3544 binding
= (struct binding
*)0;
3547 if (!lease
-> scope
)
3548 if (!(binding_scope_allocate
3549 (&lease
-> scope
, MDL
)))
3550 log_fatal ("no memory for scope");
3551 binding
= dmalloc (sizeof *binding
, MDL
);
3553 log_fatal ("No memory for lease %s.",
3555 memset (binding
, 0, sizeof *binding
);
3557 dmalloc (strlen (val
) + 1, MDL
);
3558 if (!binding
-> name
)
3559 log_fatal ("No memory for binding %s.",
3561 strcpy (binding
-> name
, val
);
3568 if (!binding_value_allocate(&nv
, MDL
))
3569 log_fatal("no memory for binding value.");
3572 token
= next_token (&val
, (unsigned *)0, cfile
);
3573 if (token
!= EQUAL
) {
3575 "expecting '=' in set statement.");
3580 if (!parse_binding_value(cfile
, nv
)) {
3581 binding_value_dereference(&nv
, MDL
);
3582 lease_dereference(&lease
, MDL
);
3587 binding_value_reference(&binding
->value
,
3589 binding
->next
= lease
->scope
->bindings
;
3590 lease
->scope
->bindings
= binding
;
3592 binding_value_dereference(&binding
->value
, MDL
);
3593 binding_value_reference(&binding
->value
,
3597 binding_value_dereference(&nv
, MDL
);
3603 if (!strcasecmp (val
, "ddns-fwd-name")) {
3607 } else if (!strcasecmp (val
, "ddns-rev-name")) {
3612 parse_warn(cfile
, "Unexpected configuration "
3614 skip_to_semi (cfile
);
3616 lease_dereference (&lease
, MDL
);
3620 if (seenmask
& seenbit
) {
3622 "Too many %s parameters in lease %s\n",
3623 tbuf
, piaddr (lease
-> ip_addr
));
3625 seenmask
|= seenbit
;
3629 /* If no binding state is specified, make one up. */
3630 if (!(seenmask
& 256)) {
3631 if (lease
->ends
> cur_time
||
3632 lease
->on_star
.on_expiry
|| lease
->on_star
.on_release
)
3633 lease
->binding_state
= FTS_ACTIVE
;
3634 #if defined (FAILOVER_PROTOCOL)
3635 else if (lease
->pool
&& lease
->pool
->failover_peer
)
3636 lease
->binding_state
= FTS_EXPIRED
;
3639 lease
->binding_state
= FTS_FREE
;
3640 if (lease
->binding_state
== FTS_ACTIVE
) {
3641 #if defined (FAILOVER_PROTOCOL)
3642 if (lease
->pool
&& lease
->pool
->failover_peer
)
3643 lease
->next_binding_state
= FTS_EXPIRED
;
3646 lease
->next_binding_state
= FTS_FREE
;
3648 lease
->next_binding_state
= lease
->binding_state
;
3650 /* The most conservative rewind state implies no rewind. */
3651 lease
->rewind_binding_state
= lease
->binding_state
;
3654 if (!(seenmask
& 65536))
3655 lease
->tstp
= lease
->ends
;
3657 lease_reference (lp
, lease
, MDL
);
3658 lease_dereference (&lease
, MDL
);
3662 /* Parse the right side of a 'binding value'.
3664 * set foo = "bar"; is a string
3665 * set foo = false; is a boolean
3666 * set foo = %31; is a numeric value.
3669 parse_binding_value(struct parse
*cfile
, struct binding_value
*value
)
3671 struct data_string
*data
;
3677 if ((cfile
== NULL
) || (value
== NULL
))
3678 log_fatal("Invalid arguments at %s:%d.", MDL
);
3680 token
= peek_token(&val
, NULL
, cfile
);
3681 if (token
== STRING
) {
3682 skip_token(&val
, &buflen
, cfile
);
3684 value
->type
= binding_data
;
3685 value
->value
.data
.len
= buflen
;
3687 data
= &value
->value
.data
;
3689 if (!buffer_allocate(&data
->buffer
, buflen
+ 1, MDL
))
3690 log_fatal ("No memory for binding.");
3692 memcpy(data
->buffer
->data
, val
, buflen
+ 1);
3694 data
->data
= data
->buffer
->data
;
3695 data
->terminated
= 1;
3696 } else if (token
== NUMBER_OR_NAME
) {
3697 value
->type
= binding_data
;
3699 data
= &value
->value
.data
;
3700 s
= parse_numeric_aggregate(cfile
, NULL
, &data
->len
,
3703 skip_to_semi(cfile
);
3708 if (!buffer_allocate(&data
->buffer
, data
->len
+ 1,
3710 log_fatal("No memory for binding.");
3712 memcpy(data
->buffer
->data
, s
, data
->len
);
3713 data
->data
= data
->buffer
->data
;
3717 } else if (token
== PERCENT
) {
3718 skip_token(&val
, NULL
, cfile
);
3719 token
= next_token(&val
, NULL
, cfile
);
3720 if (token
!= NUMBER
) {
3721 parse_warn(cfile
, "expecting decimal number.");
3723 skip_to_semi(cfile
);
3726 value
->type
= binding_numeric
;
3727 value
->value
.intval
= atol(val
);
3728 } else if (token
== NAME
) {
3729 token
= next_token(&val
, NULL
, cfile
);
3730 value
->type
= binding_boolean
;
3731 if (!strcasecmp(val
, "true"))
3732 value
->value
.boolean
= 1;
3733 else if (!strcasecmp(val
, "false"))
3734 value
->value
.boolean
= 0;
3736 parse_warn(cfile
, "expecting true or false");
3738 skip_to_semi(cfile
);
3742 parse_warn (cfile
, "expecting a constant value.");
3744 skip_to_semi (cfile
);
3751 /* address-range-declaration :== ip-address ip-address SEMI
3752 | DYNAMIC_BOOTP ip-address ip-address SEMI */
3754 void parse_address_range (cfile
, group
, type
, inpool
, lpchain
)
3755 struct parse
*cfile
;
3756 struct group
*group
;
3758 struct pool
*inpool
;
3759 struct lease
**lpchain
;
3761 struct iaddr low
, high
, net
;
3762 unsigned char addr
[4];
3763 unsigned len
= sizeof addr
;
3764 enum dhcp_token token
;
3767 struct subnet
*subnet
;
3768 struct shared_network
*share
;
3770 isc_result_t status
;
3772 if ((token
= peek_token (&val
,
3773 (unsigned *)0, cfile
)) == DYNAMIC_BOOTP
) {
3774 skip_token(&val
, (unsigned *)0, cfile
);
3778 /* Get the bottom address in the range... */
3779 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8))
3781 memcpy (low
.iabuf
, addr
, len
);
3784 /* Only one address? */
3785 token
= peek_token (&val
, (unsigned *)0, cfile
);
3789 /* Get the top address in the range... */
3790 if (!parse_numeric_aggregate (cfile
, addr
, &len
, DOT
, 10, 8))
3792 memcpy (high
.iabuf
, addr
, len
);
3796 token
= next_token (&val
, (unsigned *)0, cfile
);
3797 if (token
!= SEMI
) {
3798 parse_warn (cfile
, "semicolon expected.");
3799 skip_to_semi (cfile
);
3803 if (type
== SUBNET_DECL
) {
3804 subnet
= group
-> subnet
;
3805 share
= subnet
-> shared_network
;
3807 share
= group
-> shared_network
;
3808 for (subnet
= share
-> subnets
;
3809 subnet
; subnet
= subnet
-> next_sibling
) {
3810 net
= subnet_number (low
, subnet
-> netmask
);
3811 if (addr_eq (net
, subnet
-> net
))
3815 parse_warn (cfile
, "address range not on network %s",
3816 group
-> shared_network
-> name
);
3817 log_error ("Be sure to place pool statement after %s",
3818 "related subnet declarations.");
3824 struct pool
*last
= (struct pool
*)0;
3826 /* If we're permitting dynamic bootp for this range,
3827 then look for a pool with an empty prohibit list and
3828 a permit list with one entry that permits all clients. */
3829 for (pool
= share
-> pools
; pool
; pool
= pool
-> next
) {
3830 if ((!dynamic
&& !pool
-> permit_list
&&
3831 pool
-> prohibit_list
&&
3832 !pool
-> prohibit_list
-> next
&&
3833 (pool
-> prohibit_list
-> type
==
3834 permit_dynamic_bootp_clients
)) ||
3835 (dynamic
&& !pool
-> prohibit_list
&&
3836 pool
-> permit_list
&&
3837 !pool
-> permit_list
-> next
&&
3838 (pool
-> permit_list
-> type
==
3839 permit_all_clients
))) {
3845 /* If we didn't get a pool, make one. */
3848 status
= pool_allocate (&pool
, MDL
);
3849 if (status
!= ISC_R_SUCCESS
)
3850 log_fatal ("no memory for ad-hoc pool: %s",
3851 isc_result_totext (status
));
3852 p
= new_permit (MDL
);
3854 log_fatal ("no memory for ad-hoc permit.");
3856 /* Dynamic pools permit all clients. Otherwise
3857 we prohibit BOOTP clients. */
3859 p
-> type
= permit_all_clients
;
3860 pool
-> permit_list
= p
;
3862 p
-> type
= permit_dynamic_bootp_clients
;
3863 pool
-> prohibit_list
= p
;
3867 pool_reference (&last
-> next
, pool
, MDL
);
3869 pool_reference (&share
-> pools
, pool
, MDL
);
3870 shared_network_reference (&pool
-> shared_network
,
3872 if (!clone_group (&pool
-> group
, share
-> group
, MDL
))
3873 log_fatal ("no memory for anon pool group.");
3875 pool
= (struct pool
*)0;
3877 pool_reference (&pool
, last
, MDL
);
3879 pool_reference (&pool
, share
-> pools
, MDL
);
3882 pool
= (struct pool
*)0;
3883 pool_reference (&pool
, inpool
, MDL
);
3886 #if defined (FAILOVER_PROTOCOL)
3887 if (pool
-> failover_peer
&& dynamic
) {
3888 /* Doctor, do you think I'm overly sensitive
3889 about getting bug reports I can't fix? */
3890 parse_warn (cfile
, "dynamic-bootp flag is %s",
3891 "not permitted for address");
3892 log_error ("range declarations where there is a failover");
3893 log_error ("peer in scope. If you wish to declare an");
3894 log_error ("address range from which dynamic bootp leases");
3895 log_error ("can be allocated, please declare it within a");
3896 log_error ("pool declaration that also contains the \"no");
3897 log_error ("failover\" statement. The failover protocol");
3898 log_error ("itself does not permit dynamic bootp - this");
3899 log_error ("is not a limitation specific to the ISC DHCP");
3900 log_error ("server. Please don't ask me to defend this");
3901 log_error ("until you have read and really tried %s",
3903 log_error ("the failover protocol specification.");
3905 /* We don't actually bomb at this point - instead,
3906 we let parse_lease_file notice the error and
3907 bomb at that point - it's easier. */
3909 #endif /* FAILOVER_PROTOCOL */
3911 /* Create the new address range... */
3912 new_address_range (cfile
, low
, high
, subnet
, pool
, lpchain
);
3913 pool_dereference (&pool
, MDL
);
3918 add_ipv6_pool_to_subnet(struct subnet
*subnet
, u_int16_t type
,
3919 struct iaddr
*lo_addr
, int bits
, int units
,
3920 struct ipv6_pond
*pond
) {
3921 struct ipv6_pool
*pool
;
3922 struct in6_addr tmp_in6_addr
;
3924 struct ipv6_pool
**tmp
;
3929 if (lo_addr
->len
!= sizeof(tmp_in6_addr
)) {
3930 log_fatal("Internal error: Attempt to add non-IPv6 address "
3931 "to IPv6 shared network.");
3933 memcpy(&tmp_in6_addr
, lo_addr
->iabuf
, sizeof(tmp_in6_addr
));
3935 if (ipv6_pool_allocate(&pool
, type
, &tmp_in6_addr
,
3936 bits
, units
, MDL
) != ISC_R_SUCCESS
) {
3937 log_fatal("Out of memory");
3941 * Add to our global IPv6 pool set.
3943 if (add_ipv6_pool(pool
) != ISC_R_SUCCESS
) {
3944 log_fatal ("Out of memory");
3948 * Link the pool to its network.
3950 pool
->subnet
= NULL
;
3951 subnet_reference(&pool
->subnet
, subnet
, MDL
);
3952 pool
->shared_network
= NULL
;
3953 shared_network_reference(&pool
->shared_network
,
3954 subnet
->shared_network
, MDL
);
3955 pool
->ipv6_pond
= NULL
;
3956 ipv6_pond_reference(&pool
->ipv6_pond
, pond
, MDL
);
3959 * Increase our array size for ipv6_pools in the pond
3961 if (pond
->ipv6_pools
== NULL
) {
3965 while (pond
->ipv6_pools
[num_pools
] != NULL
) {
3969 tmp
= dmalloc(sizeof(struct ipv6_pool
*) * (num_pools
+ 2), MDL
);
3971 log_fatal("Out of memory");
3973 if (num_pools
> 0) {
3974 memcpy(tmp
, pond
->ipv6_pools
,
3975 sizeof(struct ipv6_pool
*) * num_pools
);
3977 if (pond
->ipv6_pools
!= NULL
) {
3978 dfree(pond
->ipv6_pools
, MDL
);
3980 pond
->ipv6_pools
= tmp
;
3983 * Record this pool in our array of pools for this shared network.
3985 ipv6_pool_reference(&pond
->ipv6_pools
[num_pools
], pool
, MDL
);
3986 pond
->ipv6_pools
[num_pools
+1] = NULL
;
3988 /* Update the number of elements in the pond. Conveniently
3989 * we have the total size of the block in bits and the amount
3990 * we would allocate per element in units. For an address units
3991 * will always be 128, for a prefix it will be something else.
3993 * We need to make sure the number of elements isn't too large
3994 * to track. If so, we flag it to avoid wasting time with log
3995 * threshold logic. We also emit a log stating that log-threshold
3996 * will be disabled for the shared-network but that's done
3997 * elsewhere via report_log_threshold().
4001 /* Only bother if we aren't already flagged as jumbo */
4002 if (pond
->jumbo_range
== 0) {
4003 if ((units
- bits
) > (sizeof(isc_uint64_t
) * 8)) {
4004 pond
->jumbo_range
= 1;
4005 pond
->num_total
= POND_TRACK_MAX
;
4008 isc_uint64_t space_left
4009 = POND_TRACK_MAX
- pond
->num_total
;
4011 = (isc_uint64_t
)(1) << (units
- bits
);
4013 if (addon
> space_left
) {
4014 pond
->jumbo_range
= 1;
4015 pond
->num_total
= POND_TRACK_MAX
;
4017 pond
->num_total
+= addon
;
4025 * \brief Find or create a default pond
4027 * Find or create an ipv6_pond on which to attach the ipv6_pools. We
4028 * check the shared network to see if there is a general purpose
4029 * entry - this will have an empty prohibit list and a permit list
4030 * with a single entry that permits all clients. If the shared
4031 * network doesn't have one of them create it and attach it to
4032 * the shared network and the return argument.
4034 * This function is used when we have a range6 or prefix6 statement
4035 * inside a subnet6 statement but outside of a pool6 statement.
4036 * This routine constructs the missing ipv6_pond structure so
4038 * shared_network -> ipv6_pond -> ipv6_pool
4040 * \param[in] group = a pointer to the group structure from which
4041 * we can find the subnet and shared netowrk
4043 * \param[out] ret_pond = a pointer to space for the pointer to
4044 * the structure to return
4050 add_ipv6_pond_to_network(struct group
*group
,
4051 struct ipv6_pond
**ret_pond
) {
4053 struct ipv6_pond
*pond
= NULL
, *last
= NULL
;
4055 isc_result_t status
;
4056 struct shared_network
*shared
= group
->subnet
->shared_network
;
4058 for (pond
= shared
->ipv6_pond
; pond
; pond
= pond
->next
) {
4059 if ((pond
->group
->statements
== group
->statements
) &&
4060 (pond
->prohibit_list
== NULL
) &&
4061 (pond
->permit_list
!= NULL
) &&
4062 (pond
->permit_list
->next
== NULL
) &&
4063 (pond
->permit_list
->type
== permit_all_clients
)) {
4064 ipv6_pond_reference(ret_pond
, pond
, MDL
);
4070 /* no pond available, make one */
4071 status
= ipv6_pond_allocate(&pond
, MDL
);
4072 if (status
!= ISC_R_SUCCESS
)
4073 log_fatal ("no memory for ad-hoc ipv6 pond: %s",
4074 isc_result_totext (status
));
4075 p
= new_permit (MDL
);
4077 log_fatal ("no memory for ad-hoc ipv6 permit.");
4079 /* we permit all clients */
4080 p
->type
= permit_all_clients
;
4081 pond
->permit_list
= p
;
4083 /* and attach the pond to the return argument and the shared network */
4084 ipv6_pond_reference(ret_pond
, pond
, MDL
);
4086 if (shared
->ipv6_pond
)
4087 ipv6_pond_reference(&last
->next
, pond
, MDL
);
4089 ipv6_pond_reference(&shared
->ipv6_pond
, pond
, MDL
);
4091 shared_network_reference(&pond
->shared_network
, shared
, MDL
);
4092 if (!clone_group (&pond
->group
, group
, MDL
))
4093 log_fatal ("no memory for anon pool group.");
4095 ipv6_pond_dereference(&pond
, MDL
);
4100 /* address-range6-declaration :== ip-address6 ip-address6 SEMI
4101 | ip-address6 SLASH number SEMI
4102 | ip-address6 [SLASH number] TEMPORARY SEMI */
4105 parse_address_range6(struct parse
*cfile
,
4106 struct group
*group
,
4107 struct ipv6_pond
*inpond
) {
4108 struct iaddr lo
, hi
;
4110 enum dhcp_token token
;
4112 struct iaddrcidrnetlist
*nets
, net
;
4113 struct iaddrcidrnetlist
*p
;
4114 u_int16_t type
= D6O_IA_NA
;
4115 struct ipv6_pond
*pond
= NULL
;
4117 if (local_family
!= AF_INET6
) {
4118 parse_warn(cfile
, "range6 statement is only supported "
4120 skip_to_semi(cfile
);
4124 /* This is enforced by the caller, this is just a sanity check. */
4125 if (group
->subnet
== NULL
)
4126 log_fatal("Impossible condition at %s:%d.", MDL
);
4129 * Read starting address.
4131 if (!parse_ip6_addr(cfile
, &lo
)) {
4135 /* Make sure starting address is within the subnet */
4136 if (!addr_eq(group
->subnet
->net
,
4137 subnet_number(lo
, group
->subnet
->netmask
))) {
4138 parse_warn(cfile
, "range6 start address is outside the subnet");
4139 skip_to_semi(cfile
);
4144 * zero out the net entry in case we use it
4146 memset(&net
, 0, sizeof(net
));
4147 net
.cidrnet
.lo_addr
= lo
;
4150 * See if we we're using range or CIDR notation or TEMPORARY
4152 token
= peek_token(&val
, NULL
, cfile
);
4153 if (token
== SLASH
) {
4155 * '/' means CIDR notation, so read the bits we want.
4157 skip_token(NULL
, NULL
, cfile
);
4158 token
= next_token(&val
, NULL
, cfile
);
4159 if (token
!= NUMBER
) {
4160 parse_warn(cfile
, "expecting number");
4161 skip_to_semi(cfile
);
4164 net
.cidrnet
.bits
= atoi(val
);
4165 bits
= net
.cidrnet
.bits
;
4166 if ((bits
< 0) || (bits
> 128)) {
4167 parse_warn(cfile
, "networks have 0 to 128 bits");
4168 skip_to_semi(cfile
);
4171 if (bits
< group
->subnet
->prefix_len
) {
4173 "network mask smaller than subnet mask");
4174 skip_to_semi(cfile
);
4177 if (!is_cidr_mask_valid(&net
.cidrnet
.lo_addr
, bits
)) {
4178 parse_warn(cfile
, "network mask too short");
4179 skip_to_semi(cfile
);
4183 * can be temporary (RFC 4941 like)
4185 token
= peek_token(&val
, NULL
, cfile
);
4186 if (token
== TEMPORARY
) {
4188 parse_warn(cfile
, "temporary mask too short");
4190 parse_warn(cfile
, "temporary singleton?");
4191 skip_token(NULL
, NULL
, cfile
);
4197 } else if (token
== TEMPORARY
) {
4199 * temporary (RFC 4941)
4202 skip_token(NULL
, NULL
, cfile
);
4203 net
.cidrnet
.bits
= 64;
4204 if (!is_cidr_mask_valid(&net
.cidrnet
.lo_addr
,
4205 net
.cidrnet
.bits
)) {
4206 parse_warn(cfile
, "network mask too short");
4207 skip_to_semi(cfile
);
4215 * No '/', so we are looking for the end address of
4218 if (!parse_ip6_addr(cfile
, &hi
)) {
4222 /* Make sure ending address is within the subnet */
4223 if (!addr_eq(group
->subnet
->net
,
4224 subnet_number(hi
, group
->subnet
->netmask
))) {
4226 "range6 end address is outside the subnet");
4227 skip_to_semi(cfile
);
4232 * Convert our range to a set of CIDR networks.
4235 if (range2cidr(&nets
, &lo
, &hi
) != ISC_R_SUCCESS
) {
4236 log_fatal("Error converting range to CIDR networks");
4242 * See if we have a pond for this set of pools.
4243 * If the caller supplied one we use it, otherwise
4244 * check the shared network
4247 if (inpond
!= NULL
) {
4248 ipv6_pond_reference(&pond
, inpond
, MDL
);
4250 add_ipv6_pond_to_network(group
, &pond
);
4253 /* Now that we have a pond add the nets we have parsed */
4254 for (p
=nets
; p
!= NULL
; p
=p
->next
) {
4255 add_ipv6_pool_to_subnet(group
->subnet
, type
,
4256 &p
->cidrnet
.lo_addr
,
4257 p
->cidrnet
.bits
, 128, pond
);
4260 /* if we allocated a list free it now */
4262 free_iaddrcidrnetlist(&nets
);
4264 ipv6_pond_dereference(&pond
, MDL
);
4266 token
= next_token(NULL
, NULL
, cfile
);
4267 if (token
!= SEMI
) {
4268 parse_warn(cfile
, "semicolon expected.");
4269 skip_to_semi(cfile
);
4274 /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */
4277 parse_prefix6(struct parse
*cfile
,
4278 struct group
*group
,
4279 struct ipv6_pond
*inpond
) {
4280 struct iaddr lo
, hi
;
4282 enum dhcp_token token
;
4284 struct iaddrcidrnetlist
*nets
;
4285 struct iaddrcidrnetlist
*p
;
4286 struct ipv6_pond
*pond
= NULL
;
4288 if (local_family
!= AF_INET6
) {
4289 parse_warn(cfile
, "prefix6 statement is only supported "
4291 skip_to_semi(cfile
);
4295 /* This is enforced by the caller, so it's just a sanity check. */
4296 if (group
->subnet
== NULL
)
4297 log_fatal("Impossible condition at %s:%d.", MDL
);
4300 * Read starting and ending address.
4302 if (!parse_ip6_addr(cfile
, &lo
)) {
4307 /* Prefixes are not required to be within the subnet, but I'm not
4308 * entirely sure that we won't want to revive this code as a warning
4309 * in the future so I'm ifdeffing it
4312 /* Make sure starting prefix is within the subnet */
4313 if (!addr_eq(group
->subnet
->net
,
4314 subnet_number(lo
, group
->subnet
->netmask
))) {
4315 parse_warn(cfile
, "prefix6 start prefix"
4316 " is outside the subnet");
4317 skip_to_semi(cfile
);
4322 if (!parse_ip6_addr(cfile
, &hi
)) {
4327 /* Prefixes are not required to be within the subnet, but I'm not
4328 * entirely sure that we won't want to revive this code as a warning
4329 * in the future so I'm ifdeffing it
4332 /* Make sure ending prefix is within the subnet */
4333 if (!addr_eq(group
->subnet
->net
,
4334 subnet_number(hi
, group
->subnet
->netmask
))) {
4335 parse_warn(cfile
, "prefix6 end prefix"
4336 " is outside the subnet");
4337 skip_to_semi(cfile
);
4343 * Next is '/' number ';'.
4345 token
= next_token(NULL
, NULL
, cfile
);
4346 if (token
!= SLASH
) {
4347 parse_warn(cfile
, "expecting '/'");
4349 skip_to_semi(cfile
);
4352 token
= next_token(&val
, NULL
, cfile
);
4353 if (token
!= NUMBER
) {
4354 parse_warn(cfile
, "expecting number");
4356 skip_to_semi(cfile
);
4360 if ((bits
<= 0) || (bits
>= 128)) {
4361 parse_warn(cfile
, "networks have 0 to 128 bits (exclusive)");
4366 /* Prefixes are not required to be within the subnet, but I'm not
4367 * entirely sure that we won't want to revive this code as a warning
4368 * in the future so I'm ifdeffing it
4371 if (bits
< group
->subnet
->prefix_len
) {
4372 parse_warn(cfile
, "network mask smaller than subnet mask");
4373 skip_to_semi(cfile
);
4378 if (!is_cidr_mask_valid(&lo
, bits
) ||
4379 !is_cidr_mask_valid(&hi
, bits
)) {
4380 parse_warn(cfile
, "network mask too short");
4381 skip_to_semi(cfile
);
4384 token
= next_token(NULL
, NULL
, cfile
);
4385 if (token
!= SEMI
) {
4386 parse_warn(cfile
, "semicolon expected.");
4387 skip_to_semi(cfile
);
4392 * Convert our range to a set of CIDR networks.
4395 if (range2cidr(&nets
, &lo
, &hi
) != ISC_R_SUCCESS
) {
4396 log_fatal("Error converting prefix to CIDR");
4400 * See if we have a pond for this set of pools.
4401 * If the caller supplied one we use it, otherwise
4402 * check the shared network
4405 if (inpond
!= NULL
) {
4406 ipv6_pond_reference(&pond
, inpond
, MDL
);
4408 add_ipv6_pond_to_network(group
, &pond
);
4411 for (p
= nets
; p
!= NULL
; p
= p
->next
) {
4412 /* Normalize and check. */
4413 if (p
->cidrnet
.bits
== 128) {
4414 p
->cidrnet
.bits
= bits
;
4416 if (p
->cidrnet
.bits
> bits
) {
4417 parse_warn(cfile
, "impossible mask length");
4420 add_ipv6_pool_to_subnet(group
->subnet
, D6O_IA_PD
,
4421 &p
->cidrnet
.lo_addr
,
4422 p
->cidrnet
.bits
, bits
, pond
);
4425 free_iaddrcidrnetlist(&nets
);
4428 /* fixed-prefix6 :== ip6-address SLASH number SEMI */
4431 parse_fixed_prefix6(struct parse
*cfile
, struct host_decl
*host_decl
) {
4432 struct iaddrcidrnetlist
*ia
, **h
;
4433 enum dhcp_token token
;
4437 * Get the head of the fixed-prefix list.
4439 h
= &host_decl
->fixed_prefix
;
4444 while (*h
!= NULL
) {
4449 * Allocate a new iaddrcidrnetlist structure.
4451 ia
= dmalloc(sizeof(*ia
), MDL
);
4453 log_fatal("Out of memory");
4459 if (!parse_ip6_addr(cfile
, &ia
->cidrnet
.lo_addr
)) {
4463 token
= next_token(NULL
, NULL
, cfile
);
4464 if (token
!= SLASH
) {
4466 parse_warn(cfile
, "expecting '/'");
4468 skip_to_semi(cfile
);
4471 token
= next_token(&val
, NULL
, cfile
);
4472 if (token
!= NUMBER
) {
4474 parse_warn(cfile
, "expecting number");
4476 skip_to_semi(cfile
);
4479 token
= next_token(NULL
, NULL
, cfile
);
4480 if (token
!= SEMI
) {
4482 parse_warn(cfile
, "semicolon expected.");
4483 skip_to_semi(cfile
);
4490 ia
->cidrnet
.bits
= atoi(val
);
4491 if ((ia
->cidrnet
.bits
< 0) || (ia
->cidrnet
.bits
> 128)) {
4493 parse_warn(cfile
, "networks have 0 to 128 bits");
4496 if (!is_cidr_mask_valid(&ia
->cidrnet
.lo_addr
, ia
->cidrnet
.bits
)) {
4498 parse_warn(cfile
, "network mask too short");
4511 * \brief Parse a pool6 statement
4513 * Pool statements are used to group declarations and permit & deny information
4514 * with a specific address range. They must be declared within a shared network
4515 * or subnet and there may be multiple pools withing a shared network or subnet.
4516 * Each pool may have a different set of permit or deny options.
4518 * \param[in] cfile = the configuration file being parsed
4519 * \param[in] group = the group structure for this pool
4520 * \param[in] type = the type of the enclosing statement. This must be
4521 * SUBNET_DECL for this function.
4524 * void - This function either parses the statement and updates the structures
4525 * or it generates an error message and possible halts the program if
4526 * it encounters a problem.
4528 void parse_pool6_statement (cfile
, group
, type
)
4529 struct parse
*cfile
;
4530 struct group
*group
;
4533 enum dhcp_token token
;
4536 struct ipv6_pond
*pond
, **p
;
4537 int declaration
= 0;
4538 isc_result_t status
;
4541 status
= ipv6_pond_allocate(&pond
, MDL
);
4542 if (status
!= ISC_R_SUCCESS
)
4543 log_fatal("no memory for pool6: %s",
4544 isc_result_totext (status
));
4546 if (type
== SUBNET_DECL
)
4547 shared_network_reference(&pond
->shared_network
,
4548 group
->subnet
->shared_network
,
4551 parse_warn(cfile
, "pool6s are only valid inside "
4552 "subnet statements.");
4553 ipv6_pond_dereference(&pond
, MDL
);
4554 skip_to_semi(cfile
);
4558 if (clone_group(&pond
->group
, group
, MDL
) == 0)
4559 log_fatal("can't clone pool6 group.");
4561 if (parse_lbrace(cfile
) == 0) {
4562 ipv6_pond_dereference(&pond
, MDL
);
4567 token
= peek_token(&val
, NULL
, cfile
);
4570 skip_token(NULL
, NULL
, cfile
);
4571 parse_address_range6(cfile
, group
, pond
);
4575 skip_token(NULL
, NULL
, cfile
);
4576 parse_prefix6(cfile
, group
, pond
);
4580 skip_token(NULL
, NULL
, cfile
);
4581 get_permit(cfile
, &pond
->permit_list
, 1,
4582 &pond
->valid_from
, &pond
->valid_until
);
4586 skip_token(NULL
, NULL
, cfile
);
4587 get_permit(cfile
, &pond
->prohibit_list
, 0,
4588 &pond
->valid_from
, &pond
->valid_until
);
4592 skip_token(&val
, NULL
, cfile
);
4598 * We can get to END_OF_FILE if, for instance,
4599 * the parse_statement() reads all available tokens
4600 * and leaves us at the end.
4602 parse_warn(cfile
, "unexpected end of file");
4606 declaration
= parse_statement(cfile
, pond
->group
,
4614 * A possible optimization is to see if this pond can be merged into
4615 * an already existing pond. But I'll pass on that for now as we need
4616 * to repoint the leases to the other pond which is annoying. SAR
4620 * Add this pond to the list (will need updating if we add the
4624 p
= &pond
->shared_network
->ipv6_pond
;
4625 for (; *p
; p
= &((*p
)->next
))
4627 ipv6_pond_reference(p
, pond
, MDL
);
4629 /* Don't allow a pool6 declaration with no addresses or
4630 prefixes, since it is probably a configuration error. */
4631 if (pond
->ipv6_pools
== NULL
) {
4632 parse_warn (cfile
, "Pool6 declaration with no %s.",
4633 "address range6 or prefix6");
4634 log_error ("Pool6 declarations must always contain at least");
4635 log_error ("one range6 or prefix6 statement.");
4639 ipv6_pond_dereference(&pond
, MDL
);
4646 /* allow-deny-keyword :== BOOTP
4649 | UNKNOWN_CLIENTS */
4651 int parse_allow_deny (oc
, cfile
, flag
)
4652 struct option_cache
**oc
;
4653 struct parse
*cfile
;
4656 enum dhcp_token token
;
4658 unsigned char rf
= flag
;
4660 struct option
*option
= NULL
;
4661 struct expression
*data
= (struct expression
*)0;
4664 if (!make_const_data (&data
, &rf
, 1, 0, 1, MDL
))
4667 token
= next_token (&val
, (unsigned *)0, cfile
);
4670 code
= SV_ALLOW_BOOTP
;
4674 code
= SV_ALLOW_BOOTING
;
4678 code
= SV_DYNAMIC_BOOTP
;
4681 case UNKNOWN_CLIENTS
:
4682 code
= SV_BOOT_UNKNOWN_CLIENTS
;
4686 code
= SV_DUPLICATES
;
4693 case CLIENT_UPDATES
:
4694 code
= SV_CLIENT_UPDATES
;
4698 code
= SV_LEASEQUERY
;
4702 parse_warn (cfile
, "expecting allow/deny key");
4703 skip_to_semi (cfile
);
4704 expression_dereference (&data
, MDL
);
4707 /* Reference on option is passed to option cache. */
4708 if (!option_code_hash_lookup(&option
, server_universe
.code_hash
,
4710 log_fatal("Unable to find server option %u (%s:%d).",
4712 status
= option_cache(oc
, NULL
, data
, option
, MDL
);
4713 expression_dereference (&data
, MDL
);
4719 parse_ia_na_declaration(struct parse
*cfile
) {
4720 #if !defined(DHCPv6)
4721 parse_warn(cfile
, "No DHCPv6 support.");
4722 skip_to_semi(cfile
);
4723 #else /* defined(DHCPv6) */
4724 enum dhcp_token token
;
4725 struct ia_xx
*ia
= NULL
;
4727 struct ia_xx
*old_ia
;
4730 binding_state_t state
;
4734 struct iasubopt
*iaaddr
;
4735 struct ipv6_pool
*pool
;
4736 char addr_buf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
4737 isc_boolean_t newbinding
;
4738 struct binding_scope
*scope
= NULL
;
4739 struct binding
*bnd
;
4740 struct binding_value
*nv
= NULL
;
4741 struct executable_statement
*on_star
[2] = {NULL
, NULL
};
4744 if (local_family
!= AF_INET6
) {
4745 parse_warn(cfile
, "IA_NA is only supported in DHCPv6 mode.");
4746 skip_to_semi(cfile
);
4750 if (!parse_iaid_duid(cfile
, &ia
, &iaid
, MDL
)) {
4754 ia
->ia_type
= D6O_IA_NA
;
4756 token
= next_token(&val
, NULL
, cfile
);
4757 if (token
!= LBRACE
) {
4758 parse_warn(cfile
, "corrupt lease file; expecting left brace");
4759 skip_to_semi(cfile
);
4764 token
= next_token(&val
, NULL
, cfile
);
4765 if (token
== RBRACE
) break;
4767 if (token
== CLTT
) {
4768 ia
->cltt
= parse_date (cfile
);
4772 if (token
!= IAADDR
) {
4773 parse_warn(cfile
, "corrupt lease file; "
4774 "expecting IAADDR or right brace");
4775 skip_to_semi(cfile
);
4779 if (!parse_ip6_addr(cfile
, &iaddr
)) {
4780 parse_warn(cfile
, "corrupt lease file; "
4781 "expecting IPv6 address");
4782 skip_to_semi(cfile
);
4786 token
= next_token(&val
, NULL
, cfile
);
4787 if (token
!= LBRACE
) {
4788 parse_warn(cfile
, "corrupt lease file; "
4789 "expecting left brace");
4790 skip_to_semi(cfile
);
4798 token
= next_token(&val
, NULL
, cfile
);
4799 if (token
== RBRACE
) break;
4803 /* We hit the end of file and don't know
4804 * what parts of the lease we may be missing
4805 * don't try to salvage the lease
4807 parse_warn(cfile
, "corrupt lease file; "
4808 "unexpected end of file");
4811 /* Lease binding state. */
4813 token
= next_token(&val
, NULL
, cfile
);
4814 if (token
!= STATE
) {
4815 parse_warn(cfile
, "corrupt lease file; "
4817 skip_to_semi(cfile
);
4820 token
= next_token(&val
, NULL
, cfile
);
4822 case TOKEN_ABANDONED
:
4823 state
= FTS_ABANDONED
;
4832 state
= FTS_EXPIRED
;
4834 case TOKEN_RELEASED
:
4835 state
= FTS_RELEASED
;
4843 skip_to_semi(cfile
);
4847 token
= next_token(&val
, NULL
, cfile
);
4848 if (token
!= SEMI
) {
4849 parse_warn(cfile
, "corrupt lease file; "
4855 /* Lease preferred lifetime. */
4856 case PREFERRED_LIFE
:
4857 token
= next_token(&val
, NULL
, cfile
);
4858 if (token
!= NUMBER
) {
4859 parse_warn(cfile
, "%s is not a valid "
4862 skip_to_semi(cfile
);
4865 prefer
= atoi (val
);
4868 * Currently we peek for the semi-colon to
4869 * allow processing of older lease files that
4870 * don't have the semi-colon. Eventually we
4871 * should remove the peeking code.
4873 token
= peek_token(&val
, NULL
, cfile
);
4874 if (token
== SEMI
) {
4875 skip_token(&val
, NULL
, cfile
);
4878 "corrupt lease file; "
4879 "expecting semicolon.");
4883 /* Lease valid lifetime. */
4885 token
= next_token(&val
, NULL
, cfile
);
4886 if (token
!= NUMBER
) {
4887 parse_warn(cfile
, "%s is not a valid "
4890 skip_to_semi(cfile
);
4896 * Currently we peek for the semi-colon to
4897 * allow processing of older lease files that
4898 * don't have the semi-colon. Eventually we
4899 * should remove the peeking code.
4901 token
= peek_token(&val
, NULL
, cfile
);
4902 if (token
== SEMI
) {
4903 skip_token(&val
, NULL
, cfile
);
4906 "corrupt lease file; "
4907 "expecting semicolon.");
4911 /* Lease expiration time. */
4913 end_time
= parse_date(cfile
);
4916 /* Lease binding scopes. */
4918 token
= next_token(&val
, NULL
, cfile
);
4919 if ((token
!= NAME
) &&
4920 (token
!= NUMBER_OR_NAME
)) {
4921 parse_warn(cfile
, "%s is not a valid "
4924 skip_to_semi(cfile
);
4929 bnd
= find_binding(scope
, val
);
4931 if (!binding_scope_allocate(&scope
,
4933 log_fatal("Out of memory for "
4942 bnd
= dmalloc(sizeof(*bnd
),
4945 log_fatal("No memory for "
4949 bnd
->name
= dmalloc(strlen(val
) + 1,
4951 if (bnd
->name
== NULL
) {
4952 log_fatal("No memory for "
4955 strcpy(bnd
->name
, val
);
4957 newbinding
= ISC_TRUE
;
4959 newbinding
= ISC_FALSE
;
4962 if (!binding_value_allocate(&nv
, MDL
)) {
4963 log_fatal("no memory for binding "
4967 token
= next_token(NULL
, NULL
, cfile
);
4968 if (token
!= EQUAL
) {
4969 parse_warn(cfile
, "expecting '=' in "
4974 if (!parse_binding_value(cfile
, nv
)) {
4976 binding_value_dereference(&nv
, MDL
);
4977 binding_scope_dereference(&scope
, MDL
);
4982 binding_value_reference(&bnd
->value
,
4984 bnd
->next
= scope
->bindings
;
4985 scope
->bindings
= bnd
;
4987 binding_value_dereference(&bnd
->value
,
4989 binding_value_reference(&bnd
->value
,
4993 binding_value_dereference(&nv
, MDL
);
5000 * Depending on the user config we may
5001 * have one or two on statements. We
5002 * need to save information about both
5003 * of them until we allocate the
5004 * iasubopt to hold them.
5006 if (on_star
[0] == NULL
) {
5007 if (!parse_on_statement (&on_star
[0],
5014 skip_to_rbrace (cfile
, 1);
5018 if (!parse_on_statement (&on_star
[1],
5025 skip_to_rbrace (cfile
, 1);
5033 parse_warn(cfile
, "corrupt lease file; "
5034 "expecting ia_na contents, "
5036 skip_to_semi(cfile
);
5041 if (state
== FTS_LAST
+1) {
5042 parse_warn(cfile
, "corrupt lease file; "
5043 "missing state in iaaddr");
5046 if (end_time
== -1) {
5047 parse_warn(cfile
, "corrupt lease file; "
5048 "missing end time in iaaddr");
5053 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
5054 log_fatal("Out of memory.");
5056 memcpy(&iaaddr
->addr
, iaddr
.iabuf
, sizeof(iaaddr
->addr
));
5058 iaaddr
->state
= state
;
5059 iaaddr
->prefer
= prefer
;
5060 iaaddr
->valid
= valid
;
5061 if (iaaddr
->state
== FTS_RELEASED
)
5062 iaaddr
->hard_lifetime_end_time
= end_time
;
5064 if (scope
!= NULL
) {
5065 binding_scope_reference(&iaaddr
->scope
, scope
, MDL
);
5066 binding_scope_dereference(&scope
, MDL
);
5070 * Check on both on statements. Because of how we write the
5071 * lease file we know which is which if we have two but it's
5072 * easier to write the code to be independent. We do assume
5073 * that the statements won't overlap.
5076 (i
< 2) && on_star
[i
] != NULL
;
5078 if ((on_star
[i
]->data
.on
.evtypes
& ON_EXPIRY
) &&
5079 on_star
[i
]->data
.on
.statements
) {
5080 executable_statement_reference
5081 (&iaaddr
->on_star
.on_expiry
,
5082 on_star
[i
]->data
.on
.statements
, MDL
);
5084 if ((on_star
[i
]->data
.on
.evtypes
& ON_RELEASE
) &&
5085 on_star
[i
]->data
.on
.statements
) {
5086 executable_statement_reference
5087 (&iaaddr
->on_star
.on_release
,
5088 on_star
[i
]->data
.on
.statements
, MDL
);
5090 executable_statement_dereference (&on_star
[i
], MDL
);
5093 /* find the pool this address is in */
5095 if (find_ipv6_pool(&pool
, D6O_IA_NA
,
5096 &iaaddr
->addr
) != ISC_R_SUCCESS
) {
5097 inet_ntop(AF_INET6
, &iaaddr
->addr
,
5098 addr_buf
, sizeof(addr_buf
));
5099 log_error("No pool found for IA_NA address %s",
5101 iasubopt_dereference(&iaaddr
, MDL
);
5105 if ((pool
->ipv6_pond
->use_eui_64
) &&
5106 (!valid_for_eui_64_pool(pool
, &ia
->iaid_duid
, IAID_LEN
,
5108 log_error("Non EUI-64 lease in EUI-64 pool: %s"
5110 pin6_addr(&iaaddr
->addr
));
5111 iasubopt_dereference(&iaaddr
, MDL
);
5116 /* remove old information */
5117 if (cleanup_lease6(ia_na_active
, pool
,
5118 iaaddr
, ia
) != ISC_R_SUCCESS
) {
5119 inet_ntop(AF_INET6
, &iaaddr
->addr
,
5120 addr_buf
, sizeof(addr_buf
));
5121 parse_warn(cfile
, "duplicate na lease for address %s",
5126 * if we like the lease we add it to our various structues
5127 * otherwise we leave it and it will get cleaned when we
5128 * do the iasubopt_dereference.
5130 if ((state
== FTS_ACTIVE
) || (state
== FTS_ABANDONED
)) {
5131 ia_add_iasubopt(ia
, iaaddr
, MDL
);
5132 ia_reference(&iaaddr
->ia
, ia
, MDL
);
5133 add_lease6(pool
, iaaddr
, end_time
);
5136 iasubopt_dereference(&iaaddr
, MDL
);
5137 ipv6_pool_dereference(&pool
, MDL
);
5141 * If we have an existing record for this IA_NA, remove it.
5144 if (ia_hash_lookup(&old_ia
, ia_na_active
,
5145 (unsigned char *)ia
->iaid_duid
.data
,
5146 ia
->iaid_duid
.len
, MDL
)) {
5147 ia_hash_delete(ia_na_active
,
5148 (unsigned char *)ia
->iaid_duid
.data
,
5149 ia
->iaid_duid
.len
, MDL
);
5150 ia_dereference(&old_ia
, MDL
);
5154 * If we have addresses, add this, otherwise don't bother.
5156 if (ia
->num_iasubopt
> 0) {
5157 ia_hash_add(ia_na_active
,
5158 (unsigned char *)ia
->iaid_duid
.data
,
5159 ia
->iaid_duid
.len
, ia
, MDL
);
5161 ia_dereference(&ia
, MDL
);
5162 #endif /* defined(DHCPv6) */
5166 parse_ia_ta_declaration(struct parse
*cfile
) {
5167 #if !defined(DHCPv6)
5168 parse_warn(cfile
, "No DHCPv6 support.");
5169 skip_to_semi(cfile
);
5170 #else /* defined(DHCPv6) */
5171 enum dhcp_token token
;
5172 struct ia_xx
*ia
= NULL
;
5174 struct ia_xx
*old_ia
;
5177 binding_state_t state
;
5181 struct iasubopt
*iaaddr
;
5182 struct ipv6_pool
*pool
;
5183 char addr_buf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
5184 isc_boolean_t newbinding
;
5185 struct binding_scope
*scope
= NULL
;
5186 struct binding
*bnd
;
5187 struct binding_value
*nv
= NULL
;
5188 struct executable_statement
*on_star
[2] = {NULL
, NULL
};
5191 if (local_family
!= AF_INET6
) {
5192 parse_warn(cfile
, "IA_TA is only supported in DHCPv6 mode.");
5193 skip_to_semi(cfile
);
5197 if (!parse_iaid_duid(cfile
, &ia
, &iaid
, MDL
)) {
5201 ia
->ia_type
= D6O_IA_TA
;
5203 token
= next_token(&val
, NULL
, cfile
);
5204 if (token
!= LBRACE
) {
5205 parse_warn(cfile
, "corrupt lease file; expecting left brace");
5206 skip_to_semi(cfile
);
5211 token
= next_token(&val
, NULL
, cfile
);
5212 if (token
== RBRACE
) break;
5214 if (token
== CLTT
) {
5215 ia
->cltt
= parse_date (cfile
);
5219 if (token
!= IAADDR
) {
5220 parse_warn(cfile
, "corrupt lease file; "
5221 "expecting IAADDR or right brace");
5222 skip_to_semi(cfile
);
5226 if (!parse_ip6_addr(cfile
, &iaddr
)) {
5227 parse_warn(cfile
, "corrupt lease file; "
5228 "expecting IPv6 address");
5229 skip_to_semi(cfile
);
5233 token
= next_token(&val
, NULL
, cfile
);
5234 if (token
!= LBRACE
) {
5235 parse_warn(cfile
, "corrupt lease file; "
5236 "expecting left brace");
5237 skip_to_semi(cfile
);
5245 token
= next_token(&val
, NULL
, cfile
);
5246 if (token
== RBRACE
) break;
5250 /* We hit the end of file and don't know
5251 * what parts of the lease we may be missing
5252 * don't try to salvage the lease
5254 parse_warn(cfile
, "corrupt lease file; "
5255 "unexpected end of file");
5258 /* Lease binding state. */
5260 token
= next_token(&val
, NULL
, cfile
);
5261 if (token
!= STATE
) {
5262 parse_warn(cfile
, "corrupt lease file; "
5264 skip_to_semi(cfile
);
5267 token
= next_token(&val
, NULL
, cfile
);
5269 case TOKEN_ABANDONED
:
5270 state
= FTS_ABANDONED
;
5279 state
= FTS_EXPIRED
;
5281 case TOKEN_RELEASED
:
5282 state
= FTS_RELEASED
;
5290 skip_to_semi(cfile
);
5294 token
= next_token(&val
, NULL
, cfile
);
5295 if (token
!= SEMI
) {
5296 parse_warn(cfile
, "corrupt lease file; "
5302 /* Lease preferred lifetime. */
5303 case PREFERRED_LIFE
:
5304 token
= next_token(&val
, NULL
, cfile
);
5305 if (token
!= NUMBER
) {
5306 parse_warn(cfile
, "%s is not a valid "
5309 skip_to_semi(cfile
);
5312 prefer
= atoi (val
);
5315 * Currently we peek for the semi-colon to
5316 * allow processing of older lease files that
5317 * don't have the semi-colon. Eventually we
5318 * should remove the peeking code.
5320 token
= peek_token(&val
, NULL
, cfile
);
5321 if (token
== SEMI
) {
5322 skip_token(&val
, NULL
, cfile
);
5325 "corrupt lease file; "
5326 "expecting semicolon.");
5330 /* Lease valid lifetime. */
5332 token
= next_token(&val
, NULL
, cfile
);
5333 if (token
!= NUMBER
) {
5334 parse_warn(cfile
, "%s is not a valid "
5337 skip_to_semi(cfile
);
5343 * Currently we peek for the semi-colon to
5344 * allow processing of older lease files that
5345 * don't have the semi-colon. Eventually we
5346 * should remove the peeking code.
5348 token
= peek_token(&val
, NULL
, cfile
);
5349 if (token
== SEMI
) {
5350 skip_token(&val
, NULL
, cfile
);
5353 "corrupt lease file; "
5354 "expecting semicolon.");
5358 /* Lease expiration time. */
5360 end_time
= parse_date(cfile
);
5363 /* Lease binding scopes. */
5365 token
= next_token(&val
, NULL
, cfile
);
5366 if ((token
!= NAME
) &&
5367 (token
!= NUMBER_OR_NAME
)) {
5368 parse_warn(cfile
, "%s is not a valid "
5371 skip_to_semi(cfile
);
5376 bnd
= find_binding(scope
, val
);
5378 if (!binding_scope_allocate(&scope
,
5380 log_fatal("Out of memory for "
5389 bnd
= dmalloc(sizeof(*bnd
),
5392 log_fatal("No memory for "
5396 bnd
->name
= dmalloc(strlen(val
) + 1,
5398 if (bnd
->name
== NULL
) {
5399 log_fatal("No memory for "
5402 strcpy(bnd
->name
, val
);
5404 newbinding
= ISC_TRUE
;
5406 newbinding
= ISC_FALSE
;
5409 if (!binding_value_allocate(&nv
, MDL
)) {
5410 log_fatal("no memory for binding "
5414 token
= next_token(NULL
, NULL
, cfile
);
5415 if (token
!= EQUAL
) {
5416 parse_warn(cfile
, "expecting '=' in "
5421 if (!parse_binding_value(cfile
, nv
)) {
5423 binding_value_dereference(&nv
, MDL
);
5424 binding_scope_dereference(&scope
, MDL
);
5429 binding_value_reference(&bnd
->value
,
5431 bnd
->next
= scope
->bindings
;
5432 scope
->bindings
= bnd
;
5434 binding_value_dereference(&bnd
->value
,
5436 binding_value_reference(&bnd
->value
,
5440 binding_value_dereference(&nv
, MDL
);
5447 * Depending on the user config we may
5448 * have one or two on statements. We
5449 * need to save information about both
5450 * of them until we allocate the
5451 * iasubopt to hold them.
5453 if (on_star
[0] == NULL
) {
5454 if (!parse_on_statement (&on_star
[0],
5461 skip_to_rbrace (cfile
, 1);
5465 if (!parse_on_statement (&on_star
[1],
5472 skip_to_rbrace (cfile
, 1);
5480 parse_warn(cfile
, "corrupt lease file; "
5481 "expecting ia_ta contents, "
5483 skip_to_semi(cfile
);
5488 if (state
== FTS_LAST
+1) {
5489 parse_warn(cfile
, "corrupt lease file; "
5490 "missing state in iaaddr");
5493 if (end_time
== -1) {
5494 parse_warn(cfile
, "corrupt lease file; "
5495 "missing end time in iaaddr");
5500 if (iasubopt_allocate(&iaaddr
, MDL
) != ISC_R_SUCCESS
) {
5501 log_fatal("Out of memory.");
5503 memcpy(&iaaddr
->addr
, iaddr
.iabuf
, sizeof(iaaddr
->addr
));
5505 iaaddr
->state
= state
;
5506 iaaddr
->prefer
= prefer
;
5507 iaaddr
->valid
= valid
;
5508 if (iaaddr
->state
== FTS_RELEASED
)
5509 iaaddr
->hard_lifetime_end_time
= end_time
;
5511 if (scope
!= NULL
) {
5512 binding_scope_reference(&iaaddr
->scope
, scope
, MDL
);
5513 binding_scope_dereference(&scope
, MDL
);
5517 * Check on both on statements. Because of how we write the
5518 * lease file we know which is which if we have two but it's
5519 * easier to write the code to be independent. We do assume
5520 * that the statements won't overlap.
5523 (i
< 2) && on_star
[i
] != NULL
;
5525 if ((on_star
[i
]->data
.on
.evtypes
& ON_EXPIRY
) &&
5526 on_star
[i
]->data
.on
.statements
) {
5527 executable_statement_reference
5528 (&iaaddr
->on_star
.on_expiry
,
5529 on_star
[i
]->data
.on
.statements
, MDL
);
5531 if ((on_star
[i
]->data
.on
.evtypes
& ON_RELEASE
) &&
5532 on_star
[i
]->data
.on
.statements
) {
5533 executable_statement_reference
5534 (&iaaddr
->on_star
.on_release
,
5535 on_star
[i
]->data
.on
.statements
, MDL
);
5537 executable_statement_dereference (&on_star
[i
], MDL
);
5540 /* find the pool this address is in */
5542 if (find_ipv6_pool(&pool
, D6O_IA_TA
,
5543 &iaaddr
->addr
) != ISC_R_SUCCESS
) {
5544 inet_ntop(AF_INET6
, &iaaddr
->addr
,
5545 addr_buf
, sizeof(addr_buf
));
5546 log_error("No pool found for IA_TA address %s",
5548 iasubopt_dereference(&iaaddr
, MDL
);
5552 /* remove old information */
5553 if (cleanup_lease6(ia_ta_active
, pool
,
5554 iaaddr
, ia
) != ISC_R_SUCCESS
) {
5555 inet_ntop(AF_INET6
, &iaaddr
->addr
,
5556 addr_buf
, sizeof(addr_buf
));
5557 parse_warn(cfile
, "duplicate ta lease for address %s",
5562 * if we like the lease we add it to our various structues
5563 * otherwise we leave it and it will get cleaned when we
5564 * do the iasubopt_dereference.
5566 if ((state
== FTS_ACTIVE
) || (state
== FTS_ABANDONED
)) {
5567 ia_add_iasubopt(ia
, iaaddr
, MDL
);
5568 ia_reference(&iaaddr
->ia
, ia
, MDL
);
5569 add_lease6(pool
, iaaddr
, end_time
);
5572 ipv6_pool_dereference(&pool
, MDL
);
5573 iasubopt_dereference(&iaaddr
, MDL
);
5577 * If we have an existing record for this IA_TA, remove it.
5580 if (ia_hash_lookup(&old_ia
, ia_ta_active
,
5581 (unsigned char *)ia
->iaid_duid
.data
,
5582 ia
->iaid_duid
.len
, MDL
)) {
5583 ia_hash_delete(ia_ta_active
,
5584 (unsigned char *)ia
->iaid_duid
.data
,
5585 ia
->iaid_duid
.len
, MDL
);
5586 ia_dereference(&old_ia
, MDL
);
5590 * If we have addresses, add this, otherwise don't bother.
5592 if (ia
->num_iasubopt
> 0) {
5593 ia_hash_add(ia_ta_active
,
5594 (unsigned char *)ia
->iaid_duid
.data
,
5595 ia
->iaid_duid
.len
, ia
, MDL
);
5597 ia_dereference(&ia
, MDL
);
5598 #endif /* defined(DHCPv6) */
5602 parse_ia_pd_declaration(struct parse
*cfile
) {
5603 #if !defined(DHCPv6)
5604 parse_warn(cfile
, "No DHCPv6 support.");
5605 skip_to_semi(cfile
);
5606 #else /* defined(DHCPv6) */
5607 enum dhcp_token token
;
5608 struct ia_xx
*ia
= NULL
;
5610 struct ia_xx
*old_ia
;
5614 binding_state_t state
;
5618 struct iasubopt
*iapref
;
5619 struct ipv6_pool
*pool
;
5620 char addr_buf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
5621 isc_boolean_t newbinding
;
5622 struct binding_scope
*scope
= NULL
;
5623 struct binding
*bnd
;
5624 struct binding_value
*nv
= NULL
;
5625 struct executable_statement
*on_star
[2] = {NULL
, NULL
};
5628 if (local_family
!= AF_INET6
) {
5629 parse_warn(cfile
, "IA_PD is only supported in DHCPv6 mode.");
5630 skip_to_semi(cfile
);
5634 if (!parse_iaid_duid(cfile
, &ia
, &iaid
, MDL
)) {
5638 ia
->ia_type
= D6O_IA_PD
;
5640 token
= next_token(&val
, NULL
, cfile
);
5641 if (token
!= LBRACE
) {
5642 parse_warn(cfile
, "corrupt lease file; expecting left brace");
5643 skip_to_semi(cfile
);
5648 token
= next_token(&val
, NULL
, cfile
);
5649 if (token
== RBRACE
) break;
5651 if (token
== CLTT
) {
5652 ia
->cltt
= parse_date (cfile
);
5656 if (token
!= IAPREFIX
) {
5657 parse_warn(cfile
, "corrupt lease file; expecting "
5658 "IAPREFIX or right brace");
5659 skip_to_semi(cfile
);
5663 if (!parse_ip6_prefix(cfile
, &iaddr
, &plen
)) {
5664 parse_warn(cfile
, "corrupt lease file; "
5665 "expecting IPv6 prefix");
5666 skip_to_semi(cfile
);
5670 token
= next_token(&val
, NULL
, cfile
);
5671 if (token
!= LBRACE
) {
5672 parse_warn(cfile
, "corrupt lease file; "
5673 "expecting left brace");
5674 skip_to_semi(cfile
);
5682 token
= next_token(&val
, NULL
, cfile
);
5683 if (token
== RBRACE
) break;
5687 /* We hit the end of file and don't know
5688 * what parts of the lease we may be missing
5689 * don't try to salvage the lease
5691 parse_warn(cfile
, "corrupt lease file; "
5692 "unexpected end of file");
5695 /* Prefix binding state. */
5697 token
= next_token(&val
, NULL
, cfile
);
5698 if (token
!= STATE
) {
5699 parse_warn(cfile
, "corrupt lease file; "
5701 skip_to_semi(cfile
);
5704 token
= next_token(&val
, NULL
, cfile
);
5706 case TOKEN_ABANDONED
:
5707 state
= FTS_ABANDONED
;
5716 state
= FTS_EXPIRED
;
5718 case TOKEN_RELEASED
:
5719 state
= FTS_RELEASED
;
5727 skip_to_semi(cfile
);
5731 token
= next_token(&val
, NULL
, cfile
);
5732 if (token
!= SEMI
) {
5733 parse_warn(cfile
, "corrupt lease file; "
5739 /* Lease preferred lifetime. */
5740 case PREFERRED_LIFE
:
5741 token
= next_token(&val
, NULL
, cfile
);
5742 if (token
!= NUMBER
) {
5743 parse_warn(cfile
, "%s is not a valid "
5746 skip_to_semi(cfile
);
5749 prefer
= atoi (val
);
5752 * Currently we peek for the semi-colon to
5753 * allow processing of older lease files that
5754 * don't have the semi-colon. Eventually we
5755 * should remove the peeking code.
5757 token
= peek_token(&val
, NULL
, cfile
);
5758 if (token
== SEMI
) {
5759 skip_token(&val
, NULL
, cfile
);
5762 "corrupt lease file; "
5763 "expecting semicolon.");
5767 /* Lease valid lifetime. */
5769 token
= next_token(&val
, NULL
, cfile
);
5770 if (token
!= NUMBER
) {
5771 parse_warn(cfile
, "%s is not a valid "
5774 skip_to_semi(cfile
);
5780 * Currently we peek for the semi-colon to
5781 * allow processing of older lease files that
5782 * don't have the semi-colon. Eventually we
5783 * should remove the peeking code.
5785 token
= peek_token(&val
, NULL
, cfile
);
5786 if (token
== SEMI
) {
5787 skip_token(&val
, NULL
, cfile
);
5790 "corrupt lease file; "
5791 "expecting semicolon.");
5795 /* Prefix expiration time. */
5797 end_time
= parse_date(cfile
);
5800 /* Prefix binding scopes. */
5802 token
= next_token(&val
, NULL
, cfile
);
5803 if ((token
!= NAME
) &&
5804 (token
!= NUMBER_OR_NAME
)) {
5805 parse_warn(cfile
, "%s is not a valid "
5808 skip_to_semi(cfile
);
5813 bnd
= find_binding(scope
, val
);
5815 if (!binding_scope_allocate(&scope
,
5817 log_fatal("Out of memory for "
5826 bnd
= dmalloc(sizeof(*bnd
),
5829 log_fatal("No memory for "
5833 bnd
->name
= dmalloc(strlen(val
) + 1,
5835 if (bnd
->name
== NULL
) {
5836 log_fatal("No memory for "
5839 strcpy(bnd
->name
, val
);
5841 newbinding
= ISC_TRUE
;
5843 newbinding
= ISC_FALSE
;
5846 if (!binding_value_allocate(&nv
, MDL
)) {
5847 log_fatal("no memory for binding "
5851 token
= next_token(NULL
, NULL
, cfile
);
5852 if (token
!= EQUAL
) {
5853 parse_warn(cfile
, "expecting '=' in "
5858 if (!parse_binding_value(cfile
, nv
)) {
5860 binding_value_dereference(&nv
, MDL
);
5861 binding_scope_dereference(&scope
, MDL
);
5866 binding_value_reference(&bnd
->value
,
5868 bnd
->next
= scope
->bindings
;
5869 scope
->bindings
= bnd
;
5871 binding_value_dereference(&bnd
->value
,
5873 binding_value_reference(&bnd
->value
,
5877 binding_value_dereference(&nv
, MDL
);
5884 * Depending on the user config we may
5885 * have one or two on statements. We
5886 * need to save information about both
5887 * of them until we allocate the
5888 * iasubopt to hold them.
5890 if (on_star
[0] == NULL
) {
5891 if (!parse_on_statement (&on_star
[0],
5898 skip_to_rbrace (cfile
, 1);
5902 if (!parse_on_statement (&on_star
[1],
5909 skip_to_rbrace (cfile
, 1);
5917 parse_warn(cfile
, "corrupt lease file; "
5918 "expecting ia_pd contents, "
5920 skip_to_semi(cfile
);
5925 if (state
== FTS_LAST
+1) {
5926 parse_warn(cfile
, "corrupt lease file; "
5927 "missing state in iaprefix");
5930 if (end_time
== -1) {
5931 parse_warn(cfile
, "corrupt lease file; "
5932 "missing end time in iaprefix");
5937 if (iasubopt_allocate(&iapref
, MDL
) != ISC_R_SUCCESS
) {
5938 log_fatal("Out of memory.");
5940 memcpy(&iapref
->addr
, iaddr
.iabuf
, sizeof(iapref
->addr
));
5941 iapref
->plen
= plen
;
5942 iapref
->state
= state
;
5943 iapref
->prefer
= prefer
;
5944 iapref
->valid
= valid
;
5945 if (iapref
->state
== FTS_RELEASED
)
5946 iapref
->hard_lifetime_end_time
= end_time
;
5948 if (scope
!= NULL
) {
5949 binding_scope_reference(&iapref
->scope
, scope
, MDL
);
5950 binding_scope_dereference(&scope
, MDL
);
5954 * Check on both on statements. Because of how we write the
5955 * lease file we know which is which if we have two but it's
5956 * easier to write the code to be independent. We do assume
5957 * that the statements won't overlap.
5960 (i
< 2) && on_star
[i
] != NULL
;
5962 if ((on_star
[i
]->data
.on
.evtypes
& ON_EXPIRY
) &&
5963 on_star
[i
]->data
.on
.statements
) {
5964 executable_statement_reference
5965 (&iapref
->on_star
.on_expiry
,
5966 on_star
[i
]->data
.on
.statements
, MDL
);
5968 if ((on_star
[i
]->data
.on
.evtypes
& ON_RELEASE
) &&
5969 on_star
[i
]->data
.on
.statements
) {
5970 executable_statement_reference
5971 (&iapref
->on_star
.on_release
,
5972 on_star
[i
]->data
.on
.statements
, MDL
);
5974 executable_statement_dereference (&on_star
[i
], MDL
);
5977 /* find the pool this address is in */
5979 if (find_ipv6_pool(&pool
, D6O_IA_PD
,
5980 &iapref
->addr
) != ISC_R_SUCCESS
) {
5981 inet_ntop(AF_INET6
, &iapref
->addr
,
5982 addr_buf
, sizeof(addr_buf
));
5983 log_error("No pool found for prefix %s", addr_buf
);
5984 iasubopt_dereference(&iapref
, MDL
);
5988 /* remove old information */
5989 if (cleanup_lease6(ia_pd_active
, pool
,
5990 iapref
, ia
) != ISC_R_SUCCESS
) {
5991 inet_ntop(AF_INET6
, &iapref
->addr
,
5992 addr_buf
, sizeof(addr_buf
));
5993 parse_warn(cfile
, "duplicate pd lease for address %s",
5998 * if we like the lease we add it to our various structues
5999 * otherwise we leave it and it will get cleaned when we
6000 * do the iasubopt_dereference.
6002 if ((state
== FTS_ACTIVE
) || (state
== FTS_ABANDONED
)) {
6003 ia_add_iasubopt(ia
, iapref
, MDL
);
6004 ia_reference(&iapref
->ia
, ia
, MDL
);
6005 add_lease6(pool
, iapref
, end_time
);
6008 ipv6_pool_dereference(&pool
, MDL
);
6009 iasubopt_dereference(&iapref
, MDL
);
6013 * If we have an existing record for this IA_PD, remove it.
6016 if (ia_hash_lookup(&old_ia
, ia_pd_active
,
6017 (unsigned char *)ia
->iaid_duid
.data
,
6018 ia
->iaid_duid
.len
, MDL
)) {
6019 ia_hash_delete(ia_pd_active
,
6020 (unsigned char *)ia
->iaid_duid
.data
,
6021 ia
->iaid_duid
.len
, MDL
);
6022 ia_dereference(&old_ia
, MDL
);
6026 * If we have prefixes, add this, otherwise don't bother.
6028 if (ia
->num_iasubopt
> 0) {
6029 ia_hash_add(ia_pd_active
,
6030 (unsigned char *)ia
->iaid_duid
.data
,
6031 ia
->iaid_duid
.len
, ia
, MDL
);
6033 ia_dereference(&ia
, MDL
);
6034 #endif /* defined(DHCPv6) */
6039 * When we parse a server-duid statement in a lease file, we are
6040 * looking at the saved server DUID from a previous run. In this case
6041 * we expect it to be followed by the binary representation of the
6042 * DUID stored in a string:
6044 * server-duid "\000\001\000\001\015\221\034JRT\000\0224Y";
6046 * OR as a hex string of digits:
6048 * server-duid 00:01:00:01:1e:68:b3:db:0a:00:27:00:00:02;
6051 parse_server_duid(struct parse
*cfile
) {
6052 struct data_string duid
;
6053 unsigned char bytes
[128]; /* Maximum valid DUID is 128 */
6056 len
= parse_X(cfile
, bytes
, sizeof(bytes
));
6058 parse_warn(cfile
, "Invalid duid contents");
6059 skip_to_semi(cfile
);
6063 memset(&duid
, 0x0, sizeof(duid
));
6064 if (!buffer_allocate(&duid
.buffer
, len
, MDL
)) {
6065 log_fatal("parse_server_duid: out of memory");
6068 memcpy(duid
.buffer
->data
, bytes
, len
);
6070 duid
.data
= duid
.buffer
->data
;
6072 set_server_duid(&duid
);
6073 data_string_forget(&duid
, MDL
);
6079 * When we parse a server-duid statement in a config file, we will
6080 * have the type of the server DUID to generate, and possibly the
6081 * actual value defined.
6084 * server-duid llt ethernet|ieee802|fddi 213982198 00:16:6F:49:7D:9B;
6086 * server-duid ll ethernet|ieee802|fddi 00:16:6F:49:7D:9B;
6087 * server-duid en 2495 "enterprise-specific-identifier-1234";
6090 parse_server_duid_conf(struct parse
*cfile
) {
6091 enum dhcp_token token
;
6094 u_int32_t enterprise_number
;
6096 struct data_string ll_addr
;
6098 struct data_string duid
;
6102 * Consume the SERVER_DUID token.
6104 skip_token(NULL
, NULL
, cfile
);
6107 * Obtain the DUID type.
6109 token
= next_token(&val
, NULL
, cfile
);
6112 * Enterprise is the easiest - enterprise number and raw data
6117 * Get enterprise number and identifier.
6119 token
= next_token(&val
, NULL
, cfile
);
6120 if (token
!= NUMBER
) {
6121 parse_warn(cfile
, "enterprise number expected");
6122 skip_to_semi(cfile
);
6125 enterprise_number
= atoi(val
);
6127 token
= next_token(&val
, &len
, cfile
);
6128 if (token
!= STRING
) {
6129 parse_warn(cfile
, "identifier expected");
6130 skip_to_semi(cfile
);
6137 memset(&duid
, 0, sizeof(duid
));
6138 duid
.len
= 2 + 4 + len
;
6139 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
6140 log_fatal("Out of memory storing DUID");
6142 duid
.data
= (unsigned char *)duid
.buffer
->data
;
6143 putUShort(duid
.buffer
->data
, DUID_EN
);
6144 putULong(duid
.buffer
->data
+ 2, enterprise_number
);
6145 memcpy(duid
.buffer
->data
+ 6, val
, len
);
6147 set_server_duid(&duid
);
6148 data_string_forget(&duid
, MDL
);
6152 * Next easiest is the link-layer DUID. It consists only of
6153 * the LL directive, or optionally the specific value to use.
6155 * If we have LL only, then we set the type. If we have the
6156 * value, then we set the actual DUID.
6158 else if (token
== LL
) {
6159 if (peek_token(NULL
, NULL
, cfile
) == SEMI
) {
6160 set_server_duid_type(DUID_LL
);
6163 * Get our hardware type and address.
6165 token
= next_token(NULL
, NULL
, cfile
);
6168 ll_type
= HTYPE_ETHER
;
6171 ll_type
= HTYPE_IEEE802
;
6174 ll_type
= HTYPE_FDDI
;
6177 parse_warn(cfile
, "hardware type expected");
6178 skip_to_semi(cfile
);
6181 memset(&ll_addr
, 0, sizeof(ll_addr
));
6182 if (!parse_cshl(&ll_addr
, cfile
)) {
6189 memset(&duid
, 0, sizeof(duid
));
6190 duid
.len
= 2 + 2 + ll_addr
.len
;
6191 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
6192 log_fatal("Out of memory storing DUID");
6194 duid
.data
= (unsigned char *)duid
.buffer
->data
;
6195 putUShort(duid
.buffer
->data
, DUID_LL
);
6196 putUShort(duid
.buffer
->data
+ 2, ll_type
);
6197 memcpy(duid
.buffer
->data
+ 4,
6198 ll_addr
.data
, ll_addr
.len
);
6200 set_server_duid(&duid
);
6201 data_string_forget(&duid
, MDL
);
6202 data_string_forget(&ll_addr
, MDL
);
6207 * Finally the link-layer DUID plus time. It consists only of
6208 * the LLT directive, or optionally the specific value to use.
6210 * If we have LLT only, then we set the type. If we have the
6211 * value, then we set the actual DUID.
6213 else if (token
== LLT
) {
6214 if (peek_token(NULL
, NULL
, cfile
) == SEMI
) {
6215 set_server_duid_type(DUID_LLT
);
6218 * Get our hardware type, timestamp, and address.
6220 token
= next_token(NULL
, NULL
, cfile
);
6223 ll_type
= HTYPE_ETHER
;
6226 ll_type
= HTYPE_IEEE802
;
6229 ll_type
= HTYPE_FDDI
;
6232 parse_warn(cfile
, "hardware type expected");
6233 skip_to_semi(cfile
);
6237 token
= next_token(&val
, NULL
, cfile
);
6238 if (token
!= NUMBER
) {
6239 parse_warn(cfile
, "timestamp expected");
6240 skip_to_semi(cfile
);
6243 llt_time
= atoi(val
);
6245 memset(&ll_addr
, 0, sizeof(ll_addr
));
6246 if (!parse_cshl(&ll_addr
, cfile
)) {
6253 memset(&duid
, 0, sizeof(duid
));
6254 duid
.len
= 2 + 2 + 4 + ll_addr
.len
;
6255 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
6256 log_fatal("Out of memory storing DUID");
6258 duid
.data
= (unsigned char *)duid
.buffer
->data
;
6259 putUShort(duid
.buffer
->data
, DUID_LLT
);
6260 putUShort(duid
.buffer
->data
+ 2, ll_type
);
6261 putULong(duid
.buffer
->data
+ 4, llt_time
);
6262 memcpy(duid
.buffer
->data
+ 8,
6263 ll_addr
.data
, ll_addr
.len
);
6265 set_server_duid(&duid
);
6266 data_string_forget(&duid
, MDL
);
6267 data_string_forget(&ll_addr
, MDL
);
6272 * If users want they can use a number for DUID types.
6273 * This is useful for supporting future, not-yet-defined
6276 * In this case, they have to put in the complete value.
6278 * This also works for existing DUID types of course.
6280 else if (token
== NUMBER
) {
6281 duid_type_num
= atoi(val
);
6283 token
= next_token(&val
, &len
, cfile
);
6284 if (token
!= STRING
) {
6285 parse_warn(cfile
, "identifier expected");
6286 skip_to_semi(cfile
);
6293 memset(&duid
, 0, sizeof(duid
));
6295 if (!buffer_allocate(&duid
.buffer
, duid
.len
, MDL
)) {
6296 log_fatal("Out of memory storing DUID");
6298 duid
.data
= (unsigned char *)duid
.buffer
->data
;
6299 putUShort(duid
.buffer
->data
, duid_type_num
);
6300 memcpy(duid
.buffer
->data
+ 2, val
, len
);
6302 set_server_duid(&duid
);
6303 data_string_forget(&duid
, MDL
);
6307 * Anything else is an error.
6310 parse_warn(cfile
, "DUID type of LLT, EN, or LL expected");
6311 skip_to_semi(cfile
);
6316 * Finally consume our trailing semicolon.
6318 token
= next_token(NULL
, NULL
, cfile
);
6319 if (token
!= SEMI
) {
6320 parse_warn(cfile
, "semicolon expected");
6321 skip_to_semi(cfile
);
6326 * \brief Creates a byte-order corrected uint32 from a buffer
6328 * This function creates an integer value from a buffer, converting from
6329 * the byte order specified by authoring-byte-order to the current server's
6330 * byte order if they are different. The conversion works in either direction.
6332 * If the parameter, authoring-byte-order hasn't yet been encountered we will
6333 * emit a warning and then default the byte order to match the current server's
6334 * byte order (i.e. no conversion will done).
6336 * \param source buffer containing the "raw" four byte data
6337 * \return uint32_t containing the corrected value
6339 uint32_t parse_byte_order_uint32(const void *source
) {
6342 /* use memcpy to avoid any alignment monkey business */
6343 memcpy(&value
, source
, 4);
6345 if (authoring_byte_order
== 0) {
6346 log_error ("WARNING: "
6347 "authoring-byte-order not in the lease file.\n"
6348 "Assuming file byte order matches this server.\n");
6349 authoring_byte_order
= DHCP_BYTE_ORDER
;
6352 if (authoring_byte_order
!= DHCP_BYTE_ORDER
) {
6353 value
= (((value
>> 24) & 0xff) | // move byte 3 to byte 0
6354 ((value
<< 8) & 0xff0000) | // move byte 1 to byte 2
6355 ((value
>> 8) & 0xff00) | // move byte 2 to byte 1
6356 ((value
<< 24) & 0xff000000)); // byte 0 to byte 3
6362 /* !brief Parses an iaid/duid string into an iaid and struct ia
6364 * Given a string containing the iaid-duid value read from the file,
6365 * and using the format specified by input lease-id-format, convert
6366 * it into an IAID value and an ia_xx struct.
6368 * \param cfile - file being parsed
6369 * \param ia - pointer in which to store the allocated ia_xx struct
6370 * \param iaid - pointer in which to return the IAID value
6371 * \param file - source file name of invocation
6372 * \param line - line numbe of invocation
6374 * \return 0 if parsing fails, non-zero otherwise
6377 parse_iaid_duid(struct parse
* cfile
, struct ia_xx
** ia
, u_int32_t
*iaid
,
6378 const char* file
, int line
) {
6379 unsigned char bytes
[132]; /* Maximum valid IAID-DUID is 132 */
6383 log_error("parse_iaid_duid: ia ptr cannot be null");
6388 len
= parse_X(cfile
, bytes
, sizeof(bytes
));
6390 parse_warn(cfile
, "corrupt lease file; "
6391 "iaid+ia_xx string too short");
6392 skip_to_semi(cfile
);
6396 /* Extract the IAID from the front */
6397 *iaid
= parse_byte_order_uint32(bytes
);
6399 /* Instantiate the ia_xx */
6400 if (ia_allocate(ia
, *iaid
, (const char*)bytes
+ 4, len
- 4, file
, line
)
6402 log_fatal("parse_iaid_duid:Out of memory.");