Featured image of post kamailio websocket(s)介绍

kamailio websocket(s)介绍

websocket模块依赖

websocket是http协议的升级,所以kamailio需要xhttp模块, websockets需要tls模块。 在编译kamailio时,需要把xhttp和tls模块库编译进去。

官方文档地址: websocket模块

本次测试的kamailio版本是:

version: kamailio 5.8.5 (x86_64/linux)

websocket 配置参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 保活机制: 0,不保活;1,ping;2,pong, 默认: 1
modparam("websocket", "keepalive_mechanism", 0)

# 多长时间发送一个保活信息到空闲的websockt连接: 默认: 180,单位:秒
modparam("websocket", "keepalive_timeout", 180)

# 处理websocket 保活信息的进程数: 默认: 1
modparam("websocket", "keepalive_processes", 2)

# 多个处理保活进程运行的时间间隔: 默认: 1,单位:秒
modparam("websocket", "keepalive_interval", 2)

# ping/pong 应用程序数据: 默认: "header content"
modparam("websocket", "ping_application_data", "WebSockets rock")

# 支持的通过websocket发送的数据协议, 1,sip;2,msrp,默认1
modparam("websocket", "sub_protocols", 1)

# 配置跨域,0,不添加;1,添加"Access-Control-Allow-Origin: *";2,添加"Access-Control-Allow-Origin:"值为请求的"Origin";
modparam("websocket", "cors_mode", 2)

#是否打印websocket连接列表,默认0(不打印)
modparam("websocket", "verbose_list", 1)

# 每个时间处理进程运行间隔,默认1,单位秒
modparam("websocket", "timer_interval", 5)

# 待删除的连接多久之后开始删除,默认5,单位秒
modparam("websocket", "rm_delay_interval", 2)

websocket 实战

场景一(websocket注册到kamailio)

配置参考

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!define WITH_MYSQL
#!define WITH_USRLOCDB
#!define WITH_NAT
#!define WITH_RTPENGINE
#!define WITH_JSONRPC

log_prefix="|$timef(%y-%m-%d %H:%M:%S)|$ci| "
listen=udp:172.16.4.111:5460
listen=udp:172.16.4.111:5461
listen=tcp:172.16.4.111:5461

#!ifdef WITH_MYSQL
loadmodule "db_mysql.so"
#!endif

#!ifdef WITH_JSONRPC
loadmodule "xhttp.so"
#!endif

#!ifdef WITH_NAT
loadmodule "nathelper.so"
#!ifdef WITH_RTPENGINE
loadmodule "rtpengine.so"
#!else
loadmodule "rtpproxy.so"
#!endif
#!endif


loadmodule "dialog.so"
modparam("dialog", "enable_stats", 1)

loadmodule "websocket.so"
modparam("websocket", "keepalive_mechanism", 1)
modparam("websocket", "keepalive_timeout", 30)
modparam("websocket", "keepalive_processes", 2)
modparam("websocket", "keepalive_interval", 2)
modparam("websocket", "ping_application_data", "WebSockets rock")




# ----- jsonrpcs params -----
modparam("jsonrpcs", "pretty_format", 1)
/* set the path to RPC fifo control file */
#modparam("jsonrpcs", "fifo_name", "/run/kamailio/kamailio_rpc.fifo")
#modparam("jsonrpcs", "fifo_mode", 0660)
#modparam("jsonrpcs", "fifo_group", "root")
#modparam("jsonrpcs", "fifo_user", "root")

/* set the path to RPC unix socket control file */
# modparam("jsonrpcs", "dgram_socket", "/run/kamailio/kamailio_rpc.sock")
#!ifdef WITH_JSONRPC
modparam("jsonrpcs", "transport", 7)
#!endif

# ----- ctl params -----
/* set the path to RPC unix socket control file */
# modparam("ctl", "binrpc", "unix:/run/kamailio/kamailio_ctl")

# ----- sanity params -----
modparam("sanity", "autodrop", 0)

# ----- tm params -----
# auto-discard branches from previous serial forking leg
modparam("tm", "failure_reply_mode", 3)
# default retransmission timeout: 30sec
modparam("tm", "fr_timer", 30000)
# default invite retransmission timeout after 1xx: 120sec
modparam("tm", "fr_inv_timer", 120000)

# ----- rr params -----
# set next param to 1 to add value to ;lr param (helps with some UAs)
modparam("rr", "enable_full_lr", 0)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)

# ----- registrar params -----
modparam("registrar", "method_filtering", 1)
/* uncomment the next line to disable parallel forking via location */
# modparam("registrar", "append_branches", 0)
/* uncomment the next line not to allow more than 10 contacts per AOR */
# modparam("registrar", "max_contacts", 10)
/* max value for expires of registrations */
modparam("registrar", "max_expires", 3600)
/* set it to 1 to enable GRUU */
modparam("registrar", "gruu_enabled", 0)
/* set it to 0 to disable Path handling */
modparam("registrar", "use_path", 1)
/* save Path even if not listed in Supported header */
modparam("registrar", "path_mode", 0)



# ----- usrloc params -----
modparam("usrloc", "timer_interval", 60)
modparam("usrloc", "timer_procs", 1)
modparam("usrloc", "use_domain", MULTIDOMAIN)
/* enable DB persistency for location entries */
#!ifdef WITH_USRLOCDB
modparam("usrloc", "db_url", DBURL)
modparam("usrloc", "db_mode", 0)
modparam("usrloc", "hash_size", 12)

#!endif


#!ifdef WITH_NAT
#!ifdef WITH_RTPENGINE
# ----- rtpengine params -----
modparam("rtpengine", "rtpengine_sock", "udp:172.16.4.111:2222")
#!else
# ----- rtpproxy params -----
modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:7722")
#!endif
# ----- nathelper params -----
modparam("nathelper", "natping_interval", 30)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
modparam("nathelper", "sipping_from", "sip:pinger@kamailio.org")

# params needed for NAT traversal in other modules
modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")
modparam("usrloc", "nat_bflag", FLB_NATB)
#!endif

...

# JSONRPC over HTTP(S) routing
#!ifdef WITH_JSONRPC
event_route[xhttp:request] {
        set_reply_close();
        set_reply_no_connect();
        #if(src_ip!=127.0.0.1) {
        #       xhttp_reply("403", "Forbidden", "text/html",
        #                       "<html><body>Not allowed from $si</body></html>");
        #       exit;
        #}
        #if ($hu =~ "^/RPC") {
        #       jsonrpc_dispatch();
        #       exit;
        #}
        if ($hdr(Upgrade)=~"websocket"
                        && $hdr(Connection)=~"Upgrade"
                        && $rm=~"GET") {

                # Validate Host - make sure the client is using the correct
                # alias for WebSockets
                if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) {
                        xlog("L_WARN", "Bad host $hdr(Host)\n");
                        xhttp_reply("403", "Forbidden", "", "");
                        exit;
                }

                # Optional... validate Origin - make sure the client is from an
                # authorised website.  For example,
                #
                # if ($hdr(Origin) != "http://communicator.MY_DOMAIN"
                #     && $hdr(Origin) != "https://communicator.MY_DOMAIN") {
                #       xlog("L_WARN", "Unauthorised client $hdr(Origin)\n");
                #       xhttp_reply("403", "Forbidden", "", "");
                #       exit;
                # }

                # Optional... perform HTTP authentication

                # ws_handle_handshake() exits (no further configuration file
                # processing of the request) when complete in case of failure.
                if (ws_handle_handshake())
                {
                        # Optional... cache some information about the
                        # successful connection
                        xlog("L_INFO", "------------------ successful websocket connection \n");
                        exit;
                }
        }       
        
        xlog("receive http request:\n");
        xhttp_reply("200", "OK", "text/html",
                                "<html><body>Wrong URL $hu</body></html>");

        exit;
}
#!endif

只需要监听一个tcp端口,加载websockets.so, 然后在event_route[xhttp:request]route中添加如上代码即可.

只是注册的话, 就可以不需要配置rtpengine了。

注册

客户端使用JsSip,用户名密码随便填,注册到ws://172.16.4.111:5461上,就能收到相关的注册成功信息了. register

场景二(websocket注册到kamailio 然后转到sip服务器)

如何想转到第三方的sip服务器比如freeswitch,可以参考我之前的文章kamailio关于registrar的介绍。 用户名和密码使用1000~1020之间的,密码1234.

  1. tcp配置方式
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
route[REGISTRAR] {
        if (!is_method("REGISTER")) return;

        if(isflagset(FLT_NATS)) {
                setbflag(FLB_NATB);
#!ifdef WITH_NATSIPPING
                # do SIP NAT pinging
                setbflag(FLB_NATSIPPING);
#!endif
        }
        if (!save("location","0x02")) {
                sl_reply_error();
        }
        $fs="tcp:172.16.4.111:5460";
        $du="sip:172.16.4.114:5060;transport=tcp";
        route(RELAY);
        exit;
}

$fs是kamailio转发请求使用的端口,$du是fs的地址, 配置转发使用的tcp,5460端口就没用了,使用的是随机端口. register

  1. udp配置方式
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
route[REGISTRAR] {
        if (!is_method("REGISTER")) return;

        if(isflagset(FLT_NATS)) {
                setbflag(FLB_NATB);
#!ifdef WITH_NATSIPPING
                # do SIP NAT pinging
                setbflag(FLB_NATSIPPING);
#!endif
        }
        if (!save("location","0x02")) {
                sl_reply_error();
        }
        $fs="udp:172.16.4.111:5460";
        $du="sip:172.16.4.114:5060";
        route(RELAY);
        exit;
}

具体的sip交互图为: register

转发使用udptcp的区别是,转发相当于kamailio是客户端,所以udp必须提前listen, tcp则不需要提前listen,其发送端口是按照系统随机端口区间使用的。

websockets 配置参数

在websocket的配置基础上,定义WITH_TLS,然后监听tls的端口,配置证书

1
2
3
4
5
6
7
8
9
#!define WITH_TLS
alias="服务域名"
listen=tls:172.16.4.113:5462
log_prefix="|$timef(%y-%m-%d %H:%M:%S)|$ci| "

#!ifdef WITH_TLS
# ----- tls params -----
modparam("tls", "config", "/usr/local/etc/kamailio/tls.cfg")
#!endif

打开tls.cfg文件,可以看到一下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[server:default]
method = TLSv1.2+
verify_certificate = no
require_certificate = no
private_key = /usr/local/etc/kamailio/域名.key
certificate = /usr/local/etc/kamailio/域名.pem
#ca_list = /usr/local/etc/kamailio/tls/cacert.pem
#crl = /usr/local/etc/kamailio/tls/crl.pem

[client:default]
#method = TLSv1.2+
verify_certificate = yes
require_certificate = yes

private_key配置nginx证书的私钥.key文件

certificat配置nginx证书的公钥.pem文件

verify_certificaterequire_certificate是验证证书和要求证书功能

  • server:

    配置成yes, 浏览器在访问服务端的wss://172.16.4.113:5462时,需要配置证书,虽然安全,但是比较麻烦,所以一般配置成no

  • client:

    配置成yes, 要求服务端要配置证书,然后客户端验证. 所以一般配制成yes.

websockets 实战

注册转发

使用上面的websocket的注册转发udp的方式,再加上wss的配置,得到的信令图为: register

由于wss是加密的,所以sngrep无法查看,只有转发的部分,可以在request_route里添加日志:

1
xlog("L_INFO","$si:$sp|$Ri:$Rp|$pr|$rm\n");

打印了协议类型,这样可以在日志中看到wss请求过来了。

本博客已稳定运行
发表了26篇文章 · 总计45.09k字
本站总访问量 次 · 您是本站第 位访问者
粤ICP备2025368587号-1| 使用 Hugo 构建
主题 StackJimmy 设计