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