siptrace: use the send socket also for duplication via sip
[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
44 /**
45  *
46  */
47 int sip_trace_prepare(sip_msg_t *msg)
48 {
49         if(parse_from_header(msg) == -1 || msg->from == NULL
50                         || get_from(msg) == NULL) {
51                 LM_ERR("cannot parse FROM header\n");
52                 goto error;
53         }
54
55         if(parse_to_header(msg) == -1 || msg->to == NULL || get_to(msg) == NULL) {
56                 LM_ERR("cannot parse To header\n");
57                 goto error;
58         }
59
60         if(parse_headers(msg, HDR_CALLID_F, 0) != 0 || msg->callid == NULL
61                         || msg->callid->body.s == NULL) {
62                 LM_ERR("cannot parse call-id\n");
63                 goto error;
64         }
65
66         if(msg->cseq == NULL && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1)
67                                                                         || (msg->cseq == NULL))) {
68                 LM_ERR("cannot parse cseq\n");
69                 goto error;
70         }
71
72         return 0;
73 error:
74         return -1;
75 }
76
77 /**
78  * Appends x-headers to the message in sto->body containing data from sto
79  */
80 int sip_trace_xheaders_write(struct _siptrace_data *sto)
81 {
82         char *buf = NULL;
83         int bytes_written = 0;
84         char *eoh = NULL;
85         int eoh_offset = 0;
86         char *new_eoh = NULL;
87
88         if(trace_xheaders_write == 0) {
89                 return 0;
90         }
91
92         // Memory for the message with some additional headers.
93         // It gets free()ed in sip_trace_xheaders_free().
94         buf = pkg_malloc(sto->body.len + XHEADERS_BUFSIZE);
95         if(buf == NULL) {
96                 LM_ERR("out of pkg memory\n");
97                 return -1;
98         }
99
100         // Copy the whole message to buf first; it must be \0-terminated for
101         // strstr() to work. Then search for the end-of-header sequence.
102         memcpy(buf, sto->body.s, sto->body.len);
103         buf[sto->body.len] = '\0';
104         eoh = strstr(buf, "\r\n\r\n");
105         if(eoh == NULL) {
106                 LM_ERR("malformed message\n");
107                 goto error;
108         }
109         eoh += 2; // the first \r\n belongs to the last header => skip it
110
111         // Write the new headers a the end-of-header position. This overwrites
112         // the \r\n terminating the old headers and the beginning of the message
113         // body. Both will be recovered later.
114         bytes_written =
115                         snprintf(eoh, XHEADERS_BUFSIZE, "X-Siptrace-Fromip: %.*s\r\n"
116                                                                                         "X-Siptrace-Toip: %.*s\r\n"
117                                                                                         "X-Siptrace-Time: %llu %llu\r\n"
118                                                                                         "X-Siptrace-Method: %.*s\r\n"
119                                                                                         "X-Siptrace-Dir: %s\r\n",
120                                         sto->fromip.len, sto->fromip.s, sto->toip.len, sto->toip.s,
121                                         (unsigned long long)sto->tv.tv_sec,
122                                         (unsigned long long)sto->tv.tv_usec, sto->method.len,
123                                         sto->method.s, sto->dir);
124         if(bytes_written >= XHEADERS_BUFSIZE) {
125                 LM_ERR("string too long\n");
126                 goto error;
127         }
128
129         // Copy the \r\n terminating the old headers and the message body from the
130         // old buffer in sto->body.s to the new end-of-header in buf.
131         eoh_offset = eoh - buf;
132         new_eoh = eoh + bytes_written;
133         memcpy(new_eoh, sto->body.s + eoh_offset, sto->body.len - eoh_offset);
134
135         // Change sto to point to the new buffer.
136         sto->body.s = buf;
137         sto->body.len += bytes_written;
138         return 0;
139 error:
140         if(buf != NULL) {
141                 pkg_free(buf);
142         }
143         return -1;
144 }
145
146 /**
147  * Parses x-headers, saves the data back to sto, and removes the x-headers
148  * from the message in sto->buf
149  */
150 int sip_trace_xheaders_read(struct _siptrace_data *sto)
151 {
152         char *searchend = NULL;
153         char *eoh = NULL;
154         char *xheaders = NULL;
155         long long unsigned int tv_sec, tv_usec;
156
157         if(trace_xheaders_read == 0) {
158                 return 0;
159         }
160
161         // Find the end-of-header marker \r\n\r\n
162         searchend = sto->body.s + sto->body.len - 3;
163         eoh = memchr(sto->body.s, '\r', searchend - eoh);
164         while(eoh != NULL && eoh < searchend) {
165                 if(memcmp(eoh, "\r\n\r\n", 4) == 0)
166                         break;
167                 eoh = memchr(eoh + 1, '\r', searchend - eoh);
168         }
169         if(eoh == NULL) {
170                 LM_ERR("malformed message\n");
171                 return -1;
172         }
173
174         // Find x-headers: eoh will be overwritten by \0 to allow the use of
175         // strstr(). The byte at eoh will later be recovered, when the
176         // message body is shifted towards the beginning of the message
177         // to remove the x-headers.
178         *eoh = '\0';
179         xheaders = strstr(sto->body.s, "\r\nX-Siptrace-Fromip: ");
180         if(xheaders == NULL) {
181                 LM_ERR("message without x-headers "
182                            "from %.*s, callid %.*s\n",
183                                 sto->fromip.len, sto->fromip.s, sto->callid.len, sto->callid.s);
184                 return -1;
185         }
186
187         // Allocate memory for new strings in sto
188         // (gets free()ed in sip_trace_xheaders_free() )
189         sto->fromip.s = pkg_malloc(51);
190         sto->toip.s = pkg_malloc(51);
191         sto->method.s = pkg_malloc(51);
192         sto->dir = pkg_malloc(4);
193         if(!(sto->fromip.s && sto->toip.s && sto->method.s && sto->dir)) {
194                 LM_ERR("out of pkg memory\n");
195                 goto erroraftermalloc;
196         }
197
198         // Parse the x-headers: scanf()
199         if(sscanf(xheaders, "\r\n"
200                                                 "X-Siptrace-Fromip: %50s\r\n"
201                                                 "X-Siptrace-Toip: %50s\r\n"
202                                                 "X-Siptrace-Time: %llu %llu\r\n"
203                                                 "X-Siptrace-Method: %50s\r\n"
204                                                 "X-Siptrace-Dir: %3s",
205                            sto->fromip.s, sto->toip.s, &tv_sec, &tv_usec, sto->method.s,
206                            sto->dir)
207                         == EOF) {
208                 LM_ERR("malformed x-headers\n");
209                 goto erroraftermalloc;
210         }
211         sto->fromip.len = strlen(sto->fromip.s);
212         sto->toip.len = strlen(sto->toip.s);
213         sto->tv.tv_sec = (time_t)tv_sec;
214         sto->tv.tv_usec = (suseconds_t)tv_usec;
215         sto->method.len = strlen(sto->method.s);
216
217         // Remove the x-headers: the message body is shifted towards the beginning
218         // of the message, overwriting the x-headers. Before that, the byte at eoh
219         // is recovered.
220         *eoh = '\r';
221         memmove(xheaders, eoh, sto->body.len - (eoh - sto->body.s));
222         sto->body.len -= eoh - xheaders;
223
224         return 0;
225
226 erroraftermalloc:
227         if(sto->fromip.s) {
228                 pkg_free(sto->fromip.s);
229                 sto->fromip.s = 0;
230         }
231         if(sto->toip.s) {
232                 pkg_free(sto->toip.s);
233                 sto->toip.s = 0;
234         }
235         if(sto->method.s) {
236                 pkg_free(sto->method.s);
237                 sto->method.s = 0;
238         }
239         if(sto->dir) {
240                 pkg_free(sto->dir);
241                 sto->dir = 0;
242         }
243         return -1;
244 }
245
246 /**
247  * Frees the memory allocated by sip_trace_xheaders_{write,read}
248  */
249 int sip_trace_xheaders_free(struct _siptrace_data *sto)
250 {
251         if(trace_xheaders_write != 0) {
252                 if(sto->body.s) {
253                         pkg_free(sto->body.s);
254                         sto->body.s = 0;
255                 }
256         }
257
258         if(trace_xheaders_read != 0) {
259                 if(sto->fromip.s) {
260                         pkg_free(sto->fromip.s);
261                         sto->fromip.s = 0;
262                 }
263                 if(sto->toip.s) {
264                         pkg_free(sto->toip.s);
265                         sto->toip.s = 0;
266                 }
267                 if(sto->dir) {
268                         pkg_free(sto->dir);
269                         sto->dir = 0;
270                 }
271         }
272
273         return 0;
274 }
275
276
277 /**
278  *
279  */
280 int trace_send_duplicate(char *buf, int len, dest_info_t *dst2)
281 {
282         dest_info_t dst;
283         dest_info_t pdst;
284         proxy_l_t *p = NULL;
285
286         if(buf == NULL || len <= 0) {
287                 return -1;
288         }
289
290         /* either modparam dup_uri or siptrace param dst2 */
291         if((trace_dup_uri_str.s == 0 || trace_dup_uri == NULL) && (dst2 == NULL)) {
292                 LM_WARN("Neither dup_uri modparam or siptrace destination uri param used!\n");
293                 return 0;
294         }
295
296         init_dest_info(&dst);
297
298         if(!dst2) {
299                 /* create a temporary proxy from dst param */
300                 dst.proto = PROTO_UDP;
301                 p = mk_proxy(&trace_dup_uri->host,
302                                 (trace_dup_uri->port_no) ? trace_dup_uri->port_no : SIP_PORT, dst.proto);
303                 if(p == 0) {
304                         LM_ERR("bad host name in uri\n");
305                         return -1;
306                 }
307                 hostent2su(
308                                 &dst.to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT);
309                 pdst = &dst;
310         } else {
311                 pdst = dst2;
312         }
313
314         if(pdst->send_sock == NULL) {
315                 if(trace_send_sock_str.s) {
316                         LM_DBG("send sock activated, grep for the sock_info\n");
317                         pdst->send_sock = grep_sock_info(&trace_send_sock_uri->host,
318                                         trace_send_sock_uri->port_no,
319                                         trace_send_sock_uri->proto);
320                         if(!pdst->send_sock) {
321                                 LM_WARN("cannot grep socket info\n");
322                         } else {
323                                 LM_DBG("found socket while grep: [%.*s] [%.*s]\n",
324                                                 pdst->send_sock->name.len,
325                                                 pdst->send_sock->name.s, pdst->send_sock->address_str.len,
326                                                 pdst->send_sock->address_str.s);
327                         }
328                 }
329         }
330
331         if(pdst->send_sock == NULL) {
332                 pdst->send_sock = get_send_socket(0, &pdst->to, pdst->proto);
333                 if(pdst->send_sock == 0) {
334                         LM_ERR("cannot forward to af %d, proto %d - no corresponding"
335                                    " listening socket\n",
336                                         pdst->to.s.sa_family, pdst->proto);
337                         goto error;
338                 }
339         }
340
341         if(msg_send(pdst, buf, len) < 0) {
342                 LM_ERR("cannot send duplicate message\n");
343                 goto error;
344         }
345
346         if(p) {
347                 free_proxy(p); /* frees only p content, not p itself */
348                 pkg_free(p);
349         }
350         return 0;
351 error:
352         if(p) {
353                 free_proxy(p); /* frees only p content, not p itself */
354                 pkg_free(p);
355         }
356         return -1;
357 }
358
359 /**
360  *
361  */
362 char* siptrace_proto_name(int vproto)
363 {
364         switch(vproto) {
365                 case PROTO_TCP:
366                         return "tcp";
367                 case PROTO_TLS:
368                         return "tls";
369                 case PROTO_SCTP:
370                         return "sctp";
371                 case PROTO_WS:
372                         return "ws";
373                 case PROTO_WSS:
374                         return "wss";
375                 default:
376                         return "udp";
377         }
378 }