parser: some more const-correctness for the other functions in msg_parser.[c,h]
[sip-router] / etc / sip-router.cfg
1 #
2 # $Id$
3 #
4 # Example configuration file (simpler then ser-oob.cfg, but more
5 # complex then ser-basic.cfg).
6 #
7 # First start SER sample config script with:
8 #   database, accounting, authentication, multi-domain support
9 #   PSTN GW section, named flags, named routes, global-,
10 #   domain- and user-preferences with AVPs
11 # Several of these features are only here for demonstration purpose
12 # what can be achieved with the SER config script language.
13 #
14 # If you look for a simpler version with a lot less dependencies
15 # please refer to the ser-basic.cfg file in your SER distribution.
16 #
17 # If you look for documentation, try http://sip-router.org/wiki/.
18 # The right mailing lists for questions about this file is
19 # <sr-users@lists.sip-router.org>.
20
21 # To get this config running you need to execute the following commands
22 # with the new serctl (the capital word are just place holders)
23 # - ser_ctl domain add DOMAINNAME
24 # - ser_ctl user add USERNAME@DOMAINNAME -p PASSWORD
25 # ser_ctl can be obtained from
26 # http://ftp.iptel.org/pub/serctl/daily-snapshots/.
27 #
28 # If you want to have PID header for your user
29 # - ser_attr add uid=UID asserted_id="PID"
30 # If you want to have gateway support
31 # - 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
32 # - ser_attr add global gw_ip=GATEWAY-IP
33
34
35 # ----------- Global Defines / Extra Features -------------------------------
36 # (can be enabled either by uncommenting the corresponding #!define 
37 #  statement or by starting with -A WITH_<FEATURE_NAME>, e.g.
38 #  ser -A WITH_TLS -f /etc/ser/ser-oob.cfg )
39
40 # enable TLS
41 ##!define WITH_TLS
42
43 # started from compile directory (not installed)
44 ##!define LOCAL_TEST_RUN
45
46 # xmlrpc allowed subnets (if defined XMLRPC requests with source ip matching
47 # this network addresses will be allowed, if no XMLRPC_ALLOWED_SUBNETx is
48 # defined only requests coming from localhost will be allowed).
49 # E.g.: ser -A XMLRPC_ALLOW_NET1=192.168.1.0/24 -f ser-oob.cfg
50 ##!define XMLRPC_ALLOW_NET1  192.168.0.0/16
51 ##!define XMLRPC_ALLOW_NET2  10.0.0.0/255.0.0.0
52 ##!define XMLRPC_ALLOW_NET3  172.16.0.0/12
53
54
55 # ----------- global configuration parameters ------------------------
56
57 debug=2         # debug level (cmd line: -dddddddddd)
58 #memdbg=10 # memory debug log level
59 #memlog=10 # memory statistics log level
60 #log_facility=LOG_LOCAL0 # sets the facility used for logging (see syslog(3))
61
62 /* Uncomment these lines to enter debugging mode 
63 fork=no
64 log_stderror=yes
65 */
66
67 check_via=no    # (cmd. line: -v)
68 dns=no          # (cmd. line: -r)
69 rev_dns=no      # (cmd. line: -R)
70 #port=5060
71 #children=4
72 #user=ser
73 #group=ser
74 #disable_core=yes #disables core dumping
75 #open_fd_limit=1024 # sets the open file descriptors limit
76 #mhomed=yes  # usefull for multihomed hosts, small performance penalty
77 #disable_tcp=yes 
78 #tcp_accept_aliases=yes # accepts the tcp alias via option (see NEWS)
79 sip_warning=yes
80 #!ifdef WITH_TLS
81 enable_tls=yes
82 #!endif
83
84 #
85
86 # ------------------ module loading ----------------------------------
87
88 #!ifdef LOCAL_TEST_RUN
89 loadpath "modules:modules_s"
90 #!else
91 loadpath "/usr/lib/ser/modules:/usr/lib/ser/modules_s"
92 #!endif
93
94 # load a SQL database for authentication, domains, user AVPs etc.
95 loadmodule "db_mysql"
96
97 loadmodule "tm"
98 loadmodule "sl"
99 loadmodule "rr"
100 loadmodule "maxfwd"
101 loadmodule "usrloc"
102 loadmodule "registrar"
103 loadmodule "xlog"
104 loadmodule "textops"
105 loadmodule "ctl"
106 loadmodule "cfg_rpc"
107 loadmodule "auth"
108 loadmodule "auth_db"
109 loadmodule "gflags"
110 loadmodule "domain"
111 loadmodule "uri_db"
112 loadmodule "avp"
113 loadmodule "avp_db"
114 loadmodule "acc_db"
115 loadmodule "xmlrpc"
116 #!ifdef WITH_TLS
117 loadmodule "tls"
118 #!endif
119
120 # ----------------- setting script FLAGS -----------------------------
121 flags
122   FLAG_ACC          : 1,  # include message in accounting
123   FLAG_FAILUREROUTE : 2;  # we are operating from a failure route
124
125 avpflags
126   dialog_cookie;        # handled by rr module
127
128 # ----------------- setting module-specific parameters ---------------
129
130 # specify the path to you database here
131 modparam("acc_db|auth_db|avp_db|domain|gflags|usrloc|uri_db", "db_url", "mysql://ser:heslo@127.0.0.1/ser")
132
133 # -- usrloc params --
134
135 # as we use the database anyway we will use it for usrloc as well
136 modparam("usrloc", "db_mode", 1)
137
138 # -- auth params --
139 modparam("auth_db", "calculate_ha1", yes)
140 modparam("auth_db", "plain_password_column", "password")
141
142 # -- rr params --
143 # add value to ;lr param to make some broken UAs happy
144 modparam("rr", "enable_full_lr", 1)
145 #
146 # limit the length of the AVP cookie to only necessary ones
147 modparam("rr", "cookie_filter", "(account)")
148 #
149 # you probably do not want that someone can simply read and change
150 # the AVP cookie in your Routes, thus should really change this
151 # secret value below
152 modparam("rr", "cookie_secret", "MyRRAVPcookiesecret")
153
154 # -- gflags params --
155 # load the global AVPs
156 modparam("gflags", "load_global_attrs", 1)
157
158 # -- domain params --
159 # load the domain AVPs
160 modparam("domain", "load_domain_attrs", 1)
161
162 # -- ctl params --
163 # by default ctl listens on unixs:/tmp/ser_ctl if no other address is
164 # specified in modparams; this is also the default for sercmd
165 modparam("ctl", "binrpc", "unixs:/tmp/ser_ctl")
166 # listen on the "standard" fifo for backward compatibility
167 modparam("ctl", "fifo", "fifo:/tmp/ser_fifo")
168 # listen on tcp, localhost
169 modparam("ctl", "binrpc", "tcp:127.0.0.1:2046")
170
171 # -- acc_db params --
172 # failed transactions (=negative responses) should be logged to
173 modparam("acc_db", "failed_transactions", 1)
174
175 # comment the next line if you dont want to have accounting to DB
176 modparam("acc_db", "log_flag", "FLAG_ACC")
177
178 # -- tm params --
179 # uncomment the following line if you want to avoid that each new reply
180 # restarts the resend timer (see INBOUND route below)
181 #modparam("tm", "restart_fr_on_each_reply", "0")
182
183 #!ifdef WITH_TLS
184 # -- tls params --
185 modparam("tls", "verify_certificate", 0)
186 #!ifdef  LOCAL_TEST_RUN
187 modparam("tls", "certificate", "./modules/tls/sip-router-selfsigned.pem")
188 modparam("tls", "private_key", "./modules/tls/sip-router-selfsigned.key")
189 #separate TLS config file
190 #modparam("tls", "config", "./modules/tls/tls.cfg")
191 #!else
192 modparam("tls", "certificate", "ser-selfsigned.pem")
193 modparam("tls", "private_key", "ser-selfsigned.key")
194 #separate TLS config file
195 #modparam("tls", "config", "tls.cfg")
196 #!endif
197
198
199 # -- xmlrpc params --
200 # using a sub-route from the module is a lot safer then relying on the
201 # request method to distinguish HTTP from SIP
202 modparam("xmlrpc", "route", "RPC");
203
204 # -------------------------  request routing logic -------------------
205
206 # main routing logic
207
208 route{
209         # if you have a PSTN gateway just un-comment the follwoing line and 
210         # specify the IP address of it to route calls to it
211         #$gw_ip = "1.2.3.4"
212
213         # first do some initial sanity checks
214         route(INIT);
215
216         # bypass the rest of the script for CANCELs if possible
217         route(CATCH_CANCEL);
218
219         # check if the request is routed via Route header or
220         # needs a Record-Route header
221         route(RR);
222
223         # check if the request belongs to our proxy
224         route(DOMAIN);
225
226         # handle REGISTER requests
227         route(REGISTRAR);
228
229         # from here on we want to know you is calling
230         route(AUTHENTICATION);
231
232         # check if we should be outbound proxy for a local user
233         route(OUTBOUND);
234
235         # check if the request is for a local user
236         route(INBOUND);
237
238         # here you could for example try to do an ENUM lookup before
239         # the call gets routed to the PSTN
240         #route(ENUM);
241
242         # lets see if someone wants to call a PSTN number
243         route(PSTN);
244
245         # nothing matched, reject it finally
246         sl_reply("404", "No route matched");
247 }
248
249 route[FORWARD]
250 {
251         # here you could decide wether this call needs a RTP relay or not
252
253         # if this is called from the failure route we need to open a new branch
254         if (isflagset(FLAG_FAILUREROUTE)) {
255                 append_branch();
256         }
257
258         # if this is an initial INVITE (without a To-tag) we might try another
259         # (forwarding or voicemail) target after receiving an error
260         if (method=="INVITE" && strempty(@to.tag)) {
261                 t_on_failure("FAILURE_ROUTE");
262         }
263
264         # send it out now; use stateful forwarding as it works reliably
265         # even for UDP2TCP
266         if (!t_relay()) {
267                 sl_reply_error();
268         }
269         drop;
270 }
271
272 route[INIT]
273 {
274         # initial sanity checks -- messages with
275         # max_forwards==0, or excessively long requests
276         if (!mf_process_maxfwd_header("10")) {
277                 sl_reply("483","Too Many Hops");
278                 drop;
279         }
280
281         if (msg:len >=  4096 ) {
282                 sl_reply("513", "Message too big");
283                 drop;
284         }
285
286         # you could add some NAT detection here for example
287
288         # or you cuold call here some of the check from the sanity module
289
290         # lets account all initial INVITEs
291         # further in-dialog requests are accounted by a RR cookie (see below)
292         if (method=="INVITE" && strempty(@to.tag)) {
293                 setflag(FLAG_ACC);
294         }
295 }
296
297 route[RPC]
298 {
299         # allow XMLRPC from localhost
300         if ((method=="POST" || method=="GET") &&
301                 (src_ip==127.0.0.1
302         #!ifdef XMLRPC_ALLOW_NET1
303                 || src_ip == XMLRPC_ALLOW_NET1
304         #!endif
305         #!ifdef XMLRPC_ALLOW_NET2
306                 || src_ip == XMLRPC_ALLOW_NET2
307         #!endif
308         #!ifdef XMLRPC_ALLOW_NET3
309                 || src_ip == XMLRPC_ALLOW_NET3
310         #!endif
311                 )) {
312
313                 if (msg:len >= 8192) {
314                         sl_reply("513", "Request to big");
315                         drop;
316                 }
317
318                 # close connection only for xmlrpclib user agents (there is a bug in
319                 # xmlrpclib: it waits for EOF before interpreting the response).
320                 if (search("^User-Agent:.*xmlrpclib"))
321                         set_reply_close();
322                 set_reply_no_connect(); # optional
323                 # lets see if a module wants to answer this
324                 dispatch_rpc();
325                 drop;
326         }
327 }
328
329 route[RR]
330 {
331         # subsequent messages withing a dialog should take the
332         # path determined by record-routing
333         if (loose_route()) {
334                 # mark routing logic in request
335                 append_hf("P-hint: rr-enforced\r\n"); 
336
337                 # if the Route contained the accounting AVP cookie we
338                 # set the accounting flag for the acc_db module.
339                 # this is more for demonstration purpose as this could
340                 # also be solved without RR cookies.
341                 # Note: this means all in-dialog request will show up in the
342                 # accounting tables, so prepare your accounting software for this ;-)
343                 if ($account == "yes") {
344                         setflag(FLAG_ACC);
345                 }
346
347                 # for broken devices which overwrite their Route's with each
348                 # (not present) RR from within dialog requests it is better
349                 # to repeat the RRing
350                 # and if we call rr after loose_route the AVP cookies are restored
351                 # automatically :)
352                 record_route();
353
354                 route(FORWARD);
355         } else if (!method=="REGISTER") {
356                 # we record-route all messages -- to make sure that
357                 # subsequent messages will go through our proxy; that's
358                 # particularly good if upstream and downstream entities
359                 # use different transport protocol
360
361                 # if the inital INVITE got the ACC flag store this in
362                 # an RR AVP cookie. this is more for demonstration purpose
363                 if (isflagset(FLAG_ACC)) {
364                         $account = "yes";
365                         setavpflag($account, "dialog_cookie");
366                 }
367
368                 record_route();
369         }
370 }
371
372 route[DOMAIN]
373 {
374         # check if the caller is from a local domain
375         lookup_domain("$fd", "@from.uri.host");
376
377         # check if the callee is at a local domain
378         lookup_domain("$td", "@ruri.host");
379
380         # we dont know the domain of the caller and also not
381         # the domain of the callee -> somone uses our proxy as
382         # a relay
383         if (strempty($t.did) && strempty($f.did)) {
384                 sl_reply("403", "Relaying Forbidden");
385                 drop;
386         }
387 }
388
389 route[REGISTRAR]
390 {
391         # if the request is a REGISTER lets take care of it
392         if (method=="REGISTER") {
393                 # check if the REGISTER if for one of our local domains
394                 if (strempty($t.did)) {
395                         sl_reply("403", "Register forwarding forbidden");
396                         drop;
397                 }
398
399                 # we want only authenticated users to be registered
400                 if (!www_authenticate("$fd.digest_realm", "credentials")) {
401                         if ($? == -2) {
402                                 sl_reply("500", "Internal Server Error");
403                         } else if ($? == -3) {
404                                 sl_reply("400", "Bad Request");
405                         } else {
406                                 if ($digest_challenge != "") {
407                                         append_to_reply("%$digest_challenge");
408                                 }
409                                 sl_reply("401", "Unauthorized");
410                         }
411                         drop;
412                 }
413
414                 # check if the authenticated user is the same as the target user
415                 if (!lookup_user("$tu.uid", "@to.uri")) {
416                         sl_reply("404", "Unknown user in To");
417                         drop;
418                 }
419
420                 if ($f.uid != $t.uid) {
421                         sl_reply("403", "Authentication and To-Header mismatch");
422                         drop;
423                 }
424
425                 # check if the authenticated user is the same as the request originator
426                 # you may uncomment it if you care, what uri is in From header
427                 #if (!lookup_user("$fu.uid", "@from.uri")) {
428                 #       sl_reply("404", "Unknown user in From");
429                 #       drop;
430                 #}
431                 #if ($fu.uid != $tu.uid) {
432                 #       sl_reply("403", "Authentication and From-Header mismatch");
433                 #       drop;
434                 #}
435
436                 # everything is fine so lets store the binding
437                 if (!save_contacts("location")) {
438                         sl_reply("400", "Invalid REGISTER Request");
439                         drop;
440                 }
441                 drop;
442         }
443 }
444
445 route[AUTHENTICATION]
446 {
447         if (method=="CANCEL" || method=="ACK") {
448                 # you are not allowed to challenge these methods
449                 break;
450         }
451
452         # requests from non-local to local domains should be permitted
453         # remove this if you want a walled garden
454         if (strempty($f.did)) {
455                 break;
456         }
457
458         # as gateways are usually not able to authenticate for their
459         # requests you will have trust them base on some other information
460         # like the source IP address. WARNING: if at all this is only safe
461         # in a local network!!!
462         #if (src_ip==a.b.c.d) {
463         #       break;
464         #}
465
466         if (!proxy_authenticate("$fd.digest_realm", "credentials")) {
467                 if ($? == -2) {
468                         sl_reply("500", "Internal Server Error");
469                 } else if ($? == -3) {
470                         sl_reply("400", "Bad Request");
471                 } else {
472                         if ($digest_challenge != "") {
473                                 append_to_reply("%$digest_challenge");
474                         }
475                         sl_reply("407", "Proxy Authentication Required");
476                 }
477                 drop;
478         }
479
480         # check if the UID from the authentication meets the From header
481         $authuid = $uid;
482         if (!lookup_user("$fu.uid", "@from.uri")) {
483                 del_attr("$uid");
484         }
485         if ($fu.uid != $fr.authuid) {
486                 sl_reply("403", "Fake Identity");
487                 drop;
488         }
489         # load the user AVPs (preferences) of the caller, e.g. for RPID header
490         load_attrs("$fu", "$f.uid");
491 }
492
493 route[OUTBOUND]
494 {
495         # if a local user calls to a foreign domain we play outbound proxy for him
496         # comment this out if you want a walled garden
497         if ($f.did != ""  && $t.did == "") {
498                 append_hf("P-hint: outbound\r\n");
499                 route(FORWARD);
500         }
501 }
502
503 route[INBOUND]
504 {
505         # lets see if know the callee
506         if (lookup_user("$tu.uid", "@ruri")) {
507
508                 # load the preferences of the callee to have his timeout values loaded
509                 load_attrs("$tu", "$t.uid");
510
511                 # if you want to know if the callee username was an alias
512                 # check it like this
513                 #if (strempty($tu.uri_canonical)) {
514                         # if the alias URI has different AVPs/preferences
515                         # you can load them into the URI track like this
516                         #load_attrs("$tr", "@ruri");
517                 #}
518
519                 # check for call forwarding of the callee
520                 # Note: the forwarding target has to be full routable URI
521                 #       in this example
522                 if ($tu.fwd_always_target != "") {
523                         attr2uri("$tu.fwd_always_target");
524                         route(FORWARD);
525                 }
526
527                 # native SIP destinations are handled using our USRLOC DB
528                 if (lookup_contacts("location")) {
529                         append_hf("P-hint: usrloc applied\r\n");
530
531                         # we set the TM module timers according to the prefences
532                         # of the callee (avoid too long ringing of his phones)
533                         # Note1: timer values have to be in ms now!
534                         # Note2: this makes even more sense if you switch to a voicemail
535                         #        from the FAILURE_ROUTE below
536                         if ($t.fr_inv_timer != 0) {
537                                 if ($t.fr_timer != 0) {
538                                         t_set_fr("$t.fr_inv_timer", "$t.fr_timer");
539                                 } else {
540                                         t_set_fr("$t.fr_inv_timer");
541                                 }
542                         }
543
544                         route(FORWARD);
545                 } else {
546                         sl_reply("480", "User temporarily not available");
547                         drop;
548                 }
549         }
550 }
551
552 route[PSTN]
553 {
554         # Only if the AVP 'gw_ip' is set and the request URI contains
555         # only a number we consider sending this to the PSTN GW.
556         # Only users from a local domain are permitted to make calls.
557         # Additionally you might want to check the acl AVP to verify
558         # that the user is allowed to make such expensives calls.
559         if ($f.did != "" && $gw_ip != "" &&
560                 uri=~"sips?:\+?[0-9]{3,18}@.*") {
561                 # probably you need to convert the number in the request
562                 # URI according to the requirements of your gateway here
563
564                 # if an AVP 'asserted_id' is set we insert an RPID header
565                 if ($asserted_id != "") {
566                         xlset_attr("$rpidheader", "<sip:%$asserted_id@%@ruri.host>;screen=yes");
567                         replace_attr_hf("Remote-Party-ID", "$rpidheader");
568                 }
569
570                 # just replace the domain part of the RURI with the
571                 # value from the AVP and send it out
572                 attr2uri("$gw_ip", "domain");
573                 route(FORWARD);
574         }
575 }
576
577 route[CATCH_CANCEL] {
578         # check whether there is a corresponding INVITE to the CANCEL,
579         # and bypass the rest of the script if possible
580
581         if (method == CANCEL) {
582                 if (!t_relay_cancel()) { # implicit drop if the INVITE was found
583
584                         # INVITE was found but some error occurred
585                         sl_reply("500", "Internal Server Error");
586                         drop;
587                 }
588                 # bad luck, no corresponding INVITE was found,
589                 # we have to continue with the script
590         }
591 }
592
593 failure_route[FAILURE_ROUTE]
594 {
595         # mark for the other routes that we are operating from here on from a
596         # failure route
597         setflag(FLAG_FAILUREROUTE);
598
599         if (t_check_status("486|600")) {
600                 # if we received a busy and a busy target is set, forward it there
601                 # Note: again the forwarding target has to be a routeable URI
602                 if ($tu.fwd_busy_target != "") {
603                         attr2uri("$tu.fwd_busy_target");
604                         route(FORWARD);
605                 }
606                 # alternatively you could forward the request to SEMS/voicemail here
607         }
608         else if (t_check_status("408|480")) {
609                 # if we received no answer and the noanswer target is set,
610                 # forward it there
611                 # Note: again the target has to be a routeable URI
612                 if ($tu.fwd_noanswer_target != "") {
613                         attr2uri("$tu.fwd_noanswer_target");
614                         route(FORWARD);
615                 }
616                 # alternatively you could forward the request to SEMS/voicemail here
617         }
618 }