OpenSIPS实战(八):修改sip消息-使用lumps system

目录

前言

1、lumps system简介

2、lumps system函数接口

    2.1 创建指定被操作lumps的函数

    2.2 创建用于新插入或替换lumps的函数

3、修改Contact头域与lump操作图解

    3.1 使用lumps实现FixContact函数

    3.2 图解FixContact函数的lumps操作过程

小结

 

 


 

前言

 

 

SIP消息交互的过程中,经常需要对sip消息进行修改,如修改/添加SIP头域,修改SDP内容等,在使用过程中多少也会遇到需要开发来修改信令实现功能的情况。在OpenSIPS中对SIP消息执行更改的标准机制是使用所谓的块系统(lumps system)。

 

1、lumps system简介

 

OpenSIPS的lumps system效率很高,这也是opensips性能高效的一个原因之一。这些要修改的块(lumps)存储在一个列表中,并且只在OpenSIPS脚本执行完毕之后并且在SIP消息被转发之前应用到消息中(重新组包)。因此,对SIP消息所做的更改在进一步检查时不会立即反映在SIP消息中

 

lumps system虽然设计巧妙,但是使用起来不容易理解,我也是用过几次之后,专门翻了下代码实现来研究,才慢慢理解lumps操作的。

 

Lumps分为两种,SIP消息块(SIP Message Lumps)SIP响应块(SIP Reply Lumps)。这里主要介绍常会用到的SIP消息块操作。将“lumps”直接翻译为“块”对于后文的叙述而言容易造成意义不清,后面的叙述将都使用lumps来说明。

 

2、lumps system函数接口

 

SIP消息块这种类型的lumps用于操作当前SIP消息。从操作的角度来看,SIP消息块也分为两类:删除lumps(Delete Lumps)和添加lumps(Add Lumps)。但从函数接口角度来分又可以分为两类:创建指定被操作lumps的函数和创建插入或替换lumps的函数。

下面从函数接口角度对几个常用的具有代表性的lumps操作函数进行分类介绍。

 

2.1 创建指定被操作lumps的函数

 

del_lump函数接口:

/*
Parameters :
      msg - the SIP message the lump will affect
      offset - the offset in the SIP message at which to start deleting
      len - the number of characters to delete from the SIP message
      type - indication on which header the current lump affects ( can be 0 )
Returns :
      the created lump structure for deleting part of the SIP message. 
      Can be further used to chain together different types of lumps in 
      the message attached list of lumps. NULL is returned in case of internal error.
*/
struct lump* del_lump(struct sip_msg* msg, unsigned int offset, 
        unsigned int len, enum _hdr_types_t type);

del_lump函数用于指定在当前sip_msg buffer中要删除的消息块的内存位置和删除长度。del_lump函数创建一个lump对象,指定删除的lump在sip_msg buffer中的位移(offset)以及删除长度(len)、lump类型LUMP_DEL(函数内部指定,不是参数type指定,下同)等,并将lump对象插入到sip_msg中的lump链表中,最后返回该lump对象的指针。

 

 anchor_lump函数接口:

/*
Parameters :
      msg - the SIP message that will be affected by the lump anchor
      offset - the offset in the SIP message where the anchor will be placed
      type - header type that is affected by the current change ( can be 0 )
Returns:
      the created lump structure for adding to the SIP message.
      Can be further used to chain together different types of lumps 
      in the message attached list of lumps. NULL is returned in case of internal error.
*/
struct lump* anchor_lump(struct sip_msg* msg, unsigned int offset, 
                 enum _hdr_types_t type)

anchor_lump函数创建(malloc)一个lump对象,用于保存该lump插入点在sip_msg buffer中的位移(offset),lump操作类型设置为LUMP_NOP等,并将该lump对象插入到sip_msg中的lump链表,最后返回该lump对象的指针。

 

2.2 创建用于新插入或替换lumps的函数

insert_new_lump_after和insert_new_lump_before接口:

/*
Parameters :
      after/before - the lump where we will connect our new lump
      new_hdr - string to be added
      len - length of the string to be added
      type - header type that is affected by the current change ( can be 0 )
Returns :
      the created lump structure for adding to the SIP message. 
      Can be further used to chain together different types of lumps 
      in the message attached list of lumps. NULL is returned in case of internal error.
*/
struct lump* insert_new_lump_after(struct lump* after, char* new_hdr,    
                unsigned int len, enum _hdr_types_t type);
struct lump* insert_new_lump_before(struct lump* before, char* new_hdr,
                unsigned int len,enum _hdr_types_t type);

insert_new_lump_after和insert_new_lump_before这两个函数分别用于创建用于新插入或替换原有内容的lumps。

insert_new_lump_after函数传入一个指定了新插入(或删除)位置的lumpafter(del_lump和anchor_lump函数返回的lump),并创建一个新的lump tmp,lump tmp用于保存新插入(或替换)内容的buffer指针以及buffer长度,lumps操作类型设置为LUMP_ADD,最后将after->after指向tmp,并返回tmp对象。

insert_new_lump_before函数操作和insert_new_lump_after函数基本相同,只是最后将传入的指定了新插入(或删除)位置的lump tmp赋值给了before->before。

这两个函数实现上和功能上区别不大,大部分场景这两个函数调用效果都是一样的,唯一的区别只是在消息重新组包的时候,insert_new_lump_before创建的lump比insert_new_lump_after创建的lump先被执行

 

lumps system提供的所有接口都声明在data_lump.h头文件中,这里只介绍了常用的几个。

下面举例讲解lumps操作。

 

3、使用lump实现FixContact函数

 

以下图场景为例,OpenSIPS收到的SIP消息中,Contact头域中URI地址是无效的“o8kvkeft9oak.invalid”字符串:

 

如果需要从OpenSIPS上修复这个问题,就需要用到lumps system。

 

3.1 FixContact函数实现

该函数可以实现为模块导出函数,在脚本中调用。实际上nat_traversal模块已经实现同名且功能相同的导出函数,这里做了修改,以更好的说明。

FixContact函数实现

static int
FixContact(struct sip_msg *msg)
{
    str newip;
    unsigned short newport;
    contact_t* contact;
    struct lump* anchor;
    struct sip_uri uri;
    int len, offset;
    char *addr_buf;
    
    /* 从消息中解析出Contact头域 */
    if ((parse_headers(msg, HDR_CONTACT_F, 0) == -1) || !msg->contact) {
        LM_ERR("parse the Contact header failed\n");
        return -1;
    }
            
    if (!msg->contact->parsed && parse_contact(msg->contact) < 0) {
        LM_ERR("cannot parse the Contact header\n");
        return -1;
    }

    contact = ((contact_body_t*)msg->contact->parsed)->contacts;
    if (contact == NULL) {
        LM_ERR("Contact header is NULL\n");
        return -1;
    }

    if (parse_uri(contact->uri.s, contact->uri.len, &uri) < 0 || uri.host.len <= 0) {
        LM_ERR("cannot parse the Contact URI\n");
        return -1;
    }
        
    /* 获得消息源IP地址 */
    newip.s = ip_addr2a(&msg->rcv.src_ip);
    newip.len = strlen(newip.s);
    newport = msg->rcv.src_port;

    len = newip.len + 10;
    addr_buf = pkg_malloc(len);
    if (addr_buf == NULL) {
        LM_ERR("out of memory\n");
        return -1;
    }
    /* 创建指定要被替换的lump */
    offset = uri.host.s - msg->buf;
    anchor = del_lump(msg, offset, uri.host.len, 0);
    if (!anchor) {
        pkg_free(addr_buf);
        return -1;
    }

    if(msg->rcv.src_ip.af == AF_INET6) {
        len = sprintf(addr_buf, "[%.*s]:%d", newip.len, newip.s, newport); 
    } else {
        len = sprintf(addr_buf, "gf%.*s:%d", newip.len, newip.s, newport); 
    }
    
    /* 创建用于替换的lump */
    if (insert_new_lump_after(anchor, addr_buf, len, 0) == 0) {
        pkg_free(addr_buf);
        return -1;
    }
        
    return 1;
}

如果在脚本逻辑对应位置中调用了该函数,则当前消息将会在转发修正这个问题,也就是contact URI中的“o8kvkeft9oak.invalid”被替换为了UAC的源地址,然后再转发给下一跳服务器。

 

3.2 图解FixContact函数lumps操作过程

第一步,FixContact函数从消息包中解析获得Contact头域对象,然后再解析Contact头域,获得头域中发URI对象。

 

 

第二步,计算contact URI在于消息 buffer中的偏移量,并计算要替换的字符串长度,调用del_lump函数创建指定删除字符串的lump,并保存返回的lump指针对象anchor。

第三步,使用正确的IP:Port填充addr_buf,然后调用insert_new_lump_after函数,传入anchor,addr_buf地址和addr_buf长度。

最后在消息转发前,会基于msg消息的lump链表重新进行组包,才最终将修改应用到消息中。

这里图解lumps只展示了一个概略的组包流程,实际代码实现包含很多实现细节,这里都没有展示,毕竟讲解lumps system源码实现不是本篇的目的(lumps system的源码实现还是值得学习的,如果哪天我有心情有时间也许会写一篇源码实现的介绍呢~)。

 

 

小结

 OpenSIPS的lumps system从实现的很巧妙,代码应用上也经常会用到。如果需要了解更多实现细节可以去查看lumps实现源码和消息组包源码。如果需要知道其他lumps函数的使用方法也可以去查看OpenSIPS模块的源码,看是怎么使用的,毕竟这方面文档太少。

 

 


(全文完)

 

更多查看官方文档

http://www.opensips.org/Documentation/Development-Manual#toc11

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要安装OpenSIPS,您可以按照以下步骤进行操作: 1. 首先,确保您的系统满足OpenSIPS的要求。OpenSIPS支持Linux和Unix操作系统,建议在Ubuntu、Debian、CentOS等常见发行版上进行安装。 2. 打开终端并使用root权限登录到您的服务器。 3. 更新系统软件包列表,执行以下命令: - 对于Debian/Ubuntu系统:sudo apt update - 对于CentOS系统:sudo yum update 4. 安装所需的依赖项。执行以下命令: - 对于Debian/Ubuntu系统:sudo apt install build-essential bison flex libncurses-dev libssl-dev libmysqlclient-dev libxml2-dev libpcre3-dev unixodbc-dev libcurl4-openssl-dev libldap2-dev libhiredis-dev - 对于CentOS系统:sudo yum install gcc-c++ bison flex ncurses-devel openssl-devel mysql-devel libxml2-devel pcre-devel unixODBC-devel libcurl-devel openldap-devel hiredis-devel 5. 下载OpenSIPS源代码包。您可以从OpenSIPS官方网站(https://opensips.org)下载最新版本的源代码。 6. 解压下载的源代码包,并进入解压后的目录。执行以下命令: - tar -zxvf opensips-x.x.x.tar.gz # x.x.x为下载的版本号 - cd opensips-x.x.x 7. 配置编译选项并编译源代码。执行以下命令: - make menuconfig - make all 8. 安装OpenSIPS。执行以下命令: - sudo make install 9. 配置OpenSIPS。您可以编辑配置文件进行相关设置。主要的配置文件是opensips.cfg,位于/usr/local/etc/opensips/目录下。 10. 启动OpenSIPS服务。执行以下命令: - sudo opensipsctl start 至此,您已经完成了OpenSIPS的安装和基本配置。您可以根据需要进一步配置和调整OpenSIPS以满足您的需求。记得查阅OpenSIPS官方文档以获取更多详细信息和指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值