From 40ef42ff3ac6d7df1bb191636ed38e391e851f31 Mon Sep 17 00:00:00 2001
From: Grzegorz Sluja <grzegorz.sluja@iopsys.eu>
Date: Mon, 12 Dec 2022 13:36:40 +0000
Subject: [PATCH] Respond to requests only from the configured SIP proxy

An incoming SIP request will be silently dropped if the following conditions are all met:
- The request is about to create a new session
- The source IP address of the request is not the address of the configured proxy

Note
- The source port of the request is not checked since we have not found the good way to
  retrieve the port that is used for transmission
- If the configured proxy is a domain name other than IP address, the resolved IP address
  might be different from the one which is being used in existing sessions
---
 channels/chan_pjsip.c         | 27 +++++++++++++++++++++++++++
 include/asterisk/res_pjsip.h  |  7 +++++++
 res/res_pjsip/config_global.c | 19 +++++++++++++++++++
 3 files changed, 53 insertions(+)

diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 674af7786d..782fba28c3 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -3157,6 +3157,33 @@ static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct p
 		SCOPE_EXIT_RTN_VALUE(0, "%s: No channel\n", ast_sip_session_get_name(session));
 	}
 
+	if (ast_sip_get_accept_proxy_req_only() &&
+	    session->inv_session->dlg && session->inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
+		char buf[256];
+		struct ast_sockaddr resolved_addr;
+
+		pj_sockaddr_print(&rdata->pkt_info.src_addr, buf, sizeof(buf), 3);
+		ast_log(LOG_NOTICE, "Request received from address: <%s>\n", buf);
+
+		resolved_addr.ss.ss_family = AST_AF_UNSPEC;
+		if (ast_get_ip(&resolved_addr, session->endpoint->fromdomain)) {
+			ast_log(LOG_ERROR, "Could not resolve the domain name: %s\n", session->endpoint->fromdomain);
+		} else {
+			pj_sockaddr proxy_addr;
+
+			ast_sockaddr_to_pj_sockaddr(&resolved_addr, &proxy_addr);
+			pj_sockaddr_set_port(&proxy_addr, rdata->pkt_info.src_port);
+
+			pj_sockaddr_print(&proxy_addr, buf, sizeof(buf), 3);
+			ast_log(LOG_NOTICE, "Outgoing proxy address: <%s>\n", buf);
+
+			if (pj_sockaddr_cmp(&rdata->pkt_info.src_addr, &proxy_addr)) {
+				ast_sip_session_terminate(session, 400);
+				SCOPE_EXIT_RTN_VALUE(-1, "%s: Request not from Outgoing SIP proxy. Terminating session\n", ast_sip_session_get_name(session));
+			}
+		}
+	}
+
 	/* Check for a to-tag to determine if this is a reinvite */
 	if (rdata->msg_info.to->tag.slen) {
 		/* Weird case. We've received a reinvite but we don't have a channel. The most
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 72c3416bd2..758176dc8f 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -3089,6 +3089,13 @@ unsigned int ast_sip_get_mwi_disable_initial_unsolicited(void);
  */
 unsigned int ast_sip_get_use_callerid_contact(void);
 
+/*!
+ * \brief Retrieve the global setting 'accept_proxy_req_only'.
+ *
+ * \retval value of accept_proxy_req_only
+ */
+unsigned int ast_sip_get_accept_proxy_req_only(void);
+
 /*!
  * \brief Retrieve the global setting 'norefersub'.
  *
diff --git a/res/res_pjsip/config_global.c b/res/res_pjsip/config_global.c
index 5bc1cc6704..ce2146a44d 100644
--- a/res/res_pjsip/config_global.c
+++ b/res/res_pjsip/config_global.c
@@ -50,6 +50,7 @@
 #define DEFAULT_MWI_DISABLE_INITIAL_UNSOLICITED 0
 #define DEFAULT_IGNORE_URI_USER_OPTIONS 0
 #define DEFAULT_USE_CALLERID_CONTACT 0
+#define DEFAULT_ACCEPT_PROXY_REQ_ONLY 0
 #define DEFAULT_SEND_CONTACT_STATUS_ON_UPDATE_REGISTRATION 0
 #define DEFAULT_TASKPROCESSOR_OVERLOAD_TRIGGER TASKPROCESSOR_OVERLOAD_TRIGGER_GLOBAL
 #define DEFAULT_NOREFERSUB 1
@@ -116,6 +117,7 @@ struct global_config {
 	enum ast_sip_taskprocessor_overload_trigger overload_trigger;
 	/*! Nonzero if norefersub is to be sent in Supported header */
 	unsigned int norefersub;
+	unsigned int accept_proxy_req_only;
 };
 
 static void global_destructor(void *obj)
@@ -474,6 +476,21 @@ unsigned int ast_sip_get_use_callerid_contact(void)
 	return use_callerid_contact;
 }
 
+unsigned int ast_sip_get_accept_proxy_req_only(void)
+{
+	unsigned int accept_proxy_req_only;
+	struct global_config *cfg;
+
+	cfg = get_global_cfg();
+	if (!cfg) {
+		return DEFAULT_ACCEPT_PROXY_REQ_ONLY;
+	}
+
+	accept_proxy_req_only = cfg->accept_proxy_req_only;
+	ao2_ref(cfg, -1);
+	return accept_proxy_req_only;
+}
+
 unsigned int ast_sip_get_send_contact_status_on_update_registration(void)
 {
 	unsigned int send_contact_status_on_update_registration;
@@ -723,6 +740,8 @@ int ast_sip_initialize_sorcery_global(void)
 	ast_sorcery_object_field_register(sorcery, "global", "norefersub",
 		DEFAULT_NOREFERSUB ? "yes" : "no",
 		OPT_YESNO_T, 1, FLDSET(struct global_config, norefersub));
+	ast_sorcery_object_field_register(sorcery, "global", "accept_proxy_req_only",
+		DEFAULT_ACCEPT_PROXY_REQ_ONLY, OPT_UINT_T, 0, FLDSET(struct global_config, accept_proxy_req_only));
 
 	if (ast_sorcery_instance_observer_add(sorcery, &observer_callbacks_global)) {
 		return -1;
-- 
GitLab