xref: /netbsd-src/external/mpl/dhcp/dist/keama/eval.c (revision f407d9293b6650aa8c33d6a995f797bb6aaefd90)
1 /*	$NetBSD: eval.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2017-2022 Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  *   Internet Systems Consortium, Inc.
19  *   PO Box 360
20  *   Newmarket, NH 03857 USA
21  *   <info@isc.org>
22  *   https://www.isc.org/
23  *
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: eval.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
28 
29 #include "keama.h"
30 
31 #include <sys/errno.h>
32 #include <sys/types.h>
33 #include <arpa/inet.h>
34 #include <ctype.h>
35 #include <netdb.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 static struct element *eval_equal_expression(struct element *,
42 					     struct element *);
43 static isc_boolean_t cmp_hexa(struct element *, isc_boolean_t,
44 			      struct element *,isc_boolean_t);
45 static void debug(const char* fmt, ...);
46 
47 struct element *
eval_expression(struct element * expr,isc_boolean_t * modifiedp)48 eval_expression(struct element *expr, isc_boolean_t *modifiedp)
49 {
50 	if ((expr->type == ELEMENT_BOOLEAN) ||
51 	    (expr->type == ELEMENT_INTEGER) ||
52 	    (expr->type == ELEMENT_STRING))
53 		return expr;
54 
55 	if (is_boolean_expression(expr))
56 		return eval_boolean_expression(expr, modifiedp);
57 	if (is_numeric_expression(expr))
58 		return eval_numeric_expression(expr, modifiedp);
59 	if (is_data_expression(expr))
60 		return eval_data_expression(expr, modifiedp);
61 	debug("can't type expression");
62 	return expr;
63 }
64 
65 /*
66  * boolean_expression :== CHECK STRING |
67  *                        NOT boolean-expression |
68  *                        data-expression EQUAL data-expression |
69  *                        data-expression BANG EQUAL data-expression |
70  *                        data-expression REGEX_MATCH data-expression |
71  *                        boolean-expression AND boolean-expression |
72  *                        boolean-expression OR boolean-expression
73  *                        EXISTS OPTION-NAME
74  */
75 
76 struct element *
eval_boolean_expression(struct element * expr,isc_boolean_t * modifiedp)77 eval_boolean_expression(struct element *expr, isc_boolean_t *modifiedp)
78 {
79 	/* trivial case: already done */
80 	if (expr->type == ELEMENT_BOOLEAN)
81 		return expr;
82 
83 	/*
84 	 * From is_boolean_expression
85 	 */
86 
87 	if (expr->type != ELEMENT_MAP)
88 		return expr;
89 
90 
91 	/* check */
92 	if (mapContains(expr, "check"))
93 		/*
94 		 * syntax := { "check": <collection_name> }
95 		 * semantic: check_collection
96 		 *  on server try to match classes of the collection
97 		 */
98 		return expr;
99 
100 
101 	/* exists */
102 	if (mapContains(expr, "exists"))
103 		/*
104 		 * syntax := { "exists":
105 		 *             { "universe": <option_space_old>,
106 		 *               "name":  <option_name> }
107 		 *           }
108 		 * semantic: check universe/code from incoming packet
109 		 */
110 		return expr;
111 
112 	/* variable-exists */
113 	if (mapContains(expr, "variable-exists"))
114 		/*
115 		 * syntax := { "variable-exists": <variable_name> }
116 		 * semantics: find_binding(scope, name)
117 		 */
118 		return expr;
119 
120 	/* equal */
121 	if (mapContains(expr, "equal")) {
122 		/*
123 		 * syntax := { "equal":
124 		 *             { "left":  <expression>,
125 		 *               "right": <expression> }
126 		 *           }
127 		 * semantics: evaluate branches and return true
128 		 * if same type and same value
129 		 */
130 		struct element *arg;
131 		struct element *left;
132 		struct element *right;
133 		struct element *equal;
134 		struct comments comments;
135 		isc_boolean_t lmodified = ISC_FALSE;
136 		isc_boolean_t rmodified = ISC_FALSE;
137 
138 		arg = mapGet(expr, "equal");
139 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
140 			return expr;
141 		left = mapGet(arg, "left");
142 		if (left == NULL)
143 			return expr;
144 		right = mapGet(arg, "right");
145 		if (right == NULL)
146 			return expr;
147 		left = eval_expression(left, &lmodified);
148 		if (lmodified) {
149 			mapRemove(arg, "left");
150 			mapSet(arg, left, "left");
151 		}
152 		right = eval_expression(right, &rmodified);
153 		if (rmodified) {
154 			mapRemove(arg, "right");
155 			mapSet(arg, right, "right");
156 		}
157 
158 		equal = eval_equal_expression(left, right);
159 		if ((equal == NULL) || (equal->type != ELEMENT_BOOLEAN))
160 			return expr;
161 		*modifiedp = ISC_TRUE;
162 		TAILQ_INIT(&comments);
163 		TAILQ_CONCAT(&comments, &expr->comments);
164 		TAILQ_CONCAT(&comments, &arg->comments);
165 		TAILQ_CONCAT(&comments, &equal->comments);
166 		TAILQ_CONCAT(&equal->comments, &comments);
167 		return equal;
168 	}
169 
170 	/* not-equal */
171 	if (mapContains(expr, "not-equal")) {
172 		/*
173 		 * syntax := { "not-equal":
174 		 *             { "left":  <expression>,
175                  *               "right": <expression> }
176                  *           }
177                  * semantics: evaluate branches and return true
178                  * if different type or different value
179                  */
180 		struct element *arg;
181 		struct element *left;
182 		struct element *right;
183 		struct element *equal;
184 		struct element *result;
185 		isc_boolean_t lmodified = ISC_FALSE;
186 		isc_boolean_t rmodified = ISC_FALSE;
187 
188 		arg = mapGet(expr, "not-equal");
189 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
190 			return expr;
191 		left = mapGet(arg, "left");
192 		if (left == NULL)
193 			return expr;
194 		right = mapGet(arg, "right");
195 		if (right == NULL)
196 			return expr;
197 		left = eval_expression(left, &lmodified);
198 		if (lmodified) {
199 			mapRemove(arg, "left");
200 			mapSet(arg, left, "left");
201 		}
202 		right = eval_expression(right, &rmodified);
203 		if (rmodified) {
204 			mapRemove(arg, "right");
205 			mapSet(arg, right, "right");
206 		}
207 
208 		equal = eval_equal_expression(left, right);
209 		if ((equal == NULL) || (equal->type != ELEMENT_BOOLEAN))
210 			return expr;
211 		*modifiedp = ISC_TRUE;
212 		result = createBool(ISC_TF(!boolValue(equal)));
213 		TAILQ_CONCAT(&result->comments, &expr->comments);
214 		TAILQ_CONCAT(&result->comments, &arg->comments);
215 		TAILQ_CONCAT(&result->comments, &equal->comments);
216 		return result;
217 	}
218 
219 	/* regex-match */
220 	if (mapContains(expr, "regex-match"))
221 		/*
222 		 * syntax := { "regex-match":
223 		 *             { "left":  <data_expression>,
224 		 *               "right": <data_expression> }
225 		 *           }
226 		 * semantics: evaluate branches, compile right as a
227 		 * regex and apply it to left
228 		 */
229 		return expr;
230 
231 	/* iregex-match */
232 	if (mapContains(expr, "iregex-match"))
233 		/*
234 		 * syntax := { "regex-match":
235 		 *             { "left":  <data_expression>,
236 		 *               "right": <data_expression> }
237 		 *           }
238 		 * semantics: evaluate branches, compile right as a
239 		 * case insensistive regex and apply it to left
240 		 */
241 		return expr;
242 
243 	/* and */
244 	if (mapContains(expr, "and")) {
245 		/*
246 		 * syntax := { "and":
247 		 *             { "left":  <boolean_expression>,
248 		 *               "right": <boolean_expression> }
249 		 *           }
250 		 * semantics: evaluate branches, return true
251 		 * if both are true
252 		 */
253 		struct element *arg;
254 		struct element *left;
255 		struct element *right;
256 		struct element *result;
257 		isc_boolean_t lmodified = ISC_FALSE;
258 		isc_boolean_t rmodified = ISC_FALSE;
259 
260 		arg = mapGet(expr, "and");
261 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
262 			return expr;
263 		left = mapGet(arg, "left");
264 		if (left == NULL)
265 			return expr;
266 		right = mapGet(arg, "right");
267 		if (right == NULL)
268 			debug("can't get and right branch");
269 		left = eval_boolean_expression(left, &lmodified);
270 		if (lmodified) {
271 			mapRemove(arg, "left");
272 			mapSet(arg, left, "left");
273 		}
274 		right = eval_boolean_expression(right, &rmodified);
275 		if (rmodified) {
276 			mapRemove(arg, "right");
277 			mapSet(arg, right, "right");
278 		}
279 
280 		if (left->type == ELEMENT_BOOLEAN) {
281 			*modifiedp = ISC_TRUE;
282 			if (!boolValue(left))
283 				result = createBool(ISC_FALSE);
284 			else {
285 				result = copy(right);
286 				TAILQ_INIT(&result->comments);
287 			}
288 			TAILQ_CONCAT(&result->comments, &expr->comments);
289 			TAILQ_CONCAT(&result->comments, &arg->comments);
290 			TAILQ_CONCAT(&result->comments, &left->comments);
291 			TAILQ_CONCAT(&result->comments, &right->comments);
292 			return result;
293 		}
294 		if (right->type == ELEMENT_BOOLEAN) {
295 			*modifiedp = ISC_TRUE;
296 			if (!boolValue(right))
297 				result = createBool(ISC_FALSE);
298 			else {
299 				result = copy(left);
300 				TAILQ_INIT(&result->comments);
301 			}
302 			TAILQ_CONCAT(&result->comments, &expr->comments);
303 			TAILQ_CONCAT(&result->comments, &arg->comments);
304 			TAILQ_CONCAT(&result->comments, &left->comments);
305 			TAILQ_CONCAT(&result->comments, &right->comments);
306 			return result;
307 		}
308 		return expr;
309 	}
310 
311 	/* or */
312 	if (mapContains(expr, "or")) {
313 		/*
314 		 * syntax := { "or":
315 		 *             { "left":  <boolean_expression>,
316 		 *               "right": <boolean_expression> }
317 		 *           }
318 		 * semantics: evaluate branches, return true
319 		 * if any is true
320 		 */
321 		struct element *arg;
322 		struct element *left;
323 		struct element *right;
324 		struct element *result;
325 		isc_boolean_t lmodified = ISC_FALSE;
326 		isc_boolean_t rmodified = ISC_FALSE;
327 
328 		arg = mapGet(expr, "or");
329 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
330 			return expr;
331 		left = mapGet(arg, "left");
332 		if (left == NULL)
333 			return expr;
334 		right = mapGet(arg, "right");
335 		if (right == NULL)
336 			return expr;
337 		left = eval_boolean_expression(left, &lmodified);
338 		if (lmodified) {
339 			mapRemove(arg, "left");
340 			mapSet(arg, left, "left");
341 		}
342 		right = eval_boolean_expression(right, &rmodified);
343 		if (rmodified) {
344 			mapRemove(arg, "right");
345 			mapSet(arg, right, "right");
346 		}
347 
348 		if (left->type == ELEMENT_BOOLEAN) {
349 			*modifiedp = ISC_TRUE;
350 			if (boolValue(left))
351 				result = createBool(ISC_TRUE);
352 			else {
353 				result = copy(right);
354 				TAILQ_INIT(&result->comments);
355 			}
356 			TAILQ_CONCAT(&result->comments, &expr->comments);
357 			TAILQ_CONCAT(&result->comments, &arg->comments);
358 			TAILQ_CONCAT(&result->comments, &left->comments);
359 			TAILQ_CONCAT(&result->comments, &right->comments);
360 			return result;
361 		}
362 		if (right->type == ELEMENT_BOOLEAN) {
363 			*modifiedp = ISC_TRUE;
364 			if (boolValue(right))
365 				result = createBool(ISC_TRUE);
366 			else {
367 				result = copy(left);
368 				TAILQ_INIT(&result->comments);
369 			}
370 			TAILQ_CONCAT(&result->comments, &expr->comments);
371 			TAILQ_CONCAT(&result->comments, &arg->comments);
372 			TAILQ_CONCAT(&result->comments, &left->comments);
373 			TAILQ_CONCAT(&result->comments, &right->comments);
374 			return result;
375 		}
376 		return expr;
377 	}
378 
379 	/* not */
380 	if (mapContains(expr, "not")) {
381 		/*
382 		 * syntax := { "not": <boolean_expression> }
383 		 * semantic: evaluate its branch and return its negation
384 		 */
385 		struct element *arg;
386 		struct element *result;
387 		isc_boolean_t modified = ISC_FALSE;
388 
389 		arg = mapGet(expr, "not");
390 		if (arg == NULL)
391 			return expr;
392 		arg = eval_boolean_expression(arg, &modified);
393 		if (modified) {
394 			mapRemove(expr, "not");
395 			mapSet(expr, arg, "not");
396 		}
397 
398 		/* remove double not */
399 		if ((arg->type == ELEMENT_MAP) && mapContains(arg, "not")) {
400 			arg = mapGet(arg, "not");
401 			if (arg == NULL)
402 				return expr;
403 			*modifiedp = ISC_TRUE;
404 			return arg;
405 		}
406 
407 		/* compose with equal */
408 		if ((arg->type == ELEMENT_MAP) &&
409 		    mapContains(arg, "equal")) {
410 			arg = mapGet(arg, "equal");
411 			if (arg == NULL)
412 				return expr;
413 			*modifiedp = ISC_TRUE;
414 			result = createMap();
415 			mapSet(result, arg, "not-equal");
416 			return result;
417 		}
418 
419 		/* compose with not-equal */
420 		if ((arg->type == ELEMENT_MAP) &&
421 		    mapContains(arg, "not-equal")) {
422 			arg = mapGet(arg, "not-equal");
423 			if (arg == NULL)
424 				return expr;
425 			*modifiedp = ISC_TRUE;
426 			result = createMap();
427 			mapSet(result, arg, "equal");
428 			return result;
429 		}
430 
431 		if (arg->type != ELEMENT_BOOLEAN)
432 			return expr;
433 		*modifiedp = ISC_TRUE;
434 		result = createBool(ISC_TF(!boolValue(arg)));
435 		TAILQ_CONCAT(&result->comments, &expr->comments);
436 		TAILQ_CONCAT(&result->comments, &arg->comments);
437 		return result;
438 	}
439 
440 	/* known */
441 	if (mapContains(expr, "known"))
442 		/*
443 		 * syntax := { "known": null }
444 		 * semantics: client is known, i.e., has a matching
445 		 * host declaration (aka reservation in Kea)
446 		 */
447 		return expr;
448 
449 	/* static */
450 	if (mapContains(expr, "static"))
451 		/*
452 		 * syntax := { "static": null }
453 		 * semantics: lease is static (doesn't exist in Kea)
454 		 */
455 		return expr;
456 
457 	return expr;
458 }
459 
460 /*
461  * data_expression :== SUBSTRING LPAREN data-expression COMMA
462  *                                      numeric-expression COMMA
463  *                                      numeric-expression RPAREN |
464  *                     CONCAT LPAREN data-expression COMMA
465  *                                      data-expression RPAREN
466  *                     SUFFIX LPAREN data_expression COMMA
467  *                                   numeric-expression RPAREN |
468  *                     LCASE LPAREN data_expression RPAREN |
469  *                     UCASE LPAREN data_expression RPAREN |
470  *                     OPTION option_name |
471  *                     HARDWARE |
472  *                     PACKET LPAREN numeric-expression COMMA
473  *                                   numeric-expression RPAREN |
474  *                     V6RELAY LPAREN numeric-expression COMMA
475  *                                    data-expression RPAREN |
476  *                     STRING |
477  *                     colon_separated_hex_list
478  */
479 
480 struct element *
eval_data_expression(struct element * expr,isc_boolean_t * modifiedp)481 eval_data_expression(struct element *expr, isc_boolean_t *modifiedp)
482 {
483 	/* trivial case: already done */
484 	if (expr->type == ELEMENT_STRING)
485 		return expr;
486 
487 	/*
488 	 * From is_data_expression
489 	 */
490 
491 	if (expr->type != ELEMENT_MAP)
492 		return expr;
493 
494 	/* substring */
495 	if (mapContains(expr, "substring")) {
496 		/*
497 		 * syntax := { "substring":
498 		 *             { "expression": <data_expression>,
499 		 *               "offset":     <numeric_expression>,
500 		 *               "length":     <numeric_expression> }
501 		 *           }
502 		 * semantic: evaluate arguments, if the string is
503 		 * shorter than offset return "" else return substring
504 		 */
505 		struct element *arg;
506 		struct element *string;
507 		struct element *offset;
508 		struct element *length;
509 		struct element *result;
510 		struct string *s;
511 		struct string *r;
512 		int64_t off;
513 		int64_t len;
514 		isc_boolean_t smodified = ISC_FALSE;
515 		isc_boolean_t omodified = ISC_FALSE;
516 		isc_boolean_t lmodified = ISC_FALSE;
517 
518 		arg = mapGet(expr, "substring");
519 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
520 			return expr;
521 		string = mapGet(arg, "expression");
522 		if (string == NULL)
523 			return expr;
524 		offset = mapGet(arg, "offset");
525 		if (offset  == NULL)
526 			return expr;
527 		length = mapGet(arg, "length");
528 		if (length  == NULL)
529 			return expr;
530 		string = eval_data_expression(string, &smodified);
531 		if (smodified) {
532 			mapRemove(arg, "expression");
533 			mapSet(arg, string, "expression");
534 		}
535 		offset = eval_numeric_expression(offset, &omodified);
536 		if (omodified) {
537 			mapRemove(arg, "offset");
538 			mapSet(arg, offset, "offset");
539 		}
540 		length = eval_numeric_expression(length, &lmodified);
541 		if (lmodified) {
542 			mapRemove(arg, "length");
543 			mapSet(arg, length, "length");
544 		}
545 
546 		if ((offset->type != ELEMENT_INTEGER) ||
547 		    (length->type != ELEMENT_INTEGER))
548 			return expr;
549 		off = intValue(offset);
550 		len = intValue(length);
551 		if ((off < 0) || (len < 0))
552 			return expr;
553 		/* degenerated case */
554 		if (len == 0) {
555 			*modifiedp = ISC_TRUE;
556 			r = allocString();
557 			result = createString(r);
558 			return result;
559 		}
560 
561 		/* return (part of) hw-address? */
562 		if ((local_family == AF_INET) &&
563 		    (string->type == ELEMENT_MAP) &&
564 		    mapContains(string, "concat") &&
565 		    (off >= 1)) {
566 			struct element *concat;
567 			struct element *left;
568 			struct element *right;
569 
570 			concat = mapGet(string, "concat");
571 			if (concat->type != ELEMENT_MAP)
572 				return expr;
573 			left = mapGet(concat, "left");
574 			if (left == NULL)
575 				return expr;
576 			right = mapGet(concat, "right");
577 			if (right == NULL)
578 				return expr;
579 			/* from substring(hardware, ...) */
580 			if ((left->type == ELEMENT_MAP) &&
581 			    mapContains(left, "hw-type")) {
582 				*modifiedp = ISC_TRUE;
583 				mapRemove(arg, "expression");
584 				mapSet(arg, right, "expression");
585 				mapRemove(arg, "offset");
586 				mapSet(arg, createInt(off - 1), "offset");
587 				return expr;
588 			}
589 			return expr;
590 		}
591 
592 		/* return hw-type? */
593 		if ((local_family == AF_INET) &&
594 		    (string->type == ELEMENT_MAP) &&
595 		    mapContains(string, "concat") &&
596 		    (off == 0) && (len == 1)) {
597 			struct element *concat;
598 			struct element *left;
599 			struct element *right;
600 
601 			concat = mapGet(string, "concat");
602 			if (concat->type != ELEMENT_MAP)
603 				return expr;
604 			left = mapGet(concat, "left");
605 			if (left == NULL)
606 				return expr;
607 			right = mapGet(concat, "right");
608 			if (right == NULL)
609 				return expr;
610 			/* from substring(hardware, ...) */
611 			if ((left->type == ELEMENT_MAP) &&
612 			    mapContains(left, "hw-type")) {
613 				*modifiedp = ISC_TRUE;
614 				return left;
615 			}
616 			return expr;
617 		}
618 
619 		if (string->type != ELEMENT_STRING)
620 			return expr;
621 		*modifiedp = ISC_TRUE;
622 		s = stringValue(string);
623 		if (s->length <= off)
624 			r = allocString();
625 		else {
626 			r = makeString(s->length - off, s->content + off);
627 			if (r->length > len)
628 				r->length = len;
629 		}
630 		result = createString(r);
631 		TAILQ_CONCAT(&result->comments, &expr->comments);
632 		TAILQ_CONCAT(&result->comments, &arg->comments);
633 		TAILQ_CONCAT(&result->comments, &string->comments);
634 		TAILQ_CONCAT(&result->comments, &offset->comments);
635 		TAILQ_CONCAT(&result->comments, &length->comments);
636 		return result;
637 	}
638 
639 	/* suffix */
640 	if (mapContains(expr, "suffix")) {
641 		/*
642 		 * syntax := { "suffix":
643 		 *             { "expression": <data_expression>,
644 		 *               "length":     <numeric_expression> }
645 		 *           }
646 		 * semantic: evaluate arguments, if the string is
647 		 * shorter than length return it else return suffix
648 		 */
649 		struct element *arg;
650 		struct element *string;
651 		struct element *length;
652 		struct element *result;
653 		struct string *r;
654 		int64_t len;
655 		isc_boolean_t smodified = ISC_FALSE;
656 		isc_boolean_t lmodified = ISC_FALSE;
657 
658 		arg = mapGet(expr, "suffix");
659 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
660 			return expr;
661 		string = mapGet(arg, "expression");
662 		if (string == NULL)
663 			return expr;
664 		length = mapGet(arg, "length");
665 		if (length  == NULL)
666 			return expr;
667 		string = eval_data_expression(string, &smodified);
668 		if (smodified) {
669 			mapRemove(arg, "expression");
670 			mapSet(arg, string, "expression");
671 		}
672 		length = eval_numeric_expression(length, &lmodified);
673 		if (lmodified) {
674 			mapRemove(arg, "length");
675 			mapSet(arg, length, "length");
676 		}
677 
678 		if ((string->type != ELEMENT_STRING) ||
679 		    (length->type != ELEMENT_INTEGER))
680 			return expr;
681 		len = intValue(length);
682 		if (len < 0)
683 			return expr;
684 		*modifiedp = ISC_TRUE;
685 		r = stringValue(string);
686 		if (r->length > len)
687 			r = makeString(r->length - len, r->content + len);
688 		result = createString(r);
689 		TAILQ_CONCAT(&result->comments, &expr->comments);
690 		TAILQ_CONCAT(&result->comments, &arg->comments);
691 		TAILQ_CONCAT(&result->comments, &string->comments);
692 		TAILQ_CONCAT(&result->comments, &length->comments);
693 		return result;
694 	}
695 
696 	/* lowercase */
697 	if (mapContains(expr, "lowercase")) {
698 		/*
699 		 * syntax := { "lowercase": <data_expression> }
700 		 * semantic: evaluate its argument and apply tolower to
701 		 * its content
702 		 */
703 		struct element *arg;
704 		struct element *result;
705 		struct string *r;
706 		size_t i;
707 		isc_boolean_t modified = ISC_FALSE;
708 
709 		arg = mapGet(expr, "lowercase");
710 		if (arg == NULL)
711 			return expr;
712 		arg = eval_data_expression(arg, &modified);
713 		if (modified) {
714 			mapRemove(expr, "lowercase");
715 			mapSet(expr, arg, "lowercase");
716 		}
717 
718 		if (arg->type != ELEMENT_STRING)
719 			return expr;
720 		*modifiedp = ISC_TRUE;
721 		r = allocString();
722 		concatString(r, stringValue(arg));
723 		for (i = 0; i < r->length; i++)
724 			r->content[i] = tolower(r->content[i]);
725 		result = createString(r);
726 		TAILQ_CONCAT(&result->comments, &expr->comments);
727 		TAILQ_CONCAT(&result->comments, &arg->comments);
728 		return result;
729 	}
730 
731 	/* uppercase */
732 	if (mapContains(expr, "uppercase")) {
733 		/*
734 		 * syntax := { "uppercase": <data_expression> }
735 		 * semantic: evaluate its argument and apply toupper to
736 		 * its content
737 		 */
738 		struct element *arg;
739 		struct element *result;
740 		struct string *r;
741 		size_t i;
742 		isc_boolean_t modified = ISC_FALSE;
743 
744 		arg = mapGet(expr, "uppercase");
745 		if (arg == NULL)
746 			return expr;
747 		arg = eval_data_expression(arg, &modified);
748 		if (modified) {
749 			mapRemove(expr, "lowercase");
750 			mapSet(expr, arg, "lowercase");
751 		}
752 
753 		if (arg->type != ELEMENT_STRING)
754 			return expr;
755 		*modifiedp = ISC_TRUE;
756 		r = allocString();
757 		concatString(r, stringValue(arg));
758 		for (i = 0; i < r->length; i++)
759 			r->content[i] = toupper(r->content[i]);
760 		result = createString(r);
761 		TAILQ_CONCAT(&result->comments, &expr->comments);
762 		TAILQ_CONCAT(&result->comments, &arg->comments);
763 		return result;
764 	}
765 
766 	/* option */
767 	if (mapContains(expr, "option"))
768 		/*
769 		 * syntax := { "option":
770 		 *             { "universe": <option_space_old>,
771 		 *               "name":  <option_name> }
772 		 *           }
773 		 * semantic: get universe/code option from incoming packet
774 		 */
775 		return expr;
776 
777 	/* hardware */
778 	if (mapContains(expr, "hardware")) {
779 		/*
780 		 * syntax := { "hardware": null }
781 		 * semantic: get mac type and address from incoming packet
782 		 */
783 		struct element *left;
784 		struct element *right;
785 		struct element *concat;
786 		struct element *result;
787 
788 		if (local_family != AF_INET)
789 			return expr;
790 		*modifiedp = ISC_TRUE;
791 		left = createMap();
792 		mapSet(left, createNull(), "hw-type");
793 		concat = createMap();
794 		mapSet(concat, left, "left");
795 		right = createMap();
796 		mapSet(right, createNull(), "hw-address");
797 		mapSet(concat, right, "right");
798 		result = createMap();
799 		mapSet(result, concat, "concat");
800 		return result;
801 	}
802 
803 	/* hw-type */
804 	if (mapContains(expr, "hw-type"))
805 		/*
806 		 * syntax := { "hw-type": null }
807 		 * semantic: get mac type and address from incoming packet
808 		 */
809 		return expr;
810 
811 	/* hw-address */
812 	if (mapContains(expr, "hw-address"))
813 		/*
814 		 * syntax := { "hw-address": null }
815 		 * semantic: get mac type and address from incoming packet
816 		 */
817 		return expr;
818 
819 	/* const-data */
820 	if (mapContains(expr, "const-data"))
821 		/*
822 		 * syntax := { "const-data": <string> }
823 		 * semantic: embedded string value
824 		 */
825 		return expr;
826 
827 	/* packet */
828 	if (mapContains(expr, "packet"))
829 		/*
830 		 * syntax := { "packet":
831 		 *             { "offset": <numeric_expression>,
832 		 *               "length": <numeric_expression> }
833 		 *           }
834 		 * semantic: return the selected substring of the incoming
835 		 * packet content
836 		 */
837 		return expr;
838 
839 	/* concat */
840 	if (mapContains(expr, "concat")) {
841 		/*
842 		 * syntax := { "concat":
843 		 *             { "left":  <data_expression>,
844 		 *               "right": <data_expression> }
845 		 *           }
846 		 * semantic: evaluate arguments and return the concatenation
847 		 */
848 		struct element *arg;
849 		struct element *left;
850 		struct element *right;
851 		struct element *result;
852 		struct string *r;
853 		isc_boolean_t lmodified = ISC_FALSE;
854 		isc_boolean_t rmodified = ISC_FALSE;
855 
856 		arg = mapGet(expr, "concat");
857 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
858 			return expr;
859 		left = mapGet(arg, "left");
860 		if (left == NULL)
861 			return expr;
862 		right = mapGet(arg, "right");
863 		if (right == NULL)
864 			return expr;
865 		left = eval_data_expression(left, &lmodified);
866 		if (lmodified) {
867 			mapRemove(arg, "left");
868 			mapSet(arg, left, "left");
869 		}
870 		right = eval_data_expression(right, &rmodified);
871 		if (rmodified) {
872 			mapRemove(arg, "right");
873 			mapSet(arg, right, "right");
874 		}
875 
876 		/* degenerated cases */
877 		if ((left->type == ELEMENT_STRING) &&
878 		    (stringValue(left)->length == 0)) {
879 			*modifiedp = ISC_TRUE;
880 			return right;
881 		}
882 		if ((right->type == ELEMENT_STRING) &&
883 		    (stringValue(right)->length == 0)) {
884 			*modifiedp = ISC_TRUE;
885 			return left;
886 		}
887 
888 		if ((left->type != ELEMENT_STRING) ||
889 		    (right->type != ELEMENT_STRING))
890 			return expr;
891 		*modifiedp = ISC_TRUE;
892 		r = allocString();
893 		concatString(r, stringValue(left));
894 		concatString(r, stringValue(right));
895 		result = createString(r);
896 		TAILQ_CONCAT(&result->comments, &expr->comments);
897 		TAILQ_CONCAT(&result->comments, &arg->comments);
898 		TAILQ_CONCAT(&result->comments, &left->comments);
899 		TAILQ_CONCAT(&result->comments, &right->comments);
900 		return result;
901 	}
902 
903 	/* encapsulate */
904 	if (mapContains(expr, "encapsulate"))
905 		/*
906 		 * syntax := { "encapsulate": <encapsulated_space> }
907 		 * semantic: encapsulate options of the given space
908 		 */
909 		return expr;
910 
911 	/* encode-int8 */
912 	if (mapContains(expr, "encode-int8")) {
913 		/*
914 		 * syntax := { "encode-int8": <numeric_expression> }
915 		 * semantic: return a string buffer with the evaluated
916 		 * number as content
917 		 */
918 		struct element *arg;
919 		struct element *result;
920 		struct string *r;
921 		uint8_t val;
922 		isc_boolean_t modified = ISC_FALSE;
923 
924 		arg = mapGet(expr, "encode-int8");
925 		if (arg == NULL)
926 			return expr;
927 		arg = eval_numeric_expression(arg, &modified);
928 		if (modified) {
929 			mapRemove(expr, "encode-int8");
930 			mapSet(expr, arg, "encode-int8");
931 		}
932 
933 		if (arg->type != ELEMENT_INTEGER)
934 			return expr;
935 		*modifiedp = ISC_TRUE;
936 		val = (uint8_t)intValue(arg);
937 		r = makeString(sizeof(val), (char *)&val);
938 		result = createString(r);
939 		TAILQ_CONCAT(&result->comments, &expr->comments);
940 		TAILQ_CONCAT(&result->comments, &arg->comments);
941 		return result;
942 	}
943 
944 	/* encode-int16 */
945 	if (mapContains(expr, "encode-int16")) {
946 		/*
947 		 * syntax := { "encode-int16": <numeric_expression> }
948 		 * semantic: return a string buffer with the evaluated
949 		 * number as content
950 		 */
951 		struct element *arg;
952 		struct element *result;
953 		struct string *r;
954 		uint16_t val;
955 		isc_boolean_t modified = ISC_FALSE;
956 
957 		arg = mapGet(expr, "encode-int16");
958 		if (arg == NULL)
959 			return expr;
960 		arg = eval_numeric_expression(arg, &modified);
961 		if (modified) {
962 			mapRemove(expr, "encode-int16");
963 			mapSet(expr, arg, "encode-int16");
964 		}
965 
966 		if (arg->type != ELEMENT_INTEGER)
967 			return expr;
968 		*modifiedp = ISC_TRUE;
969 		val = (uint16_t)intValue(arg);
970 		val = htons(val);
971 		r = makeString(sizeof(val), (char *)&val);
972 		result = createString(r);
973 		TAILQ_CONCAT(&result->comments, &expr->comments);
974 		TAILQ_CONCAT(&result->comments, &arg->comments);
975 		return result;
976 	}
977 
978 	/* encode-int32 */
979 	if (mapContains(expr, "encode-int32")) {
980 		/*
981 		 * syntax := { "encode-int32": <numeric_expression> }
982 		 * semantic: return a string buffer with the evaluated
983 		 * number as content
984 		 */
985 		struct element *arg;
986 		struct element *result;
987 		struct string *r;
988 		uint32_t val;
989 		isc_boolean_t modified = ISC_FALSE;
990 
991 		arg = mapGet(expr, "encode-int32");
992 		if (arg == NULL)
993 			return expr;
994 		arg = eval_numeric_expression(arg, &modified);
995 		if (modified) {
996 			mapRemove(expr, "encode-int32");
997 			mapSet(expr, arg, "encode-int32");
998 		}
999 
1000 		if (arg->type != ELEMENT_INTEGER)
1001 			return expr;
1002 		*modifiedp = ISC_TRUE;
1003 		val = (uint32_t)intValue(arg);
1004 		val = htonl(val);
1005 		r = makeString(sizeof(val), (char *)&val);
1006 		result = createString(r);
1007 		TAILQ_CONCAT(&result->comments, &expr->comments);
1008 		TAILQ_CONCAT(&result->comments, &arg->comments);
1009 		return result;
1010 	}
1011 
1012 	/* gethostbyname */
1013 	if (mapContains(expr, "gethostbyname")) {
1014 		/*
1015 		 * syntax := { "gethostbyname": <string> }
1016 		 * semantic: call gethostbyname and return
1017 		 * a binary buffer with addresses
1018 		 */
1019 		struct element *arg;
1020 		struct element *result;
1021 		struct string *r;
1022 		char *hostname;
1023 		struct hostent *h;
1024 		size_t i;
1025 
1026 		if (local_family != AF_INET)
1027 			return expr;
1028 		arg = mapGet(expr, "gethostbyname");
1029 		if ((arg == NULL) || (arg->type != ELEMENT_STRING))
1030 			return expr;
1031 		hostname = stringValue(arg)->content;
1032 		h = gethostbyname(hostname);
1033 		r = allocString();
1034 		if (h == NULL) {
1035 			switch (h_errno) {
1036 			case HOST_NOT_FOUND:
1037 				debug("gethostbyname: %s: host unknown",
1038 				      hostname);
1039 				break;
1040 			case TRY_AGAIN:
1041 				debug("gethostbyname: %s: temporary name "
1042 				      "server failure", hostname);
1043 				break;
1044 			case NO_RECOVERY:
1045 				debug("gethostbyname: %s: name server failed",
1046 				      hostname);
1047 				break;
1048 			case NO_DATA:
1049 				debug("gethostbyname: %s: no A record "
1050 				      "associated with address", hostname);
1051 				break;
1052 			}
1053 		} else
1054 			for (i = 0; h->h_addr_list[i] != NULL; i++) {
1055 				struct string *addr;
1056 
1057 				addr = makeString(4, h->h_addr_list[i]);
1058 				concatString(r, addr);
1059 			}
1060 		*modifiedp = ISC_TRUE;
1061 		r = makeStringExt(r->length, r->content, 'X');
1062 		result = createString(r);
1063 		TAILQ_CONCAT(&result->comments, &arg->comments);
1064 		return result;
1065 	}
1066 
1067 	/* binary-to-ascii */
1068 	if (mapContains(expr, "binary-to-ascii")) {
1069 		/*
1070 		 * syntax := { "binary-to-ascii":
1071 		 *             { "base":      <numeric_expression 2..16>,
1072 		 *               "width":     <numeric_expression 8, 16 or 32>,
1073 		 *               "separator": <data_expression>,
1074 		 *               "buffer":    <data_expression> }
1075 		 *           }
1076 		 * semantic: split the input buffer into int8/16/32 numbers,
1077 		 * output them separated by the given string
1078 		 */
1079 		struct element *arg;
1080 		struct element *base;
1081 		struct element *width;
1082 		struct element *separator;
1083 		struct element *buffer;
1084 		struct element *result;
1085 		struct string *sep;
1086 		struct string *buf;
1087 		struct string *r;
1088 		int64_t b;
1089 		int64_t w;
1090 		isc_boolean_t bmodified = ISC_FALSE;
1091 		isc_boolean_t wmodified = ISC_FALSE;
1092 		isc_boolean_t smodified = ISC_FALSE;
1093 		isc_boolean_t dmodified = ISC_FALSE;
1094 
1095 		arg = mapGet(expr, "binary-to-ascii");
1096 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1097 			return expr;
1098 		base = mapGet(arg, "base");
1099 		if (base == NULL)
1100 			return expr;
1101 		width = mapGet(arg, "width");
1102 		if (width == NULL)
1103 			return expr;
1104 		separator = mapGet(arg, "separator");
1105 		if (separator == NULL)
1106 			return expr;
1107 		buffer = mapGet(arg, "buffer");
1108 		if (buffer == NULL)
1109 			return expr;
1110 		base = eval_numeric_expression(base, &bmodified);
1111 		if (bmodified) {
1112 			mapRemove(arg, "base");
1113 			mapSet(arg, base, "base");
1114 		}
1115 		width = eval_numeric_expression(width, &wmodified);
1116 		if (wmodified) {
1117 			mapRemove(arg, "width");
1118 			mapSet(arg, width, "width");
1119 		}
1120 		separator = eval_data_expression(separator, &smodified);
1121 		if (smodified) {
1122 			mapRemove(arg, "separator");
1123 			mapSet(arg, separator, "separator");
1124 		}
1125 		buffer = eval_data_expression(buffer, &dmodified);
1126 		if (dmodified) {
1127 			mapRemove(arg, "buffer");
1128 			mapSet(arg, buffer, "buffer");
1129 		}
1130 
1131 		if ((base->type != ELEMENT_INTEGER) ||
1132 		    (width->type != ELEMENT_INTEGER) ||
1133 		    (separator->type != ELEMENT_STRING) ||
1134 		    (buffer->type != ELEMENT_STRING))
1135 			return expr;
1136 		b = intValue(base);
1137 		if ((b < 2) || (b > 16))
1138 			return expr;
1139 		if ((b != 8) && (b != 10) && (b != 16))
1140 			return expr;
1141 		w = intValue(width);
1142 		if ((w != 8) && (w != 16) && (w != 32))
1143 			return expr;
1144 		sep = stringValue(separator);
1145 		buf = stringValue(buffer);
1146 		r = allocString();
1147 		if (w == 8) {
1148 			size_t i;
1149 			char *fmt;
1150 
1151 			switch (b) {
1152 			case 8:
1153 				fmt = "%o";
1154 				break;
1155 			case 10:
1156 				fmt = "%d";
1157 				break;
1158 			case 16:
1159             default:
1160 				fmt = "%x";
1161 				break;
1162 			}
1163 
1164 			for (i = 0; i < buf->length; i++) {
1165 				uint8_t val;
1166 				char num[4];
1167 
1168 				if (i != 0)
1169 					concatString(r, sep);
1170 				val = (uint8_t)buf->content[i];
1171 				snprintf(num, sizeof(num), fmt, (int)val);
1172 				appendString(r, num);
1173 			}
1174 		} else if (w == 16) {
1175 			size_t i;
1176 			char *fmt;
1177 
1178 			if ((buf->length % 2) != 0)
1179 				return expr;
1180 
1181 			switch (b) {
1182 			case 8:
1183 				fmt = "%o";
1184 				break;
1185 			case 10:
1186 				fmt = "%d";
1187 				break;
1188 			case 16:
1189             default:
1190 				fmt = "%x";
1191 				break;
1192 			}
1193 
1194 			for (i = 0; i < buf->length; i += 2) {
1195 				uint16_t val;
1196 				char num[8];
1197 
1198 				if (i != 0)
1199 					concatString(r, sep);
1200 				memcpy(&val, buf->content + i, 2);
1201 				val = ntohs(val);
1202 				snprintf(num, sizeof(num), fmt, (int)val);
1203 				appendString(r, num);
1204 			}
1205 		} else if (w == 32) {
1206 			size_t i;
1207 			char *fmt;
1208 
1209 			if ((buf->length % 4) != 0)
1210 				return expr;
1211 
1212 			switch (b) {
1213 			case 8:
1214 				fmt = "%llo";
1215 				break;
1216 			case 10:
1217 				fmt = "%lld";
1218 				break;
1219 			case 16:
1220             default:
1221 				fmt = "%llx";
1222 				break;
1223 			}
1224 
1225 			for (i = 0; i < buf->length; i += 4) {
1226 				uint32_t val;
1227 				char num[40];
1228 
1229 				if (i != 0)
1230 					concatString(r, sep);
1231 				memcpy(&val, buf->content + i, 4);
1232 				val = ntohl(val);
1233 				snprintf(num, sizeof(num), fmt,
1234 					 (long long)val);
1235 				appendString(r, num);
1236 			}
1237 		}
1238 		*modifiedp = ISC_TRUE;
1239 		result = createString(r);
1240 		TAILQ_CONCAT(&result->comments, &expr->comments);
1241 		TAILQ_CONCAT(&result->comments, &arg->comments);
1242 		TAILQ_CONCAT(&result->comments, &base->comments);
1243 		TAILQ_CONCAT(&result->comments, &width->comments);
1244 		TAILQ_CONCAT(&result->comments, &separator->comments);
1245 		TAILQ_CONCAT(&result->comments, &buffer->comments);
1246 		return result;
1247 	}
1248 
1249 	/* filename */
1250 	if (mapContains(expr, "filename"))
1251 		/*
1252 		 * syntax := { "filename": null }
1253 		 * semantic: get filename field from incoming DHCPv4 packet
1254 		 */
1255 		return expr;
1256 
1257 	/* server-name */
1258 	if (mapContains(expr, "server-name"))
1259 		/*
1260 		 * syntax := { "server-name": null }
1261 		 * semantic: get server-name field from incoming DHCPv4 packet
1262 		 */
1263 		return expr;
1264 
1265 	/* reverse */
1266 	if (mapContains(expr, "reverse")) {
1267 		/*
1268 		 * syntax := { "reverse":
1269 		 *             { "width": <numeric_expression>,
1270 		 *               "buffer":    <data_expression> }
1271 		 *           }
1272 		 * semantic: reverse the input buffer by width chunks of bytes
1273 		 */
1274 		struct element *arg;
1275 		struct element *width;
1276 		struct element *buffer;
1277 		struct element *result;
1278 		struct string *buf;
1279 		struct string *r;
1280 		int64_t w;
1281 		size_t i;
1282 		isc_boolean_t wmodified = ISC_FALSE;
1283 		isc_boolean_t bmodified = ISC_FALSE;
1284 
1285 		arg = mapGet(expr, "reverse");
1286 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1287 			return expr;
1288 		width = mapGet(arg, "width");
1289 		if (width == NULL)
1290 			return expr;
1291 		buffer = mapGet(arg, "buffer");
1292 		if (buffer == NULL)
1293 			return expr;
1294 		width = eval_numeric_expression(width, &wmodified);
1295 		if (wmodified) {
1296 			mapRemove(arg, "width");
1297 			mapSet(arg, width, "width");
1298 		}
1299 		buffer = eval_data_expression(buffer, &bmodified);
1300 		if (bmodified) {
1301 			mapRemove(arg, "buffer");
1302 			mapSet(arg, buffer, "buffer");
1303 		}
1304 
1305 		if ((width->type != ELEMENT_INTEGER) ||
1306 		    (buffer->type != ELEMENT_STRING))
1307 			return expr;
1308 		w = intValue(width);
1309 		if (w <= 0)
1310 			return expr;
1311 		buf = stringValue(buffer);
1312 		if ((buf->length % w) != 0)
1313 			return expr;
1314 		*modifiedp = ISC_TRUE;
1315 		r = allocString();
1316 		concatString(r, buf);
1317 		for (i = 0; i < buf->length; i += w) {
1318 			memcpy(r->content + i,
1319 			       buf->content + (buf->length - i - w),
1320 			       w);
1321 		}
1322 		result = createString(r);
1323 		TAILQ_CONCAT(&result->comments, &expr->comments);
1324 		TAILQ_CONCAT(&result->comments, &arg->comments);
1325 		TAILQ_CONCAT(&result->comments, &width->comments);
1326 		TAILQ_CONCAT(&result->comments, &buffer->comments);
1327 		return result;
1328 	}
1329 
1330 	/* pick-first-value */
1331 	if (mapContains(expr, "pick-first-value")) {
1332 		/*
1333 		 * syntax := { "pick-first-value":
1334 		 *             [ <data_expression>, ... ]
1335 		 *           }
1336 		 * semantic: evaluates expressions and return the first
1337 		 * not null, return null if all are null
1338 		 */
1339 		struct element *arg;
1340 		struct element *result;
1341 		size_t i;
1342 		isc_boolean_t modified;
1343 		isc_boolean_t can_decide = ISC_TRUE;
1344 
1345 		arg = mapGet(expr, "pick-first-value");
1346 		if ((arg == NULL) || (arg->type != ELEMENT_LIST))
1347 			return expr;
1348 
1349 		for (i = 0; i < listSize(arg); i++) {
1350 			struct element *item;
1351 
1352 			item = listGet(arg, i);
1353 			if (item == NULL)
1354 				return expr;
1355 			modified = ISC_FALSE;
1356 			item = eval_data_expression(item, &modified);
1357 			if (modified)
1358 				listRemove(arg, i);
1359 			if (!can_decide)
1360 				goto restore;
1361 			if (item->type != ELEMENT_STRING) {
1362 				can_decide = ISC_FALSE;
1363 				goto restore;
1364 			}
1365 			if (stringValue(item)->length != 0) {
1366 				*modifiedp = ISC_TRUE;
1367 				TAILQ_CONCAT(&item->comments, &expr->comments);
1368 				TAILQ_CONCAT(&item->comments, &arg->comments);
1369 				return item;
1370 			}
1371 		restore:
1372 			listSet(arg, item, i);
1373 		}
1374 		if (!can_decide)
1375 			return expr;
1376 		*modifiedp = ISC_TRUE;
1377 		result = createString(allocString());
1378 		TAILQ_CONCAT(&result->comments, &expr->comments);
1379 		TAILQ_CONCAT(&result->comments,  &arg->comments);
1380 		return result;
1381 	}
1382 
1383 	/* host-decl-name */
1384 	if (mapContains(expr, "host-decl-name"))
1385 		/*
1386 		 * syntax := { "host-decl-name": null }
1387 		 * semantic: return the name of the matching host
1388 		 * declaration (aka revervation in kea) or null
1389 		 */
1390 		return expr;
1391 
1392 	/* leased-address */
1393 	if (mapContains(expr, "leased-address"))
1394 		/*
1395 		 * syntax := { "leased-address": null }
1396 		 * semantic: return the address of the assigned lease or
1397 		 * log a message
1398 		 */
1399 		return expr;
1400 
1401 	/* config-option */
1402 	if (mapContains(expr, "config-option"))
1403 		/*
1404 		 * syntax := { "config-option":
1405 		 *             { "universe": <option_space_old>,
1406 		 *               "name":  <option_name> }
1407 		 *           }
1408 		 * semantic: get universe/code option to send
1409 		 */
1410 		return expr;
1411 
1412 	/* null */
1413 	if (mapContains(expr, "null")) {
1414 		/*
1415 		 * syntax := { "null": null }
1416 		 * semantic: return null
1417 		 */
1418 		struct element *result;
1419 
1420 		*modifiedp = ISC_TRUE;
1421 		result = createString(allocString());
1422 		TAILQ_CONCAT(&result->comments, &expr->comments);
1423 		return result;
1424 	}
1425 
1426 	/* gethostname */
1427 	if (mapContains(expr, "gethostname")) {
1428 		/*
1429 		 * syntax := { "gethostname": null }
1430 		 * semantic: return gethostname
1431 		 */
1432 		struct element *result;
1433 		char buf[300 /* >= 255 + 1 */];
1434 
1435 		if (gethostname(buf, sizeof(buf)) != 0) {
1436 			debug("gethostname fails: %s", strerror(errno));
1437 			return expr;
1438 		}
1439 		*modifiedp = ISC_TRUE;
1440 		result = createString(makeString(-1, buf));
1441 		TAILQ_CONCAT(&result->comments, &expr->comments);
1442 		return result;
1443 	}
1444 
1445 	/* v6relay */
1446 	if (mapContains(expr, "v6relay")) {
1447 		/*
1448 		 * syntax := { "v6relay":
1449 		 *             { "relay": <numeric_expression>,
1450 		 *               "relay-option" <data_expression> }
1451 		 *           }
1452 		 * semantic: relay is a counter from client, 0 is no-op,
1453 		 * 1 is the relay closest to the client, etc, option
1454 		 * is a dhcp6 option ans is return when found
1455 		 */
1456 		struct element *arg;
1457 		struct element *relay;
1458 		isc_boolean_t modified = ISC_FALSE;
1459 
1460 		if (local_family != AF_INET6)
1461 			return expr;
1462 		arg = mapGet(expr, "v6relay");
1463 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1464 			return expr;
1465 		relay = mapGet(arg, "relay");
1466 		if (relay == NULL)
1467 			return expr;
1468 		relay = eval_numeric_expression(relay, &modified);
1469 		if (modified) {
1470 			mapRemove(arg, "relay");
1471 			mapSet(arg, relay, "relay");
1472 		}
1473 		return expr;
1474 	}
1475 
1476 	return expr;
1477 }
1478 
1479 /*
1480  * numeric-expression :== EXTRACT_INT LPAREN data-expression
1481  *                                           COMMA number RPAREN |
1482  *                        NUMBER
1483  */
1484 
1485 struct element *
eval_numeric_expression(struct element * expr,isc_boolean_t * modifiedp)1486 eval_numeric_expression(struct element *expr, isc_boolean_t *modifiedp)
1487 {
1488 	/* trivial case: already done */
1489 	if (expr->type == ELEMENT_INTEGER)
1490 		return expr;
1491 
1492 	/*
1493 	 * From is_numeric_expression
1494 	 */
1495 
1496 	if (expr->type != ELEMENT_MAP)
1497 		return expr;
1498 
1499 	/* extract-int8 */
1500 	if (mapContains(expr, "extract-int8")) {
1501 		/*
1502 		 * syntax := { "extract-int8": <data_expression> }
1503 		 * semantic: extract from the evalkuated string buffer
1504 		 * a number
1505 		 */
1506 		struct element *arg;
1507 		struct element *result;
1508 		uint8_t val = 0;
1509 		isc_boolean_t modified = ISC_FALSE;
1510 
1511 		arg = mapGet(expr, "extract-int8");
1512 		if (arg == NULL)
1513 			return expr;
1514 		arg = eval_data_expression(arg, &modified);
1515 		if (modified) {
1516 			mapRemove(expr, "extract-int8");
1517 			mapSet(expr, arg, "extract-int8");
1518 		}
1519 
1520 		if (arg->type != ELEMENT_STRING)
1521 			return expr;
1522 		*modifiedp = ISC_TRUE;
1523 		if (stringValue(arg)->length > 0)
1524 			val = (uint8_t) stringValue(arg)->content[0];
1525 		result = createInt(val);
1526 		TAILQ_CONCAT(&result->comments, &expr->comments);
1527 		TAILQ_CONCAT(&result->comments, &arg->comments);
1528 		return result;
1529 	}
1530 
1531 	/* extract-int16 */
1532 	if (mapContains(expr, "extract-int16")) {
1533 		/*
1534 		 * syntax := { "extract-int16": <data_expression> }
1535 		 * semantic: extract from the evalkuated string buffer
1536 		 * a number
1537 		 */
1538 		struct element *arg;
1539 		struct element *result;
1540 		uint16_t val;
1541 		isc_boolean_t modified = ISC_FALSE;
1542 
1543 		arg = mapGet(expr, "extract-int16");
1544 		if (arg == NULL)
1545 			return expr;
1546 		arg = eval_data_expression(arg, &modified);
1547 		if (modified) {
1548 			mapRemove(expr, "extract-int16");
1549 			mapSet(expr, arg, "extract-int16");
1550 		}
1551 
1552 		if (arg->type != ELEMENT_STRING)
1553 			return expr;
1554 		if (stringValue(arg)->length < 2)
1555 			return expr;
1556 		*modifiedp = ISC_TRUE;
1557 		memcpy(&val, stringValue(arg)->content, 2);
1558 		val = ntohs(val);
1559 		result = createInt(val);
1560 		TAILQ_CONCAT(&result->comments, &expr->comments);
1561 		TAILQ_CONCAT(&result->comments, &arg->comments);
1562 		return result;
1563 	}
1564 
1565 	/* extract-int32 */
1566 	if (mapContains(expr, "extract-int32")) {
1567 		/*
1568 		 * syntax := { "extract-int32": <data_expression> }
1569 		 * semantic: extract from the evalkuated string buffer
1570 		 * a number
1571 		 */
1572 		struct element *arg;
1573 		struct element *result;
1574 		uint32_t val;
1575 		isc_boolean_t modified = ISC_FALSE;
1576 
1577 		arg = mapGet(expr, "extract-int32");
1578 		if (arg == NULL)
1579 			return expr;
1580 		arg = eval_data_expression(arg, &modified);
1581 		if (modified) {
1582 			mapRemove(expr, "extract-int32");
1583 			mapSet(expr, arg, "extract-int32");
1584 		}
1585 
1586 		if (arg->type != ELEMENT_STRING)
1587 			return expr;
1588 		if (stringValue(arg)->length < 4)
1589 			return expr;
1590 		*modifiedp = ISC_TRUE;
1591 		memcpy(&val, stringValue(arg)->content, 4);
1592 		val = ntohl(val);
1593 		result = createInt(val);
1594 		TAILQ_CONCAT(&result->comments, &expr->comments);
1595 		TAILQ_CONCAT(&result->comments, &arg->comments);
1596 		return result;
1597 	}
1598 
1599 	/* const-int */
1600 	if (mapContains(expr, "const-int")) {
1601 		/*
1602 		 * syntax := { "const-int": <integer> }
1603 		 * semantic: embedded integer value
1604 		 */
1605 		struct element *arg;
1606 		struct element *result;
1607 
1608 		arg = mapGet(expr, "const-int");
1609 		if ((arg == NULL) || (arg->type != ELEMENT_INTEGER))
1610 			return expr;
1611 		*modifiedp = ISC_TRUE;
1612 		result = createInt(intValue(arg));
1613 		TAILQ_CONCAT(&result->comments, &expr->comments);
1614 		TAILQ_CONCAT(&result->comments, &arg->comments);
1615 		return result;
1616 	}
1617 
1618 	/* lease-time */
1619 	if (mapContains(expr, "lease-time"))
1620 		/*
1621 		 * syntax := { "lease-time": null }
1622 		 * semantic: return duration of the current lease, i.e
1623 		 * the difference between expire time and now
1624 		 */
1625 		return expr;
1626 
1627 	/* add */
1628 	if (mapContains(expr, "add")) {
1629 		/*
1630 		 * syntax := { "add":
1631 		 *             { "left":  <boolean_expression>,
1632 		 *               "right": <boolean_expression> }
1633 		 *           }
1634 		 * semantics: evaluate branches, return left plus right
1635 		 * branches
1636 		 */
1637 		struct element *arg;
1638 		struct element *left;
1639 		struct element *right;
1640 		struct element *result;
1641 		isc_boolean_t lmodified = ISC_FALSE;
1642 		isc_boolean_t rmodified = ISC_FALSE;
1643 
1644 		arg = mapGet(expr, "add");
1645 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1646 			return expr;
1647 		left = mapGet(arg, "left");
1648 		if (left == NULL)
1649 			return expr;
1650 		right = mapGet(arg, "right");
1651 		if (right == NULL)
1652 			return expr;
1653 		left = eval_numeric_expression(left, &lmodified);
1654 		if (lmodified) {
1655 			mapRemove(arg, "left");
1656 			mapSet(arg, left, "left");
1657 		}
1658 		right = eval_numeric_expression(right, &rmodified);
1659 		if (rmodified) {
1660 			mapRemove(arg, "right");
1661 			mapSet(arg, right, "right");
1662 		}
1663 
1664 		if ((left->type != ELEMENT_INTEGER) ||
1665 		    (right->type != ELEMENT_INTEGER))
1666 			return expr;
1667 		*modifiedp = ISC_TRUE;
1668 		result = createInt(intValue(left) + intValue(right));
1669 		TAILQ_CONCAT(&result->comments, &expr->comments);
1670 		TAILQ_CONCAT(&result->comments, &arg->comments);
1671 		TAILQ_CONCAT(&result->comments, &left->comments);
1672 		TAILQ_CONCAT(&result->comments, &right->comments);
1673 		return result;
1674 	}
1675 
1676 	/* subtract */
1677 	if (mapContains(expr, "subtract")) {
1678 		/*
1679 		 * syntax := { "subtract":
1680 		 *             { "left":  <boolean_expression>,
1681 		 *               "right": <boolean_expression> }
1682 		 *           }
1683 		 * semantics: evaluate branches, return left plus right
1684 		 * branches
1685 		 */
1686 		struct element *arg;
1687 		struct element *left;
1688 		struct element *right;
1689 		struct element *result;
1690 		isc_boolean_t lmodified = ISC_FALSE;
1691 		isc_boolean_t rmodified = ISC_FALSE;
1692 
1693 		arg = mapGet(expr, "subtract");
1694 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1695 			return expr;
1696 		left = mapGet(arg, "left");
1697 		if (left == NULL)
1698 			return expr;
1699 		right = mapGet(arg, "right");
1700 		if (right == NULL)
1701 			return expr;
1702 		left = eval_numeric_expression(left, &lmodified);
1703 		if (lmodified) {
1704 			mapRemove(arg, "left");
1705 			mapSet(arg, left, "left");
1706 		}
1707 		right = eval_numeric_expression(right, &rmodified);
1708 		if (rmodified) {
1709 			mapRemove(arg, "right");
1710 			mapSet(arg, right, "right");
1711 		}
1712 
1713 		if ((left->type != ELEMENT_INTEGER) ||
1714 		    (right->type != ELEMENT_INTEGER))
1715 			return expr;
1716 		*modifiedp = ISC_TRUE;
1717 		result = createInt(intValue(left) - intValue(right));
1718 		TAILQ_CONCAT(&result->comments, &expr->comments);
1719 		TAILQ_CONCAT(&result->comments, &arg->comments);
1720 		TAILQ_CONCAT(&result->comments, &left->comments);
1721 		TAILQ_CONCAT(&result->comments, &right->comments);
1722 		return result;
1723 	}
1724 
1725 	/* multiply */
1726 	if (mapContains(expr, "multiply")) {
1727 		/*
1728 		 * syntax := { "multiply":
1729 		 *             { "left":  <boolean_expression>,
1730 		 *               "right": <boolean_expression> }
1731 		 *           }
1732 		 * semantics: evaluate branches, return left plus right
1733 		 * branches
1734 		 */
1735 		struct element *arg;
1736 		struct element *left;
1737 		struct element *right;
1738 		struct element *result;
1739 		isc_boolean_t lmodified = ISC_FALSE;
1740 		isc_boolean_t rmodified = ISC_FALSE;
1741 
1742 		arg = mapGet(expr, "multiply");
1743 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1744 			return expr;
1745 		left = mapGet(arg, "left");
1746 		if (left == NULL)
1747 			return expr;
1748 		right = mapGet(arg, "right");
1749 		if (right == NULL)
1750 			return expr;
1751 		left = eval_numeric_expression(left, &lmodified);
1752 		if (lmodified) {
1753 			mapRemove(arg, "left");
1754 			mapSet(arg, left, "left");
1755 		}
1756 		right = eval_numeric_expression(right, &rmodified);
1757 		if (rmodified) {
1758 			mapRemove(arg, "right");
1759 			mapSet(arg, right, "right");
1760 		}
1761 
1762 		if ((left->type != ELEMENT_INTEGER) ||
1763 		    (right->type != ELEMENT_INTEGER))
1764 			return expr;
1765 		*modifiedp = ISC_TRUE;
1766 		result = createInt(intValue(left) * intValue(right));
1767 		TAILQ_CONCAT(&result->comments, &expr->comments);
1768 		TAILQ_CONCAT(&result->comments, &arg->comments);
1769 		TAILQ_CONCAT(&result->comments, &left->comments);
1770 		TAILQ_CONCAT(&result->comments, &right->comments);
1771 		return result;
1772 	}
1773 
1774 	/* divide */
1775 	if (mapContains(expr, "divide")) {
1776 		/*
1777 		 * syntax := { "divide":
1778 		 *             { "left":  <boolean_expression>,
1779 		 *               "right": <boolean_expression> }
1780 		 *           }
1781 		 * semantics: evaluate branches, return left plus right
1782 		 * branches
1783 		 */
1784 		struct element *arg;
1785 		struct element *left;
1786 		struct element *right;
1787 		struct element *result;
1788 		isc_boolean_t lmodified = ISC_FALSE;
1789 		isc_boolean_t rmodified = ISC_FALSE;
1790 
1791 		arg = mapGet(expr, "divide");
1792 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1793 			return expr;
1794 		left = mapGet(arg, "left");
1795 		if (left == NULL)
1796 			return expr;
1797 		right = mapGet(arg, "right");
1798 		if (right == NULL)
1799 			return expr;
1800 		left = eval_numeric_expression(left, &lmodified);
1801 		if (lmodified) {
1802 			mapRemove(arg, "left");
1803 			mapSet(arg, left, "left");
1804 		}
1805 		right = eval_numeric_expression(right, &rmodified);
1806 		if (rmodified) {
1807 			mapRemove(arg, "right");
1808 			mapSet(arg, right, "right");
1809 		}
1810 
1811 		if ((left->type != ELEMENT_INTEGER) ||
1812 		    (right->type != ELEMENT_INTEGER))
1813 			return expr;
1814 		if (intValue(right) == 0)
1815 			return expr;
1816 		*modifiedp = ISC_TRUE;
1817 		result = createInt(intValue(left) / intValue(right));
1818 		TAILQ_CONCAT(&result->comments, &expr->comments);
1819 		TAILQ_CONCAT(&result->comments, &arg->comments);
1820 		TAILQ_CONCAT(&result->comments, &left->comments);
1821 		TAILQ_CONCAT(&result->comments, &right->comments);
1822 		return result;
1823 	}
1824 
1825 	/* remainder */
1826 	if (mapContains(expr, "remainder")) {
1827 		/*
1828 		 * syntax := { "remainder":
1829 		 *             { "left":  <boolean_expression>,
1830 		 *               "right": <boolean_expression> }
1831 		 *           }
1832 		 * semantics: evaluate branches, return left plus right
1833 		 * branches
1834 		 */
1835 		struct element *arg;
1836 		struct element *left;
1837 		struct element *right;
1838 		struct element *result;
1839 		isc_boolean_t lmodified = ISC_FALSE;
1840 		isc_boolean_t rmodified = ISC_FALSE;
1841 
1842 		arg = mapGet(expr, "remainder");
1843 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1844 			return expr;
1845 		left = mapGet(arg, "left");
1846 		if (left == NULL)
1847 			return expr;
1848 		right = mapGet(arg, "right");
1849 		if (right == NULL)
1850 			return expr;
1851 		left = eval_numeric_expression(left, &lmodified);
1852 		if (lmodified) {
1853 			mapRemove(arg, "left");
1854 			mapSet(arg, left, "left");
1855 		}
1856 		right = eval_numeric_expression(right, &rmodified);
1857 		if (rmodified) {
1858 			mapRemove(arg, "right");
1859 			mapSet(arg, right, "right");
1860 		}
1861 
1862 		if ((left->type != ELEMENT_INTEGER) ||
1863 		    (right->type != ELEMENT_INTEGER))
1864 			return expr;
1865 		if (intValue(right) == 0)
1866 			return expr;
1867 		*modifiedp = ISC_TRUE;
1868 		result = createInt(intValue(left) % intValue(right));
1869 		TAILQ_CONCAT(&result->comments, &expr->comments);
1870 		TAILQ_CONCAT(&result->comments, &arg->comments);
1871 		TAILQ_CONCAT(&result->comments, &left->comments);
1872 		TAILQ_CONCAT(&result->comments, &right->comments);
1873 		return result;
1874 	}
1875 
1876 	/* binary-and */
1877 	if (mapContains(expr, "binary-and")) {
1878 		/*
1879 		 * syntax := { "binary-and":
1880 		 *             { "left":  <boolean_expression>,
1881 		 *               "right": <boolean_expression> }
1882 		 *           }
1883 		 * semantics: evaluate branches, return left plus right
1884 		 * branches
1885 		 */
1886 		struct element *arg;
1887 		struct element *left;
1888 		struct element *right;
1889 		struct element *result;
1890 		isc_boolean_t lmodified = ISC_FALSE;
1891 		isc_boolean_t rmodified = ISC_FALSE;
1892 
1893 		arg = mapGet(expr, "binary-and");
1894 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1895 			return expr;
1896 		left = mapGet(arg, "left");
1897 		if (left == NULL)
1898 			return expr;
1899 		right = mapGet(arg, "right");
1900 		if (right == NULL)
1901 			return expr;
1902 		left = eval_numeric_expression(left, &lmodified);
1903 		if (lmodified) {
1904 			mapRemove(arg, "left");
1905 			mapSet(arg, left, "left");
1906 		}
1907 		right = eval_numeric_expression(right, &rmodified);
1908 		if (rmodified) {
1909 			mapRemove(arg, "right");
1910 			mapSet(arg, right, "right");
1911 		}
1912 
1913 		if ((left->type != ELEMENT_INTEGER) ||
1914 		    (right->type != ELEMENT_INTEGER))
1915 			return expr;
1916 		*modifiedp = ISC_TRUE;
1917 		result = createInt(intValue(left) & intValue(right));
1918 		TAILQ_CONCAT(&result->comments, &expr->comments);
1919 		TAILQ_CONCAT(&result->comments, &arg->comments);
1920 		TAILQ_CONCAT(&result->comments, &left->comments);
1921 		TAILQ_CONCAT(&result->comments, &right->comments);
1922 		return result;
1923 	}
1924 
1925 	/* binary-or */
1926 	if (mapContains(expr, "binary-or")) {
1927 		/*
1928 		 * syntax := { "binary-or":
1929 		 *             { "left":  <boolean_expression>,
1930 		 *               "right": <boolean_expression> }
1931 		 *           }
1932 		 * semantics: evaluate branches, return left plus right
1933 		 * branches
1934 		 */
1935 		struct element *arg;
1936 		struct element *left;
1937 		struct element *right;
1938 		struct element *result;
1939 		isc_boolean_t lmodified = ISC_FALSE;
1940 		isc_boolean_t rmodified = ISC_FALSE;
1941 
1942 		arg = mapGet(expr, "binary-or");
1943 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1944 			return expr;
1945 		left = mapGet(arg, "left");
1946 		if (left == NULL)
1947 			return expr;
1948 		right = mapGet(arg, "right");
1949 		if (right == NULL)
1950 			return expr;
1951 		left = eval_numeric_expression(left, &lmodified);
1952 		if (lmodified) {
1953 			mapRemove(arg, "left");
1954 			mapSet(arg, left, "left");
1955 		}
1956 		right = eval_numeric_expression(right, &rmodified);
1957 		if (rmodified) {
1958 			mapRemove(arg, "right");
1959 			mapSet(arg, right, "right");
1960 		}
1961 
1962 		if ((left->type != ELEMENT_INTEGER) ||
1963 		    (right->type != ELEMENT_INTEGER))
1964 			return expr;
1965 		*modifiedp = ISC_TRUE;
1966 		result = createInt(intValue(left) | intValue(right));
1967 		TAILQ_CONCAT(&result->comments, &expr->comments);
1968 		TAILQ_CONCAT(&result->comments, &arg->comments);
1969 		TAILQ_CONCAT(&result->comments, &left->comments);
1970 		TAILQ_CONCAT(&result->comments, &right->comments);
1971 		return result;
1972 	}
1973 
1974 	/* binary-xor */
1975 	if (mapContains(expr, "binary-xor")) {
1976 		/*
1977 		 * syntax := { "binary-xor":
1978 		 *             { "left":  <boolean_expression>,
1979 		 *               "right": <boolean_expression> }
1980 		 *           }
1981 		 * semantics: evaluate branches, return left plus right
1982 		 * branches
1983 		 */
1984 		struct element *arg;
1985 		struct element *left;
1986 		struct element *right;
1987 		struct element *result;
1988 		isc_boolean_t lmodified = ISC_FALSE;
1989 		isc_boolean_t rmodified = ISC_FALSE;
1990 
1991 		arg = mapGet(expr, "binary-xor");
1992 		if ((arg == NULL) || (arg->type != ELEMENT_MAP))
1993 			return expr;
1994 		left = mapGet(arg, "left");
1995 		if (left == NULL)
1996 			return expr;
1997 		right = mapGet(arg, "right");
1998 		if (right == NULL)
1999 			return expr;
2000 		left = eval_numeric_expression(left, &lmodified);
2001 		if (lmodified) {
2002 			mapRemove(arg, "left");
2003 			mapSet(arg, left, "left");
2004 		}
2005 		right = eval_numeric_expression(right, &rmodified);
2006 		if (rmodified) {
2007 			mapRemove(arg, "right");
2008 			mapSet(arg, right, "right");
2009 		}
2010 
2011 		if ((left->type != ELEMENT_INTEGER) ||
2012 		    (right->type != ELEMENT_INTEGER))
2013 			return expr;
2014 		*modifiedp = ISC_TRUE;
2015 		result = createInt(intValue(left) ^ intValue(right));
2016 		TAILQ_CONCAT(&result->comments, &expr->comments);
2017 		TAILQ_CONCAT(&result->comments, &arg->comments);
2018 		TAILQ_CONCAT(&result->comments, &left->comments);
2019 		TAILQ_CONCAT(&result->comments, &right->comments);
2020 		return result;
2021 	}
2022 
2023 	/* client-state */
2024 	if (mapContains(expr, "client-state"))
2025 		/*
2026 		 * syntax := { "client-state": null }
2027 		 * semantic: return client state
2028 		 */
2029 		return expr;
2030 
2031 	return expr;
2032 }
2033 
2034 /*
2035  * Check if the two evaluated expressions are equal, not equal,
2036  * or we can't decide.
2037  */
2038 
2039 static struct element *
eval_equal_expression(struct element * left,struct element * right)2040 eval_equal_expression(struct element *left, struct element *right)
2041 {
2042 	struct element *result = NULL;
2043 	isc_boolean_t val;
2044 
2045 	/* in theory boolean is not possible */
2046 	if (left->type == ELEMENT_BOOLEAN) {
2047 		if (right->type == ELEMENT_BOOLEAN)
2048 			val = ISC_TF(boolValue(left) == boolValue(right));
2049 		else if (right->type == ELEMENT_MAP)
2050 			return NULL;
2051 		else
2052 			val = ISC_FALSE;
2053 	} else
2054 	/* right is boolean */
2055 	if (right->type == ELEMENT_BOOLEAN) {
2056 		if (left->type == ELEMENT_MAP)
2057 			return NULL;
2058 		else
2059 			val = ISC_FALSE;
2060 	} else
2061 	/* left is numeric literal */
2062 	if (left->type == ELEMENT_INTEGER) {
2063 		if (right->type == ELEMENT_INTEGER)
2064 			val = ISC_TF(intValue(left) == intValue(right));
2065 		else if ((right->type == ELEMENT_MAP) &&
2066 			 mapContains(right, "const-int")) {
2067 			struct element *ci;
2068 
2069 			ci = mapGet(right, "const-int");
2070 			if ((ci == NULL) || (ci->type != ELEMENT_INTEGER)) {
2071 				debug("bad const-int");
2072 				return NULL;
2073 			}
2074 			val = ISC_TF(intValue(left) == intValue(ci));
2075 		} else if (right->type == ELEMENT_MAP)
2076 			return NULL;
2077 		else
2078 			val = ISC_FALSE;
2079 	} else
2080 	/* left is const-int */
2081 	if ((left->type == ELEMENT_MAP) && mapContains(left, "const-int")) {
2082 		if (right->type == ELEMENT_INTEGER) {
2083 			struct element *ci;
2084 
2085 			ci = mapGet(left, "const-int");
2086 			if ((ci == NULL) || (ci->type != ELEMENT_INTEGER)) {
2087 				debug("bad const-int");
2088 				return NULL;
2089 			}
2090 			val = ISC_TF(intValue(ci) == intValue(right));
2091 		} else if ((right->type == ELEMENT_MAP) &&
2092 			   mapContains(right, "const-int")) {
2093 			struct element *lci;
2094 			struct element *rci;
2095 
2096 			lci = mapGet(left, "const-int");
2097 			rci = mapGet(right, "const-int");
2098 			if ((lci == NULL) || (lci->type != ELEMENT_INTEGER) ||
2099 			    (rci == NULL) || (rci->type != ELEMENT_INTEGER)) {
2100 				debug("bad const-int");
2101 				return NULL;
2102 			}
2103 			val = ISC_TF(intValue(lci) == intValue(rci));
2104 		} else if (right->type == ELEMENT_MAP)
2105 			return NULL;
2106 		else
2107 			val = ISC_FALSE;
2108 	} else
2109 	/* right is numeric literal */
2110 	if (right->type == ELEMENT_INTEGER) {
2111 		if (left->type == ELEMENT_MAP)
2112 			return NULL;
2113 		else
2114 			val = ISC_FALSE;
2115 	} else
2116 	/* right is const-int */
2117 	if ((right->type == ELEMENT_MAP) && mapContains(right, "const-int")) {
2118 		if (left->type == ELEMENT_MAP)
2119 			return NULL;
2120 		else
2121 			val = ISC_FALSE;
2122 	} else
2123 	/* left is data literal */
2124 	if (left->type == ELEMENT_STRING) {
2125 		if (right->type == ELEMENT_STRING)
2126 			val = cmp_hexa(left, ISC_FALSE, right, ISC_FALSE);
2127 		else if ((right->type == ELEMENT_MAP) &&
2128 			 mapContains(right, "const-data")) {
2129 			struct element *cd;
2130 
2131 			cd = mapGet(right, "const-data");
2132 			if ((cd == NULL) || (cd->type != ELEMENT_STRING)) {
2133 				debug("bad const-data");
2134 				return NULL;
2135 			}
2136 			val = cmp_hexa(left, ISC_FALSE, cd, ISC_TRUE);
2137 		} else if (right->type == ELEMENT_MAP)
2138 			return NULL;
2139 		else
2140 			val = ISC_FALSE;
2141 	} else
2142 	/* left is const-data */
2143 	if ((left->type == ELEMENT_MAP) && mapContains(left, "const-data")) {
2144 		if (right->type == ELEMENT_STRING) {
2145 			struct element *cd;
2146 
2147 			cd = mapGet(left, "const-data");
2148 			if ((cd == NULL) || (cd->type != ELEMENT_STRING)) {
2149 				debug("bad const-data");
2150 				return NULL;
2151 			}
2152 			val = cmp_hexa(cd, ISC_TRUE, right, ISC_FALSE);
2153 		} else if ((right->type == ELEMENT_MAP) &&
2154 			   mapContains(right, "const-data")) {
2155 			struct element *lcd;
2156 			struct element *rcd;
2157 
2158 			lcd = mapGet(left, "const-data");
2159 			rcd = mapGet(right, "const-data");
2160 			if ((lcd == NULL) || (lcd->type != ELEMENT_STRING) ||
2161 			    (rcd == NULL) || (rcd->type != ELEMENT_STRING)) {
2162 				debug("bad const-data");
2163 				return NULL;
2164 			}
2165 			val = cmp_hexa(lcd, ISC_TRUE, rcd, ISC_TRUE);
2166 		} else if (right->type == ELEMENT_MAP)
2167 			return NULL;
2168 		else
2169 			val = ISC_FALSE;
2170 	} else
2171 	/* right is data literal */
2172 	if (right->type == ELEMENT_STRING) {
2173 		if (left->type == ELEMENT_MAP)
2174 			return NULL;
2175 		else
2176 			val = ISC_FALSE;
2177 	} else
2178 	/* right is const-data */
2179 	if ((right->type == ELEMENT_MAP) && mapContains(right, "const-data")) {
2180 		if (left->type == ELEMENT_MAP)
2181 			return NULL;
2182 		else
2183 			val = ISC_FALSE;
2184 	} else
2185 	/* impossible cases */
2186 	if ((left->type != ELEMENT_MAP) || (right->type != ELEMENT_MAP)) {
2187 		debug("equal between unexpected %s and %s",
2188 		      type2name(left->type), type2name(right->type));
2189 		val = ISC_FALSE;
2190 	} else
2191 	/* can't decide */
2192 		return NULL;
2193 
2194 	result = createBool(val);
2195 	TAILQ_CONCAT(&result->comments, &left->comments);
2196 	TAILQ_CONCAT(&result->comments, &right->comments);
2197 	return result;
2198 }
2199 
2200 static isc_boolean_t
cmp_hexa(struct element * left,isc_boolean_t left_is_hexa,struct element * right,isc_boolean_t right_is_hexa)2201 cmp_hexa(struct element *left, isc_boolean_t left_is_hexa,
2202 	 struct element *right, isc_boolean_t right_is_hexa)
2203 {
2204 	struct string *sleft;
2205 	struct string *sright;
2206 
2207 	/* both are not hexa */
2208 	if (!left_is_hexa && !right_is_hexa) {
2209 		sleft = stringValue(left);
2210 		sright = stringValue(right);
2211 		/* eqString() compares lengths them use memcmp() */
2212 		return eqString(sleft, sright);
2213 	}
2214 
2215 	/* both are hexa */
2216 	if (left_is_hexa && right_is_hexa) {
2217 		sleft = stringValue(left);
2218 		sright = stringValue(right);
2219 		if (sleft->length != sright->length)
2220 			return ISC_FALSE;
2221 		if (sleft->length == 0) {
2222 			debug("empty const-data");
2223 			return ISC_TRUE;
2224 		}
2225 		return ISC_TF(strcasecmp(sleft->content,
2226 					 sright->content) == 0);
2227 	}
2228 
2229 	/* put the hexa at left */
2230 	if (left_is_hexa) {
2231 		sleft = hexaValue(left);
2232 		sright = stringValue(right);
2233 	} else {
2234 		sleft = hexaValue(right);
2235 		sright = stringValue(left);
2236 	}
2237 
2238 	/* hexa is double length */
2239 	if (sleft->length != 2 * sright->length)
2240 		return ISC_FALSE;
2241 
2242 	/* build the hexa representation */
2243 	makeStringExt(sright->length, sright->content, 'X');
2244 
2245 	return ISC_TF(strcasecmp(sleft->content, sright->content) == 0);
2246 }
2247 
2248 static void
debug(const char * fmt,...)2249 debug(const char* fmt, ...)
2250 {
2251 	va_list list;
2252 
2253 	va_start(list, fmt);
2254 	vfprintf(stderr, fmt, list);
2255 	fprintf(stderr, "\n");
2256 	va_end(list);
2257 }
2258