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