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
41static struct element *eval_equal_expression(struct element *,
42					     struct element *);
43static isc_boolean_t cmp_hexa(struct element *, isc_boolean_t,
44			      struct element *,isc_boolean_t);
45static void debug(const char* fmt, ...);
46
47struct element *
48eval_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
76struct element *
77eval_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
480struct element *
481eval_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
1485struct element *
1486eval_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
2039static struct element *
2040eval_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
2200static isc_boolean_t
2201cmp_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
2248static void
2249debug(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