2 * Copyright (c) 2006 Sebastien Raveau <sebastien.raveau@epita.fr>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 * This file contains code for tracking TCP and VoIP (SIP & H.323) sessions.
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/
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
54 #include "diag-control.h"
57 * The global variables below have the following purposes:
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).
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.
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
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.
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.
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().
102 int track_sessions
= 0;
103 uint32_t sessions_count
= 0;
104 char *sessions_file_format
= NULL
;
105 time_t sessions_expiration_delay
= 0;
110 sessions_init(const char *types _U_
)
112 error("libnids required for session tracking support, sorry.");
115 void sessions_exit(void)
119 void sessions_nids_init(pcap_t
*p _U_
)
123 #else /* HAVE_LIBNIDS */
127 # ifdef HAVE_LIBOSIPPARSER2
128 # include <osip2/osip.h>
129 # include <osipparser2/sdp_message.h>
130 # endif /* HAVE_LIBOSIPPARSER2 */
131 # ifdef HAVE_LIBOOH323C
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>
148 * Session type identifiers, used as bitmasks for
149 * convenience in searches among tracked sessions.
159 TYPE_H225_RAS
= 0x20,
161 CLASS_SIP
= TYPE_SIP
| TYPE_RTP
,
162 CLASS_H323
= TYPE_H225_RAS
| TYPE_H225_CS
| TYPE_RTP
| TYPE_RTCP
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
174 pcap_dumper_t
*filedesc
;
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
204 struct session
*(*callback
)(struct session
*elt
, u_char
*data
, uint32_t len
);
205 struct shared_dumper
*dumper
;
206 struct timeval lastseen
;
208 struct session
*next
;
209 struct session
*prev
;
210 # if defined(HAVE_LIBOSIPPARSER2) || defined(HAVE_LIBOOH323C)
213 # ifdef HAVE_LIBOSIPPARSER2
216 struct tuple4 rtp_addr
;
217 osip_call_id_t
*call_id
;
220 # endif /* HAVE_LIBOSIPPARSER2 */
221 # ifdef HAVE_LIBOOH323C
224 struct tuple4 cs_addr
;
225 H225RequestSeqNum seqnum
;
228 # endif /* HAVE_LIBOOH323C */
230 # endif /* defined(HAVE_LIBOSIPPARSER2) || defined(HAVE_LIBOOH323C) */
234 * Pointer to the head of the list containing all tracked sessions
236 static struct session
*first_session
= NULL
;
239 * Bitmask of the session types the user asked to track
241 static enum type sessions_track_types
= TYPE_NONE
;
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.
248 static unsigned int dumper_fd_count
= 0;
251 * The static functions declared below have the following purposes:
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.
258 * `sessions_del' properly removes a session object from the list.
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.
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.
272 * `dump_frame' actually saves the current packet to a PCAP file.
274 * `parse_type' simply converts a type from string to numerical form.
276 * `type2string' simply converts a type from numerical form to string.
278 * `ip_callback', `tcp_callback' and `udp_callback' are called from inside
279 * libnids upon reception of respectively IPv4, TCP and UDP packets.
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.
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
);
303 static enum type
parse_type(const char *str
)
305 if (!strcmp("tcp", str
))
307 # ifdef HAVE_LIBOSIPPARSER2
308 if (!strcmp("sip", str
))
310 # endif /* HAVE_LIBOSIPPARSER2 */
311 # ifdef HAVE_LIBOOH323C
312 if (!strcmp("h323", str
))
314 # endif /* HAVE_LIBOOH323C */
315 error("unsupported session type `%s'", str
);
321 sessions_init(const char *types
)
326 sessions_track_types
= TYPE_NONE
;
327 while (NULL
!= (comma
= strchr(types
, ','))) {
329 sessions_track_types
|= parse_type(types
);
332 sessions_track_types
|= parse_type(types
);
333 while (sessions_count
) {
334 struct session
*elt
= first_session
;
335 first_session
= first_session
->next
;
337 dumper_close(elt
->dumper
);
340 # ifdef HAVE_LIBOOH323C
341 ooH323EpInitialize(OO_CALLMODE_AUDIOCALL
, "/dev/null");
342 ooH323EpDisableAutoAnswer();
343 # endif /* HAVE_LIBOOH323C */
347 void sessions_exit(void)
350 struct session
*elt_next
;
351 time_t one_minute_later
= 0;
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.
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.
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
)) {
376 # ifdef HAVE_LIBOSIPPARSER2
377 if ((elt
->type
& TYPE_SIP
) && !elt
->u
.sip_params
.picked_up
)
379 # endif /* HAVE_LIBOSIPPARSER2 */
383 * Print a report about unclosed sessions.
385 if (sessions_count
) {
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
;
407 first_session
= NULL
;
416 void sessions_nids_init(pcap_t
*p
)
418 nids_params
.pcap_desc
= p
;
419 nids_params
.tcp_workarounds
= 1;
421 error("%s(): %s", __func__
, nids_errbuf
);
424 * These conversions between function pointer and void pointer upset GCC,
426 * See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584
429 nids_register_ip(ip_callback
);
430 nids_register_udp(udp_callback
);
431 nids_register_tcp(tcp_callback
);
435 static struct session
*
436 sessions_add(const uint8_t t
, const struct tuple4
*addr
, const struct session
*parent
)
439 static uint32_t counter
= 0;
441 if (!(t
& sessions_track_types
))
443 elt
= (struct session
*) calloc(1, sizeof(struct session
));
447 if (sessions_expiration_delay
)
448 elt
->timeout
= nids_last_pcap_header
->ts
.tv_sec
+ sessions_expiration_delay
;
450 elt
->callback
= sip_callback
;
452 if (t
& TYPE_H225_RAS
)
453 elt
->callback
= h225_ras_callback
;
455 if (t
& TYPE_H225_CS
)
456 elt
->callback
= h225_cs_callback
;
458 elt
->callback
= NULL
;
459 if (NULL
!= parent
) {
460 elt
->parent_id
= parent
->id
;
461 elt
->dumper
= parent
->dumper
;
462 elt
->dumper
->references
++;
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
;
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
,
475 timestamp_to_string(&nids_last_pcap_header
->ts
),
480 static void sessions_del(struct session
*elt
)
482 struct tcp_stream
*tcp
;
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
),
493 if (NULL
!= elt
->next
)
494 elt
->next
->prev
= elt
->prev
;
495 if (NULL
!= elt
->prev
)
496 elt
->prev
->next
= elt
->next
;
498 first_session
= elt
->next
;
501 * If this is a TCP connection, tell libnids we do not
502 * want to be notified of new data in this connection.
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.
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
);
514 # ifdef HAVE_LIBOSIPPARSER2
516 * If this is a SIP session, finally free the memory
517 * allocated for the call ID (couldn't be done before)
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 */
524 dumper_close(elt
->dumper
);
528 static struct session
*
529 sessions_find(struct session
*start
, const uint8_t t
, const uint32_t parent_id
, const struct tuple4
*addr
)
533 for (elt
= start
; NULL
!= elt
; elt
= elt
->next
) {
534 if (!(elt
->type
& t
))
536 if (parent_id
&& (elt
->parent_id
!= parent_id
))
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
))
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
))
556 static struct shared_dumper
*
557 dumper_open(const enum type t
, const uint32_t id
)
559 struct shared_dumper
*d
;
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
);
572 static void dumper_too_many_open_files(struct shared_dumper
**d
)
575 unsigned int oldest_ten_percent
;
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
;
584 if (!--oldest_ten_percent
)
588 (*d
)->filedesc
= pcap_dump_open(nids_params
.pcap_desc
, (*d
)->filename
);
590 if (NULL
== (*d
)->filedesc
) {
591 error("%s(): %s: %s", __func__
,
593 pcap_geterr(nids_params
.pcap_desc
));
597 static void dumper_close(struct shared_dumper
*d
)
602 if (!d
->references
) {
604 if (NULL
!= d
->filedesc
) {
605 pcap_dump_close(d
->filedesc
);
612 type2string(const enum type t
, const int upper
)
615 return upper
? "SIP" : "sip";
616 if ((t
& TYPE_H225_RAS
) || (t
& TYPE_H225_CS
))
617 return upper
? "H323" : "h323";
619 return upper
? "RTP" : "rtp";
621 return upper
? "TCP" : "tcp";
626 dump_frame(const u_char
*data
, const int len
, struct shared_dumper
*output
)
629 struct pcap_pkthdr ph
;
631 if (!bonus_time
&& NULL
== output
)
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
);
645 pcap_dump((u_char
*)output
->filedesc
, &ph
, frame
);
648 pcap_dump((u_char
*)global_dumper
, &ph
, frame
);
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.
663 static void ip_callback(struct ip
*ip
, int len
)
668 struct session
*elt_next
;
669 unsigned int ip_data_offset
= IPHDRLEN
;
672 error("%s(): len < 0", __func__
);
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
))
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
;
695 if (!(tcp
->th_flags
& TH_SYN
) || bonus_time
)
697 if (addr
.source
== 5060 || addr
.dest
== 5060)
698 elt
= sessions_add(TYPE_TCP
| TYPE_SIP
, &addr
, NULL
);
700 elt
= sessions_add(TYPE_TCP
, &addr
, NULL
);
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 */
708 static void udp_callback(struct tuple4
*addr
, u_char
*udp_data
, int udp_data_len
, struct ip
*ip
)
711 unsigned int udp_data_offset
= IPHDRLEN
+ UDPHDRLEN
;
713 if (NULL
== (elt
= sessions_find(first_session
, TYPE_UDP
, 0, addr
))) {
716 if (addr
->source
== 1719 || addr
->dest
== 1719)
717 elt
= sessions_add(TYPE_UDP
| TYPE_H225_RAS
, addr
, NULL
);
719 if (addr
->source
== 5060 || addr
->dest
== 5060)
720 elt
= sessions_add(TYPE_UDP
| TYPE_SIP
, addr
, NULL
);
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
);
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.
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
);
739 static void tcp_callback(struct tcp_stream
*tcp
, void **user
)
743 struct session
*start
;
745 switch (tcp
->nids_state
) {
749 elt
= sessions_find(first_session
, TYPE_TCP
, 0, &tcp
->addr
);
752 if (elt
->type
& TYPE_H225_CS
) {
753 elt
->addr
.saddr
= tcp
->addr
.saddr
;
754 elt
->addr
.source
= tcp
->addr
.source
;
757 if (!sessions_expiration_delay
)
759 tcp
->client
.collect
++;
760 tcp
->server
.collect
++;
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
);
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
)
779 sessions_del((struct session
*)*user
);
783 # ifndef HAVE_LIBOSIPPARSER2
784 static struct session
*sip_callback(struct session
*sip
, u_char
*data _U_
, uint32_t len _U_
)
788 # else /* HAVE_LIBOSIPPARSER2 */
790 sip_get_address(const osip_message_t
*msg
, u_int
*host
, u_short
*port
)
792 osip_content_type_t
*ctt
;
797 if (NULL
== (ctt
= osip_message_get_content_type(msg
)))
799 if ((NULL
== ctt
->type
) || (NULL
== ctt
->subtype
))
801 if (osip_strcasecmp(ctt
->type
, "application"))
803 if (osip_strcasecmp(ctt
->subtype
, "sdp"))
805 for (i
= 0; !osip_list_eol(&msg
->bodies
, i
); ++i
) {
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
);
813 for (j
= 0; NULL
!= sdp_message_m_media_get(sdp
, j
); ++j
) {
814 if (NULL
== (tmp
= sdp_message_m_port_get(sdp
, j
)))
817 if (NULL
== (tmp
= sdp_message_c_addr_get(sdp
, -1, 0)))
818 if (NULL
== (tmp
= sdp_message_c_addr_get(sdp
, j
, 0)))
820 *host
= (u_int
)inet_addr(tmp
);
821 sdp_message_free(sdp
);
824 sdp_message_free(sdp
);
829 static struct session
*sip_callback(struct session
*sip
, u_char
*data
, uint32_t len
)
832 struct session
*start
;
834 osip_call_id_t
*call_id
;
836 osip_message_init(&msg
);
837 if (!osip_message_parse(msg
, (char *)data
, len
)) {
838 if (NULL
== sip
->u
.sip_params
.call_id
) {
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
844 if (NULL
!= (call_id
= osip_message_get_call_id(msg
)))
845 osip_call_id_clone(call_id
, &sip
->u
.sip_params
.call_id
);
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.
862 if (NULL
== (call_id
= osip_message_get_call_id(msg
)))
864 if (!osip_call_id_match(sip
->u
.sip_params
.call_id
, call_id
))
866 } while ((sip
= sessions_find(sip
->next
, TYPE_SIP
, 0, &sip
->addr
)));
869 osip_message_free(msg
);
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
);
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.
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
891 if (MSG_IS_INVITE(msg
)) {
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;
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;
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
))) {
914 * Mark for deletion in 2 seconds, in order to give some
915 * time to the extra ACK packets that might be exchanged
917 if (sip
->type
& TYPE_UDP
)
918 sip
->timeout
= nids_last_pcap_header
->ts
.tv_sec
+ 2;
922 osip_message_free(msg
);
925 # endif /* HAVE_LIBOSIPPARSER2 */
927 # ifndef HAVE_LIBOOH323C
928 static struct session
*h225_ras_callback(struct session
*ras
, u_char
*data _U_
, uint32_t len _U_
)
933 static struct session
*h225_cs_callback(struct session
*cs
, u_char
*data _U_
, uint32_t len _U_
)
937 # else /* HAVE_LIBOOH323C */
938 static struct session
*h225_ras_callback(struct session
*ras
, u_char
*data
, uint32_t len
)
941 H225RasMessage
*pRasMsg
;
943 struct session
*rasbkp
;
946 if (ASN_OK
!= setPERBuffer(&ctxt
, data
, len
, TRUE
))
949 pRasMsg
= (H225RasMessage
*)memAlloc(&ctxt
, sizeof (H225RasMessage
));
950 if (ASN_OK
== asn1PD_H225RasMessage(&ctxt
, pRasMsg
))
951 switch (pRasMsg
->t
) {
952 case T_H225RasMessage_admissionRequest
:
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 */
962 case T_H225RasMessage_admissionConfirm
:
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
);
971 if (pRasMsg
->u
.admissionConfirm
->destCallSignalAddress
.t
!= T_H225TransportAddress_ipAddress
) {
972 ras
->timeout
= nids_last_pcap_header
->ts
.tv_sec
; /* delete after dumping frame */
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 */
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
);
988 ras
->timeout
= nids_last_pcap_header
->ts
.tv_sec
; /* delete after dumping frame */
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
);
997 ras
->u
.ras_params
.seqnum
= pRasMsg
->u
.disengageRequest
->requestSeqNum
;
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
);
1006 ras
->timeout
= nids_last_pcap_header
->ts
.tv_sec
; /* delete after dumping frame */
1008 memFreePtr(&ctxt
, pRasMsg
);
1013 static struct session
*h225_cs_callback(struct session
*cs
, u_char
*data
, uint32_t len _U_
)
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.
1019 char callType
[] = "incoming";
1021 OOH323CallData
*call
;
1024 H245OpenLogicalChannel
*olc
;
1025 H245H2250LogicalChannelParameters
*lcp
;
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
) {
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
)) {
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
)) {
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
);
1065 # endif /* HAVE_LIBOOH323C */
1067 #endif /* HAVE_LIBNIDS */