changeset 374:883330e610e1

Progress on the echo_drop sub extension
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 26 May 2009 11:37:32 +0900
parents 0cb02e490017
children 52b7e13cb1e7
files doc/sub_echo_drop.conf.sample extensions/radius_gw/CMakeLists.txt extensions/radius_gw/radius_gw.c extensions/radius_gw/rg_api.h extensions/radius_gw/rgw_extensions.c extensions/radius_gw/rgw_work.c extensions/radius_gw/sub_echo_drop.c extensions/radius_gw/sub_echo_drop.h extensions/radius_gw/sub_echo_drop.y
diffstat 9 files changed, 253 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
 #  <type>    : The attribute is interpreted as TLV (rfc3865, section 5.26) 
 #		and we match only this "vendor type" value (8 bits).
 #
-#  <ext-type>: The attribute is interpreted as extended attribute (draft-ietf-radext-extended-attributes-08)
+#  <ext-type>: 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
--- 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}")
--- 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();
--- 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.
--- 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 */
--- 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;
--- 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;
--- 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);
 
--- 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;
 			}
 			;	
 
"Welcome to our mercurial repository"