1. 仿Drouting在OpenSER中加个Nrouting模块:
  2. 宁卫通信
  3. 新闻动态
  4. 宁卫新闻
  5. 仿Drouting在OpenSER中加个Nrouting模块

仿Drouting在OpenSER中加个Nrouting模块

     在《实时检测,自动实现话务转接:OpenSER的Drouting模块应用》中,我们简单讲述了drouting,其实在实际应用中,我可能偏load balancer或dispatcher,毕竟drouting真的要用好的话,也比较难,但有时需要自定义相关的路由,在OpenSER体系中,脚本才是我们最重要的工具,可出错,或折腾来折腾去等很多的问题就跟着出现了,所以我们实现了一个Nrouting模块,用于按主叫,来源Ip,被叫三者进行主叫改号改地址,被叫改号改地址等相关操作。

表结构:

图片

图片

图片

前端界面:

图片

图片


图片

图片

opensips模块代码(kamailio差不多):

 #include <stdio.h>#include <stdlib.h>#include <string.h>#include "../../globals.h" //其中定义了extern char *db_default_url;#include "../../sr_module.h"#include "../../mem/mem.h"#include "../../mem/shm_mem.h"#include "../../dprint.h"#include "../../mod_fix.h"#include "../rr/api.h"#include "../../lib/digest_auth/digest_auth.h"#include "../../parser/digest/digest.h"#include "../../parser/parse_from.h"#include "../../parser/parse_to.h"#include "../../parser/parse_uri.h"#include "../../parser/msg_parser.h"#include "../../parser/parse_authenticate.h" #include "nrouting.h"#include "libnwayrouting.h"#define HLP1 "nr_route_media:check from media server,or rewrite ruri/furi/turi\n" \ "nr_route:check from gateway rewrite ruri/furi/turi\n"\ "nr_auth:check auth\n" int nr_mi_param =0;////////////////////////////////////////static str db_url = {NULL,0}; //默认数据库连接,如果指定了系统默认的,那么就用系统默认的,切记,一定一定要用Postgresql static str use_domain = {"0",1}; ////////////////////////////////////// static int fixup_av_mgm(void** param);static int fixup_nway_qop(void** param);static int fixup_nway_alg(void** param);///// static int mod_init(void);static void mod_destroy(void);static int child_init(int rank); static int nr_route_function(struct sip_msg* msg, char* param, char* value); //路由static int nr_auth_function(struct sip_msg* msg, char* param, char* value); //认证static int nr_challenge_function(struct sip_msg *msg, str *realm, qop_type_t qop, intptr_t algmask); //挑战static int nr_route_media_function(struct sip_msg* msg, char* param, char* value); //从媒体服务器过来 static int nr_mi_function(struct mi_root* cmd_root, void* param, unsigned int param_no);mi_response_t *nr_reload_cmd(const mi_params_t *params, struct mi_handler *async_hdl); static cmd_export_t cmds[] = { {"nr_route", (cmd_function)nr_route_function, { {CMD_PARAM_STR|CMD_PARAM_OPT,0,0}, {0,0,0}},REQUEST_ROUTE},  {"nr_auth", (cmd_function)nr_auth_function, { {CMD_PARAM_STR, 0, 0}, {0,0,0}}, REQUEST_ROUTE},  {"nr_challenge", (cmd_function)nr_challenge_function, { {CMD_PARAM_STR|CMD_PARAM_OPT, 0, 0}, /* realm */ {CMD_PARAM_STR|CMD_PARAM_OPT|CMD_PARAM_FIX_NULL, fixup_nway_qop, 0},/* qop */ {CMD_PARAM_STR|CMD_PARAM_OPT|CMD_PARAM_FIX_NULL, fixup_nway_alg, 0},/* alg */ {0,0,0}},REQUEST_ROUTE},  {"nr_route_media", (cmd_function)nr_route_media_function, { {CMD_PARAM_STR|CMD_PARAM_OPT,0,0}, {0,0,0}},REQUEST_ROUTE},  {0,0,{{0,0,0}},0}};  static const param_export_t params[] = {  {"db_url",           STR_PARAM, &db_url.s         }, {"use_domain",       STR_PARAM, &use_domain.s       }, {0, 0, 0}};   struct module_exports exports = { "nrouting", MOD_TYPE_DEFAULT, MODULE_VERSION, DEFAULT_DLFLAGS, 0,  0, cmds, /* module commands */ NULL, /* Exported async functions */ params, /* Exported parameters */ NULL, /* exported statistics */ NULL, /* exported MI functions */ NULL, /* exported pseudo-variables */ NULL, /* exported transformations */ 0, /* extra processes */ 0, /* module pre-initialization function */ mod_init, /* module initialization function */ 0, /* response function */ mod_destroy, /* destroy function */ child_init, /* child initialization function */ NULL /* reload confirm function */}; static int child_init(int rank){ return 0;}static int mod_init(void){ LM_WARN("nrouting: module initialized\n");  return 1;} static void mod_destroy(void){ LM_INFO("nrouting: module destroyed\n");} static int nr_route_function(struct sip_msg* msg, char* param, char* value){ LM_WARN("nr_route_function called with param: %s, value: %s\n", param, value);  return 1;}static int nr_auth_function(struct sip_msg* msg, char* domain, char* value){  return 1;}static int fixup_nway_qop(void** param){ return 0;}static int fixup_nway_alg(void** param){ return 0;}//challengestatic char* generate_secret_key() { char *key = (char *)pkg_malloc(33); // 32 bytes + null terminator if (!key) { return NULL; }  // 初始化随机数生成器 srand(time(NULL));  // 生成32字节的随机数据 for (int i = 0; i < 16; i++) { unsigned int random_value = rand(); sprintf(&key[i * 2], "%02x", random_value & 0xFF); }  key[32] = '\0'; // null terminator return key;}// 生成noncechar* generate_nonce(nway_challenge_t *n) { char *nonce = (char *)malloc(256); if (!nonce) { return NULL; }  // 使用当前时间和一个随机数生成nonce srand(time(NULL)); int random_value = rand(); snprintf(nonce, 256, "%ld:%d:%s", time(NULL), random_value, n->secret_key); return nonce;} //////////////////////////static int nr_challenge_function(struct sip_msg* msg, str *realm, qop_type_t qop, intptr_t algmask){  return 1; }static int nr_route_media_function(struct sip_msg* msg, char* param, char* value){  return 1;}   mi_response_t *nr_reload_cmd(const mi_params_t *params, struct mi_handler *async_hdl){  return init_mi_result_ok();} 

路由方式:

#### 加载宁卫专有模块loadmodule "nrouting.so"modparam("nrouting","use_domain","0") route{  ...  if (is_method("INVITE")  ) {      if (nr_route_media()){        t_relay();      }else if (nr_route()){       t_relay();      }else{        xlog("L_INFO","呼叫来源于非媒体服务,也非网关,进行相关验证!\n");        if (nr_auth("")){         t_relay();        }else{          xlog("L_INFO","非法呼叫$fu!\n");        }      }}

那么以上方式再结合其实一些功能模块,对于OpenSER来说,就可以更好地控制和使用。

以上模块均结合golang实现相关的逻辑,在golang中解析我们的sip消息:

type SIPMessage struct { Method      string URI         string Version     string Headers     map[string][]string}func NwayParseSIPMessage(message string) SIPMessage { lines := strings.Split(message, "\n") requestLine := strings.Fields(lines[0])  sipMessage := SIPMessage{ Method:  requestLine[0], URI:     requestLine[1], Version: requestLine[2], Headers: make(map[string][]string), }  for _, line := range lines[1:] { if line == "" { continue } header := strings.SplitN(line, ":", 2) if len(header) == 2 { key := strings.TrimSpace(header[0]) value := strings.TrimSpace(header[1]) sipMessage.Headers[key] = append(sipMessage.Headers[key], value) } }  return sipMessage}

这样在开发时,相对省时省力也性能比较高效。