内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)

总结一下内核ALG的学习方法和基本原理,方便以后需要了解这方面的朋友少走弯路。该文档分析基于broadcom5358方案。

 

一、如何查看板子是否使用内核ALG

1、建立一条含有INTERNET服务,并且开启了NAT选项的WAN连接(注意:如果是pppoedhcp,请确保连接成功,这一步一定要记得看一下,否则代码流程不会插入SIP ALG相关内核模块)。

2、开启SIP ALG功能开关。

3、使用lsmod命令查看,SIP ALG相关模块是否已经插入,5358上为nf_nat_sipnf_conntrack_sipnf_conntrack_rtp6828上只有nf_nat_sipnf_conntrack_sip,如果有些板子不支持lsmod命令,可以进入/sys/module目录,查看下面是否有相关模块的

目录。

 

二、如何识别一个SIP报文是否使用内核ALG(主要是区别与应用层ALG的差别)

应用层ALG是属于代理机制,它将LAN侧报文转发到WAN侧后,会增加一个自身WANIPVIA头域。

而内核ALG是属于隧道机制,它将LAN侧报文转发到WAN侧后,仅仅是将VIA头域修改为自身WANIP

 

三、内核代码经常有多余无用的文件,如何识别哪个文件才是真正可用的文件。

比如当前内核目录中存在net/ipv4/netfilter/ip_nat_sip.c、和net/ipv4/netfilter/nf_nat_sip.c两个文件,但当前nf_nat_sip.c会编译使用,如何需要了解内核模块方面的编译,需要系统学习kbuild相关文档,这里仅仅简单介绍一下如何识别方法,有时间还是去了解一下kbuild方面的知识比较好。

1、查看net\ipv4\netfilter目录下的Makefile文件,搜索一下“ip_nat_sip”,可以找到“obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o”,这里可以看到,ip_nat_sip.o如果要编译取决于CONFIG_IP_NF_NAT_SIP宏的设置,该宏的值就是我们在kconfig里常看到的N\M\Y的选项值。

2、在内核目录下打开.config文件,找一下是否有CONFIG_IP_NF_NAT_SIP=m,如果没有,就表示ip_nat_sip.c文件并不会被编译。

同上面流程,在.config文件中会找到CONFIG_NF_NAT_SIP=m,我们就知道了nf_nat_sip.c才是当前使用的代码文件。

 

四、SIP ALG的代码文件及模块作用。

这里以5358产品为例,有些产品的内核ALG代码略有差别(如6828

1、目前5358产品和SIP ALG最直接相关的源码为

kernel/linux/net/netfilter/nf_conntrack_sip.c

kernel/linux/net/ipv4/netfilter/nf_nat_sip.c

kernel/linux/net/ipv4/netfilter/broadcom/nf_conntrack_rtp.c

 

2、上面源码正好对应编译出来的三个内核模块nf_conntrack_sipnf_nat_sipnf_conntrack_rtp

 

nf_conntrack_sip模块是主sip_help实现的模块,向NF框架注册连接跟踪helper助手。负责sip相关报文的期望连接预处理,并调用nf_nat_sip模块设置的几个关键回调函数接口进行sip报文转换,期望连接的回调设置等处理。

 

nf_nat_sip模块包含了几个关键函数实现,并在模块初始化时,将nf_conntrack_sip中几个函数指针指向该模块的几个关键函数,辅助sip_help进行报文转换处理,及期望连接设置。

 

nf_conntrack_rtp模块向NF注册了钩子回调,主要负责经过IP_FORWARD链的RTP报文设置DSCP及为数据报文打标签,辅助策略路由。

 

五、ALG学习进阶

虽然SIP ALG直接相关的源码量比较少,但如果真正做到理解ALG实现得需要涉及netfilter机制实现,需要分析netfilter框架源码,因为ALG仅仅是netfilter框架中连接跟踪模块的一个助手钩子。如果真正做到ALG代码修改实战,解决任何ALG问题,就要学习整个Linux的网络实现。

1、  查看iptables相关手册,理解一些基本的iptables使用方法,重点了解怎样通过iptables规则实现NAT上网,及DMZ的设置。

2、  查找相关资料,了解netfilter框架,重点学习如何向netfilter框架注册自己的钩子处理函数,以及netfilter框架中各模块的优先级调用。因为netfilter中各模块(如conntracknat等)就是注册到netfilter框架中的钩子处理函数,并通过不同优先级来进行调用处理。

3、  查找相关资料,了解连接跟踪模块机制,重点理解连接跟踪的作用,及期望连接机制,这个是重点的重点。

4、  查找相关资料,了解NAT模块机制,由于NAT模块涉及到iptables表规则的查找及处理,

Netfilter开发者为了在这方面高效处理,里面含有一定的技巧实现,如果要理解这些技巧实现,建议一定要看一下iptables相关手册,并且看一下iptables应用程序实现代码,这样结合来看NAT模块才比较容易理解一些。

5、  待上面那些方面的知识都了解一些后,后面在进行ALG代码的学习就轻松多了,这时候

就需要了解一下SIP协议中和收发包相关的几个关键头域,然后接合之前所了解的知识,

从数据报进出netfilter各关键钩子模块处理,最后怎么调到sip_help代码,在sip_help

代码中又是怎么处理sip报文修改、怎么建立期望连接,这些建立的期望连接最终又是在什么场景下被触发的。

6、  系统学习LINUX整个网络子模块,因为从上面介绍可以了解到,netfilter框架在强大,它仅仅是数据包在整个LINUX网络子模块中关键走向点的地方设置的钩子回调函数,真正复杂的是LINUX整体网络子模块实现,学习上面5点只能做到理解了ALG基本原理,

但在实践中要解决一些复杂的ALG问题,还是远远不够的。(我还没到这个层次,还差很远)。

 

六、ALG基本原理

鉴于我当前对ALG的代码也没有很深入了解,还不能做到对整体代码实现进行单行注解,要学的东西还有很多,以后有机会再说吧,这节介绍内容跳过了一部分netfilter实现的细节,只是做一个引子,让大家了解一个ALG大体实现,后面想对整体细节了解需要去看我上面提供的学习进阶建议。

 

注册

不管是应用层ALG,还是内核ALG,注册的过程一定不能少,通过注册过程,LANSIP设备可以在ALG上创建一个对外的连接,这样才能保证外部设备从WAN侧呼入时,可以顺着这条连接将数据报转到对应的LANSIP设备。所以在和测试同事跟进ALG问题时,一定要提醒他们,如果WEB页面上有ALG的开关,将ALG开启后,LAN侧的SIP设备一定要重新通过ALG进行一次SIP注册。

 

1LAN侧发出注册包

A、 LAN侧设备A发起注册包后,ALG接收到此数据报,该数据报首先经过CONNTRACK模块在PRE_ROUTING链中PRI_CONNTRACK优先级设置的回调函数,建立一条连接跟踪(图中那两条黑色的实线),该连接跟踪有两个元组(代码里叫做tuple),一个元组是LAN侧设备到ALG,一个元组是ALGWAN侧,此时,LAN侧的元组会记载LAN侧设备A的地址信息(如SRC=192.168.1.123:12345),和数据包的目的地址(如DST=172.24.242.251:5060),并将此信息进行反向填入到WAN侧的元组中,即WAN侧元组的信息为(SRC=172.24.242.251:5060DST=192.168.1.123:12345)。

之后会查找是否有匹配的conntrack_helper,我们的nf_conntrack_sip模块在初始化时,向NF框架已经注册了一个目地端口为5060sip_helper,所以当数据报的目地端口为5060时,就找到了这个conntrack_helper,将sip_helper加入到当前新建的连接跟踪数据成员中。

B、 数据报经过NAT模块在POST_ROUTING链中PRI_NAT_SRC优先级设置的回调函数,由于我们之前在WEB页面建立的WAN侧连接开启了NAT选项,所以会有一条NAT地址转换的规则(如当前5358POSTROUTING链中可以看到有一条“MASQUERADE  all  --  xxxxxx  anywhere”),此时NAT模块会根据iptables设置的规则将当前数据报中ip头的源地址修改为ALG自身WAN口的公网地址。并更新连接跟踪WAN侧元组信息,由原来的“SRC=172.24.242.251:5060DSP=192.168.1.123:12345”更新为“SRC=172.24.242.2515060DSP=WANIP:12345”。

C、 数据报经过CONNTRACK模块在POST_ROUTING链中PRI_CONNTRACK_HELPER优先级设置的回调函数,该回调函数触发之前这条连接跟踪记载的sip_helpersip_helper主要对数据报中SIP一些地址相关头域进行修改(如把VIA头域中LAN侧设备A地址替换成ALG自身WAN侧地址),从这里可以了解到,NAT模块只是处理数据报中IP头的地址转换,而数据报内容中的地址信息转换则需要借助各种conntrack_helper来完成(如sip_helperftp_helper等),sip_helper除了完成SIP报文中地址信息转换,还建立了一条与当前连接跟踪相关联的信令期望连接(图中黑色的虚线),理解期望连接的机制很关键,目前在SoftX3000环境下出现的ALG BUG基本都会和期望连接打交道,期望连接的细节实现大家最好还是看一下我上面学习进阶里提出的,这里只要明白一点,期望连接是用来处理在特殊情况下WAN侧发来的数据报,辅助此数据报成功建立一新的连接跟踪,并使用期望连接里之前设置的特定期望连接处理回调,完成当前当前报文的目的地址改变,使该数据报即使在特殊情况下,也可以正确转发到LAN侧指定设备上。

D、 数据报经过CONNTRACK模块在POST_ROUTING链中CONNTRACK_CONFIRM优先级设置的回调函数,完成最终连接跟踪的生成,此时会将这条连接跟踪加入到连接跟踪表中。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第1张图片

2、服务器回应200 OK

A、当ALG收到WAN侧数据报后,该数据报首先经过CONNTRACK模块在PRE_ROUTING链中PRI_CONNTRACK优先级设置的回调函数,查找当前数据报(SRC=172.24.242.2515060DSP= WANIP:12345)是否有对应的连接跟踪,之前注册报文在经过NAT转换后,那条连接跟踪在WAN侧的元组信息正好是SRC=172.24.242.2515060DSP=WANIP:12345,所以该应答数据报成功匹配这条连接跟踪。在下图中,我将连接跟踪的实线画成了双向箭头,仅仅是表示这条连接跟踪,有了对端的信息,我们认为此连接跟踪已经连接成功了。

B、数据报经过NAT模块在PRE_ROUTING链中PRI_NAT_DST优先级设置的回调函数(注意:最开始LAN侧设备发注册请求也经过此回调,只是那时候还不涉及所关心的代码,所以我就跳过去了,建议大家一定要理解我在学习进阶中提到的不同模块不同优先级对应钩子回调的顺序),因为此时该连接跟踪之前已经进行过NAT转换处理,会设置对应的标记来表示,这时候NAT模块就不需要在去查iptables相关的规则表了(这也是netfilter机制高效的一个地方),只需要根据之前转换信息对应处理就可以完成IP头地址信息转换,在转换处理的代码流程中有一特别的地方,之前LAN侧到WAN侧的包只是做了源地址转换,此时WAN侧到LAN侧的包,我们应该需要做目的地址转换,也就是想将服务器侧发到ALG自身WAN侧的地址,改为发向对应的LAN侧设备地址,这里有一个技巧,每一条连接跟踪在建立时,两个元组都会记载当前连接方向,如我们之前注册请求是从LAN侧发出的,所以LAN侧那个元组就是这条连接跟踪的请求方,而WAN侧那个元组就是这条连接跟踪的应答方,由于连接跟踪建立后,在正常处理过程中是不会改变的,所以此连接跟踪的请求方和应答方就一直不变了。如果之前是记载的转换信息是从此连接跟踪的请求方向处理的,进行了源地址转换,那么,当来的数据包匹配此连接跟踪的应答方元组信息时,会反向做目的地址转换,之前是将源地址192.168.1.123:12345转换为WANIP:12345,现在将目的地址WANIP:12345转换为192.168.1.123:12345

C、数据报经过CONNTRACK模块在POST_ROUTING链中PRI_CONNTRACK_HELPER优先级设置的回调函数,该回调函数调用sip_helper,仅仅是完成一些SIP报文中相关目的地址信息的转换(比如将VIA头域地址ALG自身WANIP改为对应LAN侧设备AIP)。这里不需要做源地址做处理,因为当前包是从WAN过来的,所以源码址不需要关心。

 

OKLAN侧设备已经完成通过ALG的注册处理。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第2张图片

呼叫

这里只介绍一个终端情况下,终端主叫呼叫流程,并且简化SIP信令,只提关键的两个信令处理,一个是客户端发出INVITE with SDP,一个是服务器回应200 with SDP

 

1LAN侧设备A发送INVITE with SDP

A、当ALG收到LAN侧数据报后,该数据报首先经过CONNTRACK模块在PRE_ROUTING链中PRI_CONNTRACK优先级设置的回调函数,查找当前数据报(SRC=192.168.1.123:12345DSP= 172.24.242.251:5060)是否有对应的连接跟踪,之前注册报文已经建立连接跟踪,该数据报正好匹配这条连接跟踪的请求方向元组信息。

B、数据报经过NAT模块在POST_ROUTING链中PRI_NAT_SRC优先级设置的回调函数,因为此时该连接跟踪之前已经进行过NAT转换处理,会设置对应的标记来表示,所以同之前注册应答处理方法一样, NAT模块就不需要在去查iptables相关的规则表了,直接根据之前转换信息对应处理就可以完成IP头地址信息转换,因为此时LAN侧的数据包匹配此连接跟踪的请求方向信息元组,所以同之前注册请求的方向相同,直接按注册请求处理时的NAT转换信息进行源地址转换。

C、数据报经过CONNTRACK模块在POST_ROUTING链中PRI_CONNTRACK_HELPER优先级设置的回调函数,该回调函数调用sip_helpersip_helper除了对SIP报文中一些地址相关头域进行转换以外,还会对SDP中的媒体地址进行转换。并检测之前注册时的信令相关的期望连接是否还存在(就是图中黑色虚线),如果存在则刷新超时时间,如果不存在则新建一条和之前注册一样的期望连接。这里还会创建2条媒体相关的期望连接(RTPRTCP各一条,我在图中只画了1条黄色的虚线,表示是RTP的期望连接,下文描述媒体时只描述RTP的处理)。

 

2、服务器回应 200 with SDP

A、当ALG收到WAN侧数据报后,该数据报首先经过CONNTRACK模块在PRE_ROUTING链中PRI_CONNTRACK优先级设置的回调函数,查找当前数据报(SRC=172.24.242.2515060DSP= WANIP:12345)是否有对应的连接跟踪,之前注册报文在经过NAT转换后,那条连接跟踪在WAN侧的元组信息正好是SRC=172.24.242.2515060DSP=WANIP:12345,所以该应答数据报成功匹配这条连接跟踪。

B、数据报经过NAT模块在PRE_ROUTING链中PRI_NAT_DST优先级设置的回调函数,NAT模块根据之前记载的转换信息直接进行目标地址转换。

C、数据报经过CONNTRACK模块在POST_ROUTING链中PRI_CONNTRACK_HELPER优先级设置的回调函数,该回调函数调用sip_helpersip_helper仅仅完成一些SIP报文中相关目的地址信息的转换(比如将VIA头域地址ALG自身WANIP改为对应LAN侧设备AIP)。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第3张图片

媒体

因为媒体数据报并不像信令数据报那样,报文内容不含有地址信息,所以媒体处理只需要考虑连接跟踪正常,NAT模块正常就可以了,在必要情况下还需要考虑期望连接是否正确建立。

这里以常见的两种WAN侧媒体处理场景来讲述媒体处理,不会涉及netfilter框架太细节的东西,只点到基本实现。

(还有一种媒体场景,LAN侧有两个SIP设备,当两个LANSIP设备进行媒体处理时,也用到了媒体期望连接,这里就不描述这种场景的处理流程了,如果之前学习进阶的东西理解的差不多了,这种场景媒体处理流程你会很快理解的)

 

1、  LAN侧设备A先发出媒体数据报

A、当LAN侧设备A先发出RTP数据报时,整个流程同最初讲的SIP注册流程类似,它在CONNTRACK模块创建一条媒体的连接跟踪(见下图中黄色实线),然后通过NAT模块中地址转换规则,完成RTP的源地址转换,最后将RTP包发送出去。RTP数据报不需要修改内部报文信息,所以也没有相关的helper助手处理流程。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第4张图片

B、之后收到WAN侧发送的媒体数据报后,同之前注册应答处理类似,CONNTRACK模块中首先找到了匹配的连接跟踪,后面NAT模块通过之前记载的转换信息直接进行目标地址转换。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第5张图片

C、之后双向的RTP处理同信令过程类似,就不再描述了。

 

2、  WAN侧设备先发出媒体数据报

之前看到,如果LAN侧设备A做主叫方,在发出INVITE后,ALG创建了RTP的期望连接(图中黄色虚线),但一直没有使用,当WAN侧设备先出媒体数据报时,就使用了此期望连接。

 

AWAN侧发来RTP数据报时,CONNTRACK模块首先查找连接跟踪,但此时连接跟踪表中并没有可以匹配到的连接跟踪,则创建一条媒体连接跟踪,同时去查期望连接表,假设之前INVITE创建的RTP期望连接目的端口为10000,从WAN侧发来的RTP数据报目的端口是10000,则在期望连接表中找到了之前创建的RTP期望连接,此时调用期望连接之前设置的期望连接回调函数。该期望连接回调函数完成NAT模块类似功能,将RTP数据报的目的地址由到ALG自身WANIP改为到LAN侧设备AIP。同时修正新建的媒体连接跟踪的LAN侧元组信息。最后将期望连接从期望连接表中删除,期望连接已经帮忙顺利完成从WAN侧方向发来数据报的连接跟踪创建,使命已经完成,之后就被删除了。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第6张图片 

 

B、之后在从LAN侧设备A发来RTP数据报时,是可以匹配到这条新创建的连接跟踪的,处理流程同之前讲解的类似,直接通过记载的转换信息进行源地址转换。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第7张图片

信令期望连接的应用场景

前面讲解中,始终没有提到之前创建的信令期望连接(图中黑色虚线)在哪种场景中使用,这里讲解一下这个应用场景。

 

该应用场景目前在SoftX3000上可以看到,通过抓信令包可以分析到,我们LAN侧设备A之前向SoftX30005060端口进行注册,之后如果这台设备做被叫,SoftX3000做主叫(即有其它设备通过SoftX3000呼叫当前LAN侧设备A),这时候SoftX3000确使用了源端口为5061LAN侧设备A发起INVITE呼叫,由于此端口与之前LAN侧设备注册时的目标端口(5060)不一致,导致这个WAN侧来的报文在连接跟踪表中是找不到可用的连接跟踪的,这时候就要借助之前创建的信令期望连接重新创建一条连接跟踪,之后LAN侧设备ASoftX30005061端口交互的数据报都可以通过这个新的连接跟踪来处理。

后期LAN侧设备A做主叫时,发向目标端口为5060的数据包还是使用之前的连接跟踪来处理。

 

1WAN侧从不同源端口发来INVITE with SDP

AWAN侧从源端口5061发来INVITE数据报时,CONNTRACK模块首先查找连接跟踪,但此时连接跟踪表中并没有可以匹配到的连接跟踪(因为那黑色实线的连接跟踪WAN侧元组信息的源端口是5060,所以匹配不上),则创建一条新的连接跟踪(图中绿色实线),同时去查期望连接表,因为当前从SoftX3000发来的数据包的目的地址和期望连接的目的地址匹配,所以在期望连接表中找到了之前创建的期望连接,此时调用期望连接之前设置的期望连接回调函数。该期望连接回调函数完成NAT模块类似功能,将INVITE数据报的目的地址由到ALG自身WANIP改为到LAN侧设备AIP。同时修正新建的连接跟踪的LAN侧元组信息。

之后将该期望连接关联的主连接跟踪(图中黑色实线)的helper助手设置到新建的连接跟踪(图中绿色实线)上。最后将期望连接从期望连接表中删除。

B、数据报经过CONNTRACK模块在POST_ROUTING链中PRI_CONNTRACK_HELPER优先级设置的回调函数,该回调函数调用sip_helper,完成SIP数据报中目的地址相关信息的转换。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第8张图片

2LAN侧设备A回应200 with SDP

这里不再很详细的描述,基本和上面的一些机制都差不多了,LAN侧在回应200时,目的端口为5061,所以匹配了新建的连接跟踪(图中绿色实线),之后借用之前存储的地址转换信息完成IP头的源地址转换,之后通过sip_helper完成SIP报文中源地址相关信息的转换。最后建立了两条媒体期望连接(图中只画了一条黄色的RTP期望连接),用于后续媒体处理。

内核SIP ALG学习指引和基本实现原理(分析BCM方案实现)_第9张图片

你可能感兴趣的:(Sip,ALG)