Mercurial > hg > freeDiameter
changeset 1041:a740267f1be6
Add extension that removes Destination-Host from Requests and restores it for Answers.
author | Thomas Klausner <tk@giga.or.at> |
---|---|
date | Thu, 18 Apr 2013 15:49:45 +0200 |
parents | 86d37d9f7b13 |
children | dcc0eff204cf |
files | extensions/rt_ignore_dh/CMakeLists.txt extensions/rt_ignore_dh/rt_ignore_dh.c |
diffstat | 2 files changed, 221 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_ignore_dh/CMakeLists.txt Thu Apr 18 15:49:45 2013 +0200 @@ -0,0 +1,20 @@ +# The rt_ignore_dh extension +PROJECT("Routing extension that removes Destination-Host from messages and restores from Proxy-Info for answers" C) + +# List of source files +SET(RT_IGNORE_DH_SRC + rt_ignore_dh.c +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +# Compile these files as a freeDiameter extension +FD_ADD_EXTENSION(rt_ignore_dh ${RT_IGNORE_DH_SRC}) + +#### +## INSTALL section ## + +# We install with the daemon component because it is a base feature. +INSTALL(TARGETS rt_ignore_dh + LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX} + COMPONENT freeDiameter-daemon)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_ignore_dh/rt_ignore_dh.c Thu Apr 18 15:49:45 2013 +0200 @@ -0,0 +1,201 @@ +#include <freeDiameter/extension.h> + +/* + * Remove Destination-Hosts, putting it into Proxy-Info, and restore it to + * Origin-Host for answers. + */ + +struct dict_object * dh_avp_do; /* cache the Destination-Host dictionary object */ +struct dict_object * oh_avp_do; /* cache the Origin-Host dictionary object */ +struct dict_object * ph_avp_do; /* cache the Proxy-Host dictionary object */ +struct dict_object * pi_avp_do; /* cache the Proxy-Info dictionary object */ +struct dict_object * ps_avp_do; /* cache the Proxy-State dictionary object */ + +static void *memdup(void *data, size_t len) +{ + void *mem; + if ((mem=malloc(len)) == NULL) + return NULL; + memcpy(mem, data, len); + return mem; +} + +static int restore_origin_host(struct msg **msg) { + struct avp *avp, *child; + struct avp *oh_avp = NULL; + struct avp *pi_avp = NULL; + int match; + void *ps, *new_oh; + size_t ps_len, new_oh_len = 0; + union avp_value val; + + ps = new_oh = NULL; + + CHECK_FCT(fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL)); + /* look for Origin-Host and Proxy-Info matching this host */ + while (avp && (!oh_avp || !pi_avp)) { + struct avp_hdr * ahdr; + + CHECK_FCT(fd_msg_avp_hdr(avp, &ahdr)); + if (!(ahdr->avp_flags & AVP_FLAG_VENDOR)) { + switch (ahdr->avp_code) { + case AC_ORIGIN_HOST: + oh_avp = avp; + CHECK_FCT(fd_msg_parse_dict(oh_avp, fd_g_config->cnf_dict, NULL)); + break; + case AC_PROXY_INFO: + ps = NULL; + match = ps_len = 0; + CHECK_FCT(fd_msg_parse_dict(avp, fd_g_config->cnf_dict, NULL)); + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child, NULL)); + int match = 0; + while (child && (!match || !ps)) { + struct avp_hdr *chdr; + CHECK_FCT(fd_msg_avp_hdr(child, &chdr)); + if (!(chdr->avp_flags & AVP_FLAG_VENDOR)) { + switch (chdr->avp_code) { + case AC_PROXY_HOST: + if (fd_os_cmp(chdr->avp_value->os.data, chdr->avp_value->os.len, + fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len) == 0) { + match = 1; + } + break; + case AC_PROXY_STATE: + ps_len = chdr->avp_value->os.len; + ps = memdup(chdr->avp_value->os.data, ps_len); + if (!ps) { + TRACE_ERROR("malloc failure"); + return 0; + } + break; + default: + break; + } + } + CHECK_FCT(fd_msg_browse(child, MSG_BRW_NEXT, &child, NULL)); + } + if (match && ps) { + new_oh = ps; + new_oh_len = ps_len; + pi_avp = avp; + } else + free(ps); + break; + default: + break; + } + } + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + if (!pi_avp) + return 0; + + memset(&val, 0, sizeof(val)); + val.os.data = new_oh; + val.os.len = new_oh_len; + if (!oh_avp) { + TRACE_ERROR("Message contained no Origin-Host"); + } else { + CHECK_FCT(fd_msg_avp_setvalue(oh_avp, &val)); + } + fd_msg_free((msg_or_avp*)pi_avp); + + fd_log_debug("Restored Origin-Host '%.*s' from Proxy-Info", (int)new_oh_len, (char *)new_oh); + return 0; +} + +static int stow_destination_host(struct msg **msg) { + struct avp * avp = NULL; + struct avp * ph_avp = NULL; + struct avp * pi_avp = NULL; + struct avp * ps_avp = NULL; + + /* Look for the Destination-Host AVP in the message */ + CHECK_FCT(fd_msg_search_avp(*msg, dh_avp_do, &avp)); + if (avp != NULL) { + struct avp_hdr * ahdr = NULL; + union avp_value val; + + CHECK_FCT(fd_msg_avp_hdr(avp, &ahdr)); + if (ahdr->avp_value != NULL) { + /* add Proxy-Info->{Proxy-Host, Proxy-State} using Destination-Host information */ + CHECK_FCT(fd_msg_avp_new(ph_avp_do, 0, &ph_avp)); + memset(&val, 0, sizeof(val)); + val.os.data = memdup(fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len); + val.os.len = fd_g_config->cnf_diamid_len; + CHECK_FCT(fd_msg_avp_setvalue(ph_avp, &val)); + + CHECK_FCT(fd_msg_avp_new(ps_avp_do, 0, &ps_avp)); + memset(&val, 0, sizeof(val)); + val.os.data = memdup(ahdr->avp_value->os.data, ahdr->avp_value->os.len); + val.os.len = ahdr->avp_value->os.len; + CHECK_FCT(fd_msg_avp_setvalue(ps_avp, &val)); + + CHECK_FCT(fd_msg_avp_new(pi_avp_do, 0, &pi_avp)); + CHECK_FCT(fd_msg_avp_add(pi_avp, MSG_BRW_LAST_CHILD, ph_avp)); + CHECK_FCT(fd_msg_avp_add(pi_avp, MSG_BRW_LAST_CHILD, ps_avp)); + + /* remove Destination-Host from message */ + fd_msg_free((msg_or_avp*)avp); + /* add Proxy-Info */ + CHECK_FCT(fd_msg_avp_add(*msg, MSG_BRW_LAST_CHILD, pi_avp)); + fd_log_debug("Stowed Destination-Host '%.*s' into Proxy-Info", (int)val.os.len, (const char *)val.os.data); + } + } + + return 0; +} + +/* The callback for putting Destination-Host into Proxy-Info and restoring it on the way back */ +static int rt_ignore_destination_host(void * cbdata, struct msg **msg) { + struct msg_hdr * hdr; + int ret; + + TRACE_ENTRY("%p %p", cbdata, msg); + + CHECK_PARAMS(msg && *msg); + + /* Read the message header */ + CHECK_FCT(fd_msg_hdr(*msg, &hdr)); + if (hdr->msg_flags & CMD_FLAG_REQUEST) { + ret = stow_destination_host(msg); + } else { + ret = restore_origin_host(msg); + } + + return ret; +} + +/* handler */ +static struct fd_rt_fwd_hdl * rt_ignore_destination_host_hdl = NULL; + +/* entry point */ +static int rt_ignore_destination_host_entry(char * conffile) +{ + CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Host", &dh_avp_do, ENOENT), + { TRACE_ERROR("Unable to find 'Destination-Host' AVP in the loaded dictionaries."); }); + CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &oh_avp_do, ENOENT), + { TRACE_ERROR("Unable to find 'Origin-Host' AVP in the loaded dictionaries."); }); + CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Host", &ph_avp_do, ENOENT), + { TRACE_ERROR("Unable to find 'Proxy-Host' AVP in the loaded dictionaries."); }); + CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &pi_avp_do, ENOENT), + { TRACE_ERROR("Unable to find 'Proxy-Info' AVP in the loaded dictionaries."); }); + CHECK_FCT_DO(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Proxy-State", &ps_avp_do, ENOENT), + { TRACE_ERROR("Unable to find 'Proxy-State' AVP in the loaded dictionaries."); }); + + /* Register the callback */ + CHECK_FCT(fd_rt_fwd_register(rt_ignore_destination_host, NULL, RT_FWD_ALL, &rt_ignore_destination_host_hdl)); + + TRACE_DEBUG(INFO, "Extension 'Ignore Destination Host' initialized"); + return 0; +} + +/* Unload */ +void fd_ext_fini(void) +{ + /* Unregister the callbacks */ + CHECK_FCT_DO(fd_rt_fwd_unregister(rt_ignore_destination_host_hdl, NULL), /* continue */); + return ; +} + +EXTENSION_ENTRY("rt_ignore_destination_host", rt_ignore_destination_host_entry);