Changes in / [1349:73b9f2aefb75:1331:229ecec59ff5] in freeDiameter
- Files:
-
- 33 deleted
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
INSTALL.pkgsrc
r1334 r811 12 12 and follow the usual installation note. 13 13 14 NetBSD does not support SCTP, so you have to add 15 -DDISABLE_SCTP:BOOL=ON 16 to the cmake command line. 17 14 18 For the optional extensions, you need mysql*-client, postgres*-client, 15 libxml2 , jsoncpp, and json-schema. For the debugging extensions,16 you also need swig and apython -- install as usual.19 libxml2. For the debugging extensions, you also need swig and a 20 python -- install as usual. 17 21 -
LICENSE
r1349 r1331 3 3 Software License Agreement (BSD License) 4 4 5 Copyright (c) 2008-201 9, WIDE Project and NICT5 Copyright (c) 2008-2018, WIDE Project and NICT 6 6 All rights reserved. 7 7 … … 53 53 * Thomas Klausner: 54 54 several extensions and numerous fixes / improvements. 55 56 57 -
doc/rt_default.conf.sample
r1336 r1197 2 2 # 3 3 # This extension provides configurable routing properties for freeDiameter. 4 5 # This extension supports configuration reload at runtime. Send6 # signal SIGUSR1 to the process to cause the process to reload its7 # config.8 4 9 5 # Lines starting with a # are comments and ignored. -
doc/rt_ereg.conf.sample
r1338 r525 4 4 # The rt_ereg extension allows creation of routing rules based on AVP value matching regular expressions. 5 5 6 # This extension supports configuration reload at runtime. Send7 # signal SIGUSR1 to the process to cause the process to reload its8 # config.9 10 6 # First, one must indicate which AVP should be used for matching. 11 7 # At the moment, only AVP with OCTETSTRING types are valid. 12 8 # AVP = "User-Name"; 13 # It is possible to specify AVPs below GROUPED AVPs with the by separating AVPs with a colon (':'):14 # AVP = "Grouped-AVP1" : "Grouped-AVP2" : "Octetstring-AVP";15 9 # This parameter is mandatory. There is no default value. 16 10 … … 26 20 # (reminder: the server with the peer with the highest score gets the message) 27 21 # Note that all rules are tested for each message that contain the AVP, not only the first match. 28 29 # There can be multiple blocks of AVPs and rules; just start the next one with another AVP line:30 # AVP = "Other-AVP";31 # and continue with rules as above. -
extensions/CMakeLists.txt
r1348 r1278 13 13 ENDMACRO(FD_ADD_EXTENSION) 14 14 15 # Use the macro FD_EXTENSION_SUBDIR(extmacroname subdir descr default) to 15 # Use the macro FD_EXTENSION_SUBDIR(extmacroname subdir descr default) to 16 16 # add a new extension subdirectory. 17 17 MACRO(FD_EXTENSION_SUBDIR EXTSUBDIR EXTDESCR EXTDEFAULT) … … 40 40 FD_EXTENSION_SUBDIR(dict_eap "Diameter EAP (RFC4072) Dictionary definitions" ON) 41 41 42 FD_EXTENSION_SUBDIR(dict_dcca 43 FD_EXTENSION_SUBDIR(dict_dcca_3gpp 44 FD_EXTENSION_SUBDIR(dict_dcca_starent "Diameter CC Starent Dictionary definitions" ON)42 FD_EXTENSION_SUBDIR(dict_dcca "Diameter CC (RFC4006) Dictionary definitions [incomplete]" ON) 43 FD_EXTENSION_SUBDIR(dict_dcca_3gpp "Diameter CC 3GPP Dictionary definitions [incomplete]" ON) 44 FD_EXTENSION_SUBDIR(dict_dcca_starent "Diameter CC Starent Dictionary definitions" ON) 45 45 46 46 FD_EXTENSION_SUBDIR(dict_sip "Diameter SIP (RFC4740) Dictionary definitions" ON) … … 51 51 FD_EXTENSION_SUBDIR(dict_rfc5777 "Classification and QoS (RFC 5777) Dictionary definitions" ON) 52 52 53 FD_EXTENSION_SUBDIR(dict_json "Load Diameter dictionary definitions from JSON files." OFF)54 53 FD_EXTENSION_SUBDIR(dict_legacy_xml "Load Diameter dictionary definitions from XML files." OFF) 55 54 … … 69 68 # Routing extensions 70 69 71 FD_EXTENSION_SUBDIR(rt_busypeers "Handling of Diameter TOO_BUSY messages and relay timeouts" ON) 72 FD_EXTENSION_SUBDIR(rt_default "Configurable routing rules for freeDiameter" ON) 73 FD_EXTENSION_SUBDIR(rt_deny_by_size "Deny messages that are larger than a configured size" ON) 74 FD_EXTENSION_SUBDIR(rt_ereg "Configurable routing based on regexp matching of AVP values" OFF) 75 FD_EXTENSION_SUBDIR(rt_ignore_dh "Stow Destination-Host in Proxy-Info, restore to Origin-Host for answers" ON) 70 FD_EXTENSION_SUBDIR(rt_busypeers "Handling of Diameter TOO_BUSY messages and relay timeouts" ON) 71 FD_EXTENSION_SUBDIR(rt_default "Configurable routing rules for freeDiameter" ON) 72 FD_EXTENSION_SUBDIR(rt_ereg "Configurable routing based on regexp matching of AVP values" OFF) 73 FD_EXTENSION_SUBDIR(rt_ignore_dh "Stow Destination-Host in Proxy-Info, restore to Origin-Host for answers" ON) 76 74 FD_EXTENSION_SUBDIR(rt_load_balance "Balance load over multiple equal hosts, based on outstanding requests" ON) 77 FD_EXTENSION_SUBDIR(rt_randomize "Randomly choose one of the highest scored hosts and increase its score by one" ON) 78 FD_EXTENSION_SUBDIR(rt_redirect "Handling of Diameter Redirect messages" ON) 79 FD_EXTENSION_SUBDIR(rt_rewrite "Convert/remove AVP data in messages" ON) 75 FD_EXTENSION_SUBDIR(rt_randomize "Randomly choose one of the highest scored hosts and increase its score by one" ON) 76 FD_EXTENSION_SUBDIR(rt_redirect "Handling of Diameter Redirect messages" ON) 80 77 81 78 … … 89 86 # Debug & test extensions 90 87 91 FD_EXTENSION_SUBDIR(dbg_loglevel "Read loglevel from file -- allows runtime change" ON) 92 FD_EXTENSION_SUBDIR(dbg_monitor "Outputs periodical status information" ON) 88 FD_EXTENSION_SUBDIR(dbg_monitor "Outputs periodical status information" ON) 93 89 FD_EXTENSION_SUBDIR(dbg_msg_timings "Show some timing information for messages" ON) 94 FD_EXTENSION_SUBDIR(dbg_msg_dumps "Show human-readable content of the received & sent messages" ON) 95 FD_EXTENSION_SUBDIR(dbg_rt "Routing extension for debugging the routing module" ON) 96 FD_EXTENSION_SUBDIR(test_app "Testing application to send dummy message to another peer, like a Diameter 'ping'" OFF) 97 FD_EXTENSION_SUBDIR(test_as "Receive Abort-Session-Requests and display the data" OFF) 98 FD_EXTENSION_SUBDIR(test_cc "Receive Credit-Control-Requests and display the data" OFF) 99 FD_EXTENSION_SUBDIR(test_sip "Testing application to simulate Diameter-SIP client (RFC4740)" OFF) 90 FD_EXTENSION_SUBDIR(dbg_msg_dumps "Show human-readable content of the received & sent messages" ON) 91 FD_EXTENSION_SUBDIR(dbg_rt "Routing extension for debugging the routing module" ON) 92 FD_EXTENSION_SUBDIR(test_app "Testing application to send dummy message to another peer, like a Diameter 'ping'" OFF) 93 FD_EXTENSION_SUBDIR(test_sip "Testing application to simulate Diameter-SIP client (RFC4740)" OFF) 100 94 FD_EXTENSION_SUBDIR(dbg_interactive "Python-interpreter based module" OFF) 101 FD_EXTENSION_SUBDIR(test_netemul 95 FD_EXTENSION_SUBDIR(test_netemul "Simple Diameter network emulator proxy extension (latency, PDV, duplicates)" OFF) 102 96 103 97 -
extensions/dict_dcca_3gpp/dict_dcca_3gpp.c
r1337 r1324 10580 10580 { { .avp_vendor = 10415, .avp_name = "Interface-Port" }, RULE_OPTIONAL, -1, 1 }, 10581 10581 { { .avp_vendor = 10415, .avp_name = "Interface-Type" }, RULE_OPTIONAL, -1, 1 }, 10582 };10583 PARSE_loc_rules(rules, rule_avp);10584 }10585 10586 {10587 struct dict_object *rule_avp;10588 struct dict_avp_request vpa;10589 vpa.avp_vendor = 10415;10590 vpa.avp_name = "Originator-Received-Address";10591 CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);10592 struct local_rules_definition rules[] =10593 {10594 { { .avp_vendor = 10415, .avp_name = "Address-Type" }, RULE_OPTIONAL, -1, 1 },10595 { { .avp_vendor = 10415, .avp_name = "Address-Data" }, RULE_OPTIONAL, -1, 1 },10596 { { .avp_vendor = 10415, .avp_name = "Address-Domain" }, RULE_OPTIONAL, -1, 1 },10597 10582 }; 10598 10583 PARSE_loc_rules(rules, rule_avp); -
extensions/rt_default/rt_default.c
r1336 r1235 38 38 */ 39 39 40 #include <signal.h>41 42 40 #include "rt_default.h" 43 44 #define MODULE_NAME "rt_default"45 46 #include <pthread.h>47 48 static pthread_rwlock_t rtd_lock;49 50 static char *rtd_config_file;51 41 52 42 /* The callback called on new messages */ … … 55 45 struct msg * msg = *pmsg; 56 46 TRACE_ENTRY("%p %p %p", cbdata, msg, candidates); 57 int ret;58 47 59 48 CHECK_PARAMS(msg && candidates); 60 61 if (pthread_rwlock_rdlock(&rtd_lock) != 0) { 62 fd_log_notice("%s: read-lock failed, skipping handler", MODULE_NAME); 63 return 0; 64 } 49 65 50 /* Simply pass it to the appropriate function */ 66 51 if (FD_IS_LIST_EMPTY(candidates)) { 67 ret =0;52 return 0; 68 53 } else { 69 ret =rtd_process( msg, candidates );54 return rtd_process( msg, candidates ); 70 55 } 71 if (pthread_rwlock_unlock(&rtd_lock) != 0) {72 fd_log_notice("%s: read-unlock failed after rtd_out, exiting", MODULE_NAME);73 exit(1);74 }75 return ret;76 56 } 77 57 … … 79 59 static struct fd_rt_out_hdl * rtd_hdl = NULL; 80 60 81 static volatile int in_signal_handler = 0;82 83 /* signal handler */84 static void sig_hdlr(void)85 {86 if (in_signal_handler) {87 fd_log_error("%s: already handling a signal, ignoring new one", MODULE_NAME);88 return;89 }90 in_signal_handler = 1;91 92 if (pthread_rwlock_wrlock(&rtd_lock) != 0) {93 fd_log_error("%s: locking failed, aborting config reload", MODULE_NAME);94 return;95 }96 rtd_conf_reload(rtd_config_file);97 if (pthread_rwlock_unlock(&rtd_lock) != 0) {98 fd_log_error("%s: unlocking failed after config reload, exiting", MODULE_NAME);99 exit(1);100 }101 102 fd_log_notice("%s: reloaded configuration", MODULE_NAME);103 104 in_signal_handler = 0;105 }106 107 108 61 /* entry point */ 109 62 static int rtd_entry(char * conffile) 110 63 { 111 64 TRACE_ENTRY("%p", conffile); 112 113 rtd_config_file = conffile; 114 pthread_rwlock_init(&rtd_lock, NULL); 115 116 if (pthread_rwlock_wrlock(&rtd_lock) != 0) { 117 fd_log_notice("%s: write-lock failed, aborting", MODULE_NAME); 118 return EDEADLK; 119 } 120 65 121 66 /* Initialize the repo */ 122 67 CHECK_FCT( rtd_init() ); … … 124 69 /* Parse the configuration file */ 125 70 CHECK_FCT( rtd_conf_handle(conffile) ); 126 127 if (pthread_rwlock_unlock(&rtd_lock) != 0) { 128 fd_log_notice("%s: write-unlock failed, aborting", MODULE_NAME); 129 return EDEADLK; 130 } 131 132 /* Register reload callback */ 133 CHECK_FCT(fd_event_trig_regcb(SIGUSR1, MODULE_NAME, sig_hdlr)); 134 71 135 72 #if 0 136 73 /* Dump the rules */ … … 155 92 /* Destroy the data */ 156 93 rtd_fini(); 157 158 pthread_rwlock_destroy(&rtd_lock); 159 94 160 95 /* Done */ 161 96 return ; 162 97 } 163 98 164 EXTENSION_ENTRY( MODULE_NAME, rtd_entry);99 EXTENSION_ENTRY("rt_default", rtd_entry); -
extensions/rt_default/rt_default.h
r1336 r741 83 83 int rtd_process( struct msg * msg, struct fd_list * candidates ); 84 84 85 /* Reload the config file */86 void rtd_conf_reload(char *config_file);87 88 85 /* For debug: dump the rule repository */ 89 86 void rtd_dump(void); -
extensions/rt_default/rtd_conf.y
r1336 r1127 55 55 /* Forward declaration */ 56 56 int yyparse(char * conffile); 57 void rtd_confrestart(FILE *input_file);58 57 59 58 static int rules_added = 0; … … 67 66 TRACE_ENTRY("%p", conffile); 68 67 69 TRACE_DEBUG (FULL, "rt_default: Parsing configuration file: %s...", conffile); 70 71 rules_added = 0; 68 TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile); 69 72 70 rtd_confin = fopen(conffile, "r"); 73 71 if (rtd_confin == NULL) { 74 72 ret = errno; 75 73 fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret)); 76 TRACE_DEBUG (INFO, " rt_default:Error occurred, message logged -- configuration file.");74 TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file."); 77 75 return ret; 78 76 } 79 77 80 rtd_confrestart(rtd_confin);81 78 ret = yyparse(conffile); 82 79 … … 84 81 85 82 if (ret != 0) { 86 TRACE_DEBUG (INFO, " rt_default:Unable to parse the configuration file.");83 TRACE_DEBUG (INFO, "Unable to parse the configuration file."); 87 84 return EINVAL; 88 85 } else { 89 TRACE_DEBUG( INFO, "rt_default:Added %d RULES routing entries successfully.", rules_added);86 TRACE_DEBUG(FULL, "Added %d RULES routing entries successfully.", rules_added); 90 87 } 91 88 … … 99 96 void yyerror (YYLTYPE *ploc, char * conffile, char const *s) 100 97 { 101 TRACE_DEBUG(INFO, " rt_default:Error in configuration parsing");98 TRACE_DEBUG(INFO, "Error in configuration parsing"); 102 99 103 100 if (ploc->first_line != ploc->last_line) -
extensions/rt_default/rtd_rules.c
r1336 r1179 47 47 * Under each TARGET element, we have the list of RULES that are defined for this target, ordered by CRITERIA type, then is_regex, then string value. 48 48 * 49 * Note: Access these only when holding rtd_lock; config reload may change the underlying data.49 * Note: Except during configuration parsing and module termination, the lists are only ever accessed read-only, so we do not need a lock. 50 50 */ 51 51 … … 390 390 } 391 391 392 static void free_targets(void) 392 /* Destroy the module's data */ 393 void rtd_fini(void) 393 394 { 394 395 int i; 396 397 TRACE_ENTRY(); 395 398 396 399 for (i = 0; i < RTD_TAR_MAX; i++) { … … 399 402 } 400 403 } 401 } 402 403 /* Destroy the module's data */ 404 void rtd_fini(void) 405 { 406 TRACE_ENTRY(); 407 408 free_targets(); 404 409 405 } 410 406 … … 497 493 498 494 return 0; 499 }500 501 void rtd_conf_reload(char *config_file)502 {503 /* save old config in case reload goes wrong */504 struct fd_list old_config[RTD_TAR_MAX];505 int i;506 507 for (i = 0; i < RTD_TAR_MAX; i++) {508 old_config[i] = TARGETS[i];509 }510 memset(TARGETS, 0, sizeof(*TARGETS) * RTD_TAR_MAX);511 for (i = 0; i < RTD_TAR_MAX; i++) {512 fd_list_init(&TARGETS[i], NULL);513 }514 515 if (rtd_conf_handle(config_file) != 0) {516 fd_log_notice("rt_default: error reloading configuration, restoring previous configuration");517 free_targets();518 for (i = 0; i < RTD_TAR_MAX; i++) {519 TARGETS[i] = old_config[i];520 }521 } else {522 /* this has to be done in this weird way because the items contain back pointers referencing TARGETS */523 struct fd_list save_config[RTD_TAR_MAX];524 for (i = 0; i < RTD_TAR_MAX; i++) {525 save_config[i] = TARGETS[i];526 TARGETS[i] = old_config[i];527 }528 free_targets();529 for (i = 0; i < RTD_TAR_MAX; i++) {530 TARGETS[i] = save_config[i];531 }532 }533 495 } 534 496 -
extensions/rt_ereg/rtereg.c
r1338 r1216 34 34 *********************************************************************************************************/ 35 35 36 /* 36 /* 37 37 * This extension allows to perform some pattern-matching on an AVP 38 38 * and send the message to a server accordingly. … … 40 40 */ 41 41 42 #include <pthread.h>43 #include <signal.h>44 45 42 #include "rtereg.h" 46 43 47 static pthread_rwlock_t rte_lock;48 49 #define MODULE_NAME "rt_ereg"50 51 static char *rt_ereg_config_file;52 53 44 /* The configuration structure */ 54 struct rtereg_conf *rtereg_conf; 55 int rtereg_conf_size; 45 struct rtereg_conf rtereg_conf; 56 46 57 47 #ifndef HAVE_REG_STARTEND … … 61 51 #endif /* HAVE_REG_STARTEND */ 62 52 63 static int rtereg_init(void); 64 static int rtereg_init_config(void); 65 static void rtereg_fini(void); 66 67 void rtereg_conf_free(struct rtereg_conf *config_struct, int config_size) 68 { 69 int i, j; 70 71 /* Destroy the data */ 72 for (j=0; j<config_size; j++) { 73 if (config_struct[j].rules) { 74 for (i = 0; i < config_struct[j].rules_nb; i++) { 75 free(config_struct[j].rules[i].pattern); 76 free(config_struct[j].rules[i].server); 77 regfree(&config_struct[j].rules[i].preg); 78 } 79 } 80 free(config_struct[j].avps); 81 free(config_struct[j].rules); 82 } 83 free(config_struct); 84 } 85 86 static int proceed(char * value, size_t len, struct fd_list * candidates, int conf) 53 static int proceed(char * value, size_t len, struct fd_list * candidates) 87 54 { 88 55 int i; 89 90 for (i = 0; i < rtereg_conf [conf].rules_nb; i++) {56 57 for (i = 0; i < rtereg_conf.rules_nb; i++) { 91 58 /* Does this pattern match the value? */ 92 struct rtereg_rule * r = &rtereg_conf [conf].rules[i];59 struct rtereg_rule * r = &rtereg_conf.rules[i]; 93 60 int err = 0; 94 61 struct fd_list * c; 95 62 96 63 TRACE_DEBUG(ANNOYING, "Attempt pattern matching of '%.*s' with rule '%s'", (int)len, value, r->pattern); 97 64 98 65 #ifdef HAVE_REG_STARTEND 99 66 { … … 110 77 } 111 78 #endif /* HAVE_REG_STARTEND */ 112 79 113 80 if (err == REG_NOMATCH) 114 81 continue; 115 82 116 83 if (err != 0) { 117 84 char * errstr; … … 133 100 /* Free the buffer, return the error */ 134 101 free(errstr); 135 102 136 103 return (err == REG_ESPACE) ? ENOMEM : EINVAL; 137 104 } 138 105 139 106 /* From this point, the expression matched the AVP value */ 140 107 TRACE_DEBUG(FULL, "[rt_ereg] Match: '%s' to value '%.*s' => '%s' += %d", … … 144 111 r->server, 145 112 r->score); 146 113 147 114 for (c = candidates->next; c != candidates; c = c->next) { 148 115 struct rtd_candidate * cand = (struct rtd_candidate *)c; … … 154 121 } 155 122 }; 156 157 return 0; 158 } 159 160 static int find_avp(msg_or_avp *where, int conf_index, int level, struct fd_list * candidates) 161 { 162 struct dict_object *what; 163 struct dict_avp_data dictdata; 164 struct avp *nextavp = NULL; 165 struct avp_hdr *avp_hdr = NULL; 166 167 /* iterate over all AVPs and try to find a match */ 168 // for (i = 0; i<rtereg_conf[j].level; i++) { 169 if (level > rtereg_conf[conf_index].level) { 170 TRACE_DEBUG(INFO, "internal error, dug too deep"); 171 return 1; 172 } 173 what = rtereg_conf[conf_index].avps[level]; 174 175 CHECK_FCT(fd_dict_getval(what, &dictdata)); 176 CHECK_FCT(fd_msg_browse(where, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL)); 177 while (nextavp) { 178 CHECK_FCT(fd_msg_avp_hdr(nextavp, &avp_hdr)); 179 if ((avp_hdr->avp_code == dictdata.avp_code) && (avp_hdr->avp_vendor == dictdata.avp_vendor)) { 180 if (level != rtereg_conf[conf_index].level - 1) { 181 TRACE_DEBUG(INFO, "[rt_ereg] found grouped AVP %d (vendor %d), digging deeper", avp_hdr->avp_code, avp_hdr->avp_vendor); 182 CHECK_FCT(find_avp(nextavp, conf_index, level+1, candidates)); 183 } else { 184 TRACE_DEBUG(INFO, "[rt_ereg] found AVP %d (vendor %d)", avp_hdr->avp_code, avp_hdr->avp_vendor); 185 if (avp_hdr->avp_value != NULL) { 186 #ifndef HAVE_REG_STARTEND 187 int ret; 188 189 /* Lock the buffer */ 190 CHECK_POSIX( pthread_mutex_lock(&mtx) ); 191 192 /* Augment the buffer if needed */ 193 if (avp_hdr->avp_value->os.len >= bufsz) { 194 CHECK_MALLOC_DO( buf = realloc(buf, avp_hdr->avp_value->os.len + 1), 195 { pthread_mutex_unlock(&mtx); return ENOMEM; } ); 196 } 197 198 /* Copy the AVP value */ 199 memcpy(buf, avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len); 200 buf[avp_hdr->avp_value->os.len] = '\0'; 201 202 /* Now apply the rules */ 203 ret = proceed(buf, avp_hdr->avp_value->os.len, candidates, conf_index); 204 205 CHECK_POSIX(pthread_mutex_unlock(&mtx)); 206 207 CHECK_FCT(ret); 208 #else /* HAVE_REG_STARTEND */ 209 CHECK_FCT( proceed((char *) avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len, candidates, conf_index) ); 210 #endif /* HAVE_REG_STARTEND */ 211 } 212 } 213 } 214 CHECK_FCT(fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL)); 215 } 216 123 217 124 return 0; 218 125 } … … 221 128 static int rtereg_out(void * cbdata, struct msg ** pmsg, struct fd_list * candidates) 222 129 { 223 msg_or_avp *where;224 int j, ret;225 226 TRACE_ENTRY("%p %p %p", cbdata, *pmsg, candidates);227 228 CHECK_PARAMS( pmsg && *pmsg && candidates);229 230 if (pthread_rwlock_rdlock(&rte_lock) != 0) {231 fd_log_notice("%s: read-lock failed, skipping handler", MODULE_NAME);130 struct msg * msg = *pmsg; 131 struct avp * avp = NULL; 132 133 TRACE_ENTRY("%p %p %p", cbdata, msg, candidates); 134 135 CHECK_PARAMS(msg && candidates); 136 137 /* Check if it is worth processing the message */ 138 if (FD_IS_LIST_EMPTY(candidates)) { 232 139 return 0; 233 140 } 234 ret = 0; 235 /* Check if it is worth processing the message */ 236 if (!FD_IS_LIST_EMPTY(candidates)) { 237 /* Now search the AVPs in the message */ 238 239 for (j=0; j<rtereg_conf_size; j++) { 240 where = *pmsg; 241 TRACE_DEBUG(INFO, "[rt_ereg] iterating over AVP group %d", j); 242 if ((ret=find_avp(where, j, 0, candidates)) != 0) { 243 break; 141 142 /* Now search the AVP in the message */ 143 CHECK_FCT( fd_msg_search_avp ( msg, rtereg_conf.avp, &avp ) ); 144 if (avp != NULL) { 145 struct avp_hdr * ahdr = NULL; 146 CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); 147 if (ahdr->avp_value != NULL) { 148 #ifndef HAVE_REG_STARTEND 149 int ret; 150 151 /* Lock the buffer */ 152 CHECK_POSIX( pthread_mutex_lock(&mtx) ); 153 154 /* Augment the buffer if needed */ 155 if (ahdr->avp_value->os.len >= bufsz) { 156 CHECK_MALLOC_DO( buf = realloc(buf, ahdr->avp_value->os.len + 1), 157 { pthread_mutex_unlock(&mtx); return ENOMEM; } ); 244 158 } 159 160 /* Copy the AVP value */ 161 memcpy(buf, ahdr->avp_value->os.data, ahdr->avp_value->os.len); 162 buf[ahdr->avp_value->os.len] = '\0'; 163 164 /* Now apply the rules */ 165 ret = proceed(buf, ahdr->avp_value->os.len, candidates); 166 167 CHECK_POSIX(pthread_mutex_unlock(&mtx)); 168 169 CHECK_FCT(ret); 170 #else /* HAVE_REG_STARTEND */ 171 CHECK_FCT( proceed((char *) ahdr->avp_value->os.data, ahdr->avp_value->os.len, candidates) ); 172 #endif /* HAVE_REG_STARTEND */ 245 173 } 246 174 } 247 if (pthread_rwlock_unlock(&rte_lock) != 0) { 248 fd_log_notice("%s: read-unlock failed after rtereg_out, exiting", MODULE_NAME); 249 exit(1); 250 } 251 252 return ret; 175 176 return 0; 253 177 } 254 178 … … 256 180 static struct fd_rt_out_hdl * rtereg_hdl = NULL; 257 181 258 static volatile int in_signal_handler = 0;259 260 /* signal handler */261 static void sig_hdlr(void)262 {263 struct rtereg_conf *old_config;264 int old_config_size;265 266 if (in_signal_handler) {267 fd_log_error("%s: already handling a signal, ignoring new one", MODULE_NAME);268 return;269 }270 in_signal_handler = 1;271 272 if (pthread_rwlock_wrlock(&rte_lock) != 0) {273 fd_log_error("%s: locking failed, aborting config reload", MODULE_NAME);274 return;275 }276 277 /* save old config in case reload goes wrong */278 old_config = rtereg_conf;279 old_config_size = rtereg_conf_size;280 rtereg_conf = NULL;281 rtereg_conf_size = 0;282 283 if (rtereg_init_config() != 0) {284 fd_log_notice("%s: error reloading configuration, restoring previous configuration", MODULE_NAME);285 rtereg_conf = old_config;286 rtereg_conf_size = old_config_size;287 } else {288 rtereg_conf_free(old_config, old_config_size);289 }290 291 if (pthread_rwlock_unlock(&rte_lock) != 0) {292 fd_log_error("%s: unlocking failed after config reload, exiting", MODULE_NAME);293 exit(1);294 }295 296 fd_log_notice("%s: reloaded configuration, %d AVP group%s defined", MODULE_NAME, rtereg_conf_size, rtereg_conf_size != 1 ? "s" : "");297 298 in_signal_handler = 0;299 }300 301 182 /* entry point */ 302 183 static int rtereg_entry(char * conffile) 303 184 { 304 185 TRACE_ENTRY("%p", conffile); 305 306 rt_ereg_config_file = conffile; 307 308 if (rtereg_init() != 0) { 309 return 1; 310 } 311 312 /* Register reload callback */ 313 CHECK_FCT(fd_event_trig_regcb(SIGUSR1, MODULE_NAME, sig_hdlr)); 314 315 fd_log_notice("%s: configured, %d AVP group%s defined", MODULE_NAME, rtereg_conf_size, rtereg_conf_size != 1 ? "s" : ""); 316 317 return 0; 318 } 319 320 static int rtereg_init_config(void) 321 { 186 322 187 /* Initialize the configuration */ 323 if ((rtereg_conf=malloc(sizeof(*rtereg_conf))) == NULL) { 324 TRACE_DEBUG(INFO, "malloc failured"); 325 return 1; 326 } 327 rtereg_conf_size = 1; 328 memset(rtereg_conf, 0, sizeof(*rtereg_conf)); 329 188 memset(&rtereg_conf, 0, sizeof(rtereg_conf)); 189 330 190 /* Parse the configuration file */ 331 CHECK_FCT( rtereg_conf_handle(rt_ereg_config_file) ); 332 333 return 0; 334 } 335 336 337 /* Load */ 338 static int rtereg_init(void) 339 { 340 int ret; 341 342 pthread_rwlock_init(&rte_lock, NULL); 343 344 if (pthread_rwlock_wrlock(&rte_lock) != 0) { 345 fd_log_notice("%s: write-lock failed, aborting", MODULE_NAME); 346 return EDEADLK; 347 } 348 349 if ((ret=rtereg_init_config()) != 0) { 350 pthread_rwlock_unlock(&rte_lock); 351 return ret; 352 } 353 354 if (pthread_rwlock_unlock(&rte_lock) != 0) { 355 fd_log_notice("%s: write-unlock failed, aborting", MODULE_NAME); 356 return EDEADLK; 357 } 358 191 CHECK_FCT( rtereg_conf_handle(conffile) ); 192 359 193 /* Register the callback */ 360 194 CHECK_FCT( fd_rt_out_register( rtereg_out, NULL, 1, &rtereg_hdl ) ); 361 195 362 196 /* We're done */ 363 197 return 0; … … 365 199 366 200 /* Unload */ 367 static void rtereg_fini(void) 368 { 201 void fd_ext_fini(void) 202 { 203 int i; 369 204 TRACE_ENTRY(); 370 205 371 206 /* Unregister the cb */ 372 207 CHECK_FCT_DO( fd_rt_out_unregister ( rtereg_hdl, NULL ), /* continue */ ); 373 208 374 209 /* Destroy the data */ 375 rtereg_conf_free(rtereg_conf, rtereg_conf_size); 376 rtereg_conf = NULL; 377 rtereg_conf_size = 0; 210 if (rtereg_conf.rules) 211 for (i = 0; i < rtereg_conf.rules_nb; i++) { 212 free(rtereg_conf.rules[i].pattern); 213 free(rtereg_conf.rules[i].server); 214 regfree(&rtereg_conf.rules[i].preg); 215 } 216 free(rtereg_conf.rules); 378 217 #ifndef HAVE_REG_STARTEND 379 218 free(buf); 380 buf = NULL;381 219 #endif /* HAVE_REG_STARTEND */ 382 220 383 221 /* Done */ 384 222 return ; 385 223 } 386 224 387 void fd_ext_fini(void) 388 { 389 rtereg_fini(); 390 } 391 392 EXTENSION_ENTRY(MODULE_NAME, rtereg_entry); 225 EXTENSION_ENTRY("rt_ereg", rtereg_entry); -
extensions/rt_ereg/rtereg.h
r1338 r741 58 58 int rules_nb; /* Number of rules in the configuration */ 59 59 struct rtereg_rule *rules; /* The array of rules */ 60 61 struct dict_object * avp; /* cache the dictionary object that we are searching */ 62 63 } rtereg_conf; 60 64 61 int level; /* how many levels of AVPs we have to dig down into */62 int finished; /* AVP fully configured, for configuration file reading */63 struct dict_object **avps; /* cache the dictionary objects that we are searching */64 65 } *rtereg_conf;66 67 extern int rtereg_conf_size; -
extensions/rt_ereg/rtereg_conf.y
r1342 r1127 38 38 39 39 /* For development only : */ 40 %debug 40 %debug 41 41 %error-verbose 42 42 … … 45 45 46 46 /* Keep track of location */ 47 %locations 47 %locations 48 48 %pure-parser 49 49 … … 54 54 /* Forward declaration */ 55 55 int yyparse(char * conffile); 56 void rtereg_confrestart(FILE *input_file);57 56 58 57 /* Parse the configuration file */ … … 61 60 extern FILE * rtereg_confin; 62 61 int ret; 63 62 64 63 TRACE_ENTRY("%p", conffile); 65 64 66 65 TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile); 67 66 68 67 rtereg_confin = fopen(conffile, "r"); 69 68 if (rtereg_confin == NULL) { 70 69 ret = errno; 71 70 fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret)); 72 TRACE_DEBUG (INFO, " rt_ereg: error occurred, message logged -- configuration file.");71 TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file."); 73 72 return ret; 74 73 } 75 74 76 rtereg_confrestart(rtereg_confin);77 75 ret = yyparse(conffile); 78 76 79 77 fclose(rtereg_confin); 80 78 81 if (rtereg_conf[rtereg_conf_size-1].finished == 0) {82 TRACE_DEBUG(INFO, "rt_ereg: configuration invalid, AVP ended without OCTETSTRING AVP");83 return EINVAL;84 }85 86 79 if (ret != 0) { 87 TRACE_DEBUG (INFO, "rt_ereg: unable to parse the configuration file.");80 TRACE_DEBUG (INFO, "Unable to parse the configuration file."); 88 81 return EINVAL; 89 82 } else { 90 int i, sum = 0; 91 for (i=0; i<rtereg_conf_size; i++) { 92 sum += rtereg_conf[i].rules_nb; 93 } 94 TRACE_DEBUG(FULL, "[rt-ereg] Added %d rules successfully.", sum); 83 TRACE_DEBUG(FULL, "[rt-ereg] Added %d rules successfully.", rtereg_conf.rules_nb); 95 84 } 96 97 return 0; 98 } 99 100 int avp_add(const char *name) 101 { 102 void *ret; 103 int level; 104 105 if (rtereg_conf[rtereg_conf_size-1].finished) { 106 if ((ret = realloc(rtereg_conf, sizeof(*rtereg_conf)*(rtereg_conf_size+1))) == NULL) { 107 TRACE_DEBUG(INFO, "rt_ereg: realloc failed"); 108 return -1; 109 } 110 rtereg_conf_size++; 111 rtereg_conf = ret; 112 memset(&rtereg_conf[rtereg_conf_size-1], 0, sizeof(*rtereg_conf)); 113 TRACE_DEBUG(INFO, "rt_ereg: New AVP group found starting with %s", name); 114 } 115 level = rtereg_conf[rtereg_conf_size-1].level + 1; 116 117 if ((ret = realloc(rtereg_conf[rtereg_conf_size-1].avps, sizeof(*rtereg_conf[rtereg_conf_size-1].avps)*level)) == NULL) { 118 TRACE_DEBUG(INFO, "rt_ereg: realloc failed"); 119 return -1; 120 } 121 rtereg_conf[rtereg_conf_size-1].avps = ret; 122 123 CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, name, &rtereg_conf[rtereg_conf_size-1].avps[level-1], ENOENT ), 124 { 125 TRACE_DEBUG(INFO, "rt_ereg: Unable to find '%s' AVP in the loaded dictionaries.", name); 126 return -1; 127 } ); 128 129 /* Now check the type */ 130 { 131 struct dict_avp_data data; 132 CHECK_FCT( fd_dict_getval( rtereg_conf[rtereg_conf_size-1].avps[level-1], &data) ); 133 if (data.avp_basetype == AVP_TYPE_OCTETSTRING) { 134 rtereg_conf[rtereg_conf_size-1].finished = 1; 135 } else if (data.avp_basetype != AVP_TYPE_GROUPED) { 136 TRACE_DEBUG(INFO, "rt_ereg: '%s' AVP is not an OCTETSTRING nor GROUPED AVP (%d).", name, data.avp_basetype); 137 return -1; 138 } 139 } 140 rtereg_conf[rtereg_conf_size-1].level = level; 85 141 86 return 0; 142 87 } … … 148 93 void yyerror (YYLTYPE *ploc, char * conffile, char const *s) 149 94 { 150 TRACE_DEBUG(INFO, " rt_ereg: error in configuration parsing");151 95 TRACE_DEBUG(INFO, "Error in configuration parsing"); 96 152 97 if (ploc->first_line != ploc->last_line) 153 98 fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); … … 181 126 182 127 /* The grammar definition */ 183 conffile: avp rules 184 | conffile avp rules 185 ; 186 128 conffile: rules avp rules 129 ; 130 187 131 /* a server entry */ 188 avp: AVP '=' avp_part ';' 189 ; 190 191 avp_part: avp_part ':' QSTRING { if (avp_add($3) < 0) { YYERROR; } } 192 | QSTRING { if (avp_add($1) < 0) { YYERROR; } } 193 ; 194 132 avp: AVP '=' QSTRING ';' 133 { 134 if (rtereg_conf.avp != NULL) { 135 yyerror(&yylloc, conffile, "Only one AVP can be specified"); 136 YYERROR; 137 } 138 139 CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, $3, &rtereg_conf.avp, ENOENT ), 140 { 141 TRACE_DEBUG(INFO, "Unable to find '%s' AVP in the loaded dictionaries.", $3); 142 yyerror (&yylloc, conffile, "Invalid AVP value."); 143 YYERROR; 144 } ); 145 146 /* Now check the type */ 147 { 148 struct dict_avp_data data; 149 CHECK_FCT( fd_dict_getval( rtereg_conf.avp, &data) ); 150 CHECK_PARAMS_DO (data.avp_basetype == AVP_TYPE_OCTETSTRING, 151 { 152 TRACE_DEBUG(INFO, "'%s' AVP in not an OCTETSTRING AVP (%d).", $3, data.avp_basetype); 153 yyerror (&yylloc, conffile, "AVP in not an OCTETSTRING type."); 154 YYERROR; 155 } ); 156 } 157 } 158 ; 159 195 160 rules: /* empty OK */ 196 161 | rules rule 197 162 ; 198 163 199 164 rule: QSTRING ':' QSTRING '+' '=' INTEGER ';' 200 165 { 201 166 struct rtereg_rule * new; 202 167 int err; 203 168 204 169 /* Add new rule in the array */ 205 rtereg_conf [rtereg_conf_size-1].rules_nb += 1;206 CHECK_MALLOC_DO(rtereg_conf [rtereg_conf_size-1].rules = realloc(rtereg_conf[rtereg_conf_size-1].rules, rtereg_conf[rtereg_conf_size-1].rules_nb * sizeof(struct rtereg_rule)),170 rtereg_conf.rules_nb += 1; 171 CHECK_MALLOC_DO(rtereg_conf.rules = realloc(rtereg_conf.rules, rtereg_conf.rules_nb * sizeof(struct rtereg_rule)), 207 172 { 208 173 yyerror (&yylloc, conffile, "Not enough memory to store the configuration..."); 209 174 YYERROR; 210 175 } ); 211 212 new = &rtereg_conf [rtereg_conf_size-1].rules[rtereg_conf[rtereg_conf_size-1].rules_nb - 1];213 176 177 new = &rtereg_conf.rules[rtereg_conf.rules_nb - 1]; 178 214 179 new->pattern = $1; 215 180 new->server = $3; 216 181 new->score = $6; 217 182 218 183 /* Attempt to compile the regex */ 219 184 CHECK_FCT_DO( err=regcomp(&new->preg, new->pattern, REG_EXTENDED | REG_NOSUB), … … 223 188 224 189 /* Error while compiling the regex */ 225 TRACE_DEBUG(INFO, " rt_ereg: error while compiling the regular expression '%s':", new->pattern);190 TRACE_DEBUG(INFO, "Error while compiling the regular expression '%s':", new->pattern); 226 191 227 192 /* Get the error message size */ … … 234 199 regerror(err, &new->preg, buf, bl); 235 200 TRACE_DEBUG(INFO, "\t%s", buf); 236 201 237 202 /* Free the buffer, return the error */ 238 203 free(buf); 239 204 240 205 yyerror (&yylloc, conffile, "Invalid regular expression."); 241 206 YYERROR; -
freeDiameterd/main.c
r1339 r1305 34 34 *********************************************************************************************************/ 35 35 36 #if defined(__GLIBC__)37 #define _BSD_SOURCE /* for vsyslog */38 #endif39 40 36 #include <freeDiameter/freeDiameter-host.h> 41 37 #include <freeDiameter/libfdcore.h> … … 44 40 #include <getopt.h> 45 41 #include <locale.h> 46 #include <syslog.h> 47 #include <stdarg.h> 42 48 43 49 44 /* forward declarations */ … … 61 56 62 57 63 static void syslog_logger(int loglevel, const char * format, va_list args)64 {65 int level;66 67 switch (loglevel) {68 case FD_LOG_NOTICE:69 level = LOG_NOTICE;70 break;71 case FD_LOG_ERROR:72 level = LOG_ERR;73 break;74 case FD_LOG_FATAL:75 level = LOG_CRIT;76 break;77 default:78 /* fallthrough */79 case FD_LOG_DEBUG:80 /* some systems log LOG_DEBUG to a file; but81 * freeDiameter debug output is too verbose */82 return;83 #if 084 level = LOG_DEBUG;85 break;86 #endif87 }88 89 vsyslog(level, format, args);90 }91 92 93 58 /* freeDiameter starting point */ 94 59 int main(int argc, char * argv[]) … … 96 61 int ret; 97 62 sigset_t sig_all; 98 63 99 64 /* Block all signals from the current thread and all its future children -- we will catch everything in catch_signals */ 100 65 sigfillset(&sig_all); 101 66 ret = pthread_sigmask(SIG_BLOCK, &sig_all, NULL); 102 67 ASSERT(ret == 0); 103 68 104 69 /* Parse the command-line */ 105 70 ret = main_cmdline(argc, argv); … … 107 72 return ret; 108 73 } 109 74 110 75 /* Initialize the core library */ 111 76 ret = fd_core_initialize(); … … 114 79 return ret; 115 80 } 116 81 117 82 /* Set gnutls debug level ? */ 118 83 if (gnutls_debug) { … … 121 86 TRACE_DEBUG(INFO, "Enabled GNUTLS debug at level %d", gnutls_debug); 122 87 } 123 88 124 89 /* Parse the configuration file */ 125 90 CHECK_FCT_DO( fd_core_parseconf(conffile), goto error ); 126 91 127 92 /* Start the servers */ 128 93 CHECK_FCT_DO( fd_core_start(), goto error ); 129 94 130 95 /* Allow SIGINT and SIGTERM from this point to terminate the application */ 131 96 CHECK_POSIX_DO( pthread_create(&signals_thr, NULL, catch_signals, NULL), goto error ); 132 97 133 98 TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); 134 99 135 100 /* Now, just wait for termination */ 136 101 CHECK_FCT( fd_core_wait_shutdown_complete() ); 137 102 138 103 /* Just in case it was not the result of a signal, we cancel signals_thr */ 139 104 fd_thr_term(&signals_thr); 140 105 141 106 return 0; 142 error: 107 error: 143 108 CHECK_FCT_DO( fd_core_shutdown(), ); 144 109 CHECK_FCT( fd_core_wait_shutdown_complete() ); … … 173 138 " -V, --version Print version and exit\n" 174 139 " -c, --config=filename Read configuration from this file instead of the \n" 175 " default location (" DEFAULT_CONF_PATH "/" FD_DEFAULT_CONF_FILENAME ").\n" 176 " -s, --syslog Write log output to syslog (instead of stdout)\n"); 140 " default location (" DEFAULT_CONF_PATH "/" FD_DEFAULT_CONF_FILENAME ").\n"); 177 141 printf( "\nDebug:\n" 178 142 " These options are mostly useful for developers\n" … … 192 156 int option_index = 0; 193 157 char * locale; 194 158 195 159 struct option long_options[] = { 196 160 { "help", no_argument, NULL, 'h' }, 197 161 { "version", no_argument, NULL, 'V' }, 198 162 { "config", required_argument, NULL, 'c' }, 199 { "syslog", no_argument, NULL, 's' },200 163 { "debug", no_argument, NULL, 'd' }, 201 164 { "quiet", no_argument, NULL, 'q' }, … … 206 169 { NULL, 0, NULL, 0 } 207 170 }; 208 171 209 172 /* Loop on arguments */ 210 173 while (1) { 211 c = getopt_long (argc, argv, "hVc:dql:f:F:g: s", long_options, &option_index);212 if (c == -1) 174 c = getopt_long (argc, argv, "hVc:dql:f:F:g:", long_options, &option_index); 175 if (c == -1) 213 176 break; /* Exit from the loop. */ 214 177 215 178 switch (c) { 216 179 case 'h': /* Print help and exit. */ … … 237 200 } 238 201 break; 239 202 240 203 case 'd': /* Increase verbosity of debug messages. */ 241 204 fd_g_debug_lvl--; 242 205 break; 243 206 244 207 case 'f': /* Full debug for the function with this name. */ 245 208 #ifdef DEBUG … … 251 214 #endif /* DEBUG */ 252 215 break; 253 216 254 217 case 'F': /* Full debug for the file with this name. */ 255 218 #ifdef DEBUG … … 261 224 #endif /* DEBUG */ 262 225 break; 263 226 264 227 case 'g': /* Set a debug level and function for GNU TLS calls. */ 265 228 gnutls_debug = (int)atoi(optarg); 266 229 break; 267 230 268 231 case 'q': /* Decrease verbosity then remove debug messages. */ 269 232 fd_g_debug_lvl++; 270 break;271 272 case 's': /* Write log data using syslog(3) */273 if (fd_log_handler_register(syslog_logger) != 0) {274 fprintf(stderr, "Cannot initialize syslog logger\n");275 return EINVAL;276 }277 233 break; 278 234 … … 288 244 } 289 245 } 290 246 291 247 return 0; 292 248 } … … 297 253 sigset_t ss; 298 254 fd_log_threadname ( "signals catcher" ); 299 255 300 256 sigemptyset(&ss); 301 257 302 258 /* Signals that terminate the daemon */ 303 259 sigaddset(&ss, SIGTERM); 304 260 sigaddset(&ss, SIGINT); 305 261 306 262 /* Signals that send an event */ 307 263 sigaddset(&ss, SIGUSR1); 308 264 sigaddset(&ss, SIGUSR2); 309 265 310 266 /* We unblock all other signals, so that their default handler is used (such as SIGTSTP) */ 311 267 CHECK_SYS_DO( pthread_sigmask( SIG_SETMASK, &ss, NULL ), goto out ); 312 268 313 269 /* Now loop on the reception of the signal */ 314 270 while (1) { 315 271 int sig, *ps; 316 272 317 273 /* Wait to receive the next signal */ 318 274 CHECK_POSIX_DO( sigwait(&ss, &sig), break ); 319 275 320 276 TRACE_DEBUG(FULL, "Signal %d caught", sig); 321 277 322 278 switch (sig) { 323 279 case SIGUSR1: … … 327 283 CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TRIGGER, sizeof(int), ps), goto out ); 328 284 break; 329 285 330 286 case SIGINT: 331 287 case SIGTERM: … … 334 290 } 335 291 } 336 out: 292 out: 337 293 /* Better way to handle this ? */ 338 294 ASSERT(0); -
include/freeDiameter/CMakeLists.txt
r1333 r1295 18 18 # In DEBUG mode, each log can contain pid, calling function and file for easy debug. Set to ON to display this information. 19 19 OPTION(DEBUG_WITH_META "Show calling location in logs?" OFF) 20 20 21 21 # Create the absolute path for searching extensions 22 22 SET(DEFAULT_EXTENSIONS_PATH ${CMAKE_INSTALL_PREFIX}/${INSTALL_EXTENSIONS_SUFFIX}) … … 32 32 OPTION(DISABLE_PEER_EXPIRY "Disable RFC3539 Peers Connections Expiration after inactivity?" OFF) 33 33 34 # The following workaround increases compatibility with some implementations without breaking anything in freeDiameter, 35 # so it can be enabled without risk. We keep it disabled by default anyway for those people who use freeDiameter to check the 34 # The following workaround increases compatibility with some implementations without breaking anything in freeDiameter, 35 # so it can be enabled without risk. We keep it disabled by default anyway for those people who use freeDiameter to check the 36 36 # compliancy of their implementation with the Diameter RFC... 37 37 OPTION(WORKAROUND_ACCEPT_INVALID_VSAI "Do not reject a CER/CEA with a Vendor-Specific-Application-Id AVP containing both Auth- and Acct- application AVPs?" OFF) … … 45 45 INCLUDE (CheckFunctionExists) 46 46 INCLUDE (CheckIncludeFiles) 47 INCLUDE (CheckSymbolExists) 47 INCLUDE (CheckSymbolExists) 48 48 INCLUDE (CheckCSourceCompiles) 49 49 INCLUDE (TestBigEndian) … … 134 134 135 135 # IDNA process: we use libidn from GNU (unless the function & header files are included in libc) 136 IF(NOT DIAMID_IDNA_IGNORE AND NOT DIAMID_IDNA_REJECT)136 IF(NOT DIAMID_IDNA_IGNORE AND NOT DIAMID_IDNA_REJECT) 137 137 FIND_PACKAGE(IDNA) 138 138 SET(CHECK_IDNA_SOURCE_CODE " … … 160 160 SET(GNUTLS_LIBRARIES ${GNUTLS_LIBRARIES} PARENT_SCOPE) 161 161 162 FIND_PATH(GCRYPT_INCLUDE_DIR NAMES gcrypt.h)163 I F(NOT GCRYPT_INCLUDE_DIR)162 find_path(GCRYPT_INCLUDE_DIR NAMES gcrypt.h) 163 If ( NOT GCRYPT_INCLUDE_DIR ) 164 164 MESSAGE(SEND_ERROR "Unable to find gcrypt.h, please install libgcrypt-dev or equivalent") 165 E NDIF(NOT GCRYPT_INCLUDE_DIR)165 Endif ( NOT GCRYPT_INCLUDE_DIR ) 166 166 MARK_AS_ADVANCED(GCRYPT_INCLUDE_DIR) 167 167 SET(GCRYPT_INCLUDE_DIR ${GCRYPT_INCLUDE_DIR} PARENT_SCOPE) 168 168 169 169 # Also we need libgcrypt to... display its version :( 170 FIND_LIBRARY(GCRYPT_LIBRARY 170 find_library(GCRYPT_LIBRARY 171 171 NAMES gcrypt 172 172 ) 173 I F(NOT GCRYPT_LIBRARY)173 If ( NOT GCRYPT_LIBRARY ) 174 174 MESSAGE(SEND_ERROR "Unable to find libgcrypt, please install libgcrypt or equivalent") 175 E NDIF(NOT GCRYPT_LIBRARY)175 Endif ( NOT GCRYPT_LIBRARY ) 176 176 SET(GCRYPT_LIBRARY ${GCRYPT_LIBRARY} PARENT_SCOPE) 177 177 … … 229 229 SET(LFDCORE_INCLUDES ${SCTP_INCLUDE_DIR} ${GNUTLS_INCLUDE_DIR} ${GCRYPT_INCLUDE_DIR} PARENT_SCOPE) 230 230 # And dependencies 231 SET(LFDCORE_LINK_INTERFACES "" PARENT_SCOPE) 231 SET(LFDCORE_LINK_INTERFACES "" PARENT_SCOPE) 232 232 # We don't force other libraries, the programs will link with what it needs 233 233 # (such as libgnutls if it uses GNUTLS_DEBUG() macro -
libfdcore/sctp.c
r1332 r1268 401 401 fd_log_debug( " sctp_shutdown_event : %hhu", event.sctp_shutdown_event); 402 402 fd_log_debug( " sctp_partial_delivery_event : %hhu", event.sctp_partial_delivery_event); 403 //fd_log_debug( " sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event);403 fd_log_debug( " sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event); 404 404 // fd_log_debug( " sctp_authentication_event : %hhu", event.sctp_authentication_event); 405 405 } -
libfdcore/sctp3436.c
r1344 r1190 51 51 - the push function sends the data on a certain stream. 52 52 We also have a demux thread that reads the socket and store received data in the appropriate fifo 53 53 54 54 We have one gnutls_session per stream pair, and as many threads that read the gnutls records and save incoming data to the target queue. 55 55 56 56 This complexity is required because we cannot read a socket for a given stream only; we can only get the next message and find its stream. 57 57 */ … … 71 71 int event; 72 72 uint16_t strid; 73 73 74 74 TRACE_ENTRY("%p", arg); 75 75 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); 76 76 77 77 /* Set the thread name */ 78 78 { 79 char buf[ 100];79 char buf[48]; 80 80 snprintf(buf, sizeof(buf), "Demuxer (%d:%s)", conn->cc_socket, conn->cc_remid); 81 81 fd_log_threadname ( buf ); 82 82 } 83 83 84 84 ASSERT( conn->cc_proto == IPPROTO_SCTP ); 85 85 ASSERT( fd_cnx_target_queue(conn) ); 86 86 ASSERT( conn->cc_sctp3436_data.array ); 87 87 88 88 do { 89 89 CHECK_FCT_DO( fd_sctp_recvmeta(conn, &strid, &buf, &bufsz, &event), goto fatal ); … … 98 98 } 99 99 break; 100 100 101 101 case FDEVP_CNX_EP_CHANGE: 102 102 /* Send this event to the target queue */ 103 103 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal ); 104 104 break; 105 105 106 106 case FDEVP_CNX_ERROR: 107 107 goto out; 108 108 109 109 case FDEVP_CNX_SHUTDOWN: 110 110 /* Just ignore the notification for now, we will get another error later anyway */ 111 111 continue; 112 112 113 113 default: 114 114 goto fatal; 115 115 } 116 116 117 117 } while (conn->cc_loop); 118 118 119 119 out: 120 120 /* Signal termination of the connection to all decipher threads */ … … 125 125 } 126 126 fd_cnx_markerror(conn); 127 TRACE_DEBUG(FULL, "Thread terminated"); 127 TRACE_DEBUG(FULL, "Thread terminated"); 128 128 return NULL; 129 129 130 130 fatal: 131 131 /* An unrecoverable error occurred, stop the daemon */ … … 139 139 struct sctp3436_ctx * ctx = arg; 140 140 struct cnxctx *cnx; 141 141 142 142 TRACE_ENTRY("%p", arg); 143 143 CHECK_PARAMS_DO(ctx && ctx->raw_recv && ctx->parent, goto error); 144 144 cnx = ctx->parent; 145 145 ASSERT( fd_cnx_target_queue(cnx) ); 146 146 147 147 /* Set the thread name */ 148 148 { 149 char buf[ 100];149 char buf[48]; 150 150 snprintf(buf, sizeof(buf), "Decipher (%hu@%d:%s)", ctx->strid, cnx->cc_socket, cnx->cc_remid); 151 151 fd_log_threadname ( buf ); 152 152 } 153 153 154 154 /* The next function loops while there is no error */ 155 155 CHECK_FCT_DO(fd_tls_rcvthr_core(cnx, ctx->strid ? ctx->session : cnx->cc_tls_para.session), /* continue */); 156 156 error: 157 157 fd_cnx_markerror(cnx); 158 TRACE_DEBUG(FULL, "Thread terminated"); 158 TRACE_DEBUG(FULL, "Thread terminated"); 159 159 return NULL; 160 160 } … … 171 171 struct timespec tsstore, *ts = NULL; 172 172 int ret; 173 173 174 174 TRACE_ENTRY("%p %d", tr, ms); 175 175 176 176 if (ctx->partial.buf) 177 177 return 1; /* data is already available for pull */ 178 178 179 179 if (ms) { 180 180 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &tsstore), return -1 ); … … 184 184 ts = &tsstore; 185 185 } 186 186 187 187 ret = fd_fifo_select ( ctx->raw_recv, ts ); 188 188 if (ret < 0) { … … 190 190 ret = -1; 191 191 } 192 192 193 193 return ret; 194 194 } … … 201 201 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; 202 202 struct iovec iov; 203 203 204 204 TRACE_ENTRY("%p %p %zd", tr, data, len); 205 205 CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } ); 206 206 207 207 iov.iov_base = (void *)data; 208 208 iov.iov_len = len; 209 209 210 210 return fd_sctp_sendstrv(ctx->parent, ctx->strid, &iov, 1); 211 211 } … … 214 214 { 215 215 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; 216 216 217 217 TRACE_ENTRY("%p %p %d", tr, iov, iovcnt); 218 218 CHECK_PARAMS_DO( tr && iov, { errno = EINVAL; return -1; } ); 219 219 220 220 return fd_sctp_sendstrv(ctx->parent, ctx->strid, (const struct iovec *)iov, iovcnt); 221 221 } … … 228 228 size_t pulled = 0; 229 229 int emptied; 230 230 231 231 TRACE_ENTRY("%p %p %zd", tr, buf, len); 232 232 CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; goto error; } ); 233 233 234 234 /* If we don't have data available now, pull new message from the fifo -- this is blocking (until the queue is destroyed) */ 235 235 if (!ctx->partial.buf) { … … 241 241 } 242 242 } 243 243 244 244 pulled = ctx->partial.bufsz - ctx->partial.offset; 245 245 if (pulled <= len) { … … 264 264 /* We are done */ 265 265 return pulled; 266 266 267 267 error: 268 268 gnutls_transport_set_errno (ctx->session, errno); … … 278 278 /* Set the transport pointer passed to push & pull callbacks */ 279 279 GNUTLS_TRACE( gnutls_transport_set_ptr( session, (gnutls_transport_ptr_t) ctx ) ); 280 280 281 281 /* Reset the low water value, since we don't use sockets */ 282 282 #ifndef GNUTLS_VERSION_300 … … 287 287 GNUTLS_TRACE( gnutls_transport_set_pull_timeout_function( session, sctp3436_pull_timeout ) ); 288 288 #endif /* GNUTLS_VERSION_300 */ 289 289 290 290 /* Set the push and pull callbacks */ 291 291 GNUTLS_TRACE( gnutls_transport_set_pull_function(session, sctp3436_pull) ); … … 325 325 TRACE_ENTRY("%p", conn); 326 326 CHECK_PARAMS( conn && !conn->cc_sctp3436_data.sess_store ); 327 327 328 328 CHECK_MALLOC( conn->cc_sctp3436_data.sess_store = malloc(sizeof(struct sr_store)) ); 329 329 memset(conn->cc_sctp3436_data.sess_store, 0, sizeof(struct sr_store)); 330 330 331 331 fd_list_init(&conn->cc_sctp3436_data.sess_store->list, NULL); 332 332 CHECK_POSIX( pthread_rwlock_init(&conn->cc_sctp3436_data.sess_store->lock, NULL) ); 333 333 conn->cc_sctp3436_data.sess_store->parent = conn; 334 334 335 335 return 0; 336 336 } … … 342 342 TRACE_ENTRY("%p", conn); 343 343 CHECK_PARAMS_DO( conn, return ); 344 344 345 345 if (!conn->cc_sctp3436_data.sess_store) 346 346 return; 347 347 348 348 CHECK_POSIX_DO( pthread_rwlock_destroy(&conn->cc_sctp3436_data.sess_store->lock), /* continue */ ); 349 349 350 350 while (!FD_IS_LIST_EMPTY(&conn->cc_sctp3436_data.sess_store->list)) { 351 351 struct sr_data * sr = (struct sr_data *) conn->cc_sctp3436_data.sess_store->list.next; … … 355 355 free(sr); 356 356 } 357 357 358 358 free(conn->cc_sctp3436_data.sess_store); 359 359 conn->cc_sctp3436_data.sess_store = NULL; … … 366 366 struct fd_list * ret; 367 367 *match = 0; 368 368 369 369 for (ret = sto->list.next; ret != &sto->list; ret = ret->next) { 370 370 int cmp = 0; 371 371 struct sr_data * sr = (struct sr_data *)ret; 372 372 373 373 cmp = fd_os_cmp(key.data, key.size, sr->key.data, sr->key.size); 374 374 if (cmp > 0) 375 375 continue; 376 376 377 377 if (cmp == 0) 378 378 *match = 1; 379 379 380 380 break; 381 381 } 382 382 383 383 return ret; 384 384 } … … 392 392 int match = 0; 393 393 int ret = 0; 394 394 395 395 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); 396 396 CHECK_PARAMS_DO( sto && key.data && data.data, return -1 ); 397 397 398 398 CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 ); 399 399 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session store [key ", key.data, key.size, "]"); 400 400 401 401 li = find_or_next(sto, key, &match); 402 402 if (match) { 403 403 sr = (struct sr_data *)li; 404 404 405 405 /* Check the data is the same */ 406 406 if ((data.size != sr->data.size) || memcmp(data.data, sr->data.data, data.size)) { … … 409 409 TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- old data [", sr->data.data, sr->data.size, "]"); 410 410 TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- new data [", data.data, data.size, "]"); 411 411 412 412 ret = -1; 413 413 } else { … … 416 416 goto out; 417 417 } 418 418 419 419 /* Create a new entry */ 420 420 CHECK_MALLOC_DO( sr = malloc(sizeof(struct sr_data)), { ret = -1; goto out; } ); … … 430 430 sr->data.size = data.size; 431 431 memcpy(sr->data.data, data.data, data.size); 432 432 433 433 /* Save this new entry in the list, we are done */ 434 434 fd_list_insert_before(li, &sr->chain); 435 435 436 out: 436 out: 437 437 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 ); 438 438 return ret; … … 446 446 int match = 0; 447 447 int ret = 0; 448 448 449 449 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); 450 450 CHECK_PARAMS_DO( sto && key.data, return -1 ); 451 451 452 452 CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 ); 453 453 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session delete [key ", key.data, key.size, "]"); 454 454 455 455 li = find_or_next(sto, key, &match); 456 456 if (match) { 457 457 sr = (struct sr_data *)li; 458 458 459 459 /* Destroy this data */ 460 460 fd_list_unlink(li); … … 466 466 ret = -1; 467 467 } 468 468 469 469 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 ); 470 470 return ret; … … 485 485 CHECK_POSIX_DO( pthread_rwlock_rdlock(&sto->lock), return error ); 486 486 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session fetch [key ", key.data, key.size, "]"); 487 487 488 488 li = find_or_next(sto, key, &match); 489 489 if (match) { … … 493 493 memcpy(res.data, sr->data.data, res.size); 494 494 } 495 out: 495 out: 496 496 TRACE_DEBUG(GNUTLS_DBG_LEVEL, "Fetched (%p, %d) from store %p", res.data, res.size, sto); 497 497 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return error); … … 503 503 { 504 504 TRACE_ENTRY("%p", conn); 505 505 506 506 GNUTLS_TRACE( gnutls_db_set_retrieve_function(session, sr_fetch)); 507 507 GNUTLS_TRACE( gnutls_db_set_remove_function (session, sr_remove)); 508 508 GNUTLS_TRACE( gnutls_db_set_store_function (session, sr_store)); 509 509 GNUTLS_TRACE( gnutls_db_set_ptr (session, conn->cc_sctp3436_data.sess_store)); 510 510 511 511 return; 512 512 } … … 517 517 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) arg; 518 518 int resumed; 519 519 520 520 TRACE_ENTRY("%p", arg); 521 521 522 522 /* Set the thread name */ 523 523 { … … 526 526 fd_log_threadname ( buf ); 527 527 } 528 528 529 529 TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid); 530 530 531 531 CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL); 532 532 533 533 GNUTLS_TRACE( resumed = gnutls_session_is_resumed(ctx->session) ); 534 534 #ifndef GNUTLS_VERSION_300 … … 545 545 } 546 546 } 547 547 548 548 /* Finished, OK */ 549 549 return arg; … … 559 559 { 560 560 uint16_t i; 561 561 562 562 TRACE_ENTRY("%p", conn); 563 563 CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && (!conn->cc_sctp3436_data.array) ); 564 564 565 565 /* First, alloc the array and initialize the non-TLS data */ 566 566 CHECK_MALLOC( conn->cc_sctp3436_data.array = calloc(conn->cc_sctp_para.pairs, sizeof(struct sctp3436_ctx)) ); … … 570 570 CHECK_FCT( fd_fifo_new(&conn->cc_sctp3436_data.array[i].raw_recv, 10) ); 571 571 } 572 572 573 573 /* Set push/pull functions in the master session, using fifo in array[0] */ 574 574 set_sess_transport(conn->cc_tls_para.session, &conn->cc_sctp3436_data.array[0]); 575 575 576 576 /* For server side, we also initialize the resuming capabilities */ 577 577 if (conn->cc_tls_para.mode == GNUTLS_SERVER) { 578 578 579 579 /* Prepare the store for sessions data */ 580 580 CHECK_FCT( store_init(conn) ); 581 581 582 582 /* Set the callbacks for resuming in the master session */ 583 583 set_resume_callbacks(conn->cc_tls_para.session, conn); … … 586 586 /* Start the demux thread */ 587 587 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, demuxer, conn ) ); 588 588 589 589 return 0; 590 590 } … … 596 596 int errors = 0; 597 597 gnutls_datum_t master_data; 598 598 599 599 TRACE_ENTRY("%p %p", conn, priority); 600 600 CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && conn->cc_sctp3436_data.array ); … … 602 602 /* Server side: we set all the parameters, the resume callback will take care of resuming the session */ 603 603 /* Client side: we duplicate the parameters of the master session, then set the transport pointer */ 604 604 605 605 /* For client side, retrieve the master session parameters */ 606 606 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { … … 614 614 } 615 615 } 616 616 617 617 /* Initialize the session objects and start the handshake in a separate thread */ 618 618 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { 619 619 /* Set credentials and priority */ 620 620 CHECK_FCT( fd_tls_prepare(&conn->cc_sctp3436_data.array[i].session, conn->cc_tls_para.mode, 0, priority, alt_creds) ); 621 621 622 622 /* additional initialization for gnutls 3.x */ 623 623 #ifdef GNUTLS_VERSION_300 … … 644 644 set_resume_callbacks(conn->cc_sctp3436_data.array[i].session, conn); 645 645 } 646 646 647 647 /* Set transport parameters */ 648 648 set_sess_transport(conn->cc_sctp3436_data.array[i].session, &conn->cc_sctp3436_data.array[i]); 649 649 650 650 /* Start the handshake thread */ 651 651 CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[i].thr, NULL, handshake_resume_th, &conn->cc_sctp3436_data.array[i] ) ); 652 652 } 653 653 654 654 /* We can now release the memory of master session data if any */ 655 655 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { 656 656 GNUTLS_TRACE( gnutls_free(master_data.data) ); 657 657 } 658 658 659 659 /* Now wait for all handshakes to finish */ 660 660 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { … … 666 666 } 667 667 } 668 668 669 669 if (errors) { 670 670 TRACE_DEBUG(INFO, "Handshake failed on %d/%hd stream pairs", errors, conn->cc_sctp_para.pairs); … … 672 672 return ENOTCONN; 673 673 } 674 674 675 675 return 0; 676 676 } … … 680 680 { 681 681 uint16_t i; 682 682 683 683 TRACE_ENTRY("%p", conn); 684 684 CHECK_PARAMS( conn && conn->cc_sctp3436_data.array ); 685 685 686 686 if (others) { 687 687 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { … … 700 700 { 701 701 uint16_t i; 702 702 703 703 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); 704 704 705 705 /* End all TLS sessions, in series (not as efficient as paralel, but simpler) */ 706 706 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { … … 715 715 { 716 716 uint16_t i; 717 717 718 718 TRACE_ENTRY("%p", conn); 719 719 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); 720 720 721 721 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { 722 722 if (conn->cc_sctp3436_data.array[i].thr != (pthread_t)NULL) { … … 732 732 { 733 733 uint16_t i; 734 734 735 735 TRACE_ENTRY("%p", conn); 736 736 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); 737 737 738 738 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { 739 739 if (conn->cc_sctp3436_data.array[i].session) { … … 749 749 { 750 750 uint16_t i; 751 751 752 752 TRACE_ENTRY("%p", conn); 753 753 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); 754 754 755 755 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { 756 756 CHECK_FCT_DO( fd_thr_term(&conn->cc_sctp3436_data.array[i].thr), /* continue */ ); … … 763 763 { 764 764 uint16_t i; 765 765 766 766 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); 767 767 768 768 /* Terminate all receiving threads in case we did not do it yet */ 769 769 fd_sctp3436_stopthreads(conn); 770 770 771 771 /* Now, stop the demux thread */ 772 772 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); 773 773 774 774 /* Free remaining data in the array */ 775 775 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { … … 782 782 } 783 783 } 784 784 785 785 /* Free the array itself now */ 786 786 free(conn->cc_sctp3436_data.array); 787 787 conn->cc_sctp3436_data.array = NULL; 788 788 789 789 /* Delete the store of sessions */ 790 790 store_destroy(conn); 791 791 792 792 return ; 793 793 }
Note: See TracChangeset
for help on using the changeset viewer.