AST-2018-005: res_pjsip_transport_management: Move to core
[asterisk/asterisk.git] / res / res_pjsip / pjsip_message_filter.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014-2016, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.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 #include "asterisk.h"
20
21 #include <pjsip.h>
22 #include <pjsip_ua.h>
23
24 #include "asterisk/res_pjsip.h"
25 #include "asterisk/res_pjsip_session.h"
26 #include "include/res_pjsip_private.h"
27
28 #define MOD_DATA_RESTRICTIONS "restrictions"
29
30 static pj_status_t filter_on_tx_message(pjsip_tx_data *tdata);
31 static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata);
32
33 /*! \brief Outgoing message modification restrictions */
34 struct filter_message_restrictions {
35         /*! \brief Disallow modification of the From domain */
36         unsigned int disallow_from_domain_modification;
37 };
38
39 static pjsip_module filter_module_transport = {
40         .name = { "Message Filtering Transport", 27 },
41         .id = -1,
42         .priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER,
43         .on_rx_request = filter_on_rx_message,
44 };
45
46 static pjsip_module filter_module_tsx = {
47         .name = { "Message Filtering TSX", 21 },
48         .id = -1,
49         .priority = PJSIP_MOD_PRIORITY_TSX_LAYER - 1,
50         .on_tx_request = filter_on_tx_message,
51         .on_tx_response = filter_on_tx_message,
52 };
53
54 /*! \brief Helper function to get (or allocate if not already present) restrictions on a message */
55 static struct filter_message_restrictions *get_restrictions(pjsip_tx_data *tdata)
56 {
57         struct filter_message_restrictions *restrictions;
58
59         restrictions = ast_sip_mod_data_get(tdata->mod_data, filter_module_tsx.id, MOD_DATA_RESTRICTIONS);
60         if (restrictions) {
61                 return restrictions;
62         }
63
64         restrictions = PJ_POOL_ALLOC_T(tdata->pool, struct filter_message_restrictions);
65         ast_sip_mod_data_set(tdata->pool, tdata->mod_data, filter_module_tsx.id, MOD_DATA_RESTRICTIONS, restrictions);
66
67         return restrictions;
68 }
69
70 /*! \brief Callback invoked on non-session outgoing messages */
71 static void filter_outgoing_message(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)
72 {
73         struct filter_message_restrictions *restrictions = get_restrictions(tdata);
74
75         restrictions->disallow_from_domain_modification = !ast_strlen_zero(endpoint->fromdomain);
76 }
77
78 /*! \brief PJSIP Supplement for tagging messages with restrictions */
79 static struct ast_sip_supplement filter_supplement = {
80         .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST,
81         .outgoing_request = filter_outgoing_message,
82         .outgoing_response = filter_outgoing_message,
83 };
84
85 /*! \brief Callback invoked on session outgoing messages */
86 static void filter_session_outgoing_message(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
87 {
88         struct filter_message_restrictions *restrictions = get_restrictions(tdata);
89
90         restrictions->disallow_from_domain_modification = !ast_strlen_zero(session->endpoint->fromdomain);
91 }
92
93 /*! \brief PJSIP Session Supplement for tagging messages with restrictions */
94 static struct ast_sip_session_supplement filter_session_supplement = {
95         .priority = 1,
96         .outgoing_request = filter_session_outgoing_message,
97         .outgoing_response = filter_session_outgoing_message,
98 };
99
100 /*! \brief Helper function which returns a UDP transport bound to the given address and port */
101 static pjsip_transport *get_udp_transport(pj_str_t *address, int port)
102 {
103         struct ao2_container *transport_states = ast_sip_get_transport_states();
104         struct ast_sip_transport_state *transport_state;
105         struct ao2_iterator iter;
106         pjsip_transport *sip_transport = NULL;
107
108         if (!transport_states) {
109                 return NULL;
110         }
111
112         for (iter = ao2_iterator_init(transport_states, 0); (transport_state = ao2_iterator_next(&iter)); ao2_ref(transport_state, -1)) {
113                 if (transport_state && ((transport_state->type != AST_TRANSPORT_UDP) ||
114                         (pj_strcmp(&transport_state->transport->local_name.host, address)) ||
115                         (transport_state->transport->local_name.port != port))) {
116                         continue;
117                 }
118
119                 sip_transport = transport_state->transport;
120                 break;
121         }
122         ao2_iterator_destroy(&iter);
123
124         ao2_ref(transport_states, -1);
125
126         return sip_transport;
127 }
128
129 /*! \brief Helper function which determines if a transport is bound to any */
130 static int is_bound_any(pjsip_transport *transport)
131 {
132         pj_uint32_t loop6[4] = {0, 0, 0, 0};
133
134         if ((transport->local_addr.addr.sa_family == pj_AF_INET() &&
135                 transport->local_addr.ipv4.sin_addr.s_addr == PJ_INADDR_ANY) ||
136                 (transport->local_addr.addr.sa_family == pj_AF_INET6() &&
137                 !pj_memcmp(&transport->local_addr.ipv6.sin6_addr, loop6, sizeof(loop6)))) {
138                 return 1;
139         }
140
141         return 0;
142 }
143
144 /*! \brief Helper function which determines if the address within SDP should be rewritten */
145 static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp)
146 {
147         if (!sdp->conn) {
148                 return 0;
149         }
150
151         /* If the host address is used in the SDP replace it with the address of what this is going out on */
152         if ((!pj_strcmp2(&sdp->conn->addr_type, "IP4") && !pj_strcmp2(&sdp->conn->addr,
153                 ast_sip_get_host_ip_string(pj_AF_INET()))) ||
154                 (!pj_strcmp2(&sdp->conn->addr_type, "IP6") && !pj_strcmp2(&sdp->conn->addr,
155                 ast_sip_get_host_ip_string(pj_AF_INET6())))) {
156                 return 1;
157         }
158
159         return 0;
160 }
161
162 #define is_sip_uri(uri) \
163         (PJSIP_URI_SCHEME_IS_SIP(uri) || PJSIP_URI_SCHEME_IS_SIPS(uri))
164
165 static void print_sanitize_debug(char *msg, pjsip_uri_context_e context, pjsip_sip_uri *uri)
166 {
167 #ifdef AST_DEVMODE
168         char hdrbuf[512];
169         int hdrbuf_len;
170
171         hdrbuf_len = pjsip_uri_print(context, uri, hdrbuf, 512);
172         hdrbuf[hdrbuf_len] = '\0';
173         ast_debug(2, "%s: %s\n", msg, hdrbuf);
174 #endif
175 }
176
177 /* If in DEVMODE, prevent inlining to assist in debugging */
178 #ifdef AST_DEVMODE
179 #define FUNC_ATTRS __attribute__ ((noinline))
180 #else
181 #define FUNC_ATTRS
182 #endif
183
184 static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata)
185 {
186         static const pj_str_t x_name = { AST_SIP_X_AST_TXP, AST_SIP_X_AST_TXP_LEN };
187         pjsip_param *x_transport;
188         pjsip_sip_uri *uri;
189         pjsip_hdr *hdr;
190
191         if (tdata->msg->type == PJSIP_REQUEST_MSG) {
192                 if (is_sip_uri(tdata->msg->line.req.uri)) {
193                         uri = pjsip_uri_get_uri(tdata->msg->line.req.uri);
194                         print_sanitize_debug("Sanitizing Request", PJSIP_URI_IN_REQ_URI, uri);
195                         while ((x_transport = pjsip_param_find(&uri->other_param, &x_name))) {
196                                 pj_list_erase(x_transport);
197                         }
198                 }
199         }
200
201         for (hdr = tdata->msg->hdr.next; hdr != &tdata->msg->hdr; hdr = hdr->next) {
202                 if (hdr->type == PJSIP_H_TO || hdr->type == PJSIP_H_FROM) {
203                         if (is_sip_uri(((pjsip_fromto_hdr *) hdr)->uri)) {
204                                 uri = pjsip_uri_get_uri(((pjsip_fromto_hdr *) hdr)->uri);
205                                 print_sanitize_debug("Sanitizing From/To header", PJSIP_URI_IN_FROMTO_HDR, uri);
206                                 while ((x_transport = pjsip_param_find(&uri->other_param, &x_name))) {
207                                         pj_list_erase(x_transport);
208                                 }
209                         }
210                 } else if (hdr->type == PJSIP_H_CONTACT) {
211                         if (!((pjsip_contact_hdr *) hdr)->star && is_sip_uri(((pjsip_contact_hdr *) hdr)->uri)) {
212                                 uri = pjsip_uri_get_uri(((pjsip_contact_hdr *) hdr)->uri);
213                                 print_sanitize_debug("Sanitizing Contact header", PJSIP_URI_IN_CONTACT_HDR, uri);
214                                 while ((x_transport = pjsip_param_find(&uri->other_param, &x_name))) {
215                                         pj_list_erase(x_transport);
216                                 }
217                         }
218                 }
219         }
220
221         pjsip_tx_data_invalidate_msg(tdata);
222 }
223
224 static pj_status_t filter_on_tx_message(pjsip_tx_data *tdata)
225 {
226         struct filter_message_restrictions *restrictions =
227                 ast_sip_mod_data_get(tdata->mod_data, filter_module_transport.id, MOD_DATA_RESTRICTIONS);
228         pjsip_tpmgr_fla2_param prm;
229         pjsip_cseq_hdr *cseq;
230         pjsip_via_hdr *via;
231         pjsip_fromto_hdr *from;
232
233         sanitize_tdata(tdata);
234
235         /* Use the destination information to determine what local interface this message will go out on */
236         pjsip_tpmgr_fla2_param_default(&prm);
237         prm.tp_type = tdata->tp_info.transport->key.type;
238         pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);
239         prm.local_if = is_bound_any(tdata->tp_info.transport);
240
241         /* If we can't get the local address use best effort and let it pass */
242         if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) {
243                 return PJ_SUCCESS;
244         }
245
246         /* For UDP we can have multiple transports so the port needs to be maintained */
247         if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
248                 tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
249                 prm.ret_port = tdata->tp_info.transport->local_name.port;
250         }
251
252         /* If the IP source differs from the existing transport see if we need to update it */
253         if (pj_strcmp(&prm.ret_addr, &tdata->tp_info.transport->local_name.host)) {
254
255                 /* If the transport it is going out on is different reflect it in the message */
256                 if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
257                         tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
258                         pjsip_transport *transport;
259
260                         transport = get_udp_transport(&prm.ret_addr, prm.ret_port);
261
262                         if (transport) {
263                                 tdata->tp_info.transport = transport;
264                         }
265                 }
266
267                 /* If the chosen transport is not bound to any we can't use the source address as it won't get back to us */
268                 if (!is_bound_any(tdata->tp_info.transport)) {
269                         pj_strassign(&prm.ret_addr, &tdata->tp_info.transport->local_name.host);
270                 }
271         } else {
272                 /* The transport chosen will deliver this but ensure it is updated with the right information */
273                 pj_strassign(&prm.ret_addr, &tdata->tp_info.transport->local_name.host);
274         }
275
276         /* If the message needs to be updated with new address do so */
277         if (tdata->msg->type == PJSIP_REQUEST_MSG || !(cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL)) ||
278                 pj_strcmp2(&cseq->method.name, "REGISTER")) {
279                 pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
280                 if (contact && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))
281                         && !(tdata->msg->type == PJSIP_RESPONSE_MSG && tdata->msg->line.status.code / 100 == 3)) {
282                         pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
283
284                         /* prm.ret_addr is allocated from the tdata pool OR the transport so it is perfectly fine to just do an assignment like this */
285                         pj_strassign(&uri->host, &prm.ret_addr);
286                         uri->port = prm.ret_port;
287                         ast_debug(5, "Re-wrote Contact URI host/port to %.*s:%d (this may be re-written again later)\n",
288                                 (int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port);
289
290                         if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
291                                 tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
292                                 uri->transport_param.slen = 0;
293                         } else {
294                                 pj_strdup2(tdata->pool, &uri->transport_param, pjsip_transport_get_type_name(tdata->tp_info.transport->key.type));
295                         }
296
297                         pjsip_tx_data_invalidate_msg(tdata);
298                 }
299         }
300
301         if (tdata->msg->type == PJSIP_REQUEST_MSG && (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) {
302                 pj_strassign(&via->sent_by.host, &prm.ret_addr);
303                 via->sent_by.port = prm.ret_port;
304
305                 pjsip_tx_data_invalidate_msg(tdata);
306         }
307
308         if (tdata->msg->type == PJSIP_REQUEST_MSG && (from = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL)) &&
309                 (restrictions && !restrictions->disallow_from_domain_modification)) {
310                 pjsip_name_addr *id_name_addr = (pjsip_name_addr *)from->uri;
311                 pjsip_sip_uri *uri = pjsip_uri_get_uri(id_name_addr);
312                 pj_sockaddr ip;
313
314                 if (pj_strcmp2(&uri->host, "localhost") && pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &uri->host, &ip) == PJ_SUCCESS) {
315                         pj_strassign(&uri->host, &prm.ret_addr);
316                         pjsip_tx_data_invalidate_msg(tdata);
317                 }
318         }
319
320         /* Update the SDP if it is present */
321         if (tdata->msg->body && ast_sip_is_content_type(&tdata->msg->body->content_type, "application", "sdp") &&
322                 multihomed_rewrite_sdp(tdata->msg->body->data)) {
323                 struct pjmedia_sdp_session *sdp = tdata->msg->body->data;
324                 static const pj_str_t STR_IP4 = { "IP4", 3 };
325                 static const pj_str_t STR_IP6 = { "IP6", 3 };
326                 pj_str_t STR_IP;
327                 int stream;
328
329                 STR_IP = tdata->tp_info.transport->key.type & PJSIP_TRANSPORT_IPV6 ? STR_IP6 : STR_IP4;
330
331                 pj_strassign(&sdp->origin.addr, &prm.ret_addr);
332                 sdp->origin.addr_type = STR_IP;
333                 pj_strassign(&sdp->conn->addr, &prm.ret_addr);
334                 sdp->conn->addr_type = STR_IP;
335
336                 for (stream = 0; stream < sdp->media_count; ++stream) {
337                         if (sdp->media[stream]->conn) {
338                                 pj_strassign(&sdp->media[stream]->conn->addr, &prm.ret_addr);
339                                 sdp->media[stream]->conn->addr_type = STR_IP;
340                         }
341                 }
342
343                 pjsip_tx_data_invalidate_msg(tdata);
344         }
345
346         return PJ_SUCCESS;
347 }
348
349 enum uri_type {
350         URI_TYPE_REQUEST = -1,
351         URI_TYPE_TO = PJSIP_H_TO,
352         URI_TYPE_FROM = PJSIP_H_FROM,
353         URI_TYPE_CONTACT = PJSIP_H_CONTACT,
354 };
355
356 static void print_uri_debug(enum uri_type ut, pjsip_rx_data *rdata, pjsip_hdr *hdr)
357 {
358 #ifdef AST_DEVMODE
359         pjsip_uri *local_uri = NULL;
360         char hdrbuf[512];
361         int hdrbuf_len;
362         char *request_uri;
363         pjsip_uri_context_e context = PJSIP_URI_IN_OTHER;
364         char header_name[32];
365
366         switch (ut) {
367         case(URI_TYPE_REQUEST):
368                 context = PJSIP_URI_IN_REQ_URI;
369                 strcpy(header_name, "Request"); /* Safe */
370                 local_uri = rdata->msg_info.msg->line.req.uri;
371                 break;
372         case(PJSIP_H_FROM):
373                 strcpy(header_name, "From"); /* Safe */
374                 context = PJSIP_URI_IN_FROMTO_HDR;
375                 local_uri = pjsip_uri_get_uri(((pjsip_from_hdr *)hdr)->uri);
376                 break;
377         case(PJSIP_H_TO):
378                 strcpy(header_name, "To"); /* Safe */
379                 context = PJSIP_URI_IN_FROMTO_HDR;
380                 local_uri = pjsip_uri_get_uri(((pjsip_to_hdr *)hdr)->uri);
381                 break;
382         case(PJSIP_H_CONTACT):
383                 strcpy(header_name, "Contact"); /* Safe */
384                 context = PJSIP_URI_IN_CONTACT_HDR;
385                 local_uri = pjsip_uri_get_uri(((pjsip_contact_hdr *)hdr)->uri);
386                 break;
387         }
388
389         hdrbuf_len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, rdata->msg_info.msg->line.req.uri, hdrbuf, 512);
390         hdrbuf[hdrbuf_len] = '\0';
391         request_uri = ast_strdupa(hdrbuf);
392         hdrbuf_len = pjsip_uri_print(context, local_uri, hdrbuf, 512);
393         hdrbuf[hdrbuf_len] = '\0';
394
395         ast_debug(2, "There was a non sip(s) URI scheme in %s URI '%s' for request '%*.*s %s'\n",
396                 header_name, hdrbuf,
397                 (int)rdata->msg_info.msg->line.req.method.name.slen,
398                 (int)rdata->msg_info.msg->line.req.method.name.slen,
399                 rdata->msg_info.msg->line.req.method.name.ptr, request_uri);
400 #endif
401 }
402
403 static pj_bool_t on_rx_process_uris(pjsip_rx_data *rdata)
404 {
405         pjsip_contact_hdr *contact = NULL;
406
407         if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) {
408                 return PJ_FALSE;
409         }
410
411         if (!is_sip_uri(rdata->msg_info.msg->line.req.uri)) {
412                 print_uri_debug(URI_TYPE_REQUEST, rdata, NULL);
413                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata,
414                         PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);
415                 return PJ_TRUE;
416         }
417
418         if (!is_sip_uri(rdata->msg_info.from->uri)) {
419                 print_uri_debug(URI_TYPE_FROM, rdata, (pjsip_hdr *)rdata->msg_info.from);
420                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata,
421                         PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);
422                 return PJ_TRUE;
423         }
424
425         if (!is_sip_uri(rdata->msg_info.to->uri)) {
426                 print_uri_debug(URI_TYPE_TO, rdata, (pjsip_hdr *)rdata->msg_info.to);
427                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata,
428                         PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);
429                 return PJ_TRUE;
430         }
431
432
433         contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(
434                 rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
435
436         if (!contact && pjsip_method_creates_dialog(&rdata->msg_info.msg->line.req.method)) {
437                 /* A contact header is required for dialog creating methods */
438                 static const pj_str_t missing_contact = { "Missing Contact header", 22 };
439                 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400,
440                                 &missing_contact, NULL, NULL);
441                 return PJ_TRUE;
442         }
443
444         while (contact) {
445                 if (!contact->star && !is_sip_uri(contact->uri)) {
446                         print_uri_debug(URI_TYPE_CONTACT, rdata, (pjsip_hdr *)contact);
447                         pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata,
448                                 PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);
449                         return PJ_TRUE;
450                 }
451                 contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(
452                         rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next);
453         }
454
455         return PJ_FALSE;
456 }
457
458 static pj_bool_t on_rx_process_symmetric_transport(pjsip_rx_data *rdata)
459 {
460         pjsip_contact_hdr *contact;
461         pjsip_sip_uri *uri;
462         const char *transport_id;
463         struct ast_sip_transport *transport;
464         pjsip_param *x_transport;
465
466         if (rdata->msg_info.msg->type != PJSIP_REQUEST_MSG) {
467                 return PJ_FALSE;
468         }
469
470         contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
471         if (!(contact && contact->uri
472                 && ast_begins_with(rdata->tp_info.transport->info, AST_SIP_X_AST_TXP ":"))) {
473                 return PJ_FALSE;
474         }
475
476         uri = pjsip_uri_get_uri(contact->uri);
477
478         transport_id = rdata->tp_info.transport->info + AST_SIP_X_AST_TXP_LEN + 1;
479         transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_id);
480
481         if (!(transport && transport->symmetric_transport)) {
482                 ao2_cleanup(transport);
483                 return PJ_FALSE;
484         }
485         ao2_cleanup(transport);
486
487         x_transport = PJ_POOL_ALLOC_T(rdata->tp_info.pool, pjsip_param);
488         x_transport->name = pj_strdup3(rdata->tp_info.pool, AST_SIP_X_AST_TXP);
489         x_transport->value = pj_strdup3(rdata->tp_info.pool, transport_id);
490
491         pj_list_insert_before(&uri->other_param, x_transport);
492
493         ast_debug(1, "Set transport '%s' on %.*s from %.*s:%d\n", transport_id,
494                 (int)rdata->msg_info.msg->line.req.method.name.slen,
495                 rdata->msg_info.msg->line.req.method.name.ptr,
496                 (int)uri->host.slen, uri->host.ptr, uri->port);
497
498         return PJ_FALSE;
499 }
500
501 static pj_bool_t filter_on_rx_message(pjsip_rx_data *rdata)
502 {
503         pj_bool_t rc;
504
505         rc = on_rx_process_uris(rdata);
506         if (rc == PJ_TRUE) {
507                 return rc;
508         }
509
510         rc = on_rx_process_symmetric_transport(rdata);
511         if (rc == PJ_TRUE) {
512                 return rc;
513         }
514
515         return PJ_FALSE;
516 }
517
518 void ast_res_pjsip_cleanup_message_filter(void)
519 {
520         ast_sip_unregister_service(&filter_module_tsx);
521         ast_sip_unregister_service(&filter_module_transport);
522         ast_sip_unregister_supplement(&filter_supplement);
523         ast_sip_session_unregister_supplement(&filter_session_supplement);
524 }
525
526 int ast_res_pjsip_init_message_filter(void)
527 {
528         ast_sip_session_register_supplement(&filter_session_supplement);
529         ast_sip_register_supplement(&filter_supplement);
530
531         if (ast_sip_register_service(&filter_module_transport)) {
532                 ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n");
533                 ast_res_pjsip_cleanup_message_filter();
534                 return -1;
535         }
536
537         if (ast_sip_register_service(&filter_module_tsx)) {
538                 ast_log(LOG_ERROR, "Could not register message filter module for incoming and outgoing requests\n");
539                 ast_res_pjsip_cleanup_message_filter();
540                 return -1;
541         }
542
543         return 0;
544 }