123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- #!KAMAILIO
- #
- # Simple/sample kamailio.cfg for running a proxy/registrar with TLS and
- # WebSockets support.
- #!substdef "!DBURL!sqlite:///etc/kamailio/db.sqlite!g"
- #!substdef "!MY_IP_ADDR!a.b.c.d!g"
- #!substdef "!MY_DOMAIN!example.com!g"
- #!substdef "!MY_WS_PORT!80!g"
- #!substdef "!MY_WSS_PORT!443!g"
- #!substdef "!MY_MSRP_PORT!9000!g"
- #!substdef "!MY_WS_ADDR!tcp:MY_IP_ADDR:MY_WS_PORT!g"
- #!substdef "!MY_WSS_ADDR!tls:MY_IP_ADDR:MY_WSS_PORT!g"
- #!substdef "!MY_MSRP_ADDR!tls:MY_IP_ADDR:MY_MSRP_PORT!g"
- #!substdef "!MSRP_MIN_EXPIRES!1800!g"
- #!substdef "!MSRP_MAX_EXPIRES!3600!g"
- ##!define LOCAL_TEST_RUN
- #!define WITH_TLS
- #!define WITH_WEBSOCKETS
- #!define WITH_MSRP
- ####### Global Parameters #########
- fork=yes
- children=4
- #!ifdef WITH_TLS
- enable_tls=1
- #!endif
- listen=MY_IP_ADDR
- #!ifdef WITH_WEBSOCKETS
- listen=MY_WS_ADDR
- #!ifdef WITH_TLS
- listen=MY_WSS_ADDR
- #!endif
- #!endif
- #!ifdef WITH_MSRP
- listen=MY_MSRP_ADDR
- #!endif
- tcp_connection_lifetime=3604
- tcp_accept_no_cl=yes
- tcp_rd_buf_size=16384
- #!ifdef LOCAL_TEST_RUN
- debug=2
- mpath="modules"
- #!else
- debug=0
- mpath="/usr/lib64/kamailio/modules/"
- #!endif
- loadmodule "db_sqlite.so"
- loadmodule "tm.so"
- loadmodule "sl.so"
- loadmodule "rr.so"
- loadmodule "pv.so"
- loadmodule "maxfwd.so"
- loadmodule "usrloc.so"
- loadmodule "registrar.so"
- loadmodule "textops.so"
- loadmodule "siputils.so"
- loadmodule "xlog.so"
- loadmodule "sanity.so"
- loadmodule "ctl.so"
- loadmodule "auth.so"
- loadmodule "auth_db.so"
- loadmodule "kex.so"
- loadmodule "mi_rpc.so"
- loadmodule "corex.so"
- #!ifdef WITH_TLS
- loadmodule "tls.so"
- #!endif
- #!ifdef WITH_MSRP
- loadmodule "msrp.so"
- loadmodule "htable.so"
- loadmodule "cfgutils.so"
- #!endif
- #!ifdef WITH_WEBSOCKETS
- loadmodule "xhttp.so"
- loadmodule "websocket.so"
- loadmodule "nathelper.so"
- #!endif
- # ----------------- setting module-specific parameters ---------------
- # ----- 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 -----
- # add value to ;lr param to cope with most of the UAs
- modparam("rr", "enable_full_lr", 1)
- # 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)
- modparam("registrar", "max_expires", 3600)
- modparam("registrar", "gruu_enabled", 0)
- # ----- usrloc params -----
- modparam("usrloc", "db_url", "DBURL")
- modparam("usrloc", "db_mode", 0)
- # ----- auth params -----
- modparam("auth", "nonce_count", 1)
- modparam("auth", "qop", "auth")
- # ----- auth_db params -----
- modparam("auth_db", "db_url", "DBURL")
- modparam("auth_db", "calculate_ha1", yes)
- modparam("auth_db", "password_column", "password")
- modparam("auth_db", "load_credentials", "id")
- # ----- corex params -----
- modparam("corex", "alias_subdomains", "MY_DOMAIN")
- #!ifdef WITH_TLS
- # ----- tls params -----
- modparam("tls", "tls_method", "SSLv23")
- modparam("tls", "certificate", "/etc/pki/CA/ser1_cert.pem")
- modparam("tls", "private_key", "/etc/pki/CA/privkey.pem")
- modparam("tls", "ca_list", "/etc/pki/CA/calist.pem")
- #!endif
- #!ifdef WITH_WEBSOCKETS
- # ----- nathelper params -----
- modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)")
- # Note: leaving NAT pings turned off here as nathelper is _only_ being used for
- # WebSocket connections. NAT pings are not needed as WebSockets have
- # their own keep-alives.
- #!endif
- #!ifdef WITH_MSRP
- # ----- htable params -----
- modparam("htable", "htable", "msrp=>size=8;autoexpire=MSRP_MAX_EXPIRES;")
- #!endif
- ####### Routing Logic ########
- # Main SIP request routing logic
- # - processing of any incoming SIP request starts with this route
- # - note: this is the same as route { ... }
- request_route {
- if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
- && !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) {
- xlog("L_WARN", "SIP request received on $Rp\n");
- sl_send_reply("403", "Forbidden");
- exit;
- }
- # per request initial checks
- route(REQINIT);
- #!ifdef WITH_WEBSOCKETS
- if (nat_uac_test(64)) {
- # Do NAT traversal stuff for requests from a WebSocket
- # connection - even if it is not behind a NAT!
- # This won't be needed in the future if Kamailio and the
- # WebSocket client support Outbound and Path.
- force_rport();
- if (is_method("REGISTER")) {
- fix_nated_register();
- } else {
- if (!add_contact_alias()) {
- xlog("L_ERR", "Error aliasing contact <$ct>\n");
- sl_send_reply("400", "Bad Request");
- exit;
- }
- }
- }
- #!endif
- # handle requests within SIP dialogs
- route(WITHINDLG);
- ### only initial requests (no To tag)
- # CANCEL processing
- if (is_method("CANCEL")) {
- if (t_check_trans()) {
- t_relay();
- }
- exit;
- }
- t_check_trans();
- # authentication
- route(AUTH);
- # record routing for dialog forming requests (in case they are routed)
- # - remove preloaded route headers
- remove_hf("Route");
- if (is_method("INVITE")) {
- record_route();
- }
- # handle registrations
- route(REGISTRAR);
- if ($rU==$null) {
- # request with no Username in RURI
- sl_send_reply("484", "Address Incomplete");
- exit;
- }
- # user location service
- route(LOCATION);
- route(RELAY);
- }
- route[RELAY] {
- if (!t_relay()) {
- sl_reply_error();
- }
- exit;
- }
- # Per SIP request initial checks
- route[REQINIT] {
- if (!mf_process_maxfwd_header("10")) {
- sl_send_reply("483", "Too Many Hops");
- exit;
- }
- if (!sanity_check("1511", "7")) {
- xlog("Malformed SIP message from $si:$sp\n");
- exit;
- }
- if (uri == myself && is_method("OPTIONS") && !(uri=~"sip:.*[@]+.*")) {
- options_reply();
- exit;
- }
- }
- # Handle requests within SIP dialogs
- route[WITHINDLG] {
- if (has_totag()) {
- # sequential request withing a dialog should
- # take the path determined by record-routing
- if (loose_route()) {
- #!ifdef WITH_WEBSOCKETS
- if ($du == "") {
- if (!handle_ruri_alias()) {
- xlog("L_ERR", "Bad alias <$ru>\n");
- sl_send_reply("400", "Bad Request");
- exit;
- }
- }
- #!endif
- route(RELAY);
- } else {
- if ( is_method("ACK") ) {
- if ( t_check_trans() ) {
- # no loose-route, but stateful ACK;
- # must be an ACK after a 487
- # or e.g. 404 from upstream server
- t_relay();
- exit;
- } else {
- # ACK without matching transaction...
- # ignore and discard
- exit;
- }
- }
- sl_send_reply("404", "Not Found");
- }
- exit;
- }
- }
- # Handle SIP registrations
- route[REGISTRAR] {
- if (is_method("REGISTER")) {
- if (!save("location")) {
- sl_reply_error();
- }
- exit;
- }
- }
- # USER location service
- route[LOCATION] {
- if (!is_subscriber("$ru", "subscriber", "1")) {
- t_newtran();
- send_reply("404", "Not Found");
- exit;
- }
- if (!lookup("location")) {
- $var(rc) = $rc;
- t_newtran();
- switch ($var(rc)) {
- case -1:
- send_reply("480", "Temporarily Unavailable");
- exit;
- case -2:
- send_reply("405", "Method Not Allowed");
- exit;
- case -3:
- send_reply("500", "Server Internal Error");
- exit;
- }
- }
- }
- # Authentication route
- route[AUTH] {
- if (is_method("REGISTER") || from_uri==myself) {
- # authenticate requests
- if (!auth_check("$fd", "subscriber", "1")) {
- auth_challenge("$fd", "0");
- exit;
- }
- # user authenticated - remove auth header
- if(!is_method("REGISTER")) {
- consume_credentials();
- }
- }
- # if caller is not local subscriber, then check if it calls
- # a local destination, otherwise deny, not an open relay here
- if (from_uri!=myself && uri!=myself) {
- sl_send_reply("403", "Forbidden");
- exit;
- }
- }
- #!ifdef WITH_WEBSOCKETS
- onreply_route {
- if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
- && !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) {
- xlog("L_WARN", "SIP response received on $Rp\n");
- drop;
- }
- if (nat_uac_test(64)) {
- # Do NAT traversal stuff for replies to a WebSocket connection
- # - even if it is not behind a NAT!
- # This won't be needed in the future if Kamailio and the
- # WebSocket client support Outbound and Path.
- add_contact_alias();
- }
- }
- event_route[xhttp:request] {
- set_reply_close();
- set_reply_no_connect();
-
- if ($Rp != MY_WS_PORT
- #!ifdef WITH_TLS
- && $Rp != MY_WSS_PORT
- #!endif
- ) {
- xlog("L_WARN", "HTTP request received on $Rp\n");
- xhttp_reply("403", "Forbidden", "", "");
- exit;
- }
- xlog("L_DBG", "HTTP Request Received\n");
- 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.
- if (ws_handle_handshake())
- {
- # Optional... cache some information about the
- # successful connection
- exit;
- }
- }
- xhttp_reply("404", "Not Found", "", "");
- }
- event_route[websocket:closed] {
- xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
- }
- #!endif
- #!ifdef WITH_MSRP
- event_route[msrp:frame-in] {
- msrp_reply_flags("1");
- if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT)
- && !(proto == WS || proto == WSS)) && $Rp != MY_MSRP_PORT) {
- xlog("L_WARN", "MSRP request received on $Rp\n");
- msrp_reply("403", "Action-not-allowed");
- exit;
- }
- if (msrp_is_reply()) {
- msrp_relay();
- } else if($msrp(method)=="AUTH") {
- if($msrp(nexthops)>0) {
- msrp_relay();
- exit;
- }
- if (!www_authenticate("MY_DOMAIN", "subscriber",
- "$msrp(method)")) {
- if (auth_get_www_authenticate("MY_DOMAIN", "1",
- "$var(wauth)")) {
- msrp_reply("401", "Unauthorized",
- "$var(wauth)");
- } else {
- msrp_reply("500", "Server Error");
- }
- exit;
- }
- if ($hdr(Expires) != $null) {
- $var(expires) = (int) $hdr(Expires);
- if ($var(expires) < MSRP_MIN_EXPIRES) {
- msrp_reply("423", "Interval Out-of-Bounds",
- "Min-Expires: MSRP_MIN_EXPIRES\r\n");
- exit;
- } else if ($var(expires) > MSRP_MAX_EXPIRES) {
- msrp_reply("423", "Interval Out-of-Bounds",
- "Max-Expires: MSRP_MAX_EXPIRES\r\n");
- exit;
- }
- } else {
- $var(expires) = MSRP_MAX_EXPIRES;
- }
- $var(cnt) = $var(cnt) + 1;
- pv_printf("$var(sessid)", "s.$(pp).$(var(cnt)).$(RANDOM)");
- $sht(msrp=>$var(sessid)::srcaddr) = $msrp(srcaddr);
- $sht(msrp=>$var(sessid)::srcsock) = $msrp(srcsock);
- $shtex(msrp=>$var(sessid)) = $var(expires) + 5;
- # - Use-Path: the MSRP address for server + session id
- $var(hdrs) = "Use-Path: msrps://MY_IP_ADDR:MY_MSRP_PORT/"
- + $var(sessid) + ";tcp\r\n"
- + "Expires: " + $var(expires) + "\r\n";
- msrp_reply("200", "OK", "$var(hdrs)");
- } else if ($msrp(method)=="SEND" || $msrp(method)=="REPORT") {
- if ($msrp(nexthops)>1) {
- if ($msrp(method)!="REPORT") {
- msrp_reply("200", "OK");
- }
- msrp_relay();
- exit;
- }
- $var(sessid) = $msrp(sessid);
- if ($sht(msrp=>$var(sessid)::srcaddr) == $null) {
- # one more hop, but we don't have address in htable
- msrp_reply("481", "Session-does-not-exist");
- exit;
- } else if ($msrp(method)!="REPORT") {
- msrp_reply("200", "OK");
- }
- msrp_relay_flags("1");
- msrp_set_dst("$sht(msrp=>$var(sessid)::srcaddr)",
- "$sht(msrp=>$var(sessid)::srcsock)");
- msrp_relay();
- } else {
- msrp_reply("501", "Request-method-not-understood");
- }
- }
- #!endif
|