]> The Tcpdump Group git mirrors - tcpslice/blob - sessions.c
Use TS_RAW_US_MAX_DIGITS in parse_time().
[tcpslice] / sessions.c
1 /*
2 * Copyright (c) 2006 Sebastien Raveau <sebastien.raveau@epita.fr>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * This file contains code for tracking TCP and VoIP (SIP & H.323) sessions.
28 *
29 * IMPORTANT: None of these features are available if libnids >= 1.21 wasn't
30 * found by ./configure; SIP session tracking is available only if Libosip was
31 * found by ./configure and H.323 session tracking is available only if
32 * Libooh323c was found by ./configure. These libraries can be downloaded from:
33 * - http://libnids.sourceforge.net/
34 * - https://www.gnu.org/software/osip/
35 * - https://sourceforge.net/projects/ooh323c/
36 *
37 * There are several entry points (from tcpslice.c) to this file:
38 * - sessions_init() has to be called once before any tracking can be done
39 * - sessions_nids_init() has to be called each time we change PCAP file
40 * - sessions_exit() is used to clean up and report after we're done
41 * - ip_callback() is called for defragmented IPv4 packets, including UDP & TCP
42 * - udp_callback() is called upon reception of correct UDP data
43 * - tcp_callback() is called upon reception of correct TCP data
44 */
45
46 #include <config.h>
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <errno.h>
51
52 #include "varattrs.h"
53 #include "sessions.h"
54 #include "diag-control.h"
55
56 /*
57 * The global variables below have the following purposes:
58 *
59 * `verbose' counts how many times -v was specified on the
60 * command line. It is currently used by sessions_add() and
61 * sessions_del() to show when sessions are opened and closed.
62 * Specify -v once and it will show opening and closing of
63 * primary sessions, but specify it at least twice to see
64 * the opening and closing of subsessions, i.e. sessions that
65 * are created because of some primary sessions (for example
66 * a SIP session will open a RTP session for the call data).
67 *
68 * `bonus_time' equals 0 when we are between the start-time and
69 * end-time specified by the user on the command line, and 1 when
70 * we are past the end-time, in which case we continue to track
71 * the existing sessions but ignore new sessions.
72 *
73 * `track_sessions' is a flag set by sessions_init() and
74 * sessions_exit() but it is mostly used in tcpslice.c to know
75 * whether or not to pass each PCAP frame to libnids in order to
76 * track sessions (it saves further processing if the user did
77 * not want to track sessions, which should be the case most of
78 * the time).
79 *
80 * `sessions_count` is the number of active sessions at a time;
81 * it is especially used by sessions_exit() to print a report about
82 * unclosed sessions in case there are any left when we are done.
83 *
84 * `sessions_file_format' is either NULL if the user does not want
85 * each primary session and all of its subsessions to be extracted
86 * and saved to separate PCAP files, or a string of the form
87 * "/path/filename-%s-%d.pcap", where %s will be replaced by the
88 * primary session type string in lowercase ("tcp", "sip" or "h323")
89 * and %d by the primary session ID. Note that you can specify %.6d
90 * instead of %d so that files can correctly be sorted by session ID
91 * (which will be zero-padded on the left up to six digits); this
92 * prevents having x-sip-10.pcap before x-sip-2.pcap for example.
93 *
94 * `sessions_expiration_delay' can be set by the user to a number
95 * of seconds after which an idle tracked session will be considered
96 * to be closed. This is useful to deal with faulty implementations
97 * of some protocols or packet loss, which otherwise would keep
98 * resources allocated until the call to sessions_exit().
99 */
100 int verbose = 0;
101 int bonus_time = 0;
102 int track_sessions = 0;
103 uint32_t sessions_count = 0;
104 char *sessions_file_format = NULL;
105 time_t sessions_expiration_delay = 0;
106
107 #ifndef HAVE_LIBNIDS
108
109 void
110 sessions_init(const char *types _U_)
111 {
112 error("libnids required for session tracking support, sorry.");
113 }
114
115 void sessions_exit(void)
116 {
117 }
118
119 void sessions_nids_init(pcap_t *p _U_)
120 {
121 }
122
123 #else /* HAVE_LIBNIDS */
124
125 # include <string.h>
126 # include <nids.h>
127 # ifdef HAVE_LIBOSIPPARSER2
128 # include <osip2/osip.h>
129 # include <osipparser2/sdp_message.h>
130 # endif /* HAVE_LIBOSIPPARSER2 */
131 # ifdef HAVE_LIBOOH323C
132 # include <ooh323.h>
133 # include <ooCalls.h>
134 # include <printHandler.h>
135 # include <ooh323ep.h>
136 # endif /* HAVE_LIBOOH323C */
137 # include "tcpslice.h"
138 # include <netinet/ip.h>
139 # define IPHDRLEN (sizeof(struct ip))
140 # include <netinet/udp.h>
141 # define UDPHDRLEN (sizeof(struct udphdr))
142 # include <netinet/tcp.h>
143 # define TCPHDRLEN (sizeof(struct tcphdr))
144 # include <netinet/in.h>
145 # include <arpa/inet.h>
146
147 /*
148 * Session type identifiers, used as bitmasks for
149 * convenience in searches among tracked sessions.
150 */
151 enum type
152 {
153 TYPE_NONE = 0x00,
154 TYPE_UDP = 0x01,
155 TYPE_TCP = 0x02,
156 TYPE_SIP = 0x04,
157 TYPE_RTP = 0x08,
158 TYPE_RTCP = 0x10,
159 TYPE_H225_RAS = 0x20,
160 TYPE_H225_CS = 0x40,
161 CLASS_SIP = TYPE_SIP | TYPE_RTP,
162 CLASS_H323 = TYPE_H225_RAS | TYPE_H225_CS | TYPE_RTP | TYPE_RTCP
163 };
164
165 /*
166 * Structure used by sessions and subsessions to safely share
167 * the same file descriptor, when they have to be saved in the
168 * same PCAP file and can be closed in a different order than
169 * they were opened.
170 */
171 struct shared_dumper
172 {
173 char *filename;
174 pcap_dumper_t *filedesc;
175 uint32_t references;
176 };
177
178 /*
179 * (Almost) generic session description object containing
180 * the following properties:
181 * - addr: IPv4 address & port for source and destination
182 * - type: protocol bitmask (e.g. TYPE_UDP | TYPE_SIP)
183 * - id: unique number assigned to each session
184 * - parent_id: instead of a pointer (which is dangerous because parents
185 * are sometimes destroyed before their children) an ID
186 * that can be used to search for children of a specific session
187 * - parent_id: 0 for primary sessions, parent's ID for subsessions
188 * - timeout: when the session has to be forcefully closed
189 * - callback: method to call in order to process session data
190 * - dumper: file to which this session's packets will be extracted
191 * - lastseen: timestamp of the last packet in this session
192 * - bytes: total amount of data captured for this session
193 * - next: pointer to the next session in the list of all sessions
194 * - prev: pointer to the previous session in the list of all sessions
195 * - u: union containing extra properties that are needed for some session types
196 */
197 struct session
198 {
199 struct tuple4 addr;
200 enum type type;
201 uint32_t id;
202 uint32_t parent_id;
203 time_t timeout;
204 struct session *(*callback)(struct session *elt, u_char *data, uint32_t len);
205 struct shared_dumper *dumper;
206 struct timeval lastseen;
207 uint64_t bytes;
208 struct session *next;
209 struct session *prev;
210 # if defined(HAVE_LIBOSIPPARSER2) || defined(HAVE_LIBOOH323C)
211 union
212 {
213 # ifdef HAVE_LIBOSIPPARSER2
214 struct
215 {
216 struct tuple4 rtp_addr;
217 osip_call_id_t *call_id;
218 int picked_up;
219 } sip_params;
220 # endif /* HAVE_LIBOSIPPARSER2 */
221 # ifdef HAVE_LIBOOH323C
222 struct
223 {
224 struct tuple4 cs_addr;
225 H225RequestSeqNum seqnum;
226 char call_id[16];
227 } ras_params;
228 # endif /* HAVE_LIBOOH323C */
229 } u;
230 # endif /* defined(HAVE_LIBOSIPPARSER2) || defined(HAVE_LIBOOH323C) */
231 };
232
233 /*
234 * Pointer to the head of the list containing all tracked sessions
235 */
236 static struct session *first_session = NULL;
237
238 /*
239 * Bitmask of the session types the user asked to track
240 */
241 static enum type sessions_track_types = TYPE_NONE;
242
243 /*
244 * Count how many PCAP savefiles were opened, to cope with the
245 * "Too many open files" errors and work around them by closing
246 * the oldest 10% of the file descriptors.
247 */
248 static unsigned int dumper_fd_count = 0;
249
250 /*
251 * The static functions declared below have the following purposes:
252 *
253 * `sessions_add' checks if a session must be tracked or not depending on
254 * what the user wants (i.e. if `t' matches `sessions_track_types'); if so
255 * it creates a new session object, fills in the properties (based on `addr'
256 * and `parent' if there is one) and inserts in the list of tracked sessions.
257 *
258 * `sessions_del' properly removes a session object from the list.
259 *
260 * `sessions_find' is a small search engine acting on several criteria; it
261 * can search starting from the beginning of the list or from the element
262 * pointed by the `start' parameter, it can search for sessions with specific
263 * types described by the `t' parameter, or by parent ID, or most of the time
264 * by source and destination IP address & port.
265 *
266 * `dumper_open' and `dumper_close' manage multiple references to the same
267 * PCAP file used for saving packets when the user asked for extraction of
268 * sessions into separate files. `dumper_too_many_open_files' tries to cope
269 * with the "Too many open files" error that can happen when dealing with
270 * large PCAP files containing many simultaneous sessions.
271 *
272 * `dump_frame' actually saves the current packet to a PCAP file.
273 *
274 * `parse_type' simply converts a type from string to numerical form.
275 *
276 * `type2string' simply converts a type from numerical form to string.
277 *
278 * `ip_callback', `tcp_callback' and `udp_callback' are called from inside
279 * libnids upon reception of respectively IPv4, TCP and UDP packets.
280 *
281 * `sip_callback', `h225_ras_callback' and `h225_cs_callback' are called
282 * from `tcp_callback' and `udp_callback' via the session::callback field,
283 * in order to process respectively IETF's Session Initialization Protocol,
284 * ITU's H.225 Registration Admission Status and H.225 Call Signaling (both
285 * part of H.323) data.
286 */
287 static struct session *sessions_add(const uint8_t t, const struct tuple4 *addr, const struct session *parent);
288 static void sessions_del(struct session *elt);
289 static struct session *sessions_find(struct session *start, const uint8_t t, const uint32_t parent_id, const struct tuple4 *addr);
290 static struct shared_dumper *dumper_open(const enum type t, const uint32_t id);
291 static void dumper_too_many_open_files(struct shared_dumper **d);
292 static void dumper_close(struct shared_dumper *d);
293 static void dump_frame(const u_char *data, const int len, struct shared_dumper *output);
294 static enum type parse_type(const char *str);
295 static const char *type2string(const enum type t, const int upper);
296 static void ip_callback(struct ip *ip, int len);
297 static void tcp_callback(struct tcp_stream *tcp, void **user);
298 static void udp_callback(struct tuple4 *addr, u_char *data, int len, struct ip *ip);
299 static struct session *sip_callback(struct session *elt, u_char *data, uint32_t len);
300 static struct session *h225_ras_callback(struct session *elt, u_char *data, uint32_t len);
301 static struct session *h225_cs_callback(struct session *elt, u_char *data, uint32_t len);
302
303 static enum type parse_type(const char *str)
304 {
305 if (!strcmp("tcp", str))
306 return TYPE_TCP;
307 # ifdef HAVE_LIBOSIPPARSER2
308 if (!strcmp("sip", str))
309 return CLASS_SIP;
310 # endif /* HAVE_LIBOSIPPARSER2 */
311 # ifdef HAVE_LIBOOH323C
312 if (!strcmp("h323", str))
313 return CLASS_H323;
314 # endif /* HAVE_LIBOOH323C */
315 error("unsupported session type `%s'", str);
316 /* NOTREACHED */
317 return TYPE_NONE;
318 }
319
320 void
321 sessions_init(const char *types)
322 {
323 char *comma;
324
325 bonus_time = 0;
326 sessions_track_types = TYPE_NONE;
327 while (NULL != (comma = strchr(types, ','))) {
328 *comma = '\0';
329 sessions_track_types |= parse_type(types);
330 types = comma + 1;
331 }
332 sessions_track_types |= parse_type(types);
333 while (sessions_count) {
334 struct session *elt = first_session;
335 first_session = first_session->next;
336 --sessions_count;
337 dumper_close(elt->dumper);
338 free(elt);
339 }
340 # ifdef HAVE_LIBOOH323C
341 ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, "/dev/null");
342 ooH323EpDisableAutoAnswer();
343 # endif /* HAVE_LIBOOH323C */
344 track_sessions = 1;
345 }
346
347 void sessions_exit(void)
348 {
349 struct session *elt;
350 struct session *elt_next;
351 time_t one_minute_later = 0;
352
353 /*
354 * Last pass to close timeout'd session... It is needed
355 * because the last packet of a session marked for
356 * deletion can be followed only by non-IP packets, so
357 * it won't be deleted by ip_callback and would otherwise
358 * appear as unclosed in the report generated below.
359 * We jump forward one minute in order to timeout TCP
360 * sessions that were opened during the last minute
361 * of capture, which were given 60 seconds to complete
362 * handshake but failed to do so.
363 *
364 * Also close SIP sessions that did not result in a call:
365 * it happens often and the resulting spam in the report
366 * generated below can be really annoying.
367 */
368 if (NULL != nids_last_pcap_header)
369 one_minute_later = nids_last_pcap_header->ts.tv_sec + 60;
370 for (elt = first_session; NULL != elt; elt = elt_next) {
371 elt_next = elt->next;
372 if (elt->timeout && (one_minute_later >= elt->timeout)) {
373 sessions_del(elt);
374 continue;
375 }
376 # ifdef HAVE_LIBOSIPPARSER2
377 if ((elt->type & TYPE_SIP) && !elt->u.sip_params.picked_up)
378 sessions_del(elt);
379 # endif /* HAVE_LIBOSIPPARSER2 */
380 }
381
382 /*
383 * Print a report about unclosed sessions.
384 */
385 if (sessions_count) {
386 fprintf(stderr,
387 "%u unclosed %s (id, type, last, source, destination, bytes):\n",
388 sessions_count, sessions_count > 1 ? "sessions" : "session");
389 while (NULL != first_session) {
390 fprintf(stderr, "#%u\t", first_session->id);
391 fprintf(stderr, "%s\t", type2string(first_session->type, 1));
392 fprintf(stderr, "%s\t", timestamp_to_string(&first_session->lastseen));
393 fprintf(stderr, "%15s:%-5d\t",
394 inet_ntoa(*((struct in_addr *)&first_session->addr.saddr)),
395 first_session->addr.source);
396 fprintf(stderr, "%15s:%-5d\t",
397 inet_ntoa(*((struct in_addr *)&first_session->addr.daddr)),
398 first_session->addr.dest);
399 fprintf(stderr, "%12" PRIu64 "\n", first_session->bytes);
400 dumper_close(first_session->dumper);
401 if (NULL != first_session->next) {
402 first_session = first_session->next;
403 free(first_session->prev);
404 first_session->prev = NULL;
405 } else {
406 free(first_session);
407 first_session = NULL;
408 }
409 --sessions_count;
410 }
411 }
412 track_sessions = 0;
413 nids_exit();
414 }
415
416 void sessions_nids_init(pcap_t *p)
417 {
418 nids_params.pcap_desc = p;
419 nids_params.tcp_workarounds = 1;
420 if (!nids_init()) {
421 error("%s(): %s", __func__, nids_errbuf);
422 }
423 /*
424 * These conversions between function pointer and void pointer upset GCC,
425 * Clang and XL C.
426 * See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584
427 */
428 DIAG_OFF_PEDANTIC
429 nids_register_ip(ip_callback);
430 nids_register_udp(udp_callback);
431 nids_register_tcp(tcp_callback);
432 DIAG_ON_PEDANTIC
433 }
434
435 static struct session *
436 sessions_add(const uint8_t t, const struct tuple4 *addr, const struct session *parent)
437 {
438 struct session *elt;
439 static uint32_t counter = 0;
440
441 if (!(t & sessions_track_types))
442 return NULL;
443 elt = (struct session *) calloc(1, sizeof(struct session));
444 elt->addr = *addr;
445 elt->type = t;
446 elt->id = ++counter;
447 if (sessions_expiration_delay)
448 elt->timeout = nids_last_pcap_header->ts.tv_sec + sessions_expiration_delay;
449 if (t & TYPE_SIP)
450 elt->callback = sip_callback;
451 else
452 if (t & TYPE_H225_RAS)
453 elt->callback = h225_ras_callback;
454 else
455 if (t & TYPE_H225_CS)
456 elt->callback = h225_cs_callback;
457 else
458 elt->callback = NULL;
459 if (NULL != parent) {
460 elt->parent_id = parent->id;
461 elt->dumper = parent->dumper;
462 elt->dumper->references++;
463 } else
464 elt->dumper = sessions_file_format ? dumper_open(t, elt->id) : NULL;
465 elt->next = first_session;
466 if (NULL != elt->next)
467 elt->next->prev = elt;
468 elt->prev = NULL;
469 first_session = elt;
470 ++sessions_count;
471 if (verbose && (!elt->parent_id || verbose > 1))
472 printf("Session #%u (%s) opened at %s (active sessions total: %u)\n",
473 elt->parent_id ? elt->parent_id : elt->id,
474 type2string(t, 1),
475 timestamp_to_string(&nids_last_pcap_header->ts),
476 sessions_count);
477 return elt;
478 }
479
480 static void sessions_del(struct session *elt)
481 {
482 struct tcp_stream *tcp;
483
484 if (NULL == elt)
485 return;
486 --sessions_count;
487 if ((bonus_time || verbose) && (!elt->parent_id || verbose > 1))
488 printf("Session #%u (%s) closed at %s (active sessions total: %u)\n",
489 elt->parent_id ? elt->parent_id : elt->id,
490 type2string(elt->type, 1),
491 timestamp_to_string(&nids_last_pcap_header->ts),
492 sessions_count);
493 if (NULL != elt->next)
494 elt->next->prev = elt->prev;
495 if (NULL != elt->prev)
496 elt->prev->next = elt->next;
497 else
498 first_session = elt->next;
499
500 /*
501 * If this is a TCP connection, tell libnids we do not
502 * want to be notified of new data in this connection.
503 *
504 * We must not do it when the stream is already in a
505 * closing state (NIDS_CLOSE, NIDS_TIMED_OUT, NIDS_RESET
506 * or NIDS_EXITING) because nids_free_tcp_stream() would
507 * then be called twice, resulting in a crash.
508 */
509 if ((elt->type & TYPE_TCP) &&
510 (NULL != (tcp = nids_find_tcp_stream(&elt->addr))) &&
511 (NIDS_DATA == tcp->nids_state))
512 nids_free_tcp_stream(tcp);
513
514 # ifdef HAVE_LIBOSIPPARSER2
515 /*
516 * If this is a SIP session, finally free the memory
517 * allocated for the call ID (couldn't be done before)
518 */
519 if (elt->type & TYPE_SIP)
520 if (NULL != elt->u.sip_params.call_id)
521 osip_call_id_free(elt->u.sip_params.call_id);
522 # endif /* HAVE_LIBOSIPPARSER2 */
523
524 dumper_close(elt->dumper);
525 free(elt);
526 }
527
528 static struct session *
529 sessions_find(struct session *start, const uint8_t t, const uint32_t parent_id, const struct tuple4 *addr)
530 {
531 struct session *elt;
532
533 for (elt = start; NULL != elt; elt = elt->next) {
534 if (!(elt->type & t))
535 continue;
536 if (parent_id && (elt->parent_id != parent_id))
537 continue;
538 if (NULL != addr) {
539 if ((!elt->addr.source || elt->addr.source == addr->source) &&
540 (!elt->addr.dest || elt->addr.dest == addr->dest) &&
541 (!elt->addr.saddr || elt->addr.saddr == addr->saddr) &&
542 (!elt->addr.daddr || elt->addr.daddr == addr->daddr))
543 return elt;
544 if ((!elt->addr.source || elt->addr.source == addr->dest) &&
545 (!elt->addr.dest || elt->addr.dest == addr->source) &&
546 (!elt->addr.saddr || elt->addr.saddr == addr->daddr) &&
547 (!elt->addr.daddr || elt->addr.daddr == addr->saddr))
548 return elt;
549 }
550 if (parent_id)
551 return elt;
552 }
553 return NULL;
554 }
555
556 static struct shared_dumper *
557 dumper_open(const enum type t, const uint32_t id)
558 {
559 struct shared_dumper *d;
560
561 d = malloc(sizeof (struct shared_dumper));
562 d->filename = malloc(strlen(sessions_file_format) + strlen(type2string(t, 0)) + 16);
563 sprintf(d->filename, sessions_file_format, type2string(t, 0), id);
564 d->filedesc = pcap_dump_open(nids_params.pcap_desc, d->filename);
565 if (NULL == d->filedesc)
566 dumper_too_many_open_files(&d);
567 ++dumper_fd_count;
568 d->references = 1;
569 return d;
570 }
571
572 static void dumper_too_many_open_files(struct shared_dumper **d)
573 {
574 struct session *elt;
575 unsigned int oldest_ten_percent;
576
577 oldest_ten_percent = sessions_count / 10;
578 if (EMFILE == errno && oldest_ten_percent) {
579 for (elt = first_session; NULL != elt; elt = elt->next) {
580 if (NULL != elt->dumper->filedesc) {
581 pcap_dump_close(elt->dumper->filedesc);
582 elt->dumper->filedesc = NULL;
583 --dumper_fd_count;
584 if (!--oldest_ten_percent)
585 break;
586 }
587 }
588 (*d)->filedesc = pcap_dump_open(nids_params.pcap_desc, (*d)->filename);
589 }
590 if (NULL == (*d)->filedesc) {
591 error("%s(): %s: %s", __func__,
592 (*d)->filename,
593 pcap_geterr(nids_params.pcap_desc));
594 }
595 }
596
597 static void dumper_close(struct shared_dumper *d)
598 {
599 if (NULL == d)
600 return;
601 --d->references;
602 if (!d->references) {
603 free(d->filename);
604 if (NULL != d->filedesc) {
605 pcap_dump_close(d->filedesc);
606 --dumper_fd_count;
607 }
608 }
609 }
610
611 static const char *
612 type2string(const enum type t, const int upper)
613 {
614 if (t & TYPE_SIP)
615 return upper ? "SIP" : "sip";
616 if ((t & TYPE_H225_RAS) || (t & TYPE_H225_CS))
617 return upper ? "H323" : "h323";
618 if (t & TYPE_RTP)
619 return upper ? "RTP" : "rtp";
620 if (t & TYPE_TCP)
621 return upper ? "TCP" : "tcp";
622 return "???";
623 }
624
625 static void
626 dump_frame(const u_char *data, const int len, struct shared_dumper *output)
627 {
628 u_char *frame;
629 struct pcap_pkthdr ph;
630
631 if (!bonus_time && NULL == output)
632 return;
633 frame = malloc(len + nids_linkoffset);
634 memcpy(frame, nids_last_pcap_data, nids_linkoffset);
635 memcpy(frame + nids_linkoffset, data, len);
636 ph.ts = nids_last_pcap_header->ts;
637 ph.caplen = ph.len = len + nids_linkoffset;
638 if (NULL != output) {
639 if (NULL == output->filedesc) {
640 output->filedesc = pcap_dump_open(nids_params.pcap_desc, output->filename);
641 if (NULL == output->filedesc)
642 dumper_too_many_open_files(&output);
643 ++dumper_fd_count;
644 }
645 pcap_dump((u_char *)output->filedesc, &ph, frame);
646 }
647 if (bonus_time)
648 pcap_dump((u_char *)global_dumper, &ph, frame);
649 free(frame);
650 }
651
652 /*
653 * This function is called upon reception of all IPv4 packets, which
654 * means some packets will be processed by both ip_callback and
655 * {udp,tcp}_callback. It is necessary for TCP packets though because
656 * tcp_callback is only called once a connection is established (i.e.
657 * after the first SYN, SYN+ACK and ACK packets have passed) and only
658 * when data is available (PSH packets).
659 * Since we don't want failed TCP connections (portscans etc) to
660 * mobilize resources, we give TCP sessions 60 seconds to complete
661 * the TCP handshake or else they are considered to be closed.
662 */
663 static void ip_callback(struct ip *ip, int len)
664 {
665 struct tuple4 addr;
666 struct tcphdr *tcp;
667 struct session *elt;
668 struct session *elt_next;
669 unsigned int ip_data_offset = IPHDRLEN;
670
671 if (len < 0)
672 error("%s(): len < 0", __func__);
673
674 for (elt = first_session; NULL != elt; elt = elt_next) {
675 elt_next = elt->next;
676 if (elt->timeout && (nids_last_pcap_header->ts.tv_sec >= elt->timeout))
677 sessions_del(elt);
678 }
679 if ((ip->ip_hl > 5) && ((ip->ip_hl * 4) <= len))
680 ip_data_offset = ip->ip_hl * 4;
681 if ((ip->ip_p != 6) || ((unsigned)len < (ip_data_offset + TCPHDRLEN)))
682 return; /* not TCP or too short */
683 tcp = (struct tcphdr *)((char *)ip + ip_data_offset);
684 addr.saddr = *((u_int *)&ip->ip_src);
685 addr.daddr = *((u_int *)&ip->ip_dst);
686 addr.source = ntohs(tcp->th_sport);
687 addr.dest = ntohs(tcp->th_dport);
688 if (NULL != (elt = sessions_find(first_session, TYPE_TCP, 0, &addr))) {
689 dump_frame((u_char *)ip, len, elt->dumper);
690 if (sessions_expiration_delay)
691 elt->timeout = nids_last_pcap_header->ts.tv_sec + sessions_expiration_delay;
692 elt->lastseen = nids_last_pcap_header->ts;
693 return;
694 }
695 if (!(tcp->th_flags & TH_SYN) || bonus_time)
696 return;
697 if (addr.source == 5060 || addr.dest == 5060)
698 elt = sessions_add(TYPE_TCP | TYPE_SIP, &addr, NULL);
699 else
700 elt = sessions_add(TYPE_TCP, &addr, NULL);
701 if (NULL == elt)
702 return;
703 dump_frame((u_char *)ip, len, elt->dumper);
704 elt->timeout = nids_last_pcap_header->ts.tv_sec + 60;
705 /* 60 seconds to complete TCP handshake */
706 }
707
708 static void udp_callback(struct tuple4 *addr, u_char *udp_data, int udp_data_len, struct ip *ip)
709 {
710 struct session *elt;
711 unsigned int udp_data_offset = IPHDRLEN + UDPHDRLEN;
712
713 if (NULL == (elt = sessions_find(first_session, TYPE_UDP, 0, addr))) {
714 if (bonus_time)
715 return;
716 if (addr->source == 1719 || addr->dest == 1719)
717 elt = sessions_add(TYPE_UDP | TYPE_H225_RAS, addr, NULL);
718 else
719 if (addr->source == 5060 || addr->dest == 5060)
720 elt = sessions_add(TYPE_UDP | TYPE_SIP, addr, NULL);
721 }
722 if (NULL == elt)
723 return;
724 elt->bytes += udp_data_len;
725 elt->lastseen = nids_last_pcap_header->ts;
726 if (NULL != elt->callback)
727 elt = elt->callback(elt, udp_data, udp_data_len);
728
729 /*
730 * We can dump the frame only after the data is processed because
731 * a new session object (`elt') might be created by the callback,
732 * with a pointer to a different PCAP file.
733 */
734 if ((ip->ip_hl > 5) && ((ip->ip_hl * 4U) < (udp_data_offset + udp_data_len)))
735 udp_data_offset = ip->ip_hl * 4 + UDPHDRLEN;
736 dump_frame((u_char *)ip, udp_data_offset + udp_data_len, elt->dumper);
737 }
738
739 static void tcp_callback(struct tcp_stream *tcp, void **user)
740 {
741 struct session *elt;
742 struct session *rtp;
743 struct session *start;
744
745 switch (tcp->nids_state) {
746 case NIDS_JUST_EST:
747 if (bonus_time)
748 return;
749 elt = sessions_find(first_session, TYPE_TCP, 0, &tcp->addr);
750 if (NULL == elt)
751 return;
752 if (elt->type & TYPE_H225_CS) {
753 elt->addr.saddr = tcp->addr.saddr;
754 elt->addr.source = tcp->addr.source;
755 }
756 *user = elt;
757 if (!sessions_expiration_delay)
758 elt->timeout = 0;
759 tcp->client.collect++;
760 tcp->server.collect++;
761 return;
762 case NIDS_DATA:
763 elt = (struct session *)*user;
764 elt->bytes += tcp->client.count_new + tcp->server.count_new;
765 if (NULL != elt->callback) {
766 if (tcp->client.count_new)
767 elt->callback(elt, (u_char *)tcp->client.data, tcp->client.count_new);
768 if (tcp->server.count_new)
769 elt->callback(elt, (u_char *)tcp->server.data, tcp->server.count_new);
770 }
771 return;
772 case NIDS_CLOSE:
773 case NIDS_RESET:
774 case NIDS_TIMED_OUT:
775 elt = (struct session *)*user;
776 if (elt->type & TYPE_H225_CS)
777 for (start = first_session; NULL != (rtp = sessions_find(start, TYPE_RTP | TYPE_RTCP, elt->id, NULL)); start = rtp->next)
778 sessions_del(rtp);
779 sessions_del((struct session *)*user);
780 }
781 }
782
783 # ifndef HAVE_LIBOSIPPARSER2
784 static struct session *sip_callback(struct session *sip, u_char *data _U_, uint32_t len _U_)
785 {
786 return sip;
787 }
788 # else /* HAVE_LIBOSIPPARSER2 */
789 static int
790 sip_get_address(const osip_message_t *msg, u_int *host, u_short *port)
791 {
792 osip_content_type_t *ctt;
793 sdp_message_t *sdp;
794 int i;
795 int j;
796
797 if (NULL == (ctt = osip_message_get_content_type(msg)))
798 return 0;
799 if ((NULL == ctt->type) || (NULL == ctt->subtype))
800 return 0;
801 if (osip_strcasecmp(ctt->type, "application"))
802 return 0;
803 if (osip_strcasecmp(ctt->subtype, "sdp"))
804 return 0;
805 for (i = 0; !osip_list_eol(&msg->bodies, i); ++i) {
806 sdp = NULL;
807 sdp_message_init(&sdp);
808 char *tmp = ((osip_body_t *)osip_list_get(&msg->bodies, i))->body;
809 if (sdp_message_parse(sdp, tmp)) {
810 sdp_message_free(sdp);
811 continue;
812 }
813 for (j = 0; NULL != sdp_message_m_media_get(sdp, j); ++j) {
814 if (NULL == (tmp = sdp_message_m_port_get(sdp, j)))
815 continue;
816 *port = atoi(tmp);
817 if (NULL == (tmp = sdp_message_c_addr_get(sdp, -1, 0)))
818 if (NULL == (tmp = sdp_message_c_addr_get(sdp, j, 0)))
819 continue;
820 *host = (u_int)inet_addr(tmp);
821 sdp_message_free(sdp);
822 return 1;
823 }
824 sdp_message_free(sdp);
825 }
826 return 0;
827 }
828
829 static struct session *sip_callback(struct session *sip, u_char *data, uint32_t len)
830 {
831 osip_message_t *msg;
832 struct session *start;
833 struct session *rtp;
834 osip_call_id_t *call_id;
835
836 osip_message_init(&msg);
837 if (!osip_message_parse(msg, (char *)data, len)) {
838 if (NULL == sip->u.sip_params.call_id) {
839 /*
840 * If the session object was created by udp_callback
841 * we need to fill in the call_id field here because
842 * udp_callback doesn't know anything about SIP
843 */
844 if (NULL != (call_id = osip_message_get_call_id(msg)))
845 osip_call_id_clone(call_id, &sip->u.sip_params.call_id);
846 } else {
847 /*
848 * Otherwise check if the session object passed to this
849 * function call was really the one corresponding to the
850 * call ID in the SIP packet, in case several SIP calls
851 * are passed upon the same transport layer protocol,
852 * source and destination IPv4 address & port combination.
853 * udp_callback has no way of knowing how to distinguish
854 * SIP session objects based on call ID, so we have to do
855 * it here. We just continue searching in the list of all
856 * tracked sessions for similar SIP objects until we find
857 * one that has the same call ID, or else we create a new
858 * SIP session object that corresponds to the new call.
859 */
860 start = sip;
861 do {
862 if (NULL == (call_id = osip_message_get_call_id(msg)))
863 continue;
864 if (!osip_call_id_match(sip->u.sip_params.call_id, call_id))
865 break;
866 } while ((sip = sessions_find(sip->next, TYPE_SIP, 0, &sip->addr)));
867 if (NULL == sip) {
868 if (bonus_time) {
869 osip_message_free(msg);
870 return start;
871 }
872 sip = sessions_add(start->type, &start->addr, NULL);
873 if (NULL != (call_id = osip_message_get_call_id(msg)))
874 osip_call_id_clone(call_id, &sip->u.sip_params.call_id);
875 }
876 }
877 /*
878 * If the current SIP packet is an INVITE message, store the
879 * advertised source port and IPv4 address. It is not very
880 * important, since we can do only with the destination part
881 * (useful in case the capture missed the INVITE packet), but
882 * it helps discriminating from unrelated packets.
883 *
884 * Unfortunately, some SIP implementations such as the one in
885 * Audiocodes Mediant 1000 SIP gateways actually use a source
886 * port different from the one they advertised in the INVITE
887 * message parameters - how outrageous! - so we have to make
888 * our sessions search engine ignore the source port part by
889 * zeroing it :-/
890 */
891 if (MSG_IS_INVITE(msg)) {
892 if (!bonus_time) {
893 sip_get_address(msg, &sip->u.sip_params.rtp_addr.saddr, &sip->u.sip_params.rtp_addr.source);
894 #ifndef USING_NON_STUPID_SIP_IMPLEMENTATIONS
895 sip->u.sip_params.rtp_addr.source = 0;
896 #endif
897 }
898 } else
899 if (MSG_TEST_CODE(msg, 200)) {
900 if (MSG_IS_RESPONSE_FOR(msg, "INVITE")) {
901 if (!bonus_time && sip_get_address(msg, &sip->u.sip_params.rtp_addr.daddr, &sip->u.sip_params.rtp_addr.dest)) {
902 sessions_add(TYPE_UDP | TYPE_RTP, &sip->u.sip_params.rtp_addr, sip);
903 sip->u.sip_params.picked_up = 1;
904 }
905 } else
906 if (MSG_IS_RESPONSE_FOR(msg, "BYE") ||
907 MSG_IS_RESPONSE_FOR(msg, "CANCEL")) {
908 start = first_session;
909 while (NULL != (rtp = sessions_find(start, TYPE_RTP, sip->id, NULL))) {
910 sessions_del(rtp);
911 start = rtp->next;
912 }
913 /*
914 * Mark for deletion in 2 seconds, in order to give some
915 * time to the extra ACK packets that might be exchanged
916 */
917 if (sip->type & TYPE_UDP)
918 sip->timeout = nids_last_pcap_header->ts.tv_sec + 2;
919 }
920 }
921 }
922 osip_message_free(msg);
923 return sip;
924 }
925 # endif /* HAVE_LIBOSIPPARSER2 */
926
927 # ifndef HAVE_LIBOOH323C
928 static struct session *h225_ras_callback(struct session *ras, u_char *data _U_, uint32_t len _U_)
929 {
930 return ras;
931 }
932
933 static struct session *h225_cs_callback(struct session *cs, u_char *data _U_, uint32_t len _U_)
934 {
935 return cs;
936 }
937 # else /* HAVE_LIBOOH323C */
938 static struct session *h225_ras_callback(struct session *ras, u_char *data, uint32_t len)
939 {
940 OOCTXT ctxt;
941 H225RasMessage *pRasMsg;
942 struct session *cs;
943 struct session *rasbkp;
944
945 initContext(&ctxt);
946 if (ASN_OK != setPERBuffer(&ctxt, data, len, TRUE))
947 return ras;
948 rasbkp = ras;
949 pRasMsg = (H225RasMessage *)memAlloc(&ctxt, sizeof (H225RasMessage));
950 if (ASN_OK == asn1PD_H225RasMessage(&ctxt, pRasMsg))
951 switch (pRasMsg->t) {
952 case T_H225RasMessage_admissionRequest:
953 if (bonus_time)
954 break;
955 if ('\0' != ras->u.ras_params.call_id[0])
956 ras = sessions_add(TYPE_UDP | TYPE_H225_RAS, &ras->addr, NULL);
957 memcpy(ras->u.ras_params.call_id, pRasMsg->u.admissionRequest->conferenceID.data, 16);
958 ras->u.ras_params.seqnum = pRasMsg->u.admissionRequest->requestSeqNum;
959 ras->timeout = nids_last_pcap_header->ts.tv_sec + 60;
960 /* 60 seconds for the gatekeeper to confirm admission */
961 break;
962 case T_H225RasMessage_admissionConfirm:
963 if (bonus_time)
964 break;
965 while ((NULL != ras) && (ras->u.ras_params.seqnum != pRasMsg->u.admissionConfirm->requestSeqNum))
966 ras = sessions_find(ras->next, TYPE_UDP | TYPE_H225_RAS, 0, &ras->addr);
967 if (NULL == ras) {
968 ras = rasbkp;
969 break;
970 }
971 if (pRasMsg->u.admissionConfirm->destCallSignalAddress.t != T_H225TransportAddress_ipAddress) {
972 ras->timeout = nids_last_pcap_header->ts.tv_sec; /* delete after dumping frame */
973 break;
974 }
975 ras->u.ras_params.cs_addr.dest = pRasMsg->u.admissionConfirm->destCallSignalAddress.u.ipAddress->port;
976 ras->u.ras_params.cs_addr.daddr = *((u_int *)pRasMsg->u.admissionConfirm->destCallSignalAddress.u.ipAddress->ip.data);
977 if (NULL != (cs = sessions_add(TYPE_TCP | TYPE_H225_CS, &ras->u.ras_params.cs_addr, ras)))
978 cs->timeout = nids_last_pcap_header->ts.tv_sec + 60;
979 /* 60 seconds to establish the Call Signaling stream */
980 break;
981 case T_H225RasMessage_admissionReject:
982 while ((NULL != ras) && (ras->u.ras_params.seqnum != pRasMsg->u.admissionReject->requestSeqNum))
983 ras = sessions_find(ras->next, TYPE_UDP | TYPE_H225_RAS, 0, &ras->addr);
984 if (NULL == ras) {
985 ras = rasbkp;
986 break;
987 }
988 ras->timeout = nids_last_pcap_header->ts.tv_sec; /* delete after dumping frame */
989 break;
990 case T_H225RasMessage_disengageRequest:
991 while ((NULL != ras) && memcmp(ras->u.ras_params.call_id, pRasMsg->u.disengageRequest->conferenceID.data, 16))
992 ras = sessions_find(ras->next, TYPE_UDP | TYPE_H225_RAS, 0, &ras->addr);
993 if (NULL == ras) {
994 ras = rasbkp;
995 break;
996 }
997 ras->u.ras_params.seqnum = pRasMsg->u.disengageRequest->requestSeqNum;
998 break;
999 case T_H225RasMessage_disengageConfirm:
1000 while ((NULL != ras) && (ras->u.ras_params.seqnum != pRasMsg->u.disengageConfirm->requestSeqNum))
1001 ras = sessions_find(ras->next, TYPE_UDP | TYPE_H225_RAS, 0, &ras->addr);
1002 if (NULL == ras) {
1003 ras = rasbkp;
1004 break;
1005 }
1006 ras->timeout = nids_last_pcap_header->ts.tv_sec; /* delete after dumping frame */
1007 }
1008 memFreePtr(&ctxt, pRasMsg);
1009 freeContext(&ctxt);
1010 return ras;
1011 }
1012
1013 static struct session *h225_cs_callback(struct session *cs, u_char *data, uint32_t len _U_)
1014 {
1015 /* ooCreateCall() for some reason declares its read-only first argument as
1016 * "char *" instead of "const char *", wrap the string in an array in order
1017 * not to upset the compiler.
1018 */
1019 char callType[] = "incoming";
1020 char callToken[20];
1021 OOH323CallData *call;
1022 Q931Message q931;
1023 DListNode *node;
1024 H245OpenLogicalChannel *olc;
1025 H245H2250LogicalChannelParameters *lcp;
1026 struct tuple4 addr;
1027
1028 ooGenerateCallToken(callToken, 20);
1029 call = ooCreateCall(callType, callToken);
1030 call->pH225Channel = (OOH323Channel*) memAllocZ (call->pctxt, sizeof (OOH323Channel));
1031 if (OO_OK == ooQ931Decode(call, &q931, ntohs(*((u_short *)(data + 2))) - 4, data + 4)) {
1032 if (OO_OK == ooHandleH2250Message(call, &q931)) {
1033 if (!bonus_time && (q931.messageType == Q931CallProceedingMsg)) {
1034 for (node = call->remoteFastStartOLCs.head; NULL != node; node = node->next) {
1035 olc = node->data;
1036 if (4 == olc->forwardLogicalChannelParameters.multiplexParameters.t) {
1037 lcp = olc->forwardLogicalChannelParameters.multiplexParameters.u.h2250LogicalChannelParameters;
1038 if (lcp->m.mediaChannelPresent &&
1039 (1 == lcp->mediaChannel.t) &&
1040 (1 == lcp->mediaChannel.u.unicastAddress->t)) {
1041 addr.source = 0;
1042 addr.saddr = 0;
1043 addr.dest = lcp->mediaChannel.u.unicastAddress->u.iPAddress->tsapIdentifier;
1044 addr.daddr = *((u_int *)lcp->mediaChannel.u.unicastAddress->u.iPAddress->network.data);
1045 sessions_add(TYPE_UDP | TYPE_RTP, &addr, cs);
1046 if (lcp->m.mediaControlChannelPresent &&
1047 (2 == lcp->mediaControlChannel.t) &&
1048 (1 == lcp->mediaControlChannel.u.multicastAddress->t)) {
1049 addr.source = 0;
1050 addr.saddr = 0;
1051 addr.dest = lcp->mediaControlChannel.u.unicastAddress->u.iPAddress->tsapIdentifier;
1052 addr.daddr = *((u_int *)lcp->mediaControlChannel.u.unicastAddress->u.iPAddress->network.data);
1053 sessions_add(TYPE_UDP | TYPE_RTCP, &addr, cs);
1054 }
1055 /* break; */
1056 }
1057 }
1058 }
1059 }
1060 }
1061 }
1062 ooCleanCall(call);
1063 return cs;
1064 }
1065 # endif /* HAVE_LIBOOH323C */
1066
1067 #endif /* HAVE_LIBNIDS */