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