2 * siptrace module - helper module to trace sip messages
4 * Copyright (C) 2017 kamailio.org
6 * This file is part of Kamailio, a free SIP server.
8 * Kamailio is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
13 * Kamailio is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "../../core/dprint.h"
30 #include "../../core/proxy.h"
31 #include "../../core/forward.h"
32 #include "../../core/parser/parse_content.h"
33 #include "../../core/parser/parse_from.h"
34 #include "../../core/parser/parse_cseq.h"
36 #include "siptrace_send.h"
39 extern int trace_xheaders_write;
40 extern int trace_xheaders_read;
41 extern str trace_dup_uri_str;
42 extern sip_uri_t *trace_dup_uri;
43 extern str trace_send_sock_str;
44 extern sip_uri_t *trace_send_sock_uri;
49 int sip_trace_prepare(sip_msg_t *msg)
51 if(parse_from_header(msg) == -1 || msg->from == NULL
52 || get_from(msg) == NULL) {
53 LM_ERR("cannot parse FROM header\n");
57 if(parse_to_header(msg) == -1 || msg->to == NULL || get_to(msg) == NULL) {
58 LM_ERR("cannot parse To header\n");
62 if(parse_headers(msg, HDR_CALLID_F, 0) != 0 || msg->callid == NULL
63 || msg->callid->body.s == NULL) {
64 LM_ERR("cannot parse call-id\n");
68 if(msg->cseq == NULL && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1)
69 || (msg->cseq == NULL))) {
70 LM_ERR("cannot parse cseq\n");
80 * Appends x-headers to the message in sto->body containing data from sto
82 int sip_trace_xheaders_write(struct _siptrace_data *sto)
85 int bytes_written = 0;
90 if(trace_xheaders_write == 0) {
94 // Memory for the message with some additional headers.
95 // It gets free()ed in sip_trace_xheaders_free().
96 buf = pkg_malloc(sto->body.len + XHEADERS_BUFSIZE);
98 LM_ERR("out of pkg memory\n");
102 // Copy the whole message to buf first; it must be \0-terminated for
103 // strstr() to work. Then search for the end-of-header sequence.
104 memcpy(buf, sto->body.s, sto->body.len);
105 buf[sto->body.len] = '\0';
106 eoh = strstr(buf, "\r\n\r\n");
108 LM_ERR("malformed message\n");
111 eoh += 2; // the first \r\n belongs to the last header => skip it
113 // Write the new headers a the end-of-header position. This overwrites
114 // the \r\n terminating the old headers and the beginning of the message
115 // body. Both will be recovered later.
117 snprintf(eoh, XHEADERS_BUFSIZE, "X-Siptrace-Fromip: %.*s\r\n"
118 "X-Siptrace-Toip: %.*s\r\n"
119 "X-Siptrace-Time: %llu %llu\r\n"
120 "X-Siptrace-Method: %.*s\r\n"
121 "X-Siptrace-Dir: %s\r\n",
122 sto->fromip.len, sto->fromip.s, sto->toip.len, sto->toip.s,
123 (unsigned long long)sto->tv.tv_sec,
124 (unsigned long long)sto->tv.tv_usec, sto->method.len,
125 sto->method.s, sto->dir);
126 if(bytes_written >= XHEADERS_BUFSIZE) {
127 LM_ERR("string too long\n");
131 // Copy the \r\n terminating the old headers and the message body from the
132 // old buffer in sto->body.s to the new end-of-header in buf.
133 eoh_offset = eoh - buf;
134 new_eoh = eoh + bytes_written;
135 memcpy(new_eoh, sto->body.s + eoh_offset, sto->body.len - eoh_offset);
137 // Change sto to point to the new buffer.
139 sto->body.len += bytes_written;
149 * Parses x-headers, saves the data back to sto, and removes the x-headers
150 * from the message in sto->buf
152 int sip_trace_xheaders_read(struct _siptrace_data *sto)
154 char *searchend = NULL;
156 char *xheaders = NULL;
157 long long unsigned int tv_sec, tv_usec;
159 if(trace_xheaders_read == 0) {
163 // Find the end-of-header marker \r\n\r\n
164 searchend = sto->body.s + sto->body.len - 3;
165 eoh = memchr(sto->body.s, '\r', searchend - eoh);
166 while(eoh != NULL && eoh < searchend) {
167 if(memcmp(eoh, "\r\n\r\n", 4) == 0)
169 eoh = memchr(eoh + 1, '\r', searchend - eoh);
172 LM_ERR("malformed message\n");
176 // Find x-headers: eoh will be overwritten by \0 to allow the use of
177 // strstr(). The byte at eoh will later be recovered, when the
178 // message body is shifted towards the beginning of the message
179 // to remove the x-headers.
181 xheaders = strstr(sto->body.s, "\r\nX-Siptrace-Fromip: ");
182 if(xheaders == NULL) {
183 LM_ERR("message without x-headers "
184 "from %.*s, callid %.*s\n",
185 sto->fromip.len, sto->fromip.s, sto->callid.len, sto->callid.s);
189 // Allocate memory for new strings in sto
190 // (gets free()ed in sip_trace_xheaders_free() )
191 sto->fromip.s = pkg_malloc(51);
192 sto->toip.s = pkg_malloc(51);
193 sto->method.s = pkg_malloc(51);
194 sto->dir = pkg_malloc(4);
195 if(!(sto->fromip.s && sto->toip.s && sto->method.s && sto->dir)) {
196 LM_ERR("out of pkg memory\n");
197 goto erroraftermalloc;
200 // Parse the x-headers: scanf()
201 if(sscanf(xheaders, "\r\n"
202 "X-Siptrace-Fromip: %50s\r\n"
203 "X-Siptrace-Toip: %50s\r\n"
204 "X-Siptrace-Time: %llu %llu\r\n"
205 "X-Siptrace-Method: %50s\r\n"
206 "X-Siptrace-Dir: %3s",
207 sto->fromip.s, sto->toip.s, &tv_sec, &tv_usec, sto->method.s,
210 LM_ERR("malformed x-headers\n");
211 goto erroraftermalloc;
213 sto->fromip.len = strlen(sto->fromip.s);
214 sto->toip.len = strlen(sto->toip.s);
215 sto->tv.tv_sec = (time_t)tv_sec;
216 sto->tv.tv_usec = (suseconds_t)tv_usec;
217 sto->method.len = strlen(sto->method.s);
219 // Remove the x-headers: the message body is shifted towards the beginning
220 // of the message, overwriting the x-headers. Before that, the byte at eoh
223 memmove(xheaders, eoh, sto->body.len - (eoh - sto->body.s));
224 sto->body.len -= eoh - xheaders;
230 pkg_free(sto->fromip.s);
234 pkg_free(sto->toip.s);
238 pkg_free(sto->method.s);
249 * Frees the memory allocated by sip_trace_xheaders_{write,read}
251 int sip_trace_xheaders_free(struct _siptrace_data *sto)
253 if(trace_xheaders_write != 0) {
255 pkg_free(sto->body.s);
260 if(trace_xheaders_read != 0) {
262 pkg_free(sto->fromip.s);
266 pkg_free(sto->toip.s);
282 int trace_send_duplicate(char *buf, int len, dest_info_t *dst2)
285 dest_info_t *pdst = NULL;
288 if(buf == NULL || len <= 0) {
292 /* either modparam dup_uri or siptrace param dst2 */
293 if((trace_dup_uri_str.s == 0 || trace_dup_uri == NULL) && (dst2 == NULL)) {
294 LM_WARN("Neither dup_uri modparam or siptrace destination uri param used!\n");
298 init_dest_info(&dst);
301 /* create a temporary proxy from dst param */
302 dst.proto = PROTO_UDP;
303 p = mk_proxy(&trace_dup_uri->host,
304 (trace_dup_uri->port_no) ? trace_dup_uri->port_no : SIP_PORT, dst.proto);
306 LM_ERR("bad host name in uri\n");
310 &dst.to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT);
316 if(pdst->send_sock == NULL) {
317 if(trace_send_sock_str.s) {
318 LM_DBG("send sock activated, grep for the sock_info\n");
319 pdst->send_sock = grep_sock_info(&trace_send_sock_uri->host,
320 trace_send_sock_uri->port_no,
321 trace_send_sock_uri->proto);
322 if(!pdst->send_sock) {
323 LM_WARN("cannot grep socket info\n");
325 LM_DBG("found socket while grep: [%.*s] [%.*s]\n",
326 pdst->send_sock->name.len,
327 pdst->send_sock->name.s, pdst->send_sock->address_str.len,
328 pdst->send_sock->address_str.s);
333 if(pdst->send_sock == NULL) {
334 pdst->send_sock = get_send_socket(0, &pdst->to, pdst->proto);
335 if(pdst->send_sock == 0) {
336 LM_ERR("cannot forward to af %d, proto %d - no corresponding"
337 " listening socket\n",
338 pdst->to.s.sa_family, pdst->proto);
343 if(msg_send(pdst, buf, len) < 0) {
344 LM_ERR("cannot send duplicate message\n");
349 free_proxy(p); /* frees only p content, not p itself */
355 free_proxy(p); /* frees only p content, not p itself */
364 char* siptrace_proto_name(int vproto)