-
Notifications
You must be signed in to change notification settings - Fork 909
/
kamailio-basic-kemi-ruby.rb
330 lines (281 loc) · 7.72 KB
/
kamailio-basic-kemi-ruby.rb
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
## Kamailio - equivalent of routing blocks in Ruby
##
## KSR - the new dynamic object exporting Kamailio functions
## Relevant remarks:
## KSR.x.exit() is not exported in ruby as per KEMI docs, so we use native exit
## Module names are capitalised and referenced with double colons - e.g. it's KSR::HDR.append instead of KSR.hdr.append in other KEMI languages
## Global variables corresponding to defined values (e.g., flags) in kamailio.cfg
$FLT_ACC = 1
$FLT_ACCMISSED = 2
$FLT_ACCFAILED = 3
$FLT_NATS = 5
$FLB_NATB = 6
$FLB_NATSIPPING = 7
def ksr_request_route()
# Per request initial checks
ksr_route_reqinit()
ksr_route_natdetect()
if KSR.is_CANCEL() then
if KSR::TM.t_check_trans() > 0 then
ksr_route_relay()
end
return
end
# Retransmissions
if !KSR.is_ACK() then
if KSR::TMX.t_precheck_trans() > 0 then
KSR::TM.t_check_trans()
return
end
return if KSR::TM.t_check_trans() == 0
end
# Handle requests within SIP dialogs
ksr_route_withindlg()
# -- only initial requests (no To tag)
# Authentication
ksr_route_auth()
# Record routing for dialog forming requests (in case they are routed)
KSR::HDR.remove("Route")
if KSR.is_method_in("IS") then
KSR::RR.record_route()
end
KSR.setflag($FLT_ACC) if KSR.is_INVITE()
# Dispatch to external
ksr_route_sipout()
# Registrations
ksr_route_registrar()
if KSR::COREX.has_ruri_user() < 0 then
# request with no Username in RURI
KSR::SL.sl_send_reply(484, "Address Incomplete");
return;
end
# User location service
ksr_route_location()
return
end
def ksr_route_relay()
if KSR.is_method_in("IBSU") then
if KSR::TM.t_is_set("branch_route") < 0 then
KSR::TM.t_on_branch("ksr_branch_manage")
end
end
if KSR.is_method_in("ISU") then
if KSR::TM.t_is_set("onreply_route") < 0 then
KSR::TM.t_on_reply("ksr_onreply_manage")
end
end
if KSR.is_INVITE() then
if KSR::TM.t_is_set("failure_route") < 0 then
KSR::TM.t_on_failure("ksr_failure_manage")
end
end
if KSR::TM.t_relay() < 0 then
KSR::SL.sl_reply_error()
end
exit
end
def ksr_route_reqinit()
# no connect for sending replies
KSR.set_reply_no_connect();
# enforce symmetric signaling
# send back replies to the source address of request
KSR.force_rport();
if !KSR.is_myself_srcip() then
srcip = KSR::KX.get_srcip();
if KSR::HTABLE.sht_match_name("ipban", "eq", srcip) > 0 then
# ip is already blocked
KSR.dbg("request from blocked IP - " + KSR::KX.get_method() +
" from " + KSR::KX.get_furi() + " (IP:" +
srcip + ":" + KSR::KX.get_srcport() + ")\n");
exit;
end
if KSR::PIKE.pike_check_req() < 0 then
KSR.err("ALERT: pike blocking " + KSR.kx.get_method() +
" from " + KSR::KX.get_furi() + " (IP:" +
srcip + ":" + KSR.kx.get_srcport() + ")\n");
KSR::HTABLE.sht_seti("ipban", srcip, 1);
exit;
end
end
if KSR::COREX.has_user_agent() > 0 then
ua = KSR::PV.gete("$ua");
if ua.include? 'friendly' or ua.include? 'scanner' or
ua.include? 'sipcli' or ua.include? 'sipvicious' or
ua.include? 'VaxSIPUserAgent' or ua.include? 'pplsip' then
KSR::SL.sl_send_reply(200, "OK");
exit
end
end
if KSR::MAXFWD.process_maxfwd(10) < 0 then
KSR::SL.sl_send_reply(483, "Too Many Hops");
exit
end
if KSR.is_OPTIONS() and KSR.is_myself_ruri() and KSR::COREX.has_ruri_user() < 0 then
KSR::SL.sl_send_reply(200, "Keepalive");
exit
end
if KSR::SANITY.sanity_check(17895, 7) < 0 then
KSR.err("Malformed SIP message from #{KSR::PV.get('$si')}:#{KSR::PV.get('$sp')}\n");
exit
end
end
def ksr_route_withindlg()
return if KSR::SIPUTILS.has_totag() < 0
if KSR::RR.loose_route() > 0 then
ksr_route_dlguri()
if KSR.is_BYE() then
KSR.setflag($FLT_ACC)
KSR.setflag($FLT_ACCFAILED)
elsif KSR.is_ACK() then
ksr_route_natmanage()
elsif KSR.is_NOTIFY() then
KSR::RR.record_route()
end
ksr_route_relay()
exit
end
if KSR.is_ACK() then
if KSR::TM.t_check_trans() > 0 then
ksr_route_relay()
exit
else
exit
end
end
#KSR.info("404ing within dialog")
KSR::SL.sl_send_reply(404, "Not here");
exit
end
# IP authorization and user authenticaton
def ksr_route_auth()
if !KSR.is_REGISTER() then
# source IP allowed
return if KSR::PERMISSIONS.allow_source_address(1).to_i > 0
end
if KSR.is_REGISTER() or KSR.is_myself_furi() then
# auth requests
if KSR::AUTH_DB.auth_check(KSR::PV.get("$fd"), "subscriber", 1).to_i < 0 then
KSR::AUTH.auth_challenge(KSR::PV.get("$fd"), 0)
exit
end
# user authenticated - remove auth header
KSR::AUTH.consume_credentials() if !KSR.is_method_in("RP")
end
# if caller is not local subscriber, then check if it calls
# a local destination, otherwise deny, not an open relay here
if !KSR.is_myself_furi() && !KSR.is_myself_ruri() then
KSR::SL.sl_send_reply(403, "Not relaying")
exit
end
return
end
def ksr_route_natdetect()
KSR.force_rport()
if KSR::NATHELPER.nat_uac_test(19) > 0 then
if KSR.is_REGISTER() then
KSR::NATHELPER.fix_nated_register()
elsif KSR::SIPUTILS.is_first_hop() > 0 then
KSR::NATHELPER.set_contact_alias()
end
KSR.setflag($FLT_NATS)
end
return
end
def ksr_route_natmanage()
if KSR::SIPUTILS.is_request() > 0 then
if KSR::SIPUTILS.has_totag() > 0 then
if KSR::RR.check_route_param("nat=yes") > 0 then
KSR.info("Natmanage - nat=yes")
KSR.setbflag($FLB_NATB)
end
end
end
#KSR.info("Natmange - returning if NAT flags set")
return if !KSR.isflagset($FLT_NATS) and !KSR.isbflagset($FLB_NATB)
#KSR.info("Natmanage - RTPPROXY from here on")
KSR::RTPPROXY::RTPPROXY_manage("co");
if KSR::SIPUTILS.is_request() > 0 then
if !KSR::SIPUTILS.has_totag() then
if KSR::TMX.t_is_branch_route() > 0 then
KSR::RR.add_rr_param(";nat=yes")
end
end
end
if KSR::SIPUTILS.is_reply() > 0 then
if KSR.isbflagset($FLB_NATB) then
KSR::NATHELPER.set_contact_alias()
end
end
return
end
def ksr_route_dlguri()
KSR::NATHELPER.handle_ruri_alias() if !KSR.isdsturiset()
return
end
def ksr_branch_manage()
KSR.dbg("new branch [#{KSR::PV.get("$T_branch_idx")}] to #{KSR::PV.get("$ru")}\n")
ksr_route_natmanage()
return
end
def ksr_onreply_manage()
scode = KSR::PV.get("$rs");
KSR.dbg("Reply status code is #{scode}")
ksr_route_natmanage() if scode > 100 and scode <= 299
return
end
def ksr_reply_route()
#scode = KSR::PV.get("$rs");
return
end
def ksr_onsend_route()
return
end
def ksr_failure_manage()
ksr_route_natmanage()
return if KSR::TM.t_is_canceled() > 0
return
end
def ksr_dialog_event(evname)
KSR.info("===== dialog module triggered event: #{evname}");
return
end
def ksr_tm_event(evname)
KSR.info("===== TM module triggered event: #{evname}");
return
end
def ksr_route_sipout()
return if KSR.is_myself_ruri()
KSR::HDR.append("P-Hint: outbound\r\n")
ksr_route_relay()
exit
end
def ksr_route_registrar()
return if !KSR.is_REGISTER()
if KSR.isflagset($FLT_NATS) then
KSR.setbflag($FLB_NATB)
# do SIP NAT pinging
KSR.setbflag($FLB_NATSIPPING)
end
KSR.info("saving loc")
if KSR::REGISTRAR.save("location", 0).to_i < 0 then
KSR::SL.sl_reply_error()
end
exit
end
def ksr_route_location()
rc = KSR::REGISTRAR.lookup("location").to_i
if rc < 0 then
KSR::TM.t_newtran()
if rc == -1 or rc == -3 then
KSR::SL.sl_send_reply(404, "Not Found")
exit
elsif rc == -2 then
KSR::SL.sl_send_reply(405, "Method Not Allowed")
exit
end
end
# when routing via usrloc, log the missed calls also
KSR.setflag($FLT_ACCMISSED) if KSR.is_INVITE()
ksr_route_relay()
exit
end