res_pjsip_stir_shaken.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2020, Sangoma Technologies Corporation
  5. *
  6. * Ben Ford <bford@sangoma.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*** MODULEINFO
  19. <depend>pjproject</depend>
  20. <depend>res_pjsip</depend>
  21. <depend>res_pjsip_session</depend>
  22. <depend>res_stir_shaken</depend>
  23. <support_level>core</support_level>
  24. ***/
  25. #include "asterisk.h"
  26. #define _TRACE_PREFIX_ "pjss",__LINE__, ""
  27. #include "asterisk/callerid.h"
  28. #include "asterisk/res_pjsip.h"
  29. #include "asterisk/res_pjsip_session.h"
  30. #include "asterisk/module.h"
  31. #include "asterisk/rtp_engine.h"
  32. #include "asterisk/res_stir_shaken.h"
  33. static const pj_str_t identity_hdr_str = { "Identity", 8 };
  34. static const pj_str_t date_hdr_str = { "Date", 4 };
  35. /* Response codes from RFC8224 */
  36. enum sip_response_code {
  37. SIP_RESPONSE_CODE_OK = 200,
  38. SIP_RESPONSE_CODE_STALE_DATE = 403,
  39. SIP_RESPONSE_CODE_USE_IDENTITY_HEADER = 428,
  40. SIP_RESPONSE_CODE_BAD_IDENTITY_INFO = 436,
  41. SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL = 437,
  42. SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER = 438,
  43. SIP_RESPONSE_CODE_USE_SUPPORTED_PASSPORT_FORMAT = 428,
  44. SIP_RESPONSE_CODE_INTERNAL_ERROR = 500,
  45. };
  46. #define SIP_RESPONSE_CODE_OK_STR "OK"
  47. /* Response strings from RFC8224 */
  48. #define SIP_RESPONSE_CODE_STALE_DATE_STR "Stale Date"
  49. #define SIP_RESPONSE_CODE_USE_IDENTITY_HEADER_STR "Use Identity Header"
  50. #define SIP_RESPONSE_CODE_USE_SUPPORTED_PASSPORT_FORMAT_STR "Use Supported PASSporT Format"
  51. #define SIP_RESPONSE_CODE_BAD_IDENTITY_INFO_STR "Bad Identity Info"
  52. #define SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL_STR "Unsupported Credential"
  53. #define SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER_STR "Invalid Identity Header"
  54. #define SIP_RESPONSE_CODE_INTERNAL_ERROR_STR "Internal Error"
  55. #define response_to_str(_code) \
  56. case _code: \
  57. return _code ## _STR;
  58. static const char *sip_response_code_to_str(enum sip_response_code code)
  59. {
  60. switch (code) {
  61. response_to_str(SIP_RESPONSE_CODE_OK)
  62. response_to_str(SIP_RESPONSE_CODE_STALE_DATE)
  63. response_to_str(SIP_RESPONSE_CODE_USE_IDENTITY_HEADER)
  64. response_to_str(SIP_RESPONSE_CODE_BAD_IDENTITY_INFO)
  65. response_to_str(SIP_RESPONSE_CODE_UNSUPPORTED_CREDENTIAL)
  66. response_to_str(SIP_RESPONSE_CODE_INVALID_IDENTITY_HEADER)
  67. default:
  68. break;
  69. }
  70. return "";
  71. }
  72. #define translate_code(_vs_rc, _sip_rc) \
  73. case AST_STIR_SHAKEN_VS_ ## _vs_rc: \
  74. return SIP_RESPONSE_CODE_ ## _sip_rc;
  75. static enum sip_response_code vs_code_to_sip_code(
  76. enum ast_stir_shaken_vs_response_code vs_rc)
  77. {
  78. /*
  79. * We want to use a switch/case statement here because
  80. * it'll spit out an error if VS codes are added to the
  81. * enum but aren't present here.
  82. */
  83. switch (vs_rc) {
  84. translate_code(SUCCESS, OK)
  85. translate_code(DISABLED, OK)
  86. translate_code(INVALID_ARGUMENTS, INTERNAL_ERROR)
  87. translate_code(INTERNAL_ERROR, INTERNAL_ERROR)
  88. translate_code(NO_IDENTITY_HDR, USE_IDENTITY_HEADER)
  89. translate_code(NO_DATE_HDR, STALE_DATE)
  90. translate_code(DATE_HDR_PARSE_FAILURE, STALE_DATE)
  91. translate_code(DATE_HDR_EXPIRED, STALE_DATE)
  92. translate_code(NO_JWT_HDR, INVALID_IDENTITY_HEADER)
  93. translate_code(INVALID_OR_NO_X5U, INVALID_IDENTITY_HEADER)
  94. translate_code(CERT_CACHE_MISS, INVALID_IDENTITY_HEADER)
  95. translate_code(CERT_CACHE_INVALID, INVALID_IDENTITY_HEADER)
  96. translate_code(CERT_CACHE_EXPIRED, INVALID_IDENTITY_HEADER)
  97. translate_code(CERT_RETRIEVAL_FAILURE, BAD_IDENTITY_INFO)
  98. translate_code(CERT_CONTENTS_INVALID, UNSUPPORTED_CREDENTIAL)
  99. translate_code(CERT_NOT_TRUSTED, UNSUPPORTED_CREDENTIAL)
  100. translate_code(CERT_DATE_INVALID, UNSUPPORTED_CREDENTIAL)
  101. translate_code(CERT_NO_TN_AUTH_EXT, UNSUPPORTED_CREDENTIAL)
  102. translate_code(CERT_NO_SPC_IN_TN_AUTH_EXT, UNSUPPORTED_CREDENTIAL)
  103. translate_code(NO_RAW_KEY, UNSUPPORTED_CREDENTIAL)
  104. translate_code(SIGNATURE_VALIDATION, INVALID_IDENTITY_HEADER)
  105. translate_code(NO_IAT, INVALID_IDENTITY_HEADER)
  106. translate_code(IAT_EXPIRED, STALE_DATE)
  107. translate_code(INVALID_OR_NO_PPT, INVALID_IDENTITY_HEADER)
  108. translate_code(INVALID_OR_NO_ALG, INVALID_IDENTITY_HEADER)
  109. translate_code(INVALID_OR_NO_TYP, INVALID_IDENTITY_HEADER)
  110. translate_code(INVALID_OR_NO_ATTEST, INVALID_IDENTITY_HEADER)
  111. translate_code(NO_ORIGID, INVALID_IDENTITY_HEADER)
  112. translate_code(NO_ORIG_TN, INVALID_IDENTITY_HEADER)
  113. translate_code(NO_DEST_TN, INVALID_IDENTITY_HEADER)
  114. translate_code(INVALID_HEADER, INVALID_IDENTITY_HEADER)
  115. translate_code(INVALID_GRANT, INVALID_IDENTITY_HEADER)
  116. translate_code(INVALID_OR_NO_GRANTS, INVALID_IDENTITY_HEADER)
  117. translate_code(CID_ORIG_TN_MISMATCH, INVALID_IDENTITY_HEADER)
  118. translate_code(RESPONSE_CODE_MAX, INVALID_IDENTITY_HEADER)
  119. }
  120. return 500;
  121. }
  122. enum process_failure_rc {
  123. PROCESS_FAILURE_CONTINUE = 0,
  124. PROCESS_FAILURE_REJECT,
  125. PROCESS_FAILURE_SYSTEM_FAILURE,
  126. };
  127. static void reject_incoming_call(struct ast_sip_session *session,
  128. enum sip_response_code response_code)
  129. {
  130. ast_sip_session_terminate(session, response_code);
  131. ast_hangup(session->channel);
  132. }
  133. static enum process_failure_rc process_failure(struct ast_stir_shaken_vs_ctx *ctx,
  134. const char *caller_id, struct ast_sip_session *session,
  135. pjsip_rx_data *rdata, enum ast_stir_shaken_vs_response_code vs_rc)
  136. {
  137. enum sip_response_code response_code = vs_code_to_sip_code(vs_rc);
  138. pj_str_t response_str;
  139. const char *response_string =
  140. sip_response_code_to_str(response_code);
  141. enum stir_shaken_failure_action_enum failure_action =
  142. ast_stir_shaken_vs_get_failure_action(ctx);
  143. const char *tag = ast_sip_session_get_name(session);
  144. SCOPE_ENTER(1, "%s: FA: %d RC: %d\n", tag,
  145. failure_action, response_code);
  146. pj_cstr(&response_str, response_string);
  147. if (failure_action == stir_shaken_failure_action_REJECT_REQUEST) {
  148. reject_incoming_call(session, response_code);
  149. SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_REJECT,
  150. "%s: Rejecting request and terminating session\n",
  151. tag);
  152. }
  153. ast_stir_shaken_vs_ctx_set_response_code(ctx, vs_rc);
  154. ast_stir_shaken_add_result_to_channel(ctx);
  155. if (failure_action == stir_shaken_failure_action_CONTINUE_RETURN_REASON) {
  156. int rc = ast_sip_session_add_reason_header(session,
  157. ast_stir_shaken_vs_get_use_rfc9410_responses(ctx) ? "STIR" : "SIP",
  158. response_code, response_str.ptr);
  159. if (rc != 0) {
  160. SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_SYSTEM_FAILURE,
  161. "%s: Failed to add Reason header\n", tag);
  162. }
  163. SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_CONTINUE,
  164. "%s: Attaching reason code to session\n", tag);
  165. }
  166. SCOPE_EXIT_RTN_VALUE(PROCESS_FAILURE_CONTINUE,
  167. "%s: Continuing\n", tag);
  168. }
  169. /*!
  170. * \internal
  171. * \brief Session supplement callback on an incoming INVITE request
  172. *
  173. * When we receive an INVITE, check it for STIR/SHAKEN information and
  174. * decide what to do from there
  175. *
  176. * \param session The session that has received an INVITE
  177. * \param rdata The incoming INVITE
  178. */
  179. static int stir_shaken_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
  180. {
  181. RAII_VAR(struct ast_stir_shaken_vs_ctx *, ctx, NULL, ao2_cleanup);
  182. RAII_VAR(char *, header, NULL, ast_free);
  183. RAII_VAR(char *, payload, NULL, ast_free);
  184. char *identity_hdr_val;
  185. char *date_hdr_val;
  186. char *caller_id = session->id.number.str;
  187. const char *session_name = ast_sip_session_get_name(session);
  188. struct ast_channel *chan = session->channel;
  189. enum ast_stir_shaken_vs_response_code vs_rc;
  190. enum process_failure_rc p_rc;
  191. SCOPE_ENTER(1, "%s: Enter\n", session_name);
  192. if (!session) {
  193. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "No session\n");
  194. }
  195. if (!session->channel) {
  196. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No channel\n", session_name);
  197. }
  198. if (!rdata) {
  199. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No rdata\n", session_name);
  200. }
  201. /* Check if this is a reinvite. If it is, we don't need to do anything */
  202. if (rdata->msg_info.to->tag.slen) {
  203. SCOPE_EXIT_RTN_VALUE(0, "%s: Reinvite. No action needed\n", session_name);
  204. }
  205. /*
  206. * Shortcut: If there's no callerid or profile name,
  207. * just bail now.
  208. */
  209. if (ast_strlen_zero(caller_id)
  210. || ast_strlen_zero(session->endpoint->stir_shaken_profile)) {
  211. SCOPE_EXIT_RTN_VALUE(0, "%s: No callerid or profile name. No action needed\n", session_name);
  212. }
  213. vs_rc = ast_stir_shaken_vs_ctx_create(caller_id, chan,
  214. session->endpoint->stir_shaken_profile,
  215. session_name, &ctx);
  216. if (vs_rc == AST_STIR_SHAKEN_VS_DISABLED) {
  217. SCOPE_EXIT_RTN_VALUE(0, "%s: VS Disabled\n", session_name);
  218. } else if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
  219. reject_incoming_call(session, 500);
  220. SCOPE_EXIT_RTN_VALUE(1, "%s: Unable to create context. Call terminated\n",
  221. session_name);
  222. }
  223. identity_hdr_val = ast_sip_rdata_get_header_value(rdata, identity_hdr_str);
  224. if (ast_strlen_zero(identity_hdr_val)) {
  225. p_rc = process_failure(ctx, caller_id, session, rdata,
  226. AST_STIR_SHAKEN_VS_NO_IDENTITY_HDR);
  227. if (p_rc == PROCESS_FAILURE_CONTINUE) {
  228. SCOPE_EXIT_RTN_VALUE(0, "%s: No Identity header found. Call continuing\n",
  229. session_name);
  230. }
  231. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No Identity header found. Call terminated\n",
  232. session_name);
  233. }
  234. vs_rc = ast_stir_shaken_vs_ctx_add_identity_hdr(ctx, identity_hdr_val);
  235. if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
  236. reject_incoming_call(session, 500);
  237. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Unable to add Identity header. Call terminated.\n",
  238. session_name);
  239. }
  240. date_hdr_val = ast_sip_rdata_get_header_value(rdata, date_hdr_str);
  241. if (ast_strlen_zero(date_hdr_val)) {
  242. p_rc = process_failure(ctx, caller_id, session, rdata,
  243. AST_STIR_SHAKEN_VS_NO_DATE_HDR);
  244. if (p_rc == PROCESS_FAILURE_CONTINUE) {
  245. SCOPE_EXIT_RTN_VALUE(0, "%s: No Date header found. Call continuing\n",
  246. session_name);
  247. }
  248. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No Date header found. Call terminated\n",
  249. session_name);
  250. }
  251. ast_stir_shaken_vs_ctx_add_date_hdr(ctx, date_hdr_val);
  252. if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
  253. reject_incoming_call(session, 500);
  254. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Unable to add Date header. Call terminated.\n",
  255. session_name);
  256. }
  257. vs_rc = ast_stir_shaken_vs_verify(ctx);
  258. if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
  259. p_rc = process_failure(ctx, caller_id, session, rdata, vs_rc);
  260. if (p_rc == PROCESS_FAILURE_CONTINUE) {
  261. SCOPE_EXIT_RTN_VALUE(0, "%s: Verification failed. Call continuing\n",
  262. session_name);
  263. }
  264. SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Verification failed. Call terminated\n",
  265. session_name);
  266. }
  267. ast_stir_shaken_add_result_to_channel(ctx);
  268. SCOPE_EXIT_RTN_VALUE(0, "Passed\n");
  269. }
  270. static void add_fingerprints_if_present(struct ast_sip_session *session,
  271. struct ast_stir_shaken_as_ctx *ctx)
  272. {
  273. struct ast_sip_session_media_state *ms = session->pending_media_state;
  274. struct ast_sip_session_media *m = NULL;
  275. struct ast_rtp_engine_dtls *d = NULL;
  276. enum ast_rtp_dtls_hash h;
  277. int i;
  278. const char *tag = ast_sip_session_get_name(session);
  279. size_t count = AST_VECTOR_SIZE(&ms->sessions);
  280. SCOPE_ENTER(4, "%s: Check %zu media sessions for fingerprints\n",
  281. tag, count);
  282. if (!ast_stir_shaken_as_ctx_wants_fingerprints(ctx)) {
  283. SCOPE_EXIT_RTN("%s: Fingerprints not needed\n", tag);
  284. }
  285. for (i = 0; i < count; i++) {
  286. const char *f;
  287. m = AST_VECTOR_GET(&ms->sessions, i);
  288. if (!m|| !m->rtp) {
  289. ast_trace(1, "Session: %d: No session or rtp instance\n", i);
  290. continue;
  291. }
  292. d = ast_rtp_instance_get_dtls(m->rtp);
  293. h = d->get_fingerprint_hash(m->rtp);
  294. f = d->get_fingerprint(m->rtp);
  295. ast_stir_shaken_as_ctx_add_fingerprint(ctx,
  296. h == AST_RTP_DTLS_HASH_SHA256 ? "sha-256" : "sha-1", f);
  297. }
  298. SCOPE_EXIT_RTN("%s: Done\n", tag);
  299. }
  300. static char *get_dest_tn(pjsip_tx_data *tdata, const char *tag)
  301. {
  302. pjsip_fromto_hdr *to;
  303. pjsip_sip_uri *uri;
  304. char *dest_tn = NULL;
  305. SCOPE_ENTER(4, "%s: Enter\n", tag);
  306. to = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);
  307. if (!to) {
  308. SCOPE_EXIT_RTN_VALUE(NULL, "%s: Failed to find To header\n", tag);
  309. }
  310. uri = pjsip_uri_get_uri(to->uri);
  311. if (!uri) {
  312. SCOPE_EXIT_RTN_VALUE(NULL,
  313. "%s: Failed to retrieve URI from To header\n", tag);
  314. }
  315. dest_tn = ast_malloc(uri->user.slen + 1);
  316. if (!dest_tn) {
  317. SCOPE_EXIT_RTN_VALUE(NULL,
  318. "%s: Failed to allocate memory for dest_tn\n", tag);
  319. }
  320. ast_copy_pj_str(dest_tn, &uri->user, uri->user.slen + 1);
  321. SCOPE_EXIT_RTN_VALUE(dest_tn, "%s: Done\n", tag);
  322. }
  323. static void add_date_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)
  324. {
  325. pjsip_fromto_hdr *old_date;
  326. const char *session_name = ast_sip_session_get_name(session);
  327. SCOPE_ENTER(1, "%s: Enter\n", session_name);
  328. old_date = pjsip_msg_find_hdr_by_name(tdata->msg, &date_hdr_str, NULL);
  329. if (old_date) {
  330. SCOPE_EXIT_RTN("Found existing Date header, no need to add one\n");
  331. }
  332. ast_sip_add_date_header(tdata);
  333. SCOPE_EXIT_RTN("Done\n");
  334. }
  335. static void stir_shaken_outgoing_request(struct ast_sip_session *session,
  336. pjsip_tx_data *tdata)
  337. {
  338. struct ast_party_id effective_id;
  339. struct ast_party_id connected_id;
  340. pjsip_generic_string_hdr *old_identity;
  341. pjsip_generic_string_hdr *identity_hdr;
  342. pj_str_t identity_val;
  343. char *dest_tn;
  344. char *identity_str;
  345. struct ast_stir_shaken_as_ctx *ctx = NULL;
  346. enum ast_stir_shaken_as_response_code as_rc;
  347. const char *session_name = ast_sip_session_get_name(session);
  348. SCOPE_ENTER(1, "%s: Enter\n", session_name);
  349. if (!session) {
  350. SCOPE_EXIT_LOG_RTN(LOG_ERROR, "No session\n");
  351. }
  352. if (!session->channel) {
  353. SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: No channel\n", session_name);
  354. }
  355. if (!tdata) {
  356. SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: No tdata\n", session_name);
  357. }
  358. old_identity = pjsip_msg_find_hdr_by_name(tdata->msg, &identity_hdr_str, NULL);
  359. if (old_identity) {
  360. SCOPE_EXIT_RTN("Found an existing Identity header\n");
  361. }
  362. dest_tn = get_dest_tn(tdata, session_name);
  363. if (!dest_tn) {
  364. SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to find destination tn\n",
  365. session_name);
  366. }
  367. ast_party_id_init(&connected_id);
  368. ast_channel_lock(session->channel);
  369. effective_id = ast_channel_connected_effective_id(session->channel);
  370. ast_party_id_copy(&connected_id, &effective_id);
  371. ast_channel_unlock(session->channel);
  372. if (!ast_sip_can_present_connected_id(session, &connected_id)) {
  373. ast_free(dest_tn);
  374. ast_party_id_free(&connected_id);
  375. SCOPE_EXIT_RTN("Unable to get caller id\n");
  376. }
  377. as_rc = ast_stir_shaken_as_ctx_create(connected_id.number.str,
  378. dest_tn, session->channel,
  379. session->endpoint->stir_shaken_profile,
  380. session_name, &ctx);
  381. ast_free(dest_tn);
  382. ast_party_id_free(&connected_id);
  383. if (as_rc == AST_STIR_SHAKEN_AS_DISABLED) {
  384. SCOPE_EXIT_RTN("%s: AS Disabled\n", session_name);
  385. } else if (as_rc != AST_STIR_SHAKEN_AS_SUCCESS) {
  386. SCOPE_EXIT_RTN("%s: Unable to create context\n",
  387. session_name);
  388. }
  389. add_date_header(session, tdata);
  390. add_fingerprints_if_present(session, ctx);
  391. as_rc = ast_stir_shaken_attest(ctx, &identity_str);
  392. if (as_rc != AST_STIR_SHAKEN_AS_SUCCESS) {
  393. ao2_cleanup(ctx);
  394. SCOPE_EXIT_LOG(LOG_ERROR,
  395. "%s: Failed to create attestation\n", session_name);
  396. }
  397. ast_trace(1, "%s: Identity header: %s\n", session_name, identity_str);
  398. identity_val = pj_str(identity_str);
  399. identity_hdr = pjsip_generic_string_hdr_create(tdata->pool, &identity_hdr_str, &identity_val);
  400. ast_free(identity_str);
  401. if (!identity_hdr) {
  402. ao2_cleanup(ctx);
  403. SCOPE_EXIT_LOG_RTN(LOG_ERROR,
  404. "%s: Unable to create Identity header\n", session_name);
  405. }
  406. pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)identity_hdr);
  407. ao2_cleanup(ctx);
  408. SCOPE_EXIT_RTN("Done\n");
  409. }
  410. static struct ast_sip_session_supplement stir_shaken_supplement = {
  411. .method = "INVITE",
  412. .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1, /* Run AFTER channel creation */
  413. .incoming_request = stir_shaken_incoming_request,
  414. .outgoing_request = stir_shaken_outgoing_request,
  415. };
  416. static int unload_module(void)
  417. {
  418. ast_sip_session_unregister_supplement(&stir_shaken_supplement);
  419. return 0;
  420. }
  421. static int load_module(void)
  422. {
  423. ast_sip_session_register_supplement(&stir_shaken_supplement);
  424. return AST_MODULE_LOAD_SUCCESS;
  425. }
  426. #undef AST_BUILDOPT_SUM
  427. #define AST_BUILDOPT_SUM ""
  428. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP STIR/SHAKEN Module for Asterisk",
  429. .support_level = AST_MODULE_SUPPORT_CORE,
  430. .load = load_module,
  431. .unload = unload_module,
  432. .load_pri = AST_MODPRI_DEFAULT,
  433. .requires = "res_pjsip,res_pjsip_session,res_stir_shaken",
  434. );