d0694b1d44b1affff78236fb53a47a56b22e7b61
[sip-router] / src / modules / siptrace / siptrace_send.c
1 /*
2  * siptrace module - helper module to trace sip messages
3  *
4  * Copyright (C) 2017 kamailio.org
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
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
12  *
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.
17  *
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
21  *
22  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28
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"
35
36 #include "siptrace_send.h"
37
38
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;
45
46 /**
47  *
48  */
49 int sip_trace_prepare(sip_msg_t *msg)
50 {
51         if(parse_from_header(msg) == -1 || msg->from == NULL
52                         || get_from(msg) == NULL) {
53                 LM_ERR("cannot parse FROM header\n");
54                 goto error;
55         }
56
57         if(parse_to_header(msg) == -1 || msg->to == NULL || get_to(msg) == NULL) {
58                 LM_ERR("cannot parse To header\n");
59                 goto error;
60         }
61
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");
65                 goto error;
66         }
67
68         if(msg->cseq == NULL && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1)
69                                                                         || (msg->cseq == NULL))) {
70                 LM_ERR("cannot parse cseq\n");
71                 goto error;
72         }
73
74         return 0;
75 error:
76         return -1;
77 }
78
79 /**
80  * Appends x-headers to the message in sto->body containing data from sto
81  */
82 int sip_trace_xheaders_write(struct _siptrace_data *sto)
83 {
84         char *buf = NULL;
85         int bytes_written = 0;
86         char *eoh = NULL;
87         int eoh_offset = 0;
88         char *new_eoh = NULL;
89
90         if(trace_xheaders_write == 0) {
91                 return 0;
92         }
93
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);
97         if(buf == NULL) {
98                 LM_ERR("out of pkg memory\n");
99                 return -1;
100         }
101
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");
107         if(eoh == NULL) {
108                 LM_ERR("malformed message\n");
109                 goto error;
110         }
111         eoh += 2; // the first \r\n belongs to the last header => skip it
112
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.
116         bytes_written =
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");
128                 goto error;
129         }
130
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);
136
137         // Change sto to point to the new buffer.
138         sto->body.s = buf;
139         sto->body.len += bytes_written;
140         return 0;
141 error:
142         if(buf != NULL) {
143                 pkg_free(buf);
144         }
145         return -1;
146 }
147
148 /**
149  * Parses x-headers, saves the data back to sto, and removes the x-headers
150  * from the message in sto->buf
151  */
152 int sip_trace_xheaders_read(struct _siptrace_data *sto)
153 {
154         char *searchend = NULL;
155         char *eoh = NULL;
156         char *xheaders = NULL;
157         long long unsigned int tv_sec, tv_usec;
158
159         if(trace_xheaders_read == 0) {
160                 return 0;
161         }
162
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)
168                         break;
169                 eoh = memchr(eoh + 1, '\r', searchend - eoh);
170         }
171         if(eoh == NULL) {
172                 LM_ERR("malformed message\n");
173                 return -1;
174         }
175
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.
180         *eoh = '\0';
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);
186                 return -1;
187         }
188
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;
198         }
199
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,
208                            sto->dir)
209                         == EOF) {
210                 LM_ERR("malformed x-headers\n");
211                 goto erroraftermalloc;
212         }
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);
218
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
221         // is recovered.
222         *eoh = '\r';
223         memmove(xheaders, eoh, sto->body.len - (eoh - sto->body.s));
224         sto->body.len -= eoh - xheaders;
225
226         return 0;
227
228 erroraftermalloc:
229         if(sto->fromip.s) {
230                 pkg_free(sto->fromip.s);
231                 sto->fromip.s = 0;
232         }
233         if(sto->toip.s) {
234                 pkg_free(sto->toip.s);
235                 sto->toip.s = 0;
236         }
237         if(sto->method.s) {
238                 pkg_free(sto->method.s);
239                 sto->method.s = 0;
240         }
241         if(sto->dir) {
242                 pkg_free(sto->dir);
243                 sto->dir = 0;
244         }
245         return -1;
246 }
247
248 /**
249  * Frees the memory allocated by sip_trace_xheaders_{write,read}
250  */
251 int sip_trace_xheaders_free(struct _siptrace_data *sto)
252 {
253         if(trace_xheaders_write != 0) {
254                 if(sto->body.s) {
255                         pkg_free(sto->body.s);
256                         sto->body.s = 0;
257                 }
258         }
259
260         if(trace_xheaders_read != 0) {
261                 if(sto->fromip.s) {
262                         pkg_free(sto->fromip.s);
263                         sto->fromip.s = 0;
264                 }
265                 if(sto->toip.s) {
266                         pkg_free(sto->toip.s);
267                         sto->toip.s = 0;
268                 }
269                 if(sto->dir) {
270                         pkg_free(sto->dir);
271                         sto->dir = 0;
272                 }
273         }
274
275         return 0;
276 }
277
278
279 /**
280  *
281  */
282 int trace_send_duplicate(char *buf, int len, dest_info_t *dst2)
283 {
284         dest_info_t dst;
285         dest_info_t *pdst = NULL;
286         proxy_l_t *p = NULL;
287
288         if(buf == NULL || len <= 0) {
289                 return -1;
290         }
291
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");
295                 return 0;
296         }
297
298         init_dest_info(&dst);
299
300         if(!dst2) {
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);
305                 if(p == 0) {
306                         LM_ERR("bad host name in uri\n");
307                         return -1;
308                 }
309                 hostent2su(
310                                 &dst.to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT);
311                 pdst = &dst;
312         } else {
313                 pdst = dst2;
314         }
315
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");
324                         } else {
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);
329                         }
330                 }
331         }
332
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);
339                         goto error;
340                 }
341         }
342
343         if(msg_send(pdst, buf, len) < 0) {
344                 LM_ERR("cannot send duplicate message\n");
345                 goto error;
346         }
347
348         if(p) {
349                 free_proxy(p); /* frees only p content, not p itself */
350                 pkg_free(p);
351         }
352         return 0;
353 error:
354         if(p) {
355                 free_proxy(p); /* frees only p content, not p itself */
356                 pkg_free(p);
357         }
358         return -1;
359 }
360
361 /**
362  *
363  */
364 char* siptrace_proto_name(int vproto)
365 {
366         switch(vproto) {
367                 case PROTO_TCP:
368                         return "tcp";
369                 case PROTO_TLS:
370                         return "tls";
371                 case PROTO_SCTP:
372                         return "sctp";
373                 case PROTO_WS:
374                         return "ws";
375                 case PROTO_WSS:
376                         return "wss";
377                 default:
378                         return "udp";
379         }
380 }