forked from kamailio/kamailio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsip-router.cfg
618 lines (523 loc) · 17.2 KB
/
sip-router.cfg
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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
#
# $Id$
#
# Example configuration file (simpler then ser-oob.cfg, but more
# complex then ser-basic.cfg).
#
# First start SER sample config script with:
# database, accounting, authentication, multi-domain support
# PSTN GW section, named flags, named routes, global-,
# domain- and user-preferences with AVPs
# Several of these features are only here for demonstration purpose
# what can be achieved with the SER config script language.
#
# If you look for a simpler version with a lot less dependencies
# please refer to the ser-basic.cfg file in your SER distribution.
#
# If you look for documentation, try http://sip-router.org/wiki/.
# The right mailing lists for questions about this file is
# <[email protected]>.
# To get this config running you need to execute the following commands
# with the new serctl (the capital word are just place holders)
# - ser_ctl domain add DOMAINNAME
# - ser_ctl user add USERNAME@DOMAINNAME -p PASSWORD
# ser_ctl can be obtained from
# http://ftp.iptel.org/pub/serctl/daily-snapshots/.
#
# If you want to have PID header for your user
# - ser_attr add uid=UID asserted_id="PID"
# If you want to have gateway support
# - ser_db add attr_types name=gw_ip rich_type=string raw_type=2 description="The gateway IP for the default ser.cfg" default_flags=33
# - ser_attr add global gw_ip=GATEWAY-IP
# ----------- Global Defines / Extra Features -------------------------------
# (can be enabled either by uncommenting the corresponding #!define
# statement or by starting with -A WITH_<FEATURE_NAME>, e.g.
# ser -A WITH_TLS -f /etc/ser/ser-oob.cfg )
# enable TLS
##!define WITH_TLS
# started from compile directory (not installed)
##!define LOCAL_TEST_RUN
# xmlrpc allowed subnets (if defined XMLRPC requests with source ip matching
# this network addresses will be allowed, if no XMLRPC_ALLOWED_SUBNETx is
# defined only requests coming from localhost will be allowed).
# E.g.: ser -A XMLRPC_ALLOW_NET1=192.168.1.0/24 -f ser-oob.cfg
##!define XMLRPC_ALLOW_NET1 192.168.0.0/16
##!define XMLRPC_ALLOW_NET2 10.0.0.0/255.0.0.0
##!define XMLRPC_ALLOW_NET3 172.16.0.0/12
# ----------- global configuration parameters ------------------------
debug=2 # debug level (cmd line: -dddddddddd)
#memdbg=10 # memory debug log level
#memlog=10 # memory statistics log level
#log_facility=LOG_LOCAL0 # sets the facility used for logging (see syslog(3))
/* Uncomment these lines to enter debugging mode
fork=no
log_stderror=yes
*/
check_via=no # (cmd. line: -v)
dns=no # (cmd. line: -r)
rev_dns=no # (cmd. line: -R)
#port=5060
#children=4
#user=ser
#group=ser
#disable_core=yes #disables core dumping
#open_fd_limit=1024 # sets the open file descriptors limit
#mhomed=yes # usefull for multihomed hosts, small performance penalty
#disable_tcp=yes
#tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
sip_warning=yes
#!ifdef WITH_TLS
enable_tls=yes
#!endif
#
# ------------------ module loading ----------------------------------
#!ifdef LOCAL_TEST_RUN
loadpath "modules:modules_s"
#!else
loadpath "/usr/lib/ser/modules:/usr/lib/ser/modules_s"
#!endif
# load a SQL database for authentication, domains, user AVPs etc.
loadmodule "db_mysql"
loadmodule "tm"
loadmodule "sl"
loadmodule "rr"
loadmodule "maxfwd"
loadmodule "usrloc"
loadmodule "registrar"
loadmodule "xlog"
loadmodule "textops"
loadmodule "ctl"
loadmodule "cfg_rpc"
loadmodule "auth"
loadmodule "auth_db"
loadmodule "gflags"
loadmodule "domain"
loadmodule "uri_db"
loadmodule "avp"
loadmodule "avp_db"
loadmodule "acc_db"
loadmodule "xmlrpc"
#!ifdef WITH_TLS
loadmodule "tls"
#!endif
# ----------------- setting script FLAGS -----------------------------
flags
FLAG_ACC : 1, # include message in accounting
FLAG_FAILUREROUTE : 2; # we are operating from a failure route
avpflags
dialog_cookie; # handled by rr module
# ----------------- setting module-specific parameters ---------------
# specify the path to you database here
modparam("acc_db|auth_db|avp_db|domain|gflags|usrloc|uri_db", "db_url", "mysql://ser:[email protected]/ser")
# -- usrloc params --
# as we use the database anyway we will use it for usrloc as well
modparam("usrloc", "db_mode", 1)
# -- auth params --
modparam("auth_db", "calculate_ha1", yes)
modparam("auth_db", "plain_password_column", "password")
# -- rr params --
# add value to ;lr param to make some broken UAs happy
modparam("rr", "enable_full_lr", 1)
#
# limit the length of the AVP cookie to only necessary ones
modparam("rr", "cookie_filter", "(account)")
#
# you probably do not want that someone can simply read and change
# the AVP cookie in your Routes, thus should really change this
# secret value below
modparam("rr", "cookie_secret", "MyRRAVPcookiesecret")
# -- gflags params --
# load the global AVPs
modparam("gflags", "load_global_attrs", 1)
# -- domain params --
# load the domain AVPs
modparam("domain", "load_domain_attrs", 1)
# -- ctl params --
# by default ctl listens on unixs:/tmp/ser_ctl if no other address is
# specified in modparams; this is also the default for sercmd
modparam("ctl", "binrpc", "unixs:/tmp/ser_ctl")
# listen on the "standard" fifo for backward compatibility
modparam("ctl", "fifo", "fifo:/tmp/ser_fifo")
# listen on tcp, localhost
modparam("ctl", "binrpc", "tcp:127.0.0.1:2046")
# -- acc_db params --
# failed transactions (=negative responses) should be logged to
modparam("acc_db", "failed_transactions", 1)
# comment the next line if you dont want to have accounting to DB
modparam("acc_db", "log_flag", "FLAG_ACC")
# -- tm params --
# uncomment the following line if you want to avoid that each new reply
# restarts the resend timer (see INBOUND route below)
#modparam("tm", "restart_fr_on_each_reply", "0")
#!ifdef WITH_TLS
# -- tls params --
modparam("tls", "verify_certificate", 0)
#!ifdef LOCAL_TEST_RUN
modparam("tls", "certificate", "./modules/tls/sip-router-selfsigned.pem")
modparam("tls", "private_key", "./modules/tls/sip-router-selfsigned.key")
#separate TLS config file
#modparam("tls", "config", "./modules/tls/tls.cfg")
#!else
modparam("tls", "certificate", "ser-selfsigned.pem")
modparam("tls", "private_key", "ser-selfsigned.key")
#separate TLS config file
#modparam("tls", "config", "tls.cfg")
#!endif
# -- xmlrpc params --
# using a sub-route from the module is a lot safer then relying on the
# request method to distinguish HTTP from SIP
modparam("xmlrpc", "route", "RPC");
# ------------------------- request routing logic -------------------
# main routing logic
route{
# if you have a PSTN gateway just un-comment the follwoing line and
# specify the IP address of it to route calls to it
#$gw_ip = "1.2.3.4"
# first do some initial sanity checks
route(INIT);
# bypass the rest of the script for CANCELs if possible
route(CATCH_CANCEL);
# check if the request is routed via Route header or
# needs a Record-Route header
route(RR);
# check if the request belongs to our proxy
route(DOMAIN);
# handle REGISTER requests
route(REGISTRAR);
# from here on we want to know you is calling
route(AUTHENTICATION);
# check if we should be outbound proxy for a local user
route(OUTBOUND);
# check if the request is for a local user
route(INBOUND);
# here you could for example try to do an ENUM lookup before
# the call gets routed to the PSTN
#route(ENUM);
# lets see if someone wants to call a PSTN number
route(PSTN);
# nothing matched, reject it finally
sl_reply("404", "No route matched");
}
route[FORWARD]
{
# here you could decide wether this call needs a RTP relay or not
# if this is called from the failure route we need to open a new branch
if (isflagset(FLAG_FAILUREROUTE)) {
append_branch();
}
# if this is an initial INVITE (without a To-tag) we might try another
# (forwarding or voicemail) target after receiving an error
if (method=="INVITE" && strempty(@to.tag)) {
t_on_failure("FAILURE_ROUTE");
}
# send it out now; use stateful forwarding as it works reliably
# even for UDP2TCP
if (!t_relay()) {
sl_reply_error();
}
drop;
}
route[INIT]
{
# initial sanity checks -- messages with
# max_forwards==0, or excessively long requests
if (!mf_process_maxfwd_header("10")) {
sl_reply("483","Too Many Hops");
drop;
}
if (msg:len >= 4096 ) {
sl_reply("513", "Message too big");
drop;
}
# you could add some NAT detection here for example
# or you cuold call here some of the check from the sanity module
# lets account all initial INVITEs
# further in-dialog requests are accounted by a RR cookie (see below)
if (method=="INVITE" && strempty(@to.tag)) {
setflag(FLAG_ACC);
}
}
route[RPC]
{
# allow XMLRPC from localhost
if ((method=="POST" || method=="GET") &&
(src_ip==127.0.0.1
#!ifdef XMLRPC_ALLOW_NET1
|| src_ip == XMLRPC_ALLOW_NET1
#!endif
#!ifdef XMLRPC_ALLOW_NET2
|| src_ip == XMLRPC_ALLOW_NET2
#!endif
#!ifdef XMLRPC_ALLOW_NET3
|| src_ip == XMLRPC_ALLOW_NET3
#!endif
)) {
if (msg:len >= 8192) {
sl_reply("513", "Request to big");
drop;
}
# close connection only for xmlrpclib user agents (there is a bug in
# xmlrpclib: it waits for EOF before interpreting the response).
if (search("^User-Agent:.*xmlrpclib"))
set_reply_close();
set_reply_no_connect(); # optional
# lets see if a module wants to answer this
dispatch_rpc();
drop;
}
}
route[RR]
{
# subsequent messages withing a dialog should take the
# path determined by record-routing
if (loose_route()) {
# mark routing logic in request
append_hf("P-hint: rr-enforced\r\n");
# if the Route contained the accounting AVP cookie we
# set the accounting flag for the acc_db module.
# this is more for demonstration purpose as this could
# also be solved without RR cookies.
# Note: this means all in-dialog request will show up in the
# accounting tables, so prepare your accounting software for this ;-)
if ($account == "yes") {
setflag(FLAG_ACC);
}
# for broken devices which overwrite their Route's with each
# (not present) RR from within dialog requests it is better
# to repeat the RRing
# and if we call rr after loose_route the AVP cookies are restored
# automatically :)
record_route();
route(FORWARD);
} else if (!method=="REGISTER") {
# we record-route all messages -- to make sure that
# subsequent messages will go through our proxy; that's
# particularly good if upstream and downstream entities
# use different transport protocol
# if the inital INVITE got the ACC flag store this in
# an RR AVP cookie. this is more for demonstration purpose
if (isflagset(FLAG_ACC)) {
$account = "yes";
setavpflag($account, "dialog_cookie");
}
record_route();
}
}
route[DOMAIN]
{
# check if the caller is from a local domain
lookup_domain("$fd", "@from.uri.host");
# check if the callee is at a local domain
lookup_domain("$td", "@ruri.host");
# we dont know the domain of the caller and also not
# the domain of the callee -> somone uses our proxy as
# a relay
if (strempty($t.did) && strempty($f.did)) {
sl_reply("403", "Relaying Forbidden");
drop;
}
}
route[REGISTRAR]
{
# if the request is a REGISTER lets take care of it
if (method=="REGISTER") {
# check if the REGISTER if for one of our local domains
if (strempty($t.did)) {
sl_reply("403", "Register forwarding forbidden");
drop;
}
# we want only authenticated users to be registered
if (!www_authenticate("$fd.digest_realm", "credentials")) {
if ($? == -2) {
sl_reply("500", "Internal Server Error");
} else if ($? == -3) {
sl_reply("400", "Bad Request");
} else {
if ($digest_challenge != "") {
append_to_reply("%$digest_challenge");
}
sl_reply("401", "Unauthorized");
}
drop;
}
# check if the authenticated user is the same as the target user
if (!lookup_user("$tu.uid", "@to.uri")) {
sl_reply("404", "Unknown user in To");
drop;
}
if ($f.uid != $t.uid) {
sl_reply("403", "Authentication and To-Header mismatch");
drop;
}
# check if the authenticated user is the same as the request originator
# you may uncomment it if you care, what uri is in From header
#if (!lookup_user("$fu.uid", "@from.uri")) {
# sl_reply("404", "Unknown user in From");
# drop;
#}
#if ($fu.uid != $tu.uid) {
# sl_reply("403", "Authentication and From-Header mismatch");
# drop;
#}
# everything is fine so lets store the binding
if (!save_contacts("location")) {
sl_reply("400", "Invalid REGISTER Request");
drop;
}
drop;
}
}
route[AUTHENTICATION]
{
if (method=="CANCEL" || method=="ACK") {
# you are not allowed to challenge these methods
break;
}
# requests from non-local to local domains should be permitted
# remove this if you want a walled garden
if (strempty($f.did)) {
break;
}
# as gateways are usually not able to authenticate for their
# requests you will have trust them base on some other information
# like the source IP address. WARNING: if at all this is only safe
# in a local network!!!
#if (src_ip==a.b.c.d) {
# break;
#}
if (!proxy_authenticate("$fd.digest_realm", "credentials")) {
if ($? == -2) {
sl_reply("500", "Internal Server Error");
} else if ($? == -3) {
sl_reply("400", "Bad Request");
} else {
if ($digest_challenge != "") {
append_to_reply("%$digest_challenge");
}
sl_reply("407", "Proxy Authentication Required");
}
drop;
}
# check if the UID from the authentication meets the From header
$authuid = $uid;
if (!lookup_user("$fu.uid", "@from.uri")) {
del_attr("$uid");
}
if ($fu.uid != $fr.authuid) {
sl_reply("403", "Fake Identity");
drop;
}
# load the user AVPs (preferences) of the caller, e.g. for RPID header
load_attrs("$fu", "$f.uid");
}
route[OUTBOUND]
{
# if a local user calls to a foreign domain we play outbound proxy for him
# comment this out if you want a walled garden
if ($f.did != "" && $t.did == "") {
append_hf("P-hint: outbound\r\n");
route(FORWARD);
}
}
route[INBOUND]
{
# lets see if know the callee
if (lookup_user("$tu.uid", "@ruri")) {
# load the preferences of the callee to have his timeout values loaded
load_attrs("$tu", "$t.uid");
# if you want to know if the callee username was an alias
# check it like this
#if (strempty($tu.uri_canonical)) {
# if the alias URI has different AVPs/preferences
# you can load them into the URI track like this
#load_attrs("$tr", "@ruri");
#}
# check for call forwarding of the callee
# Note: the forwarding target has to be full routable URI
# in this example
if ($tu.fwd_always_target != "") {
attr2uri("$tu.fwd_always_target");
route(FORWARD);
}
# native SIP destinations are handled using our USRLOC DB
if (lookup_contacts("location")) {
append_hf("P-hint: usrloc applied\r\n");
# we set the TM module timers according to the prefences
# of the callee (avoid too long ringing of his phones)
# Note1: timer values have to be in ms now!
# Note2: this makes even more sense if you switch to a voicemail
# from the FAILURE_ROUTE below
if ($t.fr_inv_timer != 0) {
if ($t.fr_timer != 0) {
t_set_fr("$t.fr_inv_timer", "$t.fr_timer");
} else {
t_set_fr("$t.fr_inv_timer");
}
}
route(FORWARD);
} else {
sl_reply("480", "User temporarily not available");
drop;
}
}
}
route[PSTN]
{
# Only if the AVP 'gw_ip' is set and the request URI contains
# only a number we consider sending this to the PSTN GW.
# Only users from a local domain are permitted to make calls.
# Additionally you might want to check the acl AVP to verify
# that the user is allowed to make such expensives calls.
if ($f.did != "" && $gw_ip != "" &&
uri=~"sips?:\+?[0-9]{3,18}@.*") {
# probably you need to convert the number in the request
# URI according to the requirements of your gateway here
# if an AVP 'asserted_id' is set we insert an RPID header
if ($asserted_id != "") {
xlset_attr("$rpidheader", "<sip:%$asserted_id@%@ruri.host>;screen=yes");
replace_attr_hf("Remote-Party-ID", "$rpidheader");
}
# just replace the domain part of the RURI with the
# value from the AVP and send it out
attr2uri("$gw_ip", "domain");
route(FORWARD);
}
}
route[CATCH_CANCEL] {
# check whether there is a corresponding INVITE to the CANCEL,
# and bypass the rest of the script if possible
if (method == CANCEL) {
if (!t_relay_cancel()) { # implicit drop if the INVITE was found
# INVITE was found but some error occurred
sl_reply("500", "Internal Server Error");
drop;
}
# bad luck, no corresponding INVITE was found,
# we have to continue with the script
}
}
failure_route[FAILURE_ROUTE]
{
# mark for the other routes that we are operating from here on from a
# failure route
setflag(FLAG_FAILUREROUTE);
if (t_check_status("486|600")) {
# if we received a busy and a busy target is set, forward it there
# Note: again the forwarding target has to be a routeable URI
if ($tu.fwd_busy_target != "") {
attr2uri("$tu.fwd_busy_target");
route(FORWARD);
}
# alternatively you could forward the request to SEMS/voicemail here
}
else if (t_check_status("408|480")) {
# if we received no answer and the noanswer target is set,
# forward it there
# Note: again the target has to be a routeable URI
if ($tu.fwd_noanswer_target != "") {
attr2uri("$tu.fwd_noanswer_target");
route(FORWARD);
}
# alternatively you could forward the request to SEMS/voicemail here
}
}