# HG changeset patch # User Sebastien Decugis # Date 1243305452 -32400 # Node ID 883330e610e1a106a7ac78e5c13ddeff1ef1e6bd # Parent 0cb02e49001744a09469cfb3cd4014603d57e564 Progress on the echo_drop sub extension diff -r 0cb02e490017 -r 883330e610e1 doc/sub_echo_drop.conf.sample --- a/doc/sub_echo_drop.conf.sample Mon May 25 17:25:53 2009 +0900 +++ b/doc/sub_echo_drop.conf.sample Tue May 26 11:37:32 2009 +0900 @@ -23,9 +23,11 @@ # : The attribute is interpreted as TLV (rfc3865, section 5.26) # and we match only this "vendor type" value (8 bits). # -# : The attribute is interpreted as extended attribute (draft-ietf-radext-extended-attributes-08) +# : NOTE: THIS OPTION IS NOT SUPPORTED PROPERLY YET!!!! +# The attribute is interpreted as extended attribute (draft-ietf-radext-extended-attributes-08) # and we match only this "Ext-Type" value (16 bits). # This option should only be used with "CODE 26 VENDOR 0". +# # Examples: # ECHO code 25 ; # Class attributes diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/CMakeLists.txt --- a/extensions/radius_gw/CMakeLists.txt Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/CMakeLists.txt Tue May 26 11:37:32 2009 +0900 @@ -62,6 +62,7 @@ OPTION(BUILD_SUB_ECHO_DROP "Build 'echo/drop' sub-extension? (echo or drop specific RADIUS attributes, no Diameter translation)" ON) IF (BUILD_SUB_ECHO_DROP) + ADD_DEFINITIONS(-DSUB_ECHO_DROP_VERBO=2) BISON_FILE(sub_echo_drop.y) FLEX_FILE(sub_echo_drop.l) SET_SOURCE_FILES_PROPERTIES(lex.sub_echo_drop.c sub_echo_drop.tab.c PROPERTIES COMPILE_FLAGS "-I ${CMAKE_CURRENT_SOURCE_DIR}") diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/radius_gw.c --- a/extensions/radius_gw/radius_gw.c Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/radius_gw.c Tue May 26 11:37:32 2009 +0900 @@ -59,11 +59,10 @@ CHECK_FCT( rgw_conf_handle(conffile) ); - TRACE_DEBUG(FULL, "-------------------------"); + TRACE_DEBUG(INFO, "Extension RADIUS Gateway initialized with configuration: '%s'", conffile); rgw_servers_dump(); rgw_clients_dump(); rgw_extensions_dump(); - TRACE_DEBUG(FULL, "-------------------------"); /* Start making extension list accelerators */ rgw_extensions_start_cache(); diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/rg_api.h --- a/extensions/radius_gw/rg_api.h Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/rg_api.h Tue May 26 11:37:32 2009 +0900 @@ -51,18 +51,18 @@ /* handle an incoming RADIUS message */ int (*rga_rad_req_cb) ( struct rga_conf_state * cs, sess_id_t ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, msg_t ** diam_fw ); /* ret 0: continue; - ret 1: stop processing this message and destroy the session (or fallback if supported) - ret 2: stop processing this message and keep the session (or fallback if supported) - ret 3: reply the content of rad_ans to the RADIUS client immediatly and destroy the session - ret 4: reply the content of rad_ans to the RADIUS client immediatly and keep the session - ret <0: critical error (-ret), log and exit. + ret -1: stop processing this message and destroy the session (or fallback if supported) + ret -2: stop processing this message and keep the session (or fallback if supported) + ret -3: reply the content of rad_ans to the RADIUS client immediatly and destroy the session + ret -4: reply the content of rad_ans to the RADIUS client immediatly and keep the session + ret >0: critical error (errno), log and exit. for cases 3 and 4, the answer must be created with rg_msg_create_ans. */ /* handle the corresponding Diameter answer */ int (*rga_diam_ans_cb) ( struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw ); - /* ret 0: continue; ret 1: ... (tbd) */ + /* ret 0: continue; ret >0: error; ret: -1 ... (tbd) */ }; /* All extensions must provide the following entry point that is called when the extension is loaded. diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/rgw_extensions.c --- a/extensions/radius_gw/rgw_extensions.c Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/rgw_extensions.c Tue May 26 11:37:32 2009 +0900 @@ -297,12 +297,11 @@ } } - log_debug(" %-15s (%-20s) - p: %s %s, %d cc: %s\n", + log_debug(" %-15s ( %-20s) - types: %s%s, codes: %s\n", ext->extname, basename(ext->conffile), ext->type & RGW_EXT_TYPE_AUTH ? "Au" : " ", ext->type & RGW_EXT_TYPE_ACCT ? "Ac" : " ", - ext->cc_len, ext->cc ? codes : "*"); free(codes); @@ -380,13 +379,13 @@ } /* Destroy the session unless instructed to keep it */ - if (*session && (ret != 2) && (ret != 4)) { + if (*session && (ret != -2) && (ret != -4)) { CHECK_FCT_DO( sess_unlink(*session), ); *session = NULL; } /* Send the radius message back if required */ - if (((ret == 3) || (ret == 4)) && rad_ans) { + if (((ret == -3) || (ret == -4)) && rad_ans) { /* destination port: (*rad)->port */ /* destination ip: derived from cli */ /* post-processing: depends on (*rad)->serv_type */ @@ -396,10 +395,10 @@ ASSERT(0); } - if (ret < 0) { + if (ret > 0) { /* Critical error, log and exit */ - log_error("An error occurred while handling a RADIUS message, turn on DEBUG for details: %s\n", strerror(-ret)); - return -ret; + log_error("An error occurred while handling a RADIUS message, turn on DEBUG for details: %s\n", strerror(ret)); + return ret; } /* Now, discard the message and return */ diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/rgw_work.c --- a/extensions/radius_gw/rgw_work.c Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/rgw_work.c Tue May 26 11:37:32 2009 +0900 @@ -137,6 +137,8 @@ continue; /* the message was a duplicate */ } + /* Note: after this point, the radius message buffer may not be consistent with the array of attributes! */ + /* Pass the message to the list of registered extensions */ session = NULL; diam_msg = NULL; diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/sub_echo_drop.c --- a/extensions/radius_gw/sub_echo_drop.c Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/sub_echo_drop.c Tue May 26 11:37:32 2009 +0900 @@ -38,8 +38,9 @@ #define DECLARE_API_POINTERS #include "sub_echo_drop.h" -int sub_echo_drop_verbosity = 2; +int sub_echo_drop_verbosity = SUB_ECHO_DROP_VERBO; +/* Create the configuration and state structure */ static struct rga_conf_state * sed_cs_create(char * conffile) { struct rga_conf_state * cs = NULL; @@ -64,10 +65,34 @@ cs->conffile = conffile; CHECK_FCT_DO( sed_conf_parse(cs), { sess_deregext(cs->sess_hdl); free(cs); return NULL; } ); + TRACE_DEBUG(INFO, "Extension Echo/Drop initialized with configuration: '%s'", cs->conffile); + if (TRACE_BOOL(FULL)) { + struct rg_list * li; + + for (li = cs->conf.next; li != &cs->conf; li = li->next) { + struct sed_conf_item * sci = (struct sed_conf_item *)li; + char * act = (sci->action == ACT_ECHO) ? "ECHO" : "DROP"; + if (sci->ext) { + log_debug(" %s Code: %hhu, Vendor: %u, Ext-Type: %hu\n", act, sci->code, sci->vendor_id, sci->extype); + continue; + } + if (sci->tlv) { + log_debug(" %s Code: %hhu, Vendor: %u, Type: %hhu\n", act, sci->code, sci->vendor_id, sci->type); + continue; + } + if (sci->vsa) { + log_debug(" %s Code: %hhu, Vendor: %u\n", act, sci->code, sci->vendor_id); + continue; + } + log_debug(" %s Code: %hhu\n", act, sci->code); + } + } + /* We're done */ return cs; } +/* Destroy the state */ static void sed_cs_destroy(struct rga_conf_state * cs) { @@ -86,6 +111,193 @@ return; } +/* Destroy a list of attributes saved in a session */ +static void ssi_cleanup(void * ptr) +{ + TRACE_ENTRY("%p", ptr); + CHECK_PARAMS_DO( ptr , return ); + + struct rg_list *list = (struct rg_list *)ptr; + while (! rg_list_is_empty(list) ) { + struct sed_saved_item * ssi = (struct sed_saved_item *)(list->next); + rg_list_unlink(&ssi->chain); + free(ssi); + } + free(list); +} + +/* Handle attributes from a RADIUS request as specified in the configuration */ +static int sed_rad_req(struct rga_conf_state * cs, sess_id_t ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, msg_t ** diam_fw ) +{ + size_t *nattr_pos; + size_t nattr_used = 0; + int idx; + + struct rg_list echo_list; + struct rg_list *li; + + TRACE_ENTRY("%p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw); + CHECK_PARAMS(cs && rad_req); + + rg_list_init(&echo_list); + + CHECK_MALLOC( nattr_pos = malloc(rad_req->attr_size * sizeof(size_t)) ); + + /* For each attribute in the original message */ + for (idx = 0; idx < rad_req->attr_used; idx++) { + int action = 0; + struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]); + + /* Look if we have a matching attribute in our configuration */ + for (li = cs->conf.next; li != &cs->conf; li = li->next) { + struct sed_conf_item * sci = (struct sed_conf_item *)li; + uint32_t vid; + unsigned char * ptr; + + if (sci->code < attr->type) + continue; + if (sci->code > attr->type) + break; + + /* matching code */ + + if (! sci->vsa) { + action = sci->action; + break; + } + + if (attr->length < 8) + continue; + + ptr = (unsigned char *)(attr + 1); + /* since attr is not aligned, we cannot access *(attr+1) directly */ + memcpy(&vid, ptr, sizeof(uint32_t)); + + if (sci->vendor_id < ntohl(vid)) + continue; + if (sci->vendor_id > ntohl(vid)) + break; + + /* Matching vendor */ + + if ( ! sci->tlv && ! sci->ext ) { + action = sci->action; + break; + } + + if (attr->length < 10) + continue; + + if (sci->tlv) { + struct radius_attr_vendor * tl = (struct radius_attr_vendor *)(ptr + sizeof(uint32_t)); + if (tl->vendor_type == sci->type) { + action = sci->action; + break; + } + continue; + } + + if (sci->ext) { + /* To be done */ + ASSERT(0); + } + } + + switch (action) { + case ACT_DROP: + TRACE_DEBUG(FULL, "Dropping attribute with code %hhd", attr->type); + break; + + case ACT_ECHO: + { + struct sed_saved_item * sav = NULL; + TRACE_DEBUG(FULL, "Saving attribute with code %hhd", attr->type); + CHECK_MALLOC( sav = malloc(sizeof(struct sed_saved_item) + attr->length - sizeof(struct radius_attr_hdr)) ); + rg_list_init(&sav->chain); + memcpy(&sav->attr, attr, attr->length); + rg_list_insert_before(&echo_list, &sav->chain); + } + break; + + case 0: /* Attribute was not specified in the configuration */ + default: /* unknown action value */ + /* We just keep the attribute in the RADIUS message */ + nattr_pos[nattr_used++] = rad_req->attr_pos[idx]; + } + } + + /* Save the echoed values in the session, if any */ + if (!rg_list_is_empty(&echo_list)) { + CHECK_PARAMS(session && *session); + CHECK_MALLOC( li = malloc(sizeof(struct rg_list)) ); + memcpy(li, &echo_list, sizeof(struct rg_list)); + + /* Check that we have no previous data stored for this session, for debug */ + ASSERT( sess_data_dereg(*session, cs->sess_hdl, NULL) == ENOENT ); + + /* Save the list in the session */ + CHECK_FCT( sess_data_reg(*session, cs->sess_hdl, li, ssi_cleanup) ); + } + + /* Finally update the radius message to remove all handled attributes */ + free(rad_req->attr_pos); + rad_req->attr_pos = nattr_pos; + rad_req->attr_used = nattr_used; + + return 0; +} + +/* Process an answer: add back the ECHO attributes, if any */ +static int sed_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw ) +{ + int ret; + struct rg_list * list = NULL; + + TRACE_ENTRY("%p %p %p %p", cs, session, diam_ans, rad_fw); + CHECK_PARAMS(cs); + + /* If there is no session associated, just give up */ + if (! session || ! *session) { + TRACE_DEBUG(FULL, "No session associated with the message, nothing to do here..."); + return 0; + } + + /* No try and retrieve any data from the session */ + ret = sess_data_dereg( *session, cs->sess_hdl, (void *)&list ); + if (ret == ENOENT) { + TRACE_DEBUG(FULL, "No data saved in the session, no attribute to add back"); + return 0; + } + CHECK_FCT(ret); /* Return if another error occurred */ + + /* From this point on, we have a list of attributes to add to the radius message */ + + CHECK_PARAMS( rad_fw ); + if ( *rad_fw == NULL ) { + /* Will implement this when main extension is complete */ + ASSERT(0); + return ENOTSUP; + } + + while (! rg_list_is_empty(list) ) { + struct sed_saved_item * ssi = (struct sed_saved_item *)(list->next); + struct radius_attr_hdr * rc; + + rg_list_unlink(&ssi->chain); + + TRACE_DEBUG(FULL, "Echo attribute in the RADIUS answer: type %hhu, len: %hhu", ssi->attr.type, ssi->attr.length); + + /* Add this attribute in the RADIUS message */ + CHECK_MALLOC( radius_msg_add_attr(*rad_fw, ssi->attr.type, (unsigned char *)(ssi + 1), ssi->attr.length - sizeof(struct radius_attr_hdr)) ); + + free(ssi); + } + free(list); + + return 0; +} + + int rga_register(int version, waaad_api_t * waaad_api, struct radius_gw_api * api) { @@ -103,8 +315,8 @@ /* Initialize the radius_gw api callbacks */ api->rga_conf_parse_cb = sed_cs_create; api->rga_conf_free_cb = sed_cs_destroy; - api->rga_rad_req_cb = NULL; - api->rga_diam_ans_cb = NULL; + api->rga_rad_req_cb = sed_rad_req; + api->rga_diam_ans_cb = sed_diam_ans; /* We're done, we must not initialize any state here since the extension must be re-entrant, but in sample_conf_parse */ return 0; diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/sub_echo_drop.h --- a/extensions/radius_gw/sub_echo_drop.h Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/sub_echo_drop.h Tue May 26 11:37:32 2009 +0900 @@ -39,6 +39,11 @@ #ifndef _SUB_ECHO_DROP #define _SUB_ECHO_DROP +/* Default debug level for the extension */ +#ifndef SUB_ECHO_DROP_VERBO +#define SUB_ECHO_DROP_VERBO 0 +#endif /* SUB_ECHO_DROP_VERBO */ + #define IN_EXTENSION #define DEFINE_DEBUG_MACRO sub_echo_drop @@ -48,9 +53,11 @@ extern int sub_echo_drop_verbosity; +/* Action to perform on an attribute */ #define ACT_ECHO 1 #define ACT_DROP 2 +/* Parsed configuration: list of attributes and associated actions */ struct sed_conf_item { struct rg_list chain; @@ -67,7 +74,8 @@ uint8_t code; /* The attribute code, the list is ordered by this value */ }; - + +/* The structure that holds both configuration and state */ struct rga_conf_state { /* Input: configuration file */ char * conffile; @@ -79,6 +87,13 @@ sess_reg_t * sess_hdl; }; +/* For ECHO items, we save a list of these in the session */ +struct sed_saved_item { + struct rg_list chain; + struct radius_attr_hdr attr; /* copy of the attribute content, including the data */ +}; + + /* The yacc parser */ int sed_conf_parse(struct rga_conf_state *cs); diff -r 0cb02e490017 -r 883330e610e1 extensions/radius_gw/sub_echo_drop.y --- a/extensions/radius_gw/sub_echo_drop.y Mon May 25 17:25:53 2009 +0900 +++ b/extensions/radius_gw/sub_echo_drop.y Tue May 26 11:37:32 2009 +0900 @@ -140,7 +140,7 @@ attrdef: { memset(&attrinfo, 0, sizeof(attrinfo)); } - action TOK_CODE INTEGER vendordef + action TOK_CODE INTEGER vendordef ';' { struct sed_conf_item * new; struct rg_list * li; @@ -238,6 +238,8 @@ } attrinfo.extype = $2; attrinfo.ext = 1; + yyerror (&yylloc, cs, "The EXT option is not supported in this version."); + YYERROR; } ;