Changeset 168:6db078b955e3 in freeDiameter for extensions/rt_default
- Timestamp:
- Feb 2, 2010, 10:15:05 AM (14 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- extensions/rt_default
- Files:
-
- 1 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
extensions/rt_default/CMakeLists.txt
r167 r168 1 1 # The rt_default extension 2 2 PROJECT("Configurable routing extension" C) 3 4 # Check if REG_STARTEND is provided on the host 5 SET(CHECK_REG_STARTEND_SOURCE_CODE " 6 #include <unistd.h> 7 #include <regex.h> 8 int main() { 9 return regexec(NULL, NULL, 0, NULL, REG_STARTEND); 10 } 11 ") 12 CHECK_C_SOURCE_COMPILES("${CHECK_REG_STARTEND_SOURCE_CODE}" HAVE_REG_STARTEND) 13 # Generate the host.h file 14 CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/rt_default-host.h.in ${CMAKE_CURRENT_BINARY_DIR}/rt_default-host.h) 3 15 4 16 # Parser files … … 17 29 ) 18 30 31 INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) 32 19 33 # Compile these files as a freeDiameter extension 20 34 FD_ADD_EXTENSION(rt_default ${RT_DEFAULT_SRC}) -
extensions/rt_default/rt_default.c
r167 r168 69 69 CHECK_FCT( rtd_conf_handle(conffile) ); 70 70 71 #if 171 #if 0 72 72 /* Dump the rules */ 73 73 rtd_dump(); -
extensions/rt_default/rt_default.h
r167 r168 39 39 */ 40 40 41 /* FreeDiameter's common include file */ 41 42 #include <freeDiameter/extension.h> 43 44 /* Host configuration for this specific extension */ 45 #include <rt_default-host.h> 42 46 43 47 /* Parse the configuration file */ -
extensions/rt_default/rtd_conf.l
r167 r168 133 133 (?i:"un") { return UN; } 134 134 (?i:"si") { return SI; } 135 (?i:"i") { return IDENTITY;} 136 (?i:"r") { return REALM; } 135 (?i:"rlm") { return REALM; } 137 136 138 137 /* Valid single characters for yyparse */ -
extensions/rt_default/rtd_conf.y
r167 r168 152 152 %token SI 153 153 154 %token IDENTITY155 154 %token REALM 156 155 … … 180 179 YYERROR; 181 180 } ); 181 182 rules_added++; 182 183 } 183 184 ; … … 242 243 243 244 /* Details of the TARGET type */ 244 TARGET: IDENTITY '='TSTRING245 { 246 $$.str = $ 3.str;247 $$.regex =$ 3.regex;245 TARGET: TSTRING 246 { 247 $$.str = $1.str; 248 $$.regex =$1.regex; 248 249 $$.type = RTD_TAR_ID; 249 250 } -
extensions/rt_default/rtd_rules.c
r167 r168 50 50 */ 51 51 52 /* Structure to hold the data that is used for matching. Note that in case is_regex is true, the string to be matched must be \0-terminated.*/52 /* Structure to hold the data that is used for matching. */ 53 53 struct match_data { 54 54 int is_regex; /* determines how the string is matched */ … … 57 57 }; 58 58 59 /* The sentinels for the TARGET lists */ 60 static struct fd_list TARGETS[RTD_TAR_MAX]; 61 59 62 /* Structure of a TARGET element */ 60 63 struct target { 61 struct fd_list chain; /* link in the top-level list */62 struct match_data md; /* the data to determine if the current candidate matches this element */63 struct fd_list rules ; /* Sentinel for the list of rules applying to this target*/64 struct fd_list chain; /* link in the top-level list */ 65 struct match_data md; /* the data to determine if the current candidate matches this element */ 66 struct fd_list rules[RTD_CRI_MAX]; /* Sentinels for the lists of rules applying to this target. One list per rtd_crit_type */ 64 67 /* note : we do not need the rtd_targ_type here, it is implied by the root of the list this target element is attached to */ 65 68 }; … … 68 71 struct rule { 69 72 struct fd_list chain; /* link in the parent target list */ 70 enum rtd_crit_type type; /* What kind of criteria the message must match for the rule to apply */ 71 struct match_data md; /* the data that the criteria must match, if it is different from RTD_CRI_ALL */ 73 struct match_data md; /* the data that the criteria must match, -- ignored for RTD_CRI_ALL */ 72 74 int score; /* The score added to the candidate, if the message matches this criteria */ 75 /* The type of rule depends on the sentinel */ 73 76 }; 74 77 75 /* The sentinels for the TARGET lists */ 76 static struct fd_list TARGETS[RTD_TAR_MAX]; 77 78 79 78 /*********************************************************************/ 79 80 /* Compile a regular expression pattern */ 81 static int compile_regex( regex_t * preg, char * str ) 82 { 83 int err; 84 85 /* Compile the regular expression */ 86 err = regcomp(preg, str, REG_EXTENDED | REG_NOSUB); 87 if (err != 0) { 88 char * buf; 89 size_t bl; 90 91 /* Error while compiling the regex */ 92 TRACE_DEBUG(INFO, "Error while compiling the regular expression '%s':", str); 93 94 /* Get the error message size */ 95 bl = regerror(err, preg, NULL, 0); 96 97 /* Alloc the buffer for error message */ 98 CHECK_MALLOC( buf = malloc(bl) ); 99 100 /* Get the error message content */ 101 regerror(err, preg, buf, bl); 102 TRACE_DEBUG(INFO, "\t%s", buf); 103 104 /* Free the buffer, return the error */ 105 free(buf); 106 return EINVAL; 107 } 108 109 return 0; 110 } 111 112 /* Create a target item and initialize its content */ 113 static struct target * new_target(char * str, int regex) 114 { 115 int i; 116 struct target *new = NULL; 117 CHECK_MALLOC_DO( new = malloc(sizeof(struct target)), return NULL ); 118 memset(new, 0, sizeof(struct target)); 119 120 fd_list_init(&new->chain, new); 121 new->md.plain = str; 122 new->md.is_regex = regex; 123 if (regex) { 124 CHECK_FCT_DO( compile_regex(&new->md.preg, str), 125 { 126 free(new); 127 return NULL; 128 } ); 129 } 130 for (i = 0; i < RTD_CRI_MAX; i++) { 131 fd_list_init(&new->rules[i], new); 132 } 133 return new; 134 } 135 136 /* Create a rule item and initialize its content; return NULL in case of error */ 137 static struct rule * new_rule(char * str, int regex, int score) 138 { 139 struct rule *new = NULL; 140 CHECK_MALLOC_DO( new = malloc(sizeof(struct rule)), return NULL ); 141 memset(new, 0, sizeof(struct rule)); 142 143 fd_list_init(&new->chain, new); 144 new->md.plain = str; 145 new->md.is_regex = regex; 146 if (regex) { 147 CHECK_FCT_DO( compile_regex(&new->md.preg, str), 148 { 149 free(new); 150 return NULL; 151 } ); 152 } 153 new->score = score; 154 return new; 155 } 156 157 /* Debug functions */ 158 static void dump_rule(int indent, struct rule * rule) 159 { 160 fd_log_debug("%*s%s%s%s += %d\n", 161 indent, "", 162 rule->md.is_regex ? "[" : "'", 163 rule->md.plain, 164 rule->md.is_regex ? "]" : "'", 165 rule->score); 166 } 167 static void dump_target(int indent, struct target * target) 168 { 169 int i; 170 fd_log_debug("%*s%s%s%s :\n", 171 indent, "", 172 target->md.is_regex ? "[" : "'", 173 target->md.plain ?: "(empty)", 174 target->md.is_regex ? "]" : "'"); 175 for (i = 0; i < RTD_CRI_MAX; i++) { 176 if (! FD_IS_LIST_EMPTY(&target->rules[i])) { 177 struct fd_list * li; 178 fd_log_debug("%*s rules[%d]:\n", 179 indent, "", i); 180 for (li = target->rules[i].next; li != &target->rules[i]; li = li->next) { 181 dump_rule(indent + 3, (struct rule *)li); 182 } 183 } 184 } 185 } 186 187 static void clear_md(struct match_data * md) 188 { 189 /* delete the string */ 190 if (md->plain) { 191 free(md->plain); 192 md->plain = NULL; 193 } 194 195 /* delete the preg if needed */ 196 if (md->is_regex) { 197 regfree(&md->preg); 198 md->is_regex = 0; 199 } 200 } 201 202 /* Destroy a rule item */ 203 static void del_rule(struct rule * del) 204 { 205 /* Unlink this rule */ 206 fd_list_unlink(&del->chain); 207 208 /* Delete the match data */ 209 clear_md(&del->md); 210 211 free(del); 212 } 213 214 /* Destroy a target item, and all its rules */ 215 static void del_target(struct target * del) 216 { 217 int i; 218 219 /* Unlink this target */ 220 fd_list_unlink(&del->chain); 221 222 /* Delete the match data */ 223 clear_md(&del->md); 224 225 /* Delete the children rules */ 226 for (i = 0; i < RTD_CRI_MAX; i++) { 227 while (! FD_IS_LIST_EMPTY(&del->rules[i]) ) { 228 del_rule((struct rule *)(del->rules[i].next)); 229 } 230 } 231 232 free(del); 233 } 234 235 236 /* Compare a string with a match_data value. *res contains the result of the comparison (always >0 for regex non-match situations) */ 237 static int compare_match(char * str, size_t len, struct match_data * md, int * res) 238 { 239 int err; 240 241 CHECK_PARAMS( str && md && res ); 242 243 /* Plain strings: we compare with strncasecmp */ 244 if (md->is_regex == 0) { 245 *res = strncasecmp(str, md->plain, len); 246 return 0; 247 } 248 249 /* Regexp */ 250 *res = 1; 251 252 #ifdef HAVE_REG_STARTEND 253 { 254 regmatch_t pmatch[1]; 255 memset(pmatch, 0, sizeof(pmatch)); 256 pmatch[0].rm_so = 0; 257 pmatch[0].rm_eo = len; 258 err = regexec(&md->preg, str, 0, pmatch, REG_STARTEND); 259 } 260 #else /* HAVE_REG_STARTEND */ 261 { 262 /* We have to create a copy of the string in this case */ 263 char *mystrcpy; 264 CHECK_MALLOC( mystrcpy = malloc(len + 1) ); 265 memcpy(mystrcpy, str, len); 266 mystrcpy[len] = '\0'; 267 err = regexec(&md->preg, mystrcpy, 0, NULL, 0); 268 free(mystrcpy); 269 } 270 #endif /* HAVE_REG_STARTEND */ 271 272 /* Now check the result */ 273 if (err == 0) { 274 /* We have a match */ 275 *res = 0; 276 return 0; 277 } 278 279 if (err == REG_NOMATCH) { 280 *res = 1; 281 return 0; 282 } 283 284 /* In other cases, we have an error */ 285 { 286 char * buf; 287 size_t bl; 288 289 /* Error while compiling the regex */ 290 TRACE_DEBUG(INFO, "Error while executing the regular expression '%s':", md->plain); 291 292 /* Get the error message size */ 293 bl = regerror(err, &md->preg, NULL, 0); 294 295 /* Alloc the buffer for error message */ 296 CHECK_MALLOC( buf = malloc(bl) ); 297 298 /* Get the error message content */ 299 regerror(err, &md->preg, buf, bl); 300 TRACE_DEBUG(INFO, "\t%s", buf); 301 302 /* Free the buffer, return the error */ 303 free(buf); 304 } 305 306 return (err == REG_ESPACE) ? ENOMEM : EINVAL; 307 } 308 309 /* Search in list (targets or rules) the next matching item for string str(len). Returned in next_match, or *next_match == NULL if no more match. Re-enter with same next_match for the next one. */ 310 static int get_next_match(struct fd_list * list, char * str, size_t len, struct fd_list ** next_match) 311 { 312 struct fd_list * li; 313 314 TRACE_ENTRY("%p %p %zd %p", list, str, len, next_match); 315 CHECK_PARAMS(list && str && len && next_match); 316 317 if (*next_match) 318 li = (*next_match)->next; 319 else 320 li = list->next; 321 322 /* Initialize the return value */ 323 *next_match = NULL; 324 325 for ( ; li != list; li = li->next) { 326 int cmp; 327 struct { 328 struct fd_list chain; 329 struct match_data md; 330 } * next_item = (void *)li; 331 332 /* Check if the string matches this next item */ 333 CHECK_FCT( compare_match(str, len, &next_item->md, &cmp) ); 334 335 if (cmp == 0) { 336 /* matched! */ 337 *next_match = li; 338 return 0; 339 } 340 341 if (cmp < 0) /* we can stop searching */ 342 break; 343 } 344 345 /* We're done with the list */ 346 return 0; 347 } 348 349 static struct dict_object * AVP_MODELS[RTD_CRI_MAX]; 350 351 /*********************************************************************/ 352 353 /* Prepare the module */ 80 354 int rtd_init(void) 81 355 { 356 int i; 357 82 358 TRACE_ENTRY(); 83 359 360 for (i = 0; i < RTD_TAR_MAX; i++) { 361 fd_list_init(&TARGETS[i], NULL); 362 } 363 364 for (i = 1; i < RTD_CRI_MAX; i++) { 365 switch (i) { 366 case RTD_CRI_OH: 367 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &AVP_MODELS[i], ENOENT )); 368 break; 369 case RTD_CRI_OR: 370 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &AVP_MODELS[i], ENOENT )); 371 break; 372 case RTD_CRI_DH: 373 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &AVP_MODELS[i], ENOENT )); 374 break; 375 case RTD_CRI_DR: 376 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &AVP_MODELS[i], ENOENT )); 377 break; 378 case RTD_CRI_UN: 379 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &AVP_MODELS[i], ENOENT )); 380 break; 381 case RTD_CRI_SI: 382 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &AVP_MODELS[i], ENOENT )); 383 break; 384 default: 385 TRACE_DEBUG(INFO, "Missing definition in extension initializer"); 386 ASSERT( 0 ); 387 return EINVAL; 388 } 389 } 390 84 391 return 0; 85 392 } 86 393 394 /* Destroy the module's data */ 87 395 void rtd_fini(void) 88 396 { 397 int i; 398 89 399 TRACE_ENTRY(); 90 400 91 } 92 401 for (i = 0; i < RTD_TAR_MAX; i++) { 402 while (!FD_IS_LIST_EMPTY(&TARGETS[i])) { 403 del_target((struct target *) TARGETS[i].next); 404 } 405 } 406 407 } 408 409 /* Add a new rule in the repository. this is called when the configuration file is being parsed */ 93 410 int rtd_add(enum rtd_crit_type ct, char * criteria, enum rtd_targ_type tt, char * target, int score, int flags) 94 411 { 412 struct fd_list * target_suiv = NULL; 413 struct fd_list * rule_suiv = NULL; 414 struct target * trg = NULL; 415 struct rule * rul = NULL; 416 95 417 TRACE_ENTRY("%d %p %d %p %d %x", ct, criteria, tt, target, score, flags); 96 97 418 CHECK_PARAMS((ct < RTD_CRI_MAX) && ((ct == 0) || criteria) && (tt < RTD_TAR_MAX) && target); 98 419 99 420 /* First, search in the TARGET list if we already have this target */ 421 for (target_suiv = TARGETS[tt].next; target_suiv != &TARGETS[tt]; target_suiv = target_suiv->next) { 422 int cmp; 423 struct target * cur = (struct target *)target_suiv; 424 425 if (flags & RTD_TARG_REG) { 426 /* We are adding a regexp, it is saved in the list before the plain expressions */ 427 if (cur->md.is_regex == 0) 428 break; 429 } else { 430 /* We are adding a plain expression, save it after all regexps */ 431 if (cur->md.is_regex != 0) 432 continue; 433 } 434 435 /* At this point, the type is the same, so compare the plain string value */ 436 cmp = strcmp(cur->md.plain, target); 437 if (cmp < 0) 438 continue; 439 440 if (cmp == 0) /* We already have a target with the same string */ 441 trg = cur; 442 443 break; 444 } 445 446 if (trg) { 447 /* Ok, we can free the target string, we will use the previously allocated one */ 448 free(target); 449 } else { 450 CHECK_MALLOC( trg = new_target(target, flags & RTD_TARG_REG) ); 451 fd_list_insert_before( target_suiv, &trg->chain ); 452 } 453 454 /* Now, search for the rule position in this target's list */ 455 if (ct == 0) { 456 /* Special case: we don't have a criteria -- always create a rule element */ 457 CHECK_MALLOC( rul = new_rule(NULL, 0, score) ); 458 fd_list_insert_before( &trg->rules[0], &rul->chain ); 459 } else { 460 for (rule_suiv = trg->rules[ct].next; rule_suiv != &trg->rules[ct]; rule_suiv = rule_suiv->next) { 461 int cmp; 462 struct rule * cur = (struct rule *)rule_suiv; 463 464 if (flags & RTD_CRIT_REG) { 465 /* We are adding a regexp, it is saved in the list before the plain expressions */ 466 if (cur->md.is_regex == 0) 467 break; 468 } else { 469 /* We are adding a plain expression, save it after all regexps */ 470 if (cur->md.is_regex != 0) 471 continue; 472 } 473 474 /* At this point, the type is the same, so compare the plain string value */ 475 cmp = strcmp(cur->md.plain, criteria); 476 if (cmp < 0) 477 continue; 478 479 if (cmp == 0) /* We already have a target with the same string */ 480 rul = cur; 481 482 break; 483 } 484 485 if (rul) { 486 /* Ok, we can free the target string, we will use the previously allocated one */ 487 free(criteria); 488 TRACE_DEBUG(INFO, "Warning: duplicate rule (%s : %s) found, merging score...", rul->md.plain, trg->md.plain); 489 rul->score += score; 490 } else { 491 CHECK_MALLOC( rul = new_rule(criteria, flags & RTD_CRIT_REG, score) ); 492 fd_list_insert_before( rule_suiv, &rul->chain ); 493 } 494 } 100 495 101 496 return 0; 102 497 } 103 498 499 /* Check if a message and list of eligible candidate match any of our rules, and update its score according to it. */ 104 500 int rtd_process( struct msg * msg, struct fd_list * candidates ) 105 501 { 106 return ENOTSUP; 502 struct fd_list * li; 503 struct { 504 enum { NOT_RESOLVED_YET = 0, NOT_FOUND, FOUND } status; 505 union avp_value * avp; 506 } parsed_msg_avp[RTD_CRI_MAX]; 507 508 TRACE_ENTRY("%p %p", msg, candidates); 509 CHECK_PARAMS(msg && candidates); 510 511 /* We delay looking for the AVPs in the message until we really need them. Another approach would be to parse the message once and save all needed AVPs. */ 512 memset(parsed_msg_avp, 0, sizeof(parsed_msg_avp)); 513 514 /* For each candidate in the list */ 515 for (li = candidates->next; li != candidates; li = li->next) { 516 struct rtd_candidate * cand = (struct rtd_candidate *)li; 517 int i; 518 struct { 519 char * str; 520 size_t len; 521 } cand_data[RTD_TAR_MAX] = { 522 { cand->diamid, strlen(cand->diamid) }, 523 { cand->realm, strlen(cand->realm) } 524 }; 525 526 for (i = 0; i < RTD_TAR_MAX; i++) { 527 /* Search the next rule matching this candidate in the i-th target list */ 528 struct target * target = NULL; 529 530 do { 531 int j; 532 struct fd_list * l; 533 struct rule * r; 534 535 CHECK_FCT ( get_next_match( &TARGETS[i], cand_data[i].str, cand_data[i].len, (void *)&target) ); 536 if (!target) 537 break; 538 539 /* First, apply all rules of criteria RTD_CRI_ALL */ 540 for ( l = target->rules[0].next; l != &target->rules[0]; l = l->next ) { 541 r = (struct rule *)l; 542 cand->score += r->score; 543 TRACE_DEBUG(ANNOYING, "Applied rule {'%s' : '%s' += %d} to candidate '%s'", r->md.plain, target->md.plain, r->score, cand->diamid); 544 } 545 546 /* The target is matching this candidate, check if there are additional rules criteria matching this message. */ 547 for ( j = 1; j < RTD_CRI_MAX; j++ ) { 548 if ( ! FD_IS_LIST_EMPTY(&target->rules[j]) ) { 549 /* if needed, find the required data in the message */ 550 if (parsed_msg_avp[j].status == NOT_RESOLVED_YET) { 551 struct avp * avp = NULL; 552 /* Search for the AVP in the message */ 553 CHECK_FCT( fd_msg_search_avp ( msg, AVP_MODELS[j], &avp ) ); 554 if (avp == NULL) { 555 parsed_msg_avp[j].status = NOT_FOUND; 556 } else { 557 struct avp_hdr * ahdr = NULL; 558 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); 559 if (ahdr->avp_value == NULL) { 560 /* This should not happen, but anyway let's just ignore it */ 561 parsed_msg_avp[j].status = NOT_FOUND; 562 } else { 563 /* OK, we got the AVP */ 564 parsed_msg_avp[j].status = FOUND; 565 parsed_msg_avp[j].avp = ahdr->avp_value; 566 } 567 } 568 } 569 570 /* If we did not find the data for these rules in the message, just skip the series */ 571 if (parsed_msg_avp[j].status == NOT_FOUND) { 572 TRACE_DEBUG(ANNOYING, "Skipping series of rules %d of target '%s', criteria absent from the message", j, target->md.plain); 573 continue; 574 } 575 576 /* OK, we can now check if one of our rule's criteria match the message content */ 577 r = NULL; 578 do { 579 CHECK_FCT ( get_next_match( &target->rules[j], parsed_msg_avp[j].avp->os.data, parsed_msg_avp[j].avp->os.len, (void *)&r) ); 580 if (!r) 581 break; 582 583 cand->score += r->score; 584 TRACE_DEBUG(ANNOYING, "Applied rule {'%s' : '%s' += %d} to candidate '%s'", r->md.plain, target->md.plain, r->score, cand->diamid); 585 } while (1); 586 } 587 } 588 } while (1); 589 } 590 } 591 592 return 0; 107 593 } 108 594 109 595 void rtd_dump(void) 110 596 { 597 int i; 111 598 fd_log_debug("[rt_default] Dumping rules repository...\n"); 599 for (i = 0; i < RTD_TAR_MAX; i++) { 600 if (!FD_IS_LIST_EMPTY( &TARGETS[i] )) { 601 struct fd_list * li; 602 fd_log_debug(" Targets list %d:\n", i); 603 for (li = TARGETS[i].next; li != &TARGETS[i]; li = li->next) { 604 dump_target(4, (struct target *)li); 605 } 606 } 607 } 608 112 609 fd_log_debug("[rt_default] End of dump\n"); 113 610 }
Note: See TracChangeset
for help on using the changeset viewer.