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