Home | History | Annotate | Line # | Download | only in keama
      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 (at) 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 *
     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 *
     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 *
    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 *
   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 *
   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
   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
   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