Asterisk - The Open Source Telephony Project GIT-master-7e7a603
res_pjsip_rfc3329.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2022, Commend International
5 *
6 * Maximilian Fridrich <m.fridrich@commend.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
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjsip</depend>
22 <depend>res_pjsip_session</depend>
23 <support_level>core</support_level>
24 ***/
25
26#include "asterisk.h"
27
28#include <pjsip.h>
29#include <pjsip_ua.h>
30
31#include "asterisk/res_pjsip.h"
33#include "asterisk/module.h"
34#include "asterisk/causes.h"
35#include "asterisk/threadpool.h"
36
37/*! \brief Private data structure used with the modules's datastore */
40};
41
42static void datastore_destroy_cb(void *data)
43{
44 struct rfc3329_store_data *d = data;
45 if (d) {
46 ast_free(d);
47 }
48}
49
50/*! \brief The channel datastore the module uses to store state */
52 .type = "rfc3329_store",
53 .destroy = datastore_destroy_cb
54};
55
56static void rfc3329_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
57{
58 RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "rfc3329_store"), ao2_cleanup);
59 static const pj_str_t str_security_server = { "Security-Server", 15 };
60 struct ast_sip_contact_status *contact_status = NULL;
61 struct ast_sip_security_mechanism *mech;
62 struct rfc3329_store_data *store_data;
63 pjsip_generic_string_hdr *header;
64 char buf[128];
65 char *hdr_val;
66 char *mechanism;
67
68 if (!session || !session->endpoint || !session->endpoint->security_negotiation
69 || !session->contact || !(contact_status = ast_sip_get_contact_status(session->contact))
70 || !session->inv_session->dlg) {
71 return;
72 }
73
74 ao2_lock(contact_status);
75 if (AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {
76 goto out;
77 }
78
79 if (!datastore
80 && (datastore = ast_sip_session_alloc_datastore(&rfc3329_store_datastore, "rfc3329_store"))
81 && (store_data = ast_calloc(1, sizeof(struct rfc3329_store_data)))) {
82
83 store_data->last_rx_status_code = rdata->msg_info.msg->line.status.code;
84 datastore->data = store_data;
86 } else {
87 ast_log(AST_LOG_WARNING, "Could not store session data. Still attempting requests, but they might be missing necessary headers.\n");
88 }
89
90 header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_security_server, NULL);
91 for (; header;
92 header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_security_server, header->next)) {
93 /* Parse Security-Server headers and add to contact status to use for future requests. */
94 ast_copy_pj_str(buf, &header->hvalue, sizeof(buf));
95 hdr_val = ast_skip_blanks(buf);
96
97 while ((mechanism = ast_strsep(&hdr_val, ',', AST_STRSEP_ALL))) {
98 if (!ast_sip_str_to_security_mechanism(&mech, mechanism)) {
99 AST_VECTOR_APPEND(&contact_status->security_mechanisms, mech);
100 }
101 }
102 }
103
104out:
105 ao2_unlock(contact_status);
106 ao2_cleanup(contact_status);
107}
108
109static void add_outgoing_request_headers(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata,
110 struct ast_datastore *datastore)
111{
112 static const pj_str_t security_verify = { "Security-Verify", 15 };
113 struct pjsip_generic_string_hdr *hdr = NULL;
114 struct ast_sip_contact_status *contact_status = NULL;
115 struct rfc3329_store_data *store_data;
116
118 return;
119 }
120
121 contact_status = ast_sip_get_contact_status(contact);
122 hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &security_verify, NULL);
123
124 if (contact_status == NULL) {
125 return;
126 }
127
128 ao2_lock(contact_status);
129 if (AST_VECTOR_SIZE(&contact_status->security_mechanisms) && hdr == NULL) {
130 /* Add Security-Verify headers (with q-value) */
131 ast_sip_add_security_headers(&contact_status->security_mechanisms, "Security-Verify", 0, tdata);
132 }
133 if (datastore) {
134 store_data = datastore->data;
135 if (store_data->last_rx_status_code == 401) {
136 /* Add Security-Client headers (no q-value) */
137 ast_sip_add_security_headers(&endpoint->security_mechanisms, "Security-Client", 0, tdata);
138 }
139 }
140 ao2_unlock(contact_status);
141
142 ao2_cleanup(contact_status);
143}
144
145static void rfc3329_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
146{
147 RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "rfc3329_store"), ao2_cleanup);
148 if (session->contact == NULL) {
149 return;
150 }
151 add_outgoing_request_headers(session->endpoint, session->contact, tdata, datastore);
152}
153
156 .outgoing_request = rfc3329_outgoing_request,
157};
158
159static void rfc3329_options_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)
160{
161 add_outgoing_request_headers(endpoint, contact, tdata, NULL);
162}
163
165 .method = "OPTIONS",
166 .outgoing_request = rfc3329_options_request,
167};
168
169static int load_module(void)
170{
174}
175
176static int unload_module(void)
177{
180 return 0;
181}
182
183AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP RFC3329 Support (partial)",
184 .support_level = AST_MODULE_SUPPORT_CORE,
185 .load = load_module,
186 .unload = unload_module,
187 .load_pri = AST_MODPRI_APP_DEPEND,
188 .requires = "res_pjsip,res_pjsip_session",
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
Internal Asterisk hangup causes.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_LOG_WARNING
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_APP_DEPEND
Definition: module.h:328
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
Unregister a an supplement to SIP out of dialog processing.
Definition: res_pjsip.c:1476
void ast_sip_register_supplement(struct ast_sip_supplement *supplement)
Register a supplement to SIP out of dialog processing.
Definition: res_pjsip.c:1456
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
int ast_sip_str_to_security_mechanism(struct ast_sip_security_mechanism **security_mechanism, const char *value)
Allocate a security mechanism from a string.
@ AST_SIP_SECURITY_NEG_MEDIASEC
Definition: res_pjsip.h:357
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
int ast_sip_add_security_headers(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *header_name, int add_qval, pjsip_tx_data *tdata)
Add security headers to transmission data.
static struct ast_sip_supplement rfc3329_options_supplement
static void rfc3329_options_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)
static const struct ast_datastore_info rfc3329_store_datastore
The channel datastore the module uses to store state.
static struct ast_sip_session_supplement rfc3329_supplement
static void add_outgoing_request_headers(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata, struct ast_datastore *datastore)
static void rfc3329_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
static void datastore_destroy_cb(void *data)
static void rfc3329_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
static int load_module(void)
static int unload_module(void)
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
#define ast_sip_session_register_supplement(supplement)
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
Definition: pjsip_session.c:63
#define NULL
Definition: resample.c:96
@ AST_STRSEP_ALL
Definition: strings.h:258
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1835
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
A contact's status.
Definition: res_pjsip.h:451
struct ast_sip_security_mechanism_vector security_mechanisms
Definition: res_pjsip.h:466
Contact associated with an address of record.
Definition: res_pjsip.h:392
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
enum ast_sip_security_negotiation security_negotiation
Definition: res_pjsip.h:1058
struct ast_sip_security_mechanism_vector security_mechanisms
Definition: res_pjsip.h:1060
Structure representing a security mechanism as defined in RFC 3329.
Definition: res_pjsip.h:378
A supplement to SIP message processing.
void(* incoming_response)(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
Called on an incoming SIP response This method is always called from a SIP servant thread.
A structure describing a SIP session.
A supplement to SIP message processing.
Definition: res_pjsip.h:3198
const char * method
Definition: res_pjsip.h:3200
struct header * next
Private data structure used with the modules's datastore.
static struct test_val d
FILE * out
Definition: utils/frame.c:33
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256