sngrep-1.2.0/0000755000175000017500000000000012632250522012041 5ustar vsevavsevasngrep-1.2.0/AUTHORS0000644000175000017500000000006312632250522013110 0ustar vsevavsevaIvan Alonso (aka Kaian) First version of all files sngrep-1.2.0/bootstrap.sh0000755000175000017500000000165612632250522014425 0ustar vsevavseva#!/bin/sh check_for_app() { $1 --version 2>&1 >/dev/null if [ $? != 0 ] then echo "Please install $1 and run bootstrap.sh again!" exit 1 fi } # On FreeBSD and OpenBSD, multiple autoconf/automake versions have different names. # On Linux, environment variables tell which one to use. case `uname -sr` in OpenBSD*) export AUTOCONF_VERSION=2.63 export AUTOMAKE_VERSION=1.9 ;; FreeBSD*) AUTOCONF_VERSION=2.69 AUTOMAKE_VERSION=1.15 export AUTOCONF_VERSION export AUTOMAKE_VERSION ;; *) ;; esac check_for_app autoconf check_for_app autoheader check_for_app automake check_for_app aclocal echo "Generating the configure script ..." aclocal autoconf autoheader automake --add-missing --copy 2>/dev/null exit 0 sngrep-1.2.0/README.md0000644000175000017500000001043612632250522013324 0ustar vsevavseva# sngrep [![Build Status](https://travis-ci.org/irontec/sngrep.svg)](https://travis-ci.org/irontec/sngrep) sngrep is a tool for displaying SIP calls message flows from terminal. It supports live capture to display realtime SIP packets and can also be used as PCAP viewer. [Some screenshots of sngrep](https://github.com/irontec/sngrep/wiki/Screenshots) ## Installing ### Binaries * [Debian / Ubuntu] (https://github.com/irontec/sngrep/wiki/Installing-Binaries#debian--ubuntu) * [CentOS / RedHat / Fedora](https://github.com/irontec/sngrep/wiki/Installing-Binaries#centos--fedora--rhel) * [Alpine Linux](https://github.com/irontec/sngrep/wiki/Installing-Binaries#alpine-linux) * [Gentoo](https://github.com/irontec/sngrep/wiki/Installing-Binaries#gentoo) * [Arch](https://github.com/irontec/sngrep/wiki/Installing-Binaries#arch) * [OSX] (https://github.com/irontec/sngrep/wiki/Installing-Binaries#osx) ### Building from sources Prerequisites - libncurse5 - for UI, windows, panels. - libpcap - for capturing packets. - libssl - (optional) for TLS transport decrypt using OpenSSL and libcrypt - gnutls - (optional) for TLS transport decrypt using GnuTLS and libgcrypt - libncursesw5 - (optional) for UI, windows, panels (wide-character support) - libpcre - (optional) for Perl Compatible regular expressions On most systems the commands to build will be the standard autotools procedure: ./bootstrap.sh ./configure make make install (as root) You can pass following flags to ./configure to enable some features | configure flag | Feature | | ------------- | ------------- | | `--with-openssl` | Adds OpenSSL support to parse TLS captured messages (req. libssl) | | `--with-gnutls` | Adds GnuTLS support to parse TLS captured messages (req. gnutls) | | `--with-pcre`| Adds Perl Compatible regular expressions support in regexp fields | | `--enable-unicode` | Adds Ncurses UTF-8/Unicode support (req. libncursesw5) | | `--enable-ipv6` | Enable IPv6 packet capture support. | | `--enable-eep` | Enable EEP packet send/receive support. | You can find [detailed instructions for some distributions] (https://github.com/irontec/sngrep/wiki/Building) on wiki. ## Usage See `--help` for a list of available flags and their syntax For example, sngrep can be used to view SIP packets from a pcap file, also applying filters sngrep -I file.pcap host 192.168.1.1 and port 5060 or live capturing, saving packets to a new file sngrep -d eth0 -O save.pcap port 5060 and udp ## Configuration You can configure some options using [sngreprc] (https://github.com/irontec/sngrep/wiki/Configuration) file ## Frequent Asked Questions Any feedback, request or question are welcomed at [#sngrep](https://webchat.freenode.net/?channels=sngrep) channel at irc.freenode.net See FAQ on [Github Wiki](https://github.com/irontec/sngrep/wiki#frequent-asked-questions) ## License sngrep - SIP Messages flow viewer Copyright (C) 2013,2014 Irontec S.L. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . sngrep-1.2.0/.gitignore0000644000175000017500000000056112632250522014033 0ustar vsevavseva# Ignore eclipse files .*project .settings # Build files src/sngrep tests/test-*.log tests/test-*.trs tests/test-??? */*.o */.deps *gmon.out src/config.h* src/stamp-h1 .autotools Makefile Makefile.in aclocal.m4 autom4te.cache config.log config.status config.sub config.guess configure missing install-sh depcomp test-driver # Ignore Doxygen generated files doc/html sngrep-1.2.0/config/0000755000175000017500000000000012632250522013306 5ustar vsevavsevasngrep-1.2.0/config/Makefile.am0000644000175000017500000000005612632250522015343 0ustar vsevavsevasysconfdir=@sysconfdir@ sysconf_DATA=sngreprc sngrep-1.2.0/config/sngreprc0000644000175000017500000000561212632250522015060 0ustar vsevavseva##----------------------------------------------------------------------------- ## sngreprc - sngrep configuration file ##----------------------------------------------------------------------------- ## This file stores sngrep configuration and it's totally optional ## ##----------------------------------------------------------------------------- ## Enable color on or off # set color off ## Use default foreground and background colors of your terminal # set background default ## Disable syntax highlighting # set syntax off ## Or enable branch/tag highlighting # set syntax.tag on # set syntax.branch on ##----------------------------------------------------------------------------- ## Uncomment to configure packet count capture limit (can't be disabled) # set capture.limit 50000 ## Default capture keyfile for TLS transport # set capture.keyfile /etc/ssl/key.pem ## Uncommnet to lookup hostnames from packets ips # set capture.lookup on ## Set default capture device # set capture.device any ## Set default dump file # set capture.outfile /tmp/last_capture.pcap ##----------------------------------------------------------------------------- ## Default path in save dialog # set sngrep.savepath /tmp/sngrep-captures ##----------------------------------------------------------------------------- ## Change default scrolling in call list and call flow # set cl.scrollstep 20 # set cf.scrollstep 4 ## Disable exit prompt # set cl.noexitprompt off ## Or set its default button # set cl.defexitbutton 0/1 # Set default filter on startup # set cl.filter INVITE ##----------------------------------------------------------------------------- ## You can change the default number of columns in call list ## ## Set displayed columns in call list screen ## set cl.column{num} {field} ## ## You can optionally configure the column width using ## set cl.column{num}.width {num} ## ## Available columns fields are: ## - sipfrom ## - sipfromuser ## - sipto ## - siptouser ## - src ## - srchost ## - dst ## - dsthost ## - callid ## - xcallid ## - date ## - time ## - msgcnt ## - transport ## - state ## - convdur ## - totaldur ## ## Examples: # set cl.column0 sipfrom # set cl.column0.width 30 # set cl.column1 sipto # set cl.column2 msgcnt # set cl.column3 src # set cl.column4 dst # set cl.column4.width 22 # set cl.column5 starting # set cl.column5.width 15 # set cl.column6 state ##----------------------------------------------------------------------------- ## Default minimun size from Message payload in Call Flow panel # set cf.rawminwidth 40 ## Fixed raw preview size # set cf.rawfixedwidth 40 ## Set selected highlight mode in call flow (bold, reverse or reversebold) # set cf.highlight reverse ##----------------------------------------------------------------------------- ## Uncomment to display dialogs that does not start with a request method # set sip.noincomplete off sngrep-1.2.0/.travis.yml0000644000175000017500000000045712632250522014160 0ustar vsevavsevalanguage: c compiler: - clang - gcc notifications: recipients: - kaian@irontec.com before_script: - sudo apt-get update install: - sudo apt-get install -y libncurses5-dev libpcap-dev libssl-dev script: - ./bootstrap.sh - ./configure - make branches: only: - master sngrep-1.2.0/doc/0000755000175000017500000000000012632250522012606 5ustar vsevavsevasngrep-1.2.0/doc/footer.html0000644000175000017500000000034312632250522014772 0ustar vsevavseva
Generated on $datetime for $projectname  irontec
sngrep-1.2.0/doc/sngrep.80000644000175000017500000001040012632250522014170 0ustar vsevavseva.\" Man page for the sngrep .\" .\" Copyright (c) 2013-2015 Ivan Alonso .\" Copyright (c) 2013-2015 Irontec S.L. .TH SNGREP 8 "June 2015" "sngrep 1.2.0" .SH NAME sngrep \- SIP Messages flow viewer .SH SYNOPSIS .B sngrep [-hVcivlkNq] [ -IO .I pcap_dump .B ] [ -d .I dev .B ] [ -l .I limit .B ] [ -k .I keyfile .B ] [ .I .B ] [ .I .B ] .SH DESCRIPTION sngrep is a terminal tool that groups SIP (Session Initiation Protocol) Messages by Call-Id, and displays them in arrow flows similar to the used in SIP RFCs. The aim of this tool is to make easier the process of learnig or debugging SIP. It recognizes UDP, TCP and partially TLS SIP packets and understands bpf filter logic in the same way .B ngrep (8) and .B tcpdump (1) does. .SH OPTIONS .TP .I \-h Display help and usage information. .TP .I \-V Display version information. .TP .I \-c Only capture dialogs starting with an INVITE request. .TP .I \-i Make match expression case insensitive. .TP .I \-v Invert match expression. .TP .I \-I pcap_dump Read packets from pcap file instead of network devices. This option can be used with bpf filters. .TP .I \-O pcap_dump Save all captured packets to a pcap file. This option can be used with bpf filters. .TP .I \-d dev Use this capture device instead of default (\fIany\fP). .TP .I -k keyfile Use private keyfile to decrypt TLS packets. .TP .I -l limit Change default capture limit (10000 dialogs) .TP .I -N Don't display sngrep interface, just capture .TP .I -q Don't print captured dialogs in no interface mode .TP .I match expression Match given expression in Messages' payload. If one request message matches the given expression, the following messages within the same dialog will be also captured. .TP .I bpf filter Selects a filter that specifies what packets will be parsed. If no \fIbpf filter\fP is given, all SIP packets seen on the selected interface or pcap file will be displayed. Otherwise, only packets for which \fIbpf filter\fP is `true' will be displayed. .SH Interface There are multiple windows to provide different information. Most of the program windows have a help dialog with a brief description and useful keybindings. .SH " Call List Window" .PP The first window that sngrep shows is Call List window and display the different SIP Call-Ids found in messages. The displayed columns depends on your terminal width and your custom configuration. You can move between dialogs with arrow keys and selected them using Spacebar. Selecting multiple dialogs will display all them in Call flow window and Call Raw window, and will allow to save only the selected message dialogs to a PCAP file. .SH " Call Flow Window" .PP This window will a flow diagram of the selected dialogs' messages. The selected message payload will be displayed in the right side of the window. You can move between messages using arrow keys and select them using Spacebar. Selecting multiple messages will display the Message Diff Window. .SH " Call Raw Window" .PP This window will display the selected dialog messages in plain text. It was designed to allow copying the messages payload easily. You can also save the displayed information to a text file from this screen. .SH " Column selection Window" .PP Columns displayed in Call List can be updated in this window. You can add or remove columns or change their order in the list. Additionally, you can save column state to be use in next sngrep execution. .SH " Message Diff Window" .PP This window will compare two messages. Right now the comparison is done searching each line in the other message, highlighting those not found exactly. You can reach this window by selecting two messages using Spacebar in Call Flow window .SH FILES Full paths below may vary between installations. .PP .I /etc/sngreprc .IP System\-wide configuration file. Some sngrep options can be overridden using this file. .PP .I ~/.sngreprc .IP User's configuration file. If this file is present, options will be override system\-wide configurations. .SH BUGS Please report bugs to the sngrep github project at http://github.com/irontec/sngrep Non-bug, non-feature-request general feedback should be sent to the author directly by email. .SH AUTHOR Written by Ivan Alonso [a.k.a. Kaian] . sngrep-1.2.0/doc/Makefile.am0000644000175000017500000000002412632250522014636 0ustar vsevavsevaman_MANS = sngrep.8 sngrep-1.2.0/doc/ironlogo.png0000644000175000017500000000161012632250522015142 0ustar vsevavseva‰PNG  IHDRóÿasRGB®ÎébKGDÿÿÿ ½§“ pHYsUŒUŒ»? tIMEÜ &[²DÇIDAT8Ë…’[hSY†ÿ½ÏÅœ¤Í¥Fbê¤EmUŒ­%Öbµu{I§V±Et|òV,Šú$Þ@/ø003Ò_œ¥PÔ6Ж!t`|ÐPðACë¥V›c&æ4;9ÙÛ'Å‚uþ§µà_‹- sè#‡÷­3Äú²¥«&Ƈæòѯ›ÎÎÎ/µ5›ÿq~–ï·¥ÙV|G³‰DÂÓŸ†Ûí-²Xx±­937ú$Z[·©î×®®®åÐØØ8PZZêŒÇãÿ&týL¹ÏWd0†ÔL 6G!]S±vä½®ï‰Åbcápø`__ßl@0¸Ùér¹žÏÌÌ[­63Í¥˜™G&Ÿã9!„°ÙTëÃ0Èää䵆††jèï:>þJþ{sár¹æ£¬lɯcOÇ)LXY9F!$]W»a™Ýî|§(* ý¡ba(´4 zS©ÔbI’¡ªjÅõë7Þ€I•(…BU /]xçõzË¡H§Âææ–­@UUõpΊ¢Lù|¾÷W®\¤4møù<¥;ã]ðHA[[ÛpëÖÍÿE¹K)…®ë;~E ²²JøýÑÏÁô^>7çÙ::vý^U«VUþ´¾¾ÞÏ9‡¦iÅ'OžrÀOÇçLMM™œsÈ@c±Øc‹ÅƘ-ºñ?2Ms‹§hSSS\’¤7œó"]×ùÖÐÞ½?ÚÚ¶ßÉd2 5MCoï_'€;vô£ÓélWUŒ±õÕÕ5Cíí+2™¬üÕ‡·¶¶]žžÞÁç|'!„Ù¸q"‘ÔÔ¬k6 ãç”Ò¤,˯ciI’$‡Ã±”sîÈf³p»Ý÷ƒÁ`Kww·BŠÇ_^¾œx¶r¥?Â9Bܹ\n,Ë‹(¥^MÓ,„‰’’’³==w©ê< >ÏkÖÖnÀÈÈΟ¿X‰D–°———oûÓn·ç“É䳇ÉÝ»÷àöíß¾äó aI:„Øk9öIEND®B`‚sngrep-1.2.0/LICENSE.OpenSSL0000644000175000017500000000511212632250522014327 0ustar vsevavseva/* ==================================================================== * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ sngrep-1.2.0/ChangeLog0000644000175000017500000001434212632250522013617 0ustar vsevavseva2015-10-06 Ivan Alonso * sngrep 1.0.0 released * Implemented basic TCP reassembly * Implemented basic IP reassembly * Implememted EEP/HEP client/server support * Implemented command line option --dump-config * Disabled RTP packet payload storage by default * Removed --enable-openssl configure flag (use --with-openssl instead) * Removed configurable ignore directives in rc file * Removed configurable option cl.filter * Improved payload memory storage * Added a confirmation dialog to overwrite saved files * Added save button to Columns select UI * Added a keybinding to remove selected dialogs in Call List * Added a keybinding to move to the first and last item in Call List * Added attribute color support (can be disabled with cl.colorattr) * Added a compressed view in Call Flow (one message per row) * Fixed IPv6 support * Fixed multiple memory leaks 2015-09-01 Ivan Alonso * sngrep 0.4.2 released * Fixed a crash with RTP format detection * Fixed capture.rtp setting * Fixed a crash while parsing captured packets headers * Fixed a crash while creating new columns in call flow window * Restored TLS and WS transport payload display * Added Timestamp to the first RTP packet displayed in call flow window * Improved packet payload storage 2015-07-08 Ivan Alonso * sngrep 0.4.1 released * Added an option to capture RTP packets * Allow RTP packets to be saved with their calls * Improved Save panel default options * Added testing files * Improved SIP message parsed process * Improved SIP message payload memory usage * Fixed a bug with timestamp diff overflows * Fixed multiple memory leaks * Fixed compatibility with BSD systems 2015-06-24 Ivan Alonso * sngrep 0.4.0 released * Added Websocket (WS) transport support * Added an option (alias) to replace addresses on screen * Added a new screen to change/save settings * Added support for multiple SDP medias in flow screen * Added delta time between SIP messages in flow screen * Added RTP stream arrows in flow screen * RTP packets will be now saved with -O command line option * Merged pcap and txt save screens * Recoded screen update process * Replace all internal linked list with vector structures * Added index as first column in call list * Fixed a bug with address resloution 2015-05-17 Ivan Alonso * sngrep 0.3.2 released * Fixed sources compilation for BSD systems * Fixed a bug where Contact header was displayed in SIP From column * Fixed some keybindings in filter and save panels * Improved SIP packet detection from payload * Highlight local address columns in Call Flow 2015-04-14 Ivan Alonso * sngrep 0.3.1 released * Added command line option -N to not display ncurses interface * Added command line option -q to dont print any stdout output * Added optional IPv6 support * Added SIP compact headers support * Fixed autotools templates for OpenBSD 5 * Set dark background by default * Repladed SIP payload function with regexp * Implemented configurable keybindings via sngreprc * Added more default keybindings * Implement basic RTP detection * Improved parsing payload performance 2015-03-02 Ivan Alonso * sngrep 0.3.0 released * Added command line option -c to only display calls * Added command line option -l to change capture limit * Added command line match expression for packet payload * Converted all filters to regular expressions (POSIX or PCRE) * Added optional PCRE support (Perl Compatible Regular Expressions) * Added optional UTF-8 / Unicode compatible terminals support * Added current displayed and total dialogs counters in Call list * Added an option to save displayed dialogs (after filtering) * Added an option to save current columns layout * Added new attributes: - sipfromuser: User in From: Header - siptouser: User in To: header - convdur: Total conversation duration (from 200 to BYE) - totaldur: Total call duration (from first to last message) * Interface will now be displayed while pcaps are loading * Reworked Interface refresh process * Reworked Filtering process * Fixed general performance issues * Disable OpenSSL support by default * Removed command line option to read pcap without flags * Added long versions of command line flags 2015-02-09 Ivan Alonso * sngrep 0.2.2 released * Added a new panel to configure Call List columns during runtime (static configuration can still be done using sngreprc file) * Added a configuration option to change selected message highlight in Call Flow (bold is not properly displayed in some terminals) * Fixed message retransmission detection (-->>>) * Fixed some drawing issues on small screens * Fixed a crash when capturing while saving pcap dialog was being displayed * Fixed a bug that considered ACK as a response instead of a request * Fixed Call state for REJECTED calls * Fixed Colors for monochrome terminals * Changed default column width for SIP To/From to 30 characters * Other minor fixes 2015-01-22 Ivan Alonso * sngrep 0.2.1 released * Added SIP message color syntax options * Improved Call Flow refreshing logic * Fixed multiple locking problems with UI * Respect terminals colors (can be overridden with background dark option) * Improve offline pcap file reading to respect capture limit option * Swapped some keybindings * Multiple minor fixes and code refactoring 2014-12-04 Ivan Alonso * sngrep 0.2.0 released * Added Initial TLS Support (No compression, AES) * Added an option to resolve IP addresses * Added a new panel to compare two SIP messages * Fixed multiples memory leaks 2014-10-21 Ivan Alonso * sngrep 0.1.0 released * Remove ngrep compatibility. Force libpcap during compilation * Added TCP support * Allow saving selected dialogs into pcap * New UI design to maximize screen usage * Added a serach box in Call List window * Added Funtion Keys keybindings * Added command line arguments * Fixed some memory bugs 2013-04-22 Ivan Alonso * sngrep 0.0-alpha released. * Initial version, code is just a mere stub with global variables, without sanity checks... expect the worst. sngrep-1.2.0/compile0000755000175000017500000001624512632250522013427 0ustar vsevavseva#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2014 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: sngrep-1.2.0/TODO0000644000175000017500000000235012632250522012531 0ustar vsevavsevaToDo List ========= capture: * Improve Packet fragmentation Right now capture process only handle packet IP fragmentation and TCP segmentation when all parts come ordered. Also, packets being reassembled are stored in memory until fully assembled (which may never occur). ui: * Change panels initialization Right now, all panels are initializated at the same, because each panel can only be invoked once (it is not possible to have two call details panel right now) * Add horizontal scrolling It should be nice to be able to scroll horizontaly (with unused right and left keys) in Call List and Call flow. * Interface resize When the terminal size changes, the ui is not properly redraw. It would be nice to handle KEY_RESIZE event and change all displayed panels. * Improve colors for white background terminals The best approach for colors should be use terminal defaults. Right now, white background terminals must set background dark option in order to see colors properly. * Improve compatibility with IPv6 IPv6 packets are captured but IPv6 addresses can be 45 chars long, so current UI is not ready to display that kind of addresses sngrep-1.2.0/src/0000755000175000017500000000000012632250522012630 5ustar vsevavsevasngrep-1.2.0/src/media.c0000644000175000017500000000644212632250522014061 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013-2015 Ivan Alonso (Kaian) ** Copyright (C) 2013-2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file media.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in media.h */ #include "config.h" #include #include #include "media.h" #include "rtp.h" #include "util.h" sdp_media_t * media_create(struct sip_msg *msg) { sdp_media_t *media;; // Allocate memory for this media structure if (!(media = sng_malloc(sizeof(sdp_media_t)))) return NULL; // Initialize all fields media->msg = msg; media->formats = vector_create(0, 1); vector_set_destroyer(media->formats, vector_generic_destroyer); return media; } void media_destroyer(void *item) { sdp_media_t *media = (sdp_media_t *) item; if (!item) return; vector_destroy(media->formats); sng_free(media); } void media_set_port(sdp_media_t *media, u_short port) { media->port = port; } void media_set_type(sdp_media_t *media, const char *type) { strcpy(media->type, type); } void media_set_address(sdp_media_t *media, const char *address) { strcpy(media->address, address); } void media_set_prefered_format(sdp_media_t *media, u_int code) { media->fmtcode = code; } void media_add_format(sdp_media_t *media, u_int code, const char *format) { sdp_media_fmt_t *fmt; if (!(fmt = sng_malloc(sizeof(sdp_media_fmt_t)))) return; fmt->id = code; strcpy(fmt->format, format); vector_append(media->formats, fmt); } const char * media_get_address(sdp_media_t *media) { return media->address; } u_short media_get_port(sdp_media_t *media) { return media->port; } const char * media_get_type(sdp_media_t *media) { return media->type; } const char * media_get_format(sdp_media_t *media, u_int code) { sdp_media_fmt_t *format; vector_iter_t iter; iter = vector_iterator(media->formats); while ((format = vector_iterator_next(&iter))) { if (format->id == code) return format->format; } return "Unassigned"; } const char * media_get_prefered_format(sdp_media_t *media) { const char *format; // Check if format is standard if ((format = rtp_get_standard_format(media->fmtcode))) { return format; } // Try to get format form SDP payload return media_get_format(media, media->fmtcode); } int media_get_format_code(sdp_media_t *media) { return media->fmtcode; } sngrep-1.2.0/src/option.c0000644000175000017500000001206212632250522014305 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file option.c * @author Ivan Alonso [aka Kaian] * * @brief Source code of functions defined in option.h * */ #include #include #include #include #include "keybinding.h" #include "option.h" #include "setting.h" #include "util.h" /** * @brief Configuration options array * * Contains all availabe options that can be optionured * @todo make this dynamic */ option_opt_t options[1024]; int optscnt = 0; int init_options() { // Custom user conf file char userconf[128]; char *home = getenv("HOME"); // Initialize settings setting_set_value(SETTING_SAVEPATH, home); setting_set_value(SETTING_FILTER_METHODS, "REGISTER,INVITE,SUBSCRIBE,NOTIFY,OPTIONS,PUBLISH,MESSAGE"); // Add Call list column options set_option_value("cl.column0", "index"); set_option_value("cl.column1", "method"); set_option_value("cl.column2", "sipfrom"); set_option_value("cl.column3", "sipto"); set_option_value("cl.column4", "msgcnt"); set_option_value("cl.column5", "src"); set_option_value("cl.column6", "dst"); set_option_value("cl.column7", "state"); // Read options from configuration files read_options("/etc/sngreprc"); read_options("/usr/local/etc/sngreprc"); // Get user homedir configuration if (home) { sprintf(userconf, "%s/.sngreprc", home); read_options(userconf); } return 0; } void deinit_options() { int i; // Deallocate options memory for (i = 0; i < optscnt; i++) { sng_free(options[i].opt); sng_free(options[i].value); } } int read_options(const char *fname) { FILE *fh; char line[1024], type[20], option[50], value[50]; int id; if (!(fh = fopen(fname, "rt"))) return -1; while (fgets(line, 1024, fh) != NULL) { // Check if this line is a commentary or empty line if (!strlen(line) || *line == '#') continue; // Get configuration option from setting line if (sscanf(line, "%s %s %s", type, option, value) == 3) { if (!strcasecmp(type, "set")) { if ((id = setting_id(option)) >= 0) { setting_set_value(id, value); } else { set_option_value(option, value); } } else if (!strcasecmp(type, "alias")) { set_alias_value(option, value); } else if (!strcasecmp(type, "bind")) { key_bind_action(key_action_id(option), key_from_str(value)); } else if (!strcasecmp(type, "unbind")) { key_unbind_action(key_action_id(option), key_from_str(value)); } } } fclose(fh); return 0; } const char* get_option_value(const char *opt) { int i; for (i = 0; i < optscnt; i++) { if (!strcasecmp(opt, options[i].opt)) { return options[i].value; } } return NULL; } int get_option_int_value(const char *opt) { const char *value; if ((value = get_option_value(opt))) { return atoi(value); } return -1; } void set_option_value(const char *opt, const char *value) { if (!opt || !value) return; int i; if (!get_option_value(opt)) { options[optscnt].type = COLUMN; options[optscnt].opt = strdup(opt); options[optscnt].value = strdup(value); optscnt++; } else { for (i = 0; i < optscnt; i++) { if (!strcasecmp(opt, options[i].opt)) { sng_free(options[i].value); options[i].value = strdup(value); } } } } void set_alias_value(const char *address, const char *alias) { options[optscnt].type = ALIAS; options[optscnt].opt = strdup(address); options[optscnt].value = strdup(alias); optscnt++; } const char * get_alias_value(const char *address) { int i; if (!address) return NULL; for (i = 0; i < optscnt; i++) { if (options[i].type != ALIAS) continue; if (!strcmp(options[i].opt, address)) return options[i].value; } return address; } sngrep-1.2.0/src/ui_filter.h0000644000175000017500000000742512632250522014773 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2014 Ivan Alonso (Kaian) ** Copyright (C) 2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_filter.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage ui window for filtering options * * This file contains the functions and structures to manage the filter * dialog, that can be used to filter the lines in call list window. */ #ifndef __UI_FILTER_H #define __UI_FILTER_H #include "config.h" #include #include "ui_manager.h" /** * @brief Enum of available dialog fields * * Dialog form has a field array. Following enum represents the * order this fields are stored in panel info structure. * */ enum filter_field_list { FLD_FILTER_SIPFROM = 0, FLD_FILTER_SIPTO, FLD_FILTER_SRC, FLD_FILTER_DST, FLD_FILTER_PAYLOAD, FLD_FILTER_REGISTER, FLD_FILTER_INVITE, FLD_FILTER_SUBSCRIBE, FLD_FILTER_NOTIFY, FLD_FILTER_OPTIONS, FLD_FILTER_PUBLISH, FLD_FILTER_MESSAGE, FLD_FILTER_FILTER, FLD_FILTER_CANCEL, //! Never remove this field id @see filter_info FLD_FILTER_COUNT }; //! Sorter declaration of struct filter_info typedef struct filter_info filter_info_t; /** * @brief Filter panel private information * * This structure contains the durable data of filter panel. */ struct filter_info { //! Form that contains the filter fields FORM *form; //! An array of fields FIELD *fields[FLD_FILTER_COUNT + 1]; }; /** * @brief Creates a new filter panel * * This function allocates all required memory for * displaying the filter panel. It also draws all the * static information of the panel that will never be * redrawn. * * @return a panel pointer */ PANEL * filter_create(); /** * @brief Destroy filter panel * * This function do the final cleanups for this panel */ void filter_destroy(); /** * @brief Get custom information of given panel * * Return ncurses users pointer of the given panel into panel's * information structure pointer. * * @param panel Ncurses panel pointer * @return a pointer to info structure of given panel */ filter_info_t * filter_info(PANEL *panel); /** * @brief Manage pressed keys for filter panel * * This function is called by UI manager every time a * key is pressed. This allow the filter panel to manage * its own keys. * If this function return 0, the key will not be handled * by ui manager. Otherwise the return will be considered * a key code. * * @param panel Filter panel pointer * @param key key code * @return 0 if the key is handled, keycode otherwise */ int filter_handle_key(PANEL *panel, int key); /** * @brief Save form data to options * * This function will update the options values * of filter fields with its new value. * * @param panel Filter panel pointer */ void filter_save_options(PANEL *panel); /** * @brief Return String value for a filter field * * @return method name */ const char* filter_field_method(int field_id); #endif sngrep-1.2.0/src/capture.c0000644000175000017500000010017312632250522014441 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file capture.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in pcap.h * * sngrep can parse a pcap file to display call flows. * This file include the functions that uses libpcap to do so. * */ #include "config.h" #include #include "capture.h" #ifdef USE_EEP #include "capture_eep.h" #endif #ifdef WITH_GNUTLS #include "capture_gnutls.h" #endif #ifdef WITH_OPENSSL #include "capture_openssl.h" #endif #include "sip.h" #include "rtp.h" #include "setting.h" #include "ui_manager.h" // Capture information capture_config_t capture_cfg = { 0 }; void capture_init(int limit, int rtp_capture) { capture_cfg.limit = limit; capture_cfg.rtp_capture = rtp_capture; capture_cfg.sources = vector_create(1, 1); capture_cfg.tcp_reasm = vector_create(0, 10); capture_cfg.ip_reasm = vector_create(0, 10); // Fixme if (setting_has_value(SETTING_CAPTURE_STORAGE, "none")) { capture_cfg.storage = CAPTURE_STORAGE_NONE; } else if (setting_has_value(SETTING_CAPTURE_STORAGE, "memory")) { capture_cfg.storage = CAPTURE_STORAGE_MEMORY; } else if (setting_has_value(SETTING_CAPTURE_STORAGE, "disk")) { capture_cfg.storage = CAPTURE_STORAGE_DISK; } // Initialize calls lock pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(__FreeBSD__) || defined(BSD) || defined (__OpenBSD__) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); #else pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); #endif pthread_mutex_init(&capture_cfg.lock, &attr); } void capture_deinit() { // Close pcap handler capture_close(); // Deallocate vectors vector_set_destroyer(capture_cfg.sources, vector_generic_destroyer); vector_destroy(capture_cfg.sources); vector_set_destroyer(capture_cfg.tcp_reasm, capture_packet_destroyer); vector_destroy(capture_cfg.tcp_reasm); vector_set_destroyer(capture_cfg.ip_reasm, capture_packet_destroyer); vector_destroy(capture_cfg.ip_reasm); // Remove capture mutex pthread_mutex_destroy(&capture_cfg.lock); } int capture_online(const char *dev, const char *outfile) { capture_info_t *capinfo; //! Error string char errbuf[PCAP_ERRBUF_SIZE]; // Set capture mode capture_cfg.status = CAPTURE_ONLINE; // Create a new structure to handle this capture source if (!(capinfo = sng_malloc(sizeof(capture_info_t)))) { fprintf(stderr, "Can't allocate memory for capture data!\n"); return 1; } // Try to find capture device information if (pcap_lookupnet(dev, &capinfo->net, &capinfo->mask, errbuf) == -1) { fprintf(stderr, "Can't get netmask for device %s\n", dev); capinfo->net = 0; capinfo->mask = 0; return 2; } // Open capture device capinfo->handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf); if (capinfo->handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); return 2; } // Get datalink to parse packets correctly capinfo->link = pcap_datalink(capinfo->handle); // Check linktypes sngrep knowns before start parsing packets if ((capinfo->link_hl = datalink_size(capinfo->link)) == -1) { fprintf(stderr, "Unable to handle linktype %d\n", capinfo->link); return 3; } // Get Local devices addresses pcap_findalldevs(&capture_cfg.devices, errbuf); // Add this capture information as packet source vector_append(capture_cfg.sources, capinfo); // If requested store packets in a dump file if (outfile && !capture_cfg.pd) { if ((capture_cfg.pd = dump_open(outfile)) == NULL) { fprintf(stderr, "Couldn't open output dump file %s: %s\n", outfile, pcap_geterr(capinfo->handle)); return 2; } } return 0; } int capture_offline(const char *infile, const char *outfile) { capture_info_t *capinfo; // Error text (in case of file open error) char errbuf[PCAP_ERRBUF_SIZE]; // Set capture mode capture_cfg.status = CAPTURE_OFFLINE_LOADING; // Create a new structure to handle this capture source if (!(capinfo = sng_malloc(sizeof(capture_info_t)))) { fprintf(stderr, "Can't allocate memory for capture data!\n"); return 1; } // Set capture input file capinfo->infile = infile; // Open PCAP file if ((capinfo->handle = pcap_open_offline(infile, errbuf)) == NULL) { fprintf(stderr, "Couldn't open pcap file %s: %s\n", infile, errbuf); return 1; } // Get datalink to parse packets correctly capinfo->link = pcap_datalink(capinfo->handle); // Check linktypes sngrep knowns before start parsing packets if ((capinfo->link_hl = datalink_size(capinfo->link)) == -1) { fprintf(stderr, "Unable to handle linktype %d\n", capinfo->link); return 3; } // Add this capture information as packet source vector_append(capture_cfg.sources, capinfo); // If requested store packets in a dump file if (outfile && !capture_cfg.pd) { if ((capture_cfg.pd = dump_open(outfile)) == NULL) { fprintf(stderr, "Couldn't open output dump file %s: %s\n", outfile, pcap_geterr(capinfo->handle)); return 2; } } return 0; } void parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packet) { // Capture info capture_info_t *capinfo = (capture_info_t *) info; // Source and Destination Ports u_short sport, dport; // UDP header data struct udphdr *udp; // UDP header size uint16_t udp_off; // TCP header data struct tcphdr *tcp; // TCP header size uint16_t tcp_off; // Packet data u_char data[MAX_CAPTURE_LEN]; // Packet payload data u_char *payload = NULL; // Whole packet size uint32_t size_capture = header->caplen; // Packet payload size uint32_t size_payload = size_capture - capinfo->link_hl; // Captured packet info capture_packet_t *pkt; // Ignore packets while capture is paused if (capture_is_paused()) return; // Check if we have reached capture limit if (capture_cfg.limit && sip_calls_count() >= capture_cfg.limit) return; // Check maximum capture length if (header->caplen > MAX_CAPTURE_LEN) return; // Copy packet payload memcpy(data, packet, header->caplen); // Check if we have a complete IP packet if (!(pkt = capture_packet_reasm_ip(capinfo, header, data, &size_payload, &size_capture))) return; // Only interested in UDP packets if (pkt->proto == IPPROTO_UDP) { // Get UDP header udp = (struct udphdr *)((u_char *)(data) + (size_capture - size_payload)); udp_off = sizeof(struct udphdr); // Set packet ports sport = htons(udp->uh_sport); dport = htons(udp->uh_dport); // Remove UDP Header from payload size_payload -= udp_off; if ((int32_t)size_payload < 0) size_payload = 0; // Remove TCP Header from payload payload = (u_char *) (udp) + udp_off; // Complete packet with Transport information capture_packet_set_transport_data(pkt, sport, dport, CAPTURE_PACKET_SIP_UDP); capture_packet_set_payload(pkt, payload, size_payload); } else if (pkt->proto == IPPROTO_TCP) { // Get TCP header tcp = (struct tcphdr *)((u_char *)(data) + (size_capture - size_payload)); tcp_off = (tcp->th_off * 4); // Set packet ports sport = htons(tcp->th_sport); dport = htons(tcp->th_dport); // Get actual payload size size_payload -= tcp_off; if ((int32_t)size_payload < 0) size_payload = 0; // Get payload start payload = (u_char *)(tcp) + tcp_off; // Complete packet with Transport information capture_packet_set_transport_data(pkt, sport, dport, CAPTURE_PACKET_SIP_TCP); capture_packet_set_payload(pkt, payload, size_payload); // Create a structure for this captured packet if (!(pkt = capture_packet_reasm_tcp(pkt, tcp, payload, size_payload))) return; #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) // Check if packet is TLS if (capture_cfg.keyfile) tls_process_segment(pkt, tcp); #endif // Check if packet is WS or WSS capture_ws_check_packet(pkt); } else { // Not handled protocol capture_packet_destroy(pkt); return; } // Avoid parsing from multiples sources. // Avoid parsing while screen in being redrawn capture_lock(); // Check if we can handle this packet if (capture_packet_parse(pkt) == 0) { #ifdef USE_EEP // Send this packet through eep capture_eep_send(pkt); #endif // Store this packets in output file dump_packet(capture_cfg.pd, pkt); // If storage is disabled, delete frames payload if (capture_cfg.storage == 0) { capture_packet_free_frames(pkt); } // Allow Interface refresh and user input actions capture_unlock(); return; } // Not an interesting packet ... capture_packet_destroy(pkt); // Allow Interface refresh and user input actions capture_unlock(); } capture_packet_t * capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *header, u_char *packet, uint32_t *size, uint32_t *caplen) { // IP header data struct ip *ip4; #ifdef USE_IPV6 // IPv6 header data struct ip6_hdr *ip6; #endif // IP version uint32_t ip_ver; // IP protocol uint8_t ip_proto; // IP header size uint32_t ip_hl = 0; // Fragment offset uint16_t ip_off = 0; // IP content len uint16_t ip_len = 0; // Fragmentation flag uint16_t ip_frag = 0; // Fragmentation identifier uint32_t ip_id = 0; // Fragmentation offset uint16_t ip_frag_off = 0; //! Source Address char ip_src[ADDRESSLEN]; //! Destination Address char ip_dst[ADDRESSLEN]; //! Common interator for vectors vector_iter_t it; //! Packet containers capture_packet_t *pkt; //! Storage for IP frame capture_frame_t *frame; uint32_t len_data = 0; // Get IP header ip4 = (struct ip *) (packet + capinfo->link_hl); #ifdef USE_IPV6 // Get IPv6 header ip6 = (struct ip6_hdr *) (packet + capinfo->link_hl); #endif // Get IP version ip_ver = ip4->ip_v; switch (ip_ver) { case 4: ip_hl = ip4->ip_hl * 4; ip_proto = ip4->ip_p; ip_off = ntohs(ip4->ip_off); ip_len = ntohs(ip4->ip_len); ip_frag = ip_off & (IP_MF | IP_OFFMASK); ip_frag_off = (ip_frag) ? (ip_off & IP_OFFMASK) * 8 : 0; ip_id = ntohs(ip4->ip_id); inet_ntop(AF_INET, &ip4->ip_src, ip_src, sizeof(ip_src)); inet_ntop(AF_INET, &ip4->ip_dst, ip_dst, sizeof(ip_dst)); break; #ifdef USE_IPV6 case 6: ip_hl = sizeof(struct ip6_hdr); ip_proto = ip6->ip6_nxt; ip_len = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen) + ip_hl; if (ip_proto == IPPROTO_FRAGMENT) { struct ip6_frag *ip6f = (struct ip6_frag *) (ip6 + ip_hl); ip_frag_off = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK); ip_id = ntohl(ip6f->ip6f_ident); } inet_ntop(AF_INET6, &ip6->ip6_src, ip_src, sizeof(ip_src)); inet_ntop(AF_INET6, &ip6->ip6_dst, ip_dst, sizeof(ip_dst)); break; #endif default: return NULL; } // Remove IP Header length from payload if (*caplen > capinfo->link_hl + ip_len) { *size = ip_len - ip_hl; } else { *size = *caplen - capinfo->link_hl - ip_hl; } // If no fragmentation if (ip_frag == 0) { // Just create a new packet with given network data pkt = capture_packet_create(ip_ver, ip_proto, ip_src, ip_dst, ip_id); capture_packet_add_frame(pkt, header, packet); return pkt; } // Look for another packet with same id in IP reassembly vector it = vector_iterator(capture_cfg.ip_reasm); while ((pkt = vector_iterator_next(&it))) { if (!strcmp(pkt->ip_src, ip_src) && !strcmp(pkt->ip_dst, ip_dst) && pkt->ip_id == ip_id) break; } // If we already have this packet stored, append this frames to existing one if (pkt) { capture_packet_add_frame(pkt, header, packet); } else { // Add To the possible reassembly list pkt = capture_packet_create(ip_ver, ip_proto, ip_src, ip_dst, ip_id); capture_packet_add_frame(pkt, header, packet); vector_append(capture_cfg.ip_reasm, pkt); return NULL; } // If no more fragments if ((ip_off & IP_MF) == 0) { // TODO Dont check the flag, check the holes // Calculate assembled IP payload data it = vector_iterator(pkt->frames); while ((frame = vector_iterator_next(&it))) { struct ip *frame_ip = (struct ip *) (frame->data + capinfo->link_hl); len_data += frame->header->caplen - capinfo->link_hl - frame_ip->ip_hl * 4; } // Check packet content length if (len_data > MAX_CAPTURE_LEN) return NULL; // Initialize memory for the assembly packet memset(packet, 0, capinfo->link_hl + ip_hl + len_data); it = vector_iterator(pkt->frames); while ((frame = vector_iterator_next(&it))) { // Get IP header struct ip *frame_ip = (struct ip *) (frame->data + capinfo->link_hl); memcpy(packet + capinfo->link_hl + ip_hl + (ntohs(frame_ip->ip_off) & IP_OFFMASK) * 8, frame->data + capinfo->link_hl + frame_ip->ip_hl * 4, frame->header->caplen - capinfo->link_hl - frame_ip->ip_hl * 4); } *caplen = capinfo->link_hl + ip_hl + len_data; *size = len_data; // Return the assembled IP packet vector_remove(capture_cfg.ip_reasm, pkt); return pkt; } return NULL; } capture_packet_t * capture_packet_reasm_tcp(capture_packet_t *packet, struct tcphdr *tcp, u_char *payload, int size_payload) { vector_iter_t it = vector_iterator(capture_cfg.tcp_reasm); capture_packet_t *pkt; u_char *new_payload; //! Assembled if ((int32_t) size_payload <= 0) return packet; while ((pkt = vector_iterator_next(&it))) { if (!strcmp(pkt->ip_src, packet->ip_src) && !strcmp(pkt->ip_dst, packet->ip_dst) && pkt->sport == packet->sport && pkt->dport == packet->dport) break; } // If we already have this packet stored if (pkt) { capture_frame_t *frame; // Append this frames to the original packet vector_iter_t frames = vector_iterator(packet->frames); while ((frame = vector_iterator_next(&frames))) capture_packet_add_frame(pkt, frame->header, frame->data); // Destroy current packet as its frames belong to the stored packet capture_packet_destroy(packet); } else { // First time this packet has been seen pkt = packet; // Add To the possible reassembly list vector_append(capture_cfg.tcp_reasm, packet); } // If the first frame of this packet if (vector_count(pkt->frames) == 1) { // Set initial payload capture_packet_set_payload(pkt, payload, size_payload); } else { // Check payload length. Dont handle too big payload packets if (pkt->payload_len + size_payload > MAX_CAPTURE_LEN) { capture_packet_destroy(pkt); vector_remove(capture_cfg.tcp_reasm, pkt); return NULL; } // Append payload to the existing new_payload = sng_malloc(pkt->payload_len + size_payload); memcpy(new_payload, pkt->payload, pkt->payload_len); memcpy(new_payload + pkt->payload_len, payload, size_payload); capture_packet_set_payload(pkt, new_payload, pkt->payload_len + size_payload); sng_free(new_payload); } // This packet is ready to be parsed if (tcp->th_flags & TH_PUSH) { vector_remove(capture_cfg.tcp_reasm, pkt); return pkt; } return NULL; } int capture_ws_check_packet(capture_packet_t *packet) { int ws_off = 0; u_char ws_fin; u_char ws_opcode; u_char ws_mask; uint8_t ws_len; u_char ws_mask_key[4]; u_char *payload, *newpayload; uint32_t size_payload; int i; /** * WSocket header definition according to RFC 6455 * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-------+-+-------------+-------------------------------+ * |F|R|R|R| opcode|M| Payload len | Extended payload length | * |I|S|S|S| (4) |A| (7) | (16/64) | * |N|V|V|V| |S| | (if payload len==126/127) | * | |1|2|3| |K| | | * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + * | Extended payload length continued, if payload len == 127 | * + - - - - - - - - - - - - - - - +-------------------------------+ * | |Masking-key, if MASK set to 1 | * +-------------------------------+-------------------------------+ * | Masking-key (continued) | Payload Data | * +-------------------------------- - - - - - - - - - - - - - - - + * : Payload Data continued ... : * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * | Payload Data continued ... | * +---------------------------------------------------------------+ */ // Get payload from packet(s) size_payload = capture_packet_get_payload_len(packet); payload = capture_packet_get_payload(packet); // Check we have payload if (size_payload == 0) return 0; // Flags && Opcode ws_fin = (*payload & WH_FIN) >> 4; ws_opcode = *payload & WH_OPCODE; ws_off++; // Only interested in Ws text packets if (ws_opcode != WS_OPCODE_TEXT) return 0; // Masked flag && Payload len ws_mask = (*(payload + ws_off) & WH_MASK) >> 4; ws_len = (*(payload + ws_off) & WH_LEN); ws_off++; // Skip Payload len switch (ws_len) { // Extended case 126: ws_off += 2; break; case 127: ws_off += 8; break; default: return 0; } // Get Masking key if mask is enabled if (ws_mask) { memcpy(ws_mask_key, (payload + ws_off), 4); ws_off += 4; } // Skip Websocket headers size_payload -= ws_off; if ((int32_t) size_payload <= 0) return 0; newpayload = sng_malloc(size_payload); memcpy(newpayload, payload + ws_off, size_payload); // If mask is enabled, unmask the payload if (ws_mask) { for (i = 0; i < size_payload; i++) newpayload[i] = newpayload[i] ^ ws_mask_key[i % 4]; } // Set new packet payload into the packet capture_packet_set_payload(packet, newpayload, size_payload); // Free the new payload sng_free(newpayload); if (packet->type == CAPTURE_PACKET_SIP_TLS) { capture_packet_set_type(packet, CAPTURE_PACKET_SIP_WSS); } else { capture_packet_set_type(packet, CAPTURE_PACKET_SIP_WS); } return 1; } int capture_packet_parse(capture_packet_t *packet) { // Media structure for RTP packets rtp_stream_t *stream; // We're only interested in packets with payload if (capture_packet_get_payload_len(packet)) { // Parse this header and payload if (sip_check_packet(packet)) { return 0; } // Check if this packet belongs to a RTP stream if ((stream = rtp_check_packet(packet))) { // We have an RTP packet! capture_packet_set_type(packet, CAPTURE_PACKET_RTP); // Store this pacekt if capture rtp is enabled if (capture_cfg.rtp_capture) { call_add_rtp_packet(stream_get_call(stream), packet); return 0; } } } return 1; } void capture_close() { capture_info_t *capinfo; // Nothing to close if (vector_count(capture_cfg.sources) == 0) return; // Stop all captures vector_iter_t it = vector_iterator(capture_cfg.sources); while ((capinfo = vector_iterator_next(&it))) { //Close PCAP file if (capinfo->handle) { pcap_breakloop(capinfo->handle); pthread_join(capinfo->capture_t, NULL); pcap_close(capinfo->handle); } } // Close dump file if (capture_cfg.pd) { dump_close(capture_cfg.pd); } } int capture_launch_thread(capture_info_t *capinfo) { //! capture thread attributes pthread_attr_t attr; pthread_attr_init(&attr); // Start all captures threads vector_iter_t it = vector_iterator(capture_cfg.sources); while ((capinfo = vector_iterator_next(&it))) { if (pthread_create(&capinfo->capture_t, &attr, (void *) capture_thread, capinfo)) { return 1; } } pthread_attr_destroy(&attr); return 0; } void capture_thread(void *info) { capture_info_t *capinfo = (capture_info_t *) info; // Parse available packets pcap_loop(capinfo->handle, -1, parse_packet, (u_char *) capinfo); if (!capture_is_online()) capture_cfg.status = CAPTURE_OFFLINE; } int capture_is_online() { return (capture_cfg.status == CAPTURE_ONLINE || capture_cfg.status == CAPTURE_ONLINE_PAUSED); } int capture_set_bpf_filter(const char *filter) { vector_iter_t it = vector_iterator(capture_cfg.sources); capture_info_t *capinfo; // Apply the given filter to all sources while ((capinfo = vector_iterator_next(&it))) { //! Check if filter compiles if (pcap_compile(capinfo->handle, &capture_cfg.fp, filter, 0, capinfo->mask) == -1) return 1; // Set capture filter if (pcap_setfilter(capinfo->handle, &capture_cfg.fp) == -1) return 1; } return 0; } void capture_set_paused(int pause) { if (capture_is_online()) { capture_cfg.status = (pause) ? CAPTURE_ONLINE_PAUSED : CAPTURE_ONLINE; } } int capture_is_paused() { return capture_cfg.status == CAPTURE_ONLINE_PAUSED; } int capture_get_status() { return capture_cfg.status; } const char * capture_get_status_desc() { switch (capture_cfg.status) { case CAPTURE_ONLINE: return "Online"; case CAPTURE_ONLINE_PAUSED: return "Online (Paused)"; case CAPTURE_OFFLINE: return "Offline"; case CAPTURE_OFFLINE_LOADING: return "Offline (Loading)"; } return ""; } const char* capture_get_infile() { capture_info_t *capinfo; if (vector_count(capture_cfg.sources) == 1) { capinfo = vector_first(capture_cfg.sources); return capinfo->infile; } else { return "Multiple files"; } } const char* capture_get_keyfile() { return capture_cfg.keyfile; } void capture_set_keyfile(const char *keyfile) { capture_cfg.keyfile = keyfile; } char * capture_last_error(cap) { capture_info_t *capinfo; if (vector_count(capture_cfg.sources) == 1) { capinfo = vector_first(capture_cfg.sources); return pcap_geterr(capinfo->handle); } return NULL; } void capture_lock() { // Avoid parsing more packet pthread_mutex_lock(&capture_cfg.lock); } void capture_unlock() { // Allow parsing more packets pthread_mutex_unlock(&capture_cfg.lock); } capture_packet_t * capture_packet_create(uint8_t ip_ver, uint8_t proto, const char *ip_src, const char *ip_dst, uint32_t id) { // Create a new packet capture_packet_t *packet; packet = sng_malloc(sizeof(capture_packet_t)); packet->ip_version = ip_ver; packet->proto = proto; packet->frames = vector_create(1, 1); packet->ip_id = id; memcpy(packet->ip_src, ip_src, ADDRESSLEN); memcpy(packet->ip_dst, ip_dst, ADDRESSLEN); return packet; } void capture_packet_destroy(capture_packet_t *packet) { capture_frame_t *frame; // Check we have a valid packet pointer if (!packet) return; // TODO frame destroyer? vector_iter_t it = vector_iterator(packet->frames); while ((frame = vector_iterator_next(&it))) { sng_free(frame->header); sng_free(frame->data); } // Free remaining packet data vector_set_destroyer(packet->frames, vector_generic_destroyer); vector_destroy(packet->frames); sng_free(packet->payload); sng_free(packet); } void capture_packet_destroyer(void *packet) { capture_packet_destroy((capture_packet_t*) packet); } void capture_packet_free_frames(capture_packet_t *pkt) { capture_frame_t *frame; vector_iter_t it = vector_iterator(pkt->frames); while ((frame = vector_iterator_next(&it))) { sng_free(frame->data); frame->data = NULL; } } capture_packet_t * capture_packet_set_transport_data(capture_packet_t *pkt, u_short sport, u_short dport, int type) { pkt->sport = sport; pkt->dport = dport; pkt->type = type; return pkt; } capture_frame_t * capture_packet_add_frame(capture_packet_t *pkt, const struct pcap_pkthdr *header, const u_char *packet) { capture_frame_t *frame; // Add frame to this packet frame = sng_malloc(sizeof(capture_frame_t)); frame->header = sng_malloc(sizeof(struct pcap_pkthdr)); memcpy(frame->header, header, sizeof(struct pcap_pkthdr)); frame->data = sng_malloc(header->caplen); memcpy(frame->data, packet, header->caplen); vector_append(pkt->frames, frame); return frame; } void capture_packet_set_type(capture_packet_t *packet, int type) { packet->type = type; } void capture_packet_set_payload(capture_packet_t *packet, u_char *payload, uint32_t payload_len) { // Free previous payload sng_free(packet->payload); packet->payload_len = 0; // Set new payload if (payload) { packet->payload = sng_malloc(payload_len + 1); memset(packet->payload, 0, payload_len + 1); memcpy(packet->payload, payload, payload_len); packet->payload_len = payload_len; } } uint32_t capture_packet_get_payload_len(capture_packet_t *packet) { return packet->payload_len; } u_char * capture_packet_get_payload(capture_packet_t *packet) { return packet->payload; } struct timeval capture_packet_get_time(capture_packet_t *packet) { capture_frame_t *first; struct timeval ts = { 0 }; // Sanity check if (!packet) return ts; // Return first frame timestamp if ((first = vector_first(packet->frames))) ts = first->header->ts; // Return packe timestamp return ts; } void capture_packet_time_sorter(vector_t *vector, void *item) { struct timeval curts, prevts; int count = vector_count(vector); int i; // TODO Implement multiframe packets curts = capture_packet_get_time(item); prevts = capture_packet_get_time(vector_last(vector)); // Check if the item is already sorted if (timeval_is_older(curts, prevts)) { return; } for (i = count - 2 ; i >= 0; i--) { // Get previous packet prevts = capture_packet_get_time(vector_item(vector, i)); // Check if the item is already in a sorted position if (timeval_is_older(curts, prevts)) { vector_insert(vector, item, i + 1); return; } } // Put this item at the begining of the vector vector_insert(vector, item, 0); } int8_t datalink_size(int datalink) { // Datalink header size switch (datalink) { case DLT_EN10MB: return 14; case DLT_IEEE802: return 22; case DLT_LOOP: case DLT_NULL: return 4; case DLT_SLIP: case DLT_SLIP_BSDOS: return 16; case DLT_PPP: case DLT_PPP_BSDOS: case DLT_PPP_SERIAL: case DLT_PPP_ETHER: return 4; case DLT_RAW: return 0; case DLT_FDDI: return 21; case DLT_ENC: return 12; #ifdef DLT_LINUX_SLL case DLT_LINUX_SLL: return 16; #endif #ifdef DLT_IPNET case DLT_IPNET: return 24; #endif default: // Not handled datalink type return -1; } } pcap_dumper_t * dump_open(const char *dumpfile) { capture_info_t *capinfo; if (vector_count(capture_cfg.sources) == 1) { capinfo = vector_first(capture_cfg.sources); return pcap_dump_open(capinfo->handle, dumpfile); } return NULL; } void dump_packet(pcap_dumper_t *pd, const capture_packet_t *packet) { if (!pd || !packet) return; vector_iter_t it = vector_iterator(packet->frames); capture_frame_t *frame; while ((frame = vector_iterator_next(&it))) { pcap_dump((u_char*) pd, frame->header, frame->data); } pcap_dump_flush(pd); } void dump_close(pcap_dumper_t *pd) { if (!pd) return; pcap_dump_close(pd); } const char * lookup_hostname(const char *address) { int i; int hostlen; in_addr_t netaddress; struct hostent *host; const char *hostname; // No lookup enabled, return address as is if (!setting_enabled(SETTING_CAPTURE_LOOKUP)) return address; // Check if we have already tryied resolve this address for (i = 0; i < capture_cfg.dnscache.count; i++) { if (!strcmp(capture_cfg.dnscache.addr[i], address)) { return capture_cfg.dnscache.hostname[i]; } } // Convert the address to network byte order if ((netaddress = inet_addr(address)) == -1) return address; // Lookup this addres host = gethostbyaddr(&netaddress, sizeof(netaddress), AF_INET); if (!host) { hostname = address; } else { hostname = host->h_name; } // Max hostname length set to 16 chars hostlen = strlen(hostname); // Store this result in the dnscache strcpy(capture_cfg.dnscache.addr[capture_cfg.dnscache.count], address); strncpy(capture_cfg.dnscache.hostname[capture_cfg.dnscache.count], hostname, hostlen); capture_cfg.dnscache.count++; // Return the stored value return capture_cfg.dnscache.hostname[capture_cfg.dnscache.count - 1]; } int is_local_address_str(const char *address) { char straddress[ADDRESSLEN], *end; strcpy(straddress, address); // If address comes with port, remove it if ((end = strchr(straddress, ':'))) *end = '\0'; return is_local_address(inet_addr(straddress)); } int is_local_address(in_addr_t address) { pcap_if_t *device; pcap_addr_t *dev_addr; for (device = capture_cfg.devices; device; device = device->next) { for (dev_addr = device->addresses; dev_addr; dev_addr = dev_addr->next) if (dev_addr->addr && dev_addr->addr->sa_family == AF_INET && ((struct sockaddr_in*) dev_addr->addr)->sin_addr.s_addr == address) return 1; } return 0; } sngrep-1.2.0/src/util.c0000644000175000017500000000654512632250522013763 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file util.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in util.h * */ #include "config.h" #include #include #include #include #include #include "util.h" void * sng_malloc(size_t size) { void *data; // Check memory allocation size if (size <= 0 || size > MALLOC_MAX_SIZE) return NULL; // Allocate memory if (!(data = malloc(size))) return NULL; // Initialize allocated memory memset(data, 0, size); return data; } void sng_free(void *ptr) { if (ptr) free(ptr); } int timeval_is_older(struct timeval t1, struct timeval t2) { long long int t1sec, t2sec; t1sec = t1.tv_sec; t1sec = t1sec * 1000000; t2sec = t2.tv_sec; t2sec = t2sec * 1000000; return ((t2sec + t2.tv_usec) - (t1sec + t1.tv_usec) < 0); } const char * timeval_to_date(struct timeval time, char *out) { time_t t = (time_t) time.tv_sec; struct tm *timestamp = localtime(&t); strftime(out, 11, "%Y/%m/%d", timestamp); return out; } const char * timeval_to_time(struct timeval time, char *out) { time_t t = (time_t) time.tv_sec; struct tm *timestamp = localtime(&t); strftime(out, 19, "%H:%M:%S", timestamp); sprintf(out + 8, ".%06d", (int) time.tv_usec); return out; } const char * timeval_to_duration(struct timeval start, struct timeval end, char *out) { int seconds; char duration[20]; if (!out || !start.tv_sec || !end.tv_sec) return NULL; // Differnce in secons seconds = end.tv_sec - start.tv_sec; // Set Human readable format sprintf(duration, "%d:%02d", seconds / 60, seconds % 60); sprintf(out, "%7s", duration); return out; } const char * timeval_to_delta(struct timeval start, struct timeval end, char *out) { long diff; int nsec, nusec; int sign; if (!out || !start.tv_sec || !end.tv_sec) return NULL; diff = end.tv_sec * 1000000 + end.tv_usec; diff -= start.tv_sec * 1000000 + start.tv_usec; nsec = diff / 1000000; nusec = labs(diff - (nsec * 1000000)); sign = (diff >= 0) ? '+' : '-'; sprintf(out, "%c%d.%06d", sign, abs(nsec), nusec); return out; } char * strtrim(char *str) { int i; if (!str || !strlen(str)) return str; for (i = strlen(str) - 1; i >= 0 && isspace(str[i]); i--) str[i] = 0; return str; } sngrep-1.2.0/src/main.c0000644000175000017500000002732112632250522013725 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file main.c * @author Ivan Alonso [aka Kaian] * * @brief Source of initial functions used by sngrep */ #include "config.h" #include #include #include #include #include #include "option.h" #include "vector.h" #include "ui_manager.h" #include "capture.h" #include "capture_eep.h" #ifdef WITH_GNUTLS #include "capture_gnutls.h" #endif #ifdef WITH_OPENSSL #include "capture_openssl.h" #endif /** * @brief Usage function * * Print all available options (which are none actually) */ void usage() { printf("Usage: %s [-hVcivNqrD] [-IO pcap_dump] [-d dev] [-l limit]" #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) " [-k keyfile]" #endif #ifdef USE_EEP " [-LH capture_url]" #endif " [] []\n\n" " -h --help\t\t This usage\n" " -V --version\t Version information\n" " -d --device\t\t Use this capture device instead of default\n" " -I --input\t\t Read captured data from pcap file\n" " -O --output\t\t Write captured data to pcap file\n" " -c --calls\t\t Only display dialogs starting with INVITE\n" " -r --rtp\t\t Capture RTP packets payload\n" " -l --limit\t\t Set capture limit to N dialogs\n" " -i --icase\t\t Make case insensitive\n" " -v --invert\t\t Invert \n" " -N --no-interface\t Don't display sngrep interface, just capture\n" " -q --quiet\t\t Don't print captured dialogs in no interface mode\n" " -D --dump-config\t Print active configuration settings and exit\n" #ifdef USE_EEP " -H --eep-send\t Homer sipcapture url (udp:X.X.X.X:XXXX)\n" " -L --eep-listen\t Listen for encapsulated packets (udp:X.X.X.X:XXXX)\n" #endif #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) " -k --keyfile\t RSA private keyfile to decrypt captured packets\n" #endif "\n",PACKAGE); } void version() { printf("%s - %s\n" "Copyright (C) 2013-2015 Irontec S.L.\n" "License GPLv3+: GNU GPL version 3 or later .\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n" #ifdef WITH_GNUTLS " * Compiled with GnuTLS support.\n" #endif #ifdef WITH_OPENSSL " * Compiled with OpenSSL support.\n" #endif #ifdef WITH_UNICODE " * Compiled with Wide-character support.\n" #endif #ifdef WITH_PCRE " * Compiled with Perl Compatible regular expressions support.\n" #endif #ifdef USE_IPV6 " * Compiled with IPv6 support.\n" #endif #ifdef USE_EEP " * Compiled with EEP/HEP support.\n" #endif "\nWritten by Ivan Alonso [aka Kaian]\n", PACKAGE, VERSION); } /** * @brief Main function logic * * Parse command line options and start running threads */ int main(int argc, char* argv[]) { int opt, idx, limit, only_calls, no_incomplete, i; const char *device, *outfile; char bpf[512]; const char *keyfile; const char *match_expr; int match_insensitive = 0, match_invert = 0; int no_interface = 0, quiet = 0, rtp_capture = 0; vector_t *infiles = vector_create(0, 1); // Program otptions static struct option long_options[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "device", required_argument, 0, 'd' }, { "input", required_argument, 0, 'I' }, { "output", required_argument, 0, 'O' }, #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) { "keyfile", required_argument, 0, 'k' }, #endif { "calls", no_argument, 0, 'c' }, { "rtp", no_argument, 0, 'r' }, { "limit", no_argument, 0, 'l' }, { "icase", no_argument, 0, 'i' }, { "invert", no_argument, 0, 'v' }, { "no-interface", no_argument, 0, 'N' }, { "dump-config", no_argument, 0, 'D' }, #ifdef USE_EEP { "eep-listen", required_argument, 0, 'L' }, { "eep-send", required_argument, 0, 'H' }, #endif { "quiet", no_argument, 0, 'q' }, }; // Initialize configuration options init_options(); // Get initial values for configurable arguments device = setting_get_value(SETTING_CAPTURE_DEVICE); outfile = setting_get_value(SETTING_CAPTURE_OUTFILE); keyfile = setting_get_value(SETTING_CAPTURE_KEYFILE); limit = setting_get_intvalue(SETTING_CAPTURE_LIMIT); only_calls = setting_enabled(SETTING_SIP_CALLS); no_incomplete = setting_enabled(SETTING_SIP_NOINCOMPLETE); rtp_capture = setting_enabled(SETTING_CAPTURE_RTP); // Parse command line arguments opterr = 0; char *options = "hVd:I:O:pqtW:k:crl:ivNqDL:H:"; while ((opt = getopt_long(argc, argv, options, long_options, &idx)) != -1) { switch (opt) { case 'h': usage(); return 0; case 'V': version(); return 0; case 'd': device = optarg; break; case 'I': vector_append(infiles, optarg); break; case 'O': outfile = optarg; break; case 'l': if(!(limit = atoi(optarg))) { fprintf(stderr, "Invalid limit value.\n"); return 0; } break; #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) case 'k': keyfile = optarg; break; #endif case 'c': only_calls = 1; setting_set_value(SETTING_SIP_CALLS, SETTING_ON); break; case 'r': rtp_capture = 1; setting_set_value(SETTING_CAPTURE_RTP, SETTING_ON); break; case 'i': match_insensitive++; break; case 'v': match_invert++; break; case 'N': no_interface = 1; setting_set_value(SETTING_CAPTURE_STORAGE, "none"); break; case 'q': quiet = 1; break; case 'D': key_bindings_dump(); settings_dump(); return 0; // Dark options for dummy ones case 'p': case 't': case 'W': break; #ifdef USE_EEP case 'L': capture_eep_set_server_url(optarg); break; case 'H': capture_eep_set_client_url(optarg); break; #endif case '?': if (strchr(options, optopt)) { fprintf(stderr, "-%c option requires an argument.\n", optopt); } else if (isprint(optopt)) { fprintf(stderr, "Unknown option -%c.\n", optopt); } else { fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt); } return 1; default: break; } } #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) // Set capture decrypt key file capture_set_keyfile(keyfile); // Check if we have a keyfile and is valid if (keyfile && !tls_check_keyfile(keyfile)) { fprintf(stderr, "%s does not contain a valid RSA private key.\n", keyfile); return 1; } #endif // Check if given argument is a file if (argc == 2 && (access(argv[1], F_OK) == 0)) { // Old legacy option to open pcaps without other arguments printf("%s seems to be a file: You forgot -I flag?\n", argv[1]); return 0; } // Initialize SIP Messages Storage sip_init(limit, only_calls, no_incomplete); // Set capture options capture_init(limit, rtp_capture); #ifdef USE_EEP // Initialize EEP if enabled capture_eep_init(); #endif // If we have an input file, load it if (vector_count(infiles)) { for (i = 0; i < vector_count(infiles); i++) { // Try to load file if (capture_offline(vector_item(infiles, i), outfile) != 0) return 1; } } else { // Check if all capture data is valid if (capture_online(device, outfile) != 0) return 1; } // Remove Input files vector vector_destroy(infiles); // More arguments pending! if (argv[optind]) { // Assume first pending argument is match expression match_expr = argv[optind++]; // Try to build the bpf filter string with the rest memset(bpf, 0, sizeof(bpf)); for (i = optind; i < argc; i++) sprintf(bpf + strlen(bpf), "%s ", argv[i]); // Check if this BPF filter is valid if (capture_set_bpf_filter(bpf) != 0) { // BPF Filter invalid, check incluiding match_expr match_expr = 0; // There is no need to parse all payload at this point // Build the bpf filter string memset(bpf, 0, sizeof(bpf)); for (i = optind - 1; i < argc; i++) sprintf(bpf + strlen(bpf), "%s ", argv[i]); // Check bpf filter is valid again if (capture_set_bpf_filter(bpf) != 0) { fprintf(stderr, "Couldn't install filter %s: %s\n", bpf, capture_last_error()); return 1; } } // Set the capture filter if (match_expr) if (sip_set_match_expression(match_expr, match_insensitive, match_invert)) { fprintf(stderr, "Unable to parse expression %s\n", match_expr); return 1; } } // Start a capture thread if (capture_launch_thread() != 0) { ncurses_deinit(); fprintf(stderr, "Failed to launch capture thread.\n"); return 1; } if (!no_interface) { // Initialize interface ncurses_init(); // This is a blocking call. // Create the first panel and wait for user input ui_create_panel(PANEL_CALL_LIST); wait_for_input(); } else { setbuf(stdout, NULL); while(capture_get_status() != CAPTURE_OFFLINE) { if (!quiet) printf("\rDialog count: %d", sip_calls_count()); usleep(500 * 1000); } if (!quiet) printf("\rDialog count: %d\n", sip_calls_count()); } // Capture deinit capture_deinit(); // Deinitialize interface ncurses_deinit(); // Deinitialize configuration options deinit_options(); // Deallocate sip stored messages sip_deinit(); // Leaving! return 0; } sngrep-1.2.0/src/capture_gnutls.h0000644000175000017500000003003112632250522016035 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ** In addition, as a special exception, the copyright holders give ** permission to link the code of portions of this program with the ** OpenSSL library under certain conditions as described in each ** individual source file, and distribute linked combinations ** including the two. ** You must obey the GNU General Public License in all respects ** for all of the code used other than OpenSSL. If you modify ** file(s) with this exception, you may extend this exception to your ** version of the file(s), but you are not obligated to do so. If you ** do not wish to do so, delete this exception statement from your ** version. If you delete this exception statement from all source ** files in the program, then also delete it here. ** ****************************************************************************/ /** * @file capture_tls.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP TLS messages * * This file contains the functions and structures to manage the SIP messages * that use TLS as transport. * */ #ifndef __SNGREP_CAPTURE_TLS_ #define __SNGREP_CAPTURE_TLS_ #include "config.h" #include #include #include #include #include #include "capture.h" //! Cast two bytes into decimal (Big Endian) #define UINT16_INT(i) ((i.x[0] << 8) | i.x[1]) //! Cast three bytes into decimal (Big Endian) #define UINT24_INT(i) ((i.x[0] << 16) | (i.x[1] << 8) | i.x[2]) //! One byte unsigned integer typedef unsigned char uint8; //! Two bytes unsigned integer typedef struct uint16 { unsigned char x[2]; } uint16; //! Three bytes unsigned integer typedef struct uint24 { unsigned char x[3]; } uint24; //! Four bytes unsigned interger typedef struct uint32 { unsigned char x[4]; } uint32; //! One byte generic type typedef unsigned char opaque; //! SSLConnections states enum SSLConnectionState { //! Initial SYN packet has been received from client TCP_STATE_SYN = 0, //! SYN/ACK packet has been sent from the server TCP_STATE_SYN_ACK, //! Client ACK'ed the connection TCP_STATE_ACK, //! Connection is up, now SSL handshake should start! TCP_STATE_ESTABLISHED, //! Connection about to end TCP_STATE_FIN, //! Connection closed TCP_STATE_CLOSED }; //! ContentType values as defined in RFC5246 enum ContentType { change_cipher_spec = 20, alert = 21, handshake = 22, application_data = 23 }; //! HanshakeType values as defined in RFC5246 enum HandshakeType { hello_request = GNUTLS_HANDSHAKE_HELLO_REQUEST, client_hello = GNUTLS_HANDSHAKE_CLIENT_HELLO, server_hello = GNUTLS_HANDSHAKE_SERVER_HELLO, certificate = GNUTLS_HANDSHAKE_CERTIFICATE_PKT, certificate_request = GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST, server_hello_done = GNUTLS_HANDSHAKE_SERVER_HELLO_DONE, certificate_verify = GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY, client_key_exchange = GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE, finished = GNUTLS_HANDSHAKE_FINISHED }; //! ProtocolVersion header as defined in RFC5246 struct ProtocolVersion { uint8 major; uint8 minor; }; //! TLSPlaintext record structure struct TLSPlaintext { uint8 type; struct ProtocolVersion version; uint16 length; }; //! Hanshake record structure struct Handshake { uint8 type; uint24 length; }; //! Handshake random structure struct Random { uint32 gmt_unix_time; opaque random_bytes[28]; }; struct CipherSuite { uint8 cs1; uint8 cs2; }; //! ClientHello type in Handshake records struct ClientHello { struct ProtocolVersion client_version; struct Random random; // uint8 session_id_length; // CipherSuite cipher_suite; // Extension extensions; }; //! ServerHello type in Handshake records struct ServerHello { struct ProtocolVersion server_version; struct Random random; uint8 session_id_length; // SessionID session_id; // CipherSuite cipher_suite; // CompressionMethod compression_method; }; struct MasterSecret { uint8 random[48]; }; struct PreMasterSecret { struct ProtocolVersion client_version; uint8 random[46]; }; struct EncryptedPreMasterSecret { uint8 pre_master_secret[128]; }; //! ClientKeyExchange type in Handshake records struct ClientKeyExchange { uint16 length; struct EncryptedPreMasterSecret exchange_keys; }; /** * Structure to store all information from a TLS * connection. This is also used as linked list * node. */ struct SSLConnection { //! Connection status enum SSLConnectionState state; //! Current packet direction int direction; //! Data is encrypted flag int encrypted; //! Client IP address struct in_addr client_addr; //! Server IP address struct in_addr server_addr; //! Client port u_short client_port; //! Server port u_short server_port; SSL *ssl; SSL_CTX *ssl_ctx; int ciph; gnutls_privkey_t server_private_key; struct Random client_random; struct Random server_random; struct CipherSuite cipher_suite; struct PreMasterSecret pre_master_secret; struct MasterSecret master_secret; struct tls_data { uint8 client_write_MAC_key[20]; uint8 server_write_MAC_key[20]; uint8 client_write_key[32]; uint8 server_write_key[32]; uint8 client_write_IV[16]; uint8 server_write_IV[16]; } key_material; gcry_cipher_hd_t client_cipher_ctx; gcry_cipher_hd_t server_cipher_ctx; struct SSLConnection *next; }; /** * @brief P_hash expansion function as defined in RFC5246 * * This function will expand Secret and Seed into output using digest * hash function. The amount of data generated will be determined by output * length (dlen). * * @param digest Digest name to get the hash function * @param dest Destination of hash function result. Memory must be already allocated * @param dlen Destination length in bytes * @param secret Input for the hash function * @param sslen Secret length in bytes * @param seed Input for the hash function * @param slen Seed length in bytes * @return Output bytes */ int P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret, int sslen, unsigned char *seed, int slen); /** * @brief Pseudorandom Function as defined in RFC5246 * * This function will generate MasterSecret and KeyMaterial data from PreMasterSecret and Seed * * @param dest Destination of PRF function result. Memory must be already allocated * @param dlen Destination length in bytes * @param pre_master_secret PreMasterSecret decrypted from ClientKeyExchange Handhsake record * @param pslen PreMasterSecret length in bytes * @param label Fixed ASCII string * @param seed Concatenation of Random data from Hello Handshake records * @param slen Seed length in bytes * @return destination length in bytes */ int PRF(unsigned char *dest, int dlen, unsigned char *pre_master_secret, int plen, unsigned char *label, unsigned char *seed, int slen); /** * @brief Create a new SSLConnection * * This will allocate enough memory to store all connection data * from a detected SSL connection. This will also add this structure to * the connections linked list. * * @param caddr Client address * @param cport Client port * @param saddr Server address * @param sport Server port * @return a pointer to a new allocated SSLConnection structure */ struct SSLConnection * tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr, u_short sport); /** * @brief Destroys an existing SSLConnection * * This will free all allocated memory of SSLConnection also removing * the connection from connections list. * * @param conn Existing connection pointer */ void tls_connection_destroy(struct SSLConnection *conn); /** * @brief Check if given keyfile is valid * * This can be used to check if a file contains valid RSA data * * @param keyfile Absolute path the keyfile * @return 1 if file contains RSA private info, 0 otherwise */ int tls_check_keyfile(const char *keyfile); /** * @brief Determines packet direction * * Determine if the given address is from client or server. * * @param conn Existing connection pointer * @param addr Client or server address * @param port Client or server port * @return 0 if address belongs to client, 1 to server or -1 otherwise */ int tls_connection_dir(struct SSLConnection *conn, struct in_addr addr, u_short port); /** * @brief Find a connection * * Try to find connection data for a given address and port. * This address:port convination can be the client or server one. * * @param addr Client or server address * @param port Client or server port * @return an existing Connection pointer or NULL if not found */ struct SSLConnection* tls_connection_find(struct in_addr addr, u_short port); /** * @brief Process a TCP segment to check TLS data * * Check if a TCP segment contains TLS data. In case a TLS record is found * process it and return decrypted data if case of application_data record. * * @param tcp Pointer to tcp header of the packet * @param out Pointer to the output char array. Memory must be already allocated * @param out Number of bytes returned by this function * @return 0 in all cases */ int tls_process_segment(capture_packet_t *packet, struct tcphdr *tcp); /** * @brief Process TLS record data * * Process a TLS record * - If the record type is Handshake process it in tls_process_record_handshake * - If the record type is Application Data process it in tls_process_record_data * * @param conn Existing connection pointer * @param payload Packet peyload * @param len Payload length * @param out pointer to store decryted data * @param outl decrypted data length * @return Decrypted data length */ int tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int len, uint8 **out, uint32_t *outl); /** * @brief Process TLS Handshake record types * * Process all types of Handshake records to store and compute all required * data to decrypt application data packets * * @param conn Existing connection pointer * @param fragment Handshake record data * @return 0 on valid record processed, 1 otherwise */ int tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment); /** * @brief Process TLS ApplicationData record types * * Process application data record, trying to decrypt it with connection * information * * @param conn Existing connection pointer * @param fragment Application record data * @param len record length in bytes * @param out pointer to store decryted data * @param outl decrypted data length * @return decoded data length */ int tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len, uint8 **out, uint32_t *outl); /** * @brief Get the cipher data from the given connection * * Load cipher pointer depending on the selected cipher in * Handshake messages. * * This function can be used to test is a cipher decrypting is supported * @param conn Existing connection pointer * @return 0 on valid cipher, 1 otherwise */ int tls_connection_load_cipher(struct SSLConnection *conn); #endif sngrep-1.2.0/src/ui_call_flow.c0000644000175000017500000014140212632250522015435 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_call_flow.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_call_flow.h */ #include "config.h" #include #include #include "capture.h" #include "ui_manager.h" #include "ui_call_flow.h" #include "ui_call_raw.h" #include "ui_msg_diff.h" #include "util.h" #include "vector.h" #include "option.h" /*** * * Some basic ascii art of this panel. * * +--------------------------------------------------------+ * | Title | * | addr1 addr2 addr3 addr4 | Selected Raw Message | * | ----- ----- ----- ----- | preview | * | Tmst| | | | | | * | Tmst|----->| | | | | * | Tmst| |----->| | | | * | Tmst| |<-----| | | | * | Tmst| | |----->| | | * | Tmst|<-----| | | | | * | Tmst| |----->| | | | * | Tmst| |<-----| | | | * | Tmst| |------------>| | | * | Tmst| |<------------| | | * | | | | | | | * | | | | | | | * | | | | | | | * | Useful hotkeys | * +--------------------------------------------------------+ * */ /** * Ui Structure definition for Call Flow panel */ ui_t ui_call_flow = { .type = PANEL_CALL_FLOW, .panel = NULL, .create = call_flow_create, .destroy = call_flow_destroy, .draw = call_flow_draw, .handle_key = call_flow_handle_key, .help = call_flow_help }; PANEL * call_flow_create() { PANEL *panel; WINDOW *win; int height, width; call_flow_info_t *info; // Create a new panel to fill all the screen panel = new_panel(newwin(LINES, COLS, 0, 0)); // Initialize Call List specific data info = sng_malloc(sizeof(call_flow_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Let's draw the fixed elements of the screen win = panel_window(panel); getmaxyx(win, height, width); // Calculate available printable area for messages info->flow_win = subwin(win, height - 2 - 2 - 2, width - 2, 4, 0); // Header - Footer - Address info->raw_width = 0; // calculated with the available space after drawing columns info->last_msg = NULL; // Create vectors for columns and flow arrows info->columns = vector_create(2, 1); vector_set_destroyer(info->columns, vector_generic_destroyer); info->arrows = vector_create(20, 5); vector_set_destroyer(info->arrows, vector_generic_destroyer); return panel; } void call_flow_destroy(PANEL *panel) { call_flow_info_t *info; // Free the panel information if ((info = call_flow_info(panel))) { // Delete panel columns vector_destroy(info->columns); // Delete panel arrows vector_destroy(info->arrows); // Delete panel windows delwin(info->flow_win); delwin(info->raw_win); // Delete displayed call group call_group_destroy(info->group); sng_free(info); } // Delete panel window delwin(panel_window(panel)); // Deallocate panel pointer del_panel(panel); } call_flow_info_t * call_flow_info(PANEL *panel) { return (call_flow_info_t*) panel_userptr(panel); } int call_flow_draw(PANEL *panel) { call_flow_info_t *info; WINDOW *win; call_flow_arrow_t *arrow = NULL; int height, width, cline = 0; char title[256]; char callid[256]; // Get panel information info = call_flow_info(panel); // Get window of main panel win = panel_window(panel); getmaxyx(win, height, width); werase(win); // Set title if (call_group_count(info->group) == 1) { sprintf(title, "Call flow for %s", call_get_attribute(vector_first(info->group->calls), SIP_ATTR_CALLID, callid)); } else { sprintf(title, "Call flow for %d dialogs", call_group_count(info->group)); } // Print color mode in title if (setting_has_value(SETTING_COLORMODE, "request")) strcat(title, " (Color by Request/Response)"); if (setting_has_value(SETTING_COLORMODE, "callid")) strcat(title, " (Color by Call-Id)"); if (setting_has_value(SETTING_COLORMODE, "cseq")) strcat(title, " (Color by CSeq)"); // Draw panel title draw_title(panel, title); // Show some keybinding call_flow_draw_footer(panel); // Redraw columns call_flow_draw_columns(panel); for (arrow = info->first_arrow; arrow; arrow = call_flow_next_arrow(panel, arrow)) { if (arrow->type == CF_ARROW_SIP) { if (!call_flow_draw_message(panel, arrow, cline)) break; } else if (arrow->type == CF_ARROW_RTP) { if (!call_flow_draw_rtp_stream(panel, arrow, cline)) break; } else if (arrow->type == CF_ARROW_RTCP) { if (!call_flow_draw_rtcp_stream(panel, arrow, cline)) break; } cline += arrow->height; } // If there are only three columns, then draw the raw message on this panel if (setting_enabled(SETTING_CF_FORCERAW)) { switch (info->cur_arrow->type) { case CF_ARROW_RTP: call_flow_draw_raw(panel, info->cur_arrow->stream->media->msg); break; case CF_ARROW_SIP: call_flow_draw_raw(panel, info->cur_arrow->msg); break; case CF_ARROW_RTCP: call_flow_draw_raw_rtcp(panel, info->cur_arrow->stream); break; } } // Draw the scrollbar draw_vscrollbar(info->flow_win, call_group_msg_number(info->group, call_flow_arrow_message(info->first_arrow)) * 2, call_group_msg_count(info->group) * 2, 1); // Redraw flow win wnoutrefresh(info->flow_win); return 0; } void call_flow_draw_footer(PANEL *panel) { call_flow_info_t *info; sip_call_t *call = NULL; WINDOW *win; int streamcnt = 0; int height, width; // Get panel information info = call_flow_info(panel); // Get window of main panel win = panel_window(panel); getmaxyx(win, height, width); const char *keybindings[] = { key_action_key_str(ACTION_PREV_SCREEN), "Calls List", key_action_key_str(ACTION_CONFIRM), "Raw", key_action_key_str(ACTION_SELECT), "Compare", key_action_key_str(ACTION_SHOW_HELP), "Help", key_action_key_str(ACTION_SDP_INFO), "SDP", key_action_key_str(ACTION_TOGGLE_MEDIA), "RTP", key_action_key_str(ACTION_SHOW_FLOW_EX), "Extended", key_action_key_str(ACTION_COMPRESS), "Compressed", key_action_key_str(ACTION_SHOW_RAW), "Raw", key_action_key_str(ACTION_CYCLE_COLOR), "Colour by", key_action_key_str(ACTION_INCREASE_RAW), "Increase Raw" }; draw_keybindings(panel, keybindings, 22); // If any dialog has RTP streams and they are not visible if (!setting_enabled(SETTING_CF_MEDIA)) { while ((call = call_group_get_next(info->group, call)) ) { streamcnt += vector_count(call->streams); } // Highlight RTP keybinding if (streamcnt) { wattron(win, A_BOLD | COLOR_PAIR(CP_YELLOW_ON_CYAN)); mvwprintw(win, height - 1, 64, "%s %s", key_action_key_str(ACTION_TOGGLE_MEDIA), "RTP"); wattroff(win, A_BOLD | COLOR_PAIR(CP_YELLOW_ON_CYAN)); } } } int call_flow_draw_columns(PANEL *panel) { call_flow_info_t *info; call_flow_column_t *column; sip_call_t *call = NULL; rtp_stream_t *stream; WINDOW *win; sip_msg_t *msg; vector_iter_t streams; vector_iter_t columns; int flow_height, flow_width; const char *coltext; char ip_src[80], ip_dst[80]; // Get panel information info = call_flow_info(panel); // Get window of main panel win = panel_window(panel); getmaxyx(info->flow_win, flow_height, flow_width); // Load columns for (msg = call_group_get_next_msg(info->group, info->last_msg); msg; msg = call_group_get_next_msg(info->group, msg)) { memset(ip_src, 0, sizeof(ip_src)); memset(ip_dst, 0, sizeof(ip_dst)); msg_get_attribute(msg, SIP_ATTR_SRC, ip_src); msg_get_attribute(msg, SIP_ATTR_DST, ip_dst); call_flow_column_add(panel, msg->call->callid, ip_src); call_flow_column_add(panel, msg->call->callid, ip_dst); info->last_msg = msg; } // Add RTP columns FIXME Really if (!setting_disabled(SETTING_CF_MEDIA)) { while ((call = call_group_get_next(info->group, call)) ) { streams = vector_iterator(call->streams); while ((stream = vector_iterator_next(&streams))) { if (stream_get_count(stream)) { call_flow_column_add(panel, NULL, stream->ip_src); call_flow_column_add(panel, NULL, stream->ip_dst); } } } } // Draw vertical columns lines columns = vector_iterator(info->columns); while ((column = vector_iterator_next(&columns))) { mvwvline(info->flow_win, 0, 20 + 30 * column->colpos, ACS_VLINE, flow_height); mvwhline(win, 3, 10 + 30 * column->colpos, ACS_HLINE, 20); mvwaddch(win, 3, 20 + 30 * column->colpos, ACS_TTEE); // Set bold to this address if it's local if (is_local_address_str(column->addr) && setting_enabled(SETTING_CF_LOCALHIGHLIGHT)) wattron(win, A_BOLD); coltext = sip_address_port_format(column->addr); mvwprintw(win, 2, 10 + 30 * column->colpos + (22 - strlen(coltext)) / 2, "%s", coltext); wattroff(win, A_BOLD); } return 0; } call_flow_arrow_t * call_flow_draw_message(PANEL *panel, call_flow_arrow_t *arrow, int cline) { call_flow_info_t *info; WINDOW *win; sdp_media_t *media; const char *msg_callid; char msg_method[128]; char msg_time[80]; char msg_src[80]; char msg_dst[80]; char sdp_address[80]; char sdp_port[80]; char method[80]; char delta[15] = { }; int height, width; char mediastr[40]; sip_msg_t *msg = arrow->msg; vector_iter_t medias; int color = 0; int msglen; int arrow_dir = 0; /* 0: right, 1: left */ // Get panel information info = call_flow_info(panel); // Get the messages window win = info->flow_win; getmaxyx(win, height, width); // Store arrow start line arrow->line = cline; // Calculate how many lines this message requires arrow->height = call_flow_arrow_height(panel, arrow); // Check this message fits on the panel if (cline > height + arrow->height) return NULL; // Get message attributes msg_callid = msg->call->callid; msg_get_attribute(msg, SIP_ATTR_METHOD, msg_method); msg_get_attribute(msg, SIP_ATTR_TIME, msg_time); msg_get_attribute(msg, SIP_ATTR_SRC, msg_src); msg_get_attribute(msg, SIP_ATTR_DST, msg_dst); // Get Message method (include extra info) sprintf(method, "%s", msg_method); // If message has sdp information if (msg_has_sdp(msg) && setting_has_value(SETTING_CF_SDP_INFO, "off")) { // Show sdp tag in title sprintf(method, "%s (SDP)", msg_method); } // If message has sdp information if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { // Show sdp tag in title if (msg_has_sdp(msg)) { sprintf(method, "%.*s (SDP)", 12, msg_method); } else { sprintf(method, "%.*s", 17, msg_method); } } if (msg_has_sdp(msg) && setting_has_value(SETTING_CF_SDP_INFO, "first")) { sprintf(method, "%.3s (%s:%s)", msg_method, msg_get_attribute(msg, SIP_ATTR_SDP_ADDRESS, sdp_address), msg_get_attribute(msg, SIP_ATTR_SDP_PORT, sdp_port)); } if (msg_has_sdp(msg) && setting_has_value(SETTING_CF_SDP_INFO, "full")) { sprintf(method, "%.3s (%s)", msg_method, msg_get_attribute(msg, SIP_ATTR_SDP_ADDRESS, sdp_address)); } // Draw message type or status and line msglen = (strlen(method) > 24) ? 24 : strlen(method); // Get origin and destination column call_flow_column_t *column1 = call_flow_column_get(panel, msg_callid, msg_src); call_flow_column_t *column2 = call_flow_column_get(panel, msg_callid, msg_dst); call_flow_column_t *tmp; if (column1->colpos > column2->colpos) { tmp = column1; column1 = column2; column2 = tmp; arrow_dir = 1; /* swap arrow direction */ } int startpos = 20 + 30 * column1->colpos; int endpos = 20 + 30 * column2->colpos; int distance = abs(endpos - startpos) - 3; // Highlight current message if (arrow == info->cur_arrow) { if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reverse")) { wattron(win, A_REVERSE); } if (setting_has_value(SETTING_CF_HIGHTLIGHT, "bold")) { wattron(win, A_BOLD); } if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reversebold")) { wattron(win, A_REVERSE); wattron(win, A_BOLD); } } // Color the message { if (setting_has_value(SETTING_COLORMODE, "request")) { // Color by request / response color = (msg_is_request(msg)) ? CP_RED_ON_DEF : CP_GREEN_ON_DEF; } else if (setting_has_value(SETTING_COLORMODE, "callid")) { // Color by call-id color = call_group_color(info->group, msg->call); } else if (setting_has_value(SETTING_COLORMODE, "cseq")) { // Color by CSeq within the same call color = msg->cseq % 7 + 1; } // Turn on the message color wattron(win, COLOR_PAIR(color)); // Clear the line mvwprintw(win, cline, startpos + 2, "%*s", distance, ""); // Draw method mvwprintw(win, cline, startpos + distance / 2 - msglen / 2 + 2, "%.26s", method); if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) cline++; // Draw media information if (msg_has_sdp(msg) && setting_has_value(SETTING_CF_SDP_INFO, "full")) { medias = vector_iterator(msg->medias); while ((media = vector_iterator_next(&medias))) { sprintf(mediastr, "%s %d (%s)", media_get_type(media), media_get_port(media), media_get_prefered_format(media)); mvwprintw(win, cline++, startpos + distance / 2 - strlen(mediastr) / 2 + 2, mediastr); } } if (arrow == info->selected) { mvwhline(win, cline, startpos + 2, '=', distance); } else { mvwhline(win, cline, startpos + 2, ACS_HLINE, distance); } // Write the arrow at the end of the message (two arros if this is a retrans) if (arrow_dir == 0 /* right */) { mvwaddch(win, cline, endpos - 2, '>'); if (call_msg_is_retrans(msg)) { mvwaddch(win, cline, endpos - 3, '>'); mvwaddch(win, cline, endpos - 4, '>'); } } else { mvwaddch(win, cline, startpos + 2, '<'); if (call_msg_is_retrans(msg)) { mvwaddch(win, cline, startpos + 3, '<'); mvwaddch(win, cline, startpos + 4, '<'); } } if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) mvwprintw(win, cline, startpos + distance / 2 - msglen / 2 + 2, " %.26s ", method); // Turn off colors wattroff(win, COLOR_PAIR(CP_RED_ON_DEF)); wattroff(win, COLOR_PAIR(CP_GREEN_ON_DEF)); wattroff(win, COLOR_PAIR(CP_CYAN_ON_DEF)); wattroff(win, COLOR_PAIR(CP_YELLOW_ON_DEF)); wattroff(win, A_BOLD | A_REVERSE); // Print timestamp if (info->selected == arrow) wattron(win, COLOR_PAIR(CP_CYAN_ON_DEF)); mvwprintw(win, cline, 2, "%s", msg_time); // Print delta from selected message if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { if (!info->selected) { if (setting_enabled(SETTING_CF_DELTA)) timeval_to_delta(msg_get_time(call_group_get_prev_msg(info->group, msg)), msg_get_time(msg), delta); } else if (info->cur_arrow == arrow) { timeval_to_delta(msg_get_time(call_flow_arrow_message(info->selected)), msg_get_time(msg), delta); } if (strlen(delta)) { wattron(win, COLOR_PAIR(CP_CYAN_ON_DEF)); mvwprintw(win, cline - 1 , 2, "%15s", delta); } wattroff(win, COLOR_PAIR(CP_CYAN_ON_DEF)); } wattroff(win, COLOR_PAIR(CP_CYAN_ON_DEF)); return arrow; } call_flow_arrow_t * call_flow_draw_rtp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline) { call_flow_info_t *info; WINDOW *win; char text[50], time[20]; int height, width; const char *callid; char msg_dst[80], msg_src[80]; call_flow_column_t *column1, *column2; rtp_stream_t *stream = arrow->stream; int arrow_dir = 0; /* 0: right, 1: left */ // Get panel information info = call_flow_info(panel); // Get the messages window win = info->flow_win; getmaxyx(win, height, width); // Store arrow start line arrow->line = cline; // Calculate how many lines this message requires arrow->height = call_flow_arrow_height(panel, arrow); // Check this media fits on the panel if (cline > height + arrow->height) return NULL; // Get Message method (include extra info) sprintf(text, "RTP (%s) %d", stream_get_format(stream), stream_get_count(stream)); // Get message data msg_get_attribute(stream->media->msg, SIP_ATTR_SRC, msg_src); msg_get_attribute(stream->media->msg, SIP_ATTR_DST, msg_dst); // Remove port from address. We only look for columns no matter if it matches port or not sip_address_strip_port(msg_src); sip_address_strip_port(msg_dst); callid = stream->media->msg->call->callid; // Get origin column for this stream. // If we share the same Address from its setup SIP packet, use that column instead. if (!strcmp(stream->ip_src, msg_src)) { column1 = call_flow_column_get(panel, callid, msg_src); } else if (!strcmp(stream->ip_src, msg_dst)) { column1 = call_flow_column_get(panel, callid, msg_dst); } else { column1 = call_flow_column_get(panel, 0, stream->ip_src); } // Get destination column for this stream. // If we share the same Address from its setup SIP packet, use that column instead. if (!strcmp(stream->ip_dst, msg_dst)) { column2 = call_flow_column_get(panel, callid, msg_dst); } else if (!strcmp(stream->ip_dst, msg_src)) { column2 = call_flow_column_get(panel, callid, msg_src); } else { column2 = call_flow_column_get(panel, 0, stream->ip_dst); } call_flow_column_t *tmp; if (column1->colpos > column2->colpos) { tmp = column1; column1 = column2; column2 = tmp; arrow_dir = 1; /* swap arrow direction */ } int startpos = 20 + 30 * column1->colpos; int endpos = 20 + 30 * column2->colpos; // In compressed mode, we display the src and dst port inside the arrow // so fixup the stard and end position if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { startpos += 5; endpos -= 5; } int distance = abs(endpos - startpos) - 4 + 1; // Highlight current message if (arrow == info->cur_arrow) { if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reverse")) { wattron(win, A_REVERSE); } if (setting_has_value(SETTING_CF_HIGHTLIGHT, "bold")) { wattron(win, A_BOLD); } if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reversebold")) { wattron(win, A_REVERSE); wattron(win, A_BOLD); } } // Clear the line mvwprintw(win, cline, startpos + 2, "%*s", distance, ""); // Draw method mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, "%s", text); if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) cline++; // Draw line between columns mvwhline(win, cline, startpos + 2, ACS_HLINE, distance); // Write the arrow at the end of the message (two arrows if this is a retrans) if (arrow_dir == 0 /* right */) { if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { mvwprintw(win, cline, startpos - 4, "%d", stream->sport); mvwprintw(win, cline, endpos, "%d", stream->dport); } mvwaddch(win, cline, endpos - 2, '>'); if (arrow->rtp_count != stream_get_count(stream)) { arrow->rtp_count = stream_get_count(stream); arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; mvwaddch(win, cline, startpos + arrow->rtp_ind_pos + 2, '>'); } } else { if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { mvwprintw(win, cline, endpos, "%d", stream->sport); mvwprintw(win, cline, startpos - 4, "%d", stream->dport); } mvwaddch(win, cline, startpos + 2, '<'); if (arrow->rtp_count != stream_get_count(stream)) { arrow->rtp_count = stream_get_count(stream); arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; mvwaddch(win, cline, endpos - arrow->rtp_ind_pos - 2, '<'); } } if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, " %s ", text); wattroff(win, A_BOLD | A_REVERSE); // Print timestamp timeval_to_time(stream->time, time); mvwprintw(win, cline, 2, "%s", time); return arrow; } call_flow_arrow_t * call_flow_draw_rtcp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline) { call_flow_info_t *info; WINDOW *win; char text[50], time[20]; int height, width; const char *callid; char msg_dst[80], msg_src[80]; call_flow_column_t *column1, *column2; rtp_stream_t *stream = arrow->stream; int arrow_dir = 0; /* 0: right, 1: left */ // Get panel information info = call_flow_info(panel); // Get the messages window win = info->flow_win; getmaxyx(win, height, width); // Store arrow start line arrow->line = cline; // Calculate how many lines this message requires arrow->height = call_flow_arrow_height(panel, arrow); // Check this media fits on the panel if (cline > height + arrow->height) return NULL; // Arrow text sprintf(text, "RTCP (%.1f) %d", (float) stream->rtcpinfo.mosc / 10, stream_get_count(stream)); // Get message data msg_get_attribute(stream->media->msg, SIP_ATTR_SRC, msg_src); msg_get_attribute(stream->media->msg, SIP_ATTR_DST, msg_dst); // Remove port from address. We only look for columns no matter if it matches port or not sip_address_strip_port(msg_src); sip_address_strip_port(msg_dst); callid = stream->media->msg->call->callid; // Get origin column for this stream. // If we share the same Address from its setup SIP packet, use that column instead. if (!strcmp(stream->ip_src, msg_src)) { column1 = call_flow_column_get(panel, callid, msg_src); } else if (!strcmp(stream->ip_src, msg_dst)) { column1 = call_flow_column_get(panel, callid, msg_dst); } else { column1 = call_flow_column_get(panel, 0, stream->ip_src); } // Get destination column for this stream. // If we share the same Address from its setup SIP packet, use that column instead. if (!strcmp(stream->ip_dst, msg_dst)) { column2 = call_flow_column_get(panel, callid, msg_dst); } else if (!strcmp(stream->ip_dst, msg_src)) { column2 = call_flow_column_get(panel, callid, msg_src); } else { column2 = call_flow_column_get(panel, 0, stream->ip_dst); } call_flow_column_t *tmp; if (column1->colpos > column2->colpos) { tmp = column1; column1 = column2; column2 = tmp; arrow_dir = 1; /* swap arrow direction */ } int startpos = 20 + 30 * column1->colpos; int endpos = 20 + 30 * column2->colpos; // In compressed mode, we display the src and dst port inside the arrow // so fixup the stard and end position if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { startpos += 5; endpos -= 5; } int distance = abs(endpos - startpos) - 4 + 1; // Highlight current message if (arrow == info->cur_arrow) { if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reverse")) { wattron(win, A_REVERSE); } if (setting_has_value(SETTING_CF_HIGHTLIGHT, "bold")) { wattron(win, A_BOLD); } if (setting_has_value(SETTING_CF_HIGHTLIGHT, "reversebold")) { wattron(win, A_REVERSE); wattron(win, A_BOLD); } } // Clear the line mvwprintw(win, cline, startpos + 2, "%*s", distance, ""); // Draw method mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, "%s", text); if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) cline++; // Draw line between columns mvwhline(win, cline, startpos + 2, '-', distance); // Write the arrow at the end of the message (two arrows if this is a retrans) if (arrow_dir == 0 /* right */) { if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { mvwprintw(win, cline, startpos - 4, "%d", stream->sport); mvwprintw(win, cline, endpos, "%d", stream->dport); } mvwaddch(win, cline, endpos - 2, '>'); if (arrow->rtp_count != stream_get_count(stream)) { arrow->rtp_count = stream_get_count(stream); arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; mvwaddch(win, cline, startpos + arrow->rtp_ind_pos + 2, '>'); } } else { if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { mvwprintw(win, cline, endpos, "%d", stream->sport); mvwprintw(win, cline, startpos - 4, "%d", stream->dport); } mvwaddch(win, cline, startpos + 2, '<'); if (arrow->rtp_count != stream_get_count(stream)) { arrow->rtp_count = stream_get_count(stream); arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; mvwaddch(win, cline, endpos - arrow->rtp_ind_pos - 2, '<'); } } if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, " %s ", text); wattroff(win, A_BOLD | A_REVERSE); // Print timestamp timeval_to_time(stream->time, time); mvwprintw(win, cline, 2, "%s", time); return arrow; } call_flow_arrow_t * call_flow_next_arrow(PANEL *panel, const call_flow_arrow_t *cur) { sip_msg_t *msg = NULL; rtp_stream_t *stream = NULL; struct timeval cur_time; call_flow_info_t *info; call_flow_arrow_t *next; // Get panel information info = call_flow_info(panel); // Return next arrow if already parsed if (cur && (next = vector_item(info->arrows, cur->index + 1))) return next; // Get current arrow timestamp if (!cur) { memset(&cur_time, 0, sizeof(struct timeval)); } else if (cur->type == CF_ARROW_SIP) { cur_time = msg_get_time(cur->msg); } else if (cur->type == CF_ARROW_RTP || cur->type == CF_ARROW_RTCP) { cur_time = cur->stream->time; } // Look for the next message while ((msg = call_group_get_next_msg(info->group, msg))) { if (timeval_is_older(msg_get_time(msg), cur_time)) { break; } } if (!setting_disabled(SETTING_CF_MEDIA)) { // Look for the next stream while ((stream = call_group_get_next_stream(info->group, stream))) { // Only handle RTCP when required if (!setting_has_value(SETTING_CF_MEDIA, "rtcp") && stream->type == CAPTURE_PACKET_RTCP) continue; if (timeval_is_older(stream->time, cur_time)) { break; } } } if (!msg && !stream) return NULL; /* Nothing goes next */ /* a rtp stream goes next */ if (!msg) { // Create a new arrow to store next info next = sng_malloc(sizeof(call_flow_arrow_t)); next->type = (stream->type == CAPTURE_PACKET_RTP) ? CF_ARROW_RTP : CF_ARROW_RTCP; next->stream = stream; } else if (!stream) { /* a sip message goes next */ // Create a new arrow to store next info next = sng_malloc(sizeof(call_flow_arrow_t)); next->type = CF_ARROW_SIP; next->msg = msg; } else { /* Determine what goes next */ if (timeval_is_older(msg_get_time(msg), stream->time)) { // Create a new arrow to store next info next = sng_malloc(sizeof(call_flow_arrow_t)); next->type = (stream->type == CAPTURE_PACKET_RTP) ? CF_ARROW_RTP : CF_ARROW_RTCP; next->stream = stream; } else { // Create a new arrow to store next info next = sng_malloc(sizeof(call_flow_arrow_t)); next->type = CF_ARROW_SIP; next->msg = msg; } } // Add this arrow to the list and return it next->index = vector_append(info->arrows, next); return next; } call_flow_arrow_t * call_flow_prev_arrow(PANEL *panel, const call_flow_arrow_t *cur) { call_flow_arrow_t *prev; call_flow_info_t *info; if (!cur) return NULL; // Get panel information if (!(info = call_flow_info(panel))) return NULL; if ((prev = vector_item(info->arrows, cur->index - 1))) return prev; return NULL; } int call_flow_arrow_height(PANEL *panel, const call_flow_arrow_t *arrow) { if (arrow->type == CF_ARROW_SIP) { if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) return 1; if (!msg_has_sdp(arrow->msg)) return 2; if (setting_has_value(SETTING_CF_SDP_INFO, "off")) return 2; if (setting_has_value(SETTING_CF_SDP_INFO, "first")) return 2; if (setting_has_value(SETTING_CF_SDP_INFO, "full")) return msg_media_count(arrow->msg) + 2; } else if (arrow->type == CF_ARROW_RTP || arrow->type == CF_ARROW_RTCP) { if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) return 1; return 2; } return 0; } call_flow_arrow_t * call_flow_arrow_find(PANEL *panel, const void *data) { call_flow_info_t *info; call_flow_arrow_t *arrow; vector_iter_t arrows; if (!data) return NULL; if (!(info = call_flow_info(panel))) return NULL; arrows = vector_iterator(info->arrows); while ((arrow = vector_iterator_next(&arrows))) if (arrow->msg == data || arrow->stream == data) return arrow; return arrow; } sip_msg_t * call_flow_arrow_message(const call_flow_arrow_t *arrow) { if (!arrow) return NULL; if (arrow->type == CF_ARROW_SIP) return arrow->msg; if (arrow->type == CF_ARROW_RTP || arrow->type == CF_ARROW_RTCP) return arrow->stream->media->msg; return NULL; } int call_flow_draw_raw(PANEL *panel, sip_msg_t *msg) { call_flow_info_t *info; WINDOW *win, *raw_win; int raw_width, raw_height, height, width; int min_raw_width, fixed_raw_width; // Get panel information if (!(info = call_flow_info(panel))) return 1; // Get window of main panel win = panel_window(panel); getmaxyx(win, height, width); // Get min raw width min_raw_width = setting_get_intvalue(SETTING_CF_RAWMINWIDTH); fixed_raw_width = setting_get_intvalue(SETTING_CF_RAWFIXEDWIDTH); // Calculate the raw data width (width - used columns for flow - vertical lines) raw_width = width - (30 * vector_count(info->columns)) - 2; // We can define a mininum size for rawminwidth if (raw_width < min_raw_width) { raw_width = min_raw_width; } // We can configure an exact raw size if (fixed_raw_width > 0) { raw_width = fixed_raw_width; } // Height of raw window is always available size minus 6 lines for header/footer raw_height = height - 3; // If we already have a raw window raw_win = info->raw_win; if (raw_win) { // Check it has the correct size if (getmaxx(raw_win) != raw_width) { // We need a new raw window delwin(raw_win); info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0); } else { // We have a valid raw win, clear its content werase(raw_win); } } else { // Create the raw window of required size info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0); } // Draw raw box lines wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); mvwvline(win, 1, width - raw_width - 2, ACS_VLINE, height - 2); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); // Print msg payload draw_message(info->raw_win, msg); // Copy the raw_win contents into the panel copywin(raw_win, win, 0, 0, 1, width - raw_width - 1, raw_height, width - 2, 0); return 0; } int call_flow_draw_raw_rtcp(PANEL *panel, rtp_stream_t *stream) { call_flow_info_t *info; WINDOW *win, *raw_win; int raw_width, raw_height, height, width; int min_raw_width, fixed_raw_width; // Get panel information if (!(info = call_flow_info(panel))) return 1; // Get window of main panel win = panel_window(panel); getmaxyx(win, height, width); // Get min raw width min_raw_width = setting_get_intvalue(SETTING_CF_RAWMINWIDTH); fixed_raw_width = setting_get_intvalue(SETTING_CF_RAWFIXEDWIDTH); // Calculate the raw data width (width - used columns for flow - vertical lines) raw_width = width - (30 * vector_count(info->columns)) - 2; // We can define a mininum size for rawminwidth if (raw_width < min_raw_width) { raw_width = min_raw_width; } // We can configure an exact raw size if (fixed_raw_width > 0) { raw_width = fixed_raw_width; } // Height of raw window is always available size minus 6 lines for header/footer raw_height = height - 3; // If we already have a raw window raw_win = info->raw_win; if (raw_win) { // Check it has the correct size if (getmaxx(raw_win) != raw_width) { // We need a new raw window delwin(raw_win); info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0); } else { // We have a valid raw win, clear its content werase(raw_win); } } else { // Create the raw window of required size info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0); } // Draw raw box lines wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); mvwvline(win, 1, width - raw_width - 2, ACS_VLINE, height - 2); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); mvwprintw(raw_win, 0, 0, "============ RTCP Information ============"); mvwprintw(raw_win, 2, 0, "Sender's packet count: %d", stream->rtcpinfo.spc); mvwprintw(raw_win, 3, 0, "Fraction Lost: %d / 256", stream->rtcpinfo.flost); mvwprintw(raw_win, 4, 0, "Fraction discarded: %d / 256", stream->rtcpinfo.fdiscard); mvwprintw(raw_win, 6, 0, "MOS - Listening Quality: %.1f", (float) stream->rtcpinfo.mosl / 10); mvwprintw(raw_win, 7, 0, "MOS - Conversational Quality: %.1f", (float) stream->rtcpinfo.mosc / 10); // Copy the raw_win contents into the panel copywin(raw_win, win, 0, 0, 1, width - raw_width - 1, raw_height, width - 2, 0); return 0; } int call_flow_handle_key(PANEL *panel, int key) { int i, raw_width, height, width; call_flow_info_t *info = call_flow_info(panel); call_flow_arrow_t *next, *prev; ui_t *next_panel; sip_call_t *call; int rnpag_steps = setting_get_intvalue(SETTING_CF_SCROLLSTEP); int action = -1; // Sanity check, this should not happen if (!info) return -1; getmaxyx(info->flow_win, height, width); // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch(action) { case ACTION_DOWN: // Check if there is a call below us if (!(next = call_flow_next_arrow(panel, info->cur_arrow))) break; info->cur_line += call_flow_arrow_height(panel, info->cur_arrow); // If we are out of the bottom of the displayed list // refresh it starting in the next call if (info->cur_line >= height) { info->cur_line -= call_flow_arrow_height(panel, info->first_arrow); info->first_arrow = call_flow_next_arrow(panel, info->first_arrow); } info->cur_arrow = next; break; case ACTION_UP: // Get previous message if (!(prev = call_flow_prev_arrow(panel, info->cur_arrow))) break; info->cur_line -= call_flow_arrow_height(panel, info->cur_arrow); info->cur_arrow = prev; if (info->cur_line <= 0) { info->cur_line += call_flow_arrow_height(panel, prev); info->first_arrow = prev; } break; case ACTION_HNPAGE: rnpag_steps = rnpag_steps / 2; /* no break */ case ACTION_NPAGE: // Next page => N key down strokes for (i = 0; i < rnpag_steps; i++) call_flow_handle_key(panel, KEY_DOWN); break; case ACTION_HPPAGE: rnpag_steps = rnpag_steps / 2; /* no break */ case ACTION_PPAGE: // Prev page => N key up strokes for (i = 0; i < rnpag_steps; i++) call_flow_handle_key(panel, KEY_UP); break; case ACTION_BEGIN: call_flow_set_group(info->group); break; case ACTION_END: call_flow_set_group(info->group); for (i=0; i < call_group_msg_count(info->group); i++) call_flow_handle_key(panel, KEY_DOWN); break; case ACTION_SHOW_FLOW_EX: werase(panel_window(panel)); if (call_group_count(info->group) == 1) { call_group_add(info->group, call_get_xcall(vector_first(info->group->calls))); } else { call = vector_first(info->group->calls); vector_clear(info->group->calls); call_group_add(info->group, call); } call_flow_set_group(info->group); break; case ACTION_SHOW_RAW: // KEY_R, display current call in raw mode ui_create_panel(PANEL_CALL_RAW); call_raw_set_group(info->group); break; case ACTION_DECREASE_RAW: raw_width = getmaxx(info->raw_win); if (raw_width - 2 > 1) { setting_set_intvalue(SETTING_CF_RAWFIXEDWIDTH, raw_width - 2); } break; case ACTION_INCREASE_RAW: raw_width = getmaxx(info->raw_win); if (raw_width + 2 < COLS - 1) { setting_set_intvalue(SETTING_CF_RAWFIXEDWIDTH, raw_width + 2); } break; case ACTION_RESET_RAW: setting_set_intvalue(SETTING_CF_RAWFIXEDWIDTH, -1); break; case ACTION_ONLY_SDP: // Toggle SDP mode info->group->sdp_only = !(info->group->sdp_only); // Disable sdp_only if there are not messages with sdp if (call_group_msg_count(info->group) == 0) info->group->sdp_only = 0; // Reset screen call_flow_set_group(info->group); break; case ACTION_SDP_INFO: setting_toggle(SETTING_CF_SDP_INFO); break; case ACTION_TOGGLE_MEDIA: setting_toggle(SETTING_CF_MEDIA); // Force reload arrows call_flow_set_group(info->group); break; case ACTION_TOGGLE_RAW: setting_toggle(SETTING_CF_FORCERAW); break; case ACTION_COMPRESS: setting_toggle(SETTING_CF_SPLITCALLID); // Force columns reload call_flow_set_group(info->group); break; case ACTION_SELECT: if (!info->selected) { info->selected = info->cur_arrow; } else { if (info->selected == info->cur_arrow) { info->selected = NULL; } else { // Show diff panel next_panel = ui_create_panel(PANEL_MSG_DIFF); msg_diff_set_msgs(ui_get_panel(next_panel), call_flow_arrow_message(info->selected), call_flow_arrow_message(info->cur_arrow)); } } break; case ACTION_CONFIRM: // KEY_ENTER, display current message in raw mode ui_create_panel(PANEL_CALL_RAW); call_raw_set_group(info->group); call_raw_set_msg(call_flow_arrow_message(info->cur_arrow)); break; default: // Parse next action continue; } // We've handled this key, stop checking actions break; } // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } int call_flow_help(PANEL *panel) { WINDOW *help_win; int height, width; // Create a new panel and show centered height = 27; width = 65; help_win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); // Set the window title mvwprintw(help_win, 1, 18, "Call Flow Help"); // Write border and boxes around the window wattron(help_win, COLOR_PAIR(CP_BLUE_ON_DEF)); box(help_win, 0, 0); mvwhline(help_win, 2, 1, ACS_HLINE, 63); mvwhline(help_win, 7, 1, ACS_HLINE, 63); mvwhline(help_win, height - 3, 1, ACS_HLINE, 63); mvwaddch(help_win, 2, 0, ACS_LTEE); mvwaddch(help_win, 7, 0, ACS_LTEE); mvwaddch(help_win, height - 3, 0, ACS_LTEE); mvwaddch(help_win, 2, 64, ACS_RTEE); mvwaddch(help_win, 7, 64, ACS_RTEE); mvwaddch(help_win, height - 3, 64, ACS_RTEE); // Set the window footer (nice blue?) mvwprintw(help_win, height - 2, 20, "Press any key to continue"); // Some brief explanation abotu what window shows wattron(help_win, COLOR_PAIR(CP_CYAN_ON_DEF)); mvwprintw(help_win, 3, 2, "This window shows the messages from a call and its relative"); mvwprintw(help_win, 4, 2, "ordered by sent or received time."); mvwprintw(help_win, 5, 2, "This panel is mosly used when capturing at proxy systems that"); mvwprintw(help_win, 6, 2, "manages incoming and outgoing request between calls."); wattroff(help_win, COLOR_PAIR(CP_CYAN_ON_DEF)); // A list of available keys in this window mvwprintw(help_win, 8, 2, "Available keys:"); mvwprintw(help_win, 9, 2, "Esc/Q Go back to Call list window"); mvwprintw(help_win, 10, 2, "Enter Show current message Raw"); mvwprintw(help_win, 11, 2, "F1/h Show this screen"); mvwprintw(help_win, 12, 2, "F2/d Toggle SDP Address:Port info"); mvwprintw(help_win, 13, 2, "F3/m Toggle RTP arrows display"); mvwprintw(help_win, 14, 2, "F4/X Show call-flow with X-CID/X-Call-ID dialog"); mvwprintw(help_win, 15, 2, "F5/s Toggle compressed view (One address <=> one column"); mvwprintw(help_win, 16, 2, "F6/R Show original call messages in raw mode"); mvwprintw(help_win, 17, 2, "F7/c Cycle between available color modes"); mvwprintw(help_win, 18, 2, "F8/C Turn on/off message syntax highlighting"); mvwprintw(help_win, 19, 2, "F9/l Turn on/off resolved addresses"); mvwprintw(help_win, 20, 2, "9/0 Increase/Decrease raw preview size"); mvwprintw(help_win, 21, 2, "t Toggle raw preview display"); mvwprintw(help_win, 22, 2, "T Restore raw preview size"); mvwprintw(help_win, 23, 2, "D Only show SDP messages"); // Press any key to close wgetch(help_win); return 0; } int call_flow_set_group(sip_call_group_t *group) { PANEL *panel; call_flow_info_t *info; if (!(panel = ui_get_panel(ui_find_by_type(PANEL_CALL_FLOW)))) return -1; if (!(info = call_flow_info(panel))) return -1; vector_clear(info->columns); vector_clear(info->arrows); info->group = group; info->cur_arrow = info->first_arrow = info->selected = call_flow_next_arrow(panel, NULL); info->cur_line = 1; info->selected = NULL; info->last_msg = NULL; return 0; } void call_flow_column_add(PANEL *panel, const char *callid, const char *address) { call_flow_info_t *info; call_flow_column_t *column; vector_iter_t columns; char addr[ADDRESSLEN + 6]; if (!(info = call_flow_info(panel))) return; if (!address || !strlen(address)) return; // Coppy address to local var strcpy(addr, address); // when compressed view is enabled if (setting_enabled(SETTING_CF_SPLITCALLID)) { // Remove the port from the address sip_address_strip_port(addr); // Display the alias value of the address strcpy(addr, get_alias_value(addr)); } if (call_flow_column_get(panel, callid, addr)) return; columns = vector_iterator(info->columns); while ((column = vector_iterator_next(&columns))) { if (!strcasecmp(addr, column->addr) && column->colpos != 0 && !column->callid2) { column->callid2 = callid; return; } } column = sng_malloc(sizeof(call_flow_column_t)); column->callid = callid; strcpy(column->addr, addr); column->colpos = vector_count(info->columns); vector_append(info->columns, column); } call_flow_column_t * call_flow_column_get(PANEL *panel, const char *callid, const char *address) { call_flow_info_t *info; call_flow_column_t *column; vector_iter_t columns; int match_port; char coladdr[ADDRESSLEN + 6]; char addr[ADDRESSLEN + 6]; char *dots; if (!(info = call_flow_info(panel))) return NULL; // Coppy address to local var strcpy(addr, address); // when compressed view is enabled if (setting_enabled(SETTING_CF_SPLITCALLID)) { // Remove the port from the address sip_address_strip_port(addr); // Display the alias value of the address strcpy(addr, get_alias_value(addr)); } // Look for address or address:port ? match_port = (strchr(addr, ':') != NULL); columns = vector_iterator(info->columns); while ((column = vector_iterator_next(&columns))) { // Copy address:port column label strcpy(coladdr, column->addr); // Remove port if we want to match only address if (!match_port && (dots = strchr(coladdr, ':'))) *dots = '\0'; if (!strcasecmp(addr, coladdr)) { if (!match_port) return column; if (setting_enabled(SETTING_CF_SPLITCALLID)) return column; if (column->callid && !strcasecmp(callid, column->callid)) return column; if (column->callid2 && !strcasecmp(callid, column->callid2)) return column; } } return NULL; } sngrep-1.2.0/src/keybinding.h0000644000175000017500000001323412632250522015127 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013-2015 Ivan Alonso (Kaian) ** Copyright (C) 2013-2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file option.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage keybindings * * sngrep keybindings are associated with actions. Each action can store multiple * keybindings. * Keybindings configured by user using *key* directive of sngreprc file, * in the format: * * key ui_action keycode * * keycode must be a letter (lowercase or uppercase) or a ^ sign with an uppercase * letter when Ctrl modifier is used. * */ #ifndef __SNGREP_KEYBINDING_H_ #define __SNGREP_KEYBINDING_H_ //! Number of keybindings per action #define MAX_BINDINGS 5 //! Some undefined key codes #define KEY_CTRL(n) ((n)-64) #define KEY_ESC 27 #define KEY_INTRO 10 #define KEY_TAB 9 #define KEY_BACKSPACE2 8 #define KEY_BACKSPACE3 127 #define KEY_SPACE ' ' /** * @brief Available Key actions */ enum key_actions { ACTION_PRINTABLE = 0, ACTION_UP, ACTION_DOWN, ACTION_LEFT, ACTION_RIGHT, ACTION_DELETE, ACTION_BACKSPACE, ACTION_NPAGE, ACTION_PPAGE, ACTION_HNPAGE, ACTION_HPPAGE, ACTION_BEGIN, ACTION_END, ACTION_PREV_FIELD, ACTION_NEXT_FIELD, ACTION_RESIZE_SCREEN, ACTION_CLEAR, ACTION_CLEAR_CALLS, ACTION_TOGGLE_SYNTAX, ACTION_CYCLE_COLOR, ACTION_SHOW_HOSTNAMES, ACTION_SHOW_ALIAS, ACTION_TOGGLE_PAUSE, ACTION_PREV_SCREEN, ACTION_SHOW_HELP, ACTION_SHOW_RAW, ACTION_SHOW_FLOW, ACTION_SHOW_FLOW_EX, ACTION_SHOW_FILTERS, ACTION_SHOW_COLUMNS, ACTION_SHOW_SETTINGS, ACTION_SHOW_STATS, ACTION_COLUMN_MOVE_UP, ACTION_COLUMN_MOVE_DOWN, ACTION_DISP_FILTER, ACTION_SAVE, ACTION_SELECT, ACTION_CONFIRM, ACTION_TOGGLE_MEDIA, ACTION_TOGGLE_RAW, ACTION_INCREASE_RAW, ACTION_DECREASE_RAW, ACTION_RESET_RAW, ACTION_ONLY_SDP, ACTION_SDP_INFO, ACTION_COMPRESS, ACTION_TOGGLE_HINT, ACTION_AUTOSCROLL, ACTION_SENTINEL }; //! Shorter declaration of key_binding structure typedef struct key_binding key_binding_t; /** * @brief Struct to hold a keybinding data */ struct key_binding { //! Keybinding action id int id; //! Keybinding action name const char *name; //! keybindings for this action int keys[MAX_BINDINGS]; //! How many keys are binded to this action int bindcnt; }; /** * @brief Print configured keybindigs */ void key_bindings_dump(); /** * @brief Return Keybinding data for a given action * @return key_binding_t structure pointer or NULL if not found */ key_binding_t * key_binding_data(int action); /** * @brief Bind a key to an action * * @param action One action defined in @key_actions * @param key Keycode returned by getch */ void key_bind_action(int action, int key); /** * @brief Unbind a key to an action * * @param action One action defined in @key_actions * @param key Keycode returned by getch */ void key_unbind_action(int action, int key); /** * @brief Find the next action for a given key * * Set start parameter to -1 for start searching the * first action. * * @param action One action defined in @key_actions * @param key Keycode returned by getch */ int key_find_action(int key, int start); /** * @brief Return the action id associate to an action str * * This function is used to translate keybindings configuration * found in sngreprc file to internal Action IDs * * @param action Configuration string for an action * @return action id from @key_actions or -1 if none found */ int key_action_id(const char *action); /** * @brief Check if key is a printable ascii character * * @return 1 if key is alphanumeric or space */ int key_is_printable(int key); /** * @brief Return a Human readable representation of a key * * @return Character string representing the key */ const char * key_to_str(int key); /** * @brief Parse Human key declaration to curses key * * This function is used to translate keybindings configuration * keys found in sngreprc file into internal ncurses keycodes * * @return ncurses keycode for the given key string */ int key_from_str(const char *key); /** * @brief Return Human readable key for an action * * This function is used to display keybindings in the bottom bar * of panels. Depending on sngrep configuration it will display the * first associated keybding with the action or the second one * (aka alternative). * * @param action One action defined in @key_actions * @return Main/Alt keybinding for the given action */ const char * key_action_key_str(int action); /** * @brief Return key value for a given action * * @param action One action defined in @key_actions * @return Main/Alt keybinding for the given action */ int key_action_key(int action); #endif /* __SNGREP_KEYBINDING_H_ */ sngrep-1.2.0/src/keybinding.c0000644000175000017500000002113712632250522015123 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013-2015 Ivan Alonso (Kaian) ** Copyright (C) 2013-2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file group.c * @author Ivan Alonso [aka Kaian] * * @brief Source code of functions defined in keybinding.h * */ #include "config.h" #include #include #include #include "ui_manager.h" #include "setting.h" #include "keybinding.h" //! sngrep keybindings key_binding_t bindings[ACTION_SENTINEL] = { { ACTION_PRINTABLE, "", { }, 0 }, { ACTION_UP, "up", { KEY_UP, 'j' }, 2 }, { ACTION_DOWN, "down", { KEY_DOWN, 'k' }, 2 }, { ACTION_LEFT, "left", { KEY_LEFT, 'h' }, 2 }, { ACTION_RIGHT, "right", { KEY_RIGHT, 'l'}, 2 }, { ACTION_DELETE, "delete", { KEY_DC }, 1 }, { ACTION_BACKSPACE, "backspace", { KEY_BACKSPACE, KEY_BACKSPACE2, KEY_BACKSPACE3 }, 3 }, { ACTION_NPAGE, "npage", { KEY_NPAGE, KEY_CTRL('F') }, 2 }, { ACTION_PPAGE, "ppage", { KEY_PPAGE, KEY_CTRL('B') }, 2 }, { ACTION_HNPAGE, "hnpage", { KEY_CTRL('D') }, 1 }, { ACTION_HPPAGE, "hppage", { KEY_CTRL('U') }, 2 }, { ACTION_BEGIN, "begin", { KEY_HOME, KEY_CTRL('A') }, 2 }, { ACTION_END, "end", { KEY_END, KEY_CTRL('E') }, 2 }, { ACTION_PREV_FIELD, "pfield", { KEY_UP }, 1 }, { ACTION_NEXT_FIELD, "nfield", { KEY_DOWN, KEY_TAB }, 2 }, { ACTION_RESIZE_SCREEN, "", { KEY_RESIZE }, 1 }, { ACTION_CLEAR, "clear", { KEY_CTRL('U'), KEY_CTRL('W')}, 2 }, { ACTION_CLEAR_CALLS, "clearcalls", { KEY_F(5) }, 1 }, { ACTION_TOGGLE_SYNTAX, "togglesyntax", { KEY_F(8), 'C' }, 2 }, { ACTION_CYCLE_COLOR, "colormode", { 'c' }, 1 }, { ACTION_SHOW_HOSTNAMES, "togglehostname", { KEY_F(9) }, 1 }, { ACTION_SHOW_ALIAS, "togglealias", { 'a' }, 1 }, { ACTION_TOGGLE_PAUSE, "pause", { 'p' }, 1 }, { ACTION_PREV_SCREEN, "prevscreen", { KEY_ESC, 'q', 'Q' }, 3 }, { ACTION_SHOW_HELP, "help", { KEY_F(1), 'h', 'H', '?' }, 4 }, { ACTION_SHOW_RAW, "raw", { KEY_F(6), 'R', 'r' }, 3 }, { ACTION_SHOW_FLOW, "flow", { KEY_INTRO }, 1 }, { ACTION_SHOW_FLOW_EX, "flowex", { KEY_F(4), 'x', 'X' }, 3 }, { ACTION_SHOW_FILTERS, "filters", { KEY_F(7), 'f', 'F' }, 3 }, { ACTION_SHOW_COLUMNS, "columns", { KEY_F(10), 't', 'T' }, 3 }, { ACTION_SHOW_SETTINGS, "settings", { KEY_F(8), 'o', 'O' }, 3 }, { ACTION_SHOW_STATS, "stats", { 'i' }, 1 }, { ACTION_COLUMN_MOVE_UP, "columnup", { '-' }, 1 }, { ACTION_COLUMN_MOVE_DOWN, "columndown", { '+' }, 1 }, { ACTION_DISP_FILTER, "search", { KEY_F(3), '/', KEY_TAB }, 3 }, { ACTION_SAVE, "save", { KEY_F(2), 's', 'S'}, 3 }, { ACTION_SELECT, "select", { KEY_SPACE }, 1 }, { ACTION_CONFIRM, "confirm", { KEY_INTRO }, 1 }, { ACTION_TOGGLE_MEDIA, "togglemedia", { KEY_F(3), 'm' }, 2 }, { ACTION_TOGGLE_RAW, "rawpreview", { 't' }, 1 }, { ACTION_INCREASE_RAW, "morerawpreview", { '9' }, 1 }, { ACTION_DECREASE_RAW, "lessrawpreview", { '0' }, 1 }, { ACTION_RESET_RAW, "resetrawpreview", { 'T' }, 1 }, { ACTION_ONLY_SDP, "onlysdp", { 'D' }, 1 }, { ACTION_SDP_INFO, "sdpinfo", { KEY_F(2), 'd' }, 2 }, { ACTION_COMPRESS, "compress", { 's' }, 1 }, { ACTION_AUTOSCROLL, "autoscroll", { 'A' }, 1 }, { ACTION_TOGGLE_HINT, "hintalt", { 'K' }, 1 }, }; void key_bindings_dump() { int i, j; for (i = 1; i < ACTION_SENTINEL; i++) { for (j = 0; j < bindings[i].bindcnt; j++) { printf("ActionID: %d\t ActionName: %-21s Key: %d (%s)\n", bindings[i].id, bindings[i].name, bindings[i].keys[j], key_to_str(bindings[i].keys[j])); } } } key_binding_t * key_binding_data(int action) { int i; for (i = 1; i < ACTION_SENTINEL; i++) { if (bindings[i].id == action) return &bindings[i]; } return NULL; } void key_bind_action(int action, int key) { key_binding_t *bind; if (!(bind = key_binding_data(action))) return; if (bind->bindcnt == MAX_BINDINGS) return; bind->keys[bind->bindcnt++] = key; } void key_unbind_action(int action, int key) { key_binding_t tmp, *bind; int i; // Action is not valid if (!(bind = key_binding_data(action))) return; // Copy binding to temporal struct memcpy(&tmp, bind, sizeof(key_binding_t)); // Reset bindings for this action memset(&bind->keys, 0, sizeof(int) * MAX_BINDINGS); // Add all bindings but the unbinded for (i=0; i < tmp.bindcnt; i++) { if (tmp.keys[i] != key) { key_bind_action(action, tmp.keys[i]); } } } int key_find_action(int key, int start) { int i, j; for (i = start + 1; i < ACTION_SENTINEL; i++) { if (i == ACTION_PRINTABLE && key_is_printable(key)) return ACTION_PRINTABLE; for (j = 0; j < bindings[i].bindcnt; j++) if (bindings[i].keys[j] == key) return bindings[i].id; } return -1; } int key_action_id(const char *action) { int i; for (i = 1; i < ACTION_SENTINEL; i++) { if (!strcasecmp(action, bindings[i].name)) return bindings[i].id; } return -1; } int key_is_printable(int key) { return key == ' ' || (key > 33 && key < 126) || (key > 160 && key < 255); } const char * key_to_str(int key) { //! Check function keys and Special keys switch(key) { case KEY_F(1): return "F1"; case KEY_F(2): return "F2"; case KEY_F(3): return "F3"; case KEY_F(4): return "F4"; case KEY_F(5): return "F5"; case KEY_F(6): return "F6"; case KEY_F(7): return "F7"; case KEY_F(8): return "F8"; case KEY_F(9): return "F9"; case KEY_F(10): return "F10"; case KEY_ESC: return "Esc"; case KEY_INTRO: return "Enter"; case ' ': return "Space"; default: if (key_is_printable(key)) return keyname(key); } return ""; } int key_from_str(const char *key) { if (!key) return 0; // Single character string if (strlen(key) == 1) return *key; // Function keys if (*key == 'F') return KEY_F(atoi(key+1)); // Control Secuences if (*key == '^') return KEY_CTRL(toupper(*(key+1))); if (!strncasecmp(key, "Ctrl-", 5)) return KEY_CTRL(toupper(*(key+5))); // Special Name characters if (!strcasecmp(key, "Esc")) return KEY_ESC; if (!strcasecmp(key, "Space")) return ' '; if (!strcasecmp(key, "Enter")) return KEY_INTRO; return 0; } const char * key_action_key_str(int action) { key_binding_t *bind; if (!(bind = key_binding_data(action))) return NULL; if (setting_enabled(SETTING_ALTKEY_HINT) && bind->bindcnt > 1) { // First alt keybinding return key_to_str(bind->keys[1]); } else { // Default keybinding return key_to_str(bind->keys[0]); } } int key_action_key(int action) { key_binding_t *bind; if (!(bind = key_binding_data(action))) return -1; if (setting_enabled(SETTING_ALTKEY_HINT) && bind->bindcnt > 1) { // First alt keybinding return bind->keys[1]; } else { // Default keybinding return bind->keys[0]; } return -1; } sngrep-1.2.0/src/media.h0000644000175000017500000000536612632250522014072 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013-2015 Ivan Alonso (Kaian) ** Copyright (C) 2013-2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file media.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage call media * */ #ifndef __SNGREP_MEDIA_H_ #define __SNGREP_MEDIA_H_ #include "config.h" #include #include "capture.h" //! Shorter declaration of sdp_media structure typedef struct sdp_media sdp_media_t; //! Shorter declaration of sdp_media_fmt structure typedef struct sdp_media_fmt sdp_media_fmt_t; struct sip_msg; struct sip_call; struct sdp_media_fmt { u_int id; char format[50]; }; struct sdp_media { //! SDP Addresses information char address[ADDRESSLEN]; u_short port; char type[10]; u_int fmtcode; //! List of described formats in this media vector_t *formats; //! Message with this SDP content struct sip_msg *msg; }; /** * @brief Allocate memory for a new media structure * * Create a structure for a new message sdp connection data. * * @param msg SIP Message pointer owner of this media * @return new allocated structure */ sdp_media_t * media_create(struct sip_msg *msg); /** * @brief Vector destroyer for media items */ void media_destroyer(void *item); void media_set_port(sdp_media_t *media, u_short port); void media_set_type(sdp_media_t *media, const char *type); void media_set_address(sdp_media_t *media, const char *address); void media_set_prefered_format(sdp_media_t *media, u_int code); void media_add_format(sdp_media_t *media, u_int code, const char *format); const char * media_get_address(sdp_media_t *media); u_short media_get_port(sdp_media_t *media); const char * media_get_type(sdp_media_t *media); const char * media_get_format(sdp_media_t *media, u_int code); const char * media_get_prefered_format(sdp_media_t *media); int media_get_format_code(sdp_media_t *media); #endif /* __SNGREP_MEDIA_H_ */ sngrep-1.2.0/src/sip_msg.c0000644000175000017500000001121612632250522014436 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip_msg.c * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP call data * * This file contains the functions and structure to manage SIP message data * */ #include "sip_msg.h" #include "media.h" #include "sip.h" sip_msg_t * msg_create(const char *payload) { sip_msg_t *msg; if (!(msg = sng_malloc(sizeof(sip_msg_t)))) return NULL; return msg; } void msg_destroy(sip_msg_t *msg) { // Free message SDP media vector_destroy(msg->medias); // Free message packets capture_packet_destroy(msg->packet); // Free all memory sng_free(msg->sip_from); sng_free(msg->sip_to); sng_free(msg); } void msg_destroyer(void *msg) { msg_destroy((sip_msg_t *)msg); } struct sip_call * msg_get_call(const sip_msg_t *msg) { return msg->call; } int msg_media_count(sip_msg_t *msg) { return vector_count(msg->medias); } int msg_has_sdp(void *item) { return vector_count(((sip_msg_t *)item)->medias) ? 1 : 0; } int msg_is_request(sip_msg_t *msg) { return msg->reqresp < 100; } void msg_add_media(sip_msg_t *msg, sdp_media_t *media) { if (!msg->medias) { // Create a vector to store sdp msg->medias = vector_create(2, 2); vector_set_destroyer(msg->medias, media_destroyer); } vector_append(msg->medias, media); } const char * msg_get_payload(sip_msg_t *msg) { return (const char *) capture_packet_get_payload(msg->packet); } struct timeval msg_get_time(sip_msg_t *msg) { struct timeval t = { }; capture_frame_t *frame; if (msg && (frame = vector_first(msg->packet->frames))) return frame->header->ts; return t; } const char * msg_get_attribute(sip_msg_t *msg, int id, char *value) { sdp_media_t *media; char *ar; switch (id) { case SIP_ATTR_SRC: sprintf(value, "%s:%u", msg->packet->ip_src, msg->packet->sport); break; case SIP_ATTR_DST: sprintf(value, "%s:%u", msg->packet->ip_dst, msg->packet->dport); break; case SIP_ATTR_METHOD: if (sip_method_str(msg->reqresp)) { sprintf(value, "%s", sip_method_str(msg->reqresp)); } else { sip_get_response_str(msg, value); } break; case SIP_ATTR_SIPFROM: sprintf(value, "%s", msg->sip_from); break; case SIP_ATTR_SIPTO: sprintf(value, "%s", msg->sip_to); break; case SIP_ATTR_SIPFROMUSER: sprintf(value, "%s", msg->sip_from); if ((ar = strchr(value, '@'))) *ar = '\0'; break; case SIP_ATTR_SIPTOUSER: sprintf(value, "%s", msg->sip_to); if ((ar = strchr(value, '@'))) *ar = '\0'; break; case SIP_ATTR_DATE: timeval_to_date(msg_get_time(msg), value); break; case SIP_ATTR_TIME: timeval_to_time(msg_get_time(msg), value); break; case SIP_ATTR_SDP_ADDRESS: if ((media = vector_first(msg->medias))) sprintf(value, "%s", media_get_address(media)); break; case SIP_ATTR_SDP_PORT: if ((media = vector_first(msg->medias))) sprintf(value, "%d", media_get_port(media)); break; default: fprintf(stderr, "Unhandled attribute %s (%d)\n", sip_attr_get_name(id), id); abort(); break; } return strlen(value) ? value : NULL; } int msg_is_older(sip_msg_t *one, sip_msg_t *two) { // Yes, you are older than nothing if (!two) return 1; // Otherwise return timeval_is_older(msg_get_time(one), msg_get_time(two)); } sngrep-1.2.0/src/sip_call.h0000644000175000017500000001405712632250522014576 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip_call.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage sip calls * */ #ifndef __SNGREP_SIP_CALL_H #define __SNGREP_SIP_CALL_H #include "config.h" #include #include "vector.h" #include "rtp.h" #include "sip_msg.h" #include "sip_attr.h" //! Shorter declaration of sip_call structure typedef struct sip_call sip_call_t; //! SIP Call State enum call_state { SIP_CALLSTATE_CALLSETUP = 1, SIP_CALLSTATE_INCALL, SIP_CALLSTATE_CANCELLED, SIP_CALLSTATE_REJECTED, SIP_CALLSTATE_COMPLETED }; /** * @brief Contains all information of a call and its messages * * This structure acts as header of messages list of the same * callid (considered a dialog). It contains some replicated * data from its messages to speed up searches. */ struct sip_call { // Call index in the call list int index; // Call identifier char *callid; //! Related Call identifier char *xcallid; //! Flag this call as filtered so won't be displayed signed char filtered; //! Call State. For dialogs starting with an INVITE method int state; //! List of messages of this call (sip_msg_t*) vector_t *msgs; //! Message when conversation started and ended sip_msg_t *cstart_msg, *cend_msg; //! RTP streams for this call (rtp_stream_t *) vector_t *streams; //! RTP packets for this call (capture_packet_t *) vector_t *rtp_packets; }; /** * @brief Create a new call with the given callid (Minimum required data) * * Allocated required memory for a new SIP Call. The call acts as * header structure to all the messages with the same callid. * * @param callid Call-ID Header value * @param xcallid X-Call-ID Header value * @return pointer to the sip_call created */ sip_call_t * call_create(char *callid, char *xcallid); /** * @brief Free all related memory from a call and remove from call list * * Deallocate memory of an existing SIP Call. * This will also remove all messages, calling sip_msg_destroy for each * one. * * @param call Call to be destroyed */ void call_destroy(sip_call_t *call); /** * @brief Wrapper around Message destroyer to clear call vectors */ void call_destroyer(void *call); /** * @brief Append message to the call's message list * * Creates a relation between this call and the message, appending it * to the end of the message list and setting the message owner. * * @param call pointer to the call owner of the message * @param msg SIP message structure */ void call_add_message(sip_call_t *call, sip_msg_t *msg); /** * @brief Append a new RTP stream to the call * * Add a new stream to be monitored * * @param call pointer to the call owner of the stream * @param stream RTP stream data */ void call_add_stream(sip_call_t *call, rtp_stream_t *stream); /** * @brief Append a new RTP packet to the call * * @param call pointer to the call owner of the stream * @param packet new RTP packet from call rtp streams */ void call_add_rtp_packet(sip_call_t *call, capture_packet_t *packet); /** * @brief Getter for call messages linked list size * * Return the number of messages stored in this call. All messages * share the same Call-ID * * @param call SIP call structure * @return how many messages are in the call */ int call_msg_count(sip_call_t *call); /** * @brief Finds the other leg of this call. * * If this call has a X-CID or X-Call-ID header, that call will be * find and returned. Otherwise, a call with X-CID or X-Call-ID header * matching the given call's Call-ID will be find or returned. * * @param call SIP call structure * @return The other call structure or NULL if none found */ sip_call_t * call_get_xcall(sip_call_t *call); /** * @brief Determine if a dilog is a call in progress * * @param call SIP call structure * @return 1 if the passed call state is active, 0 otherwise */ int call_is_active(sip_call_t *call); /** * @brief Determine if this call starts with an Invite request * * @param call SIP call structure * @return 1 if first call message has method INVITE, 0 otherwise */ int call_is_invite(sip_call_t *call); /** * @brief Check if a message is a retransmission * * This function will compare its payload with the previous message * in the dialog, to check if it has the same content. * * @param msg SIP message that will be checked * @return 1 if the previous message is equal to msg, 0 otherwise */ int call_msg_is_retrans(sip_msg_t *msg); /** * @brief Update Call State attribute with its last parsed message * * @param call Call structure to be updated * @param msg Last received message of this call */ void call_update_state(sip_call_t *call, sip_msg_t *msg); /** * @brief Return a call attribute value * * This function will be used to avoid accessing call structure * fields directly. * * @param call SIP call structure * @param id Attribute id * @return Attribute value or NULL if not found */ const char * call_get_attribute(struct sip_call *call, enum sip_attr_id id, char *value); /** * @brief Return the string represtation of a call state * */ const char * call_state_to_str(int state); #endif /* __SNGREP_SIP_CALL_H */ sngrep-1.2.0/src/ui_call_list.c0000644000175000017500000006666512632250522015462 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_call_list.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_call_list.h * */ #include #include #include #include #include #include #include "option.h" #include "filter.h" #include "capture.h" #include "ui_manager.h" #include "ui_call_list.h" #include "ui_call_flow.h" #include "ui_call_raw.h" #include "ui_save.h" #include "sip.h" /** * Ui Structure definition for Call List panel */ ui_t ui_call_list = { .type = PANEL_CALL_LIST, .panel = NULL, .create = call_list_create, .destroy = call_list_destroy, .draw = call_list_draw, .resize = call_list_resize, .handle_key = call_list_handle_key, .help = call_list_help, }; PANEL * call_list_create() { PANEL *panel; WINDOW *win; int height, width, i, attrid, collen; call_list_info_t *info; char option[80]; const char *field, *title; // Create a new panel that fill all the screen panel = new_panel(newwin(LINES, COLS, 0, 0)); // Initialize Call List specific data info = sng_malloc(sizeof(call_list_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Add configured columns for (i = 0; i < SIP_ATTR_COUNT; i++) { // Get column attribute name from options sprintf(option, "cl.column%d", i); if ((field = get_option_value(option))) { if ((attrid = sip_attr_from_name(field)) == -1) continue; // Get column width from options sprintf(option, "cl.column%d.width", i); if ((collen = get_option_int_value(option)) == -1) collen = sip_attr_get_width(attrid); // Get column title title = sip_attr_get_title(attrid); // Add column to the list call_list_add_column(panel, attrid, field, title, collen); } } // Let's draw the fixed elements of the screen win = panel_window(panel); getmaxyx(win, height, width); // Initialize the fields info->fields[FLD_LIST_FILTER] = new_field(1, width - 19, 2, 18, 0, 0); info->fields[FLD_LIST_COUNT] = NULL; // Create the form and post it info->form = new_form(info->fields); set_form_sub(info->form, win); // Form starts inactive call_list_form_activate(panel, 0); // Calculate available printable area info->list_win = subwin(win, height - 5, width, 4, 0); info->group = call_group_create(); // Get current call list info->calls = sip_calls_iterator(); vector_iterator_set_filter(&info->calls, filter_check_call); info->cur_call = info->first_call = -1; // Set autoscroll default status info->autoscroll = setting_enabled(SETTING_CL_AUTOSCROLL); // Return the created panel return panel; } void call_list_destroy(PANEL *panel) { call_list_info_t *info; // Free its status data if ((info = call_list_info(panel))) { // Deallocate forms data if (info->form) { unpost_form(info->form); free_form(info->form); free_field(info->fields[FLD_LIST_FILTER]); } // Deallocate group data call_group_destroy(info->group); // Deallocate panel windows delwin(info->list_win); sng_free(info); } // Deallocate panel window delwin(panel_window(panel)); // Deallocate panel pointer del_panel(panel); } call_list_info_t * call_list_info(PANEL *panel) { return (call_list_info_t*) panel_userptr(panel); } int call_list_resize(PANEL *panel) { int maxx, maxy; // Get panel info call_list_info_t *info = call_list_info(panel); // Get current screen dimensions getmaxyx(stdscr, maxy, maxx); // Change the main window size wresize(panel_window(panel), maxy, maxx); // Calculate available printable area wresize(info->list_win, maxy - 5, maxx - 4); // Force list redraw call_list_clear(panel); return 0; } void call_list_draw_header(PANEL *panel) { const char *infile, *coldesc; int height, width, colpos, collen, i; // Get panel info call_list_info_t *info = call_list_info(panel); // Let's draw the fixed elements of the screen WINDOW *win = panel_window(panel); getmaxyx(win, height, width); // Draw panel title draw_title(panel, "sngrep - SIP messages flow viewer"); // Draw a Panel header lines clear_line(win, 1); if ((infile = capture_get_infile())) mvwprintw(win, 1, width - strlen(infile) - 11, "Filename: %s", infile); mvwprintw(win, 2, 2, "Display Filter: "); mvwprintw(win, 1, 2, "Current Mode: %s", capture_get_status_desc()); // Reverse colors on monochrome terminals if (!has_colors()) wattron(win, A_REVERSE); // Draw columns titles wattron(win, A_BOLD | COLOR_PAIR(CP_DEF_ON_CYAN)); mvwprintw(win, 3, 0, "%*s", width, ""); for (colpos = 6, i = 0; i < info->columncnt; i++) { // Get current column width collen = info->columns[i].width; // Get current column title coldesc = sip_attr_get_title(info->columns[i].id); // Check if the column will fit in the remaining space of the screen if (colpos + strlen(coldesc) >= width) break; mvwprintw(win, 3, colpos, "%.*s", collen, coldesc); colpos += collen + 1; } // Print Autoscroll indicator if (info->autoscroll) mvwprintw(win, 3, 0, "A"); wattroff(win, A_BOLD | A_REVERSE | COLOR_PAIR(CP_DEF_ON_CYAN)); // Get filter call counters sip_calls_stats(&info->callcnt, &info->dispcallcnt); // Print calls count (also filtered) mvwprintw(win, 1, 35, "%*s", 35, ""); if (info->callcnt != info->dispcallcnt) { mvwprintw(win, 1, 35, "Dialogs: %d (%d displayed)", info->callcnt, info->dispcallcnt); } else { mvwprintw(win, 1, 35, "Dialogs: %d", info->callcnt); } } void call_list_draw_footer(PANEL *panel) { const char *keybindings[] = { key_action_key_str(ACTION_PREV_SCREEN), "Quit", key_action_key_str(ACTION_SHOW_FLOW), "Show", key_action_key_str(ACTION_SELECT), "Select", key_action_key_str(ACTION_SHOW_HELP), "Help", key_action_key_str(ACTION_SAVE), "Save", key_action_key_str(ACTION_DISP_FILTER), "Search", key_action_key_str(ACTION_SHOW_FLOW_EX), "Extended", key_action_key_str(ACTION_CLEAR_CALLS), "Clear", key_action_key_str(ACTION_SHOW_FILTERS), "Filter", key_action_key_str(ACTION_SHOW_SETTINGS), "Settings", key_action_key_str(ACTION_SHOW_COLUMNS), "Columns" }; draw_keybindings(panel, keybindings, 22); } void call_list_draw_list(PANEL *panel) { WINDOW *win; int height, width, cline = 0; struct sip_call *call; int i, collen; char coltext[256]; int colid; int colpos; int color; // Get panel info call_list_info_t *info = call_list_info(panel); // Get window of call list panel win = info->list_win; getmaxyx(win, height, width); // If autoscroll is enabled, select the last dialog if (info->autoscroll) { call_list_handle_key(panel, key_action_key(ACTION_END)); } // If no active call, use the fist one (if exists) if (info->first_call == -1 && vector_iterator_count(&info->calls)) { vector_iterator_reset(&info->calls); call = vector_iterator_next(&info->calls); info->cur_call = info->first_call = vector_index(vector_iterator_vector(&info->calls), call); info->cur_line = info->first_line = 1; } // Clear call list before redrawing werase(win); // Set the iterator position to the first call vector_iterator_set_current(&info->calls, info->first_call - 1 ); // Fill the call list while ((call = vector_iterator_next(&info->calls))) { // Stop if we have reached the bottom of the list if (cline == height) break; // We only print calls with messages (In fact, all call should have msgs) if (!call_msg_count(call)) continue; // Show bold selected rows if (call_group_exists(info->group, call)) wattron(win, A_BOLD | COLOR_PAIR(CP_DEFAULT)); // Highlight active call if (call->index == info->cur_call + 1) { wattron(win, COLOR_PAIR(CP_WHITE_ON_BLUE)); // Reverse colors on monochrome terminals if (!has_colors()) wattron(win, A_REVERSE); } // Set current line background clear_line(win, cline); // Set current line selection box mvwprintw(win, cline, 2, call_group_exists(info->group, call) ? "[*]" : "[ ]"); // Print requested columns colpos = 6; for (i = 0; i < info->columncnt; i++) { // Get current column id colid = info->columns[i].id; // Get current column width collen = info->columns[i].width; // Check if next column fits on window width if (colpos + collen >= width) break; // Initialize column text memset(coltext, 0, sizeof(coltext)); // Get call attribute for current column if (!call_get_attribute(call, colid, coltext)) { colpos += collen + 1; continue; } // Enable attribute color (if not current one) color = 0; if (call->index != info->cur_call + 1 && (color = sip_attr_get_color(colid, coltext)) > 0) wattron(win, color); // Add the column text to the existing columns mvwprintw(win, cline, colpos, "%.*s", collen, coltext); colpos += collen + 1; // Disable attribute color if (color > 0) wattroff(win, color); } cline++; wattroff(win, COLOR_PAIR(CP_DEFAULT)); wattroff(win, COLOR_PAIR(CP_DEF_ON_BLUE)); wattroff(win, A_BOLD | A_REVERSE); } // Draw scrollbar to the right draw_vscrollbar(win, info->first_line, info->dispcallcnt, 1); wnoutrefresh(info->list_win); } int call_list_draw(PANEL *panel) { int cury, curx; // Store cursor position getyx(panel_window(panel), cury, curx); // Draw the header call_list_draw_header(panel); // Draw the footer call_list_draw_footer(panel); // Draw the list content call_list_draw_list(panel); // Restore cursor position wmove(panel_window(panel), cury, curx); return 0; } void call_list_form_activate(PANEL *panel, int active) { call_list_info_t *info = call_list_info(panel); // Store form state info->form_active = active; if (active) { set_current_field(info->form, info->fields[FLD_LIST_FILTER]); // Show cursor curs_set(1); // Change current field background set_field_back(info->fields[FLD_LIST_FILTER], A_REVERSE); } else { set_current_field(info->form, NULL); // Hide cursor curs_set(0); // Change current field background set_field_back(info->fields[FLD_LIST_FILTER], A_NORMAL); } post_form(info->form); form_driver(info->form, REQ_END_LINE); } const char * call_list_line_text(PANEL *panel, sip_call_t *call, char *text) { int i, collen; char call_attr[256]; char coltext[256]; int colid; int width; WINDOW *win = panel_window(panel); // Get window width width = getmaxx(win); // Get panel info call_list_info_t *info = call_list_info(panel); // Print requested columns for (i = 0; i < info->columncnt; i++) { // Get current column id colid = info->columns[i].id; // Get current column width collen = info->columns[i].width; // Check if next column fits on window width if (strlen(text) + collen >= width) collen = width - strlen(text); // If no space left on the screen stop processing columns if (collen <= 0) break; // Initialize column text memset(coltext, 0, sizeof(coltext)); memset(call_attr, 0, sizeof(call_attr)); // Get call attribute for current column if (call_get_attribute(call, colid, call_attr)) { sprintf(coltext, "%.*s", collen, call_attr); } // Add the column text to the existing columns sprintf(text + strlen(text), "%-*s ", collen, coltext); } return text; } int call_list_handle_key(PANEL *panel, int key) { int i, height, width, rnpag_steps = setting_get_intvalue(SETTING_CL_SCROLLSTEP); call_list_info_t *info; ui_t *next_panel; sip_call_group_t *group; int action = -1; sip_call_t *call; // Sanity check, this should not happen if (!(info = call_list_info(panel))) return -1; // Handle form key if (info->form_active) return call_list_handle_form_key(panel, key); // Get window of call list panel WINDOW *win = info->list_win; getmaxyx(win, height, width); // Reset iterator position to current call vector_iterator_set_current(&info->calls, info->cur_call); // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_DOWN: // Check if there is a call below us if (!vector_iterator_next(&info->calls)) break; info->cur_call = vector_iterator_current(&info->calls); info->cur_line++; // If we are out of the bottom of the displayed list // refresh it starting in the next call if (info->cur_line > height) { vector_iterator_set_current(&info->calls, info->first_call); vector_iterator_next(&info->calls); info->first_call = vector_iterator_current(&info->calls); info->first_line++; info->cur_line = height; } // Disable Autoscroll info->autoscroll = 0; break; case ACTION_UP: // Check if there is a call above us if (!vector_iterator_prev(&info->calls)) break; info->cur_call = vector_iterator_current(&info->calls); info->cur_line--; // If we are out of the top of the displayed list // refresh it starting in the previous (in fact current) call if (info->cur_line <= 0) { info->first_call = info->cur_call; info->first_line--; info->cur_line = 1; } // Disable Autoscroll info->autoscroll = 0; break; case ACTION_HNPAGE: rnpag_steps = rnpag_steps / 2; /* no break */ case ACTION_NPAGE: // Next page => N key down strokes for (i = 0; i < rnpag_steps; i++) call_list_handle_key(panel, KEY_DOWN); // Disable Autoscroll info->autoscroll = 0; break; case ACTION_HPPAGE: rnpag_steps = rnpag_steps / 2; /* no break */ case ACTION_PPAGE: // Prev page => N key up strokes for (i = 0; i < rnpag_steps; i++) call_list_handle_key(panel, KEY_UP); // Disable Autoscroll info->autoscroll = 0; break; case ACTION_BEGIN: // Initialize structures info->first_call = info->cur_call = -1; info->first_line = info->cur_line = 0; // Disable Autoscroll info->autoscroll = 0; break; case ACTION_END: // Check if there is a call below us while (vector_iterator_next(&info->calls)) { info->cur_call = vector_iterator_current(&info->calls); info->cur_line++; // If we are out of the bottom of the displayed list // refresh it starting in the next call if (info->cur_line > height) { vector_iterator_set_current(&info->calls, info->first_call); vector_iterator_next(&info->calls); info->first_call = vector_iterator_current(&info->calls); info->first_line++; info->cur_line = height; vector_iterator_set_current(&info->calls, info->cur_call); } } break; case ACTION_DISP_FILTER: // Activate Form call_list_form_activate(panel, 1); // Disable Autoscroll info->autoscroll = 0; break; case ACTION_SHOW_FLOW: case ACTION_SHOW_FLOW_EX: case ACTION_SHOW_RAW: // Check we have calls in the list if (info->cur_call == -1) break; // Create a new group of calls group = call_group_clone(info->group); // If not selected call, show current call flow if (call_group_count(info->group) == 0) call_group_add(group, sip_find_by_index(info->cur_call)); // Add xcall to the group if (action == ACTION_SHOW_FLOW_EX) call_group_add(group, call_get_xcall(sip_find_by_index(info->cur_call))); if (action == ACTION_SHOW_RAW) { // Create a Call Flow panel ui_create_panel(PANEL_CALL_RAW); call_raw_set_group(group); } else { // Display current call flow (normal or extended) ui_create_panel(PANEL_CALL_FLOW); call_flow_set_group(group); } break; case ACTION_SHOW_FILTERS: ui_create_panel(PANEL_FILTER); break; case ACTION_SHOW_COLUMNS: ui_create_panel(PANEL_COLUMN_SELECT); break; case ACTION_SHOW_STATS: ui_create_panel(PANEL_STATS); break; case ACTION_SAVE: next_panel = ui_create_panel(PANEL_SAVE); save_set_group(ui_get_panel(next_panel), info->group); break; case ACTION_CLEAR: // Clear group calls vector_clear(info->group->calls); break; case ACTION_CLEAR_CALLS: // Remove all stored calls sip_calls_clear(); // Clear List call_list_clear(panel); break; case ACTION_AUTOSCROLL: info->autoscroll = (info->autoscroll) ? 0 : 1; break; case ACTION_SHOW_SETTINGS: ui_create_panel(PANEL_SETTINGS); break; case ACTION_SELECT: call = vector_item(vector_iterator_vector(&info->calls), info->cur_call); if (call_group_exists(info->group, call)) { call_group_del(info->group, call); } else { call_group_add(info->group, call); } break; case ACTION_PREV_SCREEN: // Handle quit from this screen unless requested if (setting_enabled(SETTING_EXITPROMPT)) { if (dialog_confirm("Confirm exit", "Are you sure you want to quit?", "Yes,No") == 0) { return KEY_ESC; } else { return 0; } } else { return KEY_ESC; } break; default: // Parse next action continue; } // This panel has handled the key successfully break; } // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } int call_list_handle_form_key(PANEL *panel, int key) { int field_idx; char dfilter[256]; int action = -1; // Get panel information call_list_info_t *info = call_list_info(panel); // Get current field id field_idx = field_index(current_field(info->form)); // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_PRINTABLE: // If this is a normal character on input field, print it form_driver(info->form, key); break; case ACTION_PREV_SCREEN: case ACTION_NEXT_FIELD: case ACTION_CONFIRM: case ACTION_SELECT: case ACTION_UP: case ACTION_DOWN: // Activate list call_list_form_activate(panel, 0); break; case ACTION_RIGHT: form_driver(info->form, REQ_RIGHT_CHAR); break; case ACTION_LEFT: form_driver(info->form, REQ_LEFT_CHAR); break; case ACTION_BEGIN: form_driver(info->form, REQ_BEG_LINE); break; case ACTION_END: form_driver(info->form, REQ_END_LINE); break; case ACTION_CLEAR: form_driver(info->form, REQ_BEG_LINE); form_driver(info->form, REQ_CLR_EOL); break; case ACTION_DELETE: form_driver(info->form, REQ_DEL_CHAR); break; case ACTION_BACKSPACE: form_driver(info->form, REQ_DEL_PREV); break; default: // Parse next action continue; } // We've handled this key, stop checking actions break; } // Filter has changed, re-apply filter to displayed calls if (action == ACTION_PRINTABLE || action == ACTION_BACKSPACE || action == ACTION_DELETE || action == ACTION_CLEAR) { // Updated displayed results call_list_clear(panel); // Reset filters on each key stroke filter_reset_calls(); } // Validate all input data form_driver(info->form, REQ_VALIDATION); // Store dfilter input // We trim spaces with sscanf because and empty field is stored as space characters memset(dfilter, 0, sizeof(dfilter)); strcpy(dfilter, field_buffer(info->fields[FLD_LIST_FILTER], 0)); strtrim(dfilter); // Set display filter filter_set(FILTER_CALL_LIST, strlen(dfilter) ? dfilter : NULL); // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } int call_list_help(PANEL *panel) { WINDOW *help_win; int height, width; // Create a new panel and show centered height = 28; width = 65; help_win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); // Set the window title mvwprintw(help_win, 1, 25, "Call List Help"); // Write border and boxes around the window wattron(help_win, COLOR_PAIR(CP_BLUE_ON_DEF)); box(help_win, 0, 0); mvwhline(help_win, 2, 1, ACS_HLINE, width - 2); mvwhline(help_win, 7, 1, ACS_HLINE, width - 2); mvwhline(help_win, height - 3, 1, ACS_HLINE, width - 2); mvwaddch(help_win, 2, 0, ACS_LTEE); mvwaddch(help_win, 7, 0, ACS_LTEE); mvwaddch(help_win, height - 3, 0, ACS_LTEE); mvwaddch(help_win, 2, 64, ACS_RTEE); mvwaddch(help_win, 7, 64, ACS_RTEE); mvwaddch(help_win, height - 3, 64, ACS_RTEE); // Set the window footer (nice blue?) mvwprintw(help_win, height - 2, 20, "Press any key to continue"); // Some brief explanation abotu what window shows wattron(help_win, COLOR_PAIR(CP_CYAN_ON_DEF)); mvwprintw(help_win, 3, 2, "This windows show the list of parsed calls from a pcap file "); mvwprintw(help_win, 4, 2, "(Offline) or a live capture with libpcap functions (Online)."); mvwprintw(help_win, 5, 2, "You can configure the columns shown in this screen and some"); mvwprintw(help_win, 6, 2, "static filters using sngreprc resource file."); wattroff(help_win, COLOR_PAIR(CP_CYAN_ON_DEF)); // A list of available keys in this window mvwprintw(help_win, 8, 2, "Available keys:"); mvwprintw(help_win, 10, 2, "Esc/Q Exit sngrep."); mvwprintw(help_win, 11, 2, "Enter Show selected calls message flow"); mvwprintw(help_win, 12, 2, "Space Select call"); mvwprintw(help_win, 13, 2, "F1/h Show this screen"); mvwprintw(help_win, 14, 2, "F2/S Save captured packages to a file"); mvwprintw(help_win, 15, 2, "F3// Display filtering (match string case insensitive)"); mvwprintw(help_win, 16, 2, "F4/X Show selected call-flow (Extended) if available"); mvwprintw(help_win, 17, 2, "F5 Clear call list (can not be undone!)"); mvwprintw(help_win, 18, 2, "F6/R Show selected call messages in raw mode"); mvwprintw(help_win, 19, 2, "F7/F Show filter options"); mvwprintw(help_win, 20, 2, "F8/c Turn on/off window colours"); mvwprintw(help_win, 21, 2, "F9/l Turn on/off resolved addresses"); mvwprintw(help_win, 22, 2, "F10/t Select displayed columns"); mvwprintw(help_win, 23, 2, "i/I Set display filter to invite"); mvwprintw(help_win, 24, 2, "p Stop/Resume packet capture"); // Press any key to close wgetch(help_win); delwin(help_win); return 0; } int call_list_add_column(PANEL *panel, enum sip_attr_id id, const char* attr, const char *title, int width) { call_list_info_t *info; if (!(info = call_list_info(panel))) return 1; info->columns[info->columncnt].id = id; info->columns[info->columncnt].attr = attr; info->columns[info->columncnt].title = title; info->columns[info->columncnt].width = width; info->columncnt++; return 0; } void call_list_clear(PANEL *panel) { call_list_info_t *info; // Get panel info if (!(info = call_list_info(panel))) return; // Initialize structures info->first_call = info->cur_call = -1; info->first_line = info->cur_line = 0; vector_clear(info->group->calls); // Clear Displayed lines werase(info->list_win); } sngrep-1.2.0/src/ui_save.h0000644000175000017500000001152012632250522014433 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2014 Ivan Alonso (Kaian) ** Copyright (C) 2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_save_pcap.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage ui window for saving captured packages * * This file contains the functions and structures to manage the save * dialog, that can be used to copy the temporal sngrep file to another location * */ #ifndef __UI_SAVE_PCAP_H #define __UI_SAVE_PCAP_H #include "config.h" #include #include "group.h" #include "ui_manager.h" /** * @brief Enum of available dialog fields * * Dialog form has a field array. Following enum represents the * order this fields are stored in panel info structure. */ enum save_field_list { FLD_SAVE_PATH = 0, FLD_SAVE_FILE, FLD_SAVE_ALL, FLD_SAVE_SELECTED, FLD_SAVE_DISPLAYED, FLD_SAVE_PCAP, FLD_SAVE_PCAP_RTP, FLD_SAVE_TXT, FLD_SAVE_SAVE, FLD_SAVE_CANCEL, FLD_SAVE_COUNT }; /** * @brief Dialogs to be saved */ enum save_mode { SAVE_ALL = 0, SAVE_SELECTED, SAVE_DISPLAYED }; /** * @brief Save file formats */ enum save_format { SAVE_PCAP = 0, SAVE_PCAP_RTP, SAVE_TXT }; //! Sorter declaration of struct save_info typedef struct save_info save_info_t; /** * @brief Save panel private information * * This structure contains the durable data of save panel. */ struct save_info { //! Form that contains the save fields FORM *form; //! An array of fields FIELD *fields[FLD_SAVE_COUNT + 1]; //! Save mode @see save_modes enum save_mode savemode; //! Save format @see save_formats enum save_format saveformat; //! Call group to be saved sip_call_group_t *group; }; /** * @brief Creates a new save panel * * This function allocates all required memory for * displaying the save panel. It also draws all the * static information of the panel that will never be * redrawn. * * @return a panel pointer */ PANEL * save_create(); /** * @brief Destroy save panel * * This function do the final cleanups for this panel */ void save_destroy(); /** * @brief Get custom information of given panel * * Return ncurses users pointer of the given panel into panel's * information structure pointer. * * @param panel Ncurses panel pointer * @return a pointer to info structure of given panel */ save_info_t * save_info(PANEL *panel); /** * @brief Draw the Save panel * * This function will drawn the panel into the screen based on its stored * status * * @param panel Ncurses panel pointer * @return 0 if the panel has been drawn, -1 otherwise */ int save_draw(PANEL *panel); /** * @brief Manage pressed keys for save panel * * This function is called by UI manager every time a * key is pressed. This allow the save panel to manage * its own keys. * If this function return 0, the key will not be handled * by ui manager. Otherwise the return will be considered * a key code. * * @param panel Save panel pointer * @param key key code * @return 0 if the key is handled, keycode otherwise */ int save_handle_key(PANEL *panel, int key); /** * @brief Set the group call of the panel * * This function will access the panel information and will set the * group call pointer to the selected calls * * @param group Call group pointer to be set in the internal info struct */ void save_set_group(PANEL *panel, sip_call_group_t *group); /** * @brief Print an error message in Save panel * * General function to print any save error message * @param panel Save panel pointer * @param message Message to be printed in the panel */ void save_error_message(PANEL *panel, const char *message); /** * @brief Save form data to options * * This function will try to copy the temporal file to * another location user entered * * @param panel Save panel pointer */ int save_to_file(PANEL *panel); /** * @brief Save one SIP message into open file * * @param f File opened with fopen * @param msg a SIP Message */ void save_msg_txt(FILE *f, sip_msg_t *msg); #endif sngrep-1.2.0/src/sip_attr.h0000644000175000017500000001255112632250522014632 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip_attr.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP calls and messages attributes */ #ifndef __SNGREP_SIP_ATTR_H #define __SNGREP_SIP_ATTR_H #include "config.h" #include "vector.h" //! Shorter declaration of sip_attr_hdr structure typedef struct sip_attr_hdr sip_attr_hdr_t; //! Shorter declaration of sip_attr structure typedef struct sip_attr sip_attr_t; /** * @brief Available SIP Attributes * * This enum contains the list of available attributes * a call or message can have. */ enum sip_attr_id { //! Call index in the Call List SIP_ATTR_CALLINDEX = 0, //! SIP Message From: header SIP_ATTR_SIPFROM, //! SIP Message User of From: header SIP_ATTR_SIPFROMUSER, //! SIP Message To: header SIP_ATTR_SIPTO, //! SIP Message User of To: header SIP_ATTR_SIPTOUSER, //! Package IP source address and port SIP_ATTR_SRC, //! Package IP destination address and port SIP_ATTR_DST, //! SIP Message Call-ID header SIP_ATTR_CALLID, //! SIP Message X-Call-ID or X-CID header SIP_ATTR_XCALLID, //! SIP Message Date SIP_ATTR_DATE, //! SIP Message Time SIP_ATTR_TIME, //! SIP Message Method or Response code SIP_ATTR_METHOD, //! SDP Address SIP_ATTR_SDP_ADDRESS, //! SDP Port SIP_ATTR_SDP_PORT, //! SIP Message transport SIP_ATTR_TRANSPORT, //! SIP Call message counter SIP_ATTR_MSGCNT, //! SIP Call state SIP_ATTR_CALLSTATE, //! Conversation duration SIP_ATTR_CONVDUR, //! Total call duration SIP_ATTR_TOTALDUR, //! SIP Attribute count SIP_ATTR_COUNT }; /** * @brief Attribute header data * * This sctructure contains the information about the * attribute, description, id, type and so. It's the * static information of the attributed shared by all * attributes pointer to its type. * */ struct sip_attr_hdr { //! Attribute id enum sip_attr_id id; //! Attribute name char *name; //! Attribute column title char *title; //! Attribute description char *desc; //! Attribute default display width int dwidth; //! This function determines the color of this attribute in CallList int (*color)(const char *value); }; /** * @brief Attribute storage struct */ struct sip_attr { //! Attribute id enum sip_attr_id id; //! Attribute value char *value; }; /** * @brief Get the header information of an Attribute * * Retrieve header data from attribute list * * @param id Attribute id * @return Attribute header data structure pointer */ sip_attr_hdr_t * sip_attr_get_header(enum sip_attr_id id); /** * @brief Get Attribute description * * Retrieve description of given attribute from its * header structure. * * @param id Attribute id * @return Attribute description from its header */ const char * sip_attr_get_description(enum sip_attr_id id); /** * @brief Get Attribute title * * Retrieve title of given attribute from its * header structure. * * @param id Attribute id * @return Attribute title from its header */ const char * sip_attr_get_title(enum sip_attr_id id); /** * @brief Get Attribute name * * Retrieve name of given attribute from its * header structure. * * @param id Attribute id * @return Attribute name from its header */ const char * sip_attr_get_name(enum sip_attr_id id); /** * @brief Get Attribute prefered display width * * @param id Attribute id * @return prefered attribute width */ int sip_attr_get_width(enum sip_attr_id id); /** * @brief Get Attribute id from its name * * Retrieve attribute id of the given attribute name. * * @param name Attribut name * @return Attribute id or -1 if not found */ enum sip_attr_id sip_attr_from_name(const char *name); /** * @brief Determine the color of the attribute in Call List * * Return the color pair to display an attribute in * call list or -1 if default color must be used. */ int sip_attr_get_color(int id, const char *value); /** * @brief Determine the color of the attribute in Call List * * This function can be used to show the Method attribute * with different colours in Call List. */ int sip_attr_color_method(const char *value); /** * @brief Determine the color of the attribute in Call List * * This function can be used to show the state attribute * with different colours in Call List. */ int sip_attr_color_state(const char *value); #endif /* __SNGREP_SIP_ATTR_H */ sngrep-1.2.0/src/sip_msg.h0000644000175000017500000001150412632250522014443 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip_msg.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage sip messages * */ #ifndef __SNGREP_SIP_MSG_H #define __SNGREP_SIP_MSG_H #include "config.h" #include #include "vector.h" #include "media.h" #include "sip_attr.h" #include "util.h" //! Shorter declaration of sip_msg structure typedef struct sip_msg sip_msg_t; /** * @brief Information of a single message withing a dialog. * * Most of the data is just stored to be displayed in the UI so * the formats may be no the best, but the simplest for this * purpose. It also works as a linked lists of messages in a * call. */ struct sip_call; struct sip_msg { //! Request Method or Response Code @see sip_methods int reqresp; //! Message Cseq u_int cseq; //! SIP From and TO char *sip_from, *sip_to; //! SDP payload information (sdp_media_t *) vector_t *medias; //! Captured packets for this message (capture_packet_t *) capture_packet_t *packet; //! Index of this message in call int index; //! Message owner struct sip_call *call; }; /** * @brief Create a new message from the readed header and payload * * Allocate required memory for a new SIP message. This function * will only store the given information, but wont parse it until * needed. * * @param payload Raw payload content * @return a new allocated message */ sip_msg_t * msg_create(const char *payload); /** * @brief Destroy a SIP message and free its memory * * Deallocate memory of an existing SIP Message. * This function will remove the message from the call and the * passed pointer will be NULL. * * @param nsg SIP message to be deleted */ void msg_destroy(sip_msg_t *msg); /** * @brief Wrapper around Message destroyer to clear msg vectors */ void msg_destroyer(void *msg); /** * @brief Return the call owner of this message */ struct sip_call * msg_get_call(const sip_msg_t *msg); /** * @brief Getter for media of given messages * * Return the number of media structures of given msg * stored in this call. * * @param msg SIP message structure * @return how many media structures are in the msg */ int msg_media_count(sip_msg_t *msg); /** * @brief Check if given message has spd content */ int msg_has_sdp(void *item); /** * @brief Add a media structure to a msg * * @param cmsg SIP Message to be updated * @param media Media structure to be added */ void msg_add_media(sip_msg_t *msg, sdp_media_t *media); /** * @brief Check if a message is a Request or response * * @param msg SIP message that will be checked * @return 1 if the message is a request, 0 if a response */ int msg_is_request(sip_msg_t *msg); /** * @brief Add a new media for given message * * A SIP message can have multiple media description in * the SIP payload content * * @param msg SIP message that will store this packet * @param media parsed media structure from payload */ void msg_add_media(sip_msg_t *msg, sdp_media_t *media); /** * @brief Get SIP Message payload */ const char * msg_get_payload(sip_msg_t *msg); /** * @brief Get Time of message from packet header * * @param msg SIP message * @return timeval structure with message first packet time */ struct timeval msg_get_time(sip_msg_t *msg); /** * @brief Return a message attribute value * * This function will be used to avoid accessing call structure * fields directly. * * @param msg SIP message structure * @param id Attribute id * @param out Buffer to store attribute value * @return Attribute value or NULL if not found */ const char * msg_get_attribute(struct sip_msg *msg, int id, char *value); /** * @brief Check if a message is older than other * * @param one SIP message pointer * @param two SIP message pointer * @return 1 if one is older than two * @return 0 if equal or two is older than one */ int msg_is_older(sip_msg_t *one, sip_msg_t *two); #endif /* __SNGREP_SIP_MSG_H */ sngrep-1.2.0/src/ui_save.c0000644000175000017500000004327712632250522014444 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2014 Ivan Alonso (Kaian) ** Copyright (C) 2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_save_pcap.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_save_pcap.c */ #include #include #include #include #include #include #include #include "ui_save.h" #include "setting.h" #include "capture.h" #include "filter.h" /** * Ui Structure definition for Save panel */ ui_t ui_save = { .type = PANEL_SAVE, .panel = NULL, .create = save_create, .draw = save_draw, .handle_key = save_handle_key, .destroy = save_destroy }; PANEL * save_create() { PANEL *panel; WINDOW *win; int height, width; save_info_t *info; char savepath[128]; int total, displayed; // Pause the capture while saving capture_set_paused(1); // Calculate window dimensions height = 14; width = 68; // Cerate a new indow for the panel and form win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); // Create a new panel panel = new_panel(win); // Initialize save panel specific data info = sng_malloc(sizeof(save_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Initialize the fields info->fields[FLD_SAVE_PATH] = new_field(1, 52, 3, 13, 0, 0); info->fields[FLD_SAVE_FILE] = new_field(1, 47, 4, 13, 0, 0); info->fields[FLD_SAVE_ALL] = new_field(1, 1, 7, 4, 0, 0); info->fields[FLD_SAVE_SELECTED] = new_field(1, 1, 8, 4, 0, 0); info->fields[FLD_SAVE_DISPLAYED] = new_field(1, 1, 9, 4, 0, 0); info->fields[FLD_SAVE_PCAP] = new_field(1, 1, 7, 36, 0, 0); info->fields[FLD_SAVE_PCAP_RTP] = new_field(1, 1, 8, 36, 0, 0); info->fields[FLD_SAVE_TXT] = new_field(1, 1, 9, 36, 0, 0); info->fields[FLD_SAVE_SAVE] = new_field(1, 10, height - 2, 20, 0, 0); info->fields[FLD_SAVE_CANCEL] = new_field(1, 10, height - 2, 40, 0, 0); info->fields[FLD_SAVE_COUNT] = NULL; // Set fields options field_opts_off(info->fields[FLD_SAVE_PATH], O_AUTOSKIP); field_opts_off(info->fields[FLD_SAVE_FILE], O_AUTOSKIP); field_opts_off(info->fields[FLD_SAVE_ALL], O_AUTOSKIP); field_opts_off(info->fields[FLD_SAVE_SELECTED], O_AUTOSKIP); field_opts_off(info->fields[FLD_SAVE_DISPLAYED], O_AUTOSKIP); // Change background of input fields set_field_back(info->fields[FLD_SAVE_PATH], A_UNDERLINE); set_field_back(info->fields[FLD_SAVE_FILE], A_UNDERLINE); // Disable Save RTP if RTP packets are not being captured if (!setting_enabled(SETTING_CAPTURE_RTP)) field_opts_off(info->fields[FLD_SAVE_PCAP_RTP], O_ACTIVE); // Create the form and post it info->form = new_form(info->fields); set_form_sub(info->form, win); post_form(info->form); form_opts_off(info->form, O_BS_OVERLOAD); // Set Default field values sprintf(savepath, "%s", setting_get_value(SETTING_SAVEPATH)); set_field_buffer(info->fields[FLD_SAVE_PATH], 0, savepath); set_field_buffer(info->fields[FLD_SAVE_SAVE], 0, "[ Save ]"); set_field_buffer(info->fields[FLD_SAVE_CANCEL], 0, "[ Cancel ]"); // Set window boxes wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); // Window border title_foot_box(panel); // Header and footer lines mvwhline(win, height - 3, 1, ACS_HLINE, width - 1); mvwaddch(win, height - 3, 0, ACS_LTEE); mvwaddch(win, height - 3, width - 1, ACS_RTEE); // Save mode box mvwaddch(win, 6, 2, ACS_ULCORNER); mvwhline(win, 6, 3, ACS_HLINE, 30); mvwaddch(win, 6, 32, ACS_URCORNER); mvwvline(win, 7, 2, ACS_VLINE, 3); mvwvline(win, 7, 32, ACS_VLINE, 3); mvwaddch(win, 10, 2, ACS_LLCORNER); mvwhline(win, 10, 3, ACS_HLINE, 30); mvwaddch(win, 10, 32, ACS_LRCORNER); // Save mode box mvwaddch(win, 6, 34, ACS_ULCORNER); mvwhline(win, 6, 35, ACS_HLINE, 30); mvwaddch(win, 6, 64, ACS_URCORNER); mvwvline(win, 7, 34, ACS_VLINE, 3); mvwvline(win, 7, 64, ACS_VLINE, 3); mvwaddch(win, 10, 34, ACS_LLCORNER); mvwhline(win, 10, 35, ACS_HLINE, 30); mvwaddch(win, 10, 64, ACS_LRCORNER); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); // Set screen labels mvwprintw(win, 1, 27, "Save capture"); mvwprintw(win, 3, 3, "Path:"); mvwprintw(win, 4, 3, "Filename:"); wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); mvwprintw(win, 6, 4, " Dialogs "); mvwprintw(win, 6, 36, " Format "); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); // Set default cursor position set_current_field(info->form, info->fields[FLD_SAVE_FILE]); form_driver(info->form, REQ_END_LINE); curs_set(1); // Get filter stats sip_calls_stats(&total, &displayed); // Set default save modes info->savemode = (displayed == total) ? SAVE_ALL : SAVE_DISPLAYED; info->saveformat = (setting_enabled(SETTING_CAPTURE_RTP))? SAVE_PCAP_RTP : SAVE_PCAP; return panel; } void save_destroy(PANEL *panel) { save_info_t *info; int i; // Get panel information if ((info = save_info(panel))) { // Remove panel form and fields unpost_form(info->form); free_form(info->form); for (i = 0; i < FLD_SAVE_COUNT; i++) free_field(info->fields[i]); // Remove panel window and custom info delwin(panel_window(panel)); sng_free(info); } // Resume capture capture_set_paused(0); // Disable cursor position curs_set(0); } save_info_t * save_info(PANEL *panel) { return (save_info_t*) panel_userptr(panel); } int save_draw(PANEL *panel) { int total, displayed; char field_value[80]; // Get panel information save_info_t *info = save_info(panel); WINDOW *win = panel_window(panel); // Get filter stats sip_calls_stats(&total, &displayed); mvwprintw(win, 7, 3, "( ) all dialogs "); mvwprintw(win, 8, 3, "( ) selected dialogs [%d]", call_group_count(info->group)); mvwprintw(win, 9, 3, "( ) filtered dialogs [%d]", displayed); mvwprintw(win, 7, 35, "( ) .pcap (SIP)"); mvwprintw(win, 8, 35, "( ) .pcap (SIP + RTP)"); mvwprintw(win, 9, 35, "( ) .txt"); // Get filename field value. memset(field_value, 0, sizeof(field_value)); strcpy(field_value, field_buffer(info->fields[FLD_SAVE_FILE], 0)); strtrim(field_value); mvwprintw(win, 4, 60, " "); if (strstr(field_value, ".pcap")) { info->saveformat = (setting_enabled(SETTING_CAPTURE_RTP))? SAVE_PCAP_RTP : SAVE_PCAP; } else if (strstr(field_value, ".txt")) { info->saveformat = SAVE_TXT; } else { if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) mvwprintw(win, 4, 60, ".pcap"); else mvwprintw(win, 4, 60, ".txt "); } set_field_buffer(info->fields[FLD_SAVE_ALL], 0, (info->savemode == SAVE_ALL) ? "*" : " "); set_field_buffer(info->fields[FLD_SAVE_SELECTED], 0, (info->savemode == SAVE_SELECTED) ? "*" : " "); set_field_buffer(info->fields[FLD_SAVE_DISPLAYED], 0, (info->savemode == SAVE_DISPLAYED) ? "*" : " "); set_field_buffer(info->fields[FLD_SAVE_PCAP], 0, (info->saveformat == SAVE_PCAP) ? "*" : " "); set_field_buffer(info->fields[FLD_SAVE_PCAP_RTP], 0, (info->saveformat == SAVE_PCAP_RTP) ? "*" : " "); set_field_buffer(info->fields[FLD_SAVE_TXT], 0, (info->saveformat == SAVE_TXT) ? "*" : " "); // Show disabled options with makers if (!setting_enabled(SETTING_CAPTURE_RTP)) set_field_buffer(info->fields[FLD_SAVE_PCAP_RTP], 0, "-"); set_current_field(info->form, current_field(info->form)); form_driver(info->form, REQ_VALIDATION); return 0; } int save_handle_key(PANEL *panel, int key) { int field_idx; int action = -1; // Get panel information save_info_t *info = save_info(panel); // Get current field id field_idx = field_index(current_field(info->form)); // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_PRINTABLE: if (field_idx == FLD_SAVE_PATH || field_idx == FLD_SAVE_FILE) { form_driver(info->form, key); break; } continue; case ACTION_NEXT_FIELD: form_driver(info->form, REQ_NEXT_FIELD); form_driver(info->form, REQ_END_LINE); break; case ACTION_PREV_FIELD: form_driver(info->form, REQ_PREV_FIELD); form_driver(info->form, REQ_END_LINE); break; case ACTION_RIGHT: form_driver(info->form, REQ_RIGHT_CHAR); break; case ACTION_LEFT: form_driver(info->form, REQ_LEFT_CHAR); break; case ACTION_BEGIN: form_driver(info->form, REQ_BEG_LINE); break; case ACTION_END: form_driver(info->form, REQ_END_LINE); break; case ACTION_DELETE: form_driver(info->form, REQ_DEL_CHAR); break; case ACTION_BACKSPACE: form_driver(info->form, REQ_DEL_PREV); break; case ACTION_CLEAR: form_driver(info->form, REQ_CLR_FIELD); break; case ACTION_SELECT: switch (field_idx) { case FLD_SAVE_ALL: info->savemode = SAVE_ALL; break; case FLD_SAVE_SELECTED: info->savemode = SAVE_SELECTED; break; case FLD_SAVE_DISPLAYED: info->savemode = SAVE_DISPLAYED; break; case FLD_SAVE_PCAP: info->saveformat = SAVE_PCAP; break; case FLD_SAVE_PCAP_RTP: info->saveformat = SAVE_PCAP_RTP; break; case FLD_SAVE_TXT: info->saveformat = SAVE_TXT; break; case FLD_SAVE_FILE: form_driver(info->form, key); break; default: break; } break; case ACTION_CONFIRM: if (field_idx != FLD_SAVE_CANCEL) { return save_to_file(panel); } return KEY_ESC; default: // Parse next action continue; } // This panel has handled the key successfully break; } // Validate all input data form_driver(info->form, REQ_VALIDATION); // Change background and cursor of "button fields" set_field_back(info->fields[FLD_SAVE_SAVE], A_NORMAL); set_field_back(info->fields[FLD_SAVE_CANCEL], A_NORMAL); curs_set(1); // Change current field background field_idx = field_index(current_field(info->form)); if (field_idx == FLD_SAVE_SAVE || field_idx == FLD_SAVE_CANCEL) { set_field_back(info->fields[field_idx], A_REVERSE); curs_set(0); } // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } void save_set_group(PANEL *panel, sip_call_group_t *group) { // Get panel information save_info_t *info = save_info(panel); info->group = group; if (call_group_count(group)) { info->savemode = SAVE_SELECTED; } } int save_to_file(PANEL *panel) { char savepath[256]; char savefile[256]; char fullfile[512]; sip_call_t *call = NULL; sip_msg_t *msg = NULL; pcap_dumper_t *pd = NULL; FILE *f = NULL; int cur = 0, total = 0; WINDOW *progress; vector_iter_t calls, msgs, rtps, packets; capture_packet_t *packet; vector_t *sorted; // Get panel information save_info_t *info = save_info(panel); // Get current path field value. memset(savepath, 0, sizeof(savepath)); strcpy(savepath, field_buffer(info->fields[FLD_SAVE_PATH], 0)); strtrim(savepath); if (strlen(savepath)) strcat(savepath, "/"); // Get current file field value. memset(savefile, 0, sizeof(savefile)); strcpy(savefile, field_buffer(info->fields[FLD_SAVE_FILE], 0)); strtrim(savefile); if (!strlen(savefile)) { dialog_run("Please enter a valid filename"); return 1; } if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) { if (!strstr(savefile, ".pcap")) strcat(savefile, ".pcap"); } else { if (!strstr(savefile, ".txt")) strcat(savefile, ".txt"); } // Absolute filename sprintf(fullfile, "%s%s", savepath, savefile); if (access(fullfile, R_OK) == 0) { if (dialog_confirm("Overwrite confirmation", "Selected file already exits.\n Do you want to overwrite it?", "Yes,No") != 0) return 1; } // Don't allow to save no packets! if (info->savemode == SAVE_SELECTED && call_group_msg_count(info->group) == 0) { dialog_run("Unable to save: No selected dialogs."); return 1; } if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) { // Open dump file pd = dump_open(fullfile); if (access(fullfile, W_OK) != 0) { dialog_run(capture_last_error()); return 1; } } else { // Open a text file if (!(f = fopen(fullfile, "w"))) { dialog_run("Error: %s", strerror(errno)); return 0; } } // Get calls iterator switch (info->savemode) { case SAVE_ALL: // Get calls iterator calls = sip_calls_iterator(); break; case SAVE_SELECTED: // Save selected packets to file calls = vector_iterator(info->group->calls); break; case SAVE_DISPLAYED: // Set filtering for this iterator calls = sip_calls_iterator(); vector_iterator_set_filter(&calls, filter_check_call); break; } if (info->saveformat == SAVE_TXT) { // Save selected packets to file while ((call = vector_iterator_next(&calls))) { msgs = vector_iterator(call->msgs); // Save SIP message content while ((msg = vector_iterator_next(&msgs))) { save_msg_txt(f, msg); } } } else { // Store all messages in a time sorted vector sorted = vector_create(100, 50); vector_set_sorter(sorted, capture_packet_time_sorter); // Count packages for progress bar while ((call = vector_iterator_next(&calls))) { total += vector_count(call->msgs); if (info->saveformat == SAVE_PCAP_RTP) total += vector_count(call->rtp_packets); } vector_iterator_reset(&calls); progress = dialog_progress_run("Saving packets..."); dialog_progress_set_value(progress, 0); // Save selected packets to file while ((call = vector_iterator_next(&calls))) { msgs = vector_iterator(call->msgs); // Save SIP message content while ((msg = vector_iterator_next(&msgs))) { // Update progress bar dialog dialog_progress_set_value(progress, (++cur * 100) / total); vector_append(sorted, msg->packet); } // Save RTP packets if (info->saveformat == SAVE_PCAP_RTP) { rtps = vector_iterator(call->rtp_packets); while ((packet = vector_iterator_next(&rtps))) { // Update progress bar dialog dialog_progress_set_value(progress, (++cur * 100) / total); vector_append(sorted, packet); } } } // Save sorted packets packets = vector_iterator(sorted); while ((packet = vector_iterator_next(&packets))) { dump_packet(pd, packet); } dialog_progress_destroy(progress); } // Close saved file if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) { dump_close(pd); } else { fclose(f); } // Show success popup dialog_run("Successfully saved %d dialogs to %s", vector_iterator_count(&calls), savefile); return 27; } void save_msg_txt(FILE *f, sip_msg_t *msg) { char date[20], time[20], src[80], dst[80]; fprintf(f, "%s %s %s -> %s\n%s\n\n", msg_get_attribute(msg, SIP_ATTR_DATE, date), msg_get_attribute(msg, SIP_ATTR_TIME, time), msg_get_attribute(msg, SIP_ATTR_SRC, src), msg_get_attribute(msg, SIP_ATTR_DST, dst), msg_get_payload(msg)); } sngrep-1.2.0/src/group.h0000644000175000017500000001331112632250522014134 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file option.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage call groups * * Call groups are used to pass a set of calls between different panels of * sngrep. * */ #ifndef __SNGREP_GROUP_H_ #define __SNGREP_GROUP_H_ #include "config.h" #include "vector.h" #include "sip.h" //! Shorter declaration of sip_call_group structure typedef struct sip_call_group sip_call_group_t; /** * @brief Contains a list of calls * * This structure is used for displaying more than one dialog in the * same call flow. Instead of displaying a call flow, we will display * a calls group flow. */ struct sip_call_group { //! Calls array in the group vector_t *calls; //! Color of the last printed call in mode Color-by-Call int color; //! Only consider SDP messages from Calls int sdp_only; }; /** * @brief Create a new groupt to hold Calls in it * * Allocate memory to create a new calls group * * @return Pointer to a new group */ sip_call_group_t * call_group_create(); /** * @brief Deallocate memory of an existing group * * @param Pointer to an existing group */ void call_group_destroy(sip_call_group_t *group); /** * @brief Clone an existing call group * * Create a new call group with the same calls of the * original one. Beware: The call pointers are shared between * original and clone groups. * */ sip_call_group_t * call_group_clone(sip_call_group_t *original); /** * @brief Add a Call to the group * * @param group Pointer to an existing group * @param call Pointer to an existing call */ void call_group_add(sip_call_group_t *group, sip_call_t *call); /** * @brief Remove a call from the group * * @param group Pointer to an existing group * @param call Pointer to an existing call */ void call_group_del(sip_call_group_t *group, sip_call_t *call); /** * @brief Check if a call is in the group * * @param group Pointer to an existing group * @param call Pointer to an existing call * @return 1 if the call is in the group, 0 otherwise */ int call_group_exists(sip_call_group_t *group, sip_call_t *call); /** * @brief Return the color pair number of a call * * When color by callid mode is enabled, this function will * return the color pair number of the call depending its * position inside the call * * @param group Pointer to an existing group * @param call Pointer to an existing call * @return Color pair number */ int call_group_color(sip_call_group_t *group, sip_call_t *call); /** * @brief Return the next call in the group * * Return then next call after the given call parameter. * If NULL is used as parameter, return the first call. * It will return NULL if last call is given as parameter. * * @param group Pointer to an existing group * @param call Pointer to an existing call or NULL * @return Next call of the group, or NULL */ sip_call_t * call_group_get_next(sip_call_group_t *group, sip_call_t *call); /** * @brief Return number of calls in a group * * @param group Pointer to an existing group * @return How many calls the group has */ int call_group_count(sip_call_group_t *group); /** * @brief Return message count in the group * * Return the sum of messages of all calls in the group * * @param group Pointer to an existing group * @return How many messages have the calls in the group */ int call_group_msg_count(sip_call_group_t *group); /** * @brief Return Message position in the group * * Return how many messages are before the given message * sorting all messages in all group calls by timestamp * * @param group Pointer to an existing group * @param msg A sip message from a call in the group * @return The position of given message in the group */ int call_group_msg_number(sip_call_group_t *group, sip_msg_t *msg); /** * @brief Finds the next msg in a call group. * * If the passed msg is NULL it returns the first message * of the group. * * @param callgroup SIP call group structure * @param msg Actual SIP msg from any call of the group (can be NULL) * @return Next chronological message in the group or NULL */ sip_msg_t * call_group_get_next_msg(sip_call_group_t *group, sip_msg_t *msg); /** * @brief Find the previous message in a call group * * @param callgroup SIP call group structure * @param msg Actual SIP msg from any call of the group * @return Previous chronological message in the group or NULL */ sip_msg_t * call_group_get_prev_msg(sip_call_group_t *group, sip_msg_t *msg); /** * @brief Find the next stream in a call group * * @param callgroup SIP call group structure * @param msg Actual stream structure from any call of the group * @return next chronological stream in the group or NULL */ rtp_stream_t * call_group_get_next_stream(sip_call_group_t *group, rtp_stream_t *stream); #endif /* __SNGREP_GROUP_H_ */ sngrep-1.2.0/src/sip_call.c0000644000175000017500000001627012632250522014570 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip_call.c * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP call data * * This file contains the functions and structure to manage SIP call data * */ #include "sip_call.h" #include "sip.h" #include "setting.h" sip_call_t * call_create(char *callid, char *xcallid) { sip_call_t *call; // Initialize a new call structure if (!(call = sng_malloc(sizeof(sip_call_t)))) return NULL; // Create a vector to store call messages call->msgs = vector_create(2, 2); vector_set_destroyer(call->msgs, msg_destroyer); // Create an empty vector to store rtp packets if (setting_enabled(SETTING_CAPTURE_RTP)) { call->rtp_packets = vector_create(0, 40); vector_set_destroyer(call->rtp_packets, capture_packet_destroyer); } // Create an empty vector to strore stream data call->streams = vector_create(0, 2); vector_set_destroyer(call->streams, vector_generic_destroyer); // Initialize call filter status call->filtered = -1; // Set message callid call->callid = strdup(callid); call->xcallid = strdup(xcallid); return call; } void call_destroy(sip_call_t *call) { // Remove all call messages vector_destroy(call->msgs); // Remove all call streams vector_destroy(call->streams); // Remove all call rtp packets vector_destroy(call->rtp_packets); // Deallocate call memory sng_free(call->callid); sng_free(call->xcallid); sng_free(call); } void call_destroyer(void *call) { call_destroy((sip_call_t*)call); } void call_add_message(sip_call_t *call, sip_msg_t *msg) { // Set the message owner msg->call = call; // Put this msg at the end of the msg list msg->index = vector_append(call->msgs, msg); } void call_add_stream(sip_call_t *call, rtp_stream_t *stream) { vector_append(call->streams, stream); } void call_add_rtp_packet(sip_call_t *call, capture_packet_t *packet) { vector_append(call->rtp_packets, packet); } int call_msg_count(sip_call_t *call) { return vector_count(call->msgs); } int call_is_active(sip_call_t *call) { return (call->state == SIP_CALLSTATE_CALLSETUP || call->state == SIP_CALLSTATE_INCALL); } int call_is_invite(sip_call_t *call) { sip_msg_t *first; if ((first = vector_first(call->msgs))) return (first->reqresp == SIP_METHOD_INVITE); return 0; } int call_msg_is_retrans(sip_msg_t *msg) { sip_msg_t *prev = NULL; vector_iter_t it; // Get previous message in call with same origin and destination it = vector_iterator(msg->call->msgs); vector_iterator_set_current(&it, vector_index(msg->call->msgs, msg)); while ((prev = vector_iterator_prev(&it))) { if (!strcmp(prev->packet->ip_src, msg->packet->ip_src) && !strcmp(prev->packet->ip_dst, msg->packet->ip_dst)) break; } return (prev && !strcasecmp(msg_get_payload(msg), msg_get_payload(prev))); } void call_update_state(sip_call_t *call, sip_msg_t *msg) { int reqresp; sip_msg_t *first; if (!call_is_invite(call)) return; // Get the first message in the call first = vector_first(call->msgs); // Get current message Method / Response Code reqresp = msg->reqresp; // If this message is actually a call, get its current state if (call->state) { if (call->state == SIP_CALLSTATE_CALLSETUP) { if (reqresp == 200) { // Alice and Bob are talking call->state = SIP_CALLSTATE_INCALL; call->cstart_msg = msg; } else if (reqresp == SIP_METHOD_CANCEL) { // Alice is not in the mood call->state = SIP_CALLSTATE_CANCELLED; } else if (reqresp > 400) { // Bob is not in the mood call->state = SIP_CALLSTATE_REJECTED; } } else if (call->state == SIP_CALLSTATE_INCALL) { if (reqresp == SIP_METHOD_BYE) { // Thanks for all the fish! call->state = SIP_CALLSTATE_COMPLETED; call->cend_msg = msg; } } else if (reqresp == SIP_METHOD_INVITE && call->state != SIP_CALLSTATE_INCALL) { // Call is being setup (after proper authentication) call->state = SIP_CALLSTATE_CALLSETUP; } } else { // This is actually a call if (reqresp == SIP_METHOD_INVITE) { call->state = SIP_CALLSTATE_CALLSETUP; } } } const char * call_get_attribute(sip_call_t *call, enum sip_attr_id id, char *value) { sip_msg_t *first, *last; if (!call) return NULL; switch (id) { case SIP_ATTR_CALLINDEX: sprintf(value, "%d", call->index); break; case SIP_ATTR_CALLID: sprintf(value, "%s", call->callid); break; case SIP_ATTR_XCALLID: sprintf(value, "%s", call->xcallid); break; case SIP_ATTR_MSGCNT: sprintf(value, "%d", vector_count(call->msgs)); break; case SIP_ATTR_CALLSTATE: sprintf(value, "%s", call_state_to_str(call->state)); break; case SIP_ATTR_TRANSPORT: first = vector_first(call->msgs); sprintf(value, "%s", sip_transport_str(first->packet->type)); break; case SIP_ATTR_CONVDUR: timeval_to_duration(msg_get_time(call->cstart_msg), msg_get_time(call->cend_msg), value); break; case SIP_ATTR_TOTALDUR: first = vector_first(call->msgs); last = vector_last(call->msgs); timeval_to_duration(msg_get_time(first), msg_get_time(last), value); break; default: return msg_get_attribute(vector_first(call->msgs), id, value); break; } return strlen(value) ? value : NULL; } const char * call_state_to_str(int state) { switch (state) { case SIP_CALLSTATE_CALLSETUP: return "CALL SETUP"; case SIP_CALLSTATE_INCALL: return "IN CALL"; case SIP_CALLSTATE_CANCELLED: return "CANCELLED"; case SIP_CALLSTATE_REJECTED: return "REJECTED"; case SIP_CALLSTATE_COMPLETED: return "COMPLETED"; } return ""; } sngrep-1.2.0/src/group.c0000644000175000017500000001354112632250522014134 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file group.c * @author Ivan Alonso [aka Kaian] * * @brief Source code of functions defined in group.h * */ #include #include #include "group.h" sip_call_group_t * call_group_create() { sip_call_group_t *group; if (!(group = sng_malloc(sizeof(sip_call_group_t)))) { return NULL; } group->calls = vector_create(5, 2); return group; } void call_group_destroy(sip_call_group_t *group) { vector_destroy(group->calls); sng_free(group); } sip_call_group_t * call_group_clone(sip_call_group_t *original) { sip_call_group_t *clone; if (!original) return NULL; if (!(clone = sng_malloc(sizeof(sip_call_group_t)))) { return NULL; } clone->calls = vector_clone(original->calls); return clone; } void call_group_add(sip_call_group_t *group, sip_call_t *call) { vector_append(group->calls, call); } void call_group_del(sip_call_group_t *group, sip_call_t *call) { vector_remove(group->calls, call); } int call_group_exists(sip_call_group_t *group, sip_call_t *call) { return (vector_index(group->calls, call) >= 0) ? 1 : 0; } int call_group_color(sip_call_group_t *group, sip_call_t *call) { return (vector_index(group->calls, call) % 7) + 1; } sip_call_t * call_group_get_next(sip_call_group_t *group, sip_call_t *call) { sip_msg_t *next, *first; sip_call_t *c; int i; if (!group) return NULL; // Get call of the first message in group if (!call) { if ((next = call_group_get_next_msg(group, NULL))) { return next->call; } return NULL; } // Initialize candidate next = NULL; // Get the call with the next chronological message for (i = 0; i < vector_count(group->calls); i++) { if ((c = vector_item(group->calls, i)) == call) continue; // Get first message first = vector_first(c->msgs); // Is first message of this call older? if (msg_is_older(first, vector_first(call->msgs)) && (!next || !msg_is_older(first, next))) { next = first; break; } } return (next) ? next->call : NULL; } int call_group_count(sip_call_group_t *group) { return vector_count(group->calls); } int call_group_msg_count(sip_call_group_t *group) { sip_call_t *call; vector_iter_t msgs; int msgcnt = 0, i; for (i = 0; i < vector_count(group->calls); i++) { call = vector_item(group->calls, i); msgs = vector_iterator(call->msgs); if (group->sdp_only) { vector_iterator_set_filter(&msgs, msg_has_sdp); } msgcnt += vector_iterator_count(&msgs); } return msgcnt; } int call_group_msg_number(sip_call_group_t *group, sip_msg_t *msg) { int number = 0; sip_msg_t *cur = NULL; while ((cur = call_group_get_next_msg(group, cur))) { if (group->sdp_only && !msg_has_sdp(msg)) continue; if (cur == msg) return number; number++; } return 0; } sip_msg_t * call_group_get_next_msg(sip_call_group_t *group, sip_msg_t *msg) { sip_msg_t *next = NULL; sip_msg_t *cand; vector_iter_t msgs; sip_call_t *call; int i; for (i = 0; i < vector_count(group->calls); i++) { call = vector_item(group->calls, i); msgs = vector_iterator(call->msgs); if (msg && call == msg_get_call(msg)) vector_iterator_set_current(&msgs, msg->index); if (group->sdp_only) vector_iterator_set_filter(&msgs, msg_has_sdp); cand = NULL; while ((cand = vector_iterator_next(&msgs))) { // candidate must be between msg and next if (msg_is_older(cand, msg) && (!next || !msg_is_older(cand, next))) { next = cand; break; } } } return sip_parse_msg(next); } sip_msg_t * call_group_get_prev_msg(sip_call_group_t *group, sip_msg_t *msg) { sip_msg_t *next = NULL; sip_msg_t *prev = NULL; // FIXME Horrible performance for huge dialogs while ((next = call_group_get_next_msg(group, next))) { if (next == msg) break; prev = next; } return prev; } rtp_stream_t * call_group_get_next_stream(sip_call_group_t *group, rtp_stream_t *stream) { rtp_stream_t *next = NULL; rtp_stream_t *cand; sip_call_t *call; vector_iter_t streams; int i; for (i = 0; i < vector_count(group->calls); i++) { call = vector_item(group->calls, i); streams = vector_iterator(call->streams); while ( (cand = vector_iterator_next(&streams))) { if (!stream_get_count(cand)) continue; // candidate must be between msg and next if (stream_is_older(cand, stream) && (!next || stream_is_older(next, cand))) { next = cand; } } } return next; } sngrep-1.2.0/src/ui_column_select.c0000644000175000017500000003530412632250522016332 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2014,2015 Ivan Alonso (Kaian) ** Copyright (C) 2014,2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_column_select.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_column_select.h * */ #include #include #include #include #include #include "ui_manager.h" #include "ui_call_list.h" #include "ui_column_select.h" /** * Ui Structure definition for Message Diff panel */ ui_t ui_column_select = { .type = PANEL_COLUMN_SELECT, .panel = NULL, .create = column_select_create, .handle_key = column_select_handle_key, .destroy = column_select_destroy }; PANEL * column_select_create() { int attr_id, column; PANEL *panel; WINDOW *win; MENU *menu; int height, width; column_select_info_t *info; // Calculate window dimensions height = 20; width = 60; // Cerate a new indow for the panel and form win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); // Create a new panel panel = new_panel(win); // Initialize Filter panel specific data info = sng_malloc(sizeof(column_select_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Initialize the fields info->fields[FLD_COLUMNS_ACCEPT] = new_field(1, 10, height - 2, 13, 0, 0); info->fields[FLD_COLUMNS_SAVE] = new_field(1, 10, height - 2, 25, 0, 0); info->fields[FLD_COLUMNS_CANCEL] = new_field(1, 10, height - 2, 37, 0, 0); info->fields[FLD_COLUMNS_COUNT] = NULL; // Field Labels set_field_buffer(info->fields[FLD_COLUMNS_ACCEPT], 0, "[ Accept ]"); set_field_buffer(info->fields[FLD_COLUMNS_SAVE], 0, "[ Save ]"); set_field_buffer(info->fields[FLD_COLUMNS_CANCEL], 0, "[ Cancel ]"); // Create the form and post it info->form = new_form(info->fields); set_form_sub(info->form, win); post_form(info->form); // Create a subwin for the menu area info->menu_win = derwin(win, 10, width - 2, 7, 0); // Initialize one field for each attribute for (attr_id = 0; attr_id < SIP_ATTR_COUNT; attr_id++) { // Create a new field for this column info->items[attr_id] = new_item("[ ]", sip_attr_get_description(attr_id)); set_item_userptr(info->items[attr_id], (void*) sip_attr_get_name(attr_id)); } info->items[SIP_ATTR_COUNT] = NULL; // Create the columns menu and post it info->menu = menu = new_menu(info->items); // Set current enabled fields // FIXME Stealing Call list columns :/ call_list_info_t *list_info = call_list_info(ui_get_panel(ui_find_by_type(PANEL_CALL_LIST))); // Enable current enabled fields and move them to the top for (column = 0; column < list_info->columncnt; column++) { const char *attr = list_info->columns[column].attr; for (attr_id = 0; attr_id < item_count(menu); attr_id++) { if (!strcmp(item_userptr(info->items[attr_id]), attr)) { column_select_toggle_item(panel, info->items[attr_id]); column_select_move_item(panel, info->items[attr_id], column); break; } } } // Set main window and sub window set_menu_win(menu, win); set_menu_sub(menu, derwin(win, 10, width - 5, 7, 2)); set_menu_format(menu, 10, 1); set_menu_mark(menu, ""); set_menu_fore(menu, COLOR_PAIR(CP_DEF_ON_BLUE)); menu_opts_off(menu, O_ONEVALUE); post_menu(menu); // Draw a scrollbar to the right draw_vscrollbar(info->menu_win, top_row(menu), item_count(menu) - 1, 0); // Set the window title and boxes mvwprintw(win, 1, width / 2 - 14, "Call List columns selection"); wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); title_foot_box(panel); mvwhline(win, 6, 1, ACS_HLINE, width - 1); mvwaddch(win, 6, 0, ACS_LTEE); mvwaddch(win, 6, width - 1, ACS_RTEE); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); // Some brief explanation abotu what window shows wattron(win, COLOR_PAIR(CP_CYAN_ON_DEF)); mvwprintw(win, 3, 2, "This windows show the list of columns displayed on Call"); mvwprintw(win, 4, 2, "List. You can enable/disable using Space Bar and reorder"); mvwprintw(win, 5, 2, "them using + and - keys."); wattroff(win, COLOR_PAIR(CP_CYAN_ON_DEF)); info->form_active = 0; return panel; } void column_select_destroy(PANEL *panel) { int i; column_select_info_t *info = column_select_info(panel); // Remove menu and items unpost_menu(info->menu); free_menu(info->menu); for (i = 0; i < SIP_ATTR_COUNT; i++) free_item(info->items[i]); // Remove form and fields unpost_form(info->form); free_form(info->form); for (i = 0; i < FLD_COLUMNS_COUNT; i++) free_field(info->fields[i]); // Remove panel window and custom info delwin(panel_window(panel)); del_panel(panel); sng_free(info); } column_select_info_t * column_select_info(PANEL *panel) { return (column_select_info_t*) panel_userptr(panel); } int column_select_handle_key(PANEL *panel, int key) { // Get panel information column_select_info_t *info = column_select_info(panel); if (info->form_active) { return column_select_handle_key_form(panel, key); } else { return column_select_handle_key_menu(panel, key); } return 0; } int column_select_handle_key_menu(PANEL *panel, int key) { MENU *menu; ITEM *current; int current_idx; int action = -1; // Get panel information column_select_info_t *info = column_select_info(panel); menu = info->menu; current = current_item(menu); current_idx = item_index(current); // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_DOWN: menu_driver(menu, REQ_DOWN_ITEM); break; case ACTION_UP: menu_driver(menu, REQ_UP_ITEM); break; case ACTION_NPAGE: menu_driver(menu, REQ_SCR_DPAGE); break; case ACTION_PPAGE: menu_driver(menu, REQ_SCR_UPAGE); break; case ACTION_SELECT: column_select_toggle_item(panel, current); column_select_update_menu(panel); break; case ACTION_COLUMN_MOVE_DOWN: column_select_move_item(panel, current, current_idx + 1); column_select_update_menu(panel); break; case ACTION_COLUMN_MOVE_UP: column_select_move_item(panel, current, current_idx - 1); column_select_update_menu(panel); break; case ACTION_NEXT_FIELD: info->form_active = 1; set_menu_fore(menu, COLOR_PAIR(CP_DEFAULT)); set_field_back(info->fields[FLD_COLUMNS_ACCEPT], A_REVERSE); form_driver(info->form, REQ_VALIDATION); break; case ACTION_CONFIRM: column_select_update_columns(panel); return 27; default: // Parse next action continue; } // This panel has handled the key successfully break; } // Draw a scrollbar to the right draw_vscrollbar(info->menu_win, top_row(menu), item_count(menu) - 1, 0); wnoutrefresh(info->menu_win); // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } int column_select_handle_key_form(PANEL *panel, int key) { int field_idx, new_field_idx; char field_value[48]; int action = -1; // Get panel information column_select_info_t *info = column_select_info(panel); // Get current field id field_idx = field_index(current_field(info->form)); // Get current field value. memset(field_value, 0, sizeof(field_value)); strcpy(field_value, field_buffer(current_field(info->form), 0)); strtrim(field_value); // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_RIGHT: case ACTION_NEXT_FIELD: form_driver(info->form, REQ_NEXT_FIELD); break; case ACTION_LEFT: case ACTION_PREV_FIELD: form_driver(info->form, REQ_PREV_FIELD); break; case ACTION_SELECT: case ACTION_CONFIRM: switch(field_idx) { case FLD_COLUMNS_ACCEPT: column_select_update_columns(panel); return 27; case FLD_COLUMNS_CANCEL: return 27; case FLD_COLUMNS_SAVE: column_select_update_columns(panel); column_select_save_columns(panel); return 27; } break; default: // Parse next action continue; } // This panel has handled the key successfully break; } // Validate all input data form_driver(info->form, REQ_VALIDATION); // Change background and cursor of "button fields" set_field_back(info->fields[FLD_COLUMNS_ACCEPT], A_NORMAL); set_field_back(info->fields[FLD_COLUMNS_SAVE], A_NORMAL); set_field_back(info->fields[FLD_COLUMNS_CANCEL], A_NORMAL); // Get current selected field new_field_idx = field_index(current_field(info->form)); // Swap between menu and form if (field_idx == FLD_COLUMNS_CANCEL && new_field_idx == FLD_COLUMNS_ACCEPT) { set_menu_fore(info->menu, COLOR_PAIR(CP_DEF_ON_BLUE)); info->form_active = 0; } else { // Change current field background set_field_back(info->fields[new_field_idx], A_REVERSE); } // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } void column_select_update_columns(PANEL *panel) { int column, attr_id; // Get panel information column_select_info_t *info = column_select_info(panel); // Set enabled fields PANEL *list_panel = ui_get_panel(ui_find_by_type(PANEL_CALL_LIST)); call_list_info_t *list_info = call_list_info(list_panel); // Reset column count list_info->columncnt = 0; // Add all selected columns for (column = 0; column < item_count(info->menu); column++) { // If column is active if (!strncmp(item_name(info->items[column]), "[ ]", 3)) continue; // Get column attribute attr_id = sip_attr_from_name(item_userptr(info->items[column])); // Add a new column to the list call_list_add_column(list_panel, attr_id, sip_attr_get_name(attr_id), sip_attr_get_title(attr_id), sip_attr_get_width(attr_id)); } } void column_select_save_columns(PANEL *panel) { int column; FILE *fi, *fo; char columnopt[128]; char line[1024]; char *home = getenv("HOME"); char userconf[128], tmpfile[128]; // No home dir... if (!home) return; // Read current $HOME/.sngreprc file sprintf(userconf, "%s/.sngreprc", home); sprintf(tmpfile, "%s/.sngreprc.old", home); // Remove old config file unlink(tmpfile); // Move home file to temporal dir rename(userconf, tmpfile); // Create a new user conf file if (!(fo = fopen(userconf, "w"))) { dialog_run("Unable to open %s: %s", userconf, strerror(errno)); return; } // Read all lines of old sngreprc file if ((fi = fopen(tmpfile, "r"))) { // Read all configuration file while (fgets(line, 1024, fi) != NULL) { // Ignore lines starting with set (but keep settings) if (strncmp(line, "set ", 4) || strncmp(line, "set cl.column", 13)) { // Put everyting in new .sngreprc file fputs(line, fo); } } fclose(fi); } // Get panel information column_select_info_t *info = column_select_info(panel); // Add all selected columns for (column = 0; column < item_count(info->menu); column++) { // If column is active if (!strncmp(item_name(info->items[column]), "[ ]", 3)) continue; // Add the columns settings sprintf(columnopt, "set cl.column%d %s\n", column, (const char*) item_userptr(info->items[column])); fputs(columnopt, fo); } fclose(fo); // Show a information dialog dialog_run("Column layout successfully saved to %s", userconf); } void column_select_move_item(PANEL *panel, ITEM *item, int pos) { // Get panel information column_select_info_t *info = column_select_info(panel); // Check we have a valid position if (pos == item_count(info->menu) || pos < 0) return; // Swap position with destination int item_pos = item_index(item); info->items[item_pos] = info->items[pos]; info->items[item_pos]->index = item_pos; info->items[pos] = item; info->items[pos]->index = pos; } void column_select_toggle_item(PANEL *panel, ITEM *item) { // Change item name if (!strncmp(item_name(item), "[ ]", 3)) { item->name.str = "[*]"; } else { item->name.str = "[ ]"; } } void column_select_update_menu(PANEL *panel) { // Get panel information column_select_info_t *info = column_select_info(panel); ITEM *current = current_item(info->menu); int top_idx = top_row(info->menu); // Remove the menu from the subwindow unpost_menu(info->menu); // Set menu items set_menu_items(info->menu, info->items); // Put the menu agin into its subwindow post_menu(info->menu); // Move until the current position is set set_top_row(info->menu, top_idx); set_current_item(info->menu, current); } sngrep-1.2.0/src/ui_settings.c0000644000175000017500000005112012632250522015330 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_settings.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_settings.h */ #include #include #include #include "ui_manager.h" #include "ui_settings.h" #include "setting.h" /** * Ui Structure definition for Settings panel */ ui_t ui_settings = { .type = PANEL_SETTINGS, .panel = NULL, .create = settings_create, .draw = settings_draw, .handle_key = settings_handle_key, .destroy = settings_destroy }; settings_category_t categories[] = { { CAT_SETTINGS_INTERFACE, "Interface" }, { CAT_SETTINGS_CAPTURE, "Capture" }, { CAT_SETTINGS_CALL_FLOW, "Call Flow" }, { CAT_SETTINGS_EEP_HOMER, "EEP/HEP Homer" }, { 0 , NULL }, }; settings_entry_t entries[] = { { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_BACKGROUND, SETTING_BACKGROUND, "Background * .............................." }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_SYNTAX, SETTING_SYNTAX, "SIP message syntax ........................" }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_SYNTAX_TAG, SETTING_SYNTAX_TAG, "SIP tag syntax ............................" }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_SYNTAX_BRANCH, SETTING_SYNTAX_BRANCH, "SIP branch syntax ........................." }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_ALTKEY_HINT, SETTING_ALTKEY_HINT, "Alternative keybinding hints .............." }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_COLORMODE, SETTING_COLORMODE, "Default message color mode ................" }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_EXITPROMPT, SETTING_EXITPROMPT, "Always prompt on quit ....................." }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_DISPLAY_HOST, SETTING_DISPLAY_HOST, "Replace addresses with resolved hosts ....." }, { CAT_SETTINGS_INTERFACE, FLD_SETTINGS_DISPLAY_ALIAS, SETTING_DISPLAY_ALIAS, "Replace addresses with alias .............." }, { CAT_SETTINGS_CAPTURE, FLD_SETTINGS_CAPTURE_RTP, SETTING_CAPTURE_RTP, "Capture RTP packets * ....................." }, { CAT_SETTINGS_CAPTURE, FLD_SETTINGS_CAPTURE_LIMIT, SETTING_CAPTURE_LIMIT, "Max dialogs * ............................." }, { CAT_SETTINGS_CAPTURE, FLD_SETTINGS_CAPTURE_DEVICE, SETTING_CAPTURE_DEVICE, "Capture device * .........................." }, { CAT_SETTINGS_CAPTURE, FLD_SETTINGS_CAPTURE_LOOKUP, SETTING_CAPTURE_LOOKUP, "Resolved IP Addresses * ..................." }, { CAT_SETTINGS_CAPTURE, FLD_SETTINGS_SIP_NOINCOMPLETE, SETTING_SIP_NOINCOMPLETE, "Capture full transactions ................." }, { CAT_SETTINGS_CAPTURE, FLD_SETTINGS_SIP_CALLS, SETTING_SIP_CALLS, "Only capture calls * ......................" }, { CAT_SETTINGS_CAPTURE, FLD_SETTINGS_SAVEPATH, SETTING_SAVEPATH, "Default Save path ........................." }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_FORCERAW, SETTING_CF_FORCERAW, "Show message preview panel ................" }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_HIGHTLIGHT, SETTING_CF_HIGHTLIGHT, "Selected message hightlight ..............." }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_LOCALHIGHLIGHT, SETTING_CF_LOCALHIGHLIGHT, "Highlight local addresses ................." }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_SPLITCACALLID, SETTING_CF_SPLITCALLID, "Merge columns with same address ..........." }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_SDPONLY, SETTING_CF_SDP_INFO, "Show SDP information in messages .........." }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_DELTA, SETTING_CF_DELTA, "Show delta time between messages .........." }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_MEDIA, SETTING_CF_MEDIA, "Show RTP media streams ...................." }, { CAT_SETTINGS_CALL_FLOW, FLD_SETTINGS_CF_SCROLLSTEP, SETTING_CF_SCROLLSTEP, "Steps for PgUp/PgDown ....................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_SEND, SETTING_EEP_SEND, "Send all captured SIP packets ............." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_SEND_VER, SETTING_EEP_SEND_VER, "Send EEP version .........................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_SEND_ADDR, SETTING_EEP_SEND_ADDR, "Send EEP packet address ..................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_SEND_PORT, SETTING_EEP_SEND_PORT, "Send EEP packet port ......................" }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_SEND_PASS, SETTING_EEP_SEND_PASS, "EEP send password ........................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_LISTEN, SETTING_EEP_LISTEN, "Listen for eep packets ...................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_LISTEN_VER, SETTING_EEP_LISTEN_VER, "Listen EEP version ......................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_LISTEN_ADDR, SETTING_EEP_LISTEN_ADDR, "Listen EEP packet address ................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_LISTEN_PORT, SETTING_EEP_LISTEN_PORT, "Listen EEP packet port ...................." }, { CAT_SETTINGS_EEP_HOMER, FLD_SETTINGS_EEP_LISTEN_PASS, SETTING_EEP_LISTEN_PASS, "EEP server password ......................." }, { 0 , 0, 0, NULL }, }; PANEL * settings_create() { PANEL *panel; WINDOW *win; int height, width, i, j, line; settings_info_t *info; FIELD *entry, *label; int field = 0; // Calculate window dimensions height = 21; width = 70; // Cerate a new window for the panel and form win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); // Create a new panel panel = new_panel(win); // Initialize Filter panel specific data info = sng_malloc(sizeof(settings_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Create a scrollable subwindow for settings info->form_win = derwin(win, height - 11, width - 2, 8, 1); // Configure panel buttons info->buttons[BTN_SETTINGS_ACCEPT] = new_field(1, 10, height - 2, 12, 0, 0); info->buttons[BTN_SETTINGS_SAVE] = new_field(1, 10, height - 2, 29, 0, 0); info->buttons[BTN_SETTINGS_CANCEL] = new_field(1, 10, height - 2, 46, 0, 0); info->buttons[BTN_SETTINGS_COUNT] = NULL; field_opts_off(info->buttons[BTN_SETTINGS_ACCEPT], O_EDIT); field_opts_off(info->buttons[BTN_SETTINGS_SAVE], O_EDIT); field_opts_off(info->buttons[BTN_SETTINGS_CANCEL], O_EDIT); set_field_buffer(info->buttons[BTN_SETTINGS_ACCEPT], 0, "[ Accept ]"); set_field_buffer(info->buttons[BTN_SETTINGS_SAVE], 0, "[ Save ]"); set_field_buffer(info->buttons[BTN_SETTINGS_CANCEL], 0, "[ Cancel ]"); info->buttons_form = new_form(info->buttons); set_form_sub(info->buttons_form, win); post_form(info->buttons_form); // Initialize rest of settings fields for (i = 0; categories[i].cat_id; i++) { // Each category section begins with fields in the first line line = 0; for (j = 0; entries[j].cat_id; j++) { // Ignore entries of other categories if (entries[j].cat_id != categories[i].cat_id) continue; // Create the label label = new_field(1, 45, line, 3, 0, 0); set_field_buffer(label, 0, entries[j].label); field_opts_off(label, O_ACTIVE); // Change field properties according to field type switch(setting_format(entries[j].setting_id)) { case SETTING_FMT_NUMBER: entry = new_field(1, 18, line, 48, 0, 0); set_field_back(entry, A_UNDERLINE); set_field_type(entry, TYPE_REGEXP, "[0-9]+"); break; case SETTING_FMT_STRING: entry = new_field(1, 18, line, 48, 0, 0); field_opts_off(entry, O_STATIC); set_field_back(entry, A_UNDERLINE); break; case SETTING_FMT_ENUM: entry = new_field(1, 12, line, 48, 0, 0); field_opts_off(entry, O_EDIT); set_field_type(entry, TYPE_ENUM, setting_valid_values(entries[j].setting_id), 0, 0); break; } field_opts_off(entry, O_AUTOSKIP); set_field_buffer(entry, 0, setting_get_value(entries[j].setting_id)); set_field_userptr(entry, (void *) &entries[j]); if (line == 0) { // Set last field as page breaker set_new_page(entry, TRUE); } // Store field info->fields[field++] = entry; info->fields[field++] = label; line++; } } // Create the form and post it info->form = new_form(info->fields); set_form_sub(info->form, info->form_win); post_form(info->form); // Set the window title and boxes mvwprintw(win, 1, width / 2 - 5, "Settings"); wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); title_foot_box(panel); mvwhline(win, 6, 1, ACS_HLINE, width - 1); mvwaddch(win, 6, 0, ACS_LTEE); mvwaddch(win, 6, width - 1, ACS_RTEE); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); wattron(win, COLOR_PAIR(CP_CYAN_ON_DEF)); mvwprintw(win, 3, 1, " Use arrow keys, PgUp, PgDown and Tab to move arround settings."); mvwprintw(win, 4, 1, " Settings with (*) requires restart."); wattroff(win, COLOR_PAIR(CP_CYAN_ON_DEF)); // Set default field info->active_form = info->form; set_current_field(info->form, *info->fields); info->active_category = form_page(info->form) + 1; return panel; } void settings_destroy() { curs_set(0); } settings_info_t * settings_info(PANEL *panel) { return (settings_info_t*) panel_userptr(panel); } int settings_draw(PANEL *panel) { WINDOW *win; int field_idx; int i; int cury, curx; // Get panel information settings_info_t *info = settings_info(panel); win = panel_window(panel); // Store cursor position getyx(win, cury, curx); // Get current field id field_idx = field_index(current_field(info->form)); // Print category headers int colpos = 2; for (i = 0; categories[i].cat_id; i++) { if (categories[i].cat_id == info->active_category) { mvwprintw(win, 6, colpos, "%c %s %c", '[', categories[i].title, ']'); } else { wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); mvwprintw(win, 6, colpos, "%c %s %c", '[', categories[i].title, ']'); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); } colpos += strlen(categories[i].title) + 5; } // Reset all field background for (i = 0; i < FLD_SETTINGS_COUNT; i++) { set_field_fore(info->fields[i + 1], A_NORMAL); if (!strncmp(field_buffer(info->fields[i], 0), "on", 2)) set_field_fore(info->fields[i], COLOR_PAIR(CP_GREEN_ON_DEF)); if (!strncmp(field_buffer(info->fields[i], 0), "off", 3)) set_field_fore(info->fields[i], COLOR_PAIR(CP_RED_ON_DEF)); } for (i=0; i < BTN_SETTINGS_COUNT; i++) { set_field_back(info->buttons[i], A_NORMAL); } // Highlight current field if (info->active_form == info->buttons_form) { set_field_back(current_field(info->buttons_form), A_REVERSE); } else { set_field_fore(info->fields[field_index(current_field(info->form)) + 1], A_BOLD); } touchwin(win); // Restore cursor position wmove(win, cury, curx); return 0; } int settings_handle_key(PANEL *panel, int key) { int action = -1; int field_idx; settings_entry_t *entry; enum setting_fmt sett_fmt = -1; // Get panel information settings_info_t *info = settings_info(panel); // Get current field id field_idx = field_index(current_field(info->active_form)); // Get current setting id; if ((entry = ui_settings_is_entry(current_field(info->active_form)))) { sett_fmt = setting_format(entry->setting_id); } // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { if (info->active_form == info->form) { // Check if we handle this action switch (action) { case ACTION_PRINTABLE: if (sett_fmt == SETTING_FMT_NUMBER || sett_fmt == SETTING_FMT_STRING) { form_driver(info->form, key); break; } continue; case ACTION_UP: case ACTION_HPPAGE: form_driver(info->form, REQ_PREV_FIELD); form_driver(info->form, REQ_END_LINE); break; case ACTION_DOWN: case ACTION_HNPAGE: form_driver(info->form, REQ_NEXT_FIELD); form_driver(info->form, REQ_END_LINE); break; case ACTION_SELECT: case ACTION_RIGHT: form_driver(info->form, REQ_NEXT_CHOICE); form_driver(info->form, REQ_RIGHT_CHAR); break; case ACTION_LEFT: form_driver(info->form, REQ_PREV_CHOICE); form_driver(info->form, REQ_LEFT_CHAR); break; case ACTION_NPAGE: form_driver(info->form, REQ_NEXT_PAGE); form_driver(info->form, REQ_END_LINE); info->active_category = form_page(info->form) + 1; break; case ACTION_PPAGE: form_driver(info->form, REQ_PREV_PAGE); form_driver(info->form, REQ_END_LINE); info->active_category = form_page(info->form) + 1; break; case ACTION_BEGIN: form_driver(info->form, REQ_BEG_LINE); break; case ACTION_END: form_driver(info->form, REQ_END_LINE); break; case ACTION_NEXT_FIELD: info->active_form = info->buttons_form; set_current_field(info->active_form, info->buttons[BTN_SETTINGS_ACCEPT]); break; case ACTION_CLEAR: if (sett_fmt == SETTING_FMT_NUMBER || sett_fmt == SETTING_FMT_STRING) { form_driver(info->form, REQ_BEG_LINE); form_driver(info->form, REQ_CLR_EOL); } break; case ACTION_DELETE: if (sett_fmt == SETTING_FMT_NUMBER || sett_fmt == SETTING_FMT_STRING) { form_driver(info->form, REQ_DEL_CHAR); } break; case ACTION_BACKSPACE: if (sett_fmt == SETTING_FMT_NUMBER || sett_fmt == SETTING_FMT_STRING) { form_driver(info->form, REQ_DEL_PREV); } break; case ACTION_CONFIRM: ui_settings_update_settings(panel); return KEY_ESC; default: // Parse next action continue; } } else { // Check if we handle this action switch (action) { case ACTION_RIGHT: case ACTION_DOWN: case ACTION_NEXT_FIELD: if (field_idx == BTN_SETTINGS_CANCEL) { info->active_form = info->form; } else { form_driver(info->buttons_form, REQ_NEXT_FIELD); } break; case ACTION_LEFT: case ACTION_UP: case ACTION_PREV_FIELD: if (field_idx == BTN_SETTINGS_ACCEPT) { info->active_form = info->form; } else { form_driver(info->buttons_form, REQ_PREV_FIELD); } break; case ACTION_SELECT: case ACTION_CONFIRM: if (field_idx == BTN_SETTINGS_CANCEL) return KEY_ESC; if (field_idx == BTN_SETTINGS_SAVE) ui_settings_save(panel); ui_settings_update_settings(panel); return KEY_ESC; default: continue; } } // This panel has handled the key successfully break; } // Validate all input data form_driver(info->active_form, REQ_VALIDATION); // Get current setting id if ((entry = ui_settings_is_entry(current_field(info->active_form)))) { // Enable cursor on string and number fields curs_set(setting_format(entry->setting_id) != SETTING_FMT_ENUM); } else { curs_set(0); } // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } settings_entry_t * ui_settings_is_entry(FIELD *field) { return (settings_entry_t *) field_userptr(field); } int ui_settings_update_settings(PANEL *panel) { int i; char field_value[180]; settings_entry_t *entry; // Get panel information settings_info_t *info = settings_info(panel); for (i=0; i < FLD_SETTINGS_COUNT; i++) { if ((entry = ui_settings_is_entry(info->fields[i]))) { // Get field value. memset(field_value, 0, sizeof(field_value)); strcpy(field_value, field_buffer(info->fields[i], 0)); strtrim(field_value); // Change setting value setting_set_value(entry->setting_id, field_value); } } return 0; } void ui_settings_save(PANEL *panel) { int i; FILE *fi, *fo; char line[1024]; char *home = getenv("HOME"); char userconf[128], tmpfile[128]; char field_value[180]; settings_entry_t *entry; // Get panel information settings_info_t *info = settings_info(panel); // No home dir... if (!home) { dialog_run("Unable to save configuration. User has no $HOME dir."); return; } // Read current $HOME/.sngreprc file sprintf(userconf, "%s/.sngreprc", home); sprintf(tmpfile, "%s/.sngreprc.old", home); // Remove old config file unlink(tmpfile); // Move home file to temporal dir rename(userconf, tmpfile); // Create a new user conf file if (!(fo = fopen(userconf, "w"))) { return; } // Read all lines of old sngreprc file if ((fi = fopen(tmpfile, "r"))) { // Read all configuration file while (fgets(line, 1024, fi) != NULL) { // Ignore lines starting with set (but keep set column ones) if (strncmp(line, "set ", 4) || !strncmp(line, "set cl.column", 13)) { // Put everyting in new .sngreprc file fputs(line, fo); } } fclose(fi); } for (i=0; i < FLD_SETTINGS_COUNT; i++) { if ((entry = ui_settings_is_entry(info->fields[i]))) { // Get field value. memset(field_value, 0, sizeof(field_value)); strcpy(field_value, field_buffer(info->fields[i], 0)); strtrim(field_value); // Change setting value fprintf(fo, "set %s %s\n", setting_name(entry->setting_id), field_value); } } fclose(fo); dialog_run("Settings successfully saved to %s", userconf); } sngrep-1.2.0/src/vector.c0000644000175000017500000001605112632250522014301 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file vector.c * @author Ivan Alonso [aka Kaian] * * @brief Source code of functions defined in vector.h * */ #include "vector.h" #include #include #include #include "util.h" vector_t * vector_create(int limit, int step) { vector_t *v; // Allocate memory for this vector data if (!(v = sng_malloc(sizeof(vector_t)))) return NULL; v->limit = limit; v->step = step; return v; } void vector_destroy(vector_t *vector) { // Nothing to free. Done. if (!vector) return; // Remove all items if a destroyer is set vector_clear(vector); // Deallocate vector list sng_free(vector->list); // Deallocate vector itself sng_free(vector); } vector_t * vector_clone(vector_t *original) { vector_t *clone; vector_iter_t it; void *item; // Check we have a valid vector pointer if (!original) return NULL; // Create a new vector structure clone = vector_create(original->limit, original->step); vector_set_destroyer(clone, original->destroyer); vector_set_sorter(clone, original->sorter); // Fill the clone vector with the same elements it = vector_iterator(original); while ((item = vector_iterator_next(&it))) vector_append(clone, item); // Return the cloned vector return clone; } void vector_clear(vector_t *vector) { // Remove all items in the vector while (vector_first(vector)) vector_remove(vector, vector_first(vector)); } int vector_append(vector_t *vector, void *item) { // Sanity check if (!item) return vector->count; // Check if the vector has been initializated if (!vector->list) { vector->list = sng_malloc(sizeof(void *) * vector->limit); } // Check if we need to increase vector size if (vector->count == vector->limit) { // Increase vector size vector->limit += vector->step; // Add more memory to the list vector->list = realloc(vector->list, sizeof(void *) * vector->limit); } // Add item to the end of the list vector->list[vector->count++] = item; // Check if vector has a sorter if (vector->sorter) { vector->sorter(vector, item); } return vector->count - 1; } int vector_insert(vector_t *vector, void *item, int pos) { if (!item) return vector->count; if (pos < 0 || pos > vector->count) return vector->count; // If possition is occupied, move the other position if (vector->list[pos]) { memmove(vector->list + pos + 1, vector->list + pos, sizeof(void *) * (vector->count - pos)); } // Set the position vector->list[pos] = item; return vector->count; } void vector_remove(vector_t *vector, void *item) { // Get item position int idx = vector_index(vector, item); // Decrease item counter vector->count--; // Move the rest of the elements one position up memmove(vector->list + idx, vector->list + idx + 1, sizeof(void *) * (vector->count - idx)); // Reset vector last position vector->list[vector->count] = NULL; // Destroy the item if vector has a destroyer if (vector->destroyer) { vector->destroyer(item); } } void vector_set_destroyer(vector_t *vector, void (*destroyer) (void *item)) { vector->destroyer = destroyer; } void vector_set_sorter(vector_t *vector, void (*sorter) (vector_t *vector, void *item)) { vector->sorter = sorter; } void vector_generic_destroyer(void *item) { sng_free(item); } void * vector_item(vector_t *vector, int index) { if (!vector || index >= vector->count || index < 0) return NULL; return vector->list[index]; } void vector_set_item(vector_t *vector, int index, void *item) { if (!vector || index >= vector->count || index < 0) return; vector->list[index] = item; } void * vector_first(vector_t *vector) { return vector_item(vector, 0); } void * vector_last(vector_t *vector) { return vector_item(vector, vector_count(vector) - 1); } int vector_index(vector_t *vector, void *item) { // FIXME Bad perfomance int i; for (i = 0; i < vector->count; i++) { if (vector->list[i] == item) return i; } return -1; } int vector_count(vector_t *vector) { return (vector) ? vector->count : 0; } vector_iter_t vector_iterator(vector_t *vector) { vector_iter_t it; memset(&it, 0, sizeof(vector_iter_t)); it.current = -1; it.vector = vector; return it; } vector_t * vector_iterator_vector(vector_iter_t *it) { return it->vector; } int vector_iterator_count(vector_iter_t *it) { int count = 0; int pos = it->current; vector_iterator_reset(it); if (!it->filter) { count = vector_count(it->vector); } else { while (vector_iterator_next(it)) { count++; } } vector_iterator_set_current(it, pos); return count; } void * vector_iterator_next(vector_iter_t *it) { void *item; if (!it || it->current >= vector_count(it->vector)) return NULL; while ((item = vector_item(it->vector, ++it->current))) { if (it->filter) { if (it->filter(item)) { return item; } } else { return item; } } return NULL; } void * vector_iterator_prev(vector_iter_t *it) { void *item; if (it->current == -1) return NULL; while ((item = vector_item(it->vector, --it->current))) { if (it->filter) { if (it->filter(item)) { return item; } } else { return item; } } return NULL; } void vector_iterator_set_filter(vector_iter_t *it, int (*filter)(void *item)) { it->filter = filter; } void vector_iterator_set_current(vector_iter_t *it, int current) { it->current = current; } void vector_iterator_set_last(vector_iter_t *it) { it->current = vector_count(it->vector); } int vector_iterator_current(vector_iter_t *it) { return it->current; } void vector_iterator_reset(vector_iter_t *it) { vector_iterator_set_current(it, -1); } sngrep-1.2.0/src/sip.c0000644000175000017500000005304012632250522013571 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in sip.h */ #include "config.h" #include #include #include #include #include #include #include #include "sip.h" #include "option.h" #include "setting.h" #include "filter.h" /** * @brief Linked list of parsed calls * * All parsed calls will be added to this list, only accesible from * this awesome structure, so, keep it thread-safe. */ sip_call_list_t calls = { 0 }; /* @brief list of methods and responses */ sip_code_t sip_codes[] = { { SIP_METHOD_REGISTER, "REGISTER" }, { SIP_METHOD_INVITE, "INVITE" }, { SIP_METHOD_SUBSCRIBE, "SUBSCRIBE" }, { SIP_METHOD_NOTIFY, "NOTIFY" }, { SIP_METHOD_OPTIONS, "OPTIONS" }, { SIP_METHOD_PUBLISH, "PUBLISH" }, { SIP_METHOD_MESSAGE, "MESSAGE" }, { SIP_METHOD_CANCEL, "CANCEL" }, { SIP_METHOD_BYE, "BYE" }, { SIP_METHOD_ACK, "ACK" }, { SIP_METHOD_PRACK, "PRACK" }, { SIP_METHOD_INFO, "INFO" }, { SIP_METHOD_REFER, "REFER" }, { SIP_METHOD_UPDATE, "UPDATE" }, { 100, "100 Trying" }, { 180, "180 Ringing" }, { 181, "181 Call is Being Forwarded" }, { 182, "182 Queued" }, { 183, "183 Session Progress" }, { 199, "199 Early Dialog Terminated" }, { 200, "200 OK" }, { 202, "202 Accepted" }, { 204, "204 No Notification" }, { 300, "300 Multiple Choices" }, { 301, "301 Moved Permanently" }, { 302, "302 Moved Temporarily" }, { 305, "305 Use Proxy" }, { 380, "380 Alternative Service" }, { 400, "400 Bad Request" }, { 401, "401 Unauthorized" }, { 402, "402 Payment Required" }, { 403, "403 Forbidden" }, { 404, "404 Not Found" }, { 405, "405 Method Not Allowed" }, { 406, "406 Not Acceptable" }, { 407, "407 Proxy Authentication Required" }, { 408, "408 Request Timeout" }, { 409, "409 Conflict" }, { 410, "410 Gone" }, { 411, "411 Length Required" }, { 412, "412 Conditional Request Failed" }, { 413, "413 Request Entity Too Large" }, { 414, "414 Request-URI Too Long" }, { 415, "415 Unsupported Media Type" }, { 416, "416 Unsupported URI Scheme" }, { 417, "417 Unknown Resource-Priority" }, { 420, "420 Bad Extension" }, { 421, "421 Extension Required" }, { 422, "422 Session Interval Too Small" }, { 423, "423 Interval Too Brief" }, { 424, "424 Bad Location Information" }, { 428, "428 Use Identity Header" }, { 429, "429 Provide Referrer Identity" }, { 430, "430 Flow Failed" }, { 433, "433 Anonymity Disallowed" }, { 436, "436 Bad Identity-Info" }, { 437, "437 Unsupported Certificate" }, { 438, "438 Invalid Identity Header" }, { 439, "439 First Hop Lacks Outbound Support" }, { 470, "470 Consent Needed" }, { 480, "480 Temporarily Unavailable" }, { 481, "481 Call/Transaction Does Not Exist" }, { 482, "482 Loop Detected." }, { 483, "483 Too Many Hops" }, { 484, "484 Address Incomplete" }, { 485, "485 Ambiguous" }, { 486, "486 Busy Here" }, { 487, "487 Request Terminated" }, { 488, "488 Not Acceptable Here" }, { 489, "489 Bad Event" }, { 491, "491 Request Pending" }, { 493, "493 Undecipherable" }, { 494, "494 Security Agreement Required" }, { 500, "500 Server Internal Error" }, { 501, "501 Not Implemented" }, { 502, "502 Bad Gateway" }, { 503, "503 Service Unavailable" }, { 504, "504 Server Time-out" }, { 505, "505 Version Not Supported" }, { 513, "513 Message Too Large" }, { 580, "580 Precondition Failure" }, { 600, "600 Busy Everywhere" }, { 603, "603 Decline" }, { 604, "604 Does Not Exist Anywhere" }, { 606, "606 Not Acceptable" }, { -1 , NULL }, }; void sip_init(int limit, int only_calls, int no_incomplete) { int match_flags; // Store capture limit calls.limit = limit; calls.only_calls = only_calls; calls.ignore_incomplete = no_incomplete; // Create a vector to store calls calls.list = vector_create(200, 50); vector_set_destroyer(calls.list, call_destroyer); calls.active = vector_create(10, 10); // Create hash table for callid search hcreate(calls.limit); // Initialize payload parsing regexp match_flags = REG_EXTENDED | REG_ICASE | REG_NEWLINE; regcomp(&calls.reg_method, "^([a-zA-Z]+) sip:[^ ]+ SIP/2.0\r", match_flags & ~REG_NEWLINE); regcomp(&calls.reg_callid, "^(Call-ID|i):[ ]*([^ ]+)\r$", match_flags); regcomp(&calls.reg_xcallid, "^(X-Call-ID|X-CID):[ ]*([^ ]+)\r$", match_flags); regcomp(&calls.reg_response, "^SIP/2.0[ ]*(([0-9]{3}) [^\r]+)\r", match_flags & ~REG_NEWLINE); regcomp(&calls.reg_cseq, "^CSeq:[ ]*([0-9]+) .+\r$", match_flags); regcomp(&calls.reg_from, "^(From|f):[ ]*[^:]*:(([^@]+)@?[^\r>;]+)", match_flags); regcomp(&calls.reg_to, "^(To|t):[ ]*[^:]*:(([^@]+)@?[^\r>;]+)", match_flags); } void sip_deinit() { // Remove all calls sip_calls_clear(); // Remove Call-id hash table hdestroy(); // Remove calls vector vector_destroy(calls.list); vector_destroy(calls.active); // Deallocate regular expressions regfree(&calls.reg_method); regfree(&calls.reg_callid); regfree(&calls.reg_xcallid); regfree(&calls.reg_response); regfree(&calls.reg_cseq); regfree(&calls.reg_from); regfree(&calls.reg_to); } char * sip_get_callid(const char* payload, char *callid) { regmatch_t pmatch[3]; // Try to get Call-ID from payload if (regexec(&calls.reg_callid, payload, 3, pmatch, 0) == 0) { // Copy the matching part of payload strncpy(callid, payload + pmatch[2].rm_so, (int) pmatch[2].rm_eo - pmatch[2].rm_so); } return callid; } char * sip_get_xcallid(const char *payload, char *xcallid) { regmatch_t pmatch[3]; // Try to get X-Call-ID from payload if (regexec(&calls.reg_xcallid, (const char *)payload, 3, pmatch, 0) == 0) { strncpy(xcallid, (const char *)payload + pmatch[2].rm_so, (int)pmatch[2].rm_eo - pmatch[2].rm_so); } return xcallid; } sip_msg_t * sip_check_packet(capture_packet_t *packet) { ENTRY entry; sip_msg_t *msg; sip_call_t *call; char callid[1024], xcallid[1024]; const char *src, *dst; u_short sport, dport; char msg_src[ADDRESSLEN]; char msg_dst[ADDRESSLEN]; u_char payload[MAX_SIP_PAYLOAD]; // Max SIP payload allowed if (packet->payload_len > MAX_SIP_PAYLOAD) return NULL; // Get Addresses from packet src = packet->ip_src; dst = packet->ip_dst; sport = packet->sport; dport = packet->dport; // Initialize local variables memset(callid, 0, sizeof(callid)); memset(xcallid, 0, sizeof(xcallid)); memset(msg_src, 0, sizeof(msg_src)); memset(msg_dst, 0, sizeof(msg_dst)); // Get payload from packet(s) memset(payload, 0, MAX_SIP_PAYLOAD); memcpy(payload, capture_packet_get_payload(packet), capture_packet_get_payload_len(packet)); // Get the Call-ID of this message if (!sip_get_callid((const char*) payload, callid)) return NULL; // Create a new message from this data if (!(msg = msg_create((const char*) payload))) return NULL; // Get Method and request for the following checks // There is no need to parse all payload at this point // If no response or request code is found, this is not a SIP message if (!sip_get_msg_reqresp(msg, payload)) { // Deallocate message memory msg_destroy(msg); return NULL; } // Find the call for this msg if (!(call = sip_find_by_callid(callid))) { // Check if payload matches expression if (!sip_check_match_expression((const char*) payload)) goto skip_message; // User requested only INVITE starting dialogs if (calls.only_calls && msg->reqresp != SIP_METHOD_INVITE) goto skip_message; // Only create a new call if the first msg // is a request message in the following gorup if (calls.ignore_incomplete && msg->reqresp > SIP_METHOD_MESSAGE) goto skip_message; // Get the Call-ID of this message sip_get_xcallid((const char*) payload, xcallid); // Create the call if not found if (!(call = call_create(callid, xcallid))) goto skip_message; // Store this call in hash table entry.key = (char *) call->callid; entry.data = (void *) call; hsearch(entry, ENTER); // Append this call to the call list vector_append(calls.list, call); call->index = vector_count(calls.list); } // Store sorce address. Prefix too long IPv6 addresses with two dots if (strlen(src) > 15) { sprintf(msg_src, "..%s", src + strlen(src) - 13); } else { strcpy(msg_src, src); } // Store destination address. Prefix too long IPv6 addresses with two dots if (strlen(dst) > 15) { sprintf(msg_dst, "..%s", dst + strlen(dst) - 13); } else { strcpy(msg_dst, dst); } // At this point we know we're handling an interesting SIP Packet msg->packet = packet; // Always parse first call message if (call_msg_count(call) == 0) { // Parse SIP payload sip_parse_msg_payload(msg, payload); } // Add the message to the call call_add_message(call, msg); if (call_is_invite(call)) { // Parse media data sip_parse_msg_media(msg, payload); // Update Call State call_update_state(call, msg); // Check if this call should be in active call list if (call_is_active(call)) { if (vector_index(calls.active, call) == -1) { vector_append(calls.active, call); } } else { if (vector_index(calls.active, call) != -1) { vector_remove(calls.active, call); } } } // Return the loaded message return msg; skip_message: // Deallocate message memory msg_destroy(msg); return NULL; } int sip_calls_count() { return vector_count(calls.list); } vector_iter_t sip_calls_iterator() { return vector_iterator(calls.list); } vector_iter_t sip_active_calls_iterator() { return vector_iterator(calls.active); } void sip_calls_stats(int *total, int *displayed) { vector_iter_t it = vector_iterator(calls.list); // Total number of calls without filtering *total = vector_iterator_count(&it); // Total number of calls after filtering vector_iterator_set_filter(&it, filter_check_call); *displayed = vector_iterator_count(&it); } sip_call_t * sip_find_by_index(int index) { return vector_item(calls.list, index); } sip_call_t * sip_find_by_callid(const char *callid) { ENTRY entry, *eptr; entry.key = (char *) callid; if ((eptr = hsearch(entry, FIND))) return eptr->data; return NULL; } sip_call_t * sip_find_by_xcallid(const char *xcallid) { sip_call_t *cur; vector_iter_t it = vector_iterator(calls.list); // Find the call with the given X-Call-Id while ((cur = vector_iterator_next(&it))) { if (strlen(cur->xcallid) && !strcmp(cur->xcallid, xcallid)) { return cur; } } // None found return NULL; } sip_call_t * call_get_xcall(sip_call_t *call) { sip_call_t *xcall; if (strlen(call->xcallid)) { xcall = sip_find_by_callid(call->xcallid); } else { xcall = sip_find_by_xcallid(call->callid); } return xcall; } int sip_get_msg_reqresp(sip_msg_t *msg, const u_char *payload) { regmatch_t pmatch[3]; char reqresp[20]; // If not already parsed if (!msg->reqresp) { // Initialize variables memset(reqresp, 0, sizeof(reqresp)); // Method & CSeq if (regexec(&calls.reg_method, (const char *)payload, 2, pmatch, 0) == 0) { sprintf(reqresp, "%.*s", (int)(pmatch[1].rm_eo - pmatch[1].rm_so), payload + pmatch[1].rm_so); } // Response code if (regexec(&calls.reg_response, (const char *)payload, 3, pmatch, 0) == 0) { sprintf(reqresp, "%.*s", (int)(pmatch[2].rm_eo - pmatch[2].rm_so), payload + pmatch[2].rm_so); } // Get Request/Response Code msg->reqresp = sip_method_from_str(reqresp); } return msg->reqresp; } const char * sip_get_response_str(sip_msg_t *msg, char *out) { regmatch_t pmatch[3]; const char *payload; // If not already parsed if (msg_is_request(msg)) return NULL; // Get message payload payload = msg_get_payload(msg); // Response code (full text) if (regexec(&calls.reg_response, payload, 3, pmatch, 0) == 0) { sprintf(out, "%.*s", (int)(pmatch[1].rm_eo - pmatch[1].rm_so), payload + pmatch[1].rm_so); } return out; } sip_msg_t * sip_parse_msg(sip_msg_t *msg) { if (msg && !msg->cseq) { sip_parse_msg_payload(msg, (u_char*) msg_get_payload(msg)); } return msg; } int sip_parse_msg_payload(sip_msg_t *msg, const u_char *payload) { regmatch_t pmatch[4]; char cseq[11]; // CSeq if (regexec(&calls.reg_cseq, (char*)payload, 2, pmatch, 0) == 0) { sprintf(cseq, "%.*s", (int)(pmatch[1].rm_eo - pmatch[1].rm_so), payload + pmatch[1].rm_so); msg->cseq = atoi(cseq); } // From if (regexec(&calls.reg_from, (const char *)payload, 4, pmatch, 0) == 0) { msg->sip_from = sng_malloc((int)pmatch[2].rm_eo - pmatch[2].rm_so + 1); strncpy(msg->sip_from, (const char *)payload + pmatch[2].rm_so, (int)pmatch[2].rm_eo - pmatch[2].rm_so); } // To if (regexec(&calls.reg_to, (const char *)payload, 4, pmatch, 0) == 0) { msg->sip_to = sng_malloc((int)pmatch[2].rm_eo - pmatch[2].rm_so + 1); strncpy(msg->sip_to, (const char *)payload + pmatch[2].rm_so, (int)pmatch[2].rm_eo - pmatch[2].rm_so); } return 0; } void sip_parse_msg_media(sip_msg_t *msg, const u_char *payload) { char address[ADDRESSLEN]; char media_address[ADDRESSLEN] = { }; char media_type[15] = { }; char media_format[30] = { }; int media_port; u_int media_fmt_pref; u_int media_fmt_code; sdp_media_t *media = NULL; char *payload2, *tofree, *line; sip_call_t *call = msg_get_call(msg); // Initialize variables memset(address, 0, sizeof(address)); // Parse each line of payload looking for sdp information tofree = payload2 = strdup((char*)payload); while ((line = strsep(&payload2, "\r\n")) != NULL) { // Check if we have a media string if (!strncmp(line, "m=", 2)) { if (sscanf(line, "m=%s %d RTP/%*s %u", media_type, &media_port, &media_fmt_pref) == 3) { // Create a new media structure for this message if ((media = media_create(msg))) { media_set_type(media, media_type); media_set_port(media, media_port); media_set_address(media, media_address); media_set_prefered_format(media, media_fmt_pref); msg_add_media(msg, media); /** * From SDP we can only guess destination address port. RTP Capture proccess * will determine when the stream has been completed, getting source address * and port of the stream. */ // Create a new stream with this destination address:port if (!call_msg_is_retrans(msg)) { if (!rtp_find_call_stream(call, 0, 0, media_address, media_port)) { // Create RTP stream call_add_stream(call, stream_create(media, media_address, media_port, CAPTURE_PACKET_RTP)); // Create early RTCP stream call_add_stream(call, stream_create(media, media_address, media_port + 1, CAPTURE_PACKET_RTCP)); } } } } } // Check if we have a connection string if (!strncmp(line, "c=", 2)) { if (sscanf(line, "c=IN IP4 %s", media_address) && media) { media_set_address(media, media_address); } } // Check if we have attribute format string if (!strncmp(line, "a=rtpmap:", 9)) { if (media && sscanf(line, "a=rtpmap:%u %[^ ]", &media_fmt_code, media_format)) { media_add_format(media, media_fmt_code, media_format); } } // Check if we have attribute format RTCP port if (!strncmp(line, "a=rtcp:", 7)) { if (media && sscanf(line, "a=rtcp:%u", &media_port)) { // Create early RTCP stream if (!rtp_find_call_stream(call, 0, 0, media_address, media_port)) { call_add_stream(call, stream_create(media, media_address, media_port, CAPTURE_PACKET_RTCP)); } } } } sng_free(tofree); } void sip_calls_clear() { // Create again the callid hash table hdestroy(); hcreate(calls.limit); // Remove all items from vector vector_clear(calls.list); vector_clear(calls.active); } int sip_set_match_expression(const char *expr, int insensitive, int invert) { // Store expression text calls.match_expr = expr; // Set invert flag calls.match_invert = invert; #ifdef WITH_PCRE const char *re_err = NULL; int32_t err_offset; int32_t pflags = PCRE_UNGREEDY; if (insensitive) pflags |= PCRE_CASELESS; // Check if we have a valid expression calls.match_regex = pcre_compile(expr, pflags, &re_err, &err_offset, 0); return calls.match_regex == NULL; #else int cflags = REG_EXTENDED; // Case insensitive requested if (insensitive) cflags |= REG_ICASE; // Check the expresion is a compilable regexp return regcomp(&calls.match_regex, expr, cflags) != 0; #endif } int sip_check_match_expression(const char *payload) { // Everything matches when there is no match if (!calls.match_expr) return 1; #ifdef WITH_PCRE switch (pcre_exec(calls.match_regex, 0, payload, strlen(payload), 0, 0, 0, 0)) { case PCRE_ERROR_NOMATCH: return 1 == calls.match_invert; } return 0 == calls.match_invert; #else // Check if payload matches the given expresion return (regexec(&calls.match_regex, payload, 0, NULL, 0) == calls.match_invert); #endif } const char * sip_method_str(int method) { int i; // Standard method for (i = 0; sip_codes[i].id > 0; i++) { if (method == sip_codes[i].id) return sip_codes[i].text; } return NULL; } int sip_method_from_str(const char *method) { int i; // Standard method for (i = 0; sip_codes[i].id > 0; i++) { if (!strcmp(method, sip_codes[i].text)) return sip_codes[i].id; } return atoi(method); } const char * sip_transport_str(int transport) { switch(transport) { case CAPTURE_PACKET_SIP_UDP: return "UDP"; case CAPTURE_PACKET_SIP_TCP: return "TCP"; case CAPTURE_PACKET_SIP_TLS: return "TLS"; case CAPTURE_PACKET_SIP_WS: return "WS"; case CAPTURE_PACKET_SIP_WSS: return "WSS"; } return ""; } char * sip_get_msg_header(sip_msg_t *msg, char *out) { char from_addr[80], to_addr[80], time[80], date[80]; // Source and Destination address msg_get_attribute(msg, SIP_ATTR_DATE, date); msg_get_attribute(msg, SIP_ATTR_TIME, time); msg_get_attribute(msg, SIP_ATTR_SRC, from_addr); msg_get_attribute(msg, SIP_ATTR_DST, to_addr); // Get msg header sprintf(out, "%s %s %s -> %s", date, time, from_addr, to_addr); return out; } const char * sip_address_format(const char *address) { // Return address formatted depending on active settings if (setting_enabled(SETTING_DISPLAY_ALIAS)) { return get_alias_value(address); } else if (setting_enabled(SETTING_DISPLAY_HOST)) { return lookup_hostname(address); } else { return address; } } const char * sip_address_port_format(const char *addrport) { static char aport[ADDRESSLEN + 6]; char address[ADDRESSLEN + 6]; int port; strncpy(aport, addrport, sizeof(aport)); if (sscanf(aport, "%[^:]:%d", address, &port) == 2) { sprintf(aport, "%s:%d", sip_address_format(address), port); } return aport; } const char * sip_address_strip_port(char *addrport) { char *colon; if (!addrport) return NULL; // FIXME Make compatible with IPv6 if ((colon = strchr(addrport, ':'))) *colon = '\0'; return addrport; } sngrep-1.2.0/src/ui_msg_diff.h0000644000175000017500000001025412632250522015256 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_msg_diff.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage diff display * */ #ifndef __UI_MSG_DIFF_H #define __UI_MSG_DIFF_H #include "config.h" #include "ui_manager.h" //! Sorter declaration of struct msg_diff_info typedef struct msg_diff_info msg_diff_info_t; /** * @brief Call raw status information * * This data stores the actual status of the panel. It's stored in the * PANEL user pointer. */ struct msg_diff_info { sip_msg_t *one; sip_msg_t *two; WINDOW *one_win; WINDOW *two_win; }; /** * @brief Create Message diff panel * * This function will allocate the ncurses pointer and draw the static * stuff of the screen (which usually won't be redrawn) * It will also create an information structure of the panel status and * store it in the panel's userpointer * * @return the allocated ncurses panel */ PANEL * msg_diff_create(); /** * @brief Deallocate panel memory * * This function will be called from ui manager logic to free * message diff panel memory * * @param panel Ncurses panel pointer */ void msg_diff_destroy(PANEL *panel); /** * @brief Get panel information structure * * All required information of the panel is stored in the info pointer * of the panel. * This function will return the pointer to the info structure of the * panel. * * @return a pointer to the info structure or NULL if no structure exists */ msg_diff_info_t * msg_diff_info(PANEL *panel); /** * @brief Redraw panel data * * This function will be called from ui manager logic when the panels * needs to be redrawn. * * @param panel Ncurses panel pointer * @return 0 in all cases */ int msg_diff_draw(PANEL *panel); /** * @brief Draw panel footer * * Usually panel footer contains useful keybidings. This function * will draw that footer * * @param panel Ncurses panel pointer */ void msg_diff_draw_footer(PANEL *panel); /** * @brief Draw a message into a raw subwindow * * This function will be called for each message that wants to be draw * in the panel. * */ int msg_diff_draw_message(WINDOW *win, sip_msg_t *msg, char *highlight); /** * @brief Handle key strokes * * This function will manage the custom keybindings of the panel. If this * function returns a key value, the ui manager will check if the pressed key * is one of the common ones (like toggle colors and so). * * @param panel Ncurses panel pointer * @param key Pressed keycode * @return 0 if the function can handle the key, key otherwise */ int msg_diff_handle_key(PANEL *panel, int key); /** * @brief Request the panel to show its help * * This function will request to panel to show its help by * invoking its help function. * * @param panel Ncurses panel pointer * @return 0 if the screen has help */ int msg_diff_help(PANEL *panel); /** * @brief Set the panel working messages * * This function will access the panel information and will set the * msg pointers to the processed messages. * * @param panel Ncurses panel pointer * @param one Message pointer to be set in the internal info struct * @param two Message pointer to be set in the internal info struct * @return 0 in all cases */ int msg_diff_set_msgs(PANEL *panel, sip_msg_t *one, sip_msg_t *two); #endif sngrep-1.2.0/src/setting.c0000644000175000017500000002245212632250522014456 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file setting.c * @author Ivan Alonso [aka Kaian] * * @brief Source code of functions defined in setting.h * */ #include "config.h" #include #include #include #include "setting.h" #include "util.h" //! Available configurable settings setting_t settings[SETTING_COUNT] = { { SETTING_BACKGROUND, "background", SETTING_FMT_ENUM, "dark", SETTING_ENUM_BACKGROUND }, { SETTING_COLORMODE, "colormode", SETTING_FMT_ENUM, "request", SETTING_ENUM_COLORMODE }, { SETTING_SYNTAX, "syntax", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_SYNTAX_TAG, "syntax.tag", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_SYNTAX_BRANCH, "syntax.branch", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_ALTKEY_HINT, "hintkeyalt", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_EXITPROMPT, "exitprompt", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_CAPTURE_LIMIT, "capture.limit", SETTING_FMT_NUMBER, "20000", NULL }, { SETTING_CAPTURE_LOOKUP, "capture.lookup", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_CAPTURE_DEVICE, "capture.device", SETTING_FMT_STRING, "any", NULL }, { SETTING_CAPTURE_OUTFILE, "capture.outfile", SETTING_FMT_STRING, "", NULL }, { SETTING_CAPTURE_KEYFILE, "capture.keyfile", SETTING_FMT_STRING, "", NULL }, { SETTING_CAPTURE_RTP, "capture.rtp", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_CAPTURE_STORAGE, "capture.storage", SETTING_FMT_ENUM, "memory", SETTING_ENUM_STORAGE }, { SETTING_SIP_NOINCOMPLETE, "sip.noincomplete", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_SIP_CALLS, "sip.calls", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_SAVEPATH, "savepath", SETTING_FMT_STRING, "", NULL }, { SETTING_DISPLAY_HOST, "displayhost", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_DISPLAY_ALIAS, "displayalias", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_CL_SCROLLSTEP, "cl.scrollstep", SETTING_FMT_NUMBER, "4", NULL }, { SETTING_CL_COLORATTR, "cl.colorattr", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_CL_AUTOSCROLL, "cl.autoscroll", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_CF_FORCERAW, "cf.forceraw", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_CF_RAWMINWIDTH, "cf.rawminwidth", SETTING_FMT_NUMBER, "40", NULL }, { SETTING_CF_RAWFIXEDWIDTH, "cf.rawfixedwidth", SETTING_FMT_NUMBER, "", NULL }, { SETTING_CF_SPLITCALLID, "cf.splitcallid", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_CF_HIGHTLIGHT, "cf.highlight", SETTING_FMT_ENUM, "bold", SETTING_ENUM_HIGHLIGHT }, { SETTING_CF_SCROLLSTEP, "cf.scrollstep", SETTING_FMT_NUMBER, "4", NULL }, { SETTING_CF_LOCALHIGHLIGHT, "cf.localhighlight", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_CF_SDP_INFO, "cf.sdpinfo", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_SDP_INFO }, { SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_MEDIA }, { SETTING_CF_DELTA, "cf.deltatime", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL }, { SETTING_FILTER_METHODS, "filter.methods", SETTING_FMT_STRING, "", NULL }, { SETTING_EEP_SEND, "eep.send", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_EEP_SEND_VER, "eep.send.version", SETTING_FMT_ENUM, "3", SETTING_ENUM_HEPVERSION }, { SETTING_EEP_SEND_ADDR, "eep.send.address", SETTING_FMT_STRING, "10.1.1.1", NULL }, { SETTING_EEP_SEND_PORT, "eep.send.port", SETTING_FMT_NUMBER, "9060", NULL }, { SETTING_EEP_SEND_PASS, "eep.send.pass", SETTING_FMT_STRING, "myHep", NULL }, { SETTING_EEP_LISTEN, "eep.listen", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_EEP_LISTEN_VER, "eep.listen.version", SETTING_FMT_ENUM, "3", SETTING_ENUM_HEPVERSION }, { SETTING_EEP_LISTEN_ADDR, "eep.listen.address", SETTING_FMT_STRING, "0.0.0.0", NULL }, { SETTING_EEP_LISTEN_PORT, "eep.listen.port", SETTING_FMT_NUMBER, "9060", NULL }, { SETTING_EEP_LISTEN_PASS, "eep.listen.pass", SETTING_FMT_STRING, "myHep", NULL }, }; setting_t * setting_by_id(int id) { int i; for (i = 0; i < SETTING_COUNT; i++) { if (id == settings[i].id) return &settings[i]; } return NULL; } setting_t * setting_by_name(const char *name) { int i; for (i = 0; i < SETTING_COUNT; i++) { if (!strcmp(name, settings[i].name)) return &settings[i]; } return NULL; } int setting_id(const char *name) { const setting_t *sett = setting_by_name(name); return (sett) ? sett->id : -1; } const char * setting_name(int id) { const setting_t *sett = setting_by_id(id); return (sett) ? sett->name : NULL; } int setting_format(int id) { const setting_t *sett = setting_by_id(id); return (sett) ? sett->fmt : -1; } const char ** setting_valid_values(int id) { const setting_t *sett = setting_by_id(id); return (sett) ? sett->valuelist : NULL; } const char * setting_get_value(int id) { const setting_t *sett = setting_by_id(id); return (sett && strlen(sett->value)) ? sett->value : NULL; } int setting_get_intvalue(int id) { const setting_t *sett = setting_by_id(id); return (sett && strlen(sett->value)) ? atoi(sett->value) : -1; } void setting_set_value(int id, const char *value) { setting_t *sett = setting_by_id(id); if (sett) { memset(sett->value, 0, sizeof(sett->value)); if (value) { if (strlen(value) < MAX_SETTING_LEN) { strcpy(sett->value, value); } else { fprintf(stderr, "Setting value %s for %s is to long\n", sett->value, sett->name); exit(1); } } } } void setting_set_intvalue(int id, int value) { char strvalue[80]; sprintf(strvalue, "%d", value); setting_set_value(id, strvalue); } int setting_enabled(int id) { return setting_has_value(id, "on") || setting_has_value(id, "yes"); } int setting_disabled(int id) { return setting_has_value(id, "off") || setting_has_value(id, "no"); } int setting_has_value(int id, const char *value) { setting_t *sett = setting_by_id(id); if (sett && sett->value) { return !strcmp(sett->value, value); } return 0; } void setting_toggle(int id) { setting_t *sett = setting_by_id(id); if (sett) { if (sett->fmt == SETTING_FMT_STRING) return; if (sett->fmt == SETTING_FMT_NUMBER) return; if (sett->fmt == SETTING_FMT_ENUM) { setting_set_value(id, setting_enum_next(id, sett->value)); } } } const char * setting_enum_next(int id, const char *value) { int i; const char *vnext; setting_t *sett; if (!(sett = setting_by_id(id))) return NULL; if (sett->fmt != SETTING_FMT_ENUM) return NULL; if (!sett->valuelist) return NULL; // If setting has no value, set the first one if (!value) return *sett->valuelist; // Iterate through valid values for (i = 0; sett->valuelist[i]; i++) { vnext = sett->valuelist[i + 1]; // If current value matches if (!strcmp(sett->valuelist[i], value)) { return (vnext) ? vnext : setting_enum_next(id, NULL); } } return NULL; } void settings_dump() { int i; for (i = 1; i < SETTING_COUNT; i++) { printf("SettingId: %d\t SettingName: %-20s Value: %s\n", i, setting_name(i), setting_get_value(i)); } } sngrep-1.2.0/src/ui_stats.h0000644000175000017500000000402712632250522014637 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013-2015 Ivan Alonso (Kaian) ** Copyright (C) 2013-2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_stats.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage ui window for capture stats display */ #ifndef __UI_STATS_H #define __UI_STATS_H /** * @brief Creates a new stats panel * * This function allocates all required memory for * displaying the stats panel. It also draws all the * static information of the panel that will never be * redrawn. * * @return a panel pointer */ PANEL * stats_create(); /** * @brief Destroy stats panel * * This function do the final cleanups for this panel */ void stats_destroy(); /** * @brief Manage pressed keys for stats panel * * This function is called by UI manager every time a * key is pressed. This allow the filter panel to manage * its own keys. * If this function return 0, the key will not be handled * by ui manager. Otherwise the return will be considered * a key code. * * @param panel Filter panel pointer * @param key key code * @return 0 if the key is handled, keycode otherwise */ int stats_handle_key(PANEL *panel, int key); #endif /* __UI_STATS_H */ sngrep-1.2.0/src/ui_msg_diff.c0000644000175000017500000001522112632250522015250 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_msg_diff.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_msg_diff.h * */ #include #include #include "ui_msg_diff.h" #include "option.h" /*** * * Some basic ascii art of this panel. * * +--------------------------------------------------------+ * | Title | * | First message header | Second message header | * | | | * | First message payload | | * | | | * | | Second message payload | * | | | * | | | * | | | * | | | * | | | * | Usefull hotkeys | * +--------------------------------------------------------+ * */ /** * Ui Structure definition for Message Diff panel */ ui_t ui_msg_diff = { .type = PANEL_MSG_DIFF, .panel = NULL, .create = msg_diff_create, .handle_key = msg_diff_handle_key, .destroy = msg_diff_destroy, .draw = msg_diff_draw, .help = msg_diff_help }; PANEL * msg_diff_create() { PANEL *panel; WINDOW *win; int height, width, hwidth; msg_diff_info_t *info; // Create a new panel to fill all the screen panel = new_panel(newwin(LINES, COLS, 0, 0)); // Initialize panel specific data info = sng_malloc(sizeof(msg_diff_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Let's draw the fixed elements of the screen win = panel_window(panel); getmaxyx(win, height, width); // Calculate subwindows width hwidth = width / 2 - 1; // Create 2 subwindows, one for each message info->one_win = subwin(win, height - 2, hwidth, 1, 0); info->two_win = subwin(win, height - 2, hwidth, 1, hwidth + 1); // Header - Footer - Address // Draw a vertical line to separe both subwindows mvwvline(win, 0, hwidth, ACS_VLINE, height); // Draw title draw_title(panel, "sngrep - SIP messages flow viewer"); // Draw keybindings msg_diff_draw_footer(panel); return panel; } void msg_diff_destroy(PANEL *panel) { sng_free(msg_diff_info(panel)); } msg_diff_info_t * msg_diff_info(PANEL *panel) { return (msg_diff_info_t*) panel_userptr(panel); } int msg_diff_line_highlight(const char* payload1, const char* payload2, char *highlight) { char search[512]; int len, i; // Initialize search terms memset(search, 0, sizeof(search)); len = 0; for (i = 0; i < strlen(payload1); i++) { // Store this char in the search term search[len++] = payload1[i]; // If we have a full line in search array if (payload1[i] == '\n') { // Check if this line is in the other payload if (strstr(payload2, search) == NULL) { // Highlight this line as different from the other payload memset(highlight + i - len + 1, '1', len); } // Reset search terms memset(search, 0, sizeof(search)); len = 0; } } return 0; } void msg_diff_draw_footer(PANEL *panel) { const char *keybindings[] = { key_action_key_str(ACTION_PREV_SCREEN), "Calls Flow", key_action_key_str(ACTION_SHOW_HELP), "Help" }; draw_keybindings(panel, keybindings, 4); } int msg_diff_draw(PANEL *panel) { // Get panel information msg_diff_info_t *info = msg_diff_info(panel); char highlight[4086]; // Draw first message memset(highlight, 0, sizeof(highlight)); msg_diff_line_highlight(msg_get_payload(info->one), msg_get_payload(info->two), highlight); msg_diff_draw_message(info->one_win, info->one, highlight); // Draw second message memset(highlight, 0, sizeof(highlight)); msg_diff_line_highlight(msg_get_payload(info->two), msg_get_payload(info->one), highlight); msg_diff_draw_message(info->two_win, info->two, highlight); // Redraw footer msg_diff_draw_footer(panel); return 0; } int msg_diff_draw_message(WINDOW *win, sip_msg_t *msg, char *highlight) { int height, width, line, column, i; char header[256]; const char * payload = msg_get_payload(msg); // Clear the window werase(win); // Get window of main panel getmaxyx(win, height, width); wattron(win, A_BOLD); mvwprintw(win, 0, 0, sip_get_msg_header(msg, header)); wattroff(win, A_BOLD); // Print msg payload line = 2; column = 0; for (i = 0; i < strlen(payload); i++) { if (payload[i] == '\r') continue; if (column == width || payload[i] == '\n') { line++; column = 0; continue; } if (line == height) break; if (highlight[i] == '1') { wattron(win, COLOR_PAIR(CP_YELLOW_ON_DEF)); } else { wattroff(win, COLOR_PAIR(CP_YELLOW_ON_DEF)); } // Put next character in position mvwaddch(win, line, column++, payload[i]); } // Redraw raw win wnoutrefresh(win); return 0; } int msg_diff_handle_key(PANEL *panel, int key) { return key; } int msg_diff_help(PANEL *panel) { return 0; } int msg_diff_set_msgs(PANEL *panel, sip_msg_t *one, sip_msg_t *two) { msg_diff_info_t *info; // Get panel information info = msg_diff_info(panel); info->one = one; info->two = two; return 0; } sngrep-1.2.0/src/capture_openssl.c0000644000175000017500000003724712632250522016217 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file capture_tls.c * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP TLS transport for messages * * This file contains the functions and structures to manage the SIP messages * that use TLS as transport. * */ #include #include "capture.h" #include "capture_openssl.h" #include "option.h" #include "util.h" #include "sip.h" struct SSLConnection *connections; struct CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = { 0x00, 0x2F }; struct CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = { 0x00, 0x35 }; int P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret, int sslen, unsigned char *seed, int slen) { unsigned char hmac[20]; unsigned int hlen; HMAC_CTX hm; const EVP_MD *md = EVP_get_digestbyname(digest); unsigned int tmpslen; unsigned char tmpseed[slen]; unsigned char *out = dest; int pending = dlen; // Copy initial seed memcpy(tmpseed, seed, slen); tmpslen = slen; // Calculate enough data to fill destination while (pending > 0) { HMAC_Init(&hm, secret, sslen, md); HMAC_Update(&hm, tmpseed, tmpslen); HMAC_Final(&hm, tmpseed, &tmpslen); HMAC_Init(&hm, secret, sslen, md); HMAC_Update(&hm, tmpseed, tmpslen); HMAC_Update(&hm, seed, slen); HMAC_Final(&hm, hmac, &hlen); hlen = (hlen > pending) ? pending : hlen; memcpy(out, hmac, hlen); out += hlen; pending -= hlen; } HMAC_cleanup(&hm); return hlen; } int PRF(unsigned char *dest, int dlen, unsigned char *pre_master_secret, int plen, unsigned char *label, unsigned char *seed, int slen) { int i; // Split the secret by half to generate MD5 and SHA secret parts int hplen = plen / 2 + plen % 2; unsigned char md5_secret[hplen]; unsigned char sha_secret[hplen]; memcpy(md5_secret, pre_master_secret, hplen); memcpy(sha_secret, pre_master_secret + plen / 2, plen / 2); // This vars will store the values of P_MD5 and P_SHA-1 unsigned char h_md5[dlen]; unsigned char h_sha[dlen]; // Concatenate given seed to the label to get the final seed int llen = strlen((const char*) label); unsigned char fseed[slen + llen]; memcpy(fseed, label, llen); memcpy(fseed + llen, seed, slen); // Get enough MD5 and SHA1 data to fill output len P_hash("MD5", h_md5, dlen, pre_master_secret, hplen, fseed, slen + llen); P_hash("SHA1", h_sha, dlen, pre_master_secret + hplen, hplen, fseed, slen + llen); // Final output will be MD5 and SHA1 X-ORed for (i = 0; i < dlen; i++) dest[i] = h_md5[i] ^ h_sha[i]; return dlen; } struct SSLConnection * tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr, u_short sport) { struct SSLConnection *conn = NULL; conn = sng_malloc(sizeof(struct SSLConnection)); memcpy(&conn->client_addr, &caddr, sizeof(struct in_addr)); memcpy(&conn->server_addr, &saddr, sizeof(struct in_addr)); memcpy(&conn->client_port, &cport, sizeof(u_short)); memcpy(&conn->server_port, &sport, sizeof(u_short)); SSL_library_init(); ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); if (!(conn->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) return NULL; SSL_CTX_use_PrivateKey_file(conn->ssl_ctx, capture_get_keyfile(), SSL_FILETYPE_PEM); if (!(conn->ssl = SSL_new(conn->ssl_ctx))) return NULL; conn->server_private_key = SSL_get_privatekey(conn->ssl); // Add this connection to the list conn->next = connections; connections = conn; return conn; } void tls_connection_destroy(struct SSLConnection *conn) { struct SSLConnection *c; // Remove connection from connections list if (conn == connections) { connections = conn->next; } else { for (c = connections; c; c = c->next) { if (c->next == conn) { c->next = conn->next; break; } } } // Deallocate connection memory SSL_CTX_free(conn->ssl_ctx); SSL_free(conn->ssl); sng_free(conn); } /** * FIXME Replace this with a tls_load_key function and use it * in tls_connection_create. * * Most probably we only need one context and key for all connections */ int tls_check_keyfile(const char *keyfile) { SSL *ssl; SSL_CTX *ssl_ctx; SSL_library_init(); ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); if (access(capture_get_keyfile(), R_OK) != 0) return 0; if (!(ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) return 0; SSL_CTX_use_PrivateKey_file(ssl_ctx, capture_get_keyfile(), SSL_FILETYPE_PEM); if (!(ssl = SSL_new(ssl_ctx))) return 0; if (!SSL_get_privatekey(ssl)) return 0; return 1; } int tls_connection_dir(struct SSLConnection *conn, struct in_addr addr, u_short port) { if (conn->client_addr.s_addr == addr.s_addr && conn->client_port == port) return 0; if (conn->server_addr.s_addr == addr.s_addr && conn->server_port == port) return 1; return -1; } struct SSLConnection* tls_connection_find(struct in_addr addr, u_short port) { struct SSLConnection *conn; for (conn = connections; conn; conn = conn->next) { if (tls_connection_dir(conn, addr, port) != -1) { return conn; } } return NULL; } int tls_process_segment(capture_packet_t *packet, struct tcphdr *tcp) { struct SSLConnection *conn; const u_char *payload = capture_packet_get_payload(packet); uint32_t size_payload = capture_packet_get_payload_len(packet); uint8 *out; uint32_t outl = packet->payload_len; out = sng_malloc(outl); struct in_addr ip_src, ip_dst; u_short sport = packet->sport; u_short dport = packet->dport; // Convert addresses inet_pton(AF_INET, packet->ip_src, &ip_src); inet_pton(AF_INET, packet->ip_dst, &ip_dst); // Try to find a session for this ip if ((conn = tls_connection_find(ip_src, sport))) { // Update last connection direction conn->direction = tls_connection_dir(conn, ip_src, sport); // Check current connection state switch (conn->state) { case TCP_STATE_SYN: // First SYN received, this package must be SYN/ACK if (tcp->th_flags & TH_SYN & ~TH_ACK) conn->state = TCP_STATE_SYN_ACK; break; case TCP_STATE_SYN_ACK: // We expect an ACK packet here if (tcp->th_flags & ~TH_SYN & TH_ACK) conn->state = TCP_STATE_ESTABLISHED; break; case TCP_STATE_ACK: case TCP_STATE_ESTABLISHED: // Process data segment! if (tls_process_record(conn, payload, size_payload, &out, &outl) == 0) { if ((int32_t) outl > 0) { capture_packet_set_payload(packet, out, outl); capture_packet_set_type(packet, CAPTURE_PACKET_SIP_TLS); return 0; } } break; case TCP_STATE_FIN: case TCP_STATE_CLOSED: // We can delete this connection tls_connection_destroy(conn); break; } } else { if (tcp->th_flags & TH_SYN & ~TH_ACK) { // New connection, store it status and leave tls_connection_create(ip_src, sport, ip_dst, dport); } } sng_free(out); return 0; } int tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int len, uint8 **out, uint32_t *outl) { struct TLSPlaintext *record; int record_len; const opaque *fragment; // No record data here! if (len == 0) return 0; // Get Record data record = (struct TLSPlaintext *) payload; record_len = sizeof(struct TLSPlaintext) + UINT16_INT(record->length); // Process record fragment if (UINT16_INT(record->length) > 0) { // TLSPlaintext fragment pointer fragment = (opaque *) payload + sizeof(struct TLSPlaintext); switch (record->type) { case handshake: // Hanshake Record, Try to get MasterSecret data if (tls_process_record_handshake(conn, fragment) != 0) return 1; break; case change_cipher_spec: // From now on, this connection will be encrypted using MasterSecret conn->encrypted = 1; break; case application_data: if (conn->encrypted) { // Decrypt application data using MasterSecret tls_process_record_data(conn, fragment, UINT16_INT(record->length), out, outl); } break; default: break; } } // MultiRecord packet if (len > record_len) return tls_process_record(conn, payload + record_len, len - record_len, out, outl); return 0; } int tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment) { struct Handshake *handshake; struct ClientHello *clienthello; struct ServerHello *serverhello; struct ClientKeyExchange *clientkeyex; const opaque *body; // Get Handshake data handshake = (struct Handshake *) fragment; if (UINT24_INT(handshake->length) > 0) { // Hanshake body pointer body = fragment + sizeof(struct Handshake); switch (handshake->type) { case hello_request: break; case client_hello: // Store client random clienthello = (struct ClientHello *) body; memcpy(&conn->client_random, &clienthello->random, sizeof(struct Random)); // Check we have a TLS handshake if (!(clienthello->client_version.major == 0x03 && clienthello->client_version.minor == 0x01)) { tls_connection_destroy(conn); return 1; } break; case server_hello: // Store server random serverhello = (struct ServerHello *) body; memcpy(&conn->server_random, &serverhello->random, sizeof(struct Random)); // Get the selected cipher memcpy(&conn->cipher_suite, body + sizeof(struct ServerHello) + serverhello->session_id_length, sizeof(uint16)); // Check if we have a handled cipher if (tls_connection_load_cipher(conn) != 0) { tls_connection_destroy(conn); return 1; } break; case certificate: case certificate_request: case server_hello_done: case certificate_verify: break; case client_key_exchange: // Decrypt PreMasterKey clientkeyex = (struct ClientKeyExchange *) body; RSA_private_decrypt(UINT16_INT(clientkeyex->length), (const unsigned char *) &clientkeyex->exchange_keys, (unsigned char *) &conn->pre_master_secret, conn->server_private_key->pkey.rsa, RSA_PKCS1_PADDING); unsigned char *seed = sng_malloc(sizeof(struct Random) * 2); memcpy(seed, &conn->client_random, sizeof(struct Random)); memcpy(seed + sizeof(struct Random), &conn->server_random, sizeof(struct Random)); // Get MasterSecret PRF((unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) &conn->pre_master_secret, sizeof(struct PreMasterSecret), (unsigned char *) "master secret", seed, sizeof(struct Random) * 2); memcpy(seed, &conn->server_random, sizeof(struct Random)); memcpy(seed + sizeof(struct Random), &conn->client_random, sizeof(struct Random)); // Generate MACs, Write Keys and IVs PRF((unsigned char *) &conn->key_material, sizeof(struct tls_data), (unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) "key expansion", seed, sizeof(struct Random) * 2); // Done with the seed sng_free(seed); // Create Client decoder EVP_CIPHER_CTX_init(&conn->client_cipher_ctx); EVP_CipherInit(&conn->client_cipher_ctx, conn->ciph, conn->key_material.client_write_key, conn->key_material.client_write_IV, 0); EVP_CIPHER_CTX_init(&conn->server_cipher_ctx); EVP_CipherInit(&conn->server_cipher_ctx, conn->ciph, conn->key_material.server_write_key, conn->key_material.server_write_IV, 0); break; case finished: break; default: if (conn->encrypted) { // Encrypted Hanshake Message unsigned char *decoded = sng_malloc(48); uint32_t decodedlen; tls_process_record_data(conn, fragment, 48, &decoded, &decodedlen); sng_free(decoded); } break; } } return 0; } int tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len, uint8 **out, uint32_t *outl) { EVP_CIPHER_CTX *evp; unsigned char pad; unsigned char *decoded; uint32_t dlen; if (conn->direction == 0) { evp = &conn->client_cipher_ctx; } else { evp = &conn->server_cipher_ctx; } decoded = sng_malloc(len); EVP_Cipher(evp, decoded, (unsigned char *) fragment, len); // Get padding counter and remove from data pad = decoded[len - 1]; dlen = (len - (pad + 1) - /* Trailing MAC */20); if ((int32_t)dlen > 0 && dlen <= *outl) { memcpy(*out, decoded, dlen); *outl = dlen; } // Clenaup decoded memory sng_free(decoded); return *outl; } int tls_connection_load_cipher(struct SSLConnection *conn) { if (conn->cipher_suite.cs1 != 0x00) return 1; if (conn->cipher_suite.cs2 == TLS_RSA_WITH_AES_256_CBC_SHA.cs2) { conn->ciph = EVP_get_cipherbyname("AES256"); } else if (conn->cipher_suite.cs2 == TLS_RSA_WITH_AES_128_CBC_SHA.cs2) { conn->ciph = EVP_get_cipherbyname("AES128"); } else { return 1; } return 0; } sngrep-1.2.0/src/rtp.c0000644000175000017500000002641712632250522013613 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file rtp.c * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage RTP captured packets * * This file contains the functions and structures to manage the RTP streams * */ #include "rtp.h" #include "sip.h" #include "vector.h" /** * @brief Known RTP encodings */ rtp_encoding_t encodings[] = { { 0, "PCMU/8000", "g711u" }, { 3, "GSM/8000", "gsm" }, { 4, "G723/8000", "g723" }, { 5, "DVI4/8000", "dvi" }, { 6, "DVI4/16000", "dvi" }, { 7, "LPC/8000", "lpc" }, { 8, "PCMA/8000", "g711a" }, { 9, "G722/8000", "g722" }, { 10, "L16/44100", "l16" }, { 11, "L16/44100", "l16" }, { 12, "QCELP/8000", "qcelp" }, { 13, "CN/8000", "cn" }, { 14, "MPA/90000", "mpa" }, { 15, "G728/8000", "g728" }, { 16, "DVI4/11025", "dvi" }, { 17, "DVI4/22050", "dvi" }, { 18, "G729/8000", "g729" }, { 25, "CelB/90000", "celb" }, { 26, "JPEG/90000", "jpeg" }, { 28, "nv/90000", "nv" }, { 31, "H261/90000", "h261" }, { 32, "MPV/90000", "mpv" }, { 33, "MP2T/90000", "mp2t" }, { 34, "H263/90000", "h263" }, { 0, NULL, NULL } }; rtp_stream_t * stream_create(sdp_media_t *media, const char *dst, u_short dport, int type) { rtp_stream_t *stream; // Allocate memory for this stream structure if (!(stream = sng_malloc(sizeof(rtp_stream_t)))) return NULL; // Initialize all fields stream->type = type; stream->media = media; strcpy(stream->ip_dst, dst); stream->dport = dport; return stream; } rtp_stream_t * stream_complete(rtp_stream_t *stream, const char *src, u_short sport) { strcpy(stream->ip_src, src); stream->sport = sport; return stream; } void stream_set_format(rtp_stream_t *stream, uint32_t format) { stream->rtpinfo.fmtcode = format; } void stream_add_packet(rtp_stream_t *stream, capture_packet_t *packet) { if (stream->pktcnt == 0) stream->time = capture_packet_get_time(packet); stream->pktcnt++; } uint32_t stream_get_count(rtp_stream_t *stream) { return stream->pktcnt; } struct sip_call * stream_get_call(rtp_stream_t *stream) { if (stream && stream->media && stream->media->msg) return stream->media->msg->call; return NULL; } const char * stream_get_format(rtp_stream_t *stream) { const char *fmt; // Get format for media payload if (!stream || !stream->media) return NULL; // Try to get standard format form code if ((fmt = rtp_get_standard_format(stream->rtpinfo.fmtcode))) return fmt; // Try to get format form SDP payload if ((fmt = media_get_format(stream->media, stream->rtpinfo.fmtcode))) return fmt; // Not found format for this code return NULL; } const char * rtp_get_standard_format(u_int code) { int i; // Format from RTP codec id for (i = 0; encodings[i].format; i++) { if (encodings[i].id == code) return encodings[i].format; } return NULL; } rtp_stream_t * rtp_check_packet(capture_packet_t *packet) { const char *src, *dst; u_short sport, dport; rtp_stream_t *stream; rtp_stream_t *reverse; u_char format = 0; u_char *payload; uint32_t size, bsize; uint16_t len; struct rtcp_hdr_generic hdr; struct rtcp_hdr_sr hdr_sr; struct rtcp_hdr_xr hdr_xr; struct rtcp_blk_xr blk_xr; struct rtcp_blk_xr_voip blk_xr_voip; // Get packet data payload = capture_packet_get_payload(packet); size = capture_packet_get_payload_len(packet); // Get Addresses from packet src = packet->ip_src; dst = packet->ip_dst; sport = packet->sport; dport = packet->dport; // Check if we have at least RTP type if ((int32_t) size < 2) return NULL; // Check RTP version if (RTP_VERSION(*payload) != RTP_VERSION_RFC1889) return NULL; // RTP: even, RTCP: odd if (((packet->dport % 2) == 0)) { // Get RTP payload type format = RTP_PAYLOAD_TYPE(*(payload + 1)); // Find the matching stream stream = rtp_find_stream(src, sport, dst, dport, format); // Check if a valid stream has been found if (!stream) return NULL; // We have found a stream, but with different format if (stream_is_complete(stream) && stream->rtpinfo.fmtcode != format) { // Create a new stream for this new format stream = stream_create(stream->media, dst, dport, CAPTURE_PACKET_RTP); stream_complete(stream, src, sport); stream_set_format(stream, format); call_add_stream(msg_get_call(stream->media->msg), stream); } // First packet for this stream, set source data if (!(stream_is_complete(stream))) { stream_complete(stream, src, sport); stream_set_format(stream, format); // Check if an stream in the opposite direction exists if (!(reverse = rtp_find_call_stream(stream->media->msg->call, stream->ip_dst, stream->dport, stream->ip_src, stream->sport))) { reverse = stream_create(stream->media, stream->ip_src, stream->sport, CAPTURE_PACKET_RTP); stream_complete(reverse, stream->ip_dst, stream->dport); stream_set_format(reverse, format); call_add_stream(msg_get_call(stream->media->msg), reverse); } } // Add packet to stream stream_add_packet(stream, packet); } else { // Find the matching stream if ((stream = rtp_find_stream(src, sport, dst, dport, format))) { // Parse all packet payload headers while ((int32_t) size > 0) { // Check we have at least rtcp generic info if (size < sizeof(struct rtcp_hdr_generic)) break; memcpy(&hdr, payload, sizeof(hdr)); // Check RTP version if (RTP_VERSION(hdr.version) != RTP_VERSION_RFC1889) break; // Header length len = ntohs(hdr.len) * 4 + 4; // Check RTCP packet header typ switch (hdr.type) { case RTCP_HDR_SR: // Get Sender Report header memcpy(&hdr_sr, payload, sizeof(hdr_sr)); stream->rtcpinfo.spc = ntohl(hdr_sr.spc); break; case RTCP_HDR_RR: case RTCP_HDR_SDES: case RTCP_HDR_BYE: case RTCP_HDR_APP: case RTCP_RTPFB: case RTCP_PSFB: break; case RTCP_XR: // Get Sender Report Extended header memcpy(&hdr_xr, payload, sizeof(hdr_xr)); bsize = sizeof(hdr_xr); // Read all report blocks while (bsize < ntohs(hdr_xr.len) * 4 + 4) { // Read block header memcpy(&blk_xr, payload + bsize, sizeof(blk_xr)); // Check block type switch (blk_xr.type) { case RTCP_XR_VOIP_METRCS: memcpy(&blk_xr_voip, payload + sizeof(hdr_xr), sizeof(blk_xr_voip)); stream->rtcpinfo.fdiscard = blk_xr_voip.drate; stream->rtcpinfo.flost = blk_xr_voip.lrate; stream->rtcpinfo.mosl = blk_xr_voip.moslq; stream->rtcpinfo.mosc = blk_xr_voip.moscq; break; default: break; } bsize += ntohs(blk_xr.len) * 4 + 4; } break; case RTCP_AVB: case RTCP_RSI: case RTCP_TOKEN: default: // Not handled headers. Skip the rest of this packet size = 0; break; } payload += len; size -= len; } // Add packet to stream stream_complete(stream, src, sport); stream_add_packet(stream, packet); } } return stream; } rtp_stream_t * rtp_find_stream(const char *src, u_short sport, const char *dst, u_short dport, u_int format) { // Structure for RTP packet streams rtp_stream_t *stream; // Check if this is a RTP packet from active calls sip_call_t *call; // Iterator for active calls vector_iter_t calls; // Get active calls (during conversation) calls = sip_calls_iterator(); //vector_iterator_set_current(&calls, vector_iterator_count(&calls) - 1); while ((call = vector_iterator_next(&calls))) { // Check if this call has an RTP stream for current packet data if ((stream = rtp_find_call_stream(call, src, sport, dst, dport))) { return stream; } } return NULL; } rtp_stream_t * rtp_find_call_stream(struct sip_call *call, const char *ip_src, u_short sport, const char *ip_dst, u_short dport) { rtp_stream_t *stream; vector_iter_t it; // Create an iterator for call streams it = vector_iterator(call->streams); // Look for an incomplete stream with this destination vector_iterator_set_last(&it); while ((stream = vector_iterator_prev(&it))) { if (!strcmp(ip_dst, stream->ip_dst) && dport == stream->dport && !stream->pktcnt) { return stream; } } // Try to look for an incomplete stream with this destination if (ip_src && sport) { vector_iterator_set_last(&it); while ((stream = vector_iterator_prev(&it))) { if (!strcmp(ip_src, stream->ip_src) && sport == stream->sport && !strcmp(ip_dst, stream->ip_dst) && dport == stream->dport) { return stream; } } } // Nothing found return NULL; } int stream_is_older(rtp_stream_t *one, rtp_stream_t *two) { // Yes, you are older than nothing if (!two) return 1; // Otherwise return timeval_is_older(one->time, two->time); } int stream_is_complete(rtp_stream_t *stream) { return (stream->pktcnt != 0); } sngrep-1.2.0/src/ui_call_raw.h0000644000175000017500000000773512632250522015276 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_call_raw.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage Raw output screen of Sip messages * * This file contains the functions and structures to manage the raw message * output screen. * */ #ifndef __UI_CALL_RAW_H #define __UI_CALL_RAW_H #include "config.h" #include "ui_manager.h" //! Sorter declaration of struct call_raw_info typedef struct call_raw_info call_raw_info_t; /** * @brief Call raw status information * * This data stores the actual status of the panel. It's stored in the * PANEL user pointer. */ struct call_raw_info { sip_call_group_t *group; sip_msg_t *msg; sip_msg_t *last; WINDOW *pad; int padline; int scroll; }; /** * @brief Create Call Raw panel * * This function will allocate the ncurses pointer and draw the static * stuff of the screen (which usually won't be redrawn) * It will also create an information structure of the panel status and * store it in the panel's userpointer * * @return the allocated ncurses panel */ PANEL * call_raw_create(); /** * @brief Destroy panel * * This function will hide the panel and free all allocated memory. * * @param panel Ncurses panel pointer */ void call_raw_destroy(PANEL *panel); /** * @brief Get custom information of given panel * * Return ncurses users pointer of the given panel into panel's * information structure pointer. * * @param panel Ncurses panel pointer * @return a pointer to info structure of given panel */ call_raw_info_t * call_raw_info(PANEL *panel); /** * @brief Draw the Call Raw panel * * This function will drawn the panel into the screen based on its stored * status * * @param panel Ncurses panel pointer * @return 0 if the panel has been drawn, -1 otherwise */ int call_raw_draw(PANEL *panel); /** * @brief Draw a message in call Raw * * Draw a new message in the Raw pad. * * @param panel Ncurses panel pointer * @param msg New message to be printed * @return 0 in call cases */ int call_raw_print_msg(PANEL *panel, sip_msg_t *msg); /** * @brief Handle Call Raw key strokes * * This function will manage the custom keybindings of the panel. If this * function returns -1, the ui manager will check if the pressed key * is one of the common ones (like toggle colors and so). * * @param panel Ncurses panel pointer * @param key Pressed keycode * @return 0 if the function can handle the key, key otherwise */ int call_raw_handle_key(PANEL *panel, int key); /** * @brief Set the active call group of the panel * * This function will access the panel information and will set the * call group pointer to the processed calls. * * @param group Call Group pointer to be set in the internal info struct */ int call_raw_set_group(sip_call_group_t *group); /** * @brief Set the active msg of the panel * * This function will access the panel information and will set the * msg pointer to the processed message. * * @param msg Message pointer to be set in the internal info struct */ int call_raw_set_msg(sip_msg_t *msg); #endif sngrep-1.2.0/src/capture.h0000644000175000017500000003424312632250522014452 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file capture.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage pcap files * * sngrep can parse a pcap file to display call flows. * This file include the functions that uses libpcap to do so. * */ #ifndef __SNGREP_CAPTURE_H #define __SNGREP_CAPTURE_H #include "config.h" #include #include #include #include #include #ifndef __FAVOR_BSD #define __FAVOR_BSD #endif #ifndef _BSD_SOURCE #define _BSD_SOURCE 1 #endif #if defined (__OpenBSD__) #define timeval bpf_timeval #endif #if defined(BSD) || defined (__OpenBSD__) || defined(__FreeBSD__) #include #include #include #include #include #endif #ifdef USE_IPV6 #include #endif #include #include #include #include #include #include "vector.h" #ifdef INET6_ADDRSTRLEN #define ADDRESSLEN INET6_ADDRSTRLEN + 1 #else #define ADDRESSLEN 47 #endif //! Max allowed packet assembled size #define MAX_CAPTURE_LEN 20480 //! Define Websocket Transport codes #define WH_FIN 0x80 #define WH_RSV 0x70 #define WH_OPCODE 0x0F #define WH_MASK 0x80 #define WH_LEN 0x7F #define WS_OPCODE_TEXT 0x1 //! Capture modes enum capture_status { CAPTURE_ONLINE = 0, CAPTURE_ONLINE_PAUSED, CAPTURE_OFFLINE, CAPTURE_OFFLINE_LOADING, }; enum capture_storage { CAPTURE_STORAGE_NONE = 0, CAPTURE_STORAGE_MEMORY, CAPTURE_STORAGE_DISK }; //! Shorter declaration of capture_config structure typedef struct capture_config capture_config_t; //; Shorter declaration of capture_info structure typedef struct capture_info capture_info_t; //! Shorter declaration of dns_cache structure typedef struct dns_cache dns_cache_t; //! Shorter declaration of capture_packet structure typedef struct capture_packet capture_packet_t; //! Shorter declaration of capture_frame structure typedef struct capture_frame capture_frame_t; //! Stored packet types enum capture_packet_type { CAPTURE_PACKET_SIP_UDP = 0, CAPTURE_PACKET_SIP_TCP, CAPTURE_PACKET_SIP_TLS, CAPTURE_PACKET_SIP_WS, CAPTURE_PACKET_SIP_WSS, CAPTURE_PACKET_RTP, CAPTURE_PACKET_RTCP, }; /** * @brief Storage for DNS resolved ips * * Structure to store resolved addresses when capture.lookup * configuration option is enabled. */ struct dns_cache { int count; char addr[ADDRESSLEN][256]; char hostname[16][256]; }; /** * @brief Capture common configuration * * Store capture configuration and global data */ struct capture_config { //! Capture status int status; //! Calls capture limit. 0 for disabling int limit; //! Also capture RTP packets int rtp_capture; //! Where should we store captured packets int storage; //! Key file for TLS decrypt const char *keyfile; //! The compiled filter expression struct bpf_program fp; //! libpcap dump file handler pcap_dumper_t *pd; //! Cache for DNS lookups dns_cache_t dnscache; //! Local devices pointer pcap_if_t *devices; //! Capture sources vector_t *sources; //! Packets pending IP reassembly vector_t *ip_reasm; //! Packets pending TCP reassembly vector_t *tcp_reasm; //! Capture Lock. Avoid parsing and handling data at the same time pthread_mutex_t lock; }; /** * @brief store all information related with packet capture * * Store capture required data from one packet source */ struct capture_info { //! libpcap link type int link; //! libpcap link header size int8_t link_hl; //! libpcap capture handler pcap_t *handle; //! Netmask of our sniffing device bpf_u_int32 mask; //! The IP of our sniffing device bpf_u_int32 net; //! Input file in Offline capture const char *infile; //! Capture thread for online capturing pthread_t capture_t; }; /** * Packet capture data. * * One packet can contain more than one frame after * assembly. We assume than one SIP message has one packet * (maybe in multiple frames) and that one packet can only contain * one SIP message. * */ struct capture_packet { // IP protocol uint8_t ip_version; // Transport protocol uint8_t proto; // Packet type as defined in capture_packet_type int type; // Packet source and destination address char ip_src[ADDRESSLEN], ip_dst[ADDRESSLEN]; // Packet source and destination port u_short sport, dport; //! Packet IP id uint16_t ip_id; //! PCAP Packet payload when it can not be get from data u_char *payload; //! Payload length uint32_t payload_len; //! Packet frame list (capture_frame_t) vector_t *frames; }; /** * Capture frame. * One packet can contain multiple frames. */ struct capture_frame { //! PCAP Frame Header data struct pcap_pkthdr *header; //! PCAP Frame content u_char *data; }; /** * @brief Initialize capture data * * @param limit Numbers of calls >0 * @param rtp_catpure Enable rtp capture */ void capture_init(int limit, int rtp_capture); /** * @brief Deinitialize capture data */ void capture_deinit(); /** * @brief Online capture function * * @param device Device to start capture from * @param outfile Dumpfile for captured packets * * @return 0 on spawn success, 1 otherwise */ int capture_online(const char *dev, const char *outfile); /** * @brief Read from pcap file and fill sngrep sctuctures * * This function will use libpcap files and previous structures to * parse the pcap file. * * @param infile File to read packets from * * @return 0 if load has been successfull, 1 otherwise */ int capture_offline(const char *infile, const char *outfile); /** * @brief Read the next package and parse SIP messages * * This function is shared between online and offline capture * methods using pcap. This will get the payload from a package and * add it to the SIP storage layer. * */ void parse_packet(u_char *capinfo, const struct pcap_pkthdr *header, const u_char *packet); /** * @brief Reassembly capture IP fragments * * This function will try to assemble received PCAP data into a single IP packet. * It will return a packet structure if no fragmentation is found or a full packet * has been assembled. * * @note We assume packets higher than MAX_CAPTURE_LEN won't be SIP. This has been * done to avoid reassembling too big packets, that aren't likely to be interesting * for sngrep. * * TODO * Assembly only works when all of the IP fragments are received in the good order. * Properly check memory boundaries during packet reconstruction. * Implement a way to timeout pending IP fragments after some time. * TODO * * @param capinfo Packet capture session information * @para header Header received from libpcap callback * @para packet Packet contents received from libpcap callback * @param size Packet size (not including Layer and Network headers) * @param caplen Full packet size (current fragment -> whole assembled packet) * @return a Packet structure when packet is not fragmented or fully reassembled * @return NULL when packet has not been completely assembled */ capture_packet_t * capture_packet_reasm_ip(capture_info_t *capinfo, const struct pcap_pkthdr *header, u_char *packet, uint32_t *size, uint32_t *caplen); /** * @brief Reassembly capture TCP segments * * This function will try to assemble TCP segments of an existing packet. * * @note We assume packets higher than MAX_CAPTURE_LEN won't be SIP. This has been * done to avoid reassembling too big packets, that aren't likely to be interesting * for sngrep. * * @param packet Capture packet structure * @param tcp TCP header extracted from capture packet data * @param payload Assembled TCP packet payload content * @param size_payload Payload length * @return a Packet structure when packet is not segmented or fully reassembled * @return NULL when packet has not been completely assembled */ capture_packet_t * capture_packet_reasm_tcp(capture_packet_t *packet, struct tcphdr *tcp, u_char *payload, int size_payload); /** * @brief Check if given payload belongs to a Websocket connection * * Parse the given payload and determine if given payload could belong * to a Websocket packet. This function will change the payload pointer * apnd size content to point to the SIP payload data. * * @return 0 if packet is websocket, 1 otherwise */ int capture_ws_check_packet(capture_packet_t *packet); /** * @brief Check if the given packet structure is SIP/RTP/.. * * This function will call parse functions to determine if packet has relevant data * * @return 0 in case this packets has SIP/RTP data * @return 1 otherwise */ int capture_packet_parse(capture_packet_t *pkt); /** * @brief Create a capture thread for online mode * * @return 0 on success, 1 otherwise */ int capture_launch_thread(); /** * @brief PCAP Capture Thread * * This function is used as worker thread for capturing filtered packets and * pass them to the UI layer. */ void capture_thread(void *none); /** * @brief Check if capture is in Online mode * * @return 1 if capture is online, 0 if offline */ int capture_is_online(); /** * @brief Set a bpf filter in open capture * * @param filter String containing the BPF filter text * @return 0 if valid, 1 otherwise */ int capture_set_bpf_filter(const char *filter); /** * @brief Pause/Resume capture * * @param pause 1 to pause capture, 0 to resume */ void capture_set_paused(int pause); /** * @brief Check if capture is actually running * * @return 1 if capture is paused, 0 otherwise */ int capture_is_paused(); /** * @brief Get capture status value */ int capture_get_status(); /** * @brief Return a string representing current capture status */ const char * capture_get_status_desc(); /** * @brief Get Input file from Offline mode * * @return Input file in Offline mode * @return NULL in Online mode */ const char* capture_get_infile(); /** * @brief Get Key file from decrypting TLS packets * * @return given keyfile */ const char* capture_get_keyfile(); /** * @brief Set Keyfile to decrypt TLS packets * * @param keyfile Full path to keyfile */ void capture_set_keyfile(const char *keyfile); /** * @brief Return the last capture error */ char * capture_last_error(); /** * @brief Avoid parsing more packets */ void capture_lock(); /** * @brief Allow parsing more packets */ void capture_unlock(); /** * @brief Allocate memory to store new packet data */ capture_packet_t * capture_packet_create(uint8_t ip_ver, uint8_t proto, const char *ip_src, const char *ip_dst, uint32_t id); /** * @brief Set Transport layer information */ capture_packet_t * capture_packet_set_transport_data(capture_packet_t *pkt, u_short sport, u_short dport, int type); /** * @brief Add a new frame to the given packet */ capture_frame_t * capture_packet_add_frame(capture_packet_t *pkt, const struct pcap_pkthdr *header, const u_char *packet); /** * @brief Deallocate a packet structure memory */ void capture_packet_destroy(capture_packet_t *packet); /** * @brief Destroyer function for packet vectors */ void capture_packet_destroyer(void *packet); /** * @brief Free packet frames data. * * This can be used to avoid storing packet payload in memory or disk */ void capture_packet_free_frames(capture_packet_t *pkt); /** * @brief Set packet type */ void capture_packet_set_type(capture_packet_t *packet, int type); /** * @brief Set packet payload when it can not be get from packet */ void capture_packet_set_payload(capture_packet_t *packet, u_char *payload, uint32_t payload_len); /** * @brief Getter for capture payload size */ uint32_t capture_packet_get_payload_len(capture_packet_t *packet); /** * @brief Getter for capture payload pointer */ u_char * capture_packet_get_payload(capture_packet_t *packet); /** * @brief Get The timestamp for a packet. */ struct timeval capture_packet_get_time(capture_packet_t *packet); /** * @brief Sorter by time for captured packets */ void capture_packet_time_sorter(vector_t *vector, void *item); /** * @brief Close pcap handler */ void capture_close(); /** * @brief Get datalink header size * */ int8_t datalink_size(int datalink); /** * @brief Open a new dumper file for capture handler */ pcap_dumper_t * dump_open(const char *dumpfile); /** * @brief Store a packet in dump file * * File must be previously opened with dump_open */ void dump_packet(pcap_dumper_t *pd, const capture_packet_t *packet); /** * @brief Close a dump file */ void dump_close(pcap_dumper_t *pd); /** * @brief Try to get hostname from its address * * Try to get hostname from the given address, store it in * dnscache. If hostname can not be resolved, then store the * original address to avoid lookup again the same address. */ const char * lookup_hostname(const char *address); /** * @brief Check if a given address belongs to a local device * * @param address IPv4 string format for address * @return 1 if address is local, 0 otherwise */ int is_local_address_str(const char *address); /** * @brief Check if a given address belongs to a local device * * @param address IPv4 format for address * @return 1 if address is local, 0 otherwise */ int is_local_address(in_addr_t address); #endif sngrep-1.2.0/src/capture_eep.c0000644000175000017500000005450012632250522015274 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** Copyright (C) 2012 Homer Project (http://www.sipcapture.org) ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file capture.c * * @author Ivan Alonso [aka Kaian] * @author Alexandr Dubovikov * * @brief Functions to manage eep protocol * * This file contains declaration of structure and functions to send and * receive packet information through HEP-EEP (Extensible Encapsulation Protocol) * * Additional information about HEP-EEP protocol can be found in sipcature * repositories at https://github.com/sipcapture/HEP * * @note Most of this code has been taken from hep-c and sipgrep (originally * written by Alexandr Dubovikov). Modifications of sources to work with * sngrep packet structures has been made by Ivan Alonso (Kaian) * */ #include "config.h" #include #include #include #include #include #include #include "capture_eep.h" #include "util.h" #include "setting.h" capture_eep_config_t eep_cfg = { 0 }; void * accept_eep_client(void *data); int capture_eep_init() { struct addrinfo *ai, hints[1] = { { 0 } }; // Setting for EEP client if (setting_enabled(SETTING_EEP_SEND)) { // Fill configuration structure eep_cfg.capt_version = setting_get_intvalue(SETTING_EEP_SEND_VER); eep_cfg.capt_host = setting_get_value(SETTING_EEP_SEND_ADDR); eep_cfg.capt_port = setting_get_value(SETTING_EEP_SEND_PORT); eep_cfg.capt_password = setting_get_value(SETTING_EEP_SEND_PASS); eep_cfg.capt_id = 2002; hints->ai_flags = AI_NUMERICSERV; hints->ai_family = AF_UNSPEC; hints->ai_socktype = SOCK_DGRAM; hints->ai_protocol = IPPROTO_UDP; if (getaddrinfo(eep_cfg.capt_host, eep_cfg.capt_port, hints, &ai)) { fprintf(stderr, "EEP client: failed getaddrinfo() for %s:%s\n", eep_cfg.capt_host, eep_cfg.capt_port); return 1; } eep_cfg.client_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (eep_cfg.client_sock < 0) { fprintf(stderr, "Sender socket creation failed: %s\n", strerror(errno)); return 1; } if (connect(eep_cfg.client_sock, ai->ai_addr, (socklen_t) (ai->ai_addrlen)) == -1) { if (errno != EINPROGRESS) { fprintf(stderr, "Sender socket creation failed: %s\n", strerror(errno)); return 1; } } } if (setting_enabled(SETTING_EEP_LISTEN)) { // Fill configuration structure eep_cfg.capt_srv_version = setting_get_intvalue(SETTING_EEP_LISTEN_VER); eep_cfg.capt_srv_host = setting_get_value(SETTING_EEP_LISTEN_ADDR); eep_cfg.capt_srv_port = setting_get_value(SETTING_EEP_LISTEN_PORT); eep_cfg.capt_srv_password = setting_get_value(SETTING_EEP_LISTEN_PASS); hints->ai_flags = AI_NUMERICSERV; hints->ai_family = AF_UNSPEC; hints->ai_socktype = SOCK_DGRAM; hints->ai_protocol = IPPROTO_UDP; if (getaddrinfo(eep_cfg.capt_srv_host, eep_cfg.capt_srv_port, hints, &ai)) { fprintf(stderr, "EEP server: failed getaddrinfo() for %s:%s\n", eep_cfg.capt_srv_host, eep_cfg.capt_srv_port); return 1; } // Create a socket for a new TCP IPv4 connection eep_cfg.server_sock = socket(AF_INET, SOCK_DGRAM, 0); if (eep_cfg.client_sock < 0) { fprintf(stderr, "Error creating server socket: %s\n", strerror(errno)); return 1; } // Bind that socket to the requested address and port if (bind(eep_cfg.server_sock, ai->ai_addr, ai->ai_addrlen) == -1) { fprintf(stderr, "Error binding address: %s\n", strerror(errno)); return 1; } // Create a new thread for accepting client connections if (pthread_create(&eep_cfg.server_thread, NULL, accept_eep_client, NULL) != 0) { fprintf(stderr, "Error creating accept thread: %s\n", strerror(errno)); return 1; } } // Settings for EEP server return 0; } void * accept_eep_client(void *data) { capture_packet_t *pkt; // Begin accepting connections while (eep_cfg.server_sock > 0) { if ((pkt = capture_eep_receive())) { // Avoid parsing from multiples sources. // Avoid parsing while screen in being redrawn capture_lock(); if (capture_packet_parse(pkt) != 0) { capture_packet_destroy(pkt); } capture_unlock(); } } // Leave the thread gracefully pthread_exit(NULL); return 0; } void capture_eep_deinit() { if (eep_cfg.client_sock) close(eep_cfg.client_sock); if (eep_cfg.server_sock) { close(eep_cfg.server_sock); eep_cfg.server_sock = -1; //pthread_join(&eep_cfg.server_thread, &ret); } } int capture_eep_send(capture_packet_t *pkt) { // Dont send RTP packets if (pkt->type == CAPTURE_PACKET_RTP) return 1; // Check we have a connection established if (!eep_cfg.client_sock) return 1; switch (eep_cfg.capt_version) { case 2: return capture_eep_send_v2(pkt); case 3: return capture_eep_send_v3(pkt); } return 1; } int capture_eep_send_v2(capture_packet_t *pkt) { void* buffer; unsigned int buflen = 0, tlen = 0; struct hep_hdr hdr; struct hep_timehdr hep_time; struct hep_iphdr hep_ipheader; #ifdef USE_IPV6 struct hep_ip6hdr hep_ip6header; #endif unsigned char *data = capture_packet_get_payload(pkt); unsigned int len = capture_packet_get_payload_len(pkt); capture_frame_t *frame = vector_first(pkt->frames); /* Version && proto */ hdr.hp_v = 2; hdr.hp_f = pkt->ip_version == 4 ? AF_INET : AF_INET6; hdr.hp_p = pkt->proto; hdr.hp_sport = htons(pkt->sport); hdr.hp_dport = htons(pkt->dport); /* Timestamp */ hep_time.tv_sec = frame->header->ts.tv_sec; hep_time.tv_usec = frame->header->ts.tv_usec; hep_time.captid = eep_cfg.capt_id; /* Calculate initial HEP packet size */ tlen = sizeof(struct hep_hdr) + sizeof(struct hep_timehdr); /* IPv4 */ if (pkt->ip_version == 4) { inet_pton(AF_INET, pkt->ip_src, &hep_ipheader.hp_src); inet_pton(AF_INET, pkt->ip_dst, &hep_ipheader.hp_dst); tlen += sizeof(struct hep_iphdr); hdr.hp_l += sizeof(struct hep_iphdr); } #ifdef USE_IPV6 /* IPv6 */ else if(pkt->ip_version == 6) { inet_pton(AF_INET6, pkt->ip_src, &hep_ip6header.hp6_src); inet_pton(AF_INET6, pkt->ip_dst, &hep_ip6header.hp6_dst); tlen += sizeof(struct hep_ip6hdr); hdr.hp_l += sizeof(struct hep_ip6hdr); } #endif // Add payload size to the final size of HEP packet tlen += len; hdr.hp_l = htons(tlen); // Allocate memory for HEPv2 packet if (!(buffer = sng_malloc(tlen))) return 1; // Copy basic headers buflen = 0; memcpy((void*) buffer + buflen, &hdr, sizeof(struct hep_hdr)); buflen += sizeof(struct hep_hdr); // Copy IP header if (pkt->ip_version == 4) { memcpy((void*) buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr)); buflen += sizeof(struct hep_iphdr); } #ifdef USE_IPV6 else if(pkt->ip_version == 6) { memcpy((void*) buffer + buflen, &hep_ip6header, sizeof(struct hep_ip6hdr)); buflen += sizeof(struct hep_ip6hdr); } #endif // Copy TImestamp header memcpy((void*) buffer + buflen, &hep_time, sizeof(struct hep_timehdr)); buflen += sizeof(struct hep_timehdr); // Now copy payload itself memcpy((void*) buffer + buflen, data, len); buflen += len; if (send(eep_cfg.client_sock, buffer, buflen, 0) == -1) { return 1; } /* FREE */ sng_free(buffer); return 1; } int capture_eep_send_v3(capture_packet_t *pkt) { struct hep_generic *hg = NULL; void* buffer; unsigned int buflen = 0, iplen = 0, tlen = 0; hep_chunk_ip4_t src_ip4, dst_ip4; #ifdef USE_IPV6 hep_chunk_ip6_t src_ip6, dst_ip6; #endif hep_chunk_t payload_chunk; hep_chunk_t authkey_chunk; capture_frame_t *frame = vector_first(pkt->frames); unsigned char *data = capture_packet_get_payload(pkt); unsigned int len = capture_packet_get_payload_len(pkt); hg = sng_malloc(sizeof(struct hep_generic)); /* header set "HEP3" */ memcpy(hg->header.id, "\x48\x45\x50\x33", 4); /* IP proto */ hg->ip_family.chunk.vendor_id = htons(0x0000); hg->ip_family.chunk.type_id = htons(0x0001); hg->ip_family.data = pkt->ip_version == 4 ? AF_INET : AF_INET6; hg->ip_family.chunk.length = htons(sizeof(hg->ip_family)); /* Proto ID */ hg->ip_proto.chunk.vendor_id = htons(0x0000); hg->ip_proto.chunk.type_id = htons(0x0002); hg->ip_proto.data = pkt->proto; hg->ip_proto.chunk.length = htons(sizeof(hg->ip_proto)); /* IPv4 */ if (pkt->ip_version == 4) { /* SRC IP */ src_ip4.chunk.vendor_id = htons(0x0000); src_ip4.chunk.type_id = htons(0x0003); inet_pton(AF_INET, pkt->ip_src, &src_ip4.data); src_ip4.chunk.length = htons(sizeof(src_ip4)); /* DST IP */ dst_ip4.chunk.vendor_id = htons(0x0000); dst_ip4.chunk.type_id = htons(0x0004); inet_pton(AF_INET, pkt->ip_dst, &dst_ip4.data); dst_ip4.chunk.length = htons(sizeof(dst_ip4)); iplen = sizeof(dst_ip4) + sizeof(src_ip4); } #ifdef USE_IPV6 /* IPv6 */ else if(pkt->ip_version == 6) { /* SRC IPv6 */ src_ip6.chunk.vendor_id = htons(0x0000); src_ip6.chunk.type_id = htons(0x0005); inet_pton(AF_INET6, pkt->ip_src, &src_ip6.data); src_ip6.chunk.length = htonl(sizeof(src_ip6)); /* DST IPv6 */ dst_ip6.chunk.vendor_id = htons(0x0000); dst_ip6.chunk.type_id = htons(0x0006); inet_pton(AF_INET6, pkt->ip_dst, &dst_ip6.data); dst_ip6.chunk.length = htonl(sizeof(dst_ip6)); iplen = sizeof(dst_ip6) + sizeof(src_ip6); } #endif /* SRC PORT */ hg->src_port.chunk.vendor_id = htons(0x0000); hg->src_port.chunk.type_id = htons(0x0007); hg->src_port.data = htons(pkt->sport); hg->src_port.chunk.length = htons(sizeof(hg->src_port)); /* DST PORT */ hg->dst_port.chunk.vendor_id = htons(0x0000); hg->dst_port.chunk.type_id = htons(0x0008); hg->dst_port.data = htons(pkt->dport); hg->dst_port.chunk.length = htons(sizeof(hg->dst_port)); /* TIMESTAMP SEC */ hg->time_sec.chunk.vendor_id = htons(0x0000); hg->time_sec.chunk.type_id = htons(0x0009); hg->time_sec.data = htonl(frame->header->ts.tv_sec); hg->time_sec.chunk.length = htons(sizeof(hg->time_sec)); /* TIMESTAMP USEC */ hg->time_usec.chunk.vendor_id = htons(0x0000); hg->time_usec.chunk.type_id = htons(0x000a); hg->time_usec.data = htonl(frame->header->ts.tv_usec); hg->time_usec.chunk.length = htons(sizeof(hg->time_usec)); /* Protocol TYPE */ hg->proto_t.chunk.vendor_id = htons(0x0000); hg->proto_t.chunk.type_id = htons(0x000b); hg->proto_t.data = 1; hg->proto_t.chunk.length = htons(sizeof(hg->proto_t)); /* Capture ID */ hg->capt_id.chunk.vendor_id = htons(0x0000); hg->capt_id.chunk.type_id = htons(0x000c); hg->capt_id.data = htons(eep_cfg.capt_id); hg->capt_id.chunk.length = htons(sizeof(hg->capt_id)); /* Payload */ payload_chunk.vendor_id = htons(0x0000); payload_chunk.type_id = htons(0x000f); payload_chunk.length = htons(sizeof(payload_chunk) + len); tlen = sizeof(struct hep_generic) + len + iplen + sizeof(hep_chunk_t); /* auth key */ if (eep_cfg.capt_password != NULL) { tlen += sizeof(hep_chunk_t); /* Auth key */ authkey_chunk.vendor_id = htons(0x0000); authkey_chunk.type_id = htons(0x000e); authkey_chunk.length = htons(sizeof(authkey_chunk) + strlen(eep_cfg.capt_password)); tlen += strlen(eep_cfg.capt_password); } /* total */ hg->header.length = htons(tlen); if (!(buffer = sng_malloc(tlen))) { sng_free(hg); return 1; } memcpy((void*) buffer, hg, sizeof(struct hep_generic)); buflen = sizeof(struct hep_generic); /* IPv4 */ if (pkt->ip_version == 4) { /* SRC IP */ memcpy((void*) buffer + buflen, &src_ip4, sizeof(struct hep_chunk_ip4)); buflen += sizeof(struct hep_chunk_ip4); memcpy((void*) buffer + buflen, &dst_ip4, sizeof(struct hep_chunk_ip4)); buflen += sizeof(struct hep_chunk_ip4); } #ifdef USE_IPV6 /* IPv6 */ else if(pkt->ip_version == 6) { /* SRC IPv6 */ memcpy((void*) buffer+buflen, &src_ip4, sizeof(struct hep_chunk_ip6)); buflen += sizeof(struct hep_chunk_ip6); memcpy((void*) buffer+buflen, &dst_ip6, sizeof(struct hep_chunk_ip6)); buflen += sizeof(struct hep_chunk_ip6); } #endif /* AUTH KEY CHUNK */ if (eep_cfg.capt_password != NULL) { memcpy((void*) buffer + buflen, &authkey_chunk, sizeof(struct hep_chunk)); buflen += sizeof(struct hep_chunk); /* Now copying payload self */ memcpy((void*) buffer + buflen, eep_cfg.capt_password, strlen(eep_cfg.capt_password)); buflen += strlen(eep_cfg.capt_password); } /* PAYLOAD CHUNK */ memcpy((void*) buffer + buflen, &payload_chunk, sizeof(struct hep_chunk)); buflen += sizeof(struct hep_chunk); /* Now copying payload itself */ memcpy((void*) buffer + buflen, data, len); buflen += len; if (send(eep_cfg.client_sock, buffer, buflen, 0) == -1) { return 1; } /* FREE */ sng_free(buffer); sng_free(hg); return 0; } capture_packet_t * capture_eep_receive() { switch (eep_cfg.capt_srv_version) { case 2: return capture_eep_receive_v2(); case 3: return capture_eep_receive_v3(); } return NULL; } capture_packet_t * capture_eep_receive_v2() { uint8_t family, proto; unsigned char *payload = 0; unsigned int pos; char buffer[MAX_CAPTURE_LEN] ; //! Source and Destination Address char ip_src[ADDRESSLEN], ip_dst[ADDRESSLEN]; //! Source and Destination Port u_short sport, dport; //! Packet header struct pcap_pkthdr header; //! New created packet pointer capture_packet_t *pkt; //! EEP client data struct sockaddr eep_client; socklen_t eep_client_len; struct hep_hdr hdr; struct hep_timehdr hep_time; struct hep_iphdr hep_ipheader; #ifdef USE_IPV6 struct hep_ip6hdr hep_ip6header; #endif // Initialize buffer memset(buffer, 0, MAX_CAPTURE_LEN); /* Receive EEP generic header */ if (recvfrom(eep_cfg.server_sock, buffer, MAX_CAPTURE_LEN, 0, &eep_client, &eep_client_len) == -1) return NULL; /* Copy initial bytes to HEPv2 header */ memcpy(&hdr, buffer, sizeof(struct hep_hdr)); // Check HEP version if (hdr.hp_v != 2) return NULL; /* IP proto */ family = hdr.hp_f; /* Proto ID */ proto = hdr.hp_p; pos = sizeof(struct hep_hdr); /* IPv4 */ if (family == AF_INET) { memcpy(&hep_ipheader, (void*) buffer + pos, sizeof(struct hep_iphdr)); inet_ntop(AF_INET, &hep_ipheader.hp_src, ip_src, sizeof(ip_src)); inet_ntop(AF_INET, &hep_ipheader.hp_dst, ip_dst, sizeof(ip_dst)); pos += sizeof(struct hep_iphdr); } #ifdef USE_IPV6 /* IPv6 */ else if(family == AF_INET6) { memcpy(&hep_ip6header, (void*) buffer + pos, sizeof(struct hep_ip6hdr)); inet_ntop(AF_INET6, &hep_ip6header.hp6_src, ip_src, sizeof(ip_src)); inet_ntop(AF_INET6, &hep_ip6header.hp6_dst, ip_dst, sizeof(ip_dst)); pos += sizeof(struct hep_ip6hdr); } #endif /* PORTS */ sport = ntohs(hdr.hp_sport); dport = ntohs(hdr.hp_dport); /* TIMESTAMP*/ memcpy(&hep_time, (void*) buffer + pos, sizeof(struct hep_timehdr)); pos += sizeof(struct hep_timehdr); header.ts.tv_sec = hep_time.tv_sec; header.ts.tv_usec = hep_time.tv_usec; /* Protocol TYPE */ /* Capture ID */ // Calculate payload size (Total size - headers size) header.caplen = header.len = ntohs(hdr.hp_l) - pos; // Copy packet payload payload = sng_malloc(header.caplen + 1); memcpy(payload, (void*) buffer + pos, header.caplen); // Create a new packet pkt = capture_packet_create((family == AF_INET) ? 4 : 6, proto, ip_src, ip_dst, 0); capture_packet_add_frame(pkt, &header, payload); capture_packet_set_transport_data(pkt, sport, dport, CAPTURE_PACKET_SIP_UDP); capture_packet_set_payload(pkt, payload, header.caplen); /* FREE */ sng_free(payload); return pkt; } capture_packet_t * capture_eep_receive_v3() { struct hep_generic hg; hep_chunk_ip4_t src_ip4, dst_ip4; #ifdef USE_IPV6 hep_chunk_ip6_t src_ip6, dst_ip6; #endif hep_chunk_t payload_chunk; hep_chunk_t authkey_chunk; uint8_t family, proto; char password[100]; int password_len; unsigned char *payload = 0; unsigned int len, pos; char buffer[MAX_CAPTURE_LEN] ; //! Source and Destination Address char ip_src[ADDRESSLEN], ip_dst[ADDRESSLEN]; //! EEP client data struct sockaddr eep_client; socklen_t eep_client_len; //! Source and Destination Port u_short sport, dport; //! Packet header struct pcap_pkthdr header; //! New created packet pointer capture_packet_t *pkt; /* Receive EEP generic header */ if (recvfrom(eep_cfg.server_sock, buffer, MAX_CAPTURE_LEN, 0, &eep_client, &eep_client_len) == -1) return NULL; /* Copy initial bytes to EEP Generic header */ memcpy(&hg, buffer, sizeof(struct hep_generic)); /* header check */ if (memcmp(hg.header.id, "\x48\x45\x50\x33", 4) != 0) return NULL; /* IP proto */ family = hg.ip_family.data; /* Proto ID */ proto = hg.ip_proto.data; len = ntohs(hg.header.length) - sizeof(struct hep_generic); pos = sizeof(struct hep_generic); /* IPv4 */ if (family == AF_INET) { /* SRC IP */ memcpy(&src_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4)); inet_ntop(AF_INET, &src_ip4.data, ip_src, sizeof(ip_src)); pos += sizeof(struct hep_chunk_ip4); /* DST IP */ memcpy(&dst_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4)); inet_ntop(AF_INET, &dst_ip4.data, ip_dst, sizeof(ip_dst)); pos += sizeof(struct hep_chunk_ip4); } #ifdef USE_IPV6 /* IPv6 */ else if(family == AF_INET6) { /* SRC IPv6 */ memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6)); inet_ntop(AF_INET6, &src_ip6.data, ip_src, sizeof(ip_src)); pos += sizeof(struct hep_chunk_ip6); /* DST IP */ memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6)); inet_ntop(AF_INET6, &dst_ip6.data, ip_dst, sizeof(ip_dst)); pos += sizeof(struct hep_chunk_ip6); } #endif /* SRC PORT */ sport = ntohs(hg.src_port.data); /* DST PORT */ dport = ntohs(hg.dst_port.data); /* TIMESTAMP*/ header.ts.tv_sec = ntohl(hg.time_sec.data); header.ts.tv_usec = ntohl(hg.time_usec.data); /* Protocol TYPE */ /* Capture ID */ /* auth key */ if (eep_cfg.capt_srv_password != NULL) { memcpy(&authkey_chunk, (void*) buffer + pos, sizeof(authkey_chunk)); pos += sizeof(authkey_chunk); password_len = ntohs(authkey_chunk.length) - sizeof(authkey_chunk); memcpy(password, (void*) buffer + pos, password_len); pos += password_len; // Validate the password if (strncmp(password, eep_cfg.capt_srv_password, password_len) != 0) return NULL; } /* Payload */ memcpy(&payload_chunk, (void*) buffer + pos, sizeof(payload_chunk)); pos += sizeof(payload_chunk); // Calculate payload size header.caplen = header.len = ntohs(payload_chunk.length) - sizeof(payload_chunk); // Receive packet payload payload = sng_malloc(header.caplen); memcpy(payload, (void*) buffer + pos, header.caplen); // Create a new packet pkt = capture_packet_create((family == AF_INET)?4:6, proto, ip_src, ip_dst, 0); capture_packet_add_frame(pkt, &header, payload); capture_packet_set_transport_data(pkt, sport, dport, CAPTURE_PACKET_SIP_UDP); capture_packet_set_payload(pkt, payload, header.caplen); /* FREE */ sng_free(payload); return pkt; } int capture_eep_set_server_url(const char *url) { char urlstr[256]; char address[256], port[256]; memset(urlstr, 0, sizeof(urlstr)); memset(address, 0, sizeof(address)); memset(port, 0, sizeof(port)); strncpy(urlstr, url, strlen(url)); if (sscanf(urlstr, "%*[^:]:%[^:]:%s", address, port) == 2) { setting_set_value(SETTING_EEP_LISTEN, SETTING_ON); setting_set_value(SETTING_EEP_LISTEN_ADDR, address); setting_set_value(SETTING_EEP_LISTEN_PORT, port); return 0; } return 1; } int capture_eep_set_client_url(const char *url) { char urlstr[256]; char address[256], port[256]; memset(urlstr, 0, sizeof(urlstr)); memset(address, 0, sizeof(address)); memset(port, 0, sizeof(port)); strncpy(urlstr, url, strlen(url)); if (sscanf(urlstr, "%*[^:]:%[^:]:%s", address, port) == 2) { setting_set_value(SETTING_EEP_SEND, SETTING_ON); setting_set_value(SETTING_EEP_SEND_ADDR, address); setting_set_value(SETTING_EEP_SEND_PORT, port); return 0; } return 1; } sngrep-1.2.0/src/sip_attr.c0000644000175000017500000001235712632250522014631 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip_attr.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in sip_attr.h * */ #include "config.h" #include #include #include #include "option.h" #include "sip_attr.h" #include "util.h" #include "ui_manager.h" static sip_attr_hdr_t attrs[SIP_ATTR_COUNT] = { { SIP_ATTR_CALLINDEX, "index", "Idx", "Call Index", 4 }, { SIP_ATTR_SIPFROM, "sipfrom", NULL, "SIP From", 25 }, { SIP_ATTR_SIPFROMUSER, "sipfromuser", NULL, "SIP From User", 20 }, { SIP_ATTR_SIPTO, "sipto", NULL, "SIP To", 25 }, { SIP_ATTR_SIPTOUSER, "siptouser", NULL, "SIP To User", 20 }, { SIP_ATTR_SRC, "src", NULL, "Source", 22 }, { SIP_ATTR_DST, "dst", NULL, "Destination", 22 }, { SIP_ATTR_CALLID, "callid", NULL, "Call-ID", 50 }, { SIP_ATTR_XCALLID, "xcallid", NULL, "X-Call-ID", 50 }, { SIP_ATTR_DATE, "date", NULL, "Date", 10 }, { SIP_ATTR_TIME, "time", NULL, "Time", 8 }, { SIP_ATTR_METHOD, "method", NULL, "Method", 10, sip_attr_color_method }, { SIP_ATTR_SDP_ADDRESS, "sdpaddress", NULL, "SDP Address", 22 }, { SIP_ATTR_SDP_PORT, "sdpport", NULL, "SDP Port", 5 }, { SIP_ATTR_TRANSPORT, "transport", "Trans", "Transport", 3 }, { SIP_ATTR_MSGCNT, "msgcnt", "Msgs", "Message Count", 5 }, { SIP_ATTR_CALLSTATE, "state", NULL, "Call State", 10, sip_attr_color_state }, { SIP_ATTR_CONVDUR, "convdur", "ConvDur", "Conversation Duration", 7 }, { SIP_ATTR_TOTALDUR, "totaldur", "TotalDur", "Total Duration", 8 } }; sip_attr_hdr_t * sip_attr_get_header(enum sip_attr_id id) { return &attrs[id]; } const char * sip_attr_get_description(enum sip_attr_id id) { sip_attr_hdr_t *header; if ((header = sip_attr_get_header(id))) { return header->desc; } return NULL; } const char * sip_attr_get_title(enum sip_attr_id id) { sip_attr_hdr_t *header; if ((header = sip_attr_get_header(id))) { if (header->title) return header->title; return header->desc; } return NULL; } const char * sip_attr_get_name(enum sip_attr_id id) { sip_attr_hdr_t *header; if ((header = sip_attr_get_header(id))) { return header->name; } return NULL; } int sip_attr_get_width(enum sip_attr_id id) { sip_attr_hdr_t *header; if ((header = sip_attr_get_header(id))) { return header->dwidth; } return 0; } enum sip_attr_id sip_attr_from_name(const char *name) { int i; for (i = 0; i < SIP_ATTR_COUNT; i++) { if (!strcasecmp(name, attrs[i].name)) { return attrs[i].id; } } return -1; } int sip_attr_get_color(int id, const char *value) { sip_attr_hdr_t *header; if (!setting_enabled(SETTING_CL_COLORATTR)) return 0; if ((header = sip_attr_get_header(id))) { if (header->color) { return header->color(value); } } return 0; } int sip_attr_color_method(const char *value) { switch (sip_method_from_str(value)) { case SIP_METHOD_INVITE: return COLOR_PAIR(CP_RED_ON_DEF) | A_BOLD; case SIP_METHOD_NOTIFY: return COLOR_PAIR(CP_YELLOW_ON_DEF); case SIP_METHOD_OPTIONS: return COLOR_PAIR(CP_YELLOW_ON_DEF); case SIP_METHOD_REGISTER: return COLOR_PAIR(CP_MAGENTA_ON_DEF); case SIP_METHOD_SUBSCRIBE: return COLOR_PAIR(CP_BLUE_ON_DEF); default: return 0; } } int sip_attr_color_state(const char *value) { if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_CALLSETUP))) return COLOR_PAIR(CP_YELLOW_ON_DEF); if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_INCALL))) return COLOR_PAIR(CP_BLUE_ON_DEF); if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_COMPLETED))) return COLOR_PAIR(CP_GREEN_ON_DEF); if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_CANCELLED))) return COLOR_PAIR(CP_RED_ON_DEF); if (!strcmp(value, call_state_to_str(SIP_CALLSTATE_REJECTED))) return COLOR_PAIR(CP_RED_ON_DEF); return 0; } sngrep-1.2.0/src/ui_call_list.h0000644000175000017500000001674712632250522015463 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_call_list.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage Call List screen * * This file contains the functions and structures to manage the call list * screen. * */ #ifndef __UI_CALL_LIST_H #define __UI_CALL_LIST_H #include "ui_manager.h" /** * @brief Enum of available fields * */ enum call_list_field_list { FLD_LIST_FILTER = 0, //! Never remove this field id FLD_LIST_COUNT }; //! Sorter declaration of call_list_column struct typedef struct call_list_column call_list_column_t; //! Sorter declaration of call_list_info struct typedef struct call_list_info call_list_info_t; /** * @brief Call List column information * * It will be nice make which columns will appear in this list and * in which order a configurable option. * This structure is one step towards configurable stuff */ struct call_list_column { enum sip_attr_id id; const char *attr; const char *title; int width; }; /** * @brief Call List panel status information * * This data stores the actual status of the panel. It's stored in the * panel pointer. */ struct call_list_info { //! Displayed calls iterator vector_iter_t calls; //! First displayed call, for drawing faster int first_call; //! First displayed call counter, for drawing scroll arrow faster int first_line; //! Selected call in the list int cur_call; //! Selected calls with space sip_call_group_t *group; //! Displayed column list, make it configurable in the future call_list_column_t columns[SIP_ATTR_COUNT]; //! Displayed column count. int columncnt; //! Stores the current selected line int cur_line; //! List subwindow WINDOW *list_win; //! Form that contains the display filter FORM *form; //! An array of window form fields FIELD *fields[FLD_LIST_COUNT + 1]; //! We're entering keys on form int form_active; //! Number of calls displayed in the list int dispcallcnt; //! Total number of calls without filtering int callcnt; //! Move to last list entry if autoscroll is enabled int autoscroll; }; /** * @brief Create Call List panel * * This function will allocate the ncurses pointer and draw the static * stuff of the screen (which usually won't be redrawn) * It will also create an information structure of the panel status and * store it in the panel's userpointer * * @return the allocated ncurses panel */ PANEL * call_list_create(); /** * @brief Destroy panel * * This function will hide the panel and free all allocated memory. * * @param panel Ncurses panel pointer */ void call_list_destroy(PANEL *panel); /** * @brief Get custom information of given panel * * Return ncurses users pointer of the given panel into panel's * information structure pointer. * * @param panel Ncurses panel pointer * @return a pointer to info structure of given panel */ call_list_info_t * call_list_info(PANEL *panel); /** * @brief Resize the windows of Call List * * This function will be invoked when the ui size has changed * * @param panel Ncurses panel pointer * @return 0 if the panel has been resized, -1 otherwise */ int call_list_resize(PANEL *panel); /** * @brief Draw panel header * * This funtion will draw Call list header * * @param panel Ncurses panel pointer */ void call_list_draw_header(PANEL *panel); /** * @brief Draw panel footer * * This funtion will draw Call list footer that contains * keybinginds * * @param panel Ncurses panel pointer */ void call_list_draw_footer(PANEL *panel); /** * @brief Draw panel list contents * * This funtion will draw Call list dialogs list * * @param panel Ncurses panel pointer */ void call_list_draw_list(PANEL *panel); /** * @brief Draw the Call list panel * * This function will drawn the panel into the screen based on its stored * status * * @param panel Ncurses panel pointer * @return 0 if the panel has been drawn, -1 otherwise */ int call_list_draw(PANEL *panel); /** * @brief Enable/Disable Panel form focus * * Enable or disable form fields focus so the next input will be * handled by call_list_handle_key or call_list_handle_form_key * This will also set properties in fields to show them as focused * and show/hide the cursor * * @param panel Ncurses panel pointer * @param active Enable/Disable flag */ void call_list_form_activate(PANEL *panel, int active); /** * @brief Get List line from the given call * * Get the list line of the given call to display in the list * This line is built using the configured columns and sizes * * @param panel Ncurses panel pointer * @param call Call to get data from * @param text Text pointer to store the generated line * @return A pointer to text */ const char* call_list_line_text(PANEL *panel, sip_call_t *call, char *text); /** * @brief Handle Call list key strokes * * This function will manage the custom keybindings of the panel. If this * function returns -1, the ui manager will check if the pressed key * is one of the common ones (like toggle colors and so). * * @param panel Ncurses panel pointer * @param key Pressed keycode * @return 0 if the function can handle the key, key otherwise */ int call_list_handle_key(PANEL *panel, int key); /** * @brief Handle Forms entries key strokes * * This function will manage the custom keybindings of the panel form. * * @param panel Ncurses panel pointer * @param key Pressed keycode * @return 0 if the function can handle the key, key otherwise */ int call_list_handle_form_key(PANEL *panel, int key); /** * @brief Request the panel to show its help * * This function will request to panel to show its help (if any) by * invoking its help function. * * @param panel Ncurses panel pointer * @return 0 if the screen has help, -1 otherwise */ int call_list_help(PANEL *panel); /** * @brief Add a column the Call List * * This function will add a new column to the Call List panel * @todo Columns are not configurable yet. * * @param panel Ncurses panel pointer * @param id SIP call attribute id * @param attr SIP call attribute name * @param title SIP call attribute description * @param width Column Width * @return 0 if column has been successufly added to the list, -1 otherwise */ int call_list_add_column(PANEL *panel, enum sip_attr_id id, const char* attr, const char *title, int width); /** * @brief Remove all calls from the list and calls storage * * This funtion will clear all call lines in the list * @param panel Call list panel pointer */ void call_list_clear(PANEL *panel); #endif sngrep-1.2.0/src/ui_manager.h0000644000175000017500000002502012632250522015107 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_manager.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage interface panels * * All sngrep panel pointers are encapsulated into a ui structure that is * used to invoke custom functions for creating, destroying, drawing, etc * the screens. * * This sctructure also manages concurrents updates and access to ncurses * panel pointers. * */ #ifndef __SNGREP_UI_MANAGER_H #define __SNGREP_UI_MANAGER_H #include "config.h" #ifdef WITH_UNICODE #define _X_OPEN_SOURCE_EXTENDED #include #else #include #endif #include #include #include "sip.h" #include "group.h" #include "keybinding.h" #include "setting.h" //! Refresh UI every 200 ms #define REFRESHTHSECS 2 //! Default dialog dimensions #define DIALOG_MAX_WIDTH 100 #define DIALOG_MIN_WIDTH 40 //! Shorter declaration of ui structure typedef struct ui ui_t; /** * @brief Panel information structure * * This struct contains the panel related data, including * a pointer to the function that manages its drawing */ struct ui { //! Panel Type @see panel_types enum int type; //! The actual ncurses panel pointer PANEL *panel; //! Constructor for this panel PANEL * (*create)(); //! Destroy current panel void (*destroy)(PANEL *); //! Request the panel to redraw its data int (*draw)(PANEL*); //! Notifies the panel the screen has changed int (*resize)(PANEL*); //! Handle a custom keybind on this panel int (*handle_key)(PANEL*, int key); //! Show help window for this panel (if any) int (*help)(PANEL *); }; /** * @brief Enum for available color pairs */ enum sngrep_colors_pairs { CP_DEFAULT = 0, CP_CYAN_ON_DEF, CP_YELLOW_ON_DEF, CP_MAGENTA_ON_DEF, CP_GREEN_ON_DEF, CP_RED_ON_DEF, CP_BLUE_ON_DEF, CP_WHITE_ON_DEF, CP_DEF_ON_CYAN, CP_DEF_ON_BLUE, CP_WHITE_ON_BLUE, CP_BLACK_ON_CYAN, CP_WHITE_ON_CYAN, CP_YELLOW_ON_CYAN, CP_BLUE_ON_CYAN, CP_BLUE_ON_WHITE, CP_CYAN_ON_BLACK, CP_CYAN_ON_WHITE, }; // Used to configure color pairs only with fg color #define COLOR_DEFAULT -1 /** * @brief Enum for available panel types * * Mostly used for managing keybindings and offloop ui refresh */ enum panel_types { //! Call List ui screen PANEL_CALL_LIST = 0, //! Call-Flow ui screen PANEL_CALL_FLOW, //! Raw SIP messages ui screen PANEL_CALL_RAW, //! Filters panel PANEL_FILTER, //! Save to pcap panel PANEL_SAVE, //! Message comprare PANEL_MSG_DIFF, //! Column selector panel PANEL_COLUMN_SELECT, //! Settings panel PANEL_SETTINGS, //! Stats panel PANEL_STATS, //! Panel Counter PANEL_COUNT, }; /** * Define existing panels */ extern ui_t ui_call_list; extern ui_t ui_call_flow; extern ui_t ui_call_raw; extern ui_t ui_filter; extern ui_t ui_save; extern ui_t ui_msg_diff; extern ui_t ui_column_select; extern ui_t ui_settings; extern ui_t ui_stats; /** * @brief Initialize ncurses mode * * This functions will initialize ncurses mode * * @returns 0 on ncurses initialization success, 1 otherwise */ int ncurses_init(); /** * @brief Stops ncurses mode * * This functions will deinitialize ncurse mode * * @returns 0 on ncurses initialization success, 1 otherwise */ void ncurses_deinit(); /** * @brief Create a panel structure * * Create a ncurses panel associated to the given ui * This function is a small wrapper for panel create function * * @param ui UI structure * @return the ui structure with the panel pointer created */ ui_t * ui_create(ui_t *ui); /** * @brief Create a panel of a given type * * Create a ncurses panel of the given type. * This function is a small wrapper for panel create function * * @param type Panel Type * @return the ui structure with the panel pointer created* */ ui_t * ui_create_panel(enum panel_types type); /** * @brief Destroy a panel structure * * Removes the panel associatet to the given ui and free * its memory. Most part of this task is done in the custom * destroy function of the panel. * * @param ui UI structure */ void ui_destroy(ui_t *ui); /** * @brief Get panel pointer from an ui element * * Basic getter to get the Ncurses PANEL pointer * from ui structure. Use this instead of accessing * directly to the pointer. * * @param ui UI structure * @return ncurses panel pointer of given UI */ PANEL * ui_get_panel(ui_t *ui); /** * @brief Redrawn current ui * * This function acts as wrapper to custom ui draw functions * with some checks * * @param ui UI structure * @return 0 if ui has been drawn, -1 otherwise */ int ui_resize_panel(ui_t *ui); /** * @brief Notifies current ui the screen size has changed * * This function acts as wrapper to custom ui resize functions * with some checks * * @param ui UI structure * @return 0 if ui has been resize, -1 otherwise */ int ui_draw_panel(ui_t *ui); /** * @brief Show help screen from current UI (if any) * * This function will display the help screen for given * ui if exits. * All help screens exits after any character input * * @param ui UI structure */ void ui_help(ui_t *ui); /** * @brief Handle key inputs on given UI * * This function will pass the input key sequence * to the given UI. This will only happen if the key * sequence don't match any of the general keybindings * * @param ui UI structure * @param key keycode sequence of the pressed keys and mods */ int ui_handle_key(ui_t *ui, int key); /** * @brief Find a ui from its pannel pointer */ ui_t * ui_find_by_panel(PANEL *panel); /** * @brief Find a ui form its panel id */ ui_t * ui_find_by_type(enum panel_types type); /** * @brief Wait for user input in topmost panel * * This function manages all user input in all panel types and * redraws the panel using its own draw function * */ int wait_for_input(); /** * @brief Default handler for keys * * If ui doesn't handle the given key (ui_handle_key returns -1) * then the default handler will be invoked * * @param ui Current displayed UI structure * @param key key pressed by user */ int default_handle_key(ui_t *ui, int key); /** * @brief Draw a box around passed windows * * Draw a box around passed windows with two bars * (top and bottom) of one line each. * * @param win Window to draw borders on */ void title_foot_box(PANEL *panel); /** * @brief Draw title at the top of the panel * * This function will draw a line with the title on the first * row of the panel's window * * @param panel PANEL pointer to draw title on * @param title String containing the title */ void draw_title(PANEL *panel, const char *title); /** * @brief Draw keybinding info at the bottom of the panel * * This function will draw a line with the available keybindings * in the last line of the given panel * */ void draw_keybindings(PANEL *panel, const char *keybindings[], int count); /** * @brief Draw a vertical scroll * * This function will draw a vertical scroll in the * right or left side of the given window */ void draw_vscrollbar(WINDOW *win, int value, int max, int left); /** * @brief Clear a given window line * * This function can be used to clear a given line on the * screen. */ void clear_line(WINDOW *win, int line); /** * @brief Draw a message payload in a window * * Generic drawing function for payload. This function will start * writting at 0,0 and return the number of lines written. * * @param win Ncurses window to draw payload * @param msg Msg to be drawn */ int draw_message(WINDOW *win, sip_msg_t *msg); /** * @brief Draw a message payload in a window starting at a given line * * Generic drawing function for payload. This function will start * writting at line starting and first column and return the number * of lines written. * * @param win Ncurses window to draw payload * @param msg Msg to be drawn * @param starting Number of win line to start writting payload */ int draw_message_pos(WINDOW *win, sip_msg_t *msg, int starting); /** * @brief Draw a centered dialog with a message * * Create a centered dialog with a message. * @param msg Message to be drawn */ int dialog_run(const char *fmt, ...); /** * @brief Create a new progress bar dialog * * Create a new progress bar dialog with the given text. The returned * pointer should be used as parameter for @dialog_progress_set_value * in order to move the progress bar percentage. * * @param fmt, vaarg Text to be displayed above the progress bar * @return a pointer to the created window. */ WINDOW * dialog_progress_run(const char *fmt, ...); /** * @brief Set current percentage of dialog progress bar * * @param win Window pointer created with @dialog_progress_run * @param perc 0-100 percentage of progress bar */ void dialog_progress_set_value(WINDOW *win, int perc); /** * @brief Destroy a dialog created by @dialog_progress_run * * This function will deallocate all memory and close the * given window pointer. * * @param win Window pointer created with @dialog_progress_run */ void dialog_progress_destroy(WINDOW *win); /** * @brief Create a new confirmation dialog with multiple buttons * * This function can be used to create dialogs with multiple buttons to * request user confirmation. By default, the first given option will * be selected. * * @param title Title displayed in the top of the dialog * @param text Text displayed inside the dialog * @param options Comma separated labels for the different buttons * @return the index of the button pressed */ int dialog_confirm(const char *title, const char *text, const char *options); #endif // __SNGREP_UI_MANAGER_H sngrep-1.2.0/src/filter.h0000644000175000017500000000677012632250522014300 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file option.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage filtering options * * There are two types of filters: capture and display. * * Capture filters are handled in capture functions and they limit the * number of calls are created in sip storage. * * Display filters are handled in this file and they limit the number of * calls that are displayed to the user. Multiple display filters can be * set at the same time. In order to be valid, a call MUST match all the * enabled filters to be shown. * */ #ifndef __SNGREP_FILTER_H_ #define __SNGREP_FILTER_H_ #include "config.h" #ifdef WITH_PCRE #include #else #include #endif #include "sip.h" //! Shorter declaration of sip_call_group structure typedef struct filter filter_t; /** * @brief Available filter types */ enum filter_type { //! SIP From header in packet payload FILTER_SIPFROM = 0, //! SIP To header in packet payload FILTER_SIPTO, //! Packet source address FILTER_SOURCE, //! Packet destination address FILTER_DESTINATION, //! SIP Method in packet payload FILTER_METHOD, //! SIP Payload in any call packet FILTER_PAYLOAD, //! Displayed line in call list FILTER_CALL_LIST, //! Number of available filter types FILTER_COUNT, }; /** * @brief Filter information */ struct filter { //! The filter text char *expr; #ifdef WITH_PCRE //! The filter compiled expression pcre *regex; #else //! The filter compiled expression regex_t regex; #endif }; /** * @brief Set a given filter expression * * This function is used to set the filter expression * on a given filter. If given expression is NULL * the filter will be removed. * * @param type Type of the filter * @param expr Regexpression to match * @return 0 if the filter is valid, 1 otherwise */ int filter_set(int type, const char *expr); /** * @brief Get filter text expression * * @param type filter type * @return filter text expressions */ const char * filter_get(int type); /** * @brief Check if a call if filtered * * @param call Call to be checked * @return 1 if call is filtered */ int filter_check_call(void *item); /** * @brief Check if data matches the filter regexp * * @return 0 if the given data matches the filter */ int filter_check_expr(filter_t filter, const char *data); /** * @brief Reset filtered flag in all calls * * This function can be used to force reevaluation * of filters in all calls. */ void filter_reset_calls(); #endif /* __SNGREP_FILTER_H_ */ sngrep-1.2.0/src/ui_manager.c0000644000175000017500000005643212632250522015115 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_manager.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_manager.h * */ #include #include #include #include #include #include #include "setting.h" #include "ui_manager.h" #include "capture.h" #include "ui_call_list.h" #include "ui_call_flow.h" #include "ui_call_raw.h" #include "ui_filter.h" #include "ui_msg_diff.h" #include "ui_column_select.h" #include "ui_save.h" #include "ui_settings.h" /** * @brief Available panel windows list * * This list contains the available list of windows * and pointer to their main functions. */ static ui_t *panel_pool[] = { &ui_call_list, &ui_call_flow, &ui_call_raw, &ui_filter, &ui_save, &ui_msg_diff, &ui_column_select, &ui_settings, &ui_stats }; int ncurses_init() { int bg, fg; const char *term; // Set Locale setlocale(LC_CTYPE, ""); // Initialize curses if (!initscr()) { fprintf(stderr, "Unable to initialize ncurses mode.\n"); return -1; } // Check if user wants a black background if (setting_has_value(SETTING_BACKGROUND, "dark")) { assume_default_colors(COLOR_WHITE, COLOR_BLACK); } else { use_default_colors(); } // Enable Colors start_color(); cbreak(); // Dont write user input on screen noecho(); // Hide the cursor curs_set(0); // Only delay ESC Sequences 25 ms (we dont want Escape sequences) ESCDELAY = 25; // Redefine some keys term = getenv("TERM"); if (term && (!strcmp(term, "xterm") || !strcmp(term, "xterm-color") || !strcmp(term, "vt220"))) { define_key("\033[H", KEY_HOME); define_key("\033[F", KEY_END); define_key("\033OP", KEY_F(1)); define_key("\033OQ", KEY_F(2)); define_key("\033OR", KEY_F(3)); define_key("\033OS", KEY_F(4)); define_key("\033[11~", KEY_F(1)); define_key("\033[12~", KEY_F(2)); define_key("\033[13~", KEY_F(3)); define_key("\033[14~", KEY_F(4)); define_key("\033[17;2~", KEY_F(18)); } if (setting_has_value(SETTING_BACKGROUND, "dark")) { fg = COLOR_WHITE; bg = COLOR_BLACK; } else { fg = COLOR_DEFAULT; bg = COLOR_DEFAULT; } // Initialize colorpairs init_pair(CP_CYAN_ON_DEF, COLOR_CYAN, bg); init_pair(CP_YELLOW_ON_DEF, COLOR_YELLOW, bg); init_pair(CP_MAGENTA_ON_DEF, COLOR_MAGENTA, bg); init_pair(CP_GREEN_ON_DEF, COLOR_GREEN, bg); init_pair(CP_RED_ON_DEF, COLOR_RED, bg); init_pair(CP_BLUE_ON_DEF, COLOR_BLUE, bg); init_pair(CP_WHITE_ON_DEF, COLOR_WHITE, bg); init_pair(CP_DEF_ON_CYAN, fg, COLOR_CYAN); init_pair(CP_DEF_ON_BLUE, fg, COLOR_BLUE); init_pair(CP_WHITE_ON_BLUE, COLOR_WHITE, COLOR_BLUE); init_pair(CP_BLACK_ON_CYAN, COLOR_BLACK, COLOR_CYAN); init_pair(CP_WHITE_ON_CYAN, COLOR_WHITE, COLOR_CYAN); init_pair(CP_YELLOW_ON_CYAN, COLOR_YELLOW, COLOR_CYAN); init_pair(CP_BLUE_ON_CYAN, COLOR_BLUE, COLOR_CYAN); init_pair(CP_BLUE_ON_WHITE, COLOR_BLUE, COLOR_WHITE); init_pair(CP_CYAN_ON_WHITE, COLOR_CYAN, COLOR_WHITE); init_pair(CP_CYAN_ON_BLACK, COLOR_CYAN, COLOR_BLACK); return 0; } void ncurses_deinit() { // Clear screen before leaving refresh(); // End ncurses mode endwin(); } ui_t * ui_create(ui_t *ui) { // If ui has no panel if (!ui_get_panel(ui)) { // Create the new panel for this ui if (ui->create) { ui->panel = ui->create(); } } // And return it return ui; } ui_t * ui_create_panel(enum panel_types type) { // Find the panel of given type and create it return ui_create(ui_find_by_type(type)); } void ui_destroy(ui_t *ui) { // If there is no ui panel, we're done if (!ui || !ui->panel) return; // Hide this panel before destroying hide_panel(ui->panel); // If panel has a destructor function use it if (ui->destroy) ui->destroy(ui->panel); // Initialize panel pointer ui->panel = NULL; } PANEL * ui_get_panel(ui_t *ui) { // Return panel pointer of ui struct return (ui) ? ui->panel : NULL; } int ui_draw_panel(ui_t *ui) { PANEL *panel = NULL; int ret = 0; //! Sanity check, this should not happen if (!ui) return -1; // Get ui panel pointer if (!(panel = ui_get_panel(ui))) return -1; // Set character input timeout 200 ms halfdelay(REFRESHTHSECS); // Avoid parsing any packet while UI is being drawn capture_lock(); // Request the panel to draw on the scren if (ui->draw) { ret = ui->draw(panel); } else { touchwin(panel_window(panel)); } // Continue parsing packets capture_unlock(); return ret; } int ui_resize_panel(ui_t *ui) { int ret = 0; //! Sanity check, this should not happen if (!ui) return -1; // Notify the panel screen size has changed if (ui->resize) { ret = ui->resize(ui_get_panel(ui)); } return ret; } void ui_help(ui_t *ui) { // Disable input timeout nocbreak(); cbreak(); // If current ui has help function if (ui->help) { ui->help(ui_get_panel(ui)); } } int ui_handle_key(ui_t *ui, int key) { int ret = 0; // Avoid parsing any packet while key is being handled capture_lock(); if (ui->handle_key) ret = ui->handle_key(ui_get_panel(ui), key); // Continue parsing packets capture_unlock(); return ret; } ui_t * ui_find_by_panel(PANEL *panel) { int i; // Return ui pointer if found for (i = 0; i < PANEL_COUNT; i++) { if (panel_pool[i]->panel == panel) return panel_pool[i]; } return NULL; } ui_t * ui_find_by_type(enum panel_types type) { int i; // Return ui pointer if found for (i = 0; i < PANEL_COUNT; i++) { if (panel_pool[i]->type == type) return panel_pool[i]; } return NULL; } int wait_for_input() { ui_t *ui; WINDOW *win; PANEL *panel; // While there are still panels while ((panel = panel_below(NULL))) { // Get panel interface structure ui = ui_find_by_panel(panel); // Redraw this panel if (ui_draw_panel(ui) != 0) return -1; // Update panel stack update_panels(); doupdate(); // Get topmost panel panel = panel_below(NULL); // Enable key input on current panel win = panel_window(panel); keypad(win, TRUE); // Get pressed key int c = wgetch(win); // Timeout, no key pressed if (c == ERR) continue; // Check if current panel has custom bindings for that key if ((c = ui_handle_key(ui, c)) == 0) { // Key has been handled by panel continue; } // Key not handled by UI, try default handler default_handle_key(ui, c); } return -1; } int default_handle_key(ui_t *ui, int key) { int action = -1; // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_RESIZE_SCREEN: ui_resize_panel(ui); break; case ACTION_TOGGLE_SYNTAX: setting_toggle(SETTING_SYNTAX); break; case ACTION_TOGGLE_HINT: setting_toggle(SETTING_ALTKEY_HINT); break; case ACTION_CYCLE_COLOR: setting_toggle(SETTING_COLORMODE); break; case ACTION_SHOW_HOSTNAMES: setting_toggle(SETTING_DISPLAY_HOST); break; case ACTION_SHOW_ALIAS: setting_toggle(SETTING_DISPLAY_ALIAS); break; case ACTION_SHOW_SETTINGS: ui_create_panel(PANEL_SETTINGS); break; case ACTION_TOGGLE_PAUSE: // Pause/Resume capture capture_set_paused(!capture_is_paused()); break; case ACTION_SHOW_HELP: ui_help(ui); break; case ACTION_PREV_SCREEN: ui_destroy(ui); break; default: // Parse next action continue; } // Default handler has handled the key break; } // Return this is a valid handled key return (action == ERR) ? key : 0; } void title_foot_box(PANEL *panel) { int height, width; WINDOW *win = panel_window(panel); // Sanity check if (!win) return; // Get window size getmaxyx(win, height, width); box(win, 0, 0); mvwaddch(win, 2, 0, ACS_LTEE); mvwhline(win, 2, 1, ACS_HLINE, width - 2); mvwaddch(win, 2, width - 1, ACS_RTEE); mvwaddch(win, height - 3, 0, ACS_LTEE); mvwhline(win, height - 3, 1, ACS_HLINE, width - 2); mvwaddch(win, height - 3, width - 1, ACS_RTEE); } void draw_keybindings(PANEL *panel, const char *keybindings[], int count) { int height, width, key, xpos = 0; // Get window available space WINDOW *win = panel_window(panel); getmaxyx(win, height, width); // Reverse colors on monochrome terminals if (!has_colors()) wattron(win, A_REVERSE); // Write a line all the footer width wattron(win, COLOR_PAIR(CP_DEF_ON_CYAN)); clear_line(win, height - 1); // Draw keys and their actions for (key = 0; key < count; key += 2) { wattron(win, A_BOLD | COLOR_PAIR(CP_WHITE_ON_CYAN)); mvwprintw(win, height - 1, xpos, "%-*s", strlen(keybindings[key]) + 1, keybindings[key]); xpos += strlen(keybindings[key]) + 1; wattroff(win, A_BOLD | COLOR_PAIR(CP_WHITE_ON_CYAN)); wattron(win, COLOR_PAIR(CP_BLACK_ON_CYAN)); mvwprintw(win, height - 1, xpos, "%-*s", strlen(keybindings[key + 1]) + 1, keybindings[key + 1]); wattroff(win, COLOR_PAIR(CP_BLACK_ON_CYAN)); xpos += strlen(keybindings[key + 1]) + 3; } // Disable reverse mode in all cases wattroff(win, A_REVERSE); } void draw_title(PANEL *panel, const char *title) { int height, width; // Get window available space WINDOW *win = panel_window(panel); getmaxyx(win, height, width); // Reverse colors on monochrome terminals if (!has_colors()) wattron(win, A_REVERSE); // Center the title on the window wattron(win, A_BOLD | COLOR_PAIR(CP_DEF_ON_CYAN)); clear_line(win, 0); mvwprintw(win, 0, (width - strlen(title)) / 2, "%s", title); wattroff(win, A_BOLD | A_REVERSE | COLOR_PAIR(CP_DEF_ON_CYAN)); } void draw_vscrollbar(WINDOW *win, int value, int max, int left) { int height, width, cline, scrollen, scrollypos, scrollxpos; // Get window available space getmaxyx(win, height, width); // If no even a screen has been filled, don't draw it if (max < height) return; // Display the scrollbar left or right scrollxpos = (left) ? 0 : width - 1; // Initialize scrollbar line mvwvline(win, 0, scrollxpos, ACS_VLINE, height); // How long the scroll will be if (!(scrollen = (height * 1.0f / max * height) + 0.5)) scrollen = 1; // Where will the scroll start scrollypos = height * (value * 1.0f / max); // Draw the N blocks of the scrollbar for (cline = 0; cline < scrollen; cline++) mvwaddch(win, cline + scrollypos, scrollxpos, ACS_CKBOARD); } void clear_line(WINDOW *win, int line) { // We could do this with wcleartoel but we want to // preserve previous window attributes. That way we // can set the background of the line. mvwprintw(win, line, 0, "%*s", getmaxx(win), ""); } int draw_message(WINDOW *win, sip_msg_t *msg) { return draw_message_pos(win, msg, 0); } int draw_message_pos(WINDOW *win, sip_msg_t *msg, int starting) { int height, width, line, column, i; const char *cur_line, *payload; int syntax = setting_enabled(SETTING_SYNTAX); // Default text format int attrs = A_NORMAL | COLOR_PAIR(CP_DEFAULT); if (syntax) wattrset(win, attrs); // Get window of main panel getmaxyx(win, height, width); // Get packet payload cur_line = payload = (const char *) msg_get_payload(msg); // Print msg payload line = starting; column = 0; for (i = 0; i < strlen(payload); i++) { // If syntax highlighting is enabled if (syntax) { // First line highlight if (line == starting) { // Request syntax if (i == 0 && strncmp(cur_line, "SIP/2.0", 7)) attrs = A_BOLD | COLOR_PAIR(CP_YELLOW_ON_DEF); // Response syntax if (i == 8 && !strncmp(cur_line, "SIP/2.0", 7)) attrs = A_BOLD | COLOR_PAIR(CP_RED_ON_DEF); // SIP URI syntax if (!strncasecmp(payload + i, "sip:", 4)) { attrs = A_BOLD | COLOR_PAIR(CP_CYAN_ON_DEF); } } else { // Header syntax if (strchr(cur_line, ':') && payload + i < strchr(cur_line, ':')) attrs = A_NORMAL | COLOR_PAIR(CP_GREEN_ON_DEF); // Call-ID Header syntax if (!strncasecmp(cur_line, "Call-ID:", 8) && column > 8) attrs = A_BOLD | COLOR_PAIR(CP_MAGENTA_ON_DEF); // CSeq Heaedr syntax if (!strncasecmp(cur_line, "CSeq:", 5) && column > 5 && !isdigit(payload[i])) attrs = A_NORMAL | COLOR_PAIR(CP_YELLOW_ON_DEF); // tag and branch syntax if (i > 0 && payload[i - 1] == ';') { // Highlight branch if requested if (setting_enabled(SETTING_SYNTAX_BRANCH)) { if (!strncasecmp(payload + i, "branch", 6)) { attrs = A_BOLD | COLOR_PAIR(CP_CYAN_ON_DEF); } } // Highlight tag if requested if (setting_enabled(SETTING_SYNTAX_TAG)) { if (!strncasecmp(payload + i, "tag", 3)) { if (!strncasecmp(cur_line, "From:", 5)) { attrs = A_BOLD | COLOR_PAIR(CP_DEFAULT); } else { attrs = A_BOLD | COLOR_PAIR(CP_GREEN_ON_DEF); } } } } // SDP syntax if (strcspn(cur_line, "=") == 1) attrs = A_NORMAL | COLOR_PAIR(CP_DEFAULT); } // Remove previous syntax if (strcspn(payload + i, " \n;<>") == 0) { wattroff(win, attrs); attrs = A_NORMAL | COLOR_PAIR(CP_DEFAULT); } // Syntax hightlight text! wattron(win, attrs); } // Dont print this characters if (payload[i] == '\r') continue; // Store where the line begins if (payload[i] == '\n') cur_line =payload + i + 1; // Move to the next line if line is filled or a we reach a line break if (column > width || payload[i] == '\n') { line++; column = 0; continue; } // Put next character in position mvwaddch(win, line, column++, payload[i]); // Stop if we've reached the bottom of the window if (line == height) break; } // Disable syntax when leaving if (syntax) wattroff(win, attrs); // Redraw raw win wnoutrefresh(win); return line - starting; } int dialog_run(const char *fmt, ...) { char textva[2048]; va_list ap; int height, width; WINDOW *win; char *word; int col = 2; int line = 2; // Get the message from the format string va_start(ap, fmt); vsprintf(textva, fmt, ap); va_end(ap); // Determine dialog dimensions height = 6 + (strlen(textva) / 50); width = strlen(textva); // Check we don't have a too big or small window if (width > DIALOG_MAX_WIDTH) width = DIALOG_MAX_WIDTH; if (width < DIALOG_MIN_WIDTH) width = DIALOG_MIN_WIDTH; // Create the window win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); box(win, 0, 0); // Write the message into the screen for (word = strtok(textva, " "); word; word = strtok(NULL, " ")) { if (col + strlen(word) > width - 2) { line++; col = 2; } mvwprintw(win, line, col, "%s", word); col += strlen(word) + 1; } // Write Accept button wattron(win, A_REVERSE); mvwprintw(win, height - 2, width/2 - 5, "[ Accept ]"); curs_set(0); // Disable input timeout nocbreak(); cbreak(); // Wait for input wgetch(win); delwin(win); return 1; } WINDOW * dialog_progress_run(const char *fmt, ...) { char textva[2048]; va_list ap; int height, width; WINDOW *win; char *word; int col = 2; int line = 2; // Get the message from the format string va_start(ap, fmt); vsprintf(textva, fmt, ap); va_end(ap); // Determine dialog dimensions height = 6 + (strlen(textva) / 50); width = strlen(textva); // Check we don't want a too big or small window if (width > DIALOG_MAX_WIDTH) width = DIALOG_MAX_WIDTH; if (width < DIALOG_MIN_WIDTH) width = DIALOG_MIN_WIDTH; // Create the window win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); box(win, 0, 0); // Write the message into the screen for (word = strtok(textva, " "); word; word = strtok(NULL, " ")) { if (col + strlen(word) > width - 2) { line++; col = 2; } mvwprintw(win, line, col, "%s", word); col += strlen(word) + 1; } curs_set(0); wrefresh(win); // Disable input timeout nocbreak(); cbreak(); return win; } void dialog_progress_set_value(WINDOW *win, int perc) { int height, width; getmaxyx(win, height, width); mvwhline(win, 4, 4, '-', width - 10); mvwaddch(win, 4, 3, '['); mvwaddch(win, 4, width - 7, ']'); mvwprintw(win, 4, width - 5, "%d%%", perc); if (perc > 0 && perc <= 100) mvwhline(win, 4, 4, ACS_CKBOARD, (width - 10) * ((float)perc/100)); wrefresh(win); } void dialog_progress_destroy(WINDOW *win) { delwin(win); } int dialog_confirm(const char *title, const char *text, const char *options) { WINDOW *dialog_win; int c, i, curs, newl, height, width; char *str, *tofree, *option, *word; int selected = 0; int optioncnt = 1; int col = 2; int line = 3; char opts[4][10]; // Initialize memset(opts, 0, 4 * 10); // Check how many options exists for (i=0; options[i]; i++) { if (options[i] == ',') optioncnt++; } // We only support 4 options if (optioncnt > 4) return -1; // Calculate proper width taking into acount longest data width = strlen(options) + 6 * optioncnt; if (strlen(title) + 4 > width) width = strlen(title) + 4; if (strlen(text) > width && strlen(text) < 50) width = strlen(text); // Check we don't want a too big or small window if (width > DIALOG_MAX_WIDTH) width = DIALOG_MAX_WIDTH; if (width < DIALOG_MIN_WIDTH) width = DIALOG_MIN_WIDTH; // Determine dialog dimensions height = 7; // Minimum for header and button lines height += (strlen(text) / width); // Space for the text. // Add one extra line for each newline in the text for (i=0; text[i]; i++) { if (text[i] == '\n') height++; } // Parse each line of payload looking for sdp information tofree = str = strdup((char*)options); i = 0; while ((option = strsep(&str, ",")) != NULL) { strcpy(opts[i++], option); } sng_free(tofree); // Create a new panel and show centered dialog_win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); keypad(dialog_win, TRUE); curs = curs_set(0); // Set the window title mvwprintw(dialog_win, 1, (width - strlen(title)) / 2, title); // Write border and boxes around the window wattron(dialog_win, COLOR_PAIR(CP_BLUE_ON_DEF)); box(dialog_win, 0, 0); mvwhline(dialog_win, 2, 1, ACS_HLINE, width); mvwaddch(dialog_win, 2, 0, ACS_LTEE); mvwaddch(dialog_win, 2, width - 1, ACS_RTEE); mvwhline(dialog_win, height - 3, 1, ACS_HLINE, width); mvwaddch(dialog_win, height - 3, 0, ACS_LTEE); mvwaddch(dialog_win, height - 3, width - 1, ACS_RTEE); // Exit confirmation message message wattron(dialog_win, COLOR_PAIR(CP_CYAN_ON_DEF)); // Write the message into the screen tofree = str = strdup((char*)text); newl = 0; while ((word = strsep(&str, " ")) != NULL) { if (word[strlen(word)-1] == '\n') { word[strlen(word)-1] = '\0'; newl = 1; } if (col + strlen(word) > width - 2) { line++; col = 2; } mvwprintw(dialog_win, line, col, "%s", word); col += strlen(word) + 1; if (newl) { line++; col = 2; newl = 0; } } sng_free(tofree); wattroff(dialog_win, COLOR_PAIR(CP_CYAN_ON_DEF)); for (;;) { // A list of available keys in this window for (i = 0; i < optioncnt; i++ ) { if (i == selected) wattron(dialog_win, A_REVERSE); mvwprintw(dialog_win, height - 2, 10 + 10 * i, "[ %s ]", opts[i]); wattroff(dialog_win, A_REVERSE); } c = wgetch(dialog_win); switch (c) { case KEY_RIGHT: selected++; break; case KEY_TAB: case KEY_LEFT: selected--; break; case KEY_SPACE: case KEY_ENTER: case KEY_INTRO: goto done; case KEY_ESC: selected = -1; goto done; } // Cycle through ooptions if (selected > optioncnt - 1) selected = 0; if (selected < 0) selected = optioncnt - 1; } done: delwin(dialog_win); curs_set(curs); return selected; } sngrep-1.2.0/src/capture_gnutls.c0000644000175000017500000004224112632250522016036 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file capture_tls.c * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP TLS transport for messages * * This file contains the functions and structures to manage the SIP messages * that use TLS as transport. * */ #include #include "capture.h" #include "capture_gnutls.h" #include "option.h" #include "util.h" #include "sip.h" struct SSLConnection *connections; struct CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = { 0x00, 0x2F }; struct CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = { 0x00, 0x35 }; int P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret, int sslen, unsigned char *seed, int slen) { unsigned char hmac[48]; unsigned int hlen; gcry_md_hd_t md; unsigned int tmpslen; unsigned char tmpseed[slen]; unsigned char *out = dest; int pending = dlen; int algo = gcry_md_map_name(digest); int algolen = gcry_md_get_algo_dlen(algo); // Copy initial seed memcpy(tmpseed, seed, slen); tmpslen = slen; // Calculate enough data to fill destination while (pending > 0) { gcry_md_open(&md, algo, GCRY_MD_FLAG_HMAC); gcry_md_setkey(md, secret, sslen); gcry_md_write(md, tmpseed, tmpslen); memcpy(tmpseed, gcry_md_read(md, algo), algolen); tmpslen = algolen; gcry_md_close(md); gcry_md_open(&md, algo, GCRY_MD_FLAG_HMAC); gcry_md_setkey(md, secret, sslen); gcry_md_write(md, tmpseed, tmpslen); gcry_md_write(md, seed, slen); memcpy(hmac, gcry_md_read(md, algo), algolen); hlen = algolen; hlen = (hlen > pending) ? pending : hlen; memcpy(out, hmac, hlen); out += hlen; pending -= hlen; } return hlen; } int PRF(unsigned char *dest, int dlen, unsigned char *pre_master_secret, int plen, unsigned char *label, unsigned char *seed, int slen) { int i; // Split the secret by half to generate MD5 and SHA secret parts int hplen = plen / 2 + plen % 2; unsigned char md5_secret[hplen]; unsigned char sha_secret[hplen]; memcpy(md5_secret, pre_master_secret, hplen); memcpy(sha_secret, pre_master_secret + plen / 2, plen / 2); // This vars will store the values of P_MD5 and P_SHA-1 unsigned char h_md5[dlen]; unsigned char h_sha[dlen]; // Concatenate given seed to the label to get the final seed int llen = strlen((const char*) label); unsigned char fseed[slen + llen]; memcpy(fseed, label, llen); memcpy(fseed + llen, seed, slen); // Get enough MD5 and SHA1 data to fill output len P_hash("MD5", h_md5, dlen, pre_master_secret, hplen, fseed, slen + llen); P_hash("SHA1", h_sha, dlen, pre_master_secret + hplen, hplen, fseed, slen + llen); // Final output will be MD5 and SHA1 X-ORed for (i = 0; i < dlen; i++) dest[i] = h_md5[i] ^ h_sha[i]; return dlen; } struct SSLConnection * tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr, u_short sport) { struct SSLConnection *conn = NULL; gnutls_datum_t keycontent = { NULL, 0 }; FILE *keyfp; gnutls_x509_privkey_t spkey; size_t br; // Allocate memory for this connection conn = sng_malloc(sizeof(struct SSLConnection)); memcpy(&conn->client_addr, &caddr, sizeof(struct in_addr)); memcpy(&conn->server_addr, &saddr, sizeof(struct in_addr)); memcpy(&conn->client_port, &cport, sizeof(u_short)); memcpy(&conn->server_port, &sport, sizeof(u_short)); SSL_library_init(); OpenSSL_add_all_algorithms(); if (!(conn->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) return NULL; if (!(conn->ssl = SSL_new(conn->ssl_ctx))) return NULL; if (!(keyfp = fopen(capture_get_keyfile(), "rb"))) return NULL; fseek(keyfp, 0, SEEK_END); keycontent.size = ftell(keyfp); fseek(keyfp, 0, SEEK_SET); keycontent.data = sng_malloc(keycontent.size); br = fread(keycontent.data, 1, keycontent.size, keyfp); fclose(keyfp); gnutls_x509_privkey_init(&spkey); gnutls_x509_privkey_import(spkey, &keycontent, GNUTLS_X509_FMT_PEM); sng_free(keycontent.data); gnutls_privkey_init(&conn->server_private_key); gnutls_privkey_import_x509(conn->server_private_key, spkey, 0); // Add this connection to the list conn->next = connections; connections = conn; return conn; } void tls_connection_destroy(struct SSLConnection *conn) { struct SSLConnection *c; // Remove connection from connections list if (conn == connections) { connections = conn->next; } else { for (c = connections; c; c = c->next) { if (c->next == conn) { c->next = conn->next; break; } } } // Deallocate connection memory SSL_CTX_free(conn->ssl_ctx); SSL_free(conn->ssl); sng_free(conn); } /** * FIXME Replace this with a tls_load_key function and use it * in tls_connection_create. * * Most probably we only need one context and key for all connections */ int tls_check_keyfile(const char *keyfile) { gnutls_x509_privkey_t key; gnutls_datum_t keycontent = { NULL, 0 }; FILE *keyfp; size_t br; SSL_library_init(); OpenSSL_add_all_algorithms(); if (access(capture_get_keyfile(), R_OK) != 0) return 0; if (!(keyfp = fopen(capture_get_keyfile(), "rb"))) return 0; fseek(keyfp, 0, SEEK_END); keycontent.size = ftell(keyfp); fseek(keyfp, 0, SEEK_SET); keycontent.data = sng_malloc(keycontent.size); br = fread(keycontent.data, 1, keycontent.size, keyfp); fclose(keyfp); gnutls_x509_privkey_init(&key); if (gnutls_x509_privkey_import(key, &keycontent, GNUTLS_X509_FMT_PEM) < 0) return 0; sng_free(keycontent.data); return 1; } int tls_connection_dir(struct SSLConnection *conn, struct in_addr addr, u_short port) { if (conn->client_addr.s_addr == addr.s_addr && conn->client_port == port) return 0; if (conn->server_addr.s_addr == addr.s_addr && conn->server_port == port) return 1; return -1; } struct SSLConnection* tls_connection_find(struct in_addr addr, u_short port) { struct SSLConnection *conn; for (conn = connections; conn; conn = conn->next) { if (tls_connection_dir(conn, addr, port) != -1) { return conn; } } return NULL; } int tls_process_segment(capture_packet_t *packet, struct tcphdr *tcp) { struct SSLConnection *conn; const u_char *payload = capture_packet_get_payload(packet); uint32_t size_payload = capture_packet_get_payload_len(packet); uint8 *out; uint32_t outl = packet->payload_len; out = sng_malloc(outl); struct in_addr ip_src, ip_dst; u_short sport = packet->sport; u_short dport = packet->dport; // Convert addresses inet_pton(AF_INET, packet->ip_src, &ip_src); inet_pton(AF_INET, packet->ip_dst, &ip_dst); // Try to find a session for this ip if ((conn = tls_connection_find(ip_src, sport))) { // Update last connection direction conn->direction = tls_connection_dir(conn, ip_src, sport); // Check current connection state switch (conn->state) { case TCP_STATE_SYN: // First SYN received, this package must be SYN/ACK if (tcp->th_flags & TH_SYN & ~TH_ACK) conn->state = TCP_STATE_SYN_ACK; break; case TCP_STATE_SYN_ACK: // We expect an ACK packet here if (tcp->th_flags & ~TH_SYN & TH_ACK) conn->state = TCP_STATE_ESTABLISHED; break; case TCP_STATE_ACK: case TCP_STATE_ESTABLISHED: // Process data segment! if (tls_process_record(conn, payload, size_payload, &out, &outl) == 0) { if ((int32_t) outl > 0) { capture_packet_set_payload(packet, out, outl); capture_packet_set_type(packet, CAPTURE_PACKET_SIP_TLS); return 0; } } break; case TCP_STATE_FIN: case TCP_STATE_CLOSED: // We can delete this connection tls_connection_destroy(conn); break; } } else { if (tcp->th_flags & TH_SYN & ~TH_ACK) { // New connection, store it status and leave tls_connection_create(ip_src, sport, ip_dst, dport); } } sng_free(out); return 0; } int tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int len, uint8 **out, uint32_t *outl) { struct TLSPlaintext *record; int record_len; const opaque *fragment; // No record data here! if (len == 0) return 0; // Get Record data record = (struct TLSPlaintext *) payload; record_len = sizeof(struct TLSPlaintext) + UINT16_INT(record->length); // Process record fragment if (UINT16_INT(record->length) > 0) { // TLSPlaintext fragment pointer fragment = (opaque *) payload + sizeof(struct TLSPlaintext); switch (record->type) { case handshake: // Hanshake Record, Try to get MasterSecret data if (tls_process_record_handshake(conn, fragment) != 0) return 1; break; case change_cipher_spec: // From now on, this connection will be encrypted using MasterSecret conn->encrypted = 1; break; case application_data: if (conn->encrypted) { // Decrypt application data using MasterSecret tls_process_record_data(conn, fragment, UINT16_INT(record->length), out, outl); } break; default: break; } } // MultiRecord packet if (len > record_len) return tls_process_record(conn, payload + record_len, len - record_len, out, outl); return 0; } int tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment) { struct Handshake *handshake; struct ClientHello *clienthello; struct ServerHello *serverhello; struct ClientKeyExchange *clientkeyex; const opaque *body; // Get Handshake data handshake = (struct Handshake *) fragment; if (UINT24_INT(handshake->length) > 0) { // Hanshake body pointer body = fragment + sizeof(struct Handshake); switch (handshake->type) { case hello_request: break; case client_hello: // Store client random clienthello = (struct ClientHello *) body; memcpy(&conn->client_random, &clienthello->random, sizeof(struct Random)); // Check we have a TLS handshake if (!(clienthello->client_version.major == 0x03 && clienthello->client_version.minor == 0x01)) { tls_connection_destroy(conn); return 1; } break; case server_hello: // Store server random serverhello = (struct ServerHello *) body; memcpy(&conn->server_random, &serverhello->random, sizeof(struct Random)); // Get the selected cipher memcpy(&conn->cipher_suite, body + sizeof(struct ServerHello) + serverhello->session_id_length, sizeof(uint16)); // Check if we have a handled cipher if (tls_connection_load_cipher(conn) != 0) { tls_connection_destroy(conn); return 1; } break; case certificate: case certificate_request: case server_hello_done: case certificate_verify: break; case client_key_exchange: // Decrypt PreMasterKey clientkeyex = (struct ClientKeyExchange *) body; gnutls_datum_t exkeys, pms; exkeys.size = UINT16_INT(clientkeyex->length); exkeys.data = (unsigned char *)&clientkeyex->exchange_keys; gnutls_privkey_decrypt_data(conn->server_private_key, 0, &exkeys, &pms); memcpy(&conn->pre_master_secret, pms.data, pms.size); // Get MasterSecret unsigned char *seed = sng_malloc(sizeof(struct Random) * 2); memcpy(seed, &conn->client_random, sizeof(struct Random)); memcpy(seed + sizeof(struct Random), &conn->server_random, sizeof(struct Random)); PRF((unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) &conn->pre_master_secret, sizeof(struct PreMasterSecret), (unsigned char *) "master secret", seed, sizeof(struct Random) * 2); memcpy(seed, &conn->server_random, sizeof(struct Random)); memcpy(seed + sizeof(struct Random), &conn->client_random, sizeof(struct Random)); // Generate MACs, Write Keys and IVs PRF((unsigned char *) &conn->key_material, sizeof(struct tls_data), (unsigned char *) &conn->master_secret, sizeof(struct MasterSecret), (unsigned char *) "key expansion", seed, sizeof(struct Random) * 2); // Done with the seed sng_free(seed); // Create Client decoder gcry_cipher_open(&conn->client_cipher_ctx, conn->ciph, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_setkey(conn->client_cipher_ctx, conn->key_material.client_write_key, gcry_cipher_get_algo_keylen(conn->ciph)); gcry_cipher_setiv(conn->client_cipher_ctx, conn->key_material.client_write_IV, gcry_cipher_get_algo_blklen(conn->ciph)); // Create Server decoder gcry_cipher_open(&conn->server_cipher_ctx, conn->ciph, GCRY_CIPHER_MODE_CBC, 0); gcry_cipher_setkey(conn->server_cipher_ctx, conn->key_material.server_write_key, gcry_cipher_get_algo_keylen(conn->ciph)); gcry_cipher_setiv(conn->server_cipher_ctx, conn->key_material.server_write_IV, gcry_cipher_get_algo_blklen(conn->ciph)); break; case finished: break; default: if (conn->encrypted) { // Encrypted Hanshake Message unsigned char *decoded = sng_malloc(48); uint32_t decodedlen; tls_process_record_data(conn, fragment, 48, &decoded, &decodedlen); sng_free(decoded); } break; } } return 0; } int tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len, uint8 **out, uint32_t *outl) { gcry_cipher_hd_t *evp; unsigned char pad; unsigned char *decoded; size_t dlen = len; if (conn->direction == 0) { evp = &conn->client_cipher_ctx; } else { evp = &conn->server_cipher_ctx; } decoded = sng_malloc(len); gcry_cipher_decrypt(*evp, decoded, dlen, (unsigned char *) fragment, len); // Get padding counter and remove from data pad = decoded[len - 1]; dlen = (len - (pad + 1) - /* Trailing MAC */20); if ((int32_t)dlen > 0 && dlen <= *outl) { memcpy(*out, decoded, dlen); *outl = dlen; } // Clenaup decoded memory sng_free(decoded); return *outl; } int tls_connection_load_cipher(struct SSLConnection *conn) { if (conn->cipher_suite.cs1 != 0x00) return 1; if (conn->cipher_suite.cs2 == TLS_RSA_WITH_AES_256_CBC_SHA.cs2) { conn->ciph = gcry_cipher_map_name("AES256"); } else if (conn->cipher_suite.cs2 == TLS_RSA_WITH_AES_128_CBC_SHA.cs2) { conn->ciph = gcry_cipher_map_name("AES"); } else { return 1; } return 0; } sngrep-1.2.0/src/capture_eep.h0000644000175000017500000002000512632250522015272 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** Copyright (C) 2012 Homer Project (http://www.sipcapture.org) ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file capture.h * * @author Ivan Alonso [aka Kaian] * @author Alexandr Dubovikov * * @brief Functions to manage eep protocol * * This file contains declaration of structure and functions to send and * receive packet information through HEP-EEP (Extensible Encapsulation Protocol) * * Additional information about HEP-EEP protocol can be found in sipcature * repositories at https://github.com/sipcapture/HEP * * @note Most of this code has been taken from hep-c and sipgrep (originally * written by Alexandr Dubovikov). Modifications of sources to work with * sngrep packet structures has been made by Ivan Alonso (Kaian) * */ #ifndef __SNGREP_CAPTURE_EEP_H #define __SNGREP_CAPTURE_EEP_H #include #include "capture.h" //! Shorter declaration of capture_eep_config structure typedef struct capture_eep_config capture_eep_config_t; /** * @brief EEP Client/Server configuration */ struct capture_eep_config { //! Client socket for sending EEP data int client_sock; //! Server socket for receiving EEP data int server_sock; //! Capture agent id int capt_id; //! Hep Version for sending data (2 or 3) int capt_version; //! IP address to sends EEP data const char *capt_host; //! Port to send EEP data const char *capt_port; //! Password for authenticate as client const char *capt_password; // HEp version for receiving data (2 or 3) int capt_srv_version; //! IP address to received EEP data const char *capt_srv_host; //! Local oort to receive EEP data const char *capt_srv_port; //! Server password to authenticate incoming connections const char *capt_srv_password; //! Server thread to parse incoming data pthread_t server_thread; }; /* HEPv3 types */ struct hep_chunk { u_int16_t vendor_id; u_int16_t type_id; u_int16_t length; }__attribute__((packed)); typedef struct hep_chunk hep_chunk_t; struct hep_chunk_uint8 { hep_chunk_t chunk; u_int8_t data; }__attribute__((packed)); typedef struct hep_chunk_uint8 hep_chunk_uint8_t; struct hep_chunk_uint16 { hep_chunk_t chunk; u_int16_t data; }__attribute__((packed)); typedef struct hep_chunk_uint16 hep_chunk_uint16_t; struct hep_chunk_uint32 { hep_chunk_t chunk; u_int32_t data; }__attribute__((packed)); typedef struct hep_chunk_uint32 hep_chunk_uint32_t; struct hep_chunk_str { hep_chunk_t chunk; char *data; }__attribute__((packed)); typedef struct hep_chunk_str hep_chunk_str_t; struct hep_chunk_ip4 { hep_chunk_t chunk; struct in_addr data; }__attribute__((packed)); typedef struct hep_chunk_ip4 hep_chunk_ip4_t; struct hep_chunk_ip6 { hep_chunk_t chunk; struct in6_addr data; }__attribute__((packed)); typedef struct hep_chunk_ip6 hep_chunk_ip6_t; struct hep_ctrl { char id[4]; u_int16_t length; }__attribute__((packed)); typedef struct hep_ctrl hep_ctrl_t; struct hep_chunk_payload { hep_chunk_t chunk; char *data; }__attribute__((packed)); typedef struct hep_chunk_payload hep_chunk_payload_t; /** * @brief Generic HEP header * * All EEP/HEP packets will contain at least this header. */ struct hep_generic { hep_ctrl_t header; hep_chunk_uint8_t ip_family; hep_chunk_uint8_t ip_proto; hep_chunk_uint16_t src_port; hep_chunk_uint16_t dst_port; hep_chunk_uint32_t time_sec; hep_chunk_uint32_t time_usec; hep_chunk_uint8_t proto_t; hep_chunk_uint32_t capt_id; }__attribute__((packed)); typedef struct hep_generic hep_generic_t; struct hep_hdr { u_int8_t hp_v; /* version */ u_int8_t hp_l; /* length */ u_int8_t hp_f; /* family */ u_int8_t hp_p; /* protocol */ u_int16_t hp_sport; /* source port */ u_int16_t hp_dport; /* destination port */ }; struct hep_timehdr { u_int32_t tv_sec; /* seconds */ u_int32_t tv_usec; /* useconds */ u_int16_t captid; /* Capture ID node */ }; struct hep_iphdr { struct in_addr hp_src; struct in_addr hp_dst; /* source and dest address */ }; #ifdef USE_IPV6 struct hep_ip6hdr { struct in6_addr hp6_src; /* source address */ struct in6_addr hp6_dst; /* destination address */ }; #endif /** * @brief Initialize EEP proccess * * This funtion will setup all required sockets both for * send and receiving information depending on sngrep configuration. * * It will also launch a thread to received EEP data if configured * to do so. * * @return 1 on any error occurs, 0 otherwise */ int capture_eep_init(); /** * @brief Unitialize EEP process * * Close used sockets for receive and send data and stop server * thread if server mode is enabled. */ void capture_eep_deinit(); /** * @brief Wrapper for sending packet in configured EEP version * * @param pkt Packet Structure data * @return 1 on any error occurs, 0 otherwise */ int capture_eep_send(capture_packet_t *pkt); /** * @brief Send a captured packet (EEP version 2) * * Send a packet encapsulated into EEP through the client socket. * This function will only handle SIP packets if EEP client mode * has been enabled. * * @param pkt Packet Structure data * @return 1 on any error occurs, 0 otherwise */ int capture_eep_send_v2(capture_packet_t *pkt); /** * @brief Send a captured packet (EEP version 3) * * Send a packet encapsulated into EEP through the client socket. * This function will only handle SIP packets if EEP client mode * has been enabled. * * @param pkt Packet Structure data * @return 1 on any error occurs, 0 otherwise */ int capture_eep_send_v3(capture_packet_t *pkt); /** * @brief Wrapper for receiving packet in configured EEP version * * @return NULL on any error, packet structure otherwise */ capture_packet_t * capture_eep_receive(); /** * @brief Received a captured packet (EEP version 2) * * Wait for a packet to be received through the EEP server. This * function will parse received EEP data and create a new packet * structure. * * @return NULL on any error, packet structure otherwise */ capture_packet_t * capture_eep_receive_v2(); /** * @brief Received a captured packet (EEP version 3) * * Wait for a packet to be received through the EEP server. This * function will parse received EEP data and create a new packet * structure. * * @return NULL on any error, packet structure otherwise */ capture_packet_t * capture_eep_receive_v3(); /** * @brief Set EEP server url * * Set EEP servermode settings using a url in the format: * - proto:address:port * For example: * - udp:10.10.0.100:9060 * - udp:0.0.0.0:9960 * * @param url URL to be parsed * @return 0 if url has been parsed, 1 otherwise */ int capture_eep_set_server_url(const char *url); /** * @brief Set EEP client url * * Set EEP clientmode settings using a url in the format: * - proto:address:port * For example: * - udp:10.10.0.100:9060 * - udp:0.0.0.0:9960 * * @param url URL to be parsed * @return 0 if url has been parsed, 1 otherwise */ int capture_eep_set_client_url(const char *url); #endif /* __SNGREP_CAPTURE_EEP_H */ sngrep-1.2.0/src/rtp.h0000644000175000017500000001725312632250522013616 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file rtp.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage rtp captured packets * * @note RTP_VERSION and RTP_PAYLOAD_TYPE macros has been taken from wireshark * source code: packet-rtp.c */ #ifndef __SNGREP_RTP_H #define __SNGREP_RTP_H #include "config.h" #include "capture.h" #include "media.h" // Version is the first 2 bits of the first octet #define RTP_VERSION(octet) ((octet) >> 6) // Payload type is the last 7 bits #define RTP_PAYLOAD_TYPE(octet) ((octet) & 0x7F) // Handled RTP versions #define RTP_VERSION_RFC1889 2 // RTCP header types //! http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml enum rtcp_header_types { RTCP_HDR_SR = 200, RTCP_HDR_RR, RTCP_HDR_SDES, RTCP_HDR_BYE, RTCP_HDR_APP, RTCP_RTPFB, RTCP_PSFB, RTCP_XR, RTCP_AVB, RTCP_RSI, RTCP_TOKEN, }; //! http://www.iana.org/assignments/rtcp-xr-block-types/rtcp-xr-block-types.xhtml enum rtcp_xr_block_types { RTCP_XR_LOSS_RLE = 1, RTCP_XR_DUP_RLE, RTCP_XR_PKT_RXTIMES, RTCP_XR_REF_TIME, RTCP_XR_DLRR, RTCP_XR_STATS_SUMRY, RTCP_XR_VOIP_METRCS, RTCP_XR_BT_XNQ, RTCP_XR_TI_VOIP, RTCP_XR_PR_LOSS_RLE, RTCP_XR_MC_ACQ, RTCP_XR_IDMS }; //! Shorter declaration of rtp_encoding structure typedef struct rtp_encoding rtp_encoding_t; //! Shorter declaration of rtp_stream structure typedef struct rtp_stream rtp_stream_t; struct rtp_encoding { u_int id; const char *name; const char *format; }; struct rtp_stream { //! Determine stream type uint32_t type; //! Source address and port char ip_src[ADDRESSLEN]; u_short sport; //! Destination address and port char ip_dst[ADDRESSLEN]; u_short dport; //! SDP media that setup this stream sdp_media_t *media; //! Packet count for this stream uint32_t pktcnt; //! Time of first received packet of stream struct timeval time; // Stream information (depending on type) union { struct { //! Format of first received packet of stre uint32_t fmtcode; } rtpinfo; struct { //! Sender packet count uint32_t spc; //! Fraction lost x/256 uint8_t flost; //! uint8_t discarded x/256 uint8_t fdiscard; //! MOS - listening Quality uint8_t mosl; //! MOS - Conversational Quality uint8_t mosc; } rtcpinfo; }; }; struct rtcp_hdr_generic { //! version (V): 2 bits uint8_t version; //! packet type (PT): 8 bits uint8_t type; //! length: 16 bits uint16_t len; }; struct rtcp_hdr_sr { //! version (V): 2 bits uint8_t version:2; //! padding (P): 1 bit uint8_t padding:1; //! reception report count (RC): 5 bits uint8_t rcount:5; //! packet type (PT): 8 bits uint8_t type; //! length: 16 bits uint16_t len; //! SSRC: 32 bits uint32_t ssrc; //! NTP timestamp: 64 bits uint64_t ntpts; //! RTP timestamp: 32 bits uint32_t rtpts; //! sender's packet count: 32 bits uint32_t spc; //! sender's octet count: 32 bits uint32_t soc; }; struct rtcp_blk_sr { //! SSRC_n (source identifier): 32 bits uint32_t ssrc; //! fraction lost: 8 bits uint8_t flost; //! cumulative number of packets lost: 24 bits struct { uint8_t pl1; uint8_t pl2; uint8_t pl3; } plost; //! extended highest sequence number received: 32 bits uint32_t hseq; //! interarrival jitter: 32 bits uint32_t ijitter; }; struct rtcp_hdr_xr { //! version (V): 2 bits uint8_t version:2; //! padding (P): 1 bit uint8_t padding:1; //! reserved: 5 bits uint8_t reserved:5; //! packet type (PT): 8 bits uint8_t type; //! length: 16 bits uint16_t len; //! SSRC: 32 bits uint32_t ssrc; }; struct rtcp_blk_xr { //! block type (BT): 8 bits uint8_t type; //! type-specific: 8 bits uint8_t specific; //! length: 16 bits uint16_t len; }; struct rtcp_blk_xr_voip { //! block type (BT): 8 bits uint8_t type; //! type-specific: 8 bits uint8_t reserved; //! length: 16 bits uint16_t len; //! SSRC: 32 bits uint32_t ssrc; //! loss rate: 8 bits uint8_t lrate; //! discard rate: 8 bits uint8_t drate; //! burst density: 8 bits uint8_t bdens; //! gap density: 8 bits uint8_t gdens; //! burst duration: 16 bits uint16_t bdur; //! gap duration: 16 bits uint16_t gdur; //! round trip delay: 16 bits uint16_t rtd; //! end system delay: 16 bits uint16_t esd; //! signal level: 8 bits uint8_t slevel; //! noise level: 8 bits uint8_t nlevel; //! residual echo return loss (RERL): 8 bits uint8_t rerl; //! Gmin: 8 bits uint8_t gmin; //! R factor: 8 bits uint8_t rfactor; //! ext. R factor: 8 bits uint8_t xrfactor; //! MOS-LQ: 8 bits uint8_t moslq; //! MOS-CQ: 8 bits uint8_t moscq; //! receiver configuration byte (RX config): 8 bits uint8_t rxc; //! packet loss concealment (PLC): 2 bits uint8_t plc:2; //! jitter buffer adaptive (JBA): 2 bits uint8_t jba:2; //! jitter buffer rate (JB rate): 4 bits uint8_t jbrate:4; //! reserved: 8 bits uint8_t reserved2; //! jitter buffer nominal delay (JB nominal): 16 bits uint16_t jbndelay; //! jitter buffer maximum delay (JB maximum): 16 bits uint16_t jbmdelay; //! jitter buffer absolute maximum delay (JB abs max): 16 bits uint16_t jbadelay; }; rtp_stream_t * stream_create(sdp_media_t *media, const char *dst, u_short dport, int type); rtp_stream_t * stream_complete(rtp_stream_t *stream, const char *src, u_short sport); void stream_set_format(rtp_stream_t *stream, uint32_t format); void stream_add_packet(rtp_stream_t *stream, capture_packet_t *packet); uint32_t stream_get_count(rtp_stream_t *stream); struct sip_call * stream_get_call(rtp_stream_t *stream); const char * stream_get_format(rtp_stream_t *stream); const char * rtp_get_standard_format(u_int code); rtp_stream_t * rtp_check_packet(capture_packet_t *packet); rtp_stream_t * rtp_find_stream(const char *ip_src, u_short sport, const char *ip_dst, u_short dport, u_int format); rtp_stream_t * rtp_find_call_stream(struct sip_call *call, const char *ip_src, u_short sport, const char *ip_dst, u_short dport); /** * @brief Check if a message is older than other * * @param one rtp stream pointer * @param two rtp stream pointer * @return 1 if one is older than two * @return 0 if equal or two is older than one */ int stream_is_older(rtp_stream_t *one, rtp_stream_t *two); int stream_is_complete(rtp_stream_t *stream); #endif /* __SNGREP_RTP_H */ sngrep-1.2.0/src/ui_settings.h0000644000175000017500000001706412632250522015346 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_settings.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to change sngrep configurable settings * * This file contains the functions to display the interface panel that handles * the changes of settings in realtime, also allowing to save them. * */ #ifndef __SNGREP_UI_SETTINGS_H #define __SNGREP_UI_SETTINGS_H //! Sorter declaration of struct option_info typedef struct settings_info settings_info_t; //! Sorter declaration of struct settings_category typedef struct settings_category settings_category_t; //! Sorter declaration of struct settings_entry typedef struct settings_entry settings_entry_t; enum settings_category_list { CAT_SETTINGS_INTERFACE = 1, CAT_SETTINGS_CAPTURE, CAT_SETTINGS_CALL_FLOW, CAT_SETTINGS_EEP_HOMER, CAT_SETTINGS_COUNT, }; /** * @brief Enum of available dialog fields * * Dialog form has a field array. Following enum represents the * order this fields are stored in panel info structure. * */ enum settings_field_list { FLD_SETTINGS_BACKGROUND = 0, FLD_SETTINGS_BACKGROUND_LB, FLD_SETTINGS_SYNTAX, FLD_SETTINGS_SYNTAX_LB, FLD_SETTINGS_SYNTAX_TAG, FLD_SETTINGS_SYNTAX_TAG_LB, FLD_SETTINGS_SYNTAX_BRANCH, FLD_SETTINGS_SYNTAX_BRANCH_LB, FLD_SETTINGS_ALTKEY_HINT, FLD_SETTINGS_ALTKEY_HINT_LB, FLD_SETTINGS_COLORMODE, FLD_SETTINGS_COLORMODE_LB, FLD_SETTINGS_EXITPROMPT, FLD_SETTINGS_EXITPROMPT_LB, FLD_SETTINGS_DISPLAY_HOST, FLD_SETTINGS_DISPLAY_HOST_LB, FLD_SETTINGS_DISPLAY_ALIAS, FLD_SETTINGS_DISPLAY_ALIAS_LB, FLD_SETTINGS_CAPTURE_RTP, FLD_SETTINGS_CAPTURE_RTP_LB, FLD_SETTINGS_CAPTURE_LIMIT, FLD_SETTINGS_CAPTURE_LIMIT_LB, FLD_SETTINGS_CAPTURE_DEVICE, FLD_SETTINGS_CAPTURE_DEVICE_LB, FLD_SETTINGS_CAPTURE_LOOKUP, FLD_SETTINGS_CAPTURE_LOOKUP_LB, FLD_SETTINGS_SIP_NOINCOMPLETE, FLD_SETTINGS_SIP_NOINCOMPLETE_LB, FLD_SETTINGS_SIP_CALLS, FLD_SETTINGS_SIP_CALLS_LB, FLD_SETTINGS_SAVEPATH, FLD_SETTINGS_SAVEPATH_LB, FLD_SETTINGS_CF_FORCERAW, FLD_SETTINGS_CF_FORCERAW_LB, FLD_SETTINGS_CF_SPLITCACALLID, FLD_SETTINGS_CF_SPLITCACALLID_LB, FLD_SETTINGS_CF_SDPONLY, FLD_SETTINGS_CF_SDPONLY_LB, FLD_SETTINGS_CF_SCROLLSTEP, FLD_SETTINGS_CF_SCROLLSTEP_LB, FLD_SETTINGS_CF_HIGHTLIGHT, FLD_SETTINGS_CF_HIGHTLIGHT_LB, FLD_SETTINGS_CF_LOCALHIGHLIGHT, FLD_SETTINGS_CF_LOCALHIGHLIGHT_LB, FLD_SETTINGS_CF_DELTA, FLD_SETTINGS_CF_DELTA_LB, FLD_SETTINGS_CF_MEDIA, FLD_SETTINGS_CF_MEDIA_LB, FLD_SETTINGS_EEP_SEND, FLD_SETTINGS_EEP_SEND_LB, FLD_SETTINGS_EEP_SEND_VER, FLD_SETTINGS_EEP_SEND_VER_LB, FLD_SETTINGS_EEP_SEND_ADDR, FLD_SETTINGS_EEP_SEND_ADDR_LB, FLD_SETTINGS_EEP_SEND_PORT, FLD_SETTINGS_EEP_SEND_PORT_LB, FLD_SETTINGS_EEP_SEND_PASS, FLD_SETTINGS_EEP_SEND_PASS_LB, FLD_SETTINGS_EEP_LISTEN, FLD_SETTINGS_EEP_LISTEN_LB, FLD_SETTINGS_EEP_LISTEN_VER, FLD_SETTINGS_EEP_LISTEN_VER_LB, FLD_SETTINGS_EEP_LISTEN_ADDR, FLD_SETTINGS_EEP_LISTEN_ADDR_LB, FLD_SETTINGS_EEP_LISTEN_PORT, FLD_SETTINGS_EEP_LISTEN_PORT_LB, FLD_SETTINGS_EEP_LISTEN_PASS, FLD_SETTINGS_EEP_LISTEN_PASS_LB, FLD_SETTINGS_COUNT, }; enum settings_button_list { BTN_SETTINGS_ACCEPT = 0, BTN_SETTINGS_SAVE, BTN_SETTINGS_CANCEL, BTN_SETTINGS_COUNT, }; #define SETTINGS_ENTRY_COUNT (FLD_SETTINGS_COUNT - 3) struct settings_category { // Category id enum settings_category_list cat_id; // Category label const char *title; }; struct settings_entry { enum settings_category_list cat_id; //! Field id in settings_info array enum settings_field_list field_id; //! Setting id of current entry enum setting_id setting_id; //! Entry text const char *label; }; /** * @brief settings panel private information * * This structure contains the durable data of settings panel. */ struct settings_info { // Window containing form data (and buttons) WINDOW *form_win; //! Form that contains the filter fields FORM *form; //! An array of fields FIELD *fields[FLD_SETTINGS_COUNT + 1]; //! Form that contains the buttons FORM *buttons_form; //! Array of panel buttons FIELD *buttons[BTN_SETTINGS_COUNT + 1]; //! Active form FORM *active_form; //! Active category enum settings_category_list active_category; }; /** * @brief Creates a new settings panel * * This function allocates all required memory for * displaying the save panel. It also draws all the * static information of the panel that will never be * redrawn. * * @return a panel pointer */ PANEL * settings_create(); /** * @brief Destroy settings panel * * This function do the final cleanups for this panel */ void settings_destroy(); /** * @brief Get custom information of given panel * * Return ncurses users pointer of the given panel into panel's * information structure pointer. * * @param panel Ncurses panel pointer * @return a pointer to info structure of given panel */ settings_info_t * settings_info(PANEL *panel); /** * @brief Draw the settings panel * * This function will drawn the panel into the screen with * current status settings * * @param panel Ncurses panel pointer * @return 0 if the panel has been drawn, -1 otherwise */ int settings_draw(PANEL *panel); /** * @brief Manage pressed keys for settings panel * * This function is called by UI manager every time a * key is pressed. This allow the filter panel to manage * its own keys. * If this function return 0, the key will not be handled * by ui manager. Otherwise the return will be considered * a key code. * * @param panel Settings panel pointer * @param key key code * @return 0 if the key is handled, keycode otherwise */ int settings_handle_key(PANEL *panel, int key); /** * @brief Return entry information of the field * * If field is storing a setting value, return the entry * structure associated to the setting * * @param field Ncurses field pointer of screen * @return Setting information structure */ settings_entry_t * ui_settings_is_entry(FIELD *field); /** * @brief Update settings with panel values * * Update all settings with the selected on screen. * Note that some settings require application restart to * take effect. * * @param panel Settings panel pointer * @return 0 in all cases */ int ui_settings_update_settings(PANEL *panel); /** * @brief Update user resource file with panel values * * Save all settings into user configuration file located * in it's home directory. * * @param panel Settings panel pointer */ void ui_settings_save(PANEL *panel); #endif /* __SNGREP_UI_SETTINGS_H */ sngrep-1.2.0/src/Makefile.am0000644000175000017500000000102012632250522014655 0ustar vsevavsevabin_PROGRAMS=sngrep sngrep_SOURCES=capture.c if USE_EEP sngrep_SOURCES+=capture_eep.c endif if WITH_GNUTLS sngrep_SOURCES+=capture_gnutls.c endif if WITH_OPENSSL sngrep_SOURCES+=capture_openssl.c endif sngrep_SOURCES+=sip.c sip_call.c sip_msg.c sip_attr.c main.c option.c sngrep_SOURCES+=group.c filter.c keybinding.c media.c setting.c rtp.c util.c vector.c sngrep_SOURCES+=ui_manager.c ui_call_list.c ui_call_flow.c ui_call_raw.c ui_stats.c sngrep_SOURCES+=ui_filter.c ui_save.c ui_msg_diff.c ui_column_select.c ui_settings.c sngrep-1.2.0/src/setting.h0000644000175000017500000001263312632250522014463 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file setting.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage application settings * * This file contains the functions to manage application settings and * optionuration resource files. Configuration will be parsed in this order, * from less to more priority, so the later will overwrite the previous. * * - Initialization * - \@sysdir\@/sngreprc * - $HOME/.sngreprc * * This is a basic approach to configuration, but at least a minimun is required * for those who can not see all the list columns or want to disable colours in * every sngrep execution. */ #ifndef __SNGREP_SETTING_H #define __SNGREP_SETTING_H //! Max setting value #define MAX_SETTING_LEN 80 //! Shorter declarartion of setting_option struct typedef struct setting_option setting_t; //! Generic setting formats #define SETTING_ENUM_ONOFF (const char *[]){ "on", "off", NULL } #define SETTING_ENUM_YESNO (const char *[]){ "yes", "no", NULL } #define SETTING_ENUM_BACKGROUND (const char *[]){ "dark" , "default", NULL } #define SETTING_ENUM_COLORMODE (const char *[]){ "request", "cseq", "callid", NULL } #define SETTING_ENUM_HIGHLIGHT (const char *[]){ "bold", "reverse", "reversebold", NULL } #define SETTING_ENUM_SDP_INFO (const char *[]){ "off", "first", "full", "compressed", NULL} #define SETTING_ENUM_STORAGE (const char *[]){ "none", "memory", NULL } #define SETTING_ENUM_HEPVERSION (const char *[]){ "2", "3", NULL } #define SETTING_ENUM_MEDIA (const char *[]){ "on", "off", "rtcp", NULL } //! Other useful defines #define SETTING_ON "on" #define SETTING_OFF "off" #define SETTING_YES "yes" #define SETTING_NO "no" //! Available setting Options enum setting_id { SETTING_BACKGROUND = 0, SETTING_COLORMODE, SETTING_SYNTAX, SETTING_SYNTAX_TAG, SETTING_SYNTAX_BRANCH, SETTING_ALTKEY_HINT, SETTING_EXITPROMPT, SETTING_CAPTURE_LIMIT, SETTING_CAPTURE_LOOKUP, SETTING_CAPTURE_DEVICE, SETTING_CAPTURE_OUTFILE, SETTING_CAPTURE_KEYFILE, SETTING_CAPTURE_RTP, SETTING_CAPTURE_STORAGE, SETTING_SIP_NOINCOMPLETE, SETTING_SIP_CALLS, SETTING_SAVEPATH, SETTING_DISPLAY_HOST, SETTING_DISPLAY_ALIAS, SETTING_CL_SCROLLSTEP, SETTING_CL_COLORATTR, SETTING_CL_AUTOSCROLL, SETTING_CF_FORCERAW, SETTING_CF_RAWMINWIDTH, SETTING_CF_RAWFIXEDWIDTH, SETTING_CF_SPLITCALLID, SETTING_CF_HIGHTLIGHT, SETTING_CF_SCROLLSTEP, SETTING_CF_LOCALHIGHLIGHT, SETTING_CF_SDP_INFO, SETTING_CF_MEDIA, SETTING_CF_DELTA, SETTING_CR_SCROLLSTEP, SETTING_FILTER_METHODS, SETTING_EEP_SEND, SETTING_EEP_SEND_VER, SETTING_EEP_SEND_ADDR, SETTING_EEP_SEND_PORT, SETTING_EEP_SEND_PASS, SETTING_EEP_LISTEN, SETTING_EEP_LISTEN_VER, SETTING_EEP_LISTEN_ADDR, SETTING_EEP_LISTEN_PORT, SETTING_EEP_LISTEN_PASS, SETTING_COUNT }; //! Available setting formats enum setting_fmt { SETTING_FMT_STRING = 0, SETTING_FMT_NUMBER, SETTING_FMT_ENUM, }; /** * @brief Configurable Setting structure */ struct setting_option { //! Setting id enum setting_id id; //! Setting name const char *name; //! Setting format enum setting_fmt fmt; //! Value of the setting char value[MAX_SETTING_LEN]; //! Compa separated valid values const char **valuelist; }; setting_t * setting_by_id(int id); setting_t * setting_by_name(const char *name); /** * @brief Return the setting id of a given string * * @param name String representing configurable setting * @return setting id or -1 if setting is not found */ int setting_id(const char *name); /** * @brief Return string representing given setting id * * @param id Setting id from settings enum * @return string representation of setting or NULL */ const char * setting_name(int id); int setting_format(int id); const char ** setting_valid_values(int id); const char* setting_get_value(int id); int setting_get_intvalue(int id); void setting_set_value(int id, const char *value); void setting_set_intvalue(int id, int value); int setting_enabled(int id); int setting_disabled(int id); int setting_has_value(int id, const char *value); void setting_toggle(int id); const char * setting_enum_next(int id, const char *value); /** * @brief Dump configuration settings * * This function will print to stdout configuration settings * after reading system/local/user resource files (in that order). * */ void settings_dump(); #endif /* __SNGREP_SETTING_H */ sngrep-1.2.0/src/vector.h0000644000175000017500000001345712632250522014315 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file vector.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage lists of pointers * * */ #ifndef __SNGREP_VECTOR_H_ #define __SNGREP_VECTOR_H_ #include "config.h" #include //! Shorter declaration of vector structure typedef struct vector vector_t; //! Shorter declaration of iterator structure typedef struct vector_iter vector_iter_t; /** * @brief Structure to hold a list of pointers */ struct vector { //! Number of elements in list u_int count; //! Total space in list (available + elements) u_int limit; //! Number of new spaces to be reallocated u_short step; //! Elements of the vector void **list; //! Function to destroy one item void (*destroyer) (void *item); //! Function to sort each appended/inserted item void (*sorter) (vector_t *vector, void *item); }; struct vector_iter { //! Last requested position int current; //! Vector that's being iterated vector_t *vector; //! Filter iterator results using this func int (*filter) (void *item); }; /** * @brief Create a new vector * * Create a new vector with initial size and * step increase settings. */ vector_t * vector_create(int limit, int step); /** * @brief Free vector memory */ void vector_destroy(vector_t *vector); /** * @brief Clone a vector container * * The cloned vector will have its own storage of pointers * **but the items in its list will be shared with the * original vector** * * Use with caution, specially with vector that have sorter * or destroyer functions. */ vector_t * vector_clone(vector_t *original); /** * @brief Remove all items of vector * */ void vector_clear(vector_t *vector); /** * @brief Append an item to vector * * Item will be added at the end of the * items list. * * @return index of the appended item */ int vector_append(vector_t *vector, void *item); /** * @brief Insert an item in a given vector position * * @return count of elements in vector */ int vector_insert(vector_t *vector, void *item, int pos); /** * @brief Remove itemn from vector */ void vector_remove(vector_t *vector, void *item); /** * @brief Set the vector destroyer * * A destroyer is a function that will be invoked * for each item when the vector is destroyed or an * item is removed. */ void vector_set_destroyer(vector_t *vector, void (*destroyer) (void *item)); /** * @brief Set the vector sorter * * The sorter function will be invoked every time a new * item is appended into the vector. * */ void vector_set_sorter(vector_t *vector, void (*sorter) (vector_t *vector, void *item)); /** * @brief A generic item destroyer * * Generic memory deallocator for those items that only * require a simple 'free' */ void vector_generic_destroyer(void *item); /** * @brief Get an item from vector * * Return the item at given index, or NULL * if index is out of the vector bounds * */ void * vector_item(vector_t *vector, int index); /** * @brief Set an item in a given index * * This funtion will set an item in a given index. * The index MUST be in the already allocated memory * of the vector. This can be used to replace a vector * item. If position is already in use, destroyer won't * be call for existing item. */ void vector_set_item(vector_t *vector, int index, void *item); /** * @brief Return first item of the vector */ void * vector_first(vector_t *vector); /** * @brief Return last item of the vector */ void * vector_last(vector_t *vector); /** * @brief Get the index of an item * * Return the index of item in vector or -1 if * the item is not found */ int vector_index(vector_t *vector, void *item); /** * @brief Return the number of items of vector */ int vector_count(vector_t *vector); /** * @brief Return a new iterator for given vector */ vector_iter_t vector_iterator(vector_t *vector); /** * @brief Return the vector of this iterator */ vector_t * vector_iterator_vector(vector_iter_t *it); /** * @brief Return the number of items of iterator */ int vector_iterator_count(vector_iter_t *it); /** * @brief Return next element of iterator */ void * vector_iterator_next(vector_iter_t *it); /** * @brief Return prev element of iterator */ void * vector_iterator_prev(vector_iter_t *it); /** * @brief Set iterator filter funcion * * Filter iterator results using given function */ void vector_iterator_set_filter(vector_iter_t *it, int (*filter) (void *item)); /** * @brief Set current iterator position */ void vector_iterator_set_current(vector_iter_t *it, int current); /** * @brief Set iterator position to the last element */ void vector_iterator_set_last(vector_iter_t *it); /** * @brief Return current iterator position */ int vector_iterator_current(vector_iter_t *it); /** * @brief Reset iterator position to initial */ void vector_iterator_reset(vector_iter_t *it); #endif /* __SNGREP_VECTOR_H_ */ sngrep-1.2.0/src/ui_call_flow.h0000644000175000017500000002676112632250522015454 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013-2015 Ivan Alonso (Kaian) ** Copyright (C) 2013-2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_call_flow.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage Call Flow screen * * This file contains the functions and structures to manage the call flow * screen. Call flow screen display a ladder of arrows corresponding to the * SIP messages and RTP streams of the selected dialogs. * * Some basic ascii art of this panel. * * +--------------------------------------------------------+ * | Title | * | addr1 addr2 addr3 addr4 | Selected Raw Message | * | ----- ----- ----- ----- | preview | * | Tmst| | | | | | * | Tmst|----->| | | | | * | Tmst| |----->| | | | * | Tmst| |<-----| | | | * | Tmst| | |----->| | | * | Tmst|<-----| | | | | * | Tmst| |----->| | | | * | Tmst| |<-----| | | | * | Tmst| |------------>| | | * | Tmst| |<------------| | | * | | | | | | | * | | | | | | | * | | | | | | | * | Useful hotkeys | * +--------------------------------------------------------+ * */ #ifndef __SNGREP_UI_CALL_FLOW_H #define __SNGREP_UI_CALL_FLOW_H #include "ui_manager.h" #include "group.h" //! Sorter declaration of struct call_flow_info typedef struct call_flow_info call_flow_info_t; //! Sorter declaration of struct call_flow_column typedef struct call_flow_column call_flow_column_t; //! Sorter declaration of struct call_flow_arrow typedef struct call_flow_arrow call_flow_arrow_t; /** * @brief Call flow arrow types */ enum call_flow_arrow_type { CF_ARROW_SIP, CF_ARROW_RTP, CF_ARROW_RTCP, }; /** * @brief Call Flow arrow information */ struct call_flow_arrow { //! Type of arrow @see call_flow_arrow_type int type; //! Msg pointer for SIP type arrows sip_msg_t *msg; //! Stream information for RTP type arrows rtp_stream_t *stream; //! Stream packet count for this arrow int rtp_count; //! Stream arrow position int rtp_ind_pos; //! Number of screen lines this arrow uses int height; //! Line of flow window this line starts int line; //! Index in the arrow vector int index; }; /** * @brief Structure to hold one column information */ struct call_flow_column { char addr[ADDRESSLEN]; const char *callid; const char *callid2; int colpos; }; /** * @brief Call flow Extended status information * * This data stores the actual status of the panel. It's stored in the * PANEL user pointer. */ struct call_flow_info { //! Window to display SIP payload WINDOW *raw_win; //! Window to diplay arrows WINDOW *flow_win; //! Group of calls displayed on the panel sip_call_group_t *group; //! Last processed message sip_msg_t *last_msg; //! List of arrows (call_flow_arrow_t *) vector_t *arrows; //! First printed arrow of the panel call_flow_arrow_t *first_arrow; //! Current arrow where the cursor is call_flow_arrow_t *cur_arrow; //! Selected arrow to compare call_flow_arrow_t *selected; //! Width of raw_win int raw_width; //! Current line for scrolling int cur_line; //! List of columns in the panel vector_t *columns; }; /** * @brief Create Call Flow extended panel * * This function will allocate the ncurses pointer and draw the static * stuff of the screen (which usually won't be redrawn) * It will also create an information structure of the panel status and * store it in the panel's userpointer * * @return the allocated ncurses panel */ PANEL * call_flow_create(); /** * @brief Destroy panel * * This function will hide the panel and free all allocated memory. * * @return panel Ncurses panel pointer */ void call_flow_destroy(PANEL *panel); /** * @brief Get custom information of given panel * * Return ncurses users pointer of the given panel into panel's * information structure pointer. * * @param panel Ncurses panel pointer * @return a pointer to info structure of given panel */ call_flow_info_t * call_flow_info(PANEL *panel); /** * @brief Draw the Call flow extended panel * * This function will drawn the panel into the screen based on its stored * status * * @param panel Ncurses panel pointer * @return 0 if the panel has been drawn, -1 otherwise */ int call_flow_draw(PANEL *panel); /** * @brief Draw the footer of the panel with keybindings info * * @param panel Ncurses panel pointer */ void call_flow_draw_footer(PANEL *panel); /** * @brief Draw the visible columns in panel window * * @param panel Ncurses panel pointer */ int call_flow_draw_columns(PANEL *panel); /** * @brief Draw the message arrow in the given line * * Draw the given message arrow in the given line. * This function will calculate origin and destination coordinates * base on message information. Each message use multiple lines * depending on the display mode of call flow * * @param panel Ncurses panel pointer * @param arrow Call flow arrow to be drawn * @param cline Window line to draw the message * @return the arrow passed as parameter */ call_flow_arrow_t * call_flow_draw_message(PANEL *panel, call_flow_arrow_t *arrow, int cline); /** * @brief Draw the stream data in the given line * * Draw the given arrow of type stream in the given line. * * @param panel Ncurses panel pointer * @param arrow Call flow arrow to be drawn * @param cline Window line to draw the message * @return the arrow passed as parameter */ call_flow_arrow_t * call_flow_draw_rtp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline); /** * @brief Draw the RTCP stream data in the given line * * Draw the given arrow of type stream in the given line. * * @param panel Ncurses panel pointer * @param arrow Call flow arrow to be drawn * @param cline Window line to draw the message * @return the arrow passed as parameter */ call_flow_arrow_t * call_flow_draw_rtcp_stream(PANEL *panel, call_flow_arrow_t *arrow, int cline); /** * @brief Get the next chronological arrow * * Give the next arrow taking into account Call list display mode. * * @param panel Ncurses panel pointer * @param cur Current arrow to use as reference * @return next chronological arrow */ call_flow_arrow_t * call_flow_next_arrow(PANEL *panel, const call_flow_arrow_t *cur); /** * @brief Get the previous chronological arrow * * Give the previous arrow taking into account Call list display mode. * * @param panel Ncurses panel pointer * @param cur Current arrow to use as reference * @return previous chronological arrow */ call_flow_arrow_t * call_flow_prev_arrow(PANEL *panel, const call_flow_arrow_t *cur); /** * @brief Get how many lines of screen an arrow will use * * Depending on the arrow tipe and panel display mode lines can * take more than two lines. This function will calculate how many * lines the arrow will use. * * @param panel Ncurses panel pointer * @param arrow Arrow structure to calculate height * @return height the arrow will have */ int call_flow_arrow_height(PANEL *panel, const call_flow_arrow_t *arrow); /** * @brief Return the arrow of a SIP msg or RTP stream * * This function will try to find an existing arrow with a * message or stream equals to the giving pointer. * * @param panel Ncurses panel pointer * @param data Data to search in the arrow structure * @return a pointer to the found arrow or NULL */ call_flow_arrow_t * call_flow_arrow_find(PANEL *panel, const void *data); /** * @brief Return the SIP message associated with the arrow * * Return the SIP message. If the arrow is of type SIP msg, it will * return the message itself. If the arrow is of type RTP stream, * it will return the SIP msg that setups the stream. * * @param arrow Call Flow Arrow pointer * @return associated SIP message with the arrow */ sip_msg_t * call_flow_arrow_message(const call_flow_arrow_t *arrow); /** * @brief Draw raw panel with message payload * * Draw the given message payload into the raw window. * * @param panel Ncurses panel pointer * @param msg Message data to draw * @return 0 in all cases */ int call_flow_draw_raw(PANEL *panel, sip_msg_t *msg); /** * @brief Draw raw panel with RTCP data * * Draw the given stream data into the raw window. * * @param panel Ncurses panel pointer * @param rtcp stream containing the RTCP conection data * @return 0 in all cases */ int call_flow_draw_raw_rtcp(PANEL *panel, rtp_stream_t *rtcp); /** * @brief Handle Call flow extended key strokes * * This function will manage the custom keybindings of the panel. If this * function returns -1, the ui manager will check if the pressed key * is one of the common ones (like toggle colors and so). * * @param panel Ncurses panel pointer * @param key Pressed keycode * @return 0 if the function can handle the key, key otherwise */ int call_flow_handle_key(PANEL *panel, int key); /** * @brief Request the panel to show its help * * This function will request to panel to show its help (if any) by * invoking its help function. * * @param panel Ncurses panel pointer * @return 0 if the screen has help, -1 otherwise */ int call_flow_help(PANEL *panel); /** * @brief Set the group call of the panel * * This function will access the panel information and will set the * group call pointer to the processed calls. * * @param group Call group pointer to be set in the internal info struct */ int call_flow_set_group(sip_call_group_t *group); /** * @brief Add a new column (if required) * * Check if the given callid and address has already a column. * If not, create a new call for that callid/address * Each column has one address and two callids (unless split mode * is disabled) * * @param panel Ncurses panel pointer * @param callid Call-Id header of SIP payload * @param addr Address:port string */ void call_flow_column_add(PANEL *panel, const char *callid, const char *addr); /** * @brief Get a flow column data * * @param panel Ncurses panel pointer * @param callid Call-Id header of SIP payload * @param addr Address:port string * @return column structure pointer or NULL if not found */ call_flow_column_t * call_flow_column_get(PANEL *panel, const char *callid, const char *addr); #endif /* __SNGREP_UI_CALL_FLOW_H */ sngrep-1.2.0/src/capture_openssl.h0000644000175000017500000002764712632250522016227 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ** In addition, as a special exception, the copyright holders give ** permission to link the code of portions of this program with the ** OpenSSL library under certain conditions as described in each ** individual source file, and distribute linked combinations ** including the two. ** You must obey the GNU General Public License in all respects ** for all of the code used other than OpenSSL. If you modify ** file(s) with this exception, you may extend this exception to your ** version of the file(s), but you are not obligated to do so. If you ** do not wish to do so, delete this exception statement from your ** version. If you delete this exception statement from all source ** files in the program, then also delete it here. ** ****************************************************************************/ /** * @file capture_tls.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP TLS messages * * This file contains the functions and structures to manage the SIP messages * that use TLS as transport. * */ #ifndef __SNGREP_CAPTURE_TLS_ #define __SNGREP_CAPTURE_TLS_ #include "config.h" #include #include #include #include #include "capture.h" //! Cast two bytes into decimal (Big Endian) #define UINT16_INT(i) ((i.x[0] << 8) | i.x[1]) //! Cast three bytes into decimal (Big Endian) #define UINT24_INT(i) ((i.x[0] << 16) | (i.x[1] << 8) | i.x[2]) //! One byte unsigned integer typedef unsigned char uint8; //! Two bytes unsigned integer typedef struct uint16 { unsigned char x[2]; } uint16; //! Three bytes unsigned integer typedef struct uint24 { unsigned char x[3]; } uint24; //! Four bytes unsigned interger typedef struct uint32 { unsigned char x[4]; } uint32; //! One byte generic type typedef unsigned char opaque; //! SSLConnections states enum SSLConnectionState { //! Initial SYN packet has been received from client TCP_STATE_SYN = 0, //! SYN/ACK packet has been sent from the server TCP_STATE_SYN_ACK, //! Client ACK'ed the connection TCP_STATE_ACK, //! Connection is up, now SSL handshake should start! TCP_STATE_ESTABLISHED, //! Connection about to end TCP_STATE_FIN, //! Connection closed TCP_STATE_CLOSED }; //! ContentType values as defined in RFC5246 enum ContentType { change_cipher_spec = SSL3_RT_CHANGE_CIPHER_SPEC, alert = SSL3_RT_ALERT, handshake = SSL3_RT_HANDSHAKE, application_data = SSL3_RT_APPLICATION_DATA }; //! HanshakeType values as defined in RFC5246 enum HandshakeType { hello_request = SSL3_MT_HELLO_REQUEST, client_hello = SSL3_MT_CLIENT_HELLO, server_hello = SSL3_MT_SERVER_HELLO, certificate = SSL3_MT_CERTIFICATE, certificate_request = SSL3_MT_CERTIFICATE_REQUEST, server_hello_done = SSL3_MT_SERVER_DONE, certificate_verify = SSL3_MT_CERTIFICATE_VERIFY, client_key_exchange = SSL3_MT_CLIENT_KEY_EXCHANGE, finished = SSL3_MT_FINISHED }; //! ProtocolVersion header as defined in RFC5246 struct ProtocolVersion { uint8 major; uint8 minor; }; //! TLSPlaintext record structure struct TLSPlaintext { uint8 type; struct ProtocolVersion version; uint16 length; }; //! Hanshake record structure struct Handshake { uint8 type; uint24 length; }; //! Handshake random structure struct Random { uint32 gmt_unix_time; opaque random_bytes[28]; }; struct CipherSuite { uint8 cs1; uint8 cs2; }; //! ClientHello type in Handshake records struct ClientHello { struct ProtocolVersion client_version; struct Random random; // uint8 session_id_length; // CipherSuite cipher_suite; // Extension extensions; }; //! ServerHello type in Handshake records struct ServerHello { struct ProtocolVersion server_version; struct Random random; uint8 session_id_length; // SessionID session_id; // CipherSuite cipher_suite; // CompressionMethod compression_method; }; struct MasterSecret { uint8 random[48]; }; struct PreMasterSecret { struct ProtocolVersion client_version; uint8 random[46]; }; struct EncryptedPreMasterSecret { uint8 pre_master_secret[128]; }; //! ClientKeyExchange type in Handshake records struct ClientKeyExchange { uint16 length; struct EncryptedPreMasterSecret exchange_keys; }; /** * Structure to store all information from a TLS * connection. This is also used as linked list * node. */ struct SSLConnection { //! Connection status enum SSLConnectionState state; //! Current packet direction int direction; //! Data is encrypted flag int encrypted; //! Client IP address struct in_addr client_addr; //! Server IP address struct in_addr server_addr; //! Client port u_short client_port; //! Server port u_short server_port; SSL *ssl; SSL_CTX *ssl_ctx; EVP_PKEY *server_private_key; const EVP_CIPHER *ciph; struct Random client_random; struct Random server_random; struct CipherSuite cipher_suite; struct PreMasterSecret pre_master_secret; struct MasterSecret master_secret; struct tls_data { uint8 client_write_MAC_key[20]; uint8 server_write_MAC_key[20]; uint8 client_write_key[32]; uint8 server_write_key[32]; uint8 client_write_IV[16]; uint8 server_write_IV[16]; } key_material; EVP_CIPHER_CTX client_cipher_ctx; EVP_CIPHER_CTX server_cipher_ctx; struct SSLConnection *next; }; /** * @brief P_hash expansion function as defined in RFC5246 * * This function will expand Secret and Seed into output using digest * hash function. The amount of data generated will be determined by output * length (dlen). * * @param digest Digest name to get the hash function * @param dest Destination of hash function result. Memory must be already allocated * @param dlen Destination length in bytes * @param secret Input for the hash function * @param sslen Secret length in bytes * @param seed Input for the hash function * @param slen Seed length in bytes * @return Output bytes */ int P_hash(const char *digest, unsigned char *dest, int dlen, unsigned char *secret, int sslen, unsigned char *seed, int slen); /** * @brief Pseudorandom Function as defined in RFC5246 * * This function will generate MasterSecret and KeyMaterial data from PreMasterSecret and Seed * * @param dest Destination of PRF function result. Memory must be already allocated * @param dlen Destination length in bytes * @param pre_master_secret PreMasterSecret decrypted from ClientKeyExchange Handhsake record * @param pslen PreMasterSecret length in bytes * @param label Fixed ASCII string * @param seed Concatenation of Random data from Hello Handshake records * @param slen Seed length in bytes * @return destination length in bytes */ int PRF(unsigned char *dest, int dlen, unsigned char *pre_master_secret, int plen, unsigned char *label, unsigned char *seed, int slen); /** * @brief Create a new SSLConnection * * This will allocate enough memory to store all connection data * from a detected SSL connection. This will also add this structure to * the connections linked list. * * @param caddr Client address * @param cport Client port * @param saddr Server address * @param sport Server port * @return a pointer to a new allocated SSLConnection structure */ struct SSLConnection * tls_connection_create(struct in_addr caddr, u_short cport, struct in_addr saddr, u_short sport); /** * @brief Destroys an existing SSLConnection * * This will free all allocated memory of SSLConnection also removing * the connection from connections list. * * @param conn Existing connection pointer */ void tls_connection_destroy(struct SSLConnection *conn); /** * @brief Check if given keyfile is valid * * This can be used to check if a file contains valid RSA data * * @param keyfile Absolute path the keyfile * @return 1 if file contains RSA private info, 0 otherwise */ int tls_check_keyfile(const char *keyfile); /** * @brief Determines packet direction * * Determine if the given address is from client or server. * * @param conn Existing connection pointer * @param addr Client or server address * @param port Client or server port * @return 0 if address belongs to client, 1 to server or -1 otherwise */ int tls_connection_dir(struct SSLConnection *conn, struct in_addr addr, u_short port); /** * @brief Find a connection * * Try to find connection data for a given address and port. * This address:port convination can be the client or server one. * * @param addr Client or server address * @param port Client or server port * @return an existing Connection pointer or NULL if not found */ struct SSLConnection* tls_connection_find(struct in_addr addr, u_short port); /** * @brief Process a TCP segment to check TLS data * * Check if a TCP segment contains TLS data. In case a TLS record is found * process it and return decrypted data if case of application_data record. * * @param tcp Pointer to tcp header of the packet * @param out Pointer to the output char array. Memory must be already allocated * @param out Number of bytes returned by this function * @return 0 in all cases */ int tls_process_segment(capture_packet_t *packet, struct tcphdr *tcp); /** * @brief Process TLS record data * * Process a TLS record * - If the record type is Handshake process it in tls_process_record_handshake * - If the record type is Application Data process it in tls_process_record_data * * @param conn Existing connection pointer * @param payload Packet peyload * @param len Payload length * @param out pointer to store decryted data * @param outl decrypted data length * @return Decrypted data length */ int tls_process_record(struct SSLConnection *conn, const uint8 *payload, const int len, uint8 **out, uint32_t *outl); /** * @brief Process TLS Handshake record types * * Process all types of Handshake records to store and compute all required * data to decrypt application data packets * * @param conn Existing connection pointer * @param fragment Handshake record data * @return 0 on valid record processed, 1 otherwise */ int tls_process_record_handshake(struct SSLConnection *conn, const opaque *fragment); /** * @brief Process TLS ApplicationData record types * * Process application data record, trying to decrypt it with connection * information * * @param conn Existing connection pointer * @param fragment Application record data * @param len record length in bytes * @param out pointer to store decryted data * @param outl decrypted data length * @return decoded data length */ int tls_process_record_data(struct SSLConnection *conn, const opaque *fragment, const int len, uint8 **out, uint32_t *outl); /** * @brief Get the cipher data from the given connection * * Load cipher pointer depending on the selected cipher in * Handshake messages. * * This function can be used to test is a cipher decrypting is supported * @param conn Existing connection pointer * @return 0 on valid cipher, 1 otherwise */ int tls_connection_load_cipher(struct SSLConnection *conn); #endif sngrep-1.2.0/src/ui_column_select.h0000644000175000017500000001251612632250522016337 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2014,2015 Ivan Alonso (Kaian) ** Copyright (C) 2014,2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_column_select.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage columns select panel */ #ifndef __UI_COLUMN_SELECT_H #define __UI_COLUMN_SELECT_H #include "config.h" #include #include #include "ui_manager.h" #include "sip_attr.h" /** * @brief Enum of available fields */ enum column_select_field_list { FLD_COLUMNS_ACCEPT = 0, FLD_COLUMNS_SAVE, FLD_COLUMNS_CANCEL, //! Never remove this field id FLD_COLUMNS_COUNT }; //! Sorter declaration of struct columns_select_info typedef struct column_select_info column_select_info_t; /** * @brief Column selector panel private information * * This structure contains the durable data of column selection panel. */ struct column_select_info { // Section of panel where menu is being displayed WINDOW *menu_win; // Columns menu MENU *menu; // Columns Items ITEM *items[SIP_ATTR_COUNT + 1]; //! Form that contains the save fields FORM *form; //! An array of window form fields FIELD *fields[FLD_COLUMNS_COUNT + 1]; //! Flag to handle key inputs int form_active; }; /** * @brief Creates a new column selection panel * * This function allocates all required memory for * displaying the column selection panel. It also draws all the * static information of the panel that will never be * redrawn. * * @return a panel pointer */ PANEL * column_select_create(); /** * @brief Destroy column selection panel * * This function do the final cleanups for this panel */ void column_select_destroy(); /** * @brief Get custom information of given panel * * Return ncurses users pointer of the given panel into panel's * information structure pointer. * * @param panel Ncurses panel pointer * @return a pointer to info structure of given panel */ column_select_info_t * column_select_info(PANEL *panel); /** * @brief Manage pressed keys for column selection panel * * This function is called by UI manager every time a * key is pressed. This allow the filter panel to manage * its own keys. * If this function return 0, the key will not be handled * by ui manager. Otherwise the return will be considered * a key code. * * @param panel Column selection panel pointer * @param key key code * @return 0 if the key is handled, keycode otherwise */ int column_select_handle_key(PANEL *panel, int key); /** * @brief Manage pressed keys for column selection panel * * This function will handle keys when menu is active. * You can switch between menu and rest of the components * using TAB * * @param panel Column selection panel pointer * @param key key code * @return 0 if the key is handled, keycode otherwise */ int column_select_handle_key_menu(PANEL *panel, int key); /** * @brief Manage pressed keys for column selection panel * * This function will handle keys when form is active. * You can switch between menu and rest of the components * using TAB * * @param panel Column selection panel pointer * @param key key code * @return 0 if the key is handled, keycode otherwise */ int column_select_handle_key_form(PANEL *panel, int key); /** * @brief Update Call List columns * * This function will update the columns of Call List * * @param panel Column selection panel pointer */ void column_select_update_columns(PANEL *panel); /** * @brief Save selected columns to user config file * * Remove previously configurated columns from user's * $HOME/.sngreprc and add new ones * * @param panel Column selection panel pointer */ void column_select_save_columns(PANEL *panel); /** * @brief Move a item to a new position * * This function can be used to reorder the column list * * @param panel Column selection panel pointer * @param item Menu item to be moved * @param post New position in the menu */ void column_select_move_item(PANEL *panel, ITEM *item, int pos); /** * @brief Select/Deselect a menu item * * This function can be used to toggle selection status of * the menu item * * @param panel Column selection panel pointer * @param item Menu item to be (de)selected */ void column_select_toggle_item(PANEL *panel, ITEM *item); /** * @brief Update menu after a change * * After moving an item or updating its selectioactivn status * menu must be redrawn. * * @param panel Column selection panel pointer */ void column_select_update_menu(PANEL *panel); #endif /* __UI_COLUMN_SELECT_H */ sngrep-1.2.0/src/ui_stats.c0000644000175000017500000002327412632250522014637 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2014 Ivan Alonso (Kaian) ** Copyright (C) 2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_stats.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_stats.h */ /* * +---------------------------------------------------------+ * | Stats Information | * +---------------------------------------------------------+ * | Dialogs: 725 COMPLETED: 7 (22.1%) | * | Calls: 10 CANCELLED: 2 (12.2%) | * | Messages: 200 IN CALL: 10 (60.5%) | * | REJECTED: 0 (0.0%) | * | CALL SETUP: 0 (0.0%) | * +---------------------------------------------------------+ * | INVITE: 10 (0.5%) 1XX: 123 (1.5%) | * | REGISTER: 200 (5.1%) 2XX: 231 (3.1%) | * | SUBSCRIBE: 20 (1.0%) 3XX: 0 (0.0%) | * | UPDATE: 30 (1.3%) 4XX: 12 (1.5%) | * | NOTIFY: 650 (22.7%) 5XX: 0 (0.0%) | * | OPTIONS: 750 (27.4%) 6XX: 3 (0.5%) | * | PUBLISH: 0 (0.0%) 7XX: 0 (0.0%) | * | MESSAGE: 0 (0.0%) 8XX: 0 (0.0%) | * | INFO: 0 (0.0%) | * | ACK: 300 (7.2%) | * | BYE: 10 (0.5%) | * | CANCEL: 0 (0.0%) | * +---------------------------------------------------------+ * | Press any key to continue | * +---------------------------------------------------------+ * */ #include "config.h" #include "vector.h" #include "sip.h" #include "ui_manager.h" #include "ui_stats.h" /** * Ui Structure definition for Stats panel */ ui_t ui_stats = { .type = PANEL_STATS, .panel = NULL, .create = stats_create, .destroy = stats_destroy, .handle_key = stats_handle_key }; PANEL * stats_create() { PANEL *panel; WINDOW *win; int height, width; vector_iter_t calls; vector_iter_t msgs; sip_call_t *call; sip_msg_t *msg; // Counters! struct { int dtotal, dcalls, completed, cancelled, incall, rejected, setup; int mtotal, invite, regist, subscribe, update, notify, options; int publish, message, info, ack, bye, cancel; int r100, r200, r300, r400, r500, r600, r700, r800; } stats; memset(&stats, 0, sizeof(stats)); // Calculate window dimensions height = 23; width = 60; // Cerate a new indow for the panel and form win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); // Create a new panel panel = new_panel(win); // Set the window title and boxes mvwprintw(win, 1, width / 2 - 9, "Stats Information"); wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); title_foot_box(panel); mvwhline(win, 8, 1, ACS_HLINE, width - 1); mvwaddch(win, 8, 0, ACS_LTEE); mvwaddch(win, 8, width - 1, ACS_RTEE); mvwprintw(win, height - 2, width / 2 - 12, "Press any key to continue"); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); // Parse the data calls = sip_calls_iterator(); stats.dtotal = vector_iterator_count(&calls); // Ignore this screen when no dialog exists if (!stats.dtotal) { mvwprintw(win, 3, 3, "No information to display"); return panel; } while ((call = vector_iterator_next(&calls))) { // If this dialog is a call if (call->state) { // Increase call counter stats.dcalls++; // Increase call status counter switch (call->state) { case SIP_CALLSTATE_CALLSETUP: stats.setup++; break; case SIP_CALLSTATE_INCALL: stats.incall++; break; case SIP_CALLSTATE_CANCELLED: stats.cancelled++; break; case SIP_CALLSTATE_REJECTED: stats.rejected++; break; case SIP_CALLSTATE_COMPLETED: stats.completed++; break; } } // For each message in call msgs = vector_iterator(call->msgs); while ((msg = vector_iterator_next(&msgs))) { // Increase message counter stats.mtotal++; // Check message type switch (msg->reqresp) { case SIP_METHOD_REGISTER: stats.regist++; break; case SIP_METHOD_INVITE: stats.invite++; break; case SIP_METHOD_SUBSCRIBE: stats.subscribe++; break; case SIP_METHOD_NOTIFY: stats.notify++; break; case SIP_METHOD_OPTIONS: stats.options++; break; case SIP_METHOD_PUBLISH: stats.publish++; break; case SIP_METHOD_MESSAGE: stats.message++; break; case SIP_METHOD_CANCEL: stats.cancel++; break; case SIP_METHOD_BYE: stats.bye++; break; case SIP_METHOD_ACK: stats.ack++; break; // case SIP_METHOD_PRACK: case SIP_METHOD_INFO: stats.info++; break; // case SIP_METHOD_REFER: case SIP_METHOD_UPDATE: stats.update++; break; default: if (msg->reqresp >= 800) stats.r800++; else if (msg->reqresp >= 700) stats.r700++; else if (msg->reqresp >= 600) stats.r600++; else if (msg->reqresp >= 500) stats.r500++; else if (msg->reqresp >= 400) stats.r400++; else if (msg->reqresp >= 300) stats.r300++; else if (msg->reqresp >= 200) stats.r200++; else if (msg->reqresp >= 100) stats.r100++; } } } // Print parses data mvwprintw(win, 3, 3, "Dialogs: %d", stats.dtotal); mvwprintw(win, 4, 3, "Calls: %d (%.1f\%)", stats.dcalls, (float) stats.dcalls * 100 / stats.dtotal); mvwprintw(win, 5, 3, "Messages: %d", stats.mtotal); // Print status of calls if any if (stats.dcalls) { mvwprintw(win, 3, 33, "COMPLETED: %d (%.1f\%)", stats.completed, (float) stats.completed * 100 / stats.dcalls); mvwprintw(win, 4, 33, "CANCELLED: %d (%.1f\%)", stats.cancelled, (float) stats.cancelled * 100 / stats.dcalls); mvwprintw(win, 5, 33, "IN CALL: %d (%.1f\%)", stats.incall, (float) stats.incall * 100 / stats.dcalls); mvwprintw(win, 6, 33, "REJECTED: %d (%.1f\%)", stats.rejected, (float) stats.rejected * 100 / stats.dcalls); mvwprintw(win, 7, 33, "CALL SETUP: %d (%.1f\%)", stats.setup, (float) stats.setup * 100 / stats.dcalls); } mvwprintw(win, 9, 3, "INVITE: %d (%.1f\%)", stats.invite, (float) stats.invite * 100 / stats.mtotal); mvwprintw(win, 10, 3, "REGISTER: %d (%.1f\%)", stats.regist, (float) stats.regist * 100 / stats.mtotal); mvwprintw(win, 11, 3, "SUBSCRIBE: %d (%.1f\%)", stats.subscribe, (float) stats.subscribe * 100 / stats.mtotal); mvwprintw(win, 12, 3, "UPDATE: %d (%.1f\%)", stats.update, (float) stats.update * 100 / stats.mtotal); mvwprintw(win, 13, 3, "NOTIFY: %d (%.1f\%)", stats.notify, (float) stats.notify * 100 / stats.mtotal); mvwprintw(win, 14, 3, "OPTIONS: %d (%.1f\%)", stats.options, (float) stats.options * 100 / stats.mtotal); mvwprintw(win, 15, 3, "PUBLISH: %d (%.1f\%)", stats.publish, (float) stats.publish * 100 / stats.mtotal); mvwprintw(win, 16, 3, "MESSAGE: %d (%.1f\%)", stats.message, (float) stats.message * 100 / stats.mtotal); mvwprintw(win, 17, 3, "INFO: %d (%.1f\%)", stats.info, (float) stats.info * 100 / stats.mtotal); mvwprintw(win, 18, 3, "BYE: %d (%.1f\%)", stats.bye, (float) stats.bye * 100 / stats.mtotal); mvwprintw(win, 19, 3, "CANCEL: %d (%.1f\%)", stats.cancel, (float) stats.cancel * 100 / stats.mtotal); mvwprintw(win, 9, 33, "1XX: %d (%.1f\%)", stats.r100, (float) stats.r100 * 100 / stats.mtotal); mvwprintw(win, 10, 33, "2XX: %d (%.1f\%)", stats.r200, (float) stats.r200 * 100 / stats.mtotal); mvwprintw(win, 11, 33, "3XX: %d (%.1f\%)", stats.r300, (float) stats.r300 * 100 / stats.mtotal); mvwprintw(win, 12, 33, "4XX: %d (%.1f\%)", stats.r400, (float) stats.r400 * 100 / stats.mtotal); mvwprintw(win, 13, 33, "5XX: %d (%.1f\%)", stats.r500, (float) stats.r500 * 100 / stats.mtotal); mvwprintw(win, 14, 33, "6XX: %d (%.1f\%)", stats.r600, (float) stats.r600 * 100 / stats.mtotal); mvwprintw(win, 15, 33, "7XX: %d (%.1f\%)", stats.r700, (float) stats.r700 * 100 / stats.mtotal); mvwprintw(win, 16, 33, "8XX: %d (%.1f\%)", stats.r800, (float) stats.r800 * 100 / stats.mtotal); return panel; } void stats_destroy(PANEL *panel) { // Deallocate panel window delwin(panel_window(panel)); // Deallocate panel pointer del_panel(panel); } int stats_handle_key(PANEL *panel, int key) { return KEY_ESC; } sngrep-1.2.0/src/filter.c0000644000175000017500000001345012632250522014264 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file filter.c * @author Ivan Alonso [aka Kaian] * * @brief Source code of functions defined in filter.h * */ #include #include #include "sip.h" #include "ui_call_list.h" #include "filter.h" //! Storage of filter information filter_t filters[FILTER_COUNT] = { }; int filter_set(int type, const char *expr) { #ifdef WITH_PCRE pcre *regex = NULL; // If we have an expression, check if compiles before changing the filter if (expr) { const char *re_err = NULL; int32_t err_offset; int32_t pcre_options = PCRE_UNGREEDY | PCRE_CASELESS; // Check if we have a valid expression if (!(regex = pcre_compile(expr, pcre_options, &re_err, &err_offset, 0))) return 1; } // Remove previous value if (filters[type].expr) { sng_free(filters[type].expr); pcre_free(filters[type].regex); } // Set new expresion values filters[type].expr = (expr) ? strdup(expr) : NULL; filters[type].regex = regex; #else regex_t regex; // If we have an expression, check if compiles before changing the filter if (expr) { // Check if we have a valid expression if (regcomp(®ex, expr, REG_EXTENDED | REG_ICASE) != 0) return 1; } // Remove previous value if (filters[type].expr) { sng_free(filters[type].expr); regfree(&filters[type].regex); } // Set new expresion values filters[type].expr = (expr) ? strdup(expr) : NULL; memcpy(&filters[type].regex, ®ex, sizeof(regex)); #endif return 0; } const char * filter_get(int type) { return filters[type].expr; } int filter_check_call(void *item) { int i; char data[MAX_SIP_PAYLOAD]; sip_call_t *call = (sip_call_t*) item; sip_msg_t *msg; vector_iter_t it; // Dont filter calls without messages if (call_msg_count(call) == 0) return 0; // Filter for this call has already be processed if (call->filtered != -1) return (call->filtered == 0); // By default, call matches all filters call->filtered = 0; // Check all filter types for (i=0; i < FILTER_COUNT; i++) { // If filter is not enabled, go to the next if (!filters[i].expr) continue; // Initialize memset(data, 0, sizeof(data)); // Get filtered field switch(i) { case FILTER_SIPFROM: call_get_attribute(call, SIP_ATTR_SIPFROM, data); break; case FILTER_SIPTO: call_get_attribute(call, SIP_ATTR_SIPTO, data); break; case FILTER_SOURCE: call_get_attribute(call, SIP_ATTR_SRC, data); break; case FILTER_DESTINATION: call_get_attribute(call, SIP_ATTR_DST, data); break; case FILTER_METHOD: call_get_attribute(call, SIP_ATTR_METHOD, data); break; case FILTER_PAYLOAD: break; case FILTER_CALL_LIST: // FIXME Maybe call should know hot to calculate this line call_list_line_text(ui_get_panel(ui_find_by_type(PANEL_CALL_LIST)), call, data); break; default: // Unknown filter id return 0; } // For payload filtering, check all messages payload if (i == FILTER_PAYLOAD) { // Assume this call doesn't match the filter call->filtered = 1; // Create an iterator for the call messages it = vector_iterator(call->msgs); while ((msg = vector_iterator_next(&it))) { // Copy message payload strcpy(data, msg_get_payload(msg)); // Check if this payload matches the filter if (filter_check_expr(filters[i], data) == 0) { call->filtered = 0; break; } } if (call->filtered == 1) break; } else { // Check the filter against given data if (filter_check_expr(filters[i], data) != 0) { // The data didn't matched the filter call->filtered = 1; break; } } } // Return the final filter status return (call->filtered == 0); } int filter_check_expr(filter_t filter, const char *data) { #ifdef WITH_PCRE return pcre_exec(filter.regex, 0, data, strlen(data), 0, 0, 0, 0); #else // Call doesn't match this filter return regexec(&filter.regex, data, 0, NULL, 0); #endif } void filter_reset_calls() { sip_call_t *call; vector_iter_t calls = sip_calls_iterator(); // Force filter evaluation while ((call = vector_iterator_next(&calls))) call->filtered = -1; } sngrep-1.2.0/src/util.h0000644000175000017500000000455112632250522013763 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file util.h * @author Ivan Alonso [aka Kaian] * * @brief Functions for general use in the program * */ #ifndef __SNGREP_UTIL_H #define __SNGREP_UTIL_H // Capture headers has some fixes for pcap timevals in BSD systems #include "capture.h" // Max Memmory allocation #define MALLOC_MAX_SIZE 102400 /** * @brief Wrapper for memory allocation */ void * sng_malloc(size_t size); /** * @brief Wrapper for memmory deallocation */ void sng_free(void *ptr); /** * @brief Compare two timeval structures * * @param t1 First timeval structure * @param t2 Second timval structure * @return 1 if t1 > t2, 0 if t1 <= t2 */ int timeval_is_older(struct timeval t1, struct timeval t2); /** * @brief Convert timeval to yyyy/mm/dd format */ const char * timeval_to_date(struct timeval time, char *out); /** * @brief Convert timeval to HH:MM:SS.mmmmmm format */ const char * timeval_to_time(struct timeval time, char *out); /** * @brief Calculate the time difference between two timeval * * @return Human readable time difference in mm:ss format */ const char * timeval_to_duration(struct timeval start, struct timeval end, char *out); /** * @brief Convert timeval diference to +mm:ss.mmmmmm */ const char * timeval_to_delta(struct timeval start, struct timeval end, char *out); /** * @brief Return a given string without trailing spaces */ char * strtrim(char *str); #endif /* __SNGREP_UTIL_H */ sngrep-1.2.0/src/ui_filter.c0000644000175000017500000003476112632250522014771 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2014 Ivan Alonso (Kaian) ** Copyright (C) 2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_filter.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_filter.h * */ #include #include #include #include "ui_filter.h" #include "ui_call_list.h" #include "sip.h" #include "filter.h" #include "setting.h" /** * Ui Structure definition for Filter panel */ ui_t ui_filter = { .type = PANEL_FILTER, .panel = NULL, .create = filter_create, .handle_key = filter_handle_key, .destroy = filter_destroy }; PANEL * filter_create() { PANEL *panel; WINDOW *win; int height, width; filter_info_t *info; const char *method; // Calculate window dimensions height = 16; width = 50; // Cerate a new indow for the panel and form win = newwin(height, width, (LINES - height) / 2, (COLS - width) / 2); // Create a new panel panel = new_panel(win); // Initialize Filter panel specific data info = sng_malloc(sizeof(filter_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Initialize the fields info->fields[FLD_FILTER_SIPFROM] = new_field(1, 28, 3, 18, 0, 0); info->fields[FLD_FILTER_SIPTO] = new_field(1, 28, 4, 18, 0, 0); info->fields[FLD_FILTER_SRC] = new_field(1, 18, 5, 18, 0, 0); info->fields[FLD_FILTER_DST] = new_field(1, 18, 6, 18, 0, 0); info->fields[FLD_FILTER_PAYLOAD] = new_field(1, 28, 7, 18, 0, 0); info->fields[FLD_FILTER_REGISTER] = new_field(1, 1, 9, 15, 0, 0); info->fields[FLD_FILTER_INVITE] = new_field(1, 1, 10, 15, 0, 0); info->fields[FLD_FILTER_SUBSCRIBE] = new_field(1, 1, 11, 15, 0, 0); info->fields[FLD_FILTER_NOTIFY] = new_field(1, 1, 12, 15, 0, 0); info->fields[FLD_FILTER_OPTIONS] = new_field(1, 1, 9, 37, 0, 0); info->fields[FLD_FILTER_PUBLISH] = new_field(1, 1, 10, 37, 0, 0); info->fields[FLD_FILTER_MESSAGE] = new_field(1, 1, 11, 37, 0, 0); info->fields[FLD_FILTER_FILTER] = new_field(1, 10, height - 2, 11, 0, 0); info->fields[FLD_FILTER_CANCEL] = new_field(1, 10, height - 2, 30, 0, 0); info->fields[FLD_FILTER_COUNT] = NULL; // Set fields options field_opts_off(info->fields[FLD_FILTER_SIPFROM], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_SIPTO], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_SRC], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_DST], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_PAYLOAD], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_REGISTER], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_INVITE], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_SUBSCRIBE], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_NOTIFY], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_OPTIONS], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_PUBLISH], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_MESSAGE], O_AUTOSKIP); field_opts_off(info->fields[FLD_FILTER_FILTER], O_EDIT); field_opts_off(info->fields[FLD_FILTER_CANCEL], O_EDIT); // Change background of input fields set_field_back(info->fields[FLD_FILTER_SIPFROM], A_UNDERLINE); set_field_back(info->fields[FLD_FILTER_SIPTO], A_UNDERLINE); set_field_back(info->fields[FLD_FILTER_SRC], A_UNDERLINE); set_field_back(info->fields[FLD_FILTER_DST], A_UNDERLINE); set_field_back(info->fields[FLD_FILTER_PAYLOAD], A_UNDERLINE); // Create the form and post it info->form = new_form(info->fields); set_form_sub(info->form, win); post_form(info->form); // Fields labels mvwprintw(win, 3, 3, "SIP From:"); mvwprintw(win, 4, 3, "SIP To:"); mvwprintw(win, 5, 3, "Source:"); mvwprintw(win, 6, 3, "Destination:"); mvwprintw(win, 7, 3, "Payload:"); mvwprintw(win, 9, 3, "REGISTER [ ]"); mvwprintw(win, 10, 3, "INVITE [ ]"); mvwprintw(win, 11, 3, "SUBSCRIBE [ ]"); mvwprintw(win, 12, 3, "NOTIFY [ ]"); mvwprintw(win, 9, 25, "OPTIONS [ ]"); mvwprintw(win, 10, 25, "PUBLISH [ ]"); mvwprintw(win, 11, 25, "MESSAGE [ ]"); // Get Method filter if (!(method = filter_get(FILTER_METHOD))) method = setting_get_value(SETTING_FILTER_METHODS); // Set Default field values set_field_buffer(info->fields[FLD_FILTER_SIPFROM], 0, filter_get(FILTER_SIPFROM)); set_field_buffer(info->fields[FLD_FILTER_SIPTO], 0, filter_get(FILTER_SIPTO)); set_field_buffer(info->fields[FLD_FILTER_SRC], 0, filter_get(FILTER_SOURCE)); set_field_buffer(info->fields[FLD_FILTER_DST], 0, filter_get(FILTER_DESTINATION)); set_field_buffer(info->fields[FLD_FILTER_PAYLOAD], 0, filter_get(FILTER_PAYLOAD)); set_field_buffer(info->fields[FLD_FILTER_REGISTER], 0, strstr(method, sip_method_str(SIP_METHOD_REGISTER)) ? "*" : ""); set_field_buffer(info->fields[FLD_FILTER_INVITE], 0, strstr(method, sip_method_str(SIP_METHOD_INVITE)) ? "*" : ""); set_field_buffer(info->fields[FLD_FILTER_SUBSCRIBE], 0, strstr(method,sip_method_str(SIP_METHOD_SUBSCRIBE)) ? "*" : ""); set_field_buffer(info->fields[FLD_FILTER_NOTIFY], 0, strstr(method, sip_method_str(SIP_METHOD_NOTIFY)) ? "*" : ""); set_field_buffer(info->fields[FLD_FILTER_OPTIONS], 0, strstr(method, sip_method_str(SIP_METHOD_OPTIONS)) ? "*" : ""); set_field_buffer(info->fields[FLD_FILTER_PUBLISH], 0, strstr(method, sip_method_str(SIP_METHOD_PUBLISH)) ? "*" : ""); set_field_buffer(info->fields[FLD_FILTER_MESSAGE], 0, strstr(method, sip_method_str(SIP_METHOD_MESSAGE)) ? "*" : ""); set_field_buffer(info->fields[FLD_FILTER_FILTER], 0, "[ Filter ]"); set_field_buffer(info->fields[FLD_FILTER_CANCEL], 0, "[ Cancel ]"); // Set the window title and boxes mvwprintw(win, 1, 18, "Filter options"); wattron(win, COLOR_PAIR(CP_BLUE_ON_DEF)); title_foot_box(panel); mvwhline(win, 8, 1, ACS_HLINE, 49); mvwaddch(win, 8, 0, ACS_LTEE); mvwaddch(win, 8, 49, ACS_RTEE); wattroff(win, COLOR_PAIR(CP_BLUE_ON_DEF)); // Set default cursor position set_current_field(info->form, info->fields[FLD_FILTER_SIPFROM]); wmove(win, 3, 18); curs_set(1); return panel; } filter_info_t * filter_info(PANEL *panel) { return (filter_info_t*) panel_userptr(panel); } void filter_destroy(PANEL *panel) { // Disable cursor position curs_set(0); } int filter_handle_key(PANEL *panel, int key) { int field_idx; char field_value[30]; int action = -1; // Get panel information filter_info_t *info = filter_info(panel); // Get current field id field_idx = field_index(current_field(info->form)); // Get current field value. // We trim spaces with sscanf because and empty field is stored as // space characters memset(field_value, 0, sizeof(field_value)); strcpy(field_value, field_buffer(current_field(info->form), 0)); strtrim(field_value); // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_PRINTABLE: // If this is a normal character on input field, print it if (field_idx == FLD_FILTER_SIPFROM || field_idx == FLD_FILTER_SIPTO || field_idx == FLD_FILTER_SRC || field_idx == FLD_FILTER_DST || field_idx == FLD_FILTER_PAYLOAD) { form_driver(info->form, key); break; } continue; case ACTION_NEXT_FIELD: form_driver(info->form, REQ_NEXT_FIELD); form_driver(info->form, REQ_END_LINE); break; case ACTION_PREV_FIELD: form_driver(info->form, REQ_PREV_FIELD); form_driver(info->form, REQ_END_LINE); break; case ACTION_RIGHT: form_driver(info->form, REQ_RIGHT_CHAR); break; case ACTION_LEFT: form_driver(info->form, REQ_LEFT_CHAR); break; case ACTION_BEGIN: form_driver(info->form, REQ_BEG_LINE); break; case ACTION_END: form_driver(info->form, REQ_END_LINE); break; case ACTION_CLEAR: form_driver(info->form, REQ_CLR_FIELD); break; case KEY_DC: form_driver(info->form, REQ_DEL_CHAR); break; case ACTION_DELETE: form_driver(info->form, REQ_DEL_CHAR); break; case ACTION_BACKSPACE: if (strlen(field_value) > 0) form_driver(info->form, REQ_DEL_PREV); break; case ACTION_SELECT: switch (field_idx) { case FLD_FILTER_REGISTER: case FLD_FILTER_INVITE: case FLD_FILTER_SUBSCRIBE: case FLD_FILTER_NOTIFY: case FLD_FILTER_OPTIONS: case FLD_FILTER_PUBLISH: case FLD_FILTER_MESSAGE: if (field_value[0] == '*') { form_driver(info->form, REQ_DEL_CHAR); } else { form_driver(info->form, '*'); } break; case FLD_FILTER_CANCEL: return KEY_ESC; case FLD_FILTER_FILTER: filter_save_options(panel); return KEY_ESC; } break; case ACTION_CONFIRM: if (field_idx != FLD_FILTER_CANCEL) filter_save_options(panel); return KEY_ESC; default: // Parse next action continue; } // This panel has handled the key successfully break; } // Validate all input data form_driver(info->form, REQ_VALIDATION); // Change background and cursor of "button fields" set_field_back(info->fields[FLD_FILTER_FILTER], A_NORMAL); set_field_back(info->fields[FLD_FILTER_CANCEL], A_NORMAL); curs_set(1); // Change current field background field_idx = field_index(current_field(info->form)); if (field_idx == FLD_FILTER_FILTER || field_idx == FLD_FILTER_CANCEL) { set_field_back(info->fields[field_idx], A_REVERSE); curs_set(0); } // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } void filter_save_options(PANEL *panel) { char field_value[30]; char *expr; int field_id; char method_expr[256]; // Initialize variables memset(method_expr, 0, sizeof(method_expr)); // Get panel information filter_info_t *info = filter_info(panel); for (field_id = 0; field_id < FLD_FILTER_COUNT; field_id++) { // Get current field value. // We trim spaces with sscanf because and empty field is stored as // space characters memset(field_value, 0, sizeof(field_value)); strcpy(field_value, field_buffer(info->fields[field_id], 0)); strtrim(field_value); // Set filter expression expr = strlen(field_value) ? field_value : NULL; switch (field_id) { case FLD_FILTER_SIPFROM: filter_set(FILTER_SIPFROM, expr); break; case FLD_FILTER_SIPTO: filter_set(FILTER_SIPTO, expr); break; case FLD_FILTER_SRC: filter_set(FILTER_SOURCE, expr); break; case FLD_FILTER_DST: filter_set(FILTER_DESTINATION, expr); break; case FLD_FILTER_PAYLOAD: filter_set(FILTER_PAYLOAD, expr); break; case FLD_FILTER_REGISTER: case FLD_FILTER_INVITE: case FLD_FILTER_SUBSCRIBE: case FLD_FILTER_NOTIFY: case FLD_FILTER_OPTIONS: case FLD_FILTER_PUBLISH: case FLD_FILTER_MESSAGE: if (!strcmp(field_value, "*")) sprintf(method_expr + strlen(method_expr), "|%s", filter_field_method(field_id)); break; default: break; } } // Set Method filter if (strlen(method_expr)) { method_expr[0] = '('; method_expr[strlen(method_expr)+1] = '\0'; method_expr[strlen(method_expr)] = ')'; filter_set(FILTER_METHOD, method_expr); } else { filter_set(FILTER_METHOD, NULL); } // Force filter evaluation filter_reset_calls(); // TODO FIXME Refresh call list FIXME call_list_clear(ui_get_panel(ui_find_by_type(PANEL_CALL_LIST))); } const char* filter_field_method(int field_id) { int method; switch(field_id) { case FLD_FILTER_REGISTER: method = SIP_METHOD_REGISTER; break; case FLD_FILTER_INVITE: method = SIP_METHOD_INVITE; break; case FLD_FILTER_SUBSCRIBE: method = SIP_METHOD_SUBSCRIBE; break; case FLD_FILTER_NOTIFY: method = SIP_METHOD_NOTIFY; break; case FLD_FILTER_OPTIONS: method = SIP_METHOD_OPTIONS; break; case FLD_FILTER_PUBLISH: method = SIP_METHOD_PUBLISH; break; case FLD_FILTER_MESSAGE: method = SIP_METHOD_MESSAGE; break; } return sip_method_str(method); } sngrep-1.2.0/src/option.h0000644000175000017500000001021612632250522014311 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file option.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage application settings * * This file contains the functions to manage application settings and * optionuration resource files. Configuration will be parsed in this order, * from less to more priority, so the later will overwrite the previous. * * - Initialization * - \@sysdir\@/sngreprc * - $HOME/.sngreprc * * This is a basic approach to configuration, but at least a minimun is required * for those who can not see all the list columns or want to disable colours in * every sngrep execution. * */ #ifndef __SNGREP_CONFIG_H #define __SNGREP_CONFIG_H //! Shorter declarartion of config_option struct typedef struct config_option option_opt_t; //! Option types enum option_type { COLUMN = 0, ALIAS }; /** * @brief Configurable option structure * * sngrep is optionured by a group of attributes that can be * modified using resource files. */ struct config_option { //! Setting type enum option_type type; //! Name of attribute char *opt; //! Value of attribute char *value; }; /** * @brief Initialize all program options * * This function will give all available settings an initial value. * This values can be overriden using resources files, either from system dir * or user home dir. * * @return 0 in all cases */ int init_options(); /** * @brief Deallocate options memory * * Deallocate memory used for program configurations */ void deinit_options(); /** * @brief Read optionuration directives from file * * This funtion will parse passed filenames searching for configuration * directives of sngrep. See documentation for a list of available * directives and attributes * * @param fname Full path configuration file name * @return 0 in case of parse success, -1 otherwise */ int read_options(const char *fname); /** * @brief Get settings option value (string) * * Used in all the program to access the optionurable options of sngrep * Use this function instead of accessing optionuration array. * * @param opt Name of optionurable option * @return configuration option value or NULL if not found */ const char* get_option_value(const char *opt); /** * @brief Get settings option value (int) * * Basically the same as get_option_value converting the result to * integer. * Use this function instead of accessing configuration array. * * @todo -1 is an error! * * @param opt Name of optionurable option * @return option numeric value or -1 in case of error */ int get_option_int_value(const char *opt); /** * @brief Sets a settings option value * * Basic setter for 'set' directive attributes * * @param opt Name of configuration option * @param value Value of configuration option */ void set_option_value(const char *opt, const char *value); /** * @brief Sets an alias for a given address * * @param address IP Address * @param string representing the alias */ void set_alias_value(const char *address, const char *alias); /** * @brief Get alias for a given address (string) * * @param address IP Address * @return configured alias or address if not alias found */ const char * get_alias_value(const char *address); #endif sngrep-1.2.0/src/sip.h0000644000175000017500000002240612632250522013600 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file sip.h * @author Ivan Alonso [aka Kaian] * * @brief Functions to manage SIP calls and messages * * This file contains the functions and structures to manage the SIP calls and * messages. */ #ifndef __SNGREP_SIP_H #define __SNGREP_SIP_H #include "config.h" #include #ifdef WITH_PCRE #include #endif #include "sip_call.h" #include "vector.h" #define MAX_SIP_PAYLOAD 10240 //! Shorter declaration of sip_call_list structure typedef struct sip_call_list sip_call_list_t; //! Shorter declaration of sip codes structure typedef struct sip_code sip_code_t; //! SIP Methods enum sip_methods { SIP_METHOD_REGISTER = 1, SIP_METHOD_INVITE, SIP_METHOD_SUBSCRIBE, SIP_METHOD_NOTIFY, SIP_METHOD_OPTIONS, SIP_METHOD_PUBLISH, SIP_METHOD_MESSAGE, SIP_METHOD_CANCEL, SIP_METHOD_BYE, SIP_METHOD_ACK, SIP_METHOD_PRACK, SIP_METHOD_INFO, SIP_METHOD_REFER, SIP_METHOD_UPDATE, }; /** * @brief Different Request/Response codes in SIP Protocol */ struct sip_code { int id; const char *text; }; /** * @brief call structures head list * * This structure acts as header of calls list */ struct sip_call_list { //! List of all captured calls vector_t *list; //! List of active captured calls vector_t *active; // Max call limit int limit; //! Only store dialogs starting with INVITE int only_calls; //! Only store dialogs starting with some Methods int ignore_incomplete; //! match expression text const char *match_expr; #ifdef WITH_PCRE //! Compiled match expression pcre *match_regex; #else //! Compiled match expression regex_t match_regex; #endif //! Invert match expression result int match_invert; //! Regexp for payload matching regex_t reg_method; regex_t reg_callid; regex_t reg_xcallid; regex_t reg_response; regex_t reg_cseq; regex_t reg_from; regex_t reg_to; }; /** * @brief Initialize SIP Storage structures * * @param limit Max number of Stored calls * @param only_calls only parse dialogs starting with INVITE * @param no_incomplete only parse dialog starting with some methods */ void sip_init(int limit, int only_calls, int no_incomplete); /** * @brief Deallocate all memory used for SIP calls */ void sip_deinit(); /** * @brief Parses Call-ID header of a SIP message payload * * Mainly used to check if a payload contains a callid. * * @param payload SIP message payload * @param callid Character array to store callid * @return callid parsed from Call-ID header */ char * sip_get_callid(const char* payload, char *callid); /** * @brief Parses X-Call-ID header of a SIP message payload * * Mainly used to check if a payload contains a xcallid. * * @param payload SIP message payload * @paramx callid Character array to store callid * @return xcallid parsed from Call-ID header */ char * sip_get_xcallid(const char* payload, char *xcallid); /** * @brief Loads a new message from raw header/payload * * Use this function to convert raw data into call and message * structures. This is mainly used to load data from a file or * * @param packet Packet structure pointer * @return a SIP msg structure pointer */ sip_msg_t * sip_check_packet(capture_packet_t *packet); /** * @brief Getter for calls linked list size * * @return how many calls are linked in the list */ int sip_calls_count(); /** * @brief Return an iterator of call list */ vector_iter_t sip_calls_iterator(); /** * @brief Return an iterator of call list * * We consider 'active' calls those that are willing to have * an rtp stream that will receive new packets. * */ vector_iter_t sip_active_calls_iterator(); /** * @brief Return stats from call list * * @param total Total calls processed * @param displayed number of calls matching filters */ void sip_calls_stats(int *total, int *displayed); /** * @brief Find a call structure in calls linked list given a call index * * @param index Position of the call in the calls vector * @return pointer to the sip_call structure found or NULL */ sip_call_t * sip_find_by_index(int index); /** * @brief Find a call structure in calls linked list given an callid * * @param callid Call-ID Header value * @return pointer to the sip_call structure found or NULL */ sip_call_t * sip_find_by_callid(const char *callid); /** * @brief Find a call structure in calls linked list given an xcallid * * Find the call that have the xcallid attribute equal tot he given * value. * * @param xcallid X-Call-ID or X-CID Header value * @return pointer to the sip_call structure found or NULL */ sip_call_t * sip_find_by_xcallid(const char *xcallid); /** * @brief Remove al calls * * This funtion will clear the call list invoking the destroy * function for each one. */ void sip_calls_clear(); /** * @brief Get message Request/Response code * * Parse Payload to get Message Request/Response code. * * @param msg SIP Message to be parsed * @return numeric representation of Request/ResponseCode */ int sip_get_msg_reqresp(sip_msg_t *msg, const u_char *payload); /** * @brief Get full Response code (including text) * * */ const char * sip_get_response_str(sip_msg_t *msg, char *out); /** * @brief Parse SIP Message payload if not parsed * * This function can be used for delayed parsing. This way * the message will only use the minimun required memory * to store basic information. * * @param msg SIP message structure * @return parsed message */ sip_msg_t * sip_parse_msg(sip_msg_t *msg); /** * @brief Parse SIP Message payload to fill sip_msg structe * * Parse the payload content to set message attributes. * * @param msg SIP message structure * @param payload SIP message payload * @return 0 in all cases */ int sip_parse_msg_payload(sip_msg_t *msg, const u_char *payload); /** * @brief Parse SIP Message payload for SDP media streams * * Parse the payload content to get SDP information * * @param msg SIP message structure * @return 0 in all cases */ void sip_parse_msg_media(sip_msg_t *msg, const u_char *payload); /** * @brief Set Capture Matching expression * * @param expr String containing matching expreson * @param insensitive 1 for case insensitive matching * @param invert 1 for reverse matching * @return 0 if expresion is valid, 1 otherwise */ int sip_set_match_expression(const char *expr, int insensitive, int invert); /** * @brief Checks if a given payload matches expression * * @param payload Packet payload * @return 1 if matches, 0 otherwise */ int sip_check_match_expression(const char *payload); /** * @brief Get String value for a Method * * @param method One of the methods defined in @sip_codes * @return a string representing the method text */ const char * sip_method_str(int method); /* * @brief Get String value of Transport */ const char * sip_transport_str(int transport); /** * @brief Converts Request Name or Response code to number * * If the argument is a method, the corresponding value of @sip_methods * will be returned. If a Resposne code, the numeric value of the code * will be returned. * * @param a string representing the Request/Resposne code text * @return numeric representation of Request/Response code */ int sip_method_from_str(const char *method); /** * @brief Get summary of message header data * * For raw prints, it's handy to have the ngrep header style message * data. * * @param msg SIP message * @param out pointer to allocated memory to contain the header output * @returns pointer to out */ char * sip_get_msg_header(sip_msg_t *msg, char *out); /** * @brief Return address formatted depending on active settings * * Addresses can be printed in many formats depending on active settings. * Alias, resolving or just printing address as is will be * * @param address Address in string format * @return address formatted */ const char * sip_address_format(const char *address); /** * @brief Return address:port formatted depending on active settings * * Addresses can be printed in many formats depending on active settings. * Alias, resolving or just printing address as is will be * * @param addrport Address:Port in string format * @return address:port formatted */ const char * sip_address_port_format(const char *address); /** * @brief Remove port from an address */ const char * sip_address_strip_port(char *addrport); #endif sngrep-1.2.0/src/ui_call_raw.c0000644000175000017500000002242212632250522015257 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2013,2014 Ivan Alonso (Kaian) ** Copyright (C) 2013,2014 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** == 1) ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file ui_call_raw.c * @author Ivan Alonso [aka Kaian] * * @brief Source of functions defined in ui_call_raw.h * * @todo Code help screen. Please. * @todo Replace the panel refresh. Wclear sucks on high latency conections. * */ #include #include #include "ui_manager.h" #include "ui_call_raw.h" #include "ui_save.h" #include "capture.h" /** * Ui Structure definition for Call Raw panel */ ui_t ui_call_raw = { .type = PANEL_CALL_RAW, .panel = NULL, .create = call_raw_create, .destroy = call_raw_destroy, .draw = call_raw_draw, .handle_key = call_raw_handle_key }; PANEL * call_raw_create() { PANEL *panel; call_raw_info_t *info; // Create a new panel to fill all the screen panel = new_panel(newwin(LINES, COLS, 0, 0)); // Initialize Call List specific data info = sng_malloc(sizeof(call_raw_info_t)); // Store it into panel userptr set_panel_userptr(panel, (void*) info); // Create a initial pad of 1000 lines info->pad = newpad(500, COLS); info->padline = 0; info->scroll = 0; return panel; } void call_raw_destroy(PANEL *panel) { call_raw_info_t *info; if ((info = call_raw_info(panel))) { // Delete panel windows delwin(info->pad); sng_free(info); } // Delete panel window delwin(panel_window(panel)); // Delete panel del_panel(panel); } call_raw_info_t * call_raw_info(PANEL *panel) { return (call_raw_info_t*) panel_userptr(panel); } int call_raw_draw(PANEL *panel) { call_raw_info_t *info; sip_msg_t *msg = NULL; // Get panel information if(!(info = call_raw_info(panel))) return -1; if (info->group) { // Print the call group messages into the pad while ((msg = call_group_get_next_msg(info->group, info->last))) call_raw_print_msg(panel, msg); } else { call_raw_set_msg(info->msg); } // Copy the visible part of the pad into the panel window copywin(info->pad, panel_window(panel), info->scroll, 0, 0, 0, LINES - 1, COLS - 1, 0); touchwin(panel_window(panel)); return 0; } int call_raw_print_msg(PANEL *panel, sip_msg_t *msg) { call_raw_info_t *info; int payload_lines, i, column, height, width; // Message ngrep style Header char header[256]; char payload[MAX_SIP_PAYLOAD]; int color = 0; // Get panel information if (!(info = call_raw_info(panel))) return -1; // Get the pad window WINDOW *pad = info->pad; // Get current pad dimensions getmaxyx(pad, height, width); // Get message payload strcpy(payload, msg_get_payload(msg)); // Check how many lines we well need to draw this message payload_lines = 0; column = 0; for (i = 0; i < strlen(payload); i++) { if (column == width || payload[i] == '\n') { payload_lines++; column = 0; continue; } column++; } // Check if we have enough space in our huge pad to store this message if (info->padline + payload_lines > height) { // Create a new pad with more lines! pad = newpad(height + 500, COLS); // And copy all previous information overwrite(info->pad, pad); // Delete previous pad delwin(info->pad); // And store the new pad info->pad = pad; } // Color the message { if (setting_has_value(SETTING_COLORMODE, "request")) { // Determine arrow color if (msg_is_request(msg)) { color = CP_RED_ON_DEF; } else { color = CP_GREEN_ON_DEF; } } else if (info->group && setting_has_value(SETTING_COLORMODE, "callid")) { // Color by call-id color = call_group_color(info->group, msg->call); } else if (setting_has_value(SETTING_COLORMODE, "cseq")) { // Color by CSeq within the same call color = msg->cseq % 7 + 1; } // Turn on the message color wattron(pad, COLOR_PAIR(color)); // Print msg header wattron(pad, A_BOLD); mvwprintw(pad, info->padline++, 0, "%s", sip_get_msg_header(msg, header)); wattroff(pad, A_BOLD); // Print msg payload info->padline += draw_message_pos(pad, msg, info->padline); // Extra line between messages info->padline++; // Set this as the last printed message info->last = msg; return 0; } int call_raw_handle_key(PANEL *panel, int key) { call_raw_info_t *info; ui_t *next_panel; int rnpag_steps = setting_get_intvalue(SETTING_CR_SCROLLSTEP); int action = -1; // Sanity check, this should not happen if (!(info = call_raw_info(panel))) return -1; // Check actions for this key while ((action = key_find_action(key, action)) != ERR) { // Check if we handle this action switch (action) { case ACTION_DOWN: info->scroll++; break; case ACTION_UP: info->scroll--; break; case ACTION_HNPAGE: rnpag_steps = rnpag_steps / 2; /* no break */ case ACTION_NPAGE: // Next page => N key down strokes info->scroll += rnpag_steps; break; case ACTION_HPPAGE: rnpag_steps = rnpag_steps / 2; /* no break */ case ACTION_PPAGE: // Prev page => N key up strokes info->scroll -= rnpag_steps; break; case ACTION_SHOW_HOSTNAMES: // Tooggle Host/Address display setting_toggle(SETTING_DISPLAY_HOST); // Force refresh panel if (info->group) { call_raw_set_group(info->group); } else { call_raw_set_msg(info->msg); } break; case ACTION_SAVE: if (info->group) { // KEY_S, Display save panel next_panel = ui_create_panel(PANEL_SAVE); save_set_group(ui_get_panel(next_panel), info->group); } break; case ACTION_TOGGLE_SYNTAX: case ACTION_CYCLE_COLOR: // Handle colors using default handler default_handle_key(ui_find_by_panel(panel), key); // Create a new pad (forces messages draw) delwin(info->pad); info->pad = newpad(500, COLS); info->last = NULL; // Force refresh panel if (info->group) { call_raw_set_group(info->group); } else { call_raw_set_msg(info->msg); } break; default: // Parse next action continue; } // This panel has handled the key successfully break; } if (info->scroll < 0 || info->padline < LINES) { info->scroll = 0; // Disable scrolling if there's nothing to scroll } else { if (info->scroll + LINES / 2 > info->padline) info->scroll = info->padline - LINES / 2; } // Return if this panel has handled or not the key return (action == ERR) ? key : 0; } int call_raw_set_group(sip_call_group_t *group) { ui_t *raw_panel; PANEL *panel; call_raw_info_t *info; if (!group) return -1; if (!(raw_panel = ui_find_by_type(PANEL_CALL_RAW))) return -1; if (!(panel = raw_panel->panel)) return -1; if (!(info = call_raw_info(panel))) return -1; // Set call raw call group info->group = group; info->msg = NULL; // Initialize internal pad info->padline = 0; wclear(info->pad); return 0; } int call_raw_set_msg(sip_msg_t *msg) { ui_t *raw_panel; PANEL *panel; call_raw_info_t *info; if (!msg) return -1; if (!(raw_panel = ui_find_by_type(PANEL_CALL_RAW))) return -1; if (!(panel = raw_panel->panel)) return -1; if (!(info = call_raw_info(panel))) return -1; // Set call raw message info->group = NULL; info->msg = msg; // Initialize internal pad info->padline = 0; wclear(info->pad); // Print the message in the pad call_raw_print_msg(panel, msg); return 0; } sngrep-1.2.0/tests/0000755000175000017500000000000012632250522013203 5ustar vsevavsevasngrep-1.2.0/tests/test_002.c0000644000175000017500000000414512632250522014713 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_002.c * @author Ivan Alonso [aka Kaian] * * Basic Call list testing */ const char keys[] = { /* Swap some options */ 'c', 'l', 'p', 'p', /* Select some dialogs */ 107, 32, 107, 107, 32, 107, 107, 107, 32, 107, 107, /* Enter Call Flow */ 10, 27, /* Enter Call Raw */ 'R', 27, /* Enter Filter screen */ 'F', 27, /* Enter Column screen */ 't', 27, /* Unselect some dialogs */ 32, 107, 32, /* Move beyond list limits */ 107, 107, 107, 107, 107, 106, 107, 107, 107, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 4, 4, 2, 2, 4, 2, 4, 2, /* Enter help screen */ 'h', 100, /* Enter save screen */ 's', 20, 30, 40, 50, 27, /* Enter display filter */ '/', 20, 30, 40, 40, 10, '/', 27, /* Enter Call Flow once again */ 10, 27, /* Exit */ 27, 10, 0 }; #include "test_input.c" sngrep-1.2.0/tests/test_007.c0000644000175000017500000000546112632250522014722 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_vector.c * @author Ivan Alonso [aka Kaian] * * Basic testing of vector structures */ #include "config.h" #include #include #include "vector.h" #include "util.h" int main () { vector_t *vector; // Basic Vector append/remove test vector = vector_create(10, 10); assert(vector); assert(vector_count(vector) == 0); vector_append(vector, 0); assert(vector_count(vector) == 0); vector_append(vector, sng_malloc(1024)); assert(vector_count(vector) == 1); assert(vector_first(vector) == vector_item(vector, 0)); vector_remove(vector, vector_first(vector)); assert(vector_count(vector) == 0); assert(vector_first(vector) == vector_item(vector, 0)); // Vector overflow test vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); // Next append requires memory reallocation vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); vector_append(vector, sng_malloc(32)); // Expected vector size assert(vector_count(vector) == 16); // Expected empty position assert(vector_item(vector, vector_count(vector)) == 0); // Remove position (use generic destroyer) vector_set_destroyer(vector, vector_generic_destroyer); vector_remove(vector, vector_item(vector, 12)); assert(vector_count(vector) == 15); return 0; } sngrep-1.2.0/tests/test_input.c0000644000175000017500000000404512632250522015550 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_input.c * @author Ivan Alonso [aka Kaian] * * Basic input injector for sngrep testing */ #include #include #include #include #ifndef TEST_MAX_DURATION #define TEST_MAX_DURATION 5 #endif #ifndef TEST_INITIAL_WAIT #define TEST_INITIAL_WAIT 1000 * 1200 #endif #ifndef TEST_KEY_DELAY #define TEST_KEY_DELAY 3000 #endif #ifndef TEST_PCAP_INPUT #define TEST_PCAP_INPUT "aaa.pcap" #endif int main() { int ppipe[2]; int unused, ret = 0; unused = pipe(ppipe); // Max test duration alarm(TEST_MAX_DURATION); if (!fork()) { char *argv[] = { "../src/sngrep", "-I", TEST_PCAP_INPUT, 0 }; dup2(ppipe[0], STDIN_FILENO); execv(argv[0], argv); } else { usleep(TEST_INITIAL_WAIT); int i; for (i = 0; keys[i]; i++) { unused = write(ppipe[1], &keys[i], sizeof(char)); usleep(TEST_KEY_DELAY); } unused = wait(&ret); } return ret; } sngrep-1.2.0/tests/test_006.c0000644000175000017500000000262612632250522014721 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_006.c * @author Ivan Alonso [aka Kaian] * * Basic Message diff testing */ const int keys[] = { /* Select some dialog */ 107, 107, 107, 32, 10, /* Move Select some messages */ 107, 107, 32, 32, 107, 32, 107, 107, 107, 106, 32, /* Leave Diff screen */ 27, 27, /* Exit */ 27, 10, 0 }; #include "test_input.c" sngrep-1.2.0/tests/test_001.c0000644000175000017500000000224412632250522014710 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_001.c * @author Ivan Alonso [aka Kaian] * * Basic read from file test */ const char keys[] = { 27, 10, 0 }; #include "test_input.c" sngrep-1.2.0/tests/aaa.pcap0000644000175000017500000033074512632250522014606 0ustar vsevavsevaÔò¡ÿÿ$ÉBÎ \\ÿÿÿÿÿÿàín½ENiŒ€LÁÀ¨À¨ÿ‰‰:[´„ç EFEDEJFPEEEPENEBEJEOCACACACACABM %ÉB”ï\\ÿÿÿÿÿÿàín½ENi€LÀÀ¨À¨ÿ‰‰:[´„ç EFEDEJFPEEEPENEBEJEOCACACACACABM &ÉBú#\\ÿÿÿÿÿÿàín½ENiŽ€L¿À¨À¨ÿ‰‰:[´„ç EFEDEJFPEEEPENEBEJEOCACACACACABM /ÉB **ÿÿÿÿÿÿàín½àín½À¨À¨/ÉB <<àín½0T4V0T4VÀ¨àín½À¨ˆdö7 À! ÿÏ;ùÍ/ÉB· LL0T4Vàín½E>i€MÌÀ¨À¨ ˜5*#C²Ðsip cybercitydk0ÉB®ñ LL0T4Vàín½E>i€MËÀ¨À¨ ˜5*#C²Ðsip cybercitydk2ÉBý LL0T4Vàín½E>i‘€MÊÀ¨À¨ ˜5*#C²Ðsip cybercitydk2ÉBA” àín½0T4VE‚@@·À¨À¨5 ˜nÀ¨À¨5 šG[ΫҀ100127in-addrarpa À ' localhostDÉBÙá ýý0T4Vàín½Eïi˜€¦À¨Ôò!#ÄÄÛnöREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp151248737-46ea715e192.168.1.2;rport From: ;tag=903df0a To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 68 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 DÉBøàín½0T4VE@7Š+Ôò!#À¨ÄÄîÐüSIP/2.0 401 Unauthorized Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 68 REGISTER From: ;tag=903df0a To: ;tag=00-04092-1701af62-120c67172 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp151248737-46ea715e192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701af566be182070084c6f740706bb",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 EÉB.ÁVV0T4Vàín½EHi™€M¸À¨À¨ ›54ñV8Ó_sip_udpsip cybercitydk!FÉB•´VV0T4Vàín½EHiš€M·À¨À¨ ›54ñV8Ó_sip_udpsip cybercitydk!HÉBä¾VV0T4Vàín½EHi›€M¶À¨À¨ ›54ñV8Ó_sip_udpsip cybercitydk!JÉBËVV0T4Vàín½EHiœ€MµÀ¨À¨ ›54ñV8Ó_sip_udpsip cybercitydk!NÉB"áVV0T4Vàín½EHi€M´À¨À¨ ›54ñV8Ó_sip_udpsip cybercitydk!UÉBð9\\ÿÿÿÿÿÿàín½ENiž€L¯À¨À¨ÿ‰‰:[±„ê EFEDEJFPEEEPENEBEJEOCACACACACABM UÉBw– \\ÿÿÿÿÿÿàín½ENiŸ€L®À¨À¨ÿ‰‰:[±„ê EFEDEJFPEEEPENEBEJEOCACACACACABM VÉB¢éRR0T4Vàín½EDi €MµÀ¨À¨ œ50zOªÓ100127in-addrarpa VÉB€ïiiàín½0T4VE[@@·>À¨À¨5 œG\˪Ӏ100127in-addrarpa À ' localhostVÉB$÷ÒÒ0T4Vàín½EÄi¡€ÈÀ¨Ôò!#Ä݈¨REGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp149505178-438c528b192.168.1.2;rport From: ;tag=8e948b0 To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 69 REGISTER Content-Length: 0 Authorization: Digest username="voi18063",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701af566be182070084c6f740706bb",opaque="1701a1351f70795",nc="00000001",response="bd79fecae600a2eb79d37ec73214830b" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 VÉBÏ1\\àín½0T4VEN@7ŠßÔò!#À¨ÄÄ:YöSIP/2.0 100 Trying Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 69 REGISTER From: ;tag=8e948b0 To: Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp149505178-438c528b192.168.1.2 Content-Length: 0 VÉByô„„àín½0T4VEv@7Š·Ôò!#À¨ÄÄb‹xSIP/2.0 403 Wrong password Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 69 REGISTER From: ;tag=8e948b0 To: ;tag=00-04085-1701af98-51a65b340 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp149505178-438c528b192.168.1.2 Content-Length: 0 VÉB+Ê\\ÿÿÿÿÿÿàín½ENi¢€L«À¨À¨ÿ‰‰:[±„ê EFEDEJFPEEEPENEBEJEOCACACACACABM [ÉB†yóóÿÿÿÿÿÿàín½Eåi£€LÀ¨À¨ÿŠŠÑ[h„ìÀ¨Š» EEDADADCDEDGDFCACACACACACACACACA EFEDEJFPEEEPENEBEJEOCACACACACABNÿSMB%!è!V2\MAILSLOT\BROWSE€ü D002465UªkÉBJñ >>0T4Vàín½E0i¤@€&’À¨“‰^ ½Øÿ·Üp@;W´kÉB’ò >>0T4Vàín½E0i¥@€&‘À¨“‰^ ž‹-Å~àp@ ¿´nÉB´>>0T4Vàín½E0i¦@€&À¨“‰^ ž‹-Å~àp@ ¿´nÉBÝ´>>0T4Vàín½E0i§@€&À¨“‰^ ½Øÿ·Üp@;W´tÉB4Ö>>0T4Vàín½E0i¨@€&ŽÀ¨“‰^ ž‹-Å~àp@ ¿´tÉB‡Ö>>0T4Vàín½E0i©@€&À¨“‰^ ½Øÿ·Üp@;W´€ÉB]§ KK0T4Vàín½E=iª€M²À¨À¨ Ÿ5)J^íÔftpecitelecomÉBj¥ KK0T4Vàín½E=i«€M±À¨À¨ Ÿ5)J^íÔftpecitelecom‚ÉBHÓ ¨¨àín½0T4VEš@@¶ÿÀ¨À¨5 Ÿ†×áíÔ€ftpecitelecomÀ õdnsÀÀ-!“êýÀCnsbaraknetilÀCÀ-ÀOÔ–0©‚ÉBg >>0T4Vàín½E0i¬@€9ŠÀ¨“êý  ¯Ãp@n+´‚ÉBG® >>àín½0T4VE0xÿ@9q7“êýÀ¨  å•¯Ãpc6Ððƒ‚ÉB™® 660T4Vàín½E(i­@€9‘À¨“êý  ¯Ãå•PB$–‚ÉB¹'llàín½0T4VE^y@9pø“êýÀ¨  å•¯ÃPc6…é220 ProFTPD Server In ECI Telecom (ftp.ecitele.com) ‚ÉB”)FF0T4Vàín½E8i®@€9€À¨“êý  ¯Ãå•;PAî–¡USER anonymous ƒÉB¬<<àín½0T4VE(y@9q-“êýÀ¨  å•;¯Ã Pc6ý=ƒÉB3)‚‚àín½0T4VEty@9pà“êýÀ¨  å•;¯Ã Pc6^s331 Anonymous login ok, send your complete email address as your password. ƒÉBš2BB0T4Vàín½E4i¯@€9ƒÀ¨“êý  ¯Ã 啇PA¢»ÕPASS d0xa! ƒÉBØg<<àín½0T4VE(y@9q+“êýÀ¨  å•‡¯Ã,Pc6üåƒÉBx¢UUàín½0T4VEGy@9q “êýÀ¨  å•‡¯Ã,Pc6];230-Welcome To ECI FTP Server ƒÉB¥<<àín½0T4VE+y@9q&“êýÀ¨  å•¦¯Ã,Pc6Ò® ƒÉBÃ¥660T4Vàín½E(i°@€9ŽÀ¨“êý  ¯Ã,å•©PA€zƒÉB[¦<<àín½0T4VE+y@9q%“êýÀ¨  å•©¯Ã,Pc6Ò« ƒÉB»©QQàín½0T4VECy@9q “êýÀ¨  å•¬¯Ã,Pc6 /pub -> Public Folder. ƒÉBÙ©660T4Vàín½E(i±@€9À¨“êý  ¯Ã,å•ÇPAbzƒÉBܪYYàín½0T4VEKy@9q“êýÀ¨  å•ǯÃ,Pc6H® ECI users can do everything ƒÉB ¬RRàín½0T4VEDy @9q “êýÀ¨  å•ê¯Ã,Pc6' Others can only read ƒÉB*¬660T4Vàín½E(i²@€9ŒÀ¨“êý  ¯Ã,å–PA#zƒÉB€¬WWàín½0T4VEIy @9q“êýÀ¨  å–¯Ã,Pc6Ó /incoming -> Incoming Folder. ƒÉBg±qqàín½0T4VEcy @9pè“êýÀ¨  å–'¯Ã,Pc6»O Anyone can access, write & retrieve a specific file ƒÉB„±660T4Vàín½E(i³@€9‹À¨“êý  ¯Ã,å–bP@ÇzƒÉBϲWWàín½0T4VEIy @9q“êýÀ¨  å–b¯Ã,Pc6€¶ /outgoing -> outgoing Folder. ƒÉBæµqqàín½0T4VEcy @9pæ“êýÀ¨  å–ƒ¯Ã,Pc6ºó Anyone can access, write & retrieve a specific file ƒÉB¶660T4Vàín½E(i´@€9ŠÀ¨“êý  ¯Ã,å–¾P@kzƒÉB‡·<<àín½0T4VE+y@9q“êýÀ¨  å–¾¯Ã,Pc6Ñ– ƒÉBŸ¼qqàín½0T4VEcy@9pä“êýÀ¨  å–Á¯Ã,Pc6=§ Files larger then 250MB will be deleted after 5 days !!! ƒÉB½¼660T4Vàín½E(iµ@€9‰À¨“êý  ¯Ã,å–üP@-zƒÉBþ¿ffàín½0T4VEXy@9pî“êýÀ¨  å–ü¯Ã,Pc6À Other Files will be deleted after 2 weeks !!! ƒÉBÁ<<àín½0T4VE+y@9q“êýÀ¨  å—,¯Ã,Pc6Ñ( ƒÉB;Á660T4Vàín½E(i¶@€9ˆÀ¨“êý  ¯Ã,å—/P?úzƒÉBˆÁ<<àín½0T4VE+y@9q“êýÀ¨  å—/¯Ã,Pc6Ñ% ƒÉB*ÄIIàín½0T4VE;y@9q“êýÀ¨  å—2¯Ã,Pc6íì Enjoy your stay. ƒÉB]Ä660T4Vàín½E(i·@€9‡À¨“êý  ¯Ã,å—EP?äzƒÉBòË__àín½0T4VEQy@9pñ“êýÀ¨  å—E¯Ã,Pc60ª230 Guest access granted for anonymous. ƒÉBçÏ>>0T4Vàín½E0i¸@€9~À¨“êý  ¯Ã,å—nP?»LxTYPE I ƒÉBãœIIàín½0T4VE;y@9q“êýÀ¨  å—n¯Ã4Pc6k#200 Type set to I ƒÉB¼ž<<0T4Vàín½E.i¹@€9À¨“êý  ¯Ã4å—P?¨mÂPASV ƒÉB@òjjàín½0T4VE\y@9pä“êýÀ¨  å—¯Ã:Pc6YÜ227 Entering Passive Mode (147,234,1,253,230,119). ƒÉBòöII0T4Vàín½E;iº@€9qÀ¨“êý  ¯Ã:å—µP?t±“RETR SiteStat.xml ƒÉBÆø>>0T4Vàín½E0i»@€9{À¨“êý ¡æwꘊp@F´ƒÉBž>ccàín½0T4VEUy@9pê“êýÀ¨  å—µ¯ÃMPc6cÈ550 SiteStat.xml: No such file or directory ƒÉBNT>>àín½0T4VE0y@9q“êýÀ¨æw ¡å!ºꘋpc6ƒ«ƒƒÉB‘T660T4Vàín½E(i¼@€9‚À¨“êý ¡æwꘋå!ºPB$ÑPƒÉBºU660T4Vàín½E(i½@€9À¨“êý ¡æwꘋå!ºPB$ÑOƒÉB Z<<0T4Vàín½E.i¾@€9zÀ¨“êý  ¯ÃMå—âP?Gv—QUIT ƒÉBK¦<<àín½0T4VE(y@9q%“êýÀ¨æw ¡å!ºꘌPc6°=ƒÉBÛ¸DDàín½0T4VE6y@9q“êýÀ¨  å—â¯ÃSPc6 v221 Goodbye. ƒÉBù660T4Vàín½E(i¿@€9À¨“êý  ¯ÃSå—ðP?9RƒÉBD»<<àín½0T4VE(y@9q“êýÀ¨  å—ð¯ÃSPc6úTƒÉBu»660T4Vàín½E(iÀ@€9~À¨“êý  ¯ÃTå—ñP?9QƒÉBõý<<àín½0T4VE(y@9q“êýÀ¨  å—ñ¯ÃTPc6úS…ÉBçX\\ÿÿÿÿÿÿàín½ENiÁ€LŒÀ¨À¨ÿ‰‰:[ª„ñ EFEDEJFPEEEPENEBEJEOCACACACACABM …ÉB·¹ \\ÿÿÿÿÿÿàín½ENi€L‹À¨À¨ÿ‰‰:[ª„ñ EFEDEJFPEEEPENEBEJEOCACACACACABM †ÉBcí\\ÿÿÿÿÿÿàín½ENiÀLŠÀ¨À¨ÿ‰‰:[ª„ñ EFEDEJFPEEEPENEBEJEOCACACACACABM ‡ÉB‚¶ <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ù͇ÉBµ¶ **0T4Vàín½àín½À¨0T4VÀ¨ŸÉBk¢VV0T4Vàín½EHiÈ€M‰À¨À¨ ¢54lM½Õ_sip_udpsip cybercitydk! ÉBÌŸVV0T4Vàín½EHiÉ€MˆÀ¨À¨ ¢54lM½Õ_sip_udpsip cybercitydk!¢ÉB¶ªVV0T4Vàín½EHiÊ€M‡À¨À¨ ¢54lM½Õ_sip_udpsip cybercitydk!¤ÉB^·VV0T4Vàín½EHiË€M†À¨À¨ ¢54lM½Õ_sip_udpsip cybercitydk!¨ÉBŒÍVV0T4Vàín½EHiÌ€M…À¨À¨ ¢54lM½Õ_sip_udpsip cybercitydk!°ÉB%ÔRR0T4Vàín½EDiÍ€MˆÀ¨À¨ £50ãEAÖ100127in-addrarpa °ÉBþÙiiàín½0T4VE[@@·>À¨À¨5 £GÅÁAÖ€100127in-addrarpa À ' localhost°ÉB3àýý0T4Vàín½Eïi΀pÀ¨Ôò!#ÄÄÛÓ,REGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp140520199-489d520f192.168.1.2;rport From: ;tag=8602b14 To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 70 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 °ÉBÄ àín½0T4VE@7Š+Ôò!#À¨ÄÄîåªSIP/2.0 401 Unauthorized Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 70 REGISTER From: ;tag=8602b14 To: ;tag=00-04089-1701b050-61ac4c943 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp140520199-489d520f192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b042073e40dc3ac7adb052ad41d",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 °ÉB(ÒVV0T4Vàín½EHiÏ€M‚À¨À¨ ¤54SJÖÖ_sip_udpsip cybercitydk!±ÉBhÑVV0T4Vàín½EHiЀMÀ¨À¨ ¤54SJÖÖ_sip_udpsip cybercitydk!³ÉB[ÜVV0T4Vàín½EHiÑ€M€À¨À¨ ¤54SJÖÖ_sip_udpsip cybercitydk!´ÉB3Ö\\ÿÿÿÿÿÿàín½ENiÒ€L{À¨À¨ÿ‰‰:[§„ô EFEDEJFPEEEPENEBEJEOCACACACACABM µÉB›\\ÿÿÿÿÿÿàín½ENiÓ€LzÀ¨À¨ÿ‰‰:[§„ô EFEDEJFPEEEPENEBEJEOCACACACACABM µÉBøçVV0T4Vàín½EHiÔ€M}À¨À¨ ¤54SJÖÖ_sip_udpsip cybercitydk!µÉB~y \\ÿÿÿÿÿÿàín½ENiÕ€LxÀ¨À¨ÿ‰‰:[§„ô EFEDEJFPEEEPENEBEJEOCACACACACABM ¹ÉB(þVV0T4Vàín½EHiÖ€M{À¨À¨ ¤54SJÖÖ_sip_udpsip cybercitydk!ÁÉB×RR0T4Vàín½EDi×€M~À¨À¨ ¥50äB@×100127in-addrarpa ÁÉBÊ iiàín½0T4VE[@@·>À¨À¨5 ¥Gƾ@×€100127in-addrarpa À ' localhostÁÉBÃLL0T4Vàín½E>iØ€MƒÀ¨À¨ ¦5*.Í×sip cybercitydkÁÉBœ$\\àín½0T4VEN@@·KÀ¨À¨5 ¦:ªÓÍ×sip cybercitydkÀ 'Ôò!#ÁÉBš(ÒÒ0T4Vàín½EÄiÙ€À¨Ôò!#Äİ5REGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp138780672-45022a1c192.168.1.2;rport From: ;tag=845a00d To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 71 REGISTER Content-Length: 0 Authorization: Digest username="voi18063",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b042073e40dc3ac7adb052ad41d",opaque="1701a1351f70795",nc="00000001",response="cc2d4573ee9399f34c1c7f3bf5144103" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ÁÉB@z àín½0T4VE@7Š&Ôò!#À¨ÄÄó¾êSIP/2.0 401 nonce has changed Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 71 REGISTER From: ;tag=845a00d To: ;tag=00-04089-1701b067-320ad2da3 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp138780672-45022a1c192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b061158742446d3de8b80d645f3",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ÆÉBÈë<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍÆÉBüë**0T4Vàín½àín½À¨0T4VÀ¨ãÉBýþ \\ÿÿÿÿÿÿàín½ENiÚ€LsÀ¨À¨ÿ‰‰:[¤„÷ EFEDEJFPEEEPENEBEJEOCACACACACABM äÉB8,\\ÿÿÿÿÿÿàín½ENiÛ€LrÀ¨À¨ÿ‰‰:[¤„÷ EFEDEJFPEEEPENEBEJEOCACACACACABM åÉBã_\\ÿÿÿÿÿÿàín½ENiÜ€LqÀ¨À¨ÿ‰‰:[¤„÷ EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBáê\\ÿÿÿÿÿÿàín½ENiå€LhÀ¨À¨ÿ‰‰:[Ÿ„ü EFEDEJFPEEEPENEBEJEOCACACACACABM ÉB`ú \\ÿÿÿÿÿÿàín½ENiæ€LgÀ¨À¨ÿ‰‰:[Ÿ„ü EFEDEJFPEEEPENEBEJEOCACACACACABM ÉB .\\ÿÿÿÿÿÿàín½ENiç€LfÀ¨À¨ÿ‰‰:[Ÿ„ü EFEDEJFPEEEPENEBEJEOCACACACACABM CÉB%ÿ\\ÿÿÿÿÿÿàín½ENj€L0À¨À¨ÿ‰‰:[œ„ÿ EFEDEJFPEEEPENEBEJEOCACACACACABM DÉB‚+\\ÿÿÿÿÿÿàín½ENj€L/À¨À¨ÿ‰‰:[œ„ÿ EFEDEJFPEEEPENEBEJEOCACACACACABM DÉBi¡\\ÿÿÿÿÿÿàín½ENj€L.À¨À¨ÿ‰‰:[œ„ÿ EFEDEJFPEEEPENEBEJEOCACACACACABM FÉBÉ **ÿÿÿÿÿÿàín½àín½À¨À¨FÉBk <<àín½0T4V0T4VÀ¨àín½À¨ˆdö7 À! Ï;ùÍFÉB‹ VV0T4Vàín½EHj €M1À¨À¨ ¬54Í@\Ø_sip_udpsip cybercitydk!GÉBWö VV0T4Vàín½EHj!€M0À¨À¨ ¬54Í@\Ø_sip_udpsip cybercitydk!IÉB VV0T4Vàín½EHj"€M/À¨À¨ ¬54Í@\Ø_sip_udpsip cybercitydk!KÉBØ VV0T4Vàín½EHj#€M.À¨À¨ ¬54Í@\Ø_sip_udpsip cybercitydk!OÉBÆ" VV0T4Vàín½EHj$€M-À¨À¨ ¬54Í@\Ø_sip_udpsip cybercitydk!WÉBJ* RR0T4Vàín½EDj%€M0À¨À¨ ­50\9ÈØ100127in-addrarpa WÉB60 iiàín½0T4VE[@@·>À¨À¨5 ­G>µÈØ€100127in-addrarpa À ' localhostWÉB6 ýý0T4Vàín½Eïj&€À¨Ôò!#ÄÄÛ›rREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp123759063-464bc1bb192.168.1.2;rport From: ;tag=76069e4 To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 72 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 WÉB{Y àín½0T4VE@7Š+Ôò!#À¨ÄÄî‹úSIP/2.0 401 Unauthorized Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 72 REGISTER From: ;tag=76069e4 To: ;tag=00-04071-1701b172-22e1cc470 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp123759063-464bc1bb192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b16a2a09bc3847cfd2015612fe2",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 WÉBCðVV0T4Vàín½EHj'€M*À¨À¨ ®54¬<}Ú_sip_udpsip cybercitydk!XÉB@ëVV0T4Vàín½EHj(€M)À¨À¨ ®54¬<}Ú_sip_udpsip cybercitydk!ZÉB<öVV0T4Vàín½EHj)€M(À¨À¨ ®54¬<}Ú_sip_udpsip cybercitydk!\ÉBð <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ\ÉB"! **0T4Vàín½àín½À¨0T4VÀ¨\ÉB>VV0T4Vàín½EHj*€M'À¨À¨ ®54¬<}Ú_sip_udpsip cybercitydk!`ÉBVV0T4Vàín½EHj+€M&À¨À¨ ®54¬<}Ú_sip_udpsip cybercitydk!hÉBc RR0T4Vàín½EDj,€M)À¨À¨ ¯5014óÛ100127in-addrarpa hÉB@&iiàín½0T4VE[@@·>À¨À¨5 ¯G°óÛ€100127in-addrarpa À ' localhosthÉB>,ÒÒ0T4Vàín½EÄj-€<À¨Ôò!#ÄİVJREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp122028667-481b9fc8192.168.1.2;rport From: ;tag=7460288 To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 73 REGISTER Content-Length: 0 Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b16a2a09bc3847cfd2015612fe2",opaque="1701a1351f70795",nc="00000001",response="29cd776112a709cb9cbe978baff5e478" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 iÉB 7àín½0T4VE@7Š&Ôò!#À¨ÄÄó|ÖSIP/2.0 401 nonce has changed Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 73 REGISTER From: ;tag=7460288 To: ;tag=00-04086-1701b193-645204ed6 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp122028667-481b9fc8192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b191514c6b695b4a2dd659cc0ff",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 sÉB¾} \\ÿÿÿÿÿÿàín½ENj.€LÀ¨À¨ÿ‰‰:[™… EFEDEJFPEEEPENEBEJEOCACACACACABM tÉBg¬\\ÿÿÿÿÿÿàín½ENj/€LÀ¨À¨ÿ‰‰:[™… EFEDEJFPEEEPENEBEJEOCACACACACABM uÉBß\\ÿÿÿÿÿÿàín½ENj0€LÀ¨À¨ÿ‰‰:[™… EFEDEJFPEEEPENEBEJEOCACACACACABM ¡ÉBÓ´ VV0T4Vàín½EHj5€MÀ¨À¨ °54­8|Ü_sip_udpsip cybercitydk!¢ÉB>¤ VV0T4Vàín½EHj6€MÀ¨À¨ °54­8|Ü_sip_udpsip cybercitydk!¢ÉB)•\\ÿÿÿÿÿÿàín½ENj7€LÀ¨À¨ÿ‰‰:[”… EFEDEJFPEEEPENEBEJEOCACACACACABM £ÉB1 \\ÿÿÿÿÿÿàín½ENj8€LÀ¨À¨ÿ‰‰:[”… EFEDEJFPEEEPENEBEJEOCACACACACABM ¤ÉBàõ\\ÿÿÿÿÿÿàín½ENj9€LÀ¨À¨ÿ‰‰:[”… EFEDEJFPEEEPENEBEJEOCACACACACABM ¤ÉBã² VV0T4Vàín½EHj:€MÀ¨À¨ °54­8|Ü_sip_udpsip cybercitydk!¦ÉB’» VV0T4Vàín½EHj=€MÀ¨À¨ °54­8|Ü_sip_udpsip cybercitydk!ªÉBÑ VV0T4Vàín½EHj>€MÀ¨À¨ °54­8|Ü_sip_udpsip cybercitydk!²ÉB•Ø RR0T4Vàín½EDj?€MÀ¨À¨ ±50 1Ý100127in-addrarpa ²ÉBuÞ iiàín½0T4VE[@@·>À¨À¨5 ±Gì¬Ý€100127in-addrarpa À ' localhost²ÉBIä ýý0T4Vàín½Eïj@€þÀ¨Ôò!#ÄÄÛÉ¥REGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp114639000-477e7591192.168.1.2;rport From: ;tag=6d540a5 To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 74 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ³ÉBźàín½0T4VE@7Š+Ôò!#À¨ÄÄî81SIP/2.0 401 Unauthorized Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 74 REGISTER From: ;tag=6d540a5 To: ;tag=00-04089-1701b236-2b7211607 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp114639000-477e7591192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b22972b90f440c3e4eb250842bb",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ³ÉBÍiVV0T4Vàín½EHjA€MÀ¨À¨ ²54¦5ƒÝ_sip_udpsip cybercitydk!´ÉBWVV0T4Vàín½EHjB€MÀ¨À¨ ²54¦5ƒÝ_sip_udpsip cybercitydk!¶ÉBRbVV0T4Vàín½EHjC€MÀ¨À¨ ²54¦5ƒÝ_sip_udpsip cybercitydk!·ÉBŽË <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ·ÉB¿Ë **0T4Vàín½àín½À¨0T4VÀ¨¸ÉBvmVV0T4Vàín½EHjD€M À¨À¨ ²54¦5ƒÝ_sip_udpsip cybercitydk!¼ÉBõƒVV0T4Vàín½EHjE€M À¨À¨ ²54¦5ƒÝ_sip_udpsip cybercitydk!ÄÉBõ‹RR0T4Vàín½EDjF€MÀ¨À¨ ³50º-jÞ100127in-addrarpa ÄÉBÑiiàín½0T4VE[@@·>À¨À¨5 ³Gœ©jÞ€100127in-addrarpa À ' localhostÄÉB·—ÒÒ0T4Vàín½EÄjG€"À¨Ôò!#ÄİWkREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp112903503-43a64480192.168.1.2;rport From: ;tag=6bac55c To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 75 REGISTER Content-Length: 0 Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b22972b90f440c3e4eb250842bb",opaque="1701a1351f70795",nc="00000001",response="79a0543188495d288c9ebbe0c881abdc" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ÄÉB7Ð\\àín½0T4VEN@7ŠßÔò!#À¨ÄÄ:; SIP/2.0 100 Trying Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 75 REGISTER From: ;tag=6bac55c To: Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp112903503-43a64480192.168.1.2 Content-Length: 0 ÄÉB†5àín½0T4VEò@7Š;Ôò!#À¨ÄÄÞ(ÙSIP/2.0 200 OK Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;q=0.500;expires=1200 CSeq: 75 REGISTER From: ;tag=6bac55c P-Associated-URI: To: ;tag=00-04081-1701b256-5586b7324 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp112903503-43a64480192.168.1.2 Content-Length: 0 ÄÉBTmVV0T4Vàín½EHjH€M À¨À¨ ´54ý1,ß_sip_udpsip cybercitydk!ÅÉBiVV0T4Vàín½EHjI€MÀ¨À¨ ´54ý1,ß_sip_udpsip cybercitydk!ÇÉBtVV0T4Vàín½EHjJ€MÀ¨À¨ ´54ý1,ß_sip_udpsip cybercitydk!ÉÉBZVV0T4Vàín½EHjK€MÀ¨À¨ ´54ý1,ß_sip_udpsip cybercitydk!ÍÉBï•VV0T4Vàín½EHjL€MÀ¨À¨ ´54ý1,ß_sip_udpsip cybercitydk!ÒÉBNK\\ÿÿÿÿÿÿàín½ENjM€LÀ¨À¨ÿ‰‰:[‘…  EFEDEJFPEEEPENEBEJEOCACACACACABM ÒÉBر\\ÿÿÿÿÿÿàín½ENjN€KÿÀ¨À¨ÿ‰‰:[‘…  EFEDEJFPEEEPENEBEJEOCACACACACABM ÓÉB€å \\ÿÿÿÿÿÿàín½ENjO€KþÀ¨À¨ÿ‰‰:[‘…  EFEDEJFPEEEPENEBEJEOCACACACACABM ÕÉB‡RR0T4Vàín½EDjQ€MÀ¨À¨ µ50ñI3À100127in-addrarpa ÕÉBX£iiàín½0T4VE[@@·>À¨À¨5 µGÓÅ3À€100127in-addrarpa À ' localhostÕÉB½§//0T4Vàín½E!jR€ºÀ¨Ôò!#ÄÄ ÀK áÉBèøVV0T4Vàín½EHjS€LþÀ¨À¨ ¶54vN³À_sip_udpsip cybercitydk!âÉBåVV0T4Vàín½EHjT€LýÀ¨À¨ ¶54vN³À_sip_udpsip cybercitydk!äÉB-ðVV0T4Vàín½EHjU€LüÀ¨À¨ ¶54vN³À_sip_udpsip cybercitydk!æÉBžûVV0T4Vàín½EHjV€LûÀ¨À¨ ¶54vN³À_sip_udpsip cybercitydk!êÉB'VV0T4Vàín½EHjW€LúÀ¨À¨ ¶54vN³À_sip_udpsip cybercitydk!ðÉBu9óóÿÿÿÿÿÿ`—îrEå\¾€XÑÀ¨)À¨ÿŠŠÑ ‘KÀ¨)Š» EMEBECDBDBDBCACACACACACACACACACA FHEPFCELEHFCEPFFFACACACACACACABNÿSMB%!è!V2\MAILSLOT\BROWSE€ü LAB111²ïÍh"UªòÉBlRR0T4Vàín½EDjX€LýÀ¨À¨ ·50¨E|Â100127in-addrarpa òÉBHiiàín½0T4VE[@@·>À¨À¨5 ·GŠÁ|€100127in-addrarpa À ' localhostòÉBÝ#//0T4Vàín½E!jY€³À¨Ôò!#ÄÄ ÀK ÷ÉBÝ<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ÷ÉB**0T4Vàín½àín½À¨0T4VÀ¨ÿÉB%VV0T4Vàín½EHjZ€L÷À¨À¨ ¸54àIIÃ_sip_udpsip cybercitydk!ÉB‰ VV0T4Vàín½EHj[€LöÀ¨À¨ ¸54àIIÃ_sip_udpsip cybercitydk!ÉBÏ.\\ÿÿÿÿÿÿàín½ENj`€KíÀ¨À¨ÿ‰‰:[Œ… EFEDEJFPEEEPENEBEJEOCACACACACABM ÉB¶VV0T4Vàín½EHja€LðÀ¨À¨ ¸54àIIÃ_sip_udpsip cybercitydk!ÉB«Ÿ \\ÿÿÿÿÿÿàín½ENjb€KëÀ¨À¨ÿ‰‰:[Œ… EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBYÓ\\ÿÿÿÿÿÿàín½ENjc€KêÀ¨À¨ÿ‰‰:[Œ… EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBéVV0T4Vàín½EHjd€LíÀ¨À¨ ¸54àIIÃ_sip_udpsip cybercitydk!ÉBJ7VV0T4Vàín½EHje€LìÀ¨À¨ ¸54àIIÃ_sip_udpsip cybercitydk!ÉB•?RR0T4Vàín½EDjf€LïÀ¨À¨ ¹500BôÃ100127in-addrarpa ÉBeEiiàín½0T4VE[@@·>À¨À¨5 ¹G¾ôÀ100127in-addrarpa À ' localhostÉBÞK//0T4Vàín½E!jg€¥À¨Ôò!#ÄÄ ÀK ÉBùºVV0T4Vàín½EHjh€LéÀ¨À¨ º54Ë„Ä_sip_udpvoipbrujulanet!ÉB>¢VV0T4Vàín½EHji€LèÀ¨À¨ º54Ë„Ä_sip_udpvoipbrujulanet!ÉBx­VV0T4Vàín½EHjj€LçÀ¨À¨ º54Ë„Ä_sip_udpvoipbrujulanet!ÉBº¸VV0T4Vàín½EHjk€LæÀ¨À¨ º54Ë„Ä_sip_udpvoipbrujulanet!ÉBXÏVV0T4Vàín½EHjl€LåÀ¨À¨ º54Ë„Ä_sip_udpvoipbrujulanet!!ÉBtÖRR0T4Vàín½EDjm€LèÀ¨À¨ »503>ñÅ100127in-addrarpa !ÉBJÜiiàín½0T4VE[@@·>À¨À¨5 »GºñÅ€100127in-addrarpa À ' localhost!ÉBAâ``0T4Vàín½ERjn€ÊìÀ¨ÈDxQÄÄ>ò›INVITE sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 272 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 105015165 105015162 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv !ÉB—éVV0T4Vàín½EHjo€LâÀ¨À¨ ¼54,BýÆ_sip_udpsip cybercitydk!!ÉB"¢ ``0T4Vàín½ERjp€ÊêÀ¨ÈDxQÄÄ>ò›INVITE sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 272 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 105015165 105015162 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv "ÉB”ÚVV0T4Vàín½EHjq€LàÀ¨À¨ ¼54,BýÆ_sip_udpsip cybercitydk!"ÉBª ``0T4Vàín½ERjr€ÊèÀ¨ÈDxQÄÄ>ò›INVITE sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 272 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 105015165 105015162 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv #ÉBï.}}àín½0T4VEo@/G>ÈDxQÀ¨ÄÄ[(SIP/2.0 100 trying -- your call is important to us Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport=5060;received=80.230.219.70 From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 INVITE Server: Sip EXpress router (0.8.12 (i386/linux)) Content-Length: 0 Warning: 392 200.68.120.81:5060 "Noisy feedback tells: pid=32642 req_src_ip=80.230.219.70 req_src_port=5060 in_uri=sip:97239287044@voip.brujula.net out_uri=sip:97239287044@voip.brujula.net via_cnt==1" $ÉBÕåVV0T4Vàín½EHjs€LÞÀ¨À¨ ¼54,BýÆ_sip_udpsip cybercitydk!&ÉBoÐ<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ&ÉB£Ð**0T4Vàín½àín½À¨0T4VÀ¨&ÉBôðVV0T4Vàín½EHjt€LÝÀ¨À¨ ¼54,BýÆ_sip_udpsip cybercitydk!*ÉBšVV0T4Vàín½EHju€LÜÀ¨À¨ ¼54,BýÆ_sip_udpsip cybercitydk!1ÉBvò\\ÿÿÿÿÿÿàín½ENjv€K×À¨À¨ÿ‰‰:[‰… EFEDEJFPEEEPENEBEJEOCACACACACABM 2ÉB„"\\ÿÿÿÿÿÿàín½ENjw€KÖÀ¨À¨ÿ‰‰:[‰… EFEDEJFPEEEPENEBEJEOCACACACACABM 2ÉB(RR0T4Vàín½EDjx€LÝÀ¨À¨ ½50 :È100127in-addrarpa 2ÉBÙiiàín½0T4VE[@@·>À¨À¨5 ½GìµÈ€100127in-addrarpa À ' localhost2ÉBt//0T4Vàín½E!jy€“À¨Ôò!#ÄÄ ÀK 2ÉBÝ{VV0T4Vàín½EHjz€L×À¨À¨ ¾54?È_sip_udpvoipbrujulanet!2ÉBj˜ \\ÿÿÿÿÿÿàín½ENj{€KÒÀ¨À¨ÿ‰‰:[‰… EFEDEJFPEEEPENEBEJEOCACACACACABM 3ÉBsVV0T4Vàín½EHj|€LÕÀ¨À¨ ¾54?È_sip_udpvoipbrujulanet!5ÉBv~VV0T4Vàín½EHj}€LÔÀ¨À¨ ¾54?È_sip_udpvoipbrujulanet!7ÉBˆŠVV0T4Vàín½EHj~€LÓÀ¨À¨ ¾54?È_sip_udpvoipbrujulanet!;ÉB2 VV0T4Vàín½EHj€LÒÀ¨À¨ ¾54?È_sip_udpvoipbrujulanet!CÉB §RR0T4Vàín½EDj€€LÕÀ¨À¨ ¿50 6Ê100127in-addrarpa CÉB~­iiàín½0T4VE[@@·>À¨À¨5 ¿Gì±Ê€100127in-addrarpa À ' localhostCÉB-³¡¡0T4Vàín½E“j€̘À¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 CÉB`½VV0T4Vàín½EHj‚€LÏÀ¨À¨ À54¹8pÌ_sip_udpsip cybercitydk!CÉBÈr ¡¡0T4Vàín½E“jƒ€Ì–À¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 DÉB¤«VV0T4Vàín½EHj„€LÍÀ¨À¨ À54¹8pÌ_sip_udpsip cybercitydk!DÉBÜž ¡¡0T4Vàín½E“j…€Ì”À¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 EÉB­àín½0T4VE‚@/G+ÈDxQÀ¨ÄÄnSIP/2.0 408 Request Timeout Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport=5060;received=80.230.219.70 From: "arik" ;tag=6433ef9 To: ;tag=a6a1c5f60faecf035a1ae5b6e96e979a-6167 Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 INVITE Server: Sip EXpress router (0.8.12 (i386/linux)) Content-Length: 0 Warning: 392 200.68.120.81:5060 "Noisy feedback tells: pid=32753 req_src_ip=80.230.219.70 req_src_port=5060 in_uri=sip:97239287044@voip.brujula.net out_uri=sip:97239287044@voip.brujula.net via_cnt==0" EÉBÌ……0T4Vàín½Ewj†€̯À¨ÈDxQÄÄcЬACK sip:97239287044@voip.brujula.net SIP/2.0 From: "arik" ;tag=6433ef9 Call-ID: 105090259-446faf7a@192.168.1.2 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport To: ;tag=a6a1c5f60faecf035a1ae5b6e96e979a-6167 CSeq: 1 ACK Content-Length: 0 FÉBò¶VV0T4Vàín½EHj‡€LÊÀ¨À¨ À54¹8pÌ_sip_udpsip cybercitydk!FÉB‡Ñ ¡¡0T4Vàín½E“jˆ€Ì‘À¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 HÉB ÂVV0T4Vàín½EHj‰€LÈÀ¨À¨ À54¹8pÌ_sip_udpsip cybercitydk!JÉB= ¡¡0T4Vàín½E“jŠ€ÌÀ¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 LÉBñØVV0T4Vàín½EHj‹€LÆÀ¨À¨ À54¹8pÌ_sip_udpsip cybercitydk!NÉB£& ¡¡0T4Vàín½E“jŒ€ÌÀ¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 RÉB@= ¡¡0T4Vàín½E“j€ÌŒÀ¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 TÉB7àRR0T4Vàín½EDjŽ€LÇÀ¨À¨ Á50Ü/HÎ100127in-addrarpa TÉBæiiàín½0T4VE[@@·>À¨À¨5 ÁG¾«H΀100127in-addrarpa À ' localhostTÉB˜ê//0T4Vàín½E!j€}À¨Ôò!#ÄÄ ÀK VÉB}z ¡¡0T4Vàín½E“j€̉À¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ZÉB ¡¡0T4Vàín½E“j‘€̈À¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ^ÉB‰¦ ¡¡0T4Vàín½E“j’€̇À¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 `ÉBŽ:VV0T4Vàín½EHj“€L¾À¨À¨ Â54¬3}Ï_sip_udpsip cybercitydk!`ÉB½/ \\ÿÿÿÿÿÿàín½ENj”€K¹À¨À¨ÿ‰‰:[†… EFEDEJFPEEEPENEBEJEOCACACACACABM aÉBµ'VV0T4Vàín½EHj•€L¼À¨À¨ Â54¬3}Ï_sip_udpsip cybercitydk!aÉBó\\\ÿÿÿÿÿÿàín½ENj–€K·À¨À¨ÿ‰‰:[†… EFEDEJFPEEEPENEBEJEOCACACACACABM bÉBŸ\\ÿÿÿÿÿÿàín½ENj—€K¶À¨À¨ÿ‰‰:[†… EFEDEJFPEEEPENEBEJEOCACACACACABM bÉB$ä ¡¡0T4Vàín½E“j˜€ÌÀ¨ÈDxQÄÄ™œCANCEL sip:97239287044@voip.brujula.net SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport From: "arik" ;tag=6433ef9 To: Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 cÉBã2VV0T4Vàín½EHj™€L¸À¨À¨ Â54¬3}Ï_sip_udpsip cybercitydk!dÉB1B‹‹àín½0T4VE}@/G0ÈDxQÀ¨ÄÄiÈïSIP/2.0 408 Request Timeout Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp104984053-44ce4a41192.168.1.2;rport=5060;received=80.230.219.70 From: "arik" ;tag=6433ef9 To: ;tag=a6a1c5f60faecf035a1ae5b6e96e979a-e525 Call-ID: 105090259-446faf7a@192.168.1.2 CSeq: 1 CANCEL Server: Sip EXpress router (0.8.12 (i386/linux)) Content-Length: 0 Warning: 392 200.68.120.81:5060 "Noisy feedback tells: pid=32753 req_src_ip=80.230.219.70 req_src_port=5060 in_uri=sip:97239287044@voip.brujula.net out_uri=sip:97239287044@voip.brujula.net via_cnt==0" eÉBÂ>VV0T4Vàín½EHjš€L·À¨À¨ Â54¬3}Ï_sip_udpsip cybercitydk!iÉBÌ0<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍiÉB1**0T4Vàín½àín½À¨0T4VÀ¨iÉB¨ VV0T4Vàín½EHj›€L¶À¨À¨ Â54¬3}Ï_sip_udpsip cybercitydk!qÉBý RR0T4Vàín½EDjœ€L¹À¨À¨ Ã50Ï Uð100127in-addrarpa qÉBí iiàín½0T4VE[@@·>À¨À¨5 ÃG±‡Uð€100127in-addrarpa À ' localhostqÉB //0T4Vàín½E!j€oÀ¨Ôò!#ÄÄ ÀK }ÉB)a VV0T4Vàín½EHj¢€L¯À¨À¨ Ä54)ð_sip_udpsip cybercitydk!~ÉBÆN VV0T4Vàín½EHj£€L®À¨À¨ Ä54)ð_sip_udpsip cybercitydk!€ÉBëY VV0T4Vàín½EHj¤€L­À¨À¨ Ä54)ð_sip_udpsip cybercitydk!‚ÉBøe VV0T4Vàín½EHj¥€L¬À¨À¨ Ä54)ð_sip_udpsip cybercitydk!†ÉB—{ VV0T4Vàín½EHj¦€L«À¨À¨ Ä54)ð_sip_udpsip cybercitydk!ŽÉB„ RR0T4Vàín½EDj§€L®À¨À¨ Å50E ßð100127in-addrarpa ŽÉBAŠ iiàín½0T4VE[@@·>À¨À¨5 ÅG'…ßð€100127in-addrarpa À ' localhostŽÉBÕŽ //0T4Vàín½E!j¨€dÀ¨Ôò!#ÄÄ ÀK ÉBÇÞ \\ÿÿÿÿÿÿàín½ENj©€K¤À¨À¨ÿ‰‰:[… EFEDEJFPEEEPENEBEJEOCACACACACABM ‘ÉB`\\ÿÿÿÿÿÿàín½ENjª€K£À¨À¨ÿ‰‰:[… EFEDEJFPEEEPENEBEJEOCACACACACABM ’ÉBB\\ÿÿÿÿÿÿàín½ENj«€K¢À¨À¨ÿ‰‰:[… EFEDEJFPEEEPENEBEJEOCACACACACABM šÉBÛÝ VV0T4Vàín½EHj¬€L¥À¨À¨ Æ54â Gò_sip_udpsip cybercitydk!›ÉBšÊ VV0T4Vàín½EHj­€L¤À¨À¨ Æ54â Gò_sip_udpsip cybercitydk!ÉBØÕ VV0T4Vàín½EHj®€L£À¨À¨ Æ54â Gò_sip_udpsip cybercitydk!ŸÉBá VV0T4Vàín½EHj¯€L¢À¨À¨ Æ54â Gò_sip_udpsip cybercitydk!£ÉB÷ VV0T4Vàín½EHj°€L¡À¨À¨ Æ54â Gò_sip_udpsip cybercitydk!«ÉBíÿ RR0T4Vàín½EDj±€L¤À¨À¨ Ç50ü(ó100127in-addrarpa «ÉB× iiàín½0T4VE[@@·>À¨À¨5 ÇGÞ€(ó€100127in-addrarpa À ' localhost«ÉBd //0T4Vàín½E!j²€ZÀ¨Ôò!#ÄÄ ÀK °ÉBþ <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùͰÉBCþ **0T4Vàín½àín½À¨0T4VÀ¨·ÉBóY VV0T4Vàín½EHj³€LžÀ¨À¨ È54p¹ô_sip_udpsip cybercitydk!¸ÉBˆF VV0T4Vàín½EHj´€LÀ¨À¨ È54p¹ô_sip_udpsip cybercitydk!ºÉBäQ VV0T4Vàín½EHjµ€LœÀ¨À¨ È54p¹ô_sip_udpsip cybercitydk!¼ÉB/] VV0T4Vàín½EHj¶€L›À¨À¨ È54p¹ô_sip_udpsip cybercitydk!¿ÉB`Ü \\ÿÿÿÿÿÿàín½ENj·€K–À¨À¨ÿ‰‰:[~… EFEDEJFPEEEPENEBEJEOCACACACACABM ÀÉBþ \\ÿÿÿÿÿÿàín½ENj¸€K•À¨À¨ÿ‰‰:[~… EFEDEJFPEEEPENEBEJEOCACACACACABM ÀÉB{s VV0T4Vàín½EHj¹€L˜À¨À¨ È54p¹ô_sip_udpsip cybercitydk!ÁÉB²1\\ÿÿÿÿÿÿàín½ENjº€K“À¨À¨ÿ‰‰:[~… EFEDEJFPEEEPENEBEJEOCACACACACABM ÈÉBæz RR0T4Vàín½EDj»€LšÀ¨À¨ É50øÿ+ö100127in-addrarpa ÈÉB€ iiàín½0T4VE[@@·>À¨À¨5 ÉGÛ{+ö€100127in-addrarpa À ' localhostÈÉBX… //0T4Vàín½E!j¼€PÀ¨Ôò!#ÄÄ ÀK ÈÉB¹ó VV0T4Vàín½EHj½€L”À¨À¨ Ê54«~ø_sip_udpsip cybercitydk!ÉÉB2ß VV0T4Vàín½EHj¾€L“À¨À¨ Ê54«~ø_sip_udpsip cybercitydk!ËÉBpê VV0T4Vàín½EHj¿€L’À¨À¨ Ê54«~ø_sip_udpsip cybercitydk!ÍÉB õ VV0T4Vàín½EHjÀ€L‘À¨À¨ Ê54«~ø_sip_udpsip cybercitydk!ÑÉB VV0T4Vàín½EHjÁ€LÀ¨À¨ Ê54«~ø_sip_udpsip cybercitydk!ÙÉB‘ RR0T4Vàín½EDj€L“À¨À¨ Ë50tú¯ù100127in-addrarpa ÙÉBh iiàín½0T4VE[@@·>À¨À¨5 ËGWv¯ù€100127in-addrarpa À ' localhostÙÉB_ cc0T4Vàín½EUjÀÀ¨Ôò!#ÄÄAˆáINVITE sip:0097239287044@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp85213694-430aa1de192.168.1.2;rport From: "arik" ;tag=51449dc To: Call-ID: 85216695-42dcdb1d@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 270 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 85214742 85214739 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv ÙÉBµ& VV0T4Vàín½EHjÄ€LÀ¨À¨ Ì54Iýßû_sip_udpsip cybercitydk!ÚÉB&ucc0T4Vàín½EUjÅ€À¨Ôò!#ÄÄAˆáINVITE sip:0097239287044@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp85213694-430aa1de192.168.1.2;rport From: "arik" ;tag=51449dc To: Call-ID: 85216695-42dcdb1d@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 270 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 85214742 85214739 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv ÚÉB¹ VV0T4Vàín½EHjÆ€L‹À¨À¨ Ì54Iýßû_sip_udpsip cybercitydk!ÛÉBX|cc0T4Vàín½EUjÇ€À¨Ôò!#ÄÄAˆáINVITE sip:0097239287044@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp85213694-430aa1de192.168.1.2;rport From: "arik" ;tag=51449dc To: Call-ID: 85216695-42dcdb1d@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 270 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 85214742 85214739 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv ÛÉBÜØ{{àín½0T4VEm@7‰ÀÔò!#À¨ÄÄYe SIP/2.0 407 authentication required Allow: UPDATE,REFER Call-ID: 85216695-42dcdb1d@192.168.1.2 Contact: CSeq: 1 INVITE From: "arik" ;tag=51449dc Proxy-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b4767d49c41117c7b73a255a353",opaque="1701a1351f70795",stale=false,algorithm=MD5 Server: Cirpack/v4.38e (gw_sip) To: ;tag=00-04073-1701b482-069239f90 Via: SIP/2.0/UDP 192.168.1.2:5060;received=80.230.219.70;rport=5060;branch=z9hG4bKnp85213694-430aa1de192.168.1.2 Content-Length: 0 ÛÉBvó~~0T4Vàín½EpjÈ€õÀ¨Ôò!#ÄÄ\—kACK sip:0097239287044@sip.cybercity.dk SIP/2.0 From: "arik" ;tag=51449dc Call-ID: 85216695-42dcdb1d@192.168.1.2 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp85213694-430aa1de192.168.1.2;rport To: ;tag=00-04073-1701b482-069239f90 CSeq: 1 ACK Content-Length: 0 ÜÉB# VV0T4Vàín½EHjÉ€LˆÀ¨À¨ Ì54Iýßû_sip_udpsip cybercitydk!ÞÉBtú <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍÞÉB©ú **0T4Vàín½àín½À¨0T4VÀ¨ÞÉB\. VV0T4Vàín½EHjÊ€L‡À¨À¨ Ì54Iýßû_sip_udpsip cybercitydk!âÉBŸE VV0T4Vàín½EHjË€L†À¨À¨ Ì54Iýßû_sip_udpsip cybercitydk!êÉBL RR0T4Vàín½EDjÌ€L‰À¨À¨ Í50»ôhý100127in-addrarpa êÉBÌQ iiàín½0T4VE[@@·>À¨À¨5 ÍGžphý€100127in-addrarpa À ' localhostêÉBwV //0T4Vàín½E!jÍ€?À¨Ôò!#ÄÄ ÀK êÉB®Ô VV0T4Vàín½EHj΀LƒÀ¨À¨ Î54­ù{ý_sip_udpsip cybercitydk!ëÉBÂÚ VV0T4Vàín½EHjÏ€L‚À¨À¨ Î54­ù{ý_sip_udpsip cybercitydk!íÉBªâ VV0T4Vàín½EHjЀLÀ¨À¨ Î54­ù{ý_sip_udpsip cybercitydk!ïÉBêí VV0T4Vàín½EHjÑ€L€À¨À¨ Î54­ù{ý_sip_udpsip cybercitydk!ðÉB7Z\\ÿÿÿÿÿÿàín½ENjÒ€K{À¨À¨ÿ‰‰:[y…" EFEDEJFPEEEPENEBEJEOCACACACACABM ðÉB,Ì \\ÿÿÿÿÿÿàín½ENj×€KvÀ¨À¨ÿ‰‰:[y…" EFEDEJFPEEEPENEBEJEOCACACACACABM ñÉBÔÿ \\ÿÿÿÿÿÿàín½ENjØ€KuÀ¨À¨ÿ‰‰:[y…" EFEDEJFPEEEPENEBEJEOCACACACACABM óÉBVVV0T4Vàín½EHjÙ€LxÀ¨À¨ Î54­ù{ý_sip_udpsip cybercitydk!ûÉBð RR0T4Vàín½EDjÚ€L{À¨À¨ Ï50lò·ý100127in-addrarpa ûÉB¼iiàín½0T4VE[@@·>À¨À¨5 ÏGOn·ý€100127in-addrarpa À ' localhostûÉBà^^0T4Vàín½EPjÛ€À¨Ôò!#ÄÄ<$öINVITE sip:0097239287044@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp83260863-46304c10192.168.1.2;rport From: "arik" ;tag=51449dc To: Call-ID: 85216695-42dcdb1d@192.168.1.2 CSeq: 2 INVITE Proxy-Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b4767d49c41117c7b73a255a353",opaque="1701a1351f70795",nc="00000001",response="8258d3744c08b75f7af46cd0f1762510" Content-Type: application/sdp Content-Length: 270 Date: Mon, 04 Jul 2005 09:43:55 GMT Contact: Expires: 120 Accept: application/sdp Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 85214742 85214739 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv ûÉBËVV0T4Vàín½EHjÜ€LuÀ¨À¨ Ð546öòþ_sip_udpsip cybercitydk!üÉB°ôççàín½0T4VEÙ@7ŠTÔò!#À¨ÄÄÅ'QSIP/2.0 403 Wrong password or domain Allow: UPDATE,REFER Call-ID: 85216695-42dcdb1d@192.168.1.2 Contact: CSeq: 2 INVITE From: "arik" ;tag=51449dc Server: Cirpack/v4.38e (gw_sip) To: ;tag=00-04071-1701b4ad-52a186e31 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp83260863-46304c10192.168.1.2 Content-Length: 0 üÉBÜÂyy0T4Vàín½EkjÝ€åÀ¨Ôò!#ÄÄWu¯ACK sip:0097239287044@sip.cybercity.dk SIP/2.0 From: "arik" ;tag=51449dc Call-ID: 85216695-42dcdb1d@192.168.1.2 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp83260863-46304c10192.168.1.2;rport To: ;tag=00-04071-1701b4ad-52a186e31 CSeq: 2 ACK Content-Length: 0 üÉBVV0T4Vàín½EHjÞ€LsÀ¨À¨ Ð546öòþ_sip_udpsip cybercitydk!þÉB•VV0T4Vàín½EHj߀LrÀ¨À¨ Ð546öòþ_sip_udpsip cybercitydk!ÉBD'VV0T4Vàín½EHjà€LqÀ¨À¨ Ð546öòþ_sip_udpsip cybercitydk!ÉBô<VV0T4Vàín½EHjá€LpÀ¨À¨ Ð546öòþ_sip_udpsip cybercitydk! ÉBERR0T4Vàín½EDjâ€LsÀ¨À¨ Ñ50ùî*ÿ100127in-addrarpa  ÉBÞJiiàín½0T4VE[@@·>À¨À¨5 ÑGÜj*ÿ€100127in-addrarpa À ' localhost ÉBTO//0T4Vàín½E!jã€)À¨Ôò!#ÄÄ ÀK ÉBøVV0T4Vàín½EHjä€LmÀ¨À¨ Ò54)óÿÿ_sip_udpsip cybercitydk!ÉB¯öVV0T4Vàín½EHjå€LlÀ¨À¨ Ò54)óÿÿ_sip_udpsip cybercitydk!ÉB‹VV0T4Vàín½EHjæ€LkÀ¨À¨ Ò54)óÿÿ_sip_udpsip cybercitydk!ÉB VV0T4Vàín½EHjç€LjÀ¨À¨ Ò54)óÿÿ_sip_udpsip cybercitydk!ÉB­”\\ÿÿÿÿÿÿàín½ENjè€KeÀ¨À¨ÿ‰‰:[v…% EFEDEJFPEEEPENEBEJEOCACACACACABM  ÉB\Ä\\ÿÿÿÿÿÿàín½ENjé€KdÀ¨À¨ÿ‰‰:[v…% EFEDEJFPEEEPENEBEJEOCACACACACABM !ÉBø\\ÿÿÿÿÿÿàín½ENjê€KcÀ¨À¨ÿ‰‰:[v…% EFEDEJFPEEEPENEBEJEOCACACACACABM #ÉB&$VV0T4Vàín½EHjë€LfÀ¨À¨ Ò54)óÿÿ_sip_udpsip cybercitydk!+ÉB+RR0T4Vàín½EDjì€LiÀ¨À¨ Ó50' ýà100127in-addrarpa +ÉBé0iiàín½0T4VE[@@·>À¨À¨5 ÓG ‡ýà€100127in-addrarpa À ' localhost+ÉBg5//0T4Vàín½E!jí€À¨Ôò!#ÄÄ ÀK +ÉB6ø óóÿÿÿÿÿÿàín½Eåjî€JÈÀ¨À¨ÿŠŠÑ[-…'À¨Š» EEDADADCDEDGDFCACACACACACACACACA EFEDEJFPEEEPENEBEJEOCACACACACABNÿSMB%!è!V2\MAILSLOT\BROWSE€ü D002465Uª0ÉB£<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ0ÉBÕ**0T4Vàín½àín½À¨0T4VÀ¨7ÉBMmVV0T4Vàín½EHjï€LbÀ¨À¨ Ô54Œá_sip_udpsip cybercitydk!8ÉBçYVV0T4Vàín½EHjð€LaÀ¨À¨ Ô54Œá_sip_udpsip cybercitydk!:ÉB)eVV0T4Vàín½EHjñ€L`À¨À¨ Ô54Œá_sip_udpsip cybercitydk!<ÉBkpVV0T4Vàín½EHjò€L_À¨À¨ Ô54Œá_sip_udpsip cybercitydk!@ÉBÿ†VV0T4Vàín½EHjó€L^À¨À¨ Ô54Œá_sip_udpsip cybercitydk!HÉB¼ŽRR0T4Vàín½EDjô€LaÀ¨À¨ Õ50°tâ100127in-addrarpa HÉBw”iiàín½0T4VE[@@·>À¨À¨5 ÕG’ƒtâ€100127in-addrarpa À ' localhostHÉBH›//0T4Vàín½E!jõ€À¨Ôò!#ÄÄ ÀK NÉBåp \\ÿÿÿÿÿÿàín½ENjö€KWÀ¨À¨ÿ‰‰:[q…* EFEDEJFPEEEPENEBEJEOCACACACACABM OÉBÈž \\ÿÿÿÿÿÿàín½ENj÷€KVÀ¨À¨ÿ‰‰:[q…* EFEDEJFPEEEPENEBEJEOCACACACACABM PÉBÏÒ\\ÿÿÿÿÿÿàín½ENjø€KUÀ¨À¨ÿ‰‰:[q…* EFEDEJFPEEEPENEBEJEOCACACACACABM TÉB/îVV0T4Vàín½EHjù€LXÀ¨À¨ Ö54W Òâ_sip_udpsip cybercitydk!UÉBþÕVV0T4Vàín½EHjú€LWÀ¨À¨ Ö54W Òâ_sip_udpsip cybercitydk!WÉBDáVV0T4Vàín½EHjû€LVÀ¨À¨ Ö54W Òâ_sip_udpsip cybercitydk!YÉBgìVV0T4Vàín½EHjü€LUÀ¨À¨ Ö54W Òâ_sip_udpsip cybercitydk!]ÉBP VV0T4Vàín½EHjý€LTÀ¨À¨ Ö54W Òâ_sip_udpsip cybercitydk!eÉBZ RR0T4Vàín½EDjþ€LWÀ¨À¨ ×50zªâ100127in-addrarpa eÉB0 iiàín½0T4VE[@@·>À¨À¨5 ×G\ªâ€100127in-addrarpa À ' localhosteÉB­ //0T4Vàín½E!jÿ€ À¨Ôò!#ÄÄ ÀK qÉB£e VV0T4Vàín½EHk€LMÀ¨À¨ Ø54û .ã_sip_udpsip cybercitydk!rÉB¶R VV0T4Vàín½EHk€LLÀ¨À¨ Ø54û .ã_sip_udpsip cybercitydk!tÉBt] VV0T4Vàín½EHk€LKÀ¨À¨ Ø54û .ã_sip_udpsip cybercitydk!vÉBki VV0T4Vàín½EHk €LFÀ¨À¨ Ø54û .ã_sip_udpsip cybercitydk!zÉBî~ VV0T4Vàín½EHk €L1À¨À¨ Ø54û .ã_sip_udpsip cybercitydk!~ÉB$X\\ÿÿÿÿÿÿàín½ENk:€KÀ¨À¨ÿ‰‰:[l…/ EFEDEJFPEEEPENEBEJEOCACACACACABM ~ÉBTÇ\\ÿÿÿÿÿÿàín½ENk;€KÀ¨À¨ÿ‰‰:[l…/ EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBøú \\ÿÿÿÿÿÿàín½ENk<€KÀ¨À¨ÿ‰‰:[l…/ EFEDEJFPEEEPENEBEJEOCACACACACABM ‚ÉBV† RR0T4Vàín½EDk=€LÀ¨À¨ Þ50ÔüOä100127in-addrarpa ‚ÉB™Œ iiàín½0T4VE[@@·>À¨À¨5 ÞG·xOä€100127in-addrarpa À ' localhost‚ÉB½‘ //0T4Vàín½E!k>€ÎÀ¨Ôò!#ÄÄ ÀK ‡ÉB‡‹ <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ù͇ÉB¸‹ **0T4Vàín½àín½À¨0T4VÀ¨ŽÉBfá VV0T4Vàín½EHkJ€LÀ¨À¨ ß54àIä_sip_udpsip cybercitydk!ÉBéÏ VV0T4Vàín½EHkK€LÀ¨À¨ ß54àIä_sip_udpsip cybercitydk!‘ÉBFÙ VV0T4Vàín½EHkL€LÀ¨À¨ ß54àIä_sip_udpsip cybercitydk!“ÉB ä VV0T4Vàín½EHkM€LÀ¨À¨ ß54àIä_sip_udpsip cybercitydk!—ÉBìú VV0T4Vàín½EHkN€LÀ¨À¨ ß54àIä_sip_udpsip cybercitydk!ŸÉB¨ RR0T4Vàín½EDkO€LÀ¨À¨ à50†ùå100127in-addrarpa ŸÉBh iiàín½0T4VE[@@·>À¨À¨5 àGiuå€100127in-addrarpa À ' localhostŸÉBÒ //0T4Vàín½E!kP€¼À¨Ôò!#ÄÄ ÀK §ÉB¨-VV0T4Vàín½EHkQ€LÀ¨À¨ á54þ(æ_sip_udpsip cybercitydk!¨ÉBÂVV0T4Vàín½EHkR€KÿÀ¨À¨ á54þ(æ_sip_udpsip cybercitydk!ªÉBƒ%VV0T4Vàín½EHkS€KþÀ¨À¨ á54þ(æ_sip_udpsip cybercitydk!¬ÉBí0VV0T4Vàín½EHkT€KýÀ¨À¨ á54þ(æ_sip_udpsip cybercitydk!®ÉB;×\\ÿÿÿÿÿÿàín½ENkU€JøÀ¨À¨ÿ‰‰:[i…2 EFEDEJFPEEEPENEBEJEOCACACACACABM ¯ÉBü\\ÿÿÿÿÿÿàín½ENkV€J÷À¨À¨ÿ‰‰:[i…2 EFEDEJFPEEEPENEBEJEOCACACACACABM ¯ÉBåz\\ÿÿÿÿÿÿàín½ENkW€JöÀ¨À¨ÿ‰‰:[i…2 EFEDEJFPEEEPENEBEJEOCACACACACABM °ÉB)GVV0T4Vàín½EHkX€KùÀ¨À¨ á54þ(æ_sip_udpsip cybercitydk!¸ÉBœNRR0T4Vàín½EDkY€KüÀ¨À¨ â50@õãç100127in-addrarpa ¸ÉB]Tiiàín½0T4VE[@@·>À¨À¨5 âG#qãç€100127in-addrarpa À ' localhost¸ÉBZàà0T4Vàín½EÒkZ€À¨Ôò!#ÄľÖïREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp62913665-430aa2da192.168.1.2;rport From: ;tag=3bffccc To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=0;q=0.750 Expires: 0 CSeq: 76 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ¸ÉBæ^àín½0T4VE@7Š,Ôò!#À¨ÄÄíÍáSIP/2.0 401 Unauthorized Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 76 REGISTER From: ;tag=3bffccc To: ;tag=00-04090-1701b651-15c238ce6 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp62913665-430aa2da192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b63914805cd2139536c00323d58",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ¸ÉBvÔVV0T4Vàín½EHk[€KöÀ¨À¨ ã54ôù4è_sip_udpsip cybercitydk!¹ÉBÓVV0T4Vàín½EHk\€KõÀ¨À¨ ã54ôù4è_sip_udpsip cybercitydk!»ÉB áVV0T4Vàín½EHk]€KôÀ¨À¨ ã54ôù4è_sip_udpsip cybercitydk!½ÉB‰éVV0T4Vàín½EHk^€KóÀ¨À¨ ã54ôù4è_sip_udpsip cybercitydk!ÁÉBVV0T4Vàín½EHk_€KòÀ¨À¨ ã54ôù4è_sip_udpsip cybercitydk!ÉÉB[RR0T4Vàín½EDk`€KõÀ¨À¨ ä50¹ñjé100127in-addrarpa ÉÉBB iiàín½0T4VE[@@·>À¨À¨5 äGœmjé€100127in-addrarpa À ' localhostÉÉBQËË0T4Vàín½E½ka€À¨Ôò!#ÄÄ©]REGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp61178202-452852a6192.168.1.2;rport From: ;tag=3a58141 To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=0;q=0.500 Expires: 0 CSeq: 77 REGISTER Content-Length: 0 Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b63914805cd2139536c00323d58",opaque="1701a1351f70795",nc="00000001",response="d973fd6f5ae1ac5accaff93cd603c1b5" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ÉÉBŸ¢ VV0T4Vàín½EHkb€KïÀ¨À¨ å54±õwê_sip_udpsip cybercitydk!ÉÉB;tag=3a58141 To: ;tag=00-04089-1701b683-18ec171b5 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp61178202-452852a6192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b6784feeadb2410d11d8053d2a5",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ÊÉBª’ VV0T4Vàín½EHkc€KîÀ¨À¨ å54±õwê_sip_udpsip cybercitydk!ÌÉBï VV0T4Vàín½EHkd€KíÀ¨À¨ å54±õwê_sip_udpsip cybercitydk!ÎÉBÒ<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍÎÉB**0T4Vàín½àín½À¨0T4VÀ¨ÎÉBeª VV0T4Vàín½EHke€KìÀ¨À¨ å54±õwê_sip_udpsip cybercitydk!ÒÉB¿ VV0T4Vàín½EHkf€KëÀ¨À¨ å54±õwê_sip_udpsip cybercitydk!ÚÉBCÇ RR0T4Vàín½EDkg€KîÀ¨À¨ æ50Áíbë100127in-addrarpa ÚÉBÍ iiàín½0T4VE[@@·>À¨À¨5 æG¤ibë€100127in-addrarpa À ' localhostÚÉBîÒ üü0T4Vàín½Eîkh€×À¨Ôò!#ÄÄÚ5þREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp61001873-43beb0a5192.168.1.2;rport From: ;tag=3a2d0dc To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 78 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ÚÉBpñ àín½0T4VE@7Š,Ôò!#À¨ÄÄíšSIP/2.0 401 Unauthorized Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 78 REGISTER From: ;tag=3a2d0dc To: ;tag=00-04077-1701b6ab-13935c834 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp61001873-43beb0a5192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b69b47b51c6d66c9e4503c679c2",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ÛÉB¾£VV0T4Vàín½EHki€KèÀ¨À¨ ç54¦ò‚ë_sip_udpsip cybercitydk!ÜÉB²¥VV0T4Vàín½EHkj€KçÀ¨À¨ ç54¦ò‚ë_sip_udpsip cybercitydk!ÞÉBó°VV0T4Vàín½EHkk€KæÀ¨À¨ ç54¦ò‚ë_sip_udpsip cybercitydk!ÞÉBæñ\\ÿÿÿÿÿÿàín½ENkl€JáÀ¨À¨ÿ‰‰:[d…7 EFEDEJFPEEEPENEBEJEOCACACACACABM ÞÉB§_ \\ÿÿÿÿÿÿàín½ENkm€JàÀ¨À¨ÿ‰‰:[d…7 EFEDEJFPEEEPENEBEJEOCACACACACABM ßÉB]“ \\ÿÿÿÿÿÿàín½ENkn€JßÀ¨À¨ÿ‰‰:[d…7 EFEDEJFPEEEPENEBEJEOCACACACACABM àÉB3¼VV0T4Vàín½EHko€KâÀ¨À¨ ç54¦ò‚ë_sip_udpsip cybercitydk!åÉBGáVV0T4Vàín½EHkt€KÝÀ¨À¨ ç54¦ò‚ë_sip_udpsip cybercitydk!íÉB`ÕRR0T4Vàín½EDku€KàÀ¨À¨ è50ãê@ì100127in-addrarpa íÉB6Ûiiàín½0T4VE[@@·>À¨À¨5 èGÆf@ì€100127in-addrarpa À ' localhostíÉBNáÑÑ0T4Vàín½EÃkv€ôÀ¨Ôò!#Äį8ƒREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp57726197-4841c7cd192.168.1.2;rport From: ;tag=370d8e5 To: Call-ID: 578222729-4665d775@578222732-4665d772 Contact: ;expires=1200;q=0.500 Expires: 1200 CSeq: 79 REGISTER Content-Length: 0 Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b69b47b51c6d66c9e4503c679c2",opaque="1701a1351f70795",nc="00000001",response="e733a545cf353a92820b48c90153e59d" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 íÉBô& àín½0T4VE@7Š'Ôò!#À¨ÄÄòò—SIP/2.0 401 nonce has changed Call-ID: 578222729-4665d775@578222732-4665d772 CSeq: 79 REGISTER From: ;tag=370d8e5 To: ;tag=00-04083-1701b6dd-051f5dc31 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp57726197-4841c7cd192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b6cc1cbc90d328fe1f1a31a2c4e",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ÉBÞ?\\ÿÿÿÿÿÿàín½ENkw€JÖÀ¨À¨ÿ‰‰:[a…: EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBn\\ÿÿÿÿÿÿàín½ENkx€JÕÀ¨À¨ÿ‰‰:[a…: EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBã\\ÿÿÿÿÿÿàín½ENky€JÔÀ¨À¨ÿ‰‰:[a…: EFEDEJFPEEEPENEBEJEOCACACACACABM <ÉBó \\ÿÿÿÿÿÿàín½ENkz€JÓÀ¨À¨ÿ‰‰:[^…= EFEDEJFPEEEPENEBEJEOCACACACACABM =ÉB^ \\ÿÿÿÿÿÿàín½ENk{€JÒÀ¨À¨ÿ‰‰:[^…= EFEDEJFPEEEPENEBEJEOCACACACACABM >ÉBT\\ÿÿÿÿÿÿàín½ENk|€JÑÀ¨À¨ÿ‰‰:[^…= EFEDEJFPEEEPENEBEJEOCACACACACABM lÉB\Æ\\ÿÿÿÿÿÿàín½ENk€JÌÀ¨À¨ÿ‰‰:[Y…B EFEDEJFPEEEPENEBEJEOCACACACACABM lÉB7 \\ÿÿÿÿÿÿàín½ENk‚€JËÀ¨À¨ÿ‰‰:[Y…B EFEDEJFPEEEPENEBEJEOCACACACACABM mÉBÉj\\ÿÿÿÿÿÿàín½ENkƒ€JÊÀ¨À¨ÿ‰‰:[Y…B EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBPW ØØÿÿÿÿÿÿ`—îrEÊ\¿€XëÀ¨)À¨ÿŠŠ¶_±‘MÀ¨)Š  EMEBECDBDBDBCACACACACACACACACAAA FHEPFCELEHFCEPFFFACACACACACACABNÿSMB%èV\MAILSLOT\BROWSE ØÉB}W \\ÿÿÿÿÿÿ`—îrEN\À€YfÀ¨)À¨ÿ‰‰:h#‘O FHEPFCELEHFCEPFFFACACACACACACABL ‚ÉBÃ\\ÿÿÿÿÿÿ`—îrEN\Á€YeÀ¨)À¨ÿ‰‰:h#‘O FHEPFCELEHFCEPFFFACACACACACACABL ƒÉBl³\\ÿÿÿÿÿÿ`—îrEN\€YdÀ¨)À¨ÿ‰‰:h#‘O FHEPFCELEHFCEPFFFACACACACACACABL †ÉB}òØØÿÿÿÿÿÿ`—îrEÊ\ÀXçÀ¨)À¨ÿŠŠ¶_®‘PÀ¨)Š  EMEBECDBDBDBCACACACACACACACACAAA FHEPFCELEHFCEPFFFACACACACACACABNÿSMB%èV\MAILSLOT\BROWSE ؆ÉBó\\ÿÿÿÿÿÿ`—îrEN\Ä€YbÀ¨)À¨ÿ‰‰:h ‘R FHEPFCELEHFCEPFFFACACACACACACABL †ÉBug \\ÿÿÿÿÿÿ`—îrEN\Å€YaÀ¨)À¨ÿ‰‰:h ‘R FHEPFCELEHFCEPFFFACACACACACACABL ‡ÉBΚ\\ÿÿÿÿÿÿ`—îrEN\Æ€Y`À¨)À¨ÿ‰‰:h ‘R FHEPFCELEHFCEPFFFACACACACACACABL ŠÉBôÙØØÿÿÿÿÿÿ`—îrEÊ\Ç€XãÀ¨)À¨ÿŠŠ¶_«‘SÀ¨)Š  EMEBECDBDBDBCACACACACACACACACAAA FHEPFCELEHFCEPFFFACACACACACACABNÿSMB%èV\MAILSLOT\BROWSE ØŠÉBwÚ\\ÿÿÿÿÿÿ`—îrEN\È€Y^À¨)À¨ÿ‰‰:h‘U FHEPFCELEHFCEPFFFACACACACACACABL ‹ÉBÞ \\ÿÿÿÿÿÿ`—îrEN\É€Y]À¨)À¨ÿ‰‰:h‘U FHEPFCELEHFCEPFFFACACACACACACABL ‹ÉBt‚ \\ÿÿÿÿÿÿ`—îrEN\Ê€Y\À¨)À¨ÿ‰‰:h‘U FHEPFCELEHFCEPFFFACACACACACACABL ŽÉBÁ\\ÿÿÿÿÿÿ`—îrEN\Ë€Y[À¨)À¨ÿ‰‰:e‘W FHEPFCELEHFCEPFFFACACACACACACABO ÉBSô\\ÿÿÿÿÿÿ`—îrEN\Ì€YZÀ¨)À¨ÿ‰‰:e‘W FHEPFCELEHFCEPFFFACACACACACACABO ÉBÎ'\\ÿÿÿÿÿÿ`—îrEN\Í€YYÀ¨)À¨ÿ‰‰:e‘W FHEPFCELEHFCEPFFFACACACACACACABO œÉBÒ­\\ÿÿÿÿÿÿàín½ENk„€JÉÀ¨À¨ÿ‰‰:[V…E EFEDEJFPEEEPENEBEJEOCACACACACABM œÉB \\ÿÿÿÿÿÿàín½ENk…€JÈÀ¨À¨ÿ‰‰:[V…E EFEDEJFPEEEPENEBEJEOCACACACACABM ÉB²Q \\ÿÿÿÿÿÿàín½ENk†€JÇÀ¨À¨ÿ‰‰:[V…E EFEDEJFPEEEPENEBEJEOCACACACACABM ½ÉB1**ÿÿÿÿÿÿàín½àín½À¨À¨½ÉB€3<<àín½0T4V0T4VÀ¨àín½À¨ˆdö7 À! Ï;ùͽÉBš3VV0T4Vàín½EHk‡€JÊÀ¨À¨DC4‘m 8À¨àín½c‚Sc5=àín½ d002465Q d002465.<MSFT 5.07 ,./!+ÿ½ÉB:NNàín½0T4VE@@õYÀ¨À¨CD,ž•m 8À¨À¨àín½c‚Sc56À¨3 d002465ÿÿÿÀ¨À¨ÿÁÉB÷ óóÿÿÿÿÿÿ`—îrEå\΀XÁÀ¨)À¨ÿŠŠÑ‡«‘XÀ¨)Š» EMEBECDBDBDBCACACACACACACACACACA FHEPFCELEHFCEPFFFACACACACACACABNÿSMB%!è!V2\MAILSLOT\BROWSE€ü LAB111UªÌÉBó\\ÿÿÿÿÿÿàín½ENkˆ€JÅÀ¨À¨ÿ‰‰:[O…L EFEDEJFPEEEPENEBEJEOCACACACACABM ÍÉB4\\ÿÿÿÿÿÿàín½ENk‰€JÄÀ¨À¨ÿ‰‰:[O…L EFEDEJFPEEEPENEBEJEOCACACACACABM ÍÉB|ª \\ÿÿÿÿÿÿàín½ENkŠ€JÃÀ¨À¨ÿ‰‰:[O…L EFEDEJFPEEEPENEBEJEOCACACACACABM ìÉBEK LL0T4Vàín½E>k€KÌÀ¨À¨ é5*…3èìregsippstarcomíÉBDP LL0T4Vàín½E>k€KËÀ¨À¨ é5*…3èìregsippstarcomïÉB[ LL0T4Vàín½E>k‘€KÊÀ¨À¨ é5*…3èìregsippstarcomðÉBXn©©àín½0T4VE›@@¶þÀ¨À¨5 釮Eèì€regsippstarcomÀ XRbÑ'ÀXnshspeednetÀXns3ÀAÀ>>]À;ÀYÕÝRõÉBZh<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍõÉBŒh**0T4Vàín½àín½À¨0T4VÀ¨öÉB½LL0T4Vàín½E>k’€KÉÀ¨À¨ ê5*xÓ\îsip cybercitydk÷ÉBÜÂLL0T4Vàín½E>k“€KÈÀ¨À¨ ë5*òÐâïsip cybercitydk÷ÉBéùLL0T4Vàín½E>k”€KÇÀ¨À¨ ê5*xÓ\îsip cybercitydkøÉB­ÆLL0T4Vàín½E>k•€KÆÀ¨À¨ ë5*òÐâïsip cybercitydkùÉBDLL0T4Vàín½E>k–€KÅÀ¨À¨ ê5*xÓ\îsip cybercitydkúÉBÊÑLL0T4Vàín½E>k—€KÄÀ¨À¨ ë5*òÐâïsip cybercitydkûÉBbLL0T4Vàín½E>k˜€KÃÀ¨À¨ ê5*xÓ\îsip cybercitydkûÉBß9€€àín½0T4VEr@@·'À¨À¨5 ë^Ê£âï€sip cybercitydkÀ ,Ôò!#À,ns1ÀÀ,ns2ÀûÉB_A€€àín½0T4VEr@@·'À¨À¨5 ê^P¦\î€sip cybercitydkÀ ,Ôò!#À,ns2ÀÀ,ns1ÀûÉBjnVV0T4Vàín½EHk™€K¸À¨À¨ ì54ÖÇS_sip_udpsip cybercitydk!üÉBVu VV0T4Vàín½EHkš€K·À¨À¨ ì54ÖÇS_sip_udpsip cybercitydk!üÉB;3 \\ÿÿÿÿÿÿàín½ENk›€J²À¨À¨ÿ‰‰:[L…O EFEDEJFPEEEPENEBEJEOCACACACACABM ýÉB"J \\ÿÿÿÿÿÿàín½ENkœ€J±À¨À¨ÿ‰‰:[L…O EFEDEJFPEEEPENEBEJEOCACACACACABM þÉBÌ}\\ÿÿÿÿÿÿàín½ENk€J°À¨À¨ÿ‰‰:[L…O EFEDEJFPEEEPENEBEJEOCACACACACABM þÉBK VV0T4Vàín½EHkž€K³À¨À¨ ì54ÖÇS_sip_udpsip cybercitydk!ÉBÈ& VV0T4Vàín½EHkŸ€K²À¨À¨ ì54ÖÇS_sip_udpsip cybercitydk!ÉBRN VV0T4Vàín½EHk €K±À¨À¨ ì54ÖÇS_sip_udpsip cybercitydk! ÉBo9 RR0T4Vàín½EDk¡€K´À¨À¨ í50Y¿Ë100127in-addrarpa  ÉB*? iiàín½0T4VE[@@·>À¨À¨5 íG<;Ë€100127in-addrarpa À ' localhost ÉB“E üü0T4Vàín½Eîk¢€À¨Ôò!#ÄÄÚ,REGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp28874686-455dbbd9192.168.1.2;rport From: ;tag=1b89bcd To: Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel ;expires=1200;q=0.500 Expires: 1200 CSeq: 1 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ÉB'\  àín½0T4VEþ@7Š/Ôò!#À¨ÄÄêê2SIP/2.0 401 Unauthorized Call-ID: 29858147-465b0752@29858051-465b07b2 CSeq: 1 REGISTER From: ;tag=1b89bcd To: ;tag=00-04072-1701b941-779945843 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp28874686-455dbbd9192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b9333e87132e7f747c507263d93",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ÉB¿¡VV0T4Vàín½EHk£€K®À¨À¨ î54òÃ7_sip_udpsip cybercitydk!ÉB¸¢VV0T4Vàín½EHk¤€K­À¨À¨ î54òÃ7_sip_udpsip cybercitydk!ÉB®VV0T4Vàín½EHk¥€K¬À¨À¨ î54òÃ7_sip_udpsip cybercitydk!ÉBN¹VV0T4Vàín½EHk¦€K«À¨À¨ î54òÃ7_sip_udpsip cybercitydk!ÉB¯ÏVV0T4Vàín½EHk§€KªÀ¨À¨ î54òÃ7_sip_udpsip cybercitydk!ÉBî×RR0T4Vàín½EDk¨€K­À¨À¨ ï50¼100127in-addrarpa ÉBÞiiàín½0T4VE[@@·>À¨À¨5 ïGë7€100127in-addrarpa À ' localhostÉBdäÑÑ0T4Vàín½EÃk©€ÁÀ¨Ôò!#ÄįRÖREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp27111175-4330c9d6192.168.1.2;rport From: ;tag=19db316 To: Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel ;expires=1200;q=0.500 Expires: 1200 CSeq: 2 REGISTER Content-Length: 0 Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b9333e87132e7f747c507263d93",opaque="1701a1351f70795",nc="00000001",response="0df96eb528bb630a16fd0252618cf3cb" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ÉBÃVV0T4Vàín½EHkª€K§À¨À¨ ð541¿ø_sip_udpsip cybercitydk!ÉB+"XXàín½0T4VEJ@7ŠãÔò!#À¨ÄÄ6ûŸSIP/2.0 100 Trying Call-ID: 29858147-465b0752@29858051-465b07b2 CSeq: 2 REGISTER From: ;tag=19db316 To: Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp27111175-4330c9d6192.168.1.2 Content-Length: 0 ÉB Vÿÿàín½0T4VEñ@7Š<Ôò!#À¨ÄÄÝ\ëSIP/2.0 200 OK Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel;q=0.500;expires=1200 CSeq: 2 REGISTER From: ;tag=19db316 P-Associated-URI: To: ;tag=00-04095-1701b95f-5bde7e420 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp27111175-4330c9d6192.168.1.2 Content-Length: 0 ÉBC VV0T4Vàín½EHk«€K¦À¨À¨ ð541¿ø_sip_udpsip cybercitydk!!ÉB·ôVV0T4Vàín½EHk¬€K¥À¨À¨ ð541¿ø_sip_udpsip cybercitydk!#ÉB VV0T4Vàín½EHk­€K¤À¨À¨ ð541¿ø_sip_udpsip cybercitydk!'ÉBHVV0T4Vàín½EHk®€K£À¨À¨ ð541¿ø_sip_udpsip cybercitydk!,ÉBG \\ÿÿÿÿÿÿàín½ENk¯€JžÀ¨À¨ÿ‰‰:[I…R EFEDEJFPEEEPENEBEJEOCACACACACABM -ÉB½I\\ÿÿÿÿÿÿàín½ENk°€JÀ¨À¨ÿ‰‰:[I…R EFEDEJFPEEEPENEBEJEOCACACACACABM .ÉBe}\\ÿÿÿÿÿÿàín½ENk±€JœÀ¨À¨ÿ‰‰:[I…R EFEDEJFPEEEPENEBEJEOCACACACACABM /ÉBãRR0T4Vàín½EDk²€K£À¨À¨ ñ50ª¶z100127in-addrarpa /ÉBÃ#iiàín½0T4VE[@@·>À¨À¨5 ñG2z€100127in-addrarpa À ' localhost/ÉBç)üü0T4Vàín½Eîk³€ŒÀ¨Ôò!#ÄÄÚƒ¸REGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp26936945-479e83f1192.168.1.2;rport From: ;tag=19b0614 To: Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel ;expires=1200;q=0.500 Expires: 1200 CSeq: 3 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 /ÉB¸ßVV0T4Vàín½EHk´€KÀ¨À¨ ò54¼_sip_udpsip cybercitydk!/ÉBÙ>  àín½0T4VEþ@7Š/Ôò!#À¨ÄÄêÉSIP/2.0 401 Unauthorized Call-ID: 29858147-465b0752@29858051-465b07b2 CSeq: 3 REGISTER From: ;tag=19b0614 To: ;tag=00-04095-1701b970-463ba6b36 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp26936945-479e83f1192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b96c474e0c4b5dcd407f27bdde2",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 0ÉBÂÐVV0T4Vàín½EHkµ€KœÀ¨À¨ ò54¼_sip_udpsip cybercitydk!2ÉBsÜVV0T4Vàín½EHk¶€K›À¨À¨ ò54¼_sip_udpsip cybercitydk!4ÉBw<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ4ÉB¨**0T4Vàín½àín½À¨0T4VÀ¨4ÉB÷æVV0T4Vàín½EHk·€KšÀ¨À¨ ò54¼_sip_udpsip cybercitydk!8ÉB1ýVV0T4Vàín½EHk¸€K™À¨À¨ ò54¼_sip_udpsip cybercitydk!@ÉBXRR0T4Vàín½EDk¹€KœÀ¨À¨ ó50ɲ[100127in-addrarpa @ÉB€ iiàín½0T4VE[@@·>À¨À¨5 óG¬.[€100127in-addrarpa À ' localhost@ÉBÁcc0T4Vàín½EUkº€À¨Ôò!#ÄÄAZèINVITE sip:0097239287044@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp24466402-45dc61d5192.168.1.2;rport From: "arik" ;tag=175a1dd To: Call-ID: 24487391-449bf2a0@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 270 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 24466422 24466418 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv @ÉB=Ò VV0T4Vàín½EHk»€K–À¨À¨ ô54ê·?_sip_udpsip cybercitydk!@ÉB®k {{àín½0T4VEm@7‰ÀÔò!#À¨ÄÄYSIP/2.0 407 authentication required Allow: UPDATE,REFER Call-ID: 24487391-449bf2a0@192.168.1.2 Contact: CSeq: 1 INVITE From: "arik" ;tag=175a1dd Proxy-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b97b4eb6c66d64d0b20f5a0bef8",opaque="1701a1351f70795",stale=false,algorithm=MD5 Server: Cirpack/v4.38e (gw_sip) To: ;tag=00-04095-1701b9a0-13c92a672 Via: SIP/2.0/UDP 192.168.1.2:5060;received=80.230.219.70;rport=5060;branch=z9hG4bKnp24466402-45dc61d5192.168.1.2 Content-Length: 0 @ÉB { ~~0T4Vàín½Epk¼€À¨Ôò!#ÄÄ\ÃACK sip:0097239287044@sip.cybercity.dk SIP/2.0 From: "arik" ;tag=175a1dd Call-ID: 24487391-449bf2a0@192.168.1.2 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp24466402-45dc61d5192.168.1.2;rport To: ;tag=00-04095-1701b9a0-13c92a672 CSeq: 1 ACK Content-Length: 0 AÉBô¶ VV0T4Vàín½EHk½€K”À¨À¨ ô54ê·?_sip_udpsip cybercitydk!CÉB VV0T4Vàín½EHk¾€K“À¨À¨ ô54ê·?_sip_udpsip cybercitydk!EÉBuÍ VV0T4Vàín½EHk¿€K’À¨À¨ ô54ê·?_sip_udpsip cybercitydk!IÉBWä VV0T4Vàín½EHkÄ€KÀ¨À¨ ô54ê·?_sip_udpsip cybercitydk!QÉBië RR0T4Vàín½EDkÅ€KÀ¨À¨ õ50U¯Ï100127in-addrarpa QÉBQñ iiàín½0T4VE[@@·>À¨À¨5 õG8+Ï€100127in-addrarpa À ' localhostQÉBª÷ ÑÑ0T4Vàín½EÃkÆ€¤À¨Ôò!#ÄįœREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp23652235-46b50e7c192.168.1.2;rport From: ;tag=168e795 To: Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel ;expires=1200;q=0.500 Expires: 1200 CSeq: 4 REGISTER Content-Length: 0 Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b96c474e0c4b5dcd407f27bdde2",opaque="1701a1351f70795",nc="00000001",response="9e65b34f9156b9f55d83ac1bcd84ba57" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 QÉB{ß VV0T4Vàín½EHkÇ€KŠÀ¨À¨ ö54§³‚_sip_udpsip cybercitydk!QÉB¼G àín½0T4VE@7Š*Ôò!#À¨ÄÄï¹SIP/2.0 401 nonce has changed Call-ID: 29858147-465b0752@29858051-465b07b2 CSeq: 4 REGISTER From: ;tag=168e795 To: ;tag=00-04085-1701b9c9-48e7b0863 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp23652235-46b50e7c192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701b9c069173a215e356e3017b179d",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 RÉBoÛ VV0T4Vàín½EHkÈ€K‰À¨À¨ ö54§³‚_sip_udpsip cybercitydk!TÉB,æ VV0T4Vàín½EHkÉ€KˆÀ¨À¨ ö54§³‚_sip_udpsip cybercitydk!VÉBlñ VV0T4Vàín½EHkÊ€K‡À¨À¨ ö54§³‚_sip_udpsip cybercitydk!ZÉB· VV0T4Vàín½EHkË€K†À¨À¨ ö54§³‚_sip_udpsip cybercitydk![ÉBl2\\ÿÿÿÿÿÿàín½ENkÌ€JÀ¨À¨ÿ‰‰:[D…W EFEDEJFPEEEPENEBEJEOCACACACACABM \ÉB‚` \\ÿÿÿÿÿÿàín½ENkÍ€J€À¨À¨ÿ‰‰:[D…W EFEDEJFPEEEPENEBEJEOCACACACACABM ]ÉB.”\\ÿÿÿÿÿÿàín½ENk΀JÀ¨À¨ÿ‰‰:[D…W EFEDEJFPEEEPENEBEJEOCACACACACABM bÉBÏ RR0T4Vàín½EDkÏ€K†À¨À¨ ÷50q«³100127in-addrarpa bÉB« iiàín½0T4VE[@@·>À¨À¨5 ÷GT'³€100127in-addrarpa À ' localhostbÉBž //0T4Vàín½E!kЀ<À¨Ôò!#ÄÄ ÀK bÉBÙê VV0T4Vàín½EHkÑ€K€À¨À¨ ø54>®ë_sip_udpsip cybercitydk!cÉB4è VV0T4Vàín½EHkÒ€KÀ¨À¨ ø54>®ë_sip_udpsip cybercitydk!eÉBâó VV0T4Vàín½EHkÓ€K~À¨À¨ ø54>®ë_sip_udpsip cybercitydk!gÉBÕþ VV0T4Vàín½EHkÔ€K}À¨À¨ ø54>®ë_sip_udpsip cybercitydk!kÉB" VV0T4Vàín½EHkÕ€K|À¨À¨ ø54>®ë_sip_udpsip cybercitydk!sÉBO RR0T4Vàín½EDkÖ€KÀ¨À¨ ù50¨Å|100127in-addrarpa sÉB/$ iiàín½0T4VE[@@·>À¨À¨5 ùG‹A|€100127in-addrarpa À ' localhostsÉBª* ^^0T4Vàín½EPk×€À¨Ôò!#ÄÄ<~°INVITE sip:0097239287044@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp20238275-478927ba192.168.1.2;rport From: "arik" ;tag=175a1dd To: Call-ID: 24487391-449bf2a0@192.168.1.2 CSeq: 2 INVITE Proxy-Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b97b4eb6c66d64d0b20f5a0bef8",opaque="1701a1351f70795",nc="00000001",response="0b7990bb21d5572d6571e97b98c6d70f" Content-Type: application/sdp Content-Length: 270 Date: Mon, 04 Jul 2005 09:54:25 GMT Contact: Expires: 120 Accept: application/sdp Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 24466422 24466418 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv sÉBú2 VV0T4Vàín½EHkØ€KyÀ¨À¨ ú549Éð_sip_udpsip cybercitydk!tÉBÒµµàín½0T4VE§@7ІÔò!#À¨ÄÄ“–³SIP/2.0 100 Trying Allow: UPDATE,REFER Call-ID: 24487391-449bf2a0@192.168.1.2 Contact: CSeq: 2 INVITE From: "arik" ;tag=175a1dd Server: Cirpack/v4.38e (gw_sip) To: Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp20238275-478927ba192.168.1.2 Content-Length: 0 tÉB§Ýççàín½0T4VEÙ@7ŠTÔò!#À¨ÄÄÅÂTSIP/2.0 403 Wrong password or domain Allow: UPDATE,REFER Call-ID: 24487391-449bf2a0@192.168.1.2 Contact: CSeq: 2 INVITE From: "arik" ;tag=175a1dd Server: Cirpack/v4.38e (gw_sip) To: ;tag=00-04083-1701ba17-57d493ef5 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp20238275-478927ba192.168.1.2 Content-Length: 0 tÉBŒìyy0T4Vàín½EkkÙ€éÀ¨Ôò!#ÄÄW6ACK sip:0097239287044@sip.cybercity.dk SIP/2.0 From: "arik" ;tag=175a1dd Call-ID: 24487391-449bf2a0@192.168.1.2 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp20238275-478927ba192.168.1.2;rport To: ;tag=00-04083-1701ba17-57d493ef5 CSeq: 2 ACK Content-Length: 0 tÉB¶ VV0T4Vàín½EHkÚ€KwÀ¨À¨ ú549Éð_sip_udpsip cybercitydk!vÉB, VV0T4Vàín½EHkÛ€KvÀ¨À¨ ú549Éð_sip_udpsip cybercitydk!xÉB> <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍxÉBp **0T4Vàín½àín½À¨0T4VÀ¨xÉB&7 VV0T4Vàín½EHkÜ€KuÀ¨À¨ ú549Éð_sip_udpsip cybercitydk!|ÉB O VV0T4Vàín½EHkÝ€KtÀ¨À¨ ú549Éð_sip_udpsip cybercitydk!„ÉBùT RR0T4Vàín½EDkÞ€KwÀ¨À¨ û50ÌÁX100127in-addrarpa „ÉBÌZ iiàín½0T4VE[@@·>À¨À¨5 ûG¯=X€100127in-addrarpa À ' localhost„ÉB¯_ //0T4Vàín½E!k߀-À¨Ôò!#ÄÄ ÀK ‹ÉBSÝ\\ÿÿÿÿÿÿàín½ENkà€JmÀ¨À¨ÿ‰‰:[A…Z EFEDEJFPEEEPENEBEJEOCACACACACABM ŒÉB\\ÿÿÿÿÿÿàín½ENká€JlÀ¨À¨ÿ‰‰:[A…Z EFEDEJFPEEEPENEBEJEOCACACACACABM ÉB¦:\\ÿÿÿÿÿÿàín½ENkâ€JkÀ¨À¨ÿ‰‰:[A…Z EFEDEJFPEEEPENEBEJEOCACACACACABM ¥ÉBr‡VV0T4Vàín½EHkã€KnÀ¨À¨ ü54ØÆQ_sip_udpsip cybercitydk!¦ÉBënVV0T4Vàín½EHkä€KmÀ¨À¨ ü54ØÆQ_sip_udpsip cybercitydk!¨ÉB/zVV0T4Vàín½EHkå€KlÀ¨À¨ ü54ØÆQ_sip_udpsip cybercitydk!ªÉBs…VV0T4Vàín½EHkæ€KkÀ¨À¨ ü54ØÆQ_sip_udpsip cybercitydk!®ÉBœVV0T4Vàín½EHkç€KjÀ¨À¨ ü54ØÆQ_sip_udpsip cybercitydk!¶ÉBï¹RR0T4Vàín½EDkè€KmÀ¨À¨ ý50„¾ 100127in-addrarpa ¶ÉBÖ¿iiàín½0T4VE[@@·>À¨À¨5 ýGg: €100127in-addrarpa À ' localhost¶ÉB ÆXX0T4Vàín½EJké€úÀ¨Ôò!#ÄÄ6Û%INVITE sip:35104724@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp11888298-448e3777192.168.1.2;rport From: "arik" ;tag=b56e6e To: Call-ID: 11894297-4432a9f8@192.168.1.2 CSeq: 1 INVITE User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Expires: 120 Accept: application/sdp Content-Type: application/sdp Content-Length: 270 Contact: Max-Forwards: 70 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 11888330 11888327 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv ¶ÉBö- uuàín½0T4VEg@7‰ÆÔò!#À¨ÄÄSëñSIP/2.0 407 authentication required Allow: UPDATE,REFER Call-ID: 11894297-4432a9f8@192.168.1.2 Contact: CSeq: 1 INVITE From: "arik" ;tag=b56e6e Proxy-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701ba6557c1e1b4223e887e293cfa8",opaque="1701a1351f70795",stale=false,algorithm=MD5 Server: Cirpack/v4.38e (gw_sip) To: ;tag=00-04079-1701ba6f-3e08e2f66 Via: SIP/2.0/UDP 192.168.1.2:5060;received=80.230.219.70;rport=5060;branch=z9hG4bKnp11888298-448e3777192.168.1.2 Content-Length: 0 ¶ÉBÖ@ ss0T4Vàín½Eekê€ÞÀ¨Ôò!#ÄÄQ·fACK sip:35104724@sip.cybercity.dk SIP/2.0 From: "arik" ;tag=b56e6e Call-ID: 11894297-4432a9f8@192.168.1.2 Via: SIP/2.0/UDP 192.168.1.2:5060;branch=z9hG4bKnp11888298-448e3777192.168.1.2;rport To: ;tag=00-04079-1701ba6f-3e08e2f66 CSeq: 1 ACK Content-Length: 0 ¶ÉB# VV0T4Vàín½EHkë€KfÀ¨À¨ þ54êÁ?_sip_udpsip cybercitydk!·ÉB:ë VV0T4Vàín½EHkì€KeÀ¨À¨ þ54êÁ?_sip_udpsip cybercitydk!¹ÉBö VV0T4Vàín½EHkí€KdÀ¨À¨ þ54êÁ?_sip_udpsip cybercitydk!»ÉB˜\\ÿÿÿÿÿÿàín½ENkî€J_À¨À¨ÿ‰‰:[<…_ EFEDEJFPEEEPENEBEJEOCACACACACABM »ÉBg¬<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ»ÉB™¬**0T4Vàín½àín½À¨0T4VÀ¨»ÉB;Œ \\ÿÿÿÿÿÿàín½ENkï€J^À¨À¨ÿ‰‰:[<…_ EFEDEJFPEEEPENEBEJEOCACACACACABM »ÉB¾ VV0T4Vàín½EHkð€KaÀ¨À¨ þ54êÁ?_sip_udpsip cybercitydk!¼ÉBâ¿\\ÿÿÿÿÿÿàín½ENkñ€J\À¨À¨ÿ‰‰:[<…_ EFEDEJFPEEEPENEBEJEOCACACACACABM ¿ÉB; VV0T4Vàín½EHkò€K_À¨À¨ þ54êÁ?_sip_udpsip cybercitydk!ÇÉB§ RR0T4Vàín½EDk÷€K^À¨À¨ ÿ50›º‰100127in-addrarpa ÇÉBŒ& iiàín½0T4VE[@@·>À¨À¨5 ÿG~6‰€100127in-addrarpa À ' localhostÇÉB- SS0T4Vàín½EEkø€ðÀ¨Ôò!#ÄÄ1ª INVITE sip:35104724@sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp10144774-4725f980192.168.1.2;rport From: "arik" ;tag=b56e6e To: Call-ID: 11894297-4432a9f8@192.168.1.2 CSeq: 2 INVITE Proxy-Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701ba6557c1e1b4223e887e293cfa8",opaque="1701a1351f70795",nc="00000001",response="83e1608f6d9ad38597ac6bbe4d3aafae" Content-Type: application/sdp Content-Length: 270 Date: Mon, 04 Jul 2005 09:56:06 GMT Contact: Expires: 120 Accept: application/sdp Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 Allow: INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO v=0 o=SIPPS 11888330 11888327 IN IP4 192.168.1.2 s=SIP call c=IN IP4 192.168.1.2 t=0 0 m=audio 30000 RTP/AVP 0 8 97 2 3 a=rtpmap:0 pcmu/8000 a=rtpmap:8 pcma/8000 a=rtpmap:97 iLBC/8000 a=rtpmap:2 G726-32/8000 a=rtpmap:3 GSM/8000 a=fmtp:97 mode=20 a=sendrecv ÇÉBÇ>VV0T4Vàín½EHkù€KXÀ¨À¨ 54U¾Ô_sip_udpsip cybercitydk!ÈÉB‰¯¯àín½0T4VE¡@7ŠŒÔò!#À¨ÄĦ CSeq: 2 INVITE From: "arik" ;tag=b56e6e Server: Cirpack/v4.38e (gw_sip) To: Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp10144774-4725f980192.168.1.2 Content-Length: 0 ÈÉBžlÇÇàín½0T4VE¹@7‰tÔò!#À¨ÄÄ¥­“SIP/2.0 183 In band info available Allow: UPDATE,REFER Call-ID: 11894297-4432a9f8@192.168.1.2 Contact: Content-Type: application/sdp CSeq: 2 INVITE From: "arik" ;tag=b56e6e Server: Cirpack/v4.38e (gw_sip) To: ;tag=00-04075-1701baa2-2dfdf7c21 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp10144774-4725f980192.168.1.2 Content-Length: 199 v=0 o=cp10 112047106116 112047106116 IN IP4 212.242.33.75 s=SIP Call c=IN IP4 212.242.33.36 t=0 0 m=audio 40392 RTP/AVP 8 0 b=AS:64 a=rtpmap:8 PCMA/8000/1 a=rtpmap:0 PCMU/8000/1 a=ptime:20 ÈÉBOææàín½0T4VEØ@7ŠUÔò!#À¨ÄÄÄ»“SIP/2.0 480 Error Allow: UPDATE,REFER Call-ID: 11894297-4432a9f8@192.168.1.2 Contact: CSeq: 2 INVITE From: "arik" ;tag=b56e6e Reason: q.850;cause=21 Server: Cirpack/v4.38e (gw_sip) To: ;tag=00-04075-1701baa2-2dfdf7c21 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp10144774-4725f980192.168.1.2 Content-Length: 0 ÈÉB>cnn0T4Vàín½E`kú€ÓÀ¨Ôò!#ÄÄL.ÆACK sip:35104724@sip.cybercity.dk SIP/2.0 From: "arik" ;tag=b56e6e Call-ID: 11894297-4432a9f8@192.168.1.2 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp10144774-4725f980192.168.1.2;rport To: ;tag=00-04075-1701baa2-2dfdf7c21 CSeq: 2 ACK Content-Length: 0 ÉÉBv”VV0T4Vàín½EHkû€KVÀ¨À¨ 54U¾Ô_sip_udpsip cybercitydk!ÉÉBûPÖÖ0T4Vàín½EÈkü€hÀ¨Ôò!$u0È´Þ€o®Ø7–ËqÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕj   i`bj`ia}tR[Y×G\VRUDKBuYsxZ|nhjÉÉB6bÖÖ0T4Vàín½EÈký€gÀ¨Ôò!$u0È´¿«€o¯x7–Ëqnhji`njlndljlnm`f~EÆÉðüçóúåðËñöÏÍäúÂSt_B[öðòüàî—èòWZOMug}fetuCxKGUCgfmcldfdxdoollbmcjnewr@Ð÷s}~bgbjjeCqZY~`fzrrIez`x]DBÉÉBpÖÖ0T4Vàín½EÈkþ€fÀ¨Ôò!$u0È´ÜŒ€o°7–Ëqq~pvÖÅÐKtvvOPAÑXfgegoxcffjofOzeeabh`Oafdruxmljglibxf`gcatÍø×vcbaxoxr`incPYpemdagejjjoF]EÝ^DIÖÐÄQQßÔßAtgÒõåæìè—–ïà씓”êꔟœœ’—øçìçáàêÉÉB%†ÖÖ0T4Vàín½EÈkÿ€eÀ¨Ôò!$u0È´™o€o±¸7–Ëq’—èé—êåúçæìúúÀxzadp`gxËïïêì•‘îäâê’’’”•‘œž›‡‡€‚ƒƒ††€ƒƒ€†„……ž™…„……‡‡†……„€‚€ƒ˜œŸ˜Ÿ–êîìéîè—èâîúÜZÜÉóòóöèêîî—‘––‘˜›˜…‡††…œž™žŸ™ŸŸ““Ÿ…‡„“”““—”éø÷OXCTÏABÉÉB`ŽÖÖ0T4Vàín½EÈl€dÀ¨Ôò!$u0È´Ê€o²X7–ËqD}pVÞõöòàîáñÃxxdda|OTY_ÑÏàíçó䔓””•íâìñøøæäóÇÍýüýúôçíâ’êãáìçãáúÿÞÀÀB|KÐÍõWu]ÜÉñàééåðÍÅÖEBgdxgazhrÖúæèéáàçðÆüÃQpMÁúæÍËåîìæíïê—êîèË×ðÞòÓÜÝV×ÕøôðAcfxfljjo`pxÉÉB]ÖÖ0T4Vàín½EÈl€cÀ¨Ôò!$u0È´w¨€o³ø7–Ëqeef`cmbjhohjmanccimidhjibhoffmamhnjlzqFqefhirvrjjdSËÉñøíúãúËÏÔôú_OÑ[KIuTËþæìÉÉBÄÖÖ0T4Vàín½EÈl€bÀ¨Ôò!$u0È´©¢€o´˜7–ËqäÙÞKI|cibohommmcedrsxofjhhjchzsMtgz~YÚ]EÍÑÔÑÛÙËìñÜüæî—••——îéãÃóô÷õóáüóõÍÂöååúóöZIthmfgKpGTÐYMO~ZÁËóÁGpdgfldszadrxuÇãÿññMVüÖõåìïî•‘…™››……„…˜™›„…„„˜ž…›„„›œ–——ÉÉBÀ°ÖÖ0T4Vàín½EÈl€aÀ¨Ôò!$u0È´¶ƒ€oµ 87–Ëqêêìæç”“—•‘–”ì•”àøèîáÍuÛÆÇóüâàæçÚÀñøÂMÍðæîïãïêéäáøÿÛØÙ×þåãáíì“—”êìâóÏQõPÏÞÉåòã—‘—’œ‘—èê“–•êèââáïêì”—éêãþööËøâàæøý÷òËöæøúäì锕”•éèèïíê–‘““œ“‘’““‘—––‘–éêéì•——ÉÉB<ÌÖÖ0T4Vàín½EÈl€`À¨Ôò!$u0È´‡ê€o¶ Ø7–Ëq–é–œ™žŸ’–‘•íçôôòüü•‘’ž„‡„˜‘‘—”–—èã”è–‘–œŸ…„…‘—•é–ž„„›…‡……™…˜“Ÿ’êïꑟ™„˜ž‘““”ìàúøöáàôåøäèêéåõåâíþÜÕTÿúè—è””•îåæüæîî•–‘—–ìãé““Ÿ›Ÿ˜“••îéí”—’’—•ïê–ÊÉB[Œ’’0T4Vàín½E„l€£À¨Ôò!$u1Ép,€È7–ËqBÉÊ^úÆ$à  Ê 7–Ëq11894297-4432a9f8@192.168.1.2SIPPSË7–Ëqsession shutdownËÉBVžVV0T4Vàín½EHl€KKÀ¨À¨ 54U¾Ô_sip_udpsip cybercitydk!ÍÉBáVV0T4Vàín½EHl€KJÀ¨À¨ 54U¾Ô_sip_udpsip cybercitydk!ÑÉBã¶VV0T4Vàín½EHl€KIÀ¨À¨ 54U¾Ô_sip_udpsip cybercitydk!ÙÉBx½RR0T4Vàín½EDl:€KÀ¨À¨ 50± 100127in-addrarpa ÙÉBSÃiiàín½0T4VE[@@·>À¨À¨5 Gû, €100127in-addrarpa À ' localhostÙÉB=úú0T4Vàín½Eìl;€À¨Ôò!#ÄÄØ­ËREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp8886016-44b14fe3192.168.1.2;rport From: ;tag=87971a To: Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel ;expires=1200;q=0.500 Expires: 1200 CSeq: 5 REGISTER Content-Length: 0 Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 ÙÉB .  àín½0T4VEü@7Š1Ôò!#À¨ÄÄè1×SIP/2.0 401 Unauthorized Call-ID: 29858147-465b0752@29858051-465b07b2 CSeq: 5 REGISTER From: ;tag=87971a To: ;tag=00-04074-1701bac9-1daa0b4c5 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp8886016-44b14fe3192.168.1.2 WWW-Authenticate: Digest realm="sip.cybercity.dk",nonce="1701babd2ad677745e6d6bf15442a8e",opaque="1701a1351f70795",stale=false,algorithm=MD5 Content-Length: 0 ÙÉB²å VV0T4Vàín½EHl<€KÀ¨À¨ 54§´‚ _sip_udpsip cybercitydk!ÚÉBñÈ VV0T4Vàín½EHl=€KÀ¨À¨ 54§´‚ _sip_udpsip cybercitydk!ÜÉBØÔ VV0T4Vàín½EHl>€KÀ¨À¨ 54§´‚ _sip_udpsip cybercitydk!ÞÉBbß VV0T4Vàín½EHlG€K À¨À¨ 54§´‚ _sip_udpsip cybercitydk!âÉBB÷ VV0T4Vàín½EHlH€K À¨À¨ 54§´‚ _sip_udpsip cybercitydk!êÉB:ý RR0T4Vàín½EDlI€K À¨À¨ 50¬ 100127in-addrarpa êÉB& iiàín½0T4VE[@@·>À¨À¨5 Gú' €100127in-addrarpa À ' localhostêÉBt ÏÏ0T4Vàín½EÁlJ€"À¨Ôò!#ÄÄ­OÓREGISTER sip:sip.cybercity.dk SIP/2.0 Via: SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp6658824-465059f1192.168.1.2;rport From: ;tag=659abf To: Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel ;expires=1200;q=0.500 Expires: 1200 CSeq: 6 REGISTER Content-Length: 0 Authorization: Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701babd2ad677745e6d6bf15442a8e",opaque="1701a1351f70795",nc="00000001",response="92f9402a5ee6660935cb1254a04a523a" Max-Forwards: 70 User-Agent: Nero SIPPS IP Phone Version 2.0.51.16 êÉB=I VVàín½0T4VEH@7ŠåÔò!#À¨ÄÄ4!ÅSIP/2.0 100 Trying Call-ID: 29858147-465b0752@29858051-465b07b2 CSeq: 6 REGISTER From: ;tag=659abf To: Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp6658824-465059f1192.168.1.2 Content-Length: 0 êÉB¨t ýýàín½0T4VEï@7Š>Ôò!#À¨ÄÄÛ•SIP/2.0 200 OK Call-ID: 29858147-465b0752@29858051-465b07b2 Contact: pel;q=0.500;expires=1200 CSeq: 6 REGISTER From: ;tag=659abf P-Associated-URI: To: ;tag=00-04087-1701bae7-76fb74995 Via: SIP/2.0/UDP 192.168.1.2;received=80.230.219.70;rport=5060;branch=z9hG4bKnp6658824-465059f1192.168.1.2 Content-Length: 0 êÉB؇\\ÿÿÿÿÿÿàín½ENlK€JÀ¨À¨ÿ‰‰:[9…b EFEDEJFPEEEPENEBEJEOCACACACACABM ëÉB³VV0T4Vàín½EHlL€KÀ¨À¨ 54Ì®] _sip_udpsip cybercitydk!ëÉBý² \\ÿÿÿÿÿÿàín½ENlM€JÀ¨À¨ÿ‰‰:[9…b EFEDEJFPEEEPENEBEJEOCACACACACABM ìÉB#œVV0T4Vàín½EHlN€KÀ¨À¨ 54Ì®] _sip_udpsip cybercitydk!ìÉB æ\\ÿÿÿÿÿÿàín½ENlO€IþÀ¨À¨ÿ‰‰:[9…b EFEDEJFPEEEPENEBEJEOCACACACACABM îÉBX©VV0T4Vàín½EHlP€KÀ¨À¨ 54Ì®] _sip_udpsip cybercitydk!ïÉBÒò <<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍïÉBó **0T4Vàín½àín½À¨0T4VÀ¨ðÉBͲVV0T4Vàín½EHlQ€KÀ¨À¨ 54Ì®] _sip_udpsip cybercitydk!ôÉBÉVV0T4Vàín½EHlR€JÿÀ¨À¨ 54Ì®] _sip_udpsip cybercitydk!ùÉB€¨ óóÿÿÿÿÿÿàín½EålS€IcÀ¨À¨ÿŠŠÑZð…dÀ¨Š» EEDADADCDEDGDFCACACACACACACACACA EFEDEJFPEEEPENEBEJEOCACACACACABNÿSMB%!è!V2\MAILSLOT\BROWSE€ü D002465UªüÉB¢ÐRR0T4Vàín½EDlT€KÀ¨À¨ 50•¦100127in-addrarpa üÉByÖiiàín½0T4VE[@@·>À¨À¨5 Gx"€100127in-addrarpa À ' localhostüÉBXÛ//0T4Vàín½E!lU€·À¨Ôò!#ÄÄ ÀK ÉB§,VV0T4Vàín½EHlV€JûÀ¨À¨ 54D‰å0_sip_udpsip cybercitydk! ÉBKVV0T4Vàín½EHlW€JúÀ¨À¨ 54D‰å0_sip_udpsip cybercitydk! ÉB¤#VV0T4Vàín½EHlX€JùÀ¨À¨ 54D‰å0_sip_udpsip cybercitydk! ÉBã.VV0T4Vàín½EHlY€JøÀ¨À¨ 54D‰å0_sip_udpsip cybercitydk!ÉBVEVV0T4Vàín½EHlZ€J÷À¨À¨ 54D‰å0_sip_udpsip cybercitydk!ÉBOMRR0T4Vàín½EDl[€JúÀ¨À¨ 50è€<2100127in-addrarpa ÉBNSiiàín½0T4VE[@@·>À¨À¨5 GÊü<2€100127in-addrarpa À ' localhostÉB/X//0T4Vàín½E!l\€°À¨Ôò!#ÄÄ ÀK ÉBØ:\\ÿÿÿÿÿÿàín½ENl]€IðÀ¨À¨ÿ‰‰:[4…g EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBK¨\\ÿÿÿÿÿÿàín½ENl^€IïÀ¨À¨ÿ‰‰:[4…g EFEDEJFPEEEPENEBEJEOCACACACACABM ÉBúÛ \\ÿÿÿÿÿÿàín½ENl_€IîÀ¨À¨ÿ‰‰:[4…g EFEDEJFPEEEPENEBEJEOCACACACACABM %ÉB»¨VV0T4Vàín½EHl`€JñÀ¨À¨ 54Y„Ð3_sip_udpsip cybercitydk!&ÉB”VV0T4Vàín½EHla€JðÀ¨À¨ 54Y„Ð3_sip_udpsip cybercitydk!(ÉBQŸVV0T4Vàín½EHlb€JïÀ¨À¨ 54Y„Ð3_sip_udpsip cybercitydk!*ÉBt«VV0T4Vàín½EHlc€JîÀ¨À¨ 54Y„Ð3_sip_udpsip cybercitydk!,ÉBç|LL0T4Vàín½E>ld€J÷À¨À¨ 5*ˆhM5sip cybercitydk-ÉB:tLL0T4Vàín½E>le€JöÀ¨À¨ 5*ˆhM5sip cybercitydk.ÉB"ÁVV0T4Vàín½EHlf€JëÀ¨À¨ 54Y„Ð3_sip_udpsip cybercitydk!/ÉBºLL0T4Vàín½E>lg€JôÀ¨À¨ 5*ˆhM5sip cybercitydk0ÉB€€àín½0T4VEr@@·'À¨À¨5 ^`;M5€sip cybercitydkÀ ,Ôò!#À,ns1ÀÀ,ns2À5ÉB*ü<<àín½0T4V0T4VÀ¨À¨ˆdö7 À! Ï;ùÍ5ÉB[ü**0T4Vàín½àín½À¨0T4VÀ¨6ÉB–CRR0T4Vàín½EDlh€JíÀ¨À¨ 50Áyc6100127in-addrarpa 6ÉB’Iiiàín½0T4VE[@@·>À¨À¨5 G£õc6€100127in-addrarpa À ' localhost6ÉBµN//0T4Vàín½E!li€£À¨Ôò!#ÄÄ ÀK BÉBVV0T4Vàín½EHln€JãÀ¨À¨ 547~ò6_sip_udpsip cybercitydk!CÉBú†VV0T4Vàín½EHlo€JâÀ¨À¨ 547~ò6_sip_udpsip cybercitydk!sngrep-1.2.0/tests/test_003.c0000644000175000017500000000452612632250522014717 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_003.c * @author Ivan Alonso [aka Kaian] * * Basic Call Flow testing */ const char keys[] = { /* Select some dialogs */ 32, 107, 32, 107, /* Enter Call Flow */ 10, 27, /* Move arrow messages */ 107, 107, 107, 107, 107, 106, 107, 107, 107, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 4, 4, 2, 2, 4, 2, 4, 2, /* Reenter Call Flow */ 10, /* Swap colors */ 'c', 'c', 'c', 'c', 'c', 'c', /* Enter Extended Call Flow */ 'x', 'x', 'x', 'x', /* Compress column display */ 's', /* Toggle media display */ 'd', 'd', 'd', 'd', 'd', /* Toggle Only SDP */ 'D', /* Enter Call Raw (all dialogs) */ 'R', 27, /* Enter Call Raw (single message) */ 10, 27, /* Enter help screen */ 'h', 100, /* Toggle raw screen */ 't', 't', 't', 't', /* Change Raw size */ '0', '0', '0', '0', '0', '0', '0', '0', '9', '9', '9', '9', '9', '9', '9', '9', /* Reset Raw size */ 'T', 'T', /* Leave Call Flow */ 27, /* Exit */ 27, 10, 0 }; #include "test_input.c" sngrep-1.2.0/tests/Makefile.am0000644000175000017500000000051312632250522015236 0ustar vsevavsevacheck_PROGRAMS=test-001 test-002 test-003 test-004 test-005 test-006 test-007 test_001_SOURCES=test_001.c test_002_SOURCES=test_002.c test_003_SOURCES=test_003.c test_004_SOURCES=test_004.c test_005_SOURCES=test_005.c test_006_SOURCES=test_006.c test_007_SOURCES=test_007.c ../src/vector.c ../src/util.c TESTS = $(check_PROGRAMS) sngrep-1.2.0/tests/test_004.c0000644000175000017500000000427012632250522014714 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_004.c * @author Ivan Alonso [aka Kaian] * * Basic Call Raw testing */ const int keys[] = { /* Select some dialogs */ 32, 107, 107, 107, 32, 107, /* Show Raw panel */ 'r', /* Cicle options */ 'c', 'c', 'c', 'c', 'c', 'c', 'a', 'a', 'a', 'a', 'a', 'a', 'l', 'l', 'l', 'C', 'C', 'C', /* Move through Raw panel */ 107, 107, 107, 107, 107, 106, 107, 107, 107, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 4, 4, 2, 2, 4, 2, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Enter save screen */ 's', 20, 30, 40, 50, 60, 27, /* Leave call Raw */ 27, /* Exit */ 27, 10, 0 }; #include "test_input.c" sngrep-1.2.0/tests/test_005.c0000644000175000017500000000402012632250522014706 0ustar vsevavseva/************************************************************************** ** ** sngrep - SIP Messages flow viewer ** ** Copyright (C) 2015 Ivan Alonso (Kaian) ** Copyright (C) 2015 Irontec SL. All rights reserved. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . ** ****************************************************************************/ /** * @file test_005.c * @author Ivan Alonso [aka Kaian] * * Basic Column selection testing */ const int keys[] = { /* Show Raw panel */ 't', /* Cycle through fields */ 9, 9, 9, 9, 9, 9, 9, 107, 107, 9, 106, /* Move through Column list */ 107, 107, 107, 107, 107, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, /* Move items up and down */ '-', '-', '-', '-', 107, 107, '+', '+', '+', '+', 107, 107, '-', '-', '-', '-', /* Apply new settings */ 10, /* Exit */ 27, 10, 0 }; #include "test_input.c" sngrep-1.2.0/tests/README0000644000175000017500000000076512632250522014073 0ustar vsevavsevaBasic testing programs for sngrep. This set of test will do some basic inputs to check sngrep screen navigation doesn't crash. This checks are ultra-super-basic. - test_001 : UI testing - test_002 : Call List testing - test_003 : Call Flow testing - test_004 : Call Raw testing - test_005 : Column selection testing - test_006 : Message diff testing - test_007: Test vector container structures Sample capture files has been taken from wireshark Wiki: - https://wiki.wireshark.org/SampleCaptures sngrep-1.2.0/Makefile.am0000644000175000017500000000006512632250522014076 0ustar vsevavsevaSUBDIRS=src config doc tests EXTRA_DIST=bootstrap.sh sngrep-1.2.0/COPYING0000644000175000017500000010451312632250522013100 0ustar vsevavseva GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . sngrep-1.2.0/INSTALL0000644000175000017500000003633212632250522013101 0ustar vsevavsevaInstallation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. sngrep-1.2.0/Doxyfile0000644000175000017500000022051212632250522013551 0ustar vsevavseva# Doxyfile 1.7.6.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = sngrep # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "SIP Messages flow viewer" # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the # same symbol appear multiple times in the code, doxygen keeps a cache of # pre-resolved symbols. If the cache is too small doxygen will become slower. # If the cache is too large, memory is wasted. The cache size is given by this # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = YES # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST = YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = src/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.h *.c *.php *.lua *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = *.lua=/usr/bin/lua2dox # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = YES # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = doc/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the # mathjax.org site, so you can quickly see the result without installing # MathJax, but it is strongly recommended to install a local copy of MathJax # before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES sngrep-1.2.0/LICENSE0000644000175000017500000010451312632250522013052 0ustar vsevavseva GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . sngrep-1.2.0/NEWS0000644000175000017500000000000012632250522012526 0ustar vsevavsevasngrep-1.2.0/configure.ac0000644000175000017500000001771312632250522014340 0ustar vsevavsevaAC_PREREQ([2.59]) AC_INIT([sngrep], [1.2.0], [kaian@irontec.com], [sngrep], [http://www.irontec.com/]) AM_INIT_AUTOMAKE([1.9]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CONFIG_HEADERS([src/config.h]) AC_COPYRIGHT("Irontec S.L.") # Define _GNU_SOURCE etc. m4_ifdef([AC_USE_SYSTEM_EXTENSIONS], [AC_USE_SYSTEM_EXTENSIONS]) # debug compilation AC_ARG_ENABLE(debug, AC_HELP_STRING(--enable-debug, [Debug compilation (Default = no)]), enable_debug=$enableval, enable_debug=no) if test "$enable_debug" = "yes" ; then CFLAGS="$CFLAGS -g -O0 -Wall -Werror -Wno-unused-but-set-variable" CXXFLAGS="$CXXFLAGS $CFLAGS" fi # Minimum checks for a C program :) AC_PROG_CC AC_PROG_CXX AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_EGREP AC_LANG(C) ####################################################################### # Check for other REQUIRED libraries AC_CHECK_LIB([pthread], [pthread_create], [], [ AC_MSG_ERROR([ You need to have libpthread installed to compile sngrep.]) ]) AC_CHECK_LIB([pcap], [pcap_open_offline], [], [ AC_MSG_ERROR([ You need to have libpcap installed to compile sngrep.]) ]) AC_CHECK_HEADER([pcap.h], [], [ AC_MSG_ERROR([ You need to have libpcap development files installed to compile sngrep.]) ]) #### #### Ncurses Wide character support #### AC_ARG_ENABLE([unicode], AC_HELP_STRING([--enable-unicode], [Enable Ncurses Unicode support]), [AC_SUBST(UNICODE, $enableval)], [AC_SUBST(UNICODE, no)] ) AS_IF([test "x$enable_unicode" == "xyes"], [ # Ncurses with wide-character support AC_DEFINE([WITH_UNICODE], [], [Compile With Unicode compatibility]) AC_CHECK_HEADER([ncursesw/ncurses.h], [], [ AC_MSG_ERROR([ You need to have ncurses development files installed to compile sngrep.]) ]) AC_CHECK_LIB([ncursesw], [initscr], [], [ AC_MSG_ERROR([ You need to have libncursesw installed to compile sngrep.]) ]) AC_CHECK_LIB([panelw], [new_panel], [], [ AC_MSG_ERROR([ You need to have ncurses panelw library installed to compile sngrep.]) ]) AC_CHECK_LIB([formw], [new_form], [], [ AC_MSG_ERROR([ You need to have ncurses formsw library installed to compile sngrep.]) ]) AC_CHECK_LIB([menuw], [new_item], [], [ AC_MSG_ERROR([ You need to have ncurses menuw library installed to compile sngrep.]) ]) ], [ # Ncurses without wide-character support AC_CHECK_HEADER([ncurses.h], [], [ AC_MSG_ERROR([ You need to have ncurses development files installed to compile sngrep.]) ]) AC_CHECK_LIB([ncurses], [initscr], [], [ AC_MSG_ERROR([ You need to have libncurses installed to compile sngrep.]) ]) AC_CHECK_LIB([panel], [new_panel], [], [ AC_MSG_ERROR([ You need to have ncurses panel library installed to compile sngrep.]) ]) AC_CHECK_LIB([form], [new_form], [], [ AC_MSG_ERROR([ You need to have ncurses forms library installed to compile sngrep.]) ]) AC_CHECK_LIB([menu], [new_item], [], [ AC_MSG_ERROR([ You need to have ncurses menu library installed to compile sngrep.]) ]) ]) #### #### GnuTLS Support #### AC_ARG_WITH([gnutls], AS_HELP_STRING([--with-gnutls], [Enable SSL Support (TLS SIP Transport)]), [AC_SUBST(WITH_GNUTLS, $withval)], [AC_SUBST(WITH_GNUTLS, no)] ) AS_IF([test "x$WITH_GNUTLS" == "xyes"], [ AC_CHECK_LIB([gnutls], [gnutls_init], [], [ AC_MSG_ERROR([ You need to have gnutls installed to compile sngrep]) ]) AC_CHECK_LIB([gnutls-openssl], [SSL_new], [], [ AC_MSG_ERROR([ You need to have gnutls installed to compile sngrep]) ]) AC_CHECK_LIB([gcrypt], [gcry_md_map_name], [], [ AC_MSG_ERROR([ You need to have libgcrypt installed to compile sngrep]) ]) AC_DEFINE([WITH_GNUTLS],[],[Compile With GnuTLS compatibility]) ], []) #### #### OpenSSL Support #### AC_ARG_WITH([openssl], AS_HELP_STRING([--with-openssl], [Enable SSL Support (TLS SIP Transport)]), [AC_SUBST(WITH_OPENSSL, $withval)], [AC_SUBST(WITH_OPENSSL, no)] ) AS_IF([test "x$WITH_OPENSSL" == "xyes"], [ AS_IF([test "x$WITH_GNUTLS" == "xyes"], [ AC_MSG_ERROR([ GnuTLS and OpenSSL can not be enabled at the same time ]) ], []) AC_CHECK_LIB([ssl], [SSL_new], [], [ AC_MSG_ERROR([ You need to have libssl installed to compile sngrep]) ]) AC_CHECK_LIB([crypto], [EVP_get_cipherbyname], [], [ AC_MSG_ERROR([ You need to have libcrypto installed to compile sngrep]) ]) AC_DEFINE([WITH_OPENSSL],[],[Compile With Openssl compatibility]) ], []) #### #### PCRE Support #### AC_ARG_WITH([pcre], AS_HELP_STRING([--with-pcre], [Enable Perl compatible regular expressions]), [AC_SUBST(WITH_PCRE, $withval)], [AC_SUBST(WITH_PCRE, no)] ) AS_IF([test "x$WITH_PCRE" == "xyes"], [ AC_CHECK_HEADER([pcre.h], [], [ AC_MSG_ERROR([ You need libpcre development files installed to compile with pcre support.]) ]) AC_CHECK_LIB([pcre], [pcre_exec], [], [ AC_MSG_ERROR([ You need libpcre library installed to compile with pcre support.]) ]) AC_DEFINE([WITH_PCRE],[],[Compile With Perl Compatible regular expressions support]) ], []) #### #### IPv6 Support #### AC_ARG_ENABLE([ipv6], AS_HELP_STRING([--enable-ipv6], [Enable IPv6 Support]), [AC_SUBST(USE_IPV6, $enableval)], [AC_SUBST(USE_IPV6, no)] ) AS_IF([test "x$USE_IPV6" == "xyes"], [ AC_CHECK_HEADERS([netinet/in.h netinet/ip6.h], [], [ AC_MSG_ERROR([ You dont seem to have ipv6 support (no ip6.h found).]) ], [ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif ]) AC_DEFINE([USE_IPV6],[],[Compile With IPv6 support]) ], []) #### #### EEP Support #### AC_ARG_ENABLE([eep], AS_HELP_STRING([--enable-eep], [Enable EEP/HEP Support]), [AC_SUBST(USE_EEP, $enableval)], [AC_SUBST(USE_EEP, no)] ) AS_IF([test "x$USE_EEP" == "xyes"], [ AC_DEFINE([USE_EEP],[],[Compile With EEP support]) ], []) # Conditional Source inclusion AM_CONDITIONAL([WITH_GNUTLS], [test "x$WITH_GNUTLS" == "xyes"]) AM_CONDITIONAL([WITH_OPENSSL], [test "x$WITH_OPENSSL" == "xyes"]) AM_CONDITIONAL([USE_EEP], [test "x$USE_EEP" == "xyes"]) ###################################################################### # Print Logo AC_ARG_ENABLE(logo, AC_HELP_STRING(--disable-logo, [Disable Irontec Logo from Summary menu]), [ enable_logo=$enableval], [ enable_logo=yes]) AS_IF([test "x$enable_logo" == "xyes"], [ echo '' echo ' ██╗██████╗ ██████╗ ███╗ ██╗████████╗███████╗ ██████╗' echo ' ██║██╔â•â•██╗██╔â•â•â•██╗████╗ ██║╚â•â•██╔â•â•â•██╔â•â•â•â•â•██╔â•â•â•â•â•' echo ' ██║██████╔â•██║ ██║██╔██╗ ██║ ██║ █████╗ ██║ ' echo ' ██║██╔â•â•██╗██║ ██║██║╚██╗██║ ██║ ██╔â•â•╠██║ ' echo ' ██║██║ ██║╚██████╔â•██║ ╚████║ ██║ ███████╗╚██████╗' echo ' ╚â•â•╚â•╠╚â•╠╚â•â•â•â•â•╠╚â•╠╚â•â•â•╠╚â•╠╚â•â•â•â•â•â•╠╚â•â•â•â•â•â•' echo '' ]) AC_MSG_NOTICE AC_MSG_NOTICE( sngrep configure finished ) AC_MSG_NOTICE( ====================================================== ) AC_MSG_NOTICE( GnuTLS Support : ${WITH_GNUTLS} ) AC_MSG_NOTICE( OpenSSL Support : ${WITH_OPENSSL} ) AC_MSG_NOTICE( Unicode Support : ${UNICODE} ) AC_MSG_NOTICE( Perl Expressions Support : ${WITH_PCRE} ) AC_MSG_NOTICE( IPv6 Support : ${USE_IPV6} ) AC_MSG_NOTICE( EEP Support : ${USE_EEP} ) AC_MSG_NOTICE( ====================================================== ) AC_MSG_NOTICE AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([src/Makefile]) AC_CONFIG_FILES([config/Makefile]) AC_CONFIG_FILES([doc/Makefile]) AC_CONFIG_FILES([tests/Makefile]) AC_OUTPUT sngrep-1.2.0/README0000777000175000017500000000000012632250522014175 2README.mdustar vsevavseva