From 180e1db2428f40e123e8470bdb4d0e52cf4c62f9 Mon Sep 17 00:00:00 2001 From: Carsten Bock Date: Mon, 19 Sep 2016 10:49:29 +0200 Subject: [PATCH] Proxy-CSCF Sample Config: Add missing routes (closes Issue #785) --- examples/pcscf/route/mo.cfg | 231 +++++++++++++++++++++++++++++ examples/pcscf/route/mt.cfg | 151 +++++++++++++++++++ examples/pcscf/route/register.cfg | 186 +++++++++++++++++++++++ examples/pcscf/route/rtp.cfg | 188 +++++++++++++++++++++++ examples/pcscf/route/websocket.cfg | 62 ++++++++ examples/pcscf/route/xmlrpc.cfg | 27 ++++ 6 files changed, 845 insertions(+) create mode 100644 examples/pcscf/route/mo.cfg create mode 100644 examples/pcscf/route/mt.cfg create mode 100644 examples/pcscf/route/register.cfg create mode 100644 examples/pcscf/route/rtp.cfg create mode 100644 examples/pcscf/route/websocket.cfg create mode 100644 examples/pcscf/route/xmlrpc.cfg diff --git a/examples/pcscf/route/mo.cfg b/examples/pcscf/route/mo.cfg new file mode 100644 index 00000000000..f00aad61fc4 --- /dev/null +++ b/examples/pcscf/route/mo.cfg @@ -0,0 +1,231 @@ +###################################################################### +# Originating, Intial Requests +###################################################################### +route[MO] +{ + # Strip Transport from RURI: + $ru = $(ru{re.subst,/;transport=[A-Za-z]*//g}); + + # Process route headers, if any: + loose_route(); + if (!pcscf_is_registered("location")) { + send_reply("403","Forbidden - You must register first with a S-CSCF"); + exit; + } + + # We do not trust the user, let's remove the P-Asserted-Identity, if any: + remove_hf("P-Asserted-Identity"); + remove_hf("P-Preferred-Identity"); + + # Add P-Charging-Vector + sip_p_charging_vector("g"); + + if (is_present_hf("P-Preferred-Identity") && pcscf_assert_identity("location", "$hdr(P-Preferred-Identity)")) { + append_hf("P-Asserted-Identity: $hdr(P-Preferred-Identity)\r\n"); + } else if (is_present_hf("P-Asserted-Identity") && pcscf_assert_identity("location", "$hdr(P-Asserted-Identity)")) { + append_hf("P-Asserted-Identity: $hdr(P-Asserted-Identity)\r\n"); + } else if (pcscf_assert_identity("location", "$(fu{tobody.uri})")) { + append_hf("P-Asserted-Identity: <$(fu{tobody.uri})>\r\n"); + } else { + append_hf("P-Asserted-Identity: <$pcscf_asserted_identity>\r\n"); + } + + if (!pcscf_follows_service_routes("location")){ + #Variant 1 - deny access to the network + #send_reply("400","Bad Request - Not following indicated service routes"); + #break; + + #Variant 2 - enforce routes and let the dialog continue + pcscf_force_service_routes("location"); + } + + # add IBCF/THIG route here if required + # Check for "sec-agree" in the Require header: + if (is_present_hf("Require") && $hdr(Require) =~ ".*sec-agree.*") { + # Remove the old Require-Header: + remove_hf("Require"); + # Replace ", sec-agree" with "" + $var(new_hdr) = $(hdr(Require){re.subst,/[, ]*sec-agree//gi}); + if ($(var(new_hdr){s.len}) > 0) { + append_hf("Require: $var(new_hdr)\r\n"); + } + } + + # Check for "sec-agree" in the Proxy-Require header: + if (is_present_hf("Proxy-Require") && $hdr(Proxy-Require) =~ ".*sec-agree.*") { + # Remove the old Proxy-Require-Header: + remove_hf("Proxy-Require"); + # Replace ", sec-agree" with "" + $var(new_hdr) = $(hdr(Proxy-Require){re.subst,/[, ]*sec-agree//gi}); + if ($(var(new_hdr){s.len}) > 0) { + append_hf("Proxy-Require: $var(new_hdr)\r\n"); + } + } + remove_hf("Security-Verify"); + +#!ifdef TRF_FUNCTION + $var(trf) = TRF_FUNCTION; + # Check for "sec-agree" in the Proxy-Require header: + if (is_present_hf("Feature-Caps")) { + # Remove the old Proxy-Require-Header: + remove_hf("Feature-Caps"); + append_hf("Feature-Caps: $hdr(Feature-Caps);+g.3gpp.trf=\"\"\r\n"); + } else { + append_hf("Feature-Caps: *;+g.3gpp.trf=\"\"\r\n"); + } +#!endif + # Add a visited Network-ID-Header: + if (is_present_hf("P-Visited-Network-ID")) { + $var(new_hdr) = "NETWORKNAME, "+$hdr(P-Visited-Network-ID); + append_hf("P-Visited-Network-ID: $var(new_hdr)\r\n"); + } else { + append_hf("P-Visited-Network-ID: NETWORKNAME\r\n"); + } + + + t_on_reply("MO_reply"); +} + +###################################################################### +# Replies to Originating Initial Requests +###################################################################### +onreply_route[MO_reply] { + if (is_present_hf("C-Params")) { + remove_hf("Contact"); + remove_hf("C-Params"); + append_hf("Contact: $ct;$hdr(C-Params)\r\n"); + } + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); +#!ifdef WITH_RX + if (t_check_status("183")){ + xlog("L_DBG", "IMS: Received 183/200 inside orig_initial_reply\n"); + + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG","Diameter: Orig authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + $var(aarret) = Rx_AAR("MO_aar_reply","orig"); + xlog("L_DBG", "AAR return code is $var(aarret)\n"); + + switch ($var(aarret)) { + case 1: + #suspend was successful and we must break + xlog("L_DBG", "Success sending AAR for media\n"); + exit; + + case -1: + #this is retransmitted response so we just drop it + xlog("L_DBG", "AAR still processing dropping retransmitted response\n"); + drop(); + exit; + + default: + xlog("L_ERR", "Unable to send AAR for media\n"); + #comment this if you want to allow even if Rx fails + dlg_terminate("all", "Sorry no QoS available"); + exit; + + } + } + +route[MO_aar_reply] +{ + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} + + +###################################################################### +# In-Dialog-Mo-Requests +###################################################################### +route[MO_indialog] { + setflag(FLT_MOBILE_ORIG); + t_on_reply("MO_indialog_reply"); +} + +onreply_route[MO_indialog_reply] { + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); + +#!ifdef WITH_RX + if(t_check_status("200") && is_method("INVITE")) { + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG", "IMS: ORIG_SUBSEQUENT reply. This is a 200 OK to a re-INVITE\n"); + xlog("L_DBG","Diameter: Orig authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + $var(aarret) = Rx_AAR("MO_indialog_aar_reply","orig"); + xlog("L_DBG", "AAR return code is $var(aarret)\n"); + + switch ($var(aarret)) { + case 1: + #suspend was successful and we must break + xlog("L_DBG", "Success sending AAR for media\n"); + exit; + + case -1: + #this is retransmitted response so we just drop it + xlog("L_DBG", "AAR still processing dropping retransmitted response\n"); + drop(); + exit; + + default: + xlog("L_ERR", "Unable to send AAR for media\n"); + #comment this if you want to allow even if Rx fails + dlg_terminate("all", "Sorry no QoS available"); + exit; + + } + } +} + +route[MO_indialog_aar_reply] +{ + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} diff --git a/examples/pcscf/route/mt.cfg b/examples/pcscf/route/mt.cfg new file mode 100644 index 00000000000..3ee9d66c523 --- /dev/null +++ b/examples/pcscf/route/mt.cfg @@ -0,0 +1,151 @@ +###################################################################### +# Terminating, Initial requests +###################################################################### +route[MT] { + t_on_reply("MT_reply"); +} + +###################################################################### +# Replies to Originating Initial Requests +###################################################################### +onreply_route[MT_reply] { + if (!strempty($(ct{tobody.params}))) { + append_hf("C-Params: $(ct{tobody.params})\r\n"); + } + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); +#!ifdef WITH_RX + if (t_check_status("183")){ + xlog("L_DBG", "IMS: Received 183 inside term_initial_reply\n"); + + xlog("L_DBG", "About to test if this is a retransmitted reply which is still currently suspended\n"); + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG","Diameter: Term authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + $var(aarret) = Rx_AAR("MT_aar_reply","term"); + xlog("L_DBG", "AAR return code is $var(aarret)\n"); + + switch ($var(aarret)) { + case 1: + #suspend was successful and we must break + xlog("L_DBG", "Success sending AAR for media\n"); + exit; + + case -1: + #this is retransmitted response so we just drop it + xlog("L_DBG", "AAR still processing dropping retransmitted response\n"); + drop(); + exit; + + default: + xlog("L_ERR", "Unable to send AAR for media\n"); + #comment this if you want to allow even if Rx fails + dlg_terminate("all", "Sorry no QoS available"); + exit; + + } + } +} + +route[MT_aar_reply] +{ + xlog("L_DBG", "IMS: TERM_SESSION_AAR_REPLY\n"); + + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} + + +###################################################################### +# In-Dialog-MT-Requests +###################################################################### +route[MT_indialog] { + t_on_reply("MT_indialog_reply"); +} + +onreply_route[MT_indialog_reply] { + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); + +#!ifdef WITH_RX + if(t_check_status("200") && is_method("INVITE")) { + if (t_is_retr_async_reply()) { + xlog("L_DBG", "Dropping retransmitted reply which is still currently suspended\n"); + drop(); + } + + xlog("L_DBG", "IMS: TERM_SUBSEQUENT reply. This is a 200 OK to a re-INVITE\n"); + xlog("L_DBG","Diameter: Term authorizing media via Rx\n"); + $avp(FTAG_CUSTOM_AVP)=$ft; + $avp(TTAG_CUSTOM_AVP)=$tt; + $avp(CALLID_CUSTOM_AVP)=$ci; + + $var(aarret) = Rx_AAR("MT_indialog_aar_reply","term"); + xlog("L_DBG", "AAR return code is $var(aarret)\n"); + + switch ($var(aarret)) { + case 1: + #suspend was successful and we must break + xlog("L_DBG", "Success sending AAR for media\n"); + exit; + + case -1: + #this is retransmitted response so we just drop it + xlog("L_DBG", "AAR still processing dropping retransmitted response\n"); + drop(); + exit; + + default: + xlog("L_ERR", "Unable to send AAR for media\n"); + #comment this if you want to allow even if Rx fails + dlg_terminate("all", "Sorry no QoS available"); + exit; + + } + } +} + +route[MT_indialog_aar_reply] +{ + #this is async so to know status we have to check the reply avp + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: Orig AAR success on media authorization\n"); + break; + default: + xlog("L_ERR", "IMS: AAR failed Orig\n"); + xlog("L_ERR", "IMS: ttag: "+ "$avp(TTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: ftag: "+ "$avp(FTAG_CUSTOM_AVP)"); + xlog("L_ERR", "IMS: callid: "+ "$avp(CALLID_CUSTOM_AVP)"); + #comment this if you want to allow even if Rx fails + if(dlg_get("$avp(CALLID_CUSTOM_AVP)","$avp(FTAG_CUSTOM_AVP)","$avp(TTAG_CUSTOM_AVP)")){ + dlg_terminate("all", "Sorry no QoS available"); + exit; + } + } +#!endif +} diff --git a/examples/pcscf/route/register.cfg b/examples/pcscf/route/register.cfg new file mode 100644 index 00000000000..df7ddcd1cdd --- /dev/null +++ b/examples/pcscf/route/register.cfg @@ -0,0 +1,186 @@ +###################################################################### +# Route for handling Registrations: +###################################################################### +route[REGISTER] { + # Provide some statistics + if ($sht(a=>$ci::start_time) == $null || $sht(a=>$ci::start_time) == 0) { + $sht(a=>$ci::start_time) = $TV(Sn); + } + + # Strip Transport from RURI: + $ru = $(ru{re.subst,/;transport=[A-Za-z]*//g}); + + if (is_present_hf("Contact")) { + pcscf_save_pending("location"); + } else { + send_reply("403", "No contact header"); + exit; + } + + + # Strip additional Tags from RURI: + if ($rU == $null) + $ru = "sip:"+$rd; + else + $ru = "sip:"+$rU+"@"+$rd; + +#!ifdef WITH_RX + xlog("L_DBG","Subscribing to signalling bearer status\n"); + + Rx_AAR_Register("REG_AAR_REPLY", "location"); + switch ($retcode) { + case -1: + # There was an error sending the AAR-Request: + xlog("L_ERR", "Diameter: AAR failed on subscription to signalling\n"); + send_reply("403", "Can't register to QoS for signalling"); + exit; + break; + case 0: + # We are waiting for an async reply, just exit here. + exit; + break; + case 1: + # We did not need to send AAR, so just continue as normal + route(REGISTER_CONTINUE); + break; + } + exit; +} + +route[REG_AAR_REPLY] { + switch ($avp(s:aar_return_code)) { + case 1: + xlog("L_DBG", "Diameter: AAR success on subscription to signalling\n"); + break; + default: + xlog("L_ERR", "Diameter: AAR failed on subscription to signalling\n"); + send_reply("403", "Can't register to QoS for signalling"); + exit; + } + # Proceed with Registering: + route(REGISTER_CONTINUE); +} + +route[REGISTER_CONTINUE] { +#!endif + append_hf("Path: \r\n"); + + remove_hf("Supported"); + append_hf("Supported: path\r\n"); + remove_hf("Require"); + append_hf("Require: path\r\n"); + + # Add a visited Network-ID-Header: + if (is_present_hf("P-Visited-Network-ID")) { + $var(new_hdr) = "NETWORKNAME, "+$hdr(P-Visited-Network-ID); + append_hf("P-Visited-Network-ID: $var(new_hdr)\r\n"); + } else { + append_hf("P-Visited-Network-ID: NETWORKNAME\r\n"); + } +#!ifdef WITH_SBC +#!ifndef WITH_SBC_CALL + t_on_failure("SBC_failure"); + # Choose an SBC to send the call to: + if (!ds_select_dst(DISPATCHER_LIST_SBC, "4")) { + send_reply("503", "Service Unavailable (SBC failure)"); + exit; + } +#!else + t_on_failure("REGISTER_failure"); +#!endif +#!else + t_on_failure("REGISTER_failure"); +#!endif + t_on_reply("REGISTER_reply"); + # Forward request: + route(RELAY); + exit; +} + +# Replies for REGISTER requests: +###################################################################### +onreply_route[REGISTER_reply] +{ +#!ifdef WITH_IMS_HDR_CACHE + if (is_present_hf("Service-Route")) { + $sht(serviceroutes=>$ci) = $hdr(Service-Route); + } else { + if ($sht(serviceroutes=>$ci) != $null) { + append_hf("Service-Route: $sht(serviceroutes=>$ci)\r\n"); + msg_apply_changes(); + } + } + if (is_present_hf("P-Associated-URI")) { + $sht(associateduris=>$ci) = $hdr(P-Associated-URI); + } else { + if ($sht(associateduris=>$ci) != $null) { + append_hf("P-Associated-URI: $sht(associateduris=>$ci)\r\n"); + msg_apply_changes(); + } + } +#!endif + + if (t_check_status("200")) { +#!ifdef WITH_IPBLOCK + $sht(failedauth=>$T_req($si)) = $null; +#!endif + pcscf_save("location"); +#!ifdef WITH_NATPING +#!ifdef WITH_PING_UDP + if ($T_req($pr) == "udp") { + $var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp); + $sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri}); + } +#!endif +#!ifdef WITH_PING_TCP + if ($T_req($pr) == "tcp") { + $var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp)+";transport=tcp"; + $sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri}); + } +#!endif +#!ifdef WITH_PING_TLS + if ($T_req($pr) == "tls") { + $var(ouri) = "sip:"+$T_req($si)+":"+$T_req($sp)+";transport=tls"; + $sht(natping=>$var(ouri)) = $(T_req($ct){nameaddr.uri}); + } +#!endif +#!endif + #update stats for register reply on success + $var(start_secs) = $(sht(a=>$ci::start_time){s.select,0,.}); + $var(start_usecs) = $(sht(a=>$ci::start_time){s.select,1,.}); + $var(diff_secs) = $TV(s) - $var(start_secs); + $var(diff_usecs) = $TV(u) - $var(start_usecs); + $var(diff_ms) = $var(diff_secs)*1000 + ($var(diff_usecs)/1000); + $sht(a=>$ci::start_time)=0; + $var(stat_add) = "+" + $var(diff_ms); + xlog("L_DBG", "REGISTER SUCCESS[$ci] took $var(stat_add)ms\n"); + update_stat("register_success", "+1"); + update_stat("register_time", "$var(stat_add)"); + } + exit; +} + +# Negative replies to REGISTER requests: +###################################################################### +failure_route[REGISTER_failure] +{ +#!ifdef WITH_IPBLOCK + if (t_check_status("403|[5-6][0-9][0-9]")) { + if ($sht(failedauth=>$si) != $null) + $sht(failedauth=>$si) = $sht(failedauth=>$si) + 1; + else + $sht(failedauth=>$si) = 1; + if ($sht(failedauth=>$si) > 10) { + xlog("L_ALERT","ALERT: blocking $rm from $fu (IP:$si:$sp), more than 5 failed auth requests!\n"); + xlog("Blocking traffic from $si\n"); + $sht(ipban=>$si) = 1; + } + update_stat("register_failed", "+1"); + } +#!endif + if (t_check_status("408")) { + send_reply("504","Server Time-Out"); + update_stat("register_failed", "+1"); + exit; + } +} diff --git a/examples/pcscf/route/rtp.cfg b/examples/pcscf/route/rtp.cfg new file mode 100644 index 00000000000..34b05c3d21e --- /dev/null +++ b/examples/pcscf/route/rtp.cfg @@ -0,0 +1,188 @@ +# RTPProxy control +route[ENC_SRTP] { + add_rr_param(";rm=1"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_SRTP] { + add_rr_param(";rm=2"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVP"; +} + +route[ENC_WS_RTP] { + add_rr_param(";rm=3"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force RTP AVPF"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_WS_RTP] { + add_rr_param(";rm=4"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force RTP AVPF"; +} + +route[ENC_WSS_RTP] { + add_rr_param(";rm=5"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVPF DTLS=passive"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_WSS_RTP] { + add_rr_param(";rm=6"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force SRTP AVPF DTLS=passive"; +} + +route[ENC_RTP] { + add_rr_param(";rm=7"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=force RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; +} + +route[DEC_RTP] { + add_rr_param(";rm=8"); + $avp(rtpproxy_offer_flags) = "replace-origin replace-session-connection ICE=remove RTP AVP"; + $avp(rtpproxy_answer_flags) = "replace-origin replace-session-connection ICE=force RTP AVP"; +} + +# RTPProxy control +route[NATMANAGE] { +#!ifdef WITH_DEBUG + if (is_request()) + xlog("REQUEST: $rm $ru ($si:$sp, $ci)\n"); + else + xlog("REPLY: $rs $rr ($rm, $si:$sp, $ci)\n"); + + if (is_direction("downstream")) + xlog(" downstream\n"); + else + xlog(" upstream\n"); + + xlog(" Offer: $avp(rtpproxy_offer_flags)\n"); + xlog(" Answer: $avp(rtpproxy_answer_flags)\n"); + if (isflagset(FLT_MOBILE_ORIG)) { + xlog(" mo\n"); + } else { + xlog(" mt\n"); + } +#!endif + if ((is_reply() && ($T_req($tt) != $null)) || (is_request() && has_totag())) { + xlog("L_DBG", "Request had ToTag."); + #if((is_request() && !check_route_param("rm=")) || (is_reply() && !isflagset(FLT_RTP))) { + if(!check_route_param("rm=") && !isflagset(FLT_RTP)) { + xlog("L_DBG", "No RM Param\n"); + return; + } + if (is_request()) { + if (isflagset(FLT_MOBILE_ORIG) && is_direction("downstream")) { + xlog("L_DBG", "1) add_contact_alias();"); + add_contact_alias(); + } else if (!isflagset(FLT_MOBILE_ORIG) && is_direction("upstream")) { + xlog("L_DBG", "2) add_contact_alias();"); + add_contact_alias(); + } + } else { + if (!isflagset(FLT_MOBILE_ORIG) && is_direction("downstream")) { + xlog("L_DBG", "1) ADD_contact_alias();"); + add_contact_alias(); + } else if (isflagset(FLT_MOBILE_ORIG) && is_direction("downstream")) { + xlog("L_DBG", "2) ADD_contact_alias();"); + add_contact_alias(); + } + } + } else { + if (is_reply() && !isflagset(FLT_MOBILE_ORIG)) { + xlog("L_DBG", "3) ADD_contact_alias();"); + add_contact_alias(); + } + } + + if (isflagset(FLT_MOBILE_ORIG)) { + $avp(setid) = 1; + $avp(extra_id) = "mo"; + } else { + $avp(setid) = 2; + $avp(extra_id) = "mt"; + } + + if(!t_is_set("onreply_route")) t_on_reply("NAT_REPLY"); + if(!t_is_set("failure_route")) t_on_failure("NATMANAGE"); + + if (is_method("BYE") || t_is_failure_route()) { + rtpengine_manage(); + return; + } + + setflag(FLT_RTP); + + if (!has_body("application/sdp")) + return; + +#!ifdef REMOVE_BITALIGNED_AMR + route(REMOVE_BITALIGNED); +#!endif + +#!ifndef FORCE_RTPRELAY + if (!isflagset(FLT_NAT) || !check_route_param("rm=")) + return; +#!endif + + if ((is_reply() && ($T_req($tt) != $null)) || (is_request() && has_totag())) { + rtpengine_manage(); + } else { + if ($avp(rtpproxy_offer_flags) == $null) + return; + if ($avp(rtpproxy_answer_flags) == $null) + return; + + if (is_request()) { + rtpengine_manage($avp(rtpproxy_offer_flags)); + } else { + rtpengine_manage($avp(rtpproxy_answer_flags)); + } + } +} + +# manage incoming replies +onreply_route[NAT_REPLY] { + # In case of 1xx and 2xx do NAT + if(status=~"[12][0-9][0-9]") + route(NATMANAGE); +} + +route[REMOVE_BITALIGNED] { + if (sdp_get_line_startswith("$avp(mline)", "m=")) { + # xlog("m-line: $avp(mline)\n"); + sdp_get("$avp(sdp)"); + # xlog("\n$avp(sdp)\n"); + $var(x) = -1; + $var(remove) = ""; + $var(codec) = $(avp(mline){s.select,$var(x), }); + # xlog("$$var(codec) => $var(codec)\n"); + while ($(var(codec){s.int}) > 0) { + # xlog("$var(x)) $$var(codec) => $var(codec)\n"); + $var(s) = "a=fmtp:"+$var(codec); + # xlog("$$var(s) => $var(s)\n"); + $var(fmtp) = $(avp(sdp){line.sw,$var(s)}); + # xlog("$$var(fmtp) => $var(fmtp)\n"); + if ($var(fmtp) =~ "a=fmtp:"+$var(codec)+" mode-change-capability.*") { + # xlog("Match: $var(codec)\n"); + if ($var(remove) == "") { + $var(remove) = $var(codec); + } else { + $var(remove) = $var(remove)+","+$var(codec); + } + } + $var(codec) = $(avp(mline){s.select,$var(x), }); + $var(x) = $var(x) - 1; + } + # xlog("$$var(remove) => $var(remove)\n"); + if ($var(remove) != "") { + sdp_remove_codecs_by_id($var(remove), "audio"); + msg_apply_changes(); + } + } +} + diff --git a/examples/pcscf/route/websocket.cfg b/examples/pcscf/route/websocket.cfg new file mode 100644 index 00000000000..1f5b70fd046 --- /dev/null +++ b/examples/pcscf/route/websocket.cfg @@ -0,0 +1,62 @@ +event_route[xhttp:request] { + set_reply_close(); + set_reply_no_connect(); + +#!ifdef WITH_XMLRPC + if ($hu =~ "^/RPC") { + route(XMLRPC); + exit; + } +#!endif + + 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 - HTTP request received on $Rp", "", ""); + exit; + } + + if ($hdr(Upgrade)=~"websocket" + && in_list("Upgrade", $hdr(Connection), ",") + && $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 - invalid host", "", ""); + exit; + } + +#!ifdef WEBSOCKET_WEBSERVER + # Validate Origin - make sure the client is from the authorised website + if ($hdr(Origin) != "http://"+WEBSOCKET_WEBSERVER +#!ifdef WITH_TLS + && $hdr(Origin) != "https://"+WEBSOCKET_WEBSERVER +#!endif + ) { + xlog("L_WARN", "Unauthorised client $hdr(Origin)\n"); + xhttp_reply("403", "Forbidden - invalid website", "", ""); + exit; + } +#!endif + + # 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("200", "OK", "text/html", "Wrong URL $hu"); + xhttp_reply("404", "Not Found", "", ""); +} + +event_route[websocket:closed] { + xlog("L_DBG", "WebSocket connection from $si:$sp has closed\n"); +} diff --git a/examples/pcscf/route/xmlrpc.cfg b/examples/pcscf/route/xmlrpc.cfg new file mode 100644 index 00000000000..50571c0792e --- /dev/null +++ b/examples/pcscf/route/xmlrpc.cfg @@ -0,0 +1,27 @@ +# XMLRPC routing +route[XMLRPC] { + # allow XMLRPC from localhost + if ((method=="POST" || method=="GET") +#!ifdef XMLRPC_WHITELIST_1 +&& ((src_ip == XMLRPC_WHITELIST_1) +#!ifdef XMLRPC_WHITELIST_2 + || (src_ip == XMLRPC_WHITELIST_2) +#!endif +#!ifdef XMLRPC_WHITELIST_3 + || (src_ip == XMLRPC_WHITELIST_3) +#!endif +) +#!endif +) { + # close connection only for xmlrpclib user agents (there is a bug in + # xmlrpclib: it waits for EOF before interpreting the response). + if ($hdr(User-Agent) =~ "xmlrpclib") + set_reply_close(); + set_reply_no_connect(); + dispatch_rpc(); + exit; + } + send_reply("403", "Forbidden"); + exit; +} +