Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
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
36/*! \brief Private data structure used with the modules's datastore */
40
41static void datastore_destroy_cb(void *data)
42{
43 struct rfc3329_store_data *d = data;
44 if (d) {
45 ast_free(d);
46 }
47}
48
49/*! \brief The channel datastore the module uses to store state */
51 .type = "rfc3329_store",
52 .destroy = datastore_destroy_cb
53};
54
55static void rfc3329_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
56{
57 RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "rfc3329_store"), ao2_cleanup);
58 static const pj_str_t str_security_server = { "Security-Server", 15 };
59 struct ast_sip_contact_status *contact_status = NULL;
60 struct ast_sip_security_mechanism *mech;
61 struct rfc3329_store_data *store_data;
62 pjsip_generic_string_hdr *header;
63 char buf[128];
64 char *hdr_val;
65 char *mechanism;
66
67 if (!session || !session->endpoint || !session->endpoint->security_negotiation
68 || !session->contact || !(contact_status = ast_sip_get_contact_status(session->contact))
69 || !session->inv_session->dlg) {
70 return;
71 }
72
73 ao2_lock(contact_status);
74 if (AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {
75 goto out;
76 }
77
78 if (!datastore
79 && (datastore = ast_sip_session_alloc_datastore(&rfc3329_store_datastore, "rfc3329_store"))
80 && (store_data = ast_calloc(1, sizeof(struct rfc3329_store_data)))) {
81
82 store_data->last_rx_status_code = rdata->msg_info.msg->line.status.code;
83 datastore->data = store_data;
85 } else {
86 ast_log(AST_LOG_WARNING, "Could not store session data. Still attempting requests, but they might be missing necessary headers.\n");
87 }
88
89 header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_security_server, NULL);
90 for (; header;
91 header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_security_server, header->next)) {
92 /* Parse Security-Server headers and add to contact status to use for future requests. */
93 ast_copy_pj_str(buf, &header->hvalue, sizeof(buf));
94 hdr_val = ast_skip_blanks(buf);
95
96 while ((mechanism = ast_strsep(&hdr_val, ',', AST_STRSEP_ALL))) {
97 if (!ast_sip_str_to_security_mechanism(&mech, mechanism)) {
98 AST_VECTOR_APPEND(&contact_status->security_mechanisms, mech);
99 }
100 }
101 }
102
103out:
104 ao2_unlock(contact_status);
105 ao2_cleanup(contact_status);
106}
107
108static void add_outgoing_request_headers(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata,
109 struct ast_datastore *datastore)
110{
111 static const pj_str_t security_verify = { "Security-Verify", 15 };
112 struct pjsip_generic_string_hdr *hdr = NULL;
113 struct ast_sip_contact_status *contact_status = NULL;
114 struct rfc3329_store_data *store_data;
115
117 return;
118 }
119
120 contact_status = ast_sip_get_contact_status(contact);
121 hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &security_verify, NULL);
122
123 if (contact_status == NULL) {
124 return;
125 }
126
127 ao2_lock(contact_status);
128 if (AST_VECTOR_SIZE(&contact_status->security_mechanisms) && hdr == NULL) {
129 /* Add Security-Verify headers (with q-value) */
130 ast_sip_add_security_headers(&contact_status->security_mechanisms, "Security-Verify", 0, tdata);
131 }
132 if (datastore) {
133 store_data = datastore->data;
134 if (store_data->last_rx_status_code == 401) {
135 /* Add Security-Client headers (no q-value) */
136 ast_sip_add_security_headers(&endpoint->security_mechanisms, "Security-Client", 0, tdata);
137 }
138 }
139 ao2_unlock(contact_status);
140
141 ao2_cleanup(contact_status);
142}
143
144static void rfc3329_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
145{
146 RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "rfc3329_store"), ao2_cleanup);
147 if (session->contact == NULL) {
148 return;
149 }
150 add_outgoing_request_headers(session->endpoint, session->contact, tdata, datastore);
151}
152
157
158static void rfc3329_options_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)
159{
160 add_outgoing_request_headers(endpoint, contact, tdata, NULL);
161}
162
164 .method = "OPTIONS",
165 .outgoing_request = rfc3329_options_request,
166};
167
174
181
182AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP RFC3329 Support (partial)",
183 .support_level = AST_MODULE_SUPPORT_CORE,
184 .load = load_module,
185 .unload = unload_module,
186 .load_pri = AST_MODPRI_APP_DEPEND,
187 .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:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_APP_DEPEND
Definition module.h:342
@ 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:1470
void ast_sip_register_supplement(struct ast_sip_supplement *supplement)
Register a supplement to SIP out of dialog processing.
Definition res_pjsip.c:1450
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:2172
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:355
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.
#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:1871
char *attribute_pure 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:390
An entity with which Asterisk communicates.
Definition res_pjsip.h:1061
enum ast_sip_security_negotiation security_negotiation
Definition res_pjsip.h:1158
struct ast_sip_security_mechanism_vector security_mechanisms
Definition res_pjsip.h:1160
Structure representing a security mechanism as defined in RFC 3329.
Definition res_pjsip.h:376
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:3376
const char * method
Definition res_pjsip.h:3378
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:981
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267