ISC DHCP  4.4.3
A reference DHCPv4 and DHCPv6 implementation
reduce.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 *reduce_equal_expression(struct element *left,
37  struct element *right);
38 static void debug(const char* fmt, ...);
39 
40 /*
41  * boolean_expression :== CHECK STRING |
42  * NOT boolean-expression |
43  * data-expression EQUAL data-expression |
44  * data-expression BANG EQUAL data-expression |
45  * data-expression REGEX_MATCH data-expression |
46  * boolean-expression AND boolean-expression |
47  * boolean-expression OR boolean-expression
48  * EXISTS OPTION-NAME
49  */
50 
51 struct element *
53 {
54  /* trivial case: already done */
55  if (expr->type == ELEMENT_BOOLEAN)
56  return expr;
57 
58  /*
59  * From is_boolean_expression
60  */
61 
62  if (expr->type != ELEMENT_MAP)
63  return NULL;
64 
65  /* check */
66  if (mapContains(expr, "check"))
67  /*
68  * syntax := { "check": <collection_name> }
69  * semantic: check_collection
70  * on server try to match classes of the collection
71  */
72  return NULL;
73 
74 
75  /* exists */
76  if (mapContains(expr, "exists")) {
77  /*
78  * syntax := { "exists":
79  * { "universe": <option_space_old>,
80  * "name": <option_name> }
81  * }
82  * semantic: check universe/code from incoming packet
83  */
84  struct element *arg;
85  struct element *universe;
86  struct element *name;
87  struct option *option;
88  char result[80];
89 
90  arg = mapGet(expr, "exists");
91  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
92  debug("can't get exists argument");
93  return NULL;
94  }
95  universe = mapGet(arg, "universe");
96  if ((universe == NULL) || (universe->type != ELEMENT_STRING)) {
97  debug("can't get exists option universe");
98  return NULL;
99  }
100  name = mapGet(arg, "name");
101  if ((name == NULL) || (name->type != ELEMENT_STRING)) {
102  debug("can't get exists option name");
103  return NULL;
104  }
106  stringValue(name)->content);
107  if ((option == NULL) || (option->code == 0))
108  return NULL;
109  if (((local_family == AF_INET) &&
110  (strcmp(option->space->name, "dhcp4") != 0)) ||
111  ((local_family == AF_INET6) &&
112  (strcmp(option->space->name, "dhcp6") != 0)))
113  return NULL;
114  snprintf(result, sizeof(result),
115  "option[%u].exists", option->code);
116  return createString(makeString(-1, result));
117  }
118 
119  /* variable-exists */
120  if (mapContains(expr, "variable-exists"))
121  /*
122  * syntax := { "variable-exists": <variable_name> }
123  * semantics: find_binding(scope, name)
124  */
125  return NULL;
126 
127  /* equal */
128  if (mapContains(expr, "equal")) {
129  /*
130  * syntax := { "equal":
131  * { "left": <expression>,
132  * "right": <expression> }
133  * }
134  * semantics: evaluate branches and return true
135  * if same type and same value
136  */
137  struct element *arg;
138  struct element *left;
139  struct element *right;
140 
141  arg = mapGet(expr, "equal");
142  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
143  debug("can't get equal argument");
144  return NULL;
145  }
146  left = mapGet(arg, "left");
147  if (left == NULL) {
148  debug("can't get equal left branch");
149  return NULL;
150  }
151  right = mapGet(arg, "right");
152  if (right == NULL) {
153  debug("can't get equal right branch");
154  return NULL;
155  }
156  return reduce_equal_expression(left, right);
157  }
158 
159  /* not-equal */
160  if (mapContains(expr, "not-equal")) {
161  /*
162  * syntax := { "not-equal":
163  * { "left": <expression>,
164  * "right": <expression> }
165  * }
166  * semantics: evaluate branches and return true
167  * if different type or different value
168  */
169  struct element *arg;
170  struct element *left;
171  struct element *right;
172  struct element *equal;
173  struct string *result;
174 
175  arg = mapGet(expr, "not-equal");
176  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
177  debug("can't get not-equal argument");
178  return NULL;
179  }
180  left = mapGet(arg, "left");
181  if (left == NULL) {
182  debug("can't get not-equal left branch");
183  return NULL;
184  }
185  right = mapGet(arg, "right");
186  if (right == NULL) {
187  debug("can't get not-equal right branch");
188  return NULL;
189  }
190  equal = reduce_equal_expression(left, right);
191  if ((equal == NULL) || (equal->type != ELEMENT_STRING))
192  return NULL;
193  result = makeString(-1, "not (");
194  concatString(result, stringValue(equal));
195  appendString(result, ")");
196  return createString(result);
197  }
198 
199  /* regex-match */
200  if (mapContains(expr, "regex-match"))
201  /*
202  * syntax := { "regex-match":
203  * { "left": <data_expression>,
204  * "right": <data_expression> }
205  * }
206  * semantics: evaluate branches, compile right as a
207  * regex and apply it to left
208  */
209  return NULL;
210 
211  /* iregex-match */
212  if (mapContains(expr, "iregex-match"))
213  /*
214  * syntax := { "regex-match":
215  * { "left": <data_expression>,
216  * "right": <data_expression> }
217  * }
218  * semantics: evaluate branches, compile right as a
219  * case insensistive regex and apply it to left
220  */
221  return NULL;
222 
223  /* and */
224  if (mapContains(expr, "and")) {
225  /*
226  * syntax := { "and":
227  * { "left": <boolean_expression>,
228  * "right": <boolean_expression> }
229  * }
230  * semantics: evaluate branches, return true
231  * if both are true
232  */
233  struct element *arg;
234  struct element *left;
235  struct element *right;
236  struct string *result;
237 
238  arg = mapGet(expr, "and");
239  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
240  debug("can't get and argument");
241  return NULL;
242  }
243  left = mapGet(arg, "left");
244  if (left == NULL) {
245  debug("can't get and left branch");
246  return NULL;
247  }
248  right = mapGet(arg, "right");
249  if (right == NULL) {
250  debug("can't get and right branch");
251  return NULL;
252  }
253  left = reduce_boolean_expression(left);
254  if ((left == NULL) || (left->type != ELEMENT_STRING))
255  return NULL;
256  right = reduce_boolean_expression(right);
257  if ((right == NULL) || (right->type != ELEMENT_STRING))
258  return NULL;
259  result = makeString(-1, "(");
260  concatString(result, stringValue(left));
261  appendString(result, ") and (");
262  concatString(result, stringValue(right));
263  appendString(result, ")");
264  return createString(result);
265  }
266 
267  /* or */
268  if (mapContains(expr, "or")) {
269  /*
270  * syntax := { "or":
271  * { "left": <boolean_expression>,
272  * "right": <boolean_expression> }
273  * }
274  * semantics: evaluate branches, return true
275  * if any is true
276  */
277  struct element *arg;
278  struct element *left;
279  struct element *right;
280  struct string *result;
281 
282  arg = mapGet(expr, "or");
283  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
284  debug("can't get or argument");
285  return NULL;
286  }
287  left = mapGet(arg, "left");
288  if (left == NULL) {
289  debug("can't get or left branch");
290  return NULL;
291  }
292  right = mapGet(arg, "right");
293  if (right == NULL) {
294  debug("can't get or right branch");
295  return NULL;
296  }
297  left = reduce_boolean_expression(left);
298  if ((left == NULL) || (left->type != ELEMENT_STRING))
299  return NULL;
300  right = reduce_boolean_expression(right);
301  if ((right == NULL) || (right->type != ELEMENT_STRING))
302  return NULL;
303  result = makeString(-1, "(");
304  concatString(result, stringValue(left));
305  appendString(result, ") or (");
306  concatString(result, stringValue(right));
307  appendString(result, ")");
308  return createString(result);
309  }
310 
311  /* not */
312  if (mapContains(expr, "not")) {
313  /*
314  * syntax := { "not": <boolean_expression> }
315  * semantic: evaluate its branch and return its negation
316  */
317  struct element *arg;
318  struct string *result;
319 
320  arg = mapGet(expr, "not");
321  if (arg == NULL) {
322  debug("can't get not argument");
323  return NULL;
324  }
325  arg = reduce_boolean_expression(arg);
326  if ((arg == NULL) || (arg->type != ELEMENT_STRING))
327  return NULL;
328  result = makeString(-1, "not (");
329  concatString(result, stringValue(arg));
330  appendString(result, ")");
331  return createString(result);
332  }
333 
334  /* known */
335  if (mapContains(expr, "known"))
336  /*
337  * syntax := { "known": null }
338  * semantics: client is known, i.e., has a matching
339  * host declaration (aka reservation in Kea)
340  */
341  return NULL;
342 
343  /* static */
344  if (mapContains(expr, "static"))
345  /*
346  * syntax := { "static": null }
347  * semantics: lease is static (doesn't exist in Kea)
348  */
349  return NULL;
350 
351  return NULL;
352 }
353 
354 /*
355  * data_expression :== SUBSTRING LPAREN data-expression COMMA
356  * numeric-expression COMMA
357  * numeric-expression RPAREN |
358  * CONCAT LPAREN data-expression COMMA
359  * data-expression RPAREN
360  * SUFFIX LPAREN data_expression COMMA
361  * numeric-expression RPAREN |
362  * LCASE LPAREN data_expression RPAREN |
363  * UCASE LPAREN data_expression RPAREN |
364  * OPTION option_name |
365  * HARDWARE |
366  * PACKET LPAREN numeric-expression COMMA
367  * numeric-expression RPAREN |
368  * V6RELAY LPAREN numeric-expression COMMA
369  * data-expression RPAREN |
370  * STRING |
371  * colon_separated_hex_list
372  */
373 
374 struct element *
376 {
377  /* trivial case: already done */
378  if (expr->type == ELEMENT_STRING)
379  return expr;
380 
381  /*
382  * From is_data_expression
383  */
384 
385  if (expr->type != ELEMENT_MAP)
386  return NULL;
387 
388  /* substring */
389  if (mapContains(expr, "substring")) {
390  /*
391  * syntax := { "substring":
392  * { "expression": <data_expression>,
393  * "offset": <numeric_expression>,
394  * "length": <numeric_expression> }
395  * }
396  * semantic: evaluate arguments, if the string is
397  * shorter than offset return "" else return substring
398  */
399  struct element *arg;
400  struct element *string;
401  struct element *offset;
402  struct element *length;
403  struct string *result;
404  int64_t off;
405  int64_t len;
406  char buf[80];
407 
408  arg = mapGet(expr, "substring");
409  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
410  debug("can't get substring argument");
411  return NULL;
412  }
413  string = mapGet(arg, "expression");
414  if (string == NULL) {
415  debug("can't get substring expression");
416  return NULL;
417  }
418  offset = mapGet(arg, "offset");
419  if (offset == NULL) {
420  debug("can't get substring offset");
421  return NULL;
422  }
423  length = mapGet(arg, "length");
424  if (length == NULL) {
425  debug("can't get substring length");
426  return NULL;
427  }
428  /* can't be a literal as it was evaluated before */
429  string = reduce_data_expression(string);
430  if ((string == NULL) || (string->type != ELEMENT_STRING))
431  return NULL;
432  offset = reduce_numeric_expression(offset);
433  if ((offset == NULL) || (offset->type != ELEMENT_INTEGER))
434  return NULL;
435  off = intValue(offset);
436  if (off < 0) {
437  debug("substring with a negative offset (%lld)",
438  (long long)off);
439  return NULL;
440  }
442  if ((length == NULL) || (length->type != ELEMENT_INTEGER))
443  return NULL;
444  len = intValue(length);
445  if (len < 0) {
446  debug("substring with a negative length (%lld)",
447  (long long)len);
448  return NULL;
449  }
450  result = makeString(-1, "substring(");
451  concatString(result, stringValue(string));
452  snprintf(buf, sizeof(buf),
453  ",%u,%u)", (unsigned)off, (unsigned)len);
454  appendString(result, buf);
455  return createString(result);
456  }
457 
458  /* suffix */
459  if (mapContains(expr, "suffix")) {
460  /*
461  * syntax := { "suffix":
462  * { "expression": <data_expression>,
463  * "length": <numeric_expression> }
464  * }
465  * semantic: evaluate arguments, if the string is
466  * shorter than length return it else return suffix
467  */
468  struct element *arg;
469  struct element *string;
470  struct element *length;
471  struct string *result;
472  int64_t len;
473  char buf[80];
474 
475  arg = mapGet(expr, "suffix");
476  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
477  debug("can't get suffix argument");
478  return NULL;
479  }
480  string = mapGet(arg, "expression");
481  if (string == NULL) {
482  debug("can't get suffix expression");
483  return NULL;
484  }
485  length = mapGet(arg, "length");
486  if (length == NULL) {
487  debug("can't get suffix length");
488  return NULL;
489  }
490  /* can't be a literal as it was evaluated before */
491  string = reduce_data_expression(string);
492  if ((string == NULL) || (string->type != ELEMENT_STRING))
493  return NULL;
495  if ((length == NULL) || (length->type != ELEMENT_INTEGER))
496  return NULL;
497  len = intValue(length);
498  if (len < 0) {
499  debug("suffix with a negative length (%lld)",
500  (long long)len);
501  return NULL;
502  }
503  result = makeString(-1, "substring(");
504  concatString(result, stringValue(string));
505  snprintf(buf, sizeof(buf), ",-%u,all)", (unsigned)len);
506  appendString(result, buf);
507  return createString(result);
508  }
509 
510  /* lowercase */
511  if (mapContains(expr, "lowercase"))
512  /*
513  * syntax := { "lowercase": <data_expression> }
514  * semantic: evaluate its argument and apply tolower to
515  * its content
516  */
517  return NULL;
518 
519  /* uppercase */
520  if (mapContains(expr, "uppercase"))
521  /*
522  * syntax := { "uppercase": <data_expression> }
523  * semantic: evaluate its argument and apply toupper to
524  * its content
525  */
526  return NULL;
527 
528  /* option */
529  if (mapContains(expr, "option")) {
530  /*
531  * syntax := { "option":
532  * { "universe": <option_space_old>,
533  * "name": <option_name> }
534  * }
535  * semantic: get universe/code option from incoming packet
536  */
537  struct element *arg;
538  struct element *universe;
539  struct element *name;
540  struct option *option;
541  char result[80];
542 
543  arg = mapGet(expr, "option");
544  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
545  debug("can't get option argument");
546  return NULL;
547  }
548  universe = mapGet(arg, "universe");
549  if ((universe == NULL) || (universe->type != ELEMENT_STRING)) {
550  debug("can't get option universe");
551  return NULL;
552  }
553  name = mapGet(arg, "name");
554  if ((name == NULL) || (name->type != ELEMENT_STRING)) {
555  debug("can't get option name");
556  return NULL;
557  }
559  stringValue(name)->content);
560  if ((option == NULL) || (option->code == 0))
561  return NULL;
562  if (((local_family == AF_INET) &&
563  (strcmp(option->space->name, "dhcp4") != 0)) ||
564  ((local_family == AF_INET6) &&
565  (strcmp(option->space->name, "dhcp6") != 0)))
566  return NULL;
567  snprintf(result, sizeof(result),
568  "option[%u].hex", option->code);
569  return createString(makeString(-1, result));
570  }
571 
572  /* hardware */
573  if (mapContains(expr, "hardware")) {
574  /*
575  * syntax := { "hardware": null }
576  * semantic: get mac type and address from incoming packet
577  */
578  struct string *result;
579 
580  if (local_family != AF_INET) {
581  debug("get hardware for DHCPv6");
582  return NULL;
583  }
584  result = makeString(-1,
585  "concat(substring(pkt4.htype,-1,all),pkt4.mac)");
586  return createString(result);
587  }
588 
589  /* hw-type */
590  if (mapContains(expr, "hw-type")) {
591  /*
592  * ADDED
593  * syntax := { "hw-type": null }
594  * semantic: get mac type from incoming packet
595  */
596  struct string *result;
597 
598  if (local_family != AF_INET) {
599  debug("get hw-type for DHCPv6");
600  return NULL;
601  }
602  result = makeString(-1, "substring(pkt4.htype,-1,all)");
603  return createString(result);
604  }
605 
606  /* hw-address */
607  if (mapContains(expr, "hw-address")) {
608  /*
609  * ADDED
610  * syntax := { "hw-address": null }
611  * semantic: get mac address from incoming packet
612  */
613  struct string *result;
614 
615  if (local_family != AF_INET) {
616  debug("get hw-address for DHCPv6");
617  return NULL;
618  }
619  result = makeString(-1, "pkt4.mac");
620  return createString(result);
621  }
622 
623  /* const-data */
624  if (mapContains(expr, "const-data")) {
625  /*
626  * syntax := { "const-data": <string> }
627  * semantic: embedded string value
628  */
629  struct element *arg;
630 
631  arg = mapGet(expr, "const-data");
632  if ((arg == NULL) || (arg->type != ELEMENT_STRING)) {
633  debug("can't get const-data argument");
634  return NULL;
635  }
636  return createString(stringValue(arg));
637  }
638 
639  /* packet */
640  if (mapContains(expr, "packet"))
641  /*
642  * syntax := { "packet":
643  * { "offset": <numeric_expression>,
644  * "length": <numeric_expression> }
645  * }
646  * semantic: return the selected substring of the incoming
647  * packet content
648  */
649  return NULL;
650 
651  /* concat */
652  if (mapContains(expr, "concat")) {
653  /*
654  * syntax := { "concat":
655  * { "left": <data_expression>,
656  * "right": <data_expression> }
657  * }
658  * semantic: evaluate arguments and return the concatenation
659  */
660  struct element *arg;
661  struct element *left;
662  struct element *right;
663  struct string *result;
664 
665  arg = mapGet(expr, "concat");
666  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
667  debug("can't get concat argument");
668  return NULL;
669  }
670  left = mapGet(arg, "left");
671  if (left == NULL) {
672  debug("can't get concat left branch");
673  return NULL;
674  }
675  right = mapGet(arg, "right");
676  if (right == NULL) {
677  debug("can't get concat right branch");
678  return NULL;
679  }
680  /* left is a literal case */
681  if (left->type == ELEMENT_STRING) {
682  /* can't be a literal as it was evaluated before */
683  right = reduce_data_expression(right);
684  if ((right == NULL) || (right->type != ELEMENT_STRING))
685  return NULL;
686  result = makeString(-1, "concat(");
687  concatString(result, quote(stringValue(left)));
688  appendString(result, ", ");
689  concatString(result, stringValue(right));
690  appendString(result, ")");
691  return createString(result);
692  }
693  left = reduce_data_expression(left);
694  if ((left == NULL) || (left->type != ELEMENT_STRING))
695  return NULL;
696  /* right is a literal case */
697  if (right->type == ELEMENT_STRING) {
698  /* literal left was handled before */
699  result = makeString(-1, "concat(");
700  concatString(result, stringValue(left));
701  appendString(result, ", ");
702  concatString(result, quote(stringValue(right)));
703  appendString(result, ")");
704  return createString(result);
705  }
706  right = reduce_data_expression(right);
707  if ((right == NULL) || (right->type != ELEMENT_STRING))
708  return NULL;
709  result = makeString(-1, "concat(");
710  concatString(result, stringValue(left));
711  appendString(result, ", ");
712  concatString(result, stringValue(right));
713  appendString(result, ")");
714  return createString(result);
715  }
716 
717  /* encapsulate */
718  if (mapContains(expr, "encapsulate"))
719  /*
720  * syntax := { "encapsulate": <encapsulated_space> }
721  * semantic: encapsulate options of the given space
722  */
723  return NULL;
724 
725  /* encode-int8 */
726  if (mapContains(expr, "encode-int8"))
727  /*
728  * syntax := { "encode-int8": <numeric_expression> }
729  * semantic: return a string buffer with the evaluated
730  * number as content
731  */
732  return NULL;
733 
734  /* encode-int16 */
735  if (mapContains(expr, "encode-int16"))
736  /*
737  * syntax := { "encode-int16": <numeric_expression> }
738  * semantic: return a string buffer with the evaluated
739  * number as content
740  */
741  return NULL;
742 
743  /* encode-int32 */
744  if (mapContains(expr, "encode-int32"))
745  /*
746  * syntax := { "encode-int32": <numeric_expression> }
747  * semantic: return a string buffer with the evaluated
748  * number as content
749  */
750  return NULL;
751 
752  /* gethostbyname */
753  if (mapContains(expr, "gethostbyname"))
754  /*
755  * syntax := { "gethostbyname": <string> }
756  * semantic: call gethostbyname and return
757  * a binary buffer with addresses
758  */
759  return NULL;
760 
761  /* binary-to-ascii */
762  if (mapContains(expr, "binary-to-ascii"))
763  /*
764  * syntax := { "binary-to-ascii":
765  * { "base": <numeric_expression 2..16>,
766  * "width": <numeric_expression 8, 16 or 32>,
767  * "separator": <data_expression>,
768  * "buffer": <data_expression> }
769  * }
770  * semantic: split the input buffer into int8/16/32 numbers,
771  * output them separated by the given string
772  */
773  return NULL;
774 
775  /* filename */
776  if (mapContains(expr, "filename"))
777  /*
778  * syntax := { "filename": null }
779  * semantic: get filename field from incoming DHCPv4 packet
780  */
781  return NULL;
782 
783  /* server-name */
784  if (mapContains(expr, "server-name"))
785  /*
786  * syntax := { "server-name": null }
787  * semantic: get server-name field from incoming DHCPv4 packet
788  */
789  return NULL;
790 
791  /* reverse */
792  if (mapContains(expr, "reverse"))
793  /*
794  * syntax := { "reverse":
795  * { "width": <numeric_expression>,
796  * "buffer": <data_expression> }
797  * }
798  * semantic: reverse the input buffer by width chunks of bytes
799  */
800  return NULL;
801 
802  /* pick-first-value */
803  if (mapContains(expr, "pick-first-value"))
804  /*
805  * syntax := { "pick-first-value":
806  * [ <data_expression>, ... ]
807  * }
808  * semantic: evaluates expressions and return the first
809  * not null, return null if all are null
810  */
811  return NULL;
812 
813  /* host-decl-name */
814  if (mapContains(expr, "host-decl-name"))
815  /*
816  * syntax := { "host-decl-name": null }
817  * semantic: return the name of the matching host
818  * declaration (aka revervation in kea) or null
819  */
820  return NULL;
821 
822  /* leased-address */
823  if (mapContains(expr, "leased-address"))
824  /*
825  * syntax := { "leased-address": null }
826  * semantic: return the address of the assigned lease or
827  * log a message
828  */
829  return NULL;
830 
831  /* config-option */
832  if (mapContains(expr, "config-option"))
833  /*
834  * syntax := { "config-option":
835  * { "universe": <option_space_old>,
836  * "name": <option_name> }
837  * }
838  * semantic: get universe/code option to send
839  */
840  return NULL;
841 
842  /* null */
843  if (mapContains(expr, "null")) {
844  /*
845  * syntax := { "null": null }
846  * semantic: return null
847  */
848  debug("unexpected null: this expression was not evaluated");
849  return NULL;
850  }
851 
852  /* gethostname */
853  if (mapContains(expr, "gethostname")) {
854  /*
855  * syntax := { "gethostname": null }
856  * semantic: return gethostname
857  */
858  debug("unexpected gethostname: this expression was not "
859  "evaluated");
860  return NULL;
861  }
862 
863  /* v6relay */
864  if (mapContains(expr, "v6relay")) {
865  /*
866  * syntax := { "v6relay":
867  * { "relay": <numeric_expression>,
868  * "relay-option" <data_expression> }
869  * }
870  * semantic: relay is a counter from client, 0 is no-op,
871  * 1 is the relay closest to the client, etc, option
872  * is a dhcp6 option ans is return when found
873  */
874  struct element *arg;
875  struct element *relay;
876  struct element *universe;
877  struct element *name;
878  struct option *option;
879  int64_t r;
880  char result[100];
881 
882  if (local_family != AF_INET6) {
883  debug("get v6relay for DHCPv4");
884  return NULL;
885  }
886  arg = mapGet(expr, "v6relay");
887  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
888  debug("can't get v6relay argument");
889  return NULL;
890  }
891  relay = mapGet(arg, "relay");
892  if (relay == NULL) {
893  debug("can't get v6relay relay");
894  return NULL;
895  }
896  relay = reduce_numeric_expression(relay);
897  if ((relay == NULL) || (relay->type != ELEMENT_INTEGER))
898  return NULL;
899  r = intValue(relay);
900  if (r < 0) {
901  debug("v6relay called with illegal relay (%lld)",
902  (long long)r);
903  return NULL;
904  }
905  arg = mapGet(arg, "relay-option");
906  if ((arg == NULL) || (arg->type != ELEMENT_MAP)) {
907  debug("can't get v6relay relay-option");
908  return NULL;
909  }
910  universe = mapGet(arg, "universe");
911  if ((universe == NULL) || (universe->type != ELEMENT_STRING)) {
912  debug("can't get v6relay option universe");
913  NULL;
914  }
915  name = mapGet(arg, "name");
916  if ((name == NULL) || (name->type != ELEMENT_STRING)) {
917  debug("can't get v6relay option name");
918  return NULL;
919  }
921  stringValue(name)->content);
922  if ((option == NULL) || (option->code == 0) ||
923  (strcmp(option->space->name, "dhcp6") != 0))
924  return NULL;
925  if (r == 0)
926  snprintf(result, sizeof(result),
927  "option[%u].hex", option->code);
928  else {
929  /* r > MAX_V6RELAY_HOPS means the relay closest
930  to server */
931  if (r > MAX_V6RELAY_HOPS)
932  r = 0;
933  /* Kea counts from the server, use negative nesting
934  levels to count from the client */
935  snprintf(result, sizeof(result),
936  "relay6[%d].option[%u].hex",
937  (int)-r, option->code);
938  }
939  return createString(makeString(-1, result));
940  }
941 
942  return NULL;
943 }
944 
945 struct element *
947 {
948  /* trivial case: already done */
949  if (expr->type == ELEMENT_INTEGER)
950  return expr;
951 
952  if (expr->type != ELEMENT_MAP)
953  return NULL;
954 
955  /* Kea has no numeric operators... */
956  return NULL;
957 }
958 
959 static struct element *
960 reduce_equal_expression(struct element *left, struct element *right)
961 {
962  struct string *result;
963 
964  /*
965  * numeric case was handled by evaluation
966  */
967 
968  if (!is_data_expression(left) || !is_data_expression(right))
969  return NULL;
970 
971  /* left is a literal case */
972  if (left->type == ELEMENT_STRING) {
973  /* can't be a literal as it was evaluated before */
974  right = reduce_data_expression(right);
975  if ((right == NULL) || (right->type != ELEMENT_STRING))
976  return NULL;
977  result = allocString();
978  concatString(result, quote(stringValue(left)));
979  appendString(result, " == ");
980  concatString(result, stringValue(right));
981  return createString(result);
982  }
983  left = reduce_data_expression(left);
984  if ((left == NULL) || (left->type != ELEMENT_STRING))
985  return NULL;
986 
987  /* right is a literal case */
988  if (right->type == ELEMENT_STRING) {
989  /* literal left was handled before */
990  result = allocString();
991  concatString(result, stringValue(left));
992  appendString(result, " == ");
993  concatString(result, quote(stringValue(right)));
994  return createString(result);
995  }
996  right = reduce_data_expression(right);
997  if ((right == NULL) || (right->type != ELEMENT_STRING))
998  return NULL;
999 
1000  result = allocString();
1001  concatString(result, stringValue(left));
1002  appendString(result, " == ");
1003  concatString(result, stringValue(right));
1004  return createString(result);
1005 }
1006 
1007 static void
1008 debug(const char* fmt, ...)
1009 {
1010  va_list list;
1011 
1012  va_start(list, fmt);
1013  vfprintf(stderr, fmt, list);
1014  fprintf(stderr, "\n");
1015  va_end(list);
1016 }
struct string * quote(struct string *s)
Definition: data.c:356
void concatString(struct string *s, const struct string *a)
Definition: data.c:330
struct string * makeString(int l, const char *s)
Definition: data.c:44
struct element * mapGet(struct element *m, const char *k)
Definition: data.c:759
struct string * stringValue(struct element *e)
Definition: data.c:408
void appendString(struct string *s, const char *a)
Definition: data.c:311
isc_boolean_t mapContains(const struct element *m, const char *k)
Definition: data.c:811
struct string * allocString(void)
Definition: data.c:32
struct element * createString(const struct string *s)
Definition: data.c:492
int64_t intValue(const struct element *e)
Definition: data.c:383
#define ELEMENT_INTEGER
Definition: data.h:162
#define ELEMENT_STRING
Definition: data.h:166
#define ELEMENT_BOOLEAN
Definition: data.h:164
#define ELEMENT_MAP
Definition: data.h:168
#define MAX_V6RELAY_HOPS
Definition: dhcp6.h:246
int local_family
Definition: discover.c:59
struct option * option_lookup_name(const char *, const char *)
Definition: options.c:579
struct element * reduce_numeric_expression(struct element *expr)
Definition: reduce.c:946
struct element * reduce_data_expression(struct element *expr)
Definition: reduce.c:375
struct element * reduce_boolean_expression(struct element *expr)
Definition: reduce.c:52
Definition: data.h:216
int type
Definition: data.h:217
Definition: tree.h:345
unsigned code
Definition: tree.h:349
const struct space * space
Definition: keama.h:295
const char * name
Definition: tree.h:346
const char * name
Definition: keama.h:285
Definition: data.h:171
size_t length
Definition: data.h:172
Definition: tree.h:301
int is_data_expression(struct expression *expr)
Definition: tree.c:3048