Imported Upstream version 1.3a debian upstream upstream/1.3a
authorDevon Kearns <dookie@kali.org>
Mon, 31 Dec 2012 01:00:01 +0000 (18:00 -0700)
committerDevon Kearns <dookie@kali.org>
Mon, 31 Dec 2012 01:00:01 +0000 (18:00 -0700)
21 files changed:
CHANGELOG [new file with mode: 0644]
COPYING [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
THANKS [new file with mode: 0644]
check_version.sh [new file with mode: 0755]
doc/rtpbreak_en.css [new file with mode: 0644]
doc/rtpbreak_en.html [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/VERSION [new file with mode: 0644]
src/bpf.h [new file with mode: 0644]
src/common.c [new file with mode: 0644]
src/common.h [new file with mode: 0644]
src/ieee80211.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/main.h [new file with mode: 0644]
src/net.c [new file with mode: 0644]
src/net.h [new file with mode: 0644]
src/queue.h [new file with mode: 0644]
src/rtp.h [new file with mode: 0644]
src/rtp_pt.h [new file with mode: 0644]

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..f340bbf
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,41 @@
+--- CHANGELOG BEGIN ---
+
+05.05.08 * version 1.3a
+  - Improved logging output of net.c
+  - Added missing gcc option -O3 in src/Makefile
+  - Fixed a -W option bug (partial results corruption)
+
+19.02.08 * version 1.3
+  - Added -w and -W options (enable/disable raw/pcap output)
+  - Simplified command line options
+  - Changed the default value of some SELECT options (this should
+    improve the detection, using more memory!) 
+  - Improved output files
+  - Fixed a bug that caused a silent drop of the noise packets
+  - Improved documentation
+  - Removed the italian documentation
+  - Some bugs fixed in common.c
+  - Added the dissector for AP_DLT_IEEE802_11 network frames,
+    this implies a better support for wireless networks
+
+14.08.07 * version 1.2
+  - Added privilege dropping
+  - Added syslog logging
+  - Improved output files
+  - Simplified command line options
+  - Improved reverse rtp stream detection
+  - Added background execution
+  - In Makefile added gcc option -O3 and removed gcc option -ggdb
+  - Added files COPYING and CHANGELOG
+  - In Makefile added version information
+  - README.* updated to reflect changes
+
+22.07.07 * version 1.1
+  - Fixed a bug that caused some broken stats and 1 lost packet
+    when (rtp_packet.seq == 0)
+
+25.05.07 * version 1.0
+  - First public release!
+
+--- CHANGELOG END ---
+
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d511905
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  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.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+                    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
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This 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.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..deb334b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+# project Makefile.
+
+INSTALL_DIR       = "$(HOME)/bin/" 
+
+#####################################################################
+
+
+all: build
+
+check_version:
+       @./check_version.sh
+
+build:
+       @cd src ; $(MAKE)
+       @echo "% "
+       @echo "% You can check the web if this is the latest public version"
+       @echo "% issuing the command \"make check_version\". have fun!"
+       @echo "%"
+
+
+install:
+       cp src/rtpbreak $(INSTALL_DIR)
+       @echo "%"
+       @echo "% Now rtpbreak is properly installed, ready to sniff packets!"
+       @echo "%"
+
+clean:
+       cd src ; $(MAKE) clean
+
+#eof
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..539668d
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+See the doc directory.
+
diff --git a/THANKS b/THANKS
new file mode 100644 (file)
index 0000000..8750c9f
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,8 @@
+--- THANKS BEGIN ---
+
+- Prudhvi Krishna Surapaneni, mantainer of the FreeBSD Port
+- Timothy Redaelli, mantainer of the Gentoo package
+- Esa Hyytia, suggesting new features and reporting bugs
+- Miguel Olivares, reporting bugs
+
+--- THANKS END ---
diff --git a/check_version.sh b/check_version.sh
new file mode 100755 (executable)
index 0000000..96bf257
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+PATH=${PATH}:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin
+################################################################################
+#
+# check_version.sh by xenion -- 2008-02-23 10:39 -- v.1ce37613244d6fcb5d0ba4be290c9558
+#
+
+latest_version_absurl="http://xenion.antifork.org/rtpbreak/VERSION"
+this_version_relpath="src/VERSION"
+
+echo "Getting file $latest_version_absurl ..."
+
+latest_version="`wget -qO- "$latest_version_absurl" | cut -f2- -d=`"
+this_version="`cat "$this_version_relpath" | cut -f2- -d=`"
+
+if [ "$latest_version" = "" ] ;
+  then
+    echo "ERR: unable to wget $latest_version_absurl"
+  else
+    if [ "$latest_version" = "$this_version" ] ;
+       then
+         echo "You have the latest available version! (latest:$latest_version == this:$this_version)"
+       else
+         echo "You have not the latest available version! (latest:$latest_version != this:$this_version)"
+        echo "You can get it at http://xenion.antifork.org/"
+    fi
+fi
+
+
+
+
+
diff --git a/doc/rtpbreak_en.css b/doc/rtpbreak_en.css
new file mode 100644 (file)
index 0000000..5459bd7
--- /dev/null
@@ -0,0 +1,34 @@
+/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
+.MATH    { font-family: "Century Schoolbook", serif; }
+.MATH I  { font-family: "Century Schoolbook", serif; font-style: italic }
+.BOLDMATH { font-family: "Century Schoolbook", serif; font-weight: bold }
+
+/* implement both fixed-size and relative sizes */
+SMALL.XTINY            { font-size : xx-small }
+SMALL.TINY             { font-size : x-small  }
+SMALL.SCRIPTSIZE       { font-size : smaller  }
+SMALL.FOOTNOTESIZE     { font-size : small    }
+SMALL.SMALL            {  }
+BIG.LARGE              {  }
+BIG.XLARGE             { font-size : large    }
+BIG.XXLARGE            { font-size : x-large  }
+BIG.HUGE               { font-size : larger   }
+BIG.XHUGE              { font-size : xx-large }
+
+/* heading styles */
+H1             {  }
+H2             {  }
+H3             {  }
+H4             {  }
+H5             {  }
+
+/* mathematics styles */
+DIV.displaymath                { }     /* math displays */
+TD.eqno                        { }     /* equation-number cells */
+
+
+/* document-specific styles come next */
+DIV.navigation         {   }
+PRE.preform            {   }
+SPAN.textit            { font-style: italic  }
+SPAN.arabic            {   }
diff --git a/doc/rtpbreak_en.html b/doc/rtpbreak_en.html
new file mode 100644 (file)
index 0000000..991bca2
--- /dev/null
@@ -0,0 +1,775 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+
+<!--Converted with LaTeX2HTML 2002-2-1 (1.71)
+original version by:  Nikos Drakos, CBLU, University of Leeds
+* revised and updated by:  Marcus Hennecke, Ross Moore, Herb Swan
+* with significant contributions from:
+  Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
+<HTML>
+<HEAD>
+<TITLE>rtpbreak 1.3a</TITLE>
+<META NAME="description" CONTENT="rtpbreak 1.3a">
+<META NAME="keywords" CONTENT="rtpbreak_en">
+<META NAME="resource-type" CONTENT="document">
+<META NAME="distribution" CONTENT="global">
+
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+<META NAME="Generator" CONTENT="LaTeX2HTML v2002-2-1">
+<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
+
+<LINK REL="STYLESHEET" HREF="rtpbreak_en.css">
+
+</HEAD>
+
+<BODY >
+<H1 ALIGN="CENTER">rtpbreak 1.3a</H1>
+<DIV CLASS="author_info">
+
+<P ALIGN="CENTER"><STRONG>xenion - Michele Dallachiesa</STRONG></P>
+<P ALIGN="CENTER"><I>michele dot dallachiesa at poste dot it</I></P>
+</DIV>
+
+<BR>
+
+<H2><A NAME="SECTION00010000000000000000">
+Contents</A>
+</H2>
+<!--Table of Contents-->
+
+<UL CLASS="TofC">
+<LI><A NAME="tex2html14"
+  HREF="rtpbreak_en.html#SECTION00020000000000000000">Introduction</A>
+<LI><A NAME="tex2html15"
+  HREF="rtpbreak_en.html#SECTION00030000000000000000">Usage</A>
+<LI><A NAME="tex2html16"
+  HREF="rtpbreak_en.html#SECTION00040000000000000000">Examples</A>
+<UL>
+<LI><A NAME="tex2html17"
+  HREF="rtpbreak_en.html#SECTION00041000000000000000">Record, mix and replay a VoIP call</A>
+<LI><A NAME="tex2html18"
+  HREF="rtpbreak_en.html#SECTION00042000000000000000">Analyze an RTP session</A>
+<LI><A NAME="tex2html19"
+  HREF="rtpbreak_en.html#SECTION00043000000000000000">Particular scenarios</A>
+</UL>
+<BR>
+<LI><A NAME="tex2html20"
+  HREF="rtpbreak_en.html#SECTION00050000000000000000">How it works</A>
+<LI><A NAME="tex2html21"
+  HREF="rtpbreak_en.html#SECTION00060000000000000000">Dependencies and compilation</A>
+<LI><A NAME="tex2html22"
+  HREF="rtpbreak_en.html#SECTION00070000000000000000">Links</A>
+</UL>
+<!--End of Table of Contents-->
+<P>
+
+<H1><A NAME="SECTION00020000000000000000">
+Introduction</A>
+</H1>
+With rtpbreak you can detect, reconstruct and analyze any RTP session. It doesn't require the presence of RTCP packets and works independently form the used signaling protocol (SIP, H.323, SCCP, ...). The input is a sequence of packets, the output is a set of files you can use as input for other tools (wireshark/tshark, sox, grep/awk/cut/cat/sed, ...). It supports also wireless (AP_DLT_IEEE802_11) networks. This is a list of scenarios where rtpbreak is a good choice:
+
+<UL>
+<LI>reconstruct any RTP stream with an unknown or unsupported signaling protocol
+</LI>
+<LI>reconstruct any RTP stream in wireless networks, while doing channel hopping (VoIP activity detector)
+</LI>
+<LI>reconstruct and decode any RTP stream in batch mode (with sox, asterisk, ...)
+</LI>
+<LI>reconstruct any already existing RTP stream
+</LI>
+<LI>reorder the packets of any RTP stream for later analysis (with tshark, wireshark, ...)
+</LI>
+<LI>build a tiny wireless VoIP tapping system in a single chip Linux unit
+</LI>
+<LI>build a complete VoIP tapping system (rtpbreak would be just the RTP dissector module!)
+</LI>
+</UL>
+This project is released under license GPL version 2. 
+
+<H1><A NAME="SECTION00030000000000000000">
+Usage</A>
+</H1>
+The unique mandatory input parameter is the packet source (network interface or pcap file). This is the list of  accepted parameters:
+
+<P>
+<DL>
+<DT><STRONG>INPUT</STRONG></DT>
+<DD><DL>
+<DT><STRONG>-r &lt;str&gt;</STRONG></DT>
+<DD>Read packets from file (pcap format) &lt;str&gt;
+</DD>
+<DT><STRONG>-i &lt;str&gt;</STRONG></DT>
+<DD>Read packets from network interface &lt;str&gt;
+</DD>
+<DT><STRONG>-L &lt;int&gt;</STRONG></DT>
+<DD>Force the datalink header length to &lt;int&gt; bytes. This is useful if the interface type is not correctly recognized by libpcap
+</DD>
+</DL>
+
+<P>
+</DD>
+<DT><STRONG>OUTPUT</STRONG></DT>
+<DD><DL>
+<DT><STRONG>-d &lt;str&gt;</STRONG></DT>
+<DD>Set the output directory to &lt;str&gt;
+</DD>
+<DT><STRONG>-w</STRONG></DT>
+<DD>Disable the raw dump of RTP sessions
+</DD>
+<DT><STRONG>-W</STRONG></DT>
+<DD>Disable the pcap dump of RTP sessions
+</DD>
+<DT><STRONG>-g</STRONG></DT>
+<DD>Fill the gaps of lost packets in raw dumps with the last sniffed packet, preventing desynchronization problems when decoding/mixing multiple RTP streams (with sox, ...)
+</DD>
+<DT><STRONG>-n</STRONG></DT>
+<DD>Dump packets passing the single packet pattern but not the multiple packets pattern (the noise packets) to pcap file
+</DD>
+<DT><STRONG>-f</STRONG></DT>
+<DD>Disable stdout logging
+</DD>
+<DT><STRONG>-F</STRONG></DT>
+<DD>Enable syslog logging
+</DD>
+<DT><STRONG>-v</STRONG></DT>
+<DD>Be verbose
+</DD>
+</DL>
+
+<P>
+</DD>
+<DT><STRONG>SELECT</STRONG></DT>
+<DD><DL>
+<DT><STRONG>-m</STRONG></DT>
+<DD>Sniff packets in promiscuous mode
+</DD>
+<DT><STRONG>-p &lt;str&gt;</STRONG></DT>
+<DD>Consider only  packets matching the libpcap filter &lt;str&gt;
+</DD>
+<DT><STRONG>-e</STRONG></DT>
+<DD>Expect an even destination UDP port. The RTP packets must have an even destination UDP port. This should be always true, anyway some VoIP networks (like Yahoo) don't respect this rule
+</DD>
+<DT><STRONG>-u</STRONG></DT>
+<DD>Expect unprivileged source/destination UDP ports (&gt; 1024). This should always be true
+</DD>
+<DT><STRONG>-y &lt;int&gt;</STRONG></DT>
+<DD>The RTP packets must have exactly this payload type. For example, if we want only RTP streams with data encoded in G.711 ulaw, we should add the option -y 0, value obtained from the -k option
+</DD>
+<DT><STRONG>-l &lt;int&gt;</STRONG></DT>
+<DD>The RTP payload length must be exactly &lt;int&gt; bytes
+</DD>
+<DT><STRONG>-t &lt;float&gt;</STRONG></DT>
+<DD>Consider terminated any session without new packets for &lt;float&gt; seconds
+</DD>
+<DT><STRONG>-T &lt;float&gt;</STRONG></DT>
+<DD>Consider a timeout of &lt;float&gt; seconds in the pattern over multiple packets
+</DD>
+<DT><STRONG>-P &lt;int&gt;</STRONG></DT>
+<DD>Consider &lt;int&gt; packets in the pattern over multiple packets
+</DD>
+</DL>
+
+<P>
+</DD>
+<DT><STRONG>EXECUTION</STRONG></DT>
+<DD><DL>
+<DT><STRONG>-Z &lt;str&gt;</STRONG></DT>
+<DD>Run as user &lt;str&gt;
+</DD>
+<DT><STRONG>-D</STRONG></DT>
+<DD>Run in background (option -f implicit)
+</DD>
+</DL>
+
+<P>
+</DD>
+<DT><STRONG>MISC</STRONG></DT>
+<DD><DL>
+<DT><STRONG>-k</STRONG></DT>
+<DD>Dump a list of known RTP payload types. Note that, because of the useless functionality called "Dynamic RTP Payload", those values shouldn't be considered too much. The rtp_payload_type and codec association
+is in fact concorded through the Signaling messages (SIP, H.323, SCCP, ...), assigning new values also for those codecs already having a standard and predefined value
+</DD>
+<DT><STRONG>-h</STRONG></DT>
+<DD>Display a summary of the valid options and exit
+</DD>
+</DL>
+
+<P>
+</DD>
+</DL>
+
+<P>
+The files in the output directory have the following naming scheme: The set of files with pattern <SPAN  CLASS="textit">rtp.x.*</SPAN> refer to the rtpbreak execution number <SPAN  CLASS="textit">x</SPAN>, the subset of files with pattern <SPAN  CLASS="textit">rtp.x.y.*</SPAN> refer to the RTP session number <SPAN  CLASS="textit">y</SPAN> (of the rtpbreak execution number <SPAN  CLASS="textit">x</SPAN>). At each execution and at each RTP session detection, <SPAN  CLASS="textit">x</SPAN> and <SPAN  CLASS="textit">y</SPAN> are respectively incremented. The set of output files of the rtpbreak execution number <SPAN  CLASS="textit">x</SPAN> is organized as follows:
+<DL>
+<DT><STRONG>rtp.x.txt</STRONG></DT>
+<DD>The rtpbreak execution log, always generated
+</DD>
+<DT><STRONG>rtp.x.noise.pcap</STRONG></DT>
+<DD>The noise packets, generated with option <SPAN  CLASS="textit">-n</SPAN> enabled
+</DD>
+<DT><STRONG>rtp.x.y.*</STRONG></DT>
+<DD>For each detected RTP stream <SPAN  CLASS="textit">y</SPAN>:
+<DL>
+<DT><STRONG>rtp.x.y.raw</STRONG></DT>
+<DD>The  transported raw data of the RTP session <SPAN  CLASS="textit">y</SPAN>. Generated by default, can be disabled with option <SPAN  CLASS="textit">-w</SPAN> enabled
+</DD>
+<DT><STRONG>rtp.x.y.pcap</STRONG></DT>
+<DD>The reordered packets of the RTP session <SPAN  CLASS="textit">y</SPAN>. Generated by default, can be disabled with option <SPAN  CLASS="textit">-W</SPAN> enabled
+</DD>
+<DT><STRONG>rtp.x.y.txt</STRONG></DT>
+<DD>The <SPAN  CLASS="textit">y</SPAN>  RTP session log, always generated
+</DD>
+</DL>
+</DD>
+</DL>
+<H1><A NAME="SECTION00040000000000000000">
+Examples</A>
+</H1>
+In this section there are  some commented examples.
+
+<H2><A NAME="SECTION00041000000000000000">
+Record, mix and replay a VoIP call</A>
+</H2>
+Scope: We want to detect, reconstruct and decode a conversation between two VoIP Wireless phones, the final output should be a wav file. First of all, we sniff the packets with rtpbreak (fill gaps, sniff packets in promisc mode, gather packets from network interface wifi0, use './logz/' as output directory):
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ sudo src/rtpbreak -i wifi0 -g -m -d logz
+ + rtpbreak v1.3 running here!
+ + pid: 3580, date/time: 19/02/2008#09:49:21
+ + Configuration
+   + INPUT
+     Packet source: iface 'wifi0'
+     Force datalink header length: disabled
+   + OUTPUT
+     Output directory: 'logz'
+     RTP raw dumps: enabled
+     RTP pcap dumps: enabled
+     Fill gaps: enabled
+     Dump noise: disabled
+     Logfile: 'logz/rtp.0.txt'
+     Logging to stdout: enabled
+     Logging to syslog: disabled
+     Be verbose: disabled
+   + SELECT
+     Sniff packets in promisc mode: enabled
+     Add pcap filter: disabled
+     Expecting even destination UDP port: disabled
+     Expecting unprivileged source/destination UDP ports: disabled
+     Expecting RTP payload type: any
+     Expecting RTP payload length: any
+     Packet timeout: 10.00 seconds
+     Pattern timeout: 0.25 seconds
+     Pattern packets: 5
+   + EXECUTION
+     Running as user/group: root/root
+     Running daemonized: disabled
+ * You can dump stats sending me a SIGUSR2 signal
+ * Reading packets...
+ ! [rtp0] detected: pt=0(g711U) 192.168.0.30:2072 =&gt; 192.168.0.20:2074
+ ! [rtp1] detected: pt=0(g711U) 192.168.0.20:2074 =&gt; 192.168.0.30:2072
+ * [rtp1] probable reverse RTP stream: [rtp0]
+ + Status
+   Alive RTP Sessions: 2
+   Closed RTP Sessions: 0
+   Detected RTP Sessions: 2
+   Flushed RTP packets: 3358
+   Lost RTP packets: 122 (3.51%)
+   Noise (false positive) packets: 0
+ + [rtp1] stats: packets inbuffer=262 flushed=1673 lost=61(3.52%), call_length=1m2s
+ + [rtp0] stats: packets inbuffer=270 flushed=1685 lost=61(3.49%), call_length=1m2s
+ * [rtp1] closed: packets inbuffer=0 flushed=2800 lost=115(3.95%), call_length=1m28s
+ * [rtp0] closed: packets inbuffer=0 flushed=2819 lost=106(3.62%), call_length=1m28s
+--
+Caught SIGINT signal (2), cleaning up...
+--
+ + Status
+   Alive RTP Sessions: 0
+   Closed RTP Sessions: 2
+   Detected RTP Sessions: 2
+   Flushed RTP packets: 5619
+   Lost RTP packets: 221 (3.78%)
+   Noise (false positive) packets: 0
+ + No active RTP streams
+
+xenion@gollum:~/dev/rtpbreak-1.3$
+</PRE>
+
+<P>
+We've sent a SIGUSR2 signal to the rtpbreak process at call_length=1m2s, forcing a stats print. The final output directory content is the following:
+
+<P>
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ ls -1 logz
+rtp.0.0.pcap
+rtp.0.0.raw
+rtp.0.0.txt
+rtp.0.1.pcap
+rtp.0.1.raw
+rtp.0.1.txt
+rtp.0.txt
+xenion@gollum:~/dev/rtpbreak-1.3$
+</PRE>
+
+<P>
+Those are the two RTP sessions logs:
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ cat logz/rtp.0.0.txt 
+RTP stream id: rtp.0.0
+Packet source: iface  'wifi0'
+First seen packet: 19/02/2008#09:49:29 (pcap time)
+Stream peers: 192.168.0.30:2072 =&gt; 192.168.0.20:2074
+RTP ssrc: 1695569992
+RTP payload type: 0 (ITU-T G.711 PCMU)
+Last seen packet: 19/02/2008#09:50:57 (pcap time)
+Call length: 1m28s
+Flushed packets: 2819
+Lost packets: 106 (3.62%)
+RTP payload length: 240 bytes (fixed)
+xenion@gollum:~/dev/rtpbreak-1.3$ cat logz/rtp.0.1.txt 
+RTP stream id: rtp.0.1
+Packet source: iface  'wifi0'
+First seen packet: 19/02/2008#09:49:29 (pcap time)
+Stream peers: 192.168.0.20:2074 =&gt; 192.168.0.30:2072
+RTP ssrc: 112268413
+RTP payload type: 0 (ITU-T G.711 PCMU)
+Probable reverse RTP stream id: rtp.0.0
+Last seen packet: 19/02/2008#09:50:57 (pcap time)
+Call length: 1m28s
+Flushed packets: 2800
+Lost packets: 115 (3.95%)
+RTP payload length: 240 bytes (fixed)
+xenion@gollum:~/dev/rtpbreak-1.3$
+</PRE>
+
+<P>
+Now, we've to decode, mix and replay this recorded call:
+
+<P>
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ sox -r8000 -c1 -t ul logz/rtp.0.0.raw -t wav logz/0.wav
+xenion@gollum:~/dev/rtpbreak-1.3$ sox -r8000 -c1 -t ul logz/rtp.0.1.raw -t wav logz/1.wav
+xenion@gollum:~/dev/rtpbreak-1.3$ sox -m logz/0.wav logz/1.wav logz/call.wav
+xenion@gollum:~/dev/rtpbreak-1.3$ mplayer logz/call.wav
+</PRE>
+
+<P>
+
+<H2><A NAME="SECTION00042000000000000000">
+Analyze an RTP session</A>
+</H2>
+Scope: We want to analyze a pcap file with some RTP streams, using the most aggressive configuration of the detection heuristics. First of all, we reconstruct the RTP streams with rtpbreak:
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ rtpbreak -P2 -t100 -T100 -d logz -r h323.pcap  
+ + rtpbreak v1.3 running here!
+ + pid: 4613, date/time: 19/02/2008#10:18:54
+ + Configuration
+   + INPUT
+     Packet source: rxfile 'h323.pcap'
+     Force datalink header length: disabled
+   + OUTPUT
+     Output directory: 'logz'
+     RTP raw dumps: enabled
+     RTP pcap dumps: enabled
+     Fill gaps: disabled
+     Dump noise: disabled
+     Logfile: 'logz/rtp.1.txt'
+     Logging to stdout: enabled
+     Logging to syslog: disabled
+     Be verbose: disabled
+   + SELECT
+     Sniff packets in promisc mode: disabled
+     Add pcap filter: disabled
+     Expecting even destination UDP port: disabled
+     Expecting unprivileged source/destination UDP ports: disabled
+     Expecting RTP payload type: any
+     Expecting RTP payload length: any
+     Packet timeout: 100.00 seconds
+     Pattern timeout: 100.00 seconds
+     Pattern packets: 2
+   + EXECUTION
+     Running as user/group: xenion/xenion
+     Running daemonized: disabled
+ * You can dump stats sending me a SIGUSR2 signal
+ * Reading packets...
+ ! [rtp0] detected: pt=102(?) 172.16.1.109:5004 =&gt; 172.16.1.105:5012
+ ! [rtp1] detected: pt=0(g711U) 172.16.1.105:5012 =&gt; 172.16.1.109:5004
+ * [rtp1] probable reverse RTP stream: [rtp0]
+ ! [rtp2] detected: pt=31(h261) 172.16.1.109:5006 =&gt; 172.16.1.105:5014
+ * eof reached.
+--
+Caught SIGTERM signal (15), cleaning up...
+--
+ * [rtp2] closed: packets inbuffer=0 flushed=2286 lost=0(0.00%), call_length=4m10s
+ * [rtp1] closed: packets inbuffer=0 flushed=4465 lost=0(0.00%), call_length=4m8s
+ * [rtp0] closed: packets inbuffer=0 flushed=6254 lost=0(0.00%), call_length=4m10s
+ + Status
+   Alive RTP Sessions: 0
+   Closed RTP Sessions: 3
+   Detected RTP Sessions: 3
+   Flushed RTP packets: 13005
+   Lost RTP packets: 0 (0.00%)
+   Noise (false positive) packets: 70
+ + No active RTP streams
+
+xenion@gollum:~/dev/rtpbreak-1.3$
+</PRE>
+ The output directory content, after running examples 1 and 2, should be the following:
+
+<P>
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ ls -1 logz
+0.wav
+1.wav
+call.wav
+rtp.0.0.pcap
+rtp.0.0.raw
+rtp.0.0.txt
+rtp.0.1.pcap
+rtp.0.1.raw
+rtp.0.1.txt
+rtp.0.txt
+rtp.1.0.pcap
+rtp.1.0.raw
+rtp.1.0.txt
+rtp.1.1.pcap
+rtp.1.1.raw
+rtp.1.1.txt
+rtp.1.2.pcap
+rtp.1.2.raw
+rtp.1.2.txt
+rtp.1.txt
+xenion@gollum:~/dev/rtpbreak-1.3$
+</PRE>
+The set of files of the second rtpbreak execution have prefix <SPAN  CLASS="textit">rtp.1</SPAN>. Those are the three RTP sessions logs:
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ cat logz/rtp.1.0.txt
+RTP stream id: rtp.1.0
+Packet source: rxfile 'h323.pcap'
+First seen packet: 14/11/2006#17:57:29 (pcap time)
+Stream peers: 172.16.1.109:5004 =&gt; 172.16.1.105:5012
+RTP ssrc: 268399165
+RTP payload type: 102 (Unknown)
+Last seen packet: 14/11/2006#18:01:39 (pcap time)
+Call length: 4m10s
+Flushed packets: 6254
+Lost packets: 0 (0.00%)
+RTP payload length: 65 bytes (fixed)
+xenion@gollum:~/dev/rtpbreak-1.3$ cat logz/rtp.1.1.txt
+RTP stream id: rtp.1.1
+Packet source: rxfile 'h323.pcap'
+First seen packet: 14/11/2006#17:57:29 (pcap time)
+Stream peers: 172.16.1.105:5012 =&gt; 172.16.1.109:5004
+RTP ssrc: 1910395951
+RTP payload type: 0 (ITU-T G.711 PCMU)
+Probable reverse RTP stream id: rtp.1.0
+Last seen packet: 14/11/2006#18:01:37 (pcap time)
+Call length: 4m8s
+Flushed packets: 4465
+Lost packets: 0 (0.00%)
+RTP payload length: 240 bytes (fixed)
+xenion@gollum:~/dev/rtpbreak-1.3$ cat logz/rtp.1.2.txt
+RTP stream id: rtp.1.2
+Packet source: rxfile 'h323.pcap'
+First seen packet: 14/11/2006#17:57:29 (pcap time)
+Stream peers: 172.16.1.109:5006 =&gt; 172.16.1.105:5014
+RTP ssrc: 267301810
+RTP payload type: 31 (ITU-T H.261)
+Last seen packet: 14/11/2006#18:01:39 (pcap time)
+Call length: 4m10s
+Flushed packets: 2286
+Lost packets: 0 (0.00%)
+RTP payload length: 945 bytes (variable, this is the last seen)
+xenion@gollum:~/dev/rtpbreak-1.3$
+</PRE>
+
+<P>
+Now, we completely dissect the first packet of the third RTP session with tshark:
+
+<P>
+<PRE>
+xenion@gollum:~/dev/rtpbreak-1.3$ cat logz/rtp.1.2.txt | grep "Stream peers"
+Stream peers: 172.16.1.109:5006 =&gt; 172.16.1.105:5014
+xenion@gollum:~/dev/rtpbreak-1.3$ tshark -r logz/rtp.1.2.pcap -d udp.port==5006,rtp -c 1 -V
+Frame 1 (1073 bytes on wire, 1073 bytes captured)
+    Arrival Time: Nov 14, 2006 17:57:29.972300000
+    [Time delta from previous captured frame: 0.000000000 seconds]
+    [Time delta from previous displayed frame: 0.000000000 seconds]
+    [Time since reference or first frame: 0.000000000 seconds]
+    Frame Number: 1
+    Frame Length: 1073 bytes
+    Capture Length: 1073 bytes
+    [Frame is marked: False]
+    [Protocols in frame: eth:ip:udp:rtp:h261]
+Ethernet II, Src: Dell_15:09:a6 (00:12:3f:15:09:a6), Dst: Dell_ca:ec:cd (00:14:22:ca:ec:cd)
+    Destination: Dell_ca:ec:cd (00:14:22:ca:ec:cd)
+        Address: Dell_ca:ec:cd (00:14:22:ca:ec:cd)
+        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+    Source: Dell_15:09:a6 (00:12:3f:15:09:a6)
+        Address: Dell_15:09:a6 (00:12:3f:15:09:a6)
+        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+    Type: IP (0x0800)
+Internet Protocol, Src: 172.16.1.109 (172.16.1.109), Dst: 172.16.1.105 (172.16.1.105)
+    Version: 4
+    Header length: 20 bytes
+    Differentiated Services Field: 0x10 (DSCP 0x04: Unknown DSCP; ECN: 0x00)
+        0001 00.. = Differentiated Services Codepoint: Unknown (0x04)
+        .... ..0. = ECN-Capable Transport (ECT): 0
+        .... ...0 = ECN-CE: 0
+    Total Length: 1059
+    Identification: 0x0000 (0)
+    Flags: 0x04 (Don't Fragment)
+        0... = Reserved bit: Not set
+        .1.. = Don't fragment: Set
+        ..0. = More fragments: Not set
+    Fragment offset: 0
+    Time to live: 64
+    Protocol: UDP (0x11)
+    Header checksum: 0xdbc3 [correct]
+        [Good: True]
+        [Bad : False]
+    Source: 172.16.1.109 (172.16.1.109)
+    Destination: 172.16.1.105 (172.16.1.105)
+User Datagram Protocol, Src Port: wsm-server (5006), Dst Port: 5014 (5014)
+    Source port: wsm-server (5006)
+    Destination port: 5014 (5014)
+    Length: 1039
+    Checksum: 0x5f17 [incorrect, should be 0x270c (maybe caused by "UDP checksum offload"?)]
+        [Good Checksum: False]
+        [Bad Checksum: True]
+Real-Time Transport Protocol
+    10.. .... = Version: RFC 1889 Version (2)
+    ..0. .... = Padding: False
+    ...0 .... = Extension: False
+    .... 0000 = Contributing source identifiers count: 0
+    0... .... = Marker: False
+    Payload type: ITU-T H.261 (31)
+    Sequence number: 42926
+    Timestamp: 3003
+    Synchronization Source identifier: 0x0feeb3b2 (267301810)
+ITU-T Recommendation H.261
+    Start bit position: 0
+    End bit position: 2
+    Intra frame encoded data flag: False
+    Motion vector flag: True
+    GOB Number: 0
+    Macroblock address predictor: 0
+    Quantizer: 0
+    Horizontal motion vector data: 0
+    Vertical motion vector data: 0
+    H.261 stream: 00010006000113220300C0300DFF7FD1019B8103881035C0...
+
+xenion@gollum:~/dev/rtpbreak-1.3$
+</PRE>
+The wrong UDP checksum comes from the original network packet, rtpbreak only reorders the network packets of each RTP stream. As we did, rtpbreak can be used together with tshark/wireshark to handle complex needs.
+
+<P>
+
+<H2><A NAME="SECTION00043000000000000000">
+Particular scenarios</A>
+</H2>
+
+<P>
+Scope: We want to (successfully) handle some particular scenarios. This is a list of problem description, (probable) cause and (hopefully) solution.
+
+<OL>
+<LI><DL>
+<DT><STRONG>Problem</STRONG></DT>
+<DD>An improbable high number of RTP sessions and noise packets is detected.
+</DD>
+<DT><STRONG>Cause</STRONG></DT>
+<DD>There is some type of silence suppression.
+</DD>
+<DT><STRONG>Solution</STRONG></DT>
+<DD>Dilate the timeouts: <PRE>rtpbreak -i eth0 -n -t100 -T100
+</PRE>
+</DD>
+</DL>
+
+<P>
+</LI>
+<LI><DL>
+<DT><STRONG>Problem</STRONG></DT>
+<DD>An expected RTP session is not recognized and some noise packets are detected.
+</DD>
+<DT><STRONG>Cause</STRONG></DT>
+<DD>The conversation has been immediately terminated.
+</DD>
+<DT><STRONG>Solution</STRONG></DT>
+<DD>Reduce the number of required packets for the multiple packets pattern: <PRE>rtpbreak -i eth0 -n -P2
+</PRE>
+</DD>
+</DL>
+
+<P>
+</LI>
+<LI><DL>
+<DT><STRONG>Problem</STRONG></DT>
+<DD>The expected RTP sessions are not recognized.
+</DD>
+<DT><STRONG>Cause</STRONG></DT>
+<DD>The protocol is not RTP, the network interface is not in promisc mode, the conversation is very disturbed, the conversation was immediately terminated.
+</DD>
+<DT><STRONG>Solution</STRONG></DT>
+<DD>Dilate the timeouts and reduce the number of required packets for the multiple packets pattern: <PRE>rtpbreak -i eth0 -m -n -P2 -t100 -T100
+</PRE> This is the most aggressive (and computationally expensive) configuration of the detection heuristics and will always detect any RTP session.
+</DD>
+</DL>
+
+<P>
+</LI>
+</OL>
+
+<P>
+
+<H1><A NAME="SECTION00050000000000000000">
+How it works</A>
+</H1>
+
+<P>
+The RTP sessions are composed by an ordered sequence of RTP packets. Those packets transport the Real Time data using the UDP transport protocol. The RTP packets must respect some well defined rules in order to be considered valid, this characteristic allows us to define a pattern on the single packet that is used to discriminate the captured network traffic from packets that can be RTP and those that securely are not. The fixed RTP header has this format:
+
+<P>
+<PRE>
+ 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
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|V=2|P|X|  CC   |M|     PT      |       sequence number         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                           timestamp                           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|           synchronization source (SSRC) identifier            |
++=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+|            contributing source (CSRC) identifiers             |
+|                             ....                              |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+</PRE>
+
+<P>
+The following checks are performed (on each sniffed packet):
+
+<OL>
+<LI>Destination UDP port: The destination UDP port must be even, as specified in [rfc1889]. Beyond this, it must be greater than 1024. This because in the UDP and TCP transport  protocols  the ports &lt;= 1024 are considered privileged and   they can't be used by user applications, like VoIP clients.
+</LI>
+<LI>Minimal packet size: The UDP payload size must be greater than 12 bytes, this is the size of
+  the fixed header always present in any RTP packet.
+</LI>
+<LI>RTP version: The RTP protocol version always used is 2, so the value of the V field
+  in the fixed RTP header must be equal to 2.
+</LI>
+<LI>Padding bit: RTP allows to append some bytes as packet trailer, that must be ignored.   The number of those bytes is specified exactly in the last packet byte. The   P field in the fixed RTP header indicates if this functionality is active.  If active, the RTP payload size is adjusted, checking it to be greater than 0.
+</LI>
+<LI>CSRC list:   RTP allows the RTP Mixer to insert a list of contributing sources. This
+  list, if present, follows immediately the fixed RTP header and it's
+  composed by addresses (of 32 bits), their number is indicated
+  by the CC field in the fixed RTP header. If present, the RTP payload 
+  size is adjusted, checking it to be greater than 0.
+</LI>
+<LI>Extension bit: RTP allows to extend the fixed RTP header. If present, this extension
+  follows the fixed RTP header and the optional CSRC list. His format
+  follows:
+<PRE>
+ 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
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      defined by profile       |           length              |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        header extension                       |
+|                             ....                              |
+</PRE>
+
+<P>
+The length field indicates the extension size, header of the extension excluded. His presence is indicated by the X field value. If active, the RTP payload size is adjusted, checking it to be greater than 0.
+
+<P>
+</LI>
+</OL>
+
+<P>
+The UDP packets passing those checks are considered like 
+"maybe RTP" packets. Note that the IP and UDP packet checksums aren't checked because quite often they're erroneously computed by VoIP clients. The UDP packets passing those checks are compared with the already detected RTP sessions (this is called pattern over multiple packets).  The comparison is done considering the following informations:
+
+<OL>
+<LI>SSRC: The value of the SSRC field in the fixed RTP header indicates the 
+  unique identifier of the Sender of the session. His value is constant
+  in all RTP packets of the same session.
+</LI>
+<LI>IP addresses and UDP ports: The IP addresses and the UDP ports of the Sender and Receiver are constant
+  in all RTP packets of the same session.
+</LI>
+<LI>Sequence number: The seq field in the fixed RTP header indicates the packet sequence number,
+  a value that isn't necessarily initialized to 1 but that it's strictly
+  increasing in RTP packets of the same session. It's considered a window of
+  acceptable values for each session, that changes dynamically.
+  This allows to consider the eventuality that some RTP packets may have been lost.
+</LI>
+<LI>Timestamp: The ts field in the fixed RTP header indicates the sampling timestamp
+  of the first byte of the RTP payload, a value strictly increasing in
+  RTP packets of the same session. Also in this case it's considered a window
+  of acceptable values for each session, that changes dynamically.
+  This allows to consider the eventuality that some RTP packets may have been lost.
+</LI>
+</OL>
+
+<P>
+If it's identified a possible session, the UDP packet is inserted in his buffer. If this doesn't happen, a new one is created. When to a session  are assigned a minimal set of UDP packets, it's considered valid  and any UDP packet in his buffer is considered definitely RTP. This must  happen before a timeout, after that the session is considered a false  positive (noise packets) and destroyed.
+
+<P>
+
+<H1><A NAME="SECTION00060000000000000000">
+Dependencies and compilation</A>
+</H1>
+This is a Unix-oriented application written in C. The compilation requires a C compiler like gcc and the following libs: libpcap (&ge;0.7), libnet (&ge;1.1). In debian, you need the following packages (or higher versions):
+
+<UL>
+<LI>libnet1
+</LI>
+<LI>libnet1-dev
+</LI>
+<LI>libpcap0.7
+</LI>
+<LI>libpcap0.7-dev
+</LI>
+</UL>
+
+<P>
+To compile, type "make" in the top directory.
+
+<P>
+In order to decode the RTP streams with <SPAN  CLASS="textit">sox</SPAN>, you need <SPAN  CLASS="textit">sox</SPAN> with the support for the required formats. In debian, you need the following packages:
+
+<P>
+
+<UL>
+<LI>sox
+</LI>
+<LI>libsox-fmt-all
+</LI>
+</UL>
+
+<P>
+
+<H1><A NAME="SECTION00070000000000000000"></A>
+<A NAME="Links"></A>
+<BR>
+Links
+</H1>
+
+<UL>
+<LI>Antifork: <A NAME="tex2html1"
+  HREF="http://www.antifork.org">http://www.antifork.org</A>
+</LI>
+<LI>xenion headquarter: <A NAME="tex2html2"
+  HREF="http://xenion.antifork.org">http://xenion.antifork.org</A>
+</LI>
+<LI>rtpbreak home: <A NAME="tex2html3"
+  HREF="http://xenion.antifork.org/rtpbreak">http://xenion.antifork.org/rtpbreak</A>
+</LI>
+</UL>
+
+<P>
+<BR><HR>
+<ADDRESS>
+xenion - Thu Feb 28 15:22:15 CET 2008
+</ADDRESS>
+</BODY>
+</HTML>
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..845a6a2
--- /dev/null
@@ -0,0 +1,41 @@
+# src Makefile.
+
+include VERSION
+
+CC       = cc
+CFLAGS   = -Wall -O3  # debug: put -ggdb instead of -O3
+LDFLAGS  =
+LIBS     = -lpcap -lnet 
+DEFS     = 
+
+#####################################################################
+
+
+all: header
+       $(CC) -c -DVERSION=\"$(VERSION)\" $(CFLAGS) $(DEFS) main.c
+       $(CC) -c $(CFLAGS) $(DEFS) common.c
+       $(CC) -c $(CFLAGS) $(DEFS) net.c
+       $(CC) $(LDFLAGS) main.o common.o net.o -o rtpbreak $(LIBS)
+       @echo "%"
+
+header:
+       @echo "%"
+       @echo "%  Compiling rtpbreak v$(VERSION)"
+       @echo "%"
+       @echo "%  CC...................: $(CC)"
+       @echo "%  CFLAGS...............: $(CFLAGS)"
+       @echo "%  LDFLAGS..............: $(LDFLAGS)"
+       @echo "%  LIBS.................: $(LIBS)"
+       @echo "%  DEFS.................: $(DEFS)"
+       @echo "%"
+
+indent:
+       astyle --convert-tabs --style=gnu *.[hc]
+
+srcheaders:
+       update_src_header.sh *h *c
+
+clean:
+       @rm -f rtpbreak *.[hc].orig rtp.*.txt rtp.*.*.* *.o *.wav *~~
+
+#eof
diff --git a/src/VERSION b/src/VERSION
new file mode 100644 (file)
index 0000000..f601f26
--- /dev/null
@@ -0,0 +1 @@
+VERSION=1.3a
diff --git a/src/bpf.h b/src/bpf.h
new file mode 100644 (file)
index 0000000..145009c
--- /dev/null
+++ b/src/bpf.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * 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 acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 REGENTS OR 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.
+ *
+ *      @(#)bpf.h       7.1 (Berkeley) 5/7/91
+ *
+ */
+
+
+#define AP_DLT_NULL  0 /* no link-layer encapsulation */
+#define AP_DLT_EN10MB  1 /* Ethernet (10Mb) */
+#define AP_DLT_EN3MB  2 /* Experimental Ethernet (3Mb) */
+#define AP_DLT_AX25  3 /* Amateur Radio AX.25 */
+#define AP_DLT_PRONET  4 /* Proteon ProNET Token Ring */
+#define AP_DLT_CHAOS  5 /* Chaos */
+#define AP_DLT_IEEE802  6 /* IEEE 802 Networks */
+#define AP_DLT_ARCNET  7 /* ARCNET */
+#define AP_DLT_SLIP  8 /* Serial Line IP */
+#define AP_DLT_PPP  9 /* Point-to-point Protocol */
+#define AP_DLT_FDDI  10 /* FDDI */
+#define AP_DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */
+
+#if defined(__OpenBSD__)
+#define AP_DLT_LOOP  12 /* old DLT_LOOP interface :4 byte offset */
+#define AP_DLT_RAW              14      /* raw IP: 0 byte offset */
+#else
+#define AP_DLT_RAW              12      /* raw IP: 0 byte offset*/
+#define AP_DLT_LOOP             108
+#endif
+
+#define AP_DLT_ENC  13
+#define AP_DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */
+#define AP_DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */
+#define AP_DLT_ATM_CLIP  19 /* Linux Classical-IP over ATM */
+#define AP_DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */
+#define AP_DLT_PPP_ETHER 51 /* PPP over Ethernet */
+#define AP_DLT_C_HDLC  104 /* Cisco HDLC */
+#define AP_DLT_CHDLC  DLT_C_HDLC
+#define AP_DLT_IEEE802_11 105 /* IEEE 802.11 wireless */
+#define AP_DLT_LINUX_SLL 113
+#define AP_DLT_LTALK  114
+#define AP_DLT_ECONET  115
+#define AP_DLT_IPFILTER  116
+#define AP_DLT_PFLOG  117
+#define AP_DLT_CISCO_IOS 118
+#define AP_DLT_PRISM_HEADER 119
+#define AP_DLT_AIRONET_HEADER 120
diff --git a/src/common.c b/src/common.c
new file mode 100644 (file)
index 0000000..22e37a4
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * common.c by xenion -- 2008-05-05 -- v.fdb23b830c7d63aa1208dfdad3ccf845
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <dirent.h>
+#include "common.h"
+
+
+/* globals */
+
+static int verbose_enabled = 0;
+static FILE *f = NULL;
+static int syslog_enabled = 0;
+static int stdout_enabled = 0;
+static char line_buffer[LINE_BUFFER_MAX] = {0, };
+
+
+/* extern */
+
+extern void cleanup();
+
+
+/* protos */
+
+void sigdie(int signo);
+
+
+/*******************************************/
+
+
+void enable_verbose()
+{
+  verbose_enabled = 1;
+}
+
+
+void disable_verbose()
+{
+  verbose_enabled = 0;
+}
+
+
+void enable_syslog()
+{
+  syslog_enabled = 1;
+}
+
+
+void disable_syslog()
+{
+  syslog_enabled = 0;
+}
+
+
+void enable_stdout()
+{
+  stdout_enabled = 1;
+}
+
+
+void disable_stdout()
+{
+  stdout_enabled = 0;
+}
+
+
+void open_logfile(char *pathname)
+{
+  if (f)
+    SAFE_FCLOSE(f);
+
+  if ((f =  fopen(pathname, "a")) == NULL)
+    FATAL("fopen(): %s", strerror(errno));
+}
+
+
+void close_logfile()
+{
+  if (f != NULL && f != stdout && f != stderr)
+    SAFE_FCLOSE(f);
+}
+
+
+void
+logthis(char *file, const char *function, int line, int ifverbose,int h, int n, const char *fmt, ...)
+{
+  u_int32_t len;
+  va_list ap;
+
+
+  // The program must first execute the macro va_start within the body
+  // of the function to initialize an object with context information.
+
+  va_start(ap, fmt);
+
+  if (ifverbose && verbose_enabled == 0)
+    return;
+
+  if (f == NULL) // stdout by default...
+    f = stdout;
+  if (f == stdout) // prevent double logging to stdout...
+    disable_stdout();
+
+  if (h)
+    {
+      line_buffer[0] = '\0';
+      if (verbose_enabled)
+        snprintf(line_buffer,LINE_BUFFER_MAX,"%s %s:%d:",strtime(time(NULL)),function, line);
+    }
+
+  len = strlen(line_buffer);
+
+  vsnprintf(line_buffer+len,LINE_BUFFER_MAX-len,fmt, ap);
+
+  len = strlen(line_buffer);
+
+  if (len >= LINE_BUFFER_MAX-1)
+    {
+      // we reached the end-1... probably the string was truncated. we keep 1 byte for trailing '\n', inserted in if(n) ....
+      line_buffer[0] = '\0';
+      FATAL("line buffer full");
+    }
+
+
+  if (n)
+    {
+
+      line_buffer[len] = '\n';
+      line_buffer[len+1] = 0;
+
+      fprintf(f, "%s", line_buffer);
+      fflush(f);
+
+      if (syslog_enabled)
+        syslog(LOG_DAEMON|LOG_INFO, line_buffer);
+
+      if (stdout_enabled)
+        printf("%s", line_buffer);
+
+      line_buffer[0] = 0;
+    }
+
+  va_end(ap);
+}
+
+
+void
+fatal(char *file, const char *function, int line, const char *fmt, ...)
+{
+  va_list         ap;
+
+
+  // The program must first execute the macro va_start within the body
+  // of the function to initialize an object with context information.
+
+  va_start(ap, fmt);
+
+  if (f == NULL)
+    f = stdout;
+  if (f == stdout)
+    disable_stdout();
+  disable_verbose();
+
+  snprintf(line_buffer,LINE_BUFFER_MAX,"%s Fatal error at %s:%d:%s: ",strtime(time(NULL)),file, line, function);
+  vsnprintf(line_buffer+strlen(line_buffer),LINE_BUFFER_MAX-strlen(line_buffer),fmt, ap);
+  snprintf(line_buffer+strlen(line_buffer),LINE_BUFFER_MAX-strlen(line_buffer),"; exit forced.");
+
+  if (strlen(line_buffer) >= LINE_BUFFER_MAX-1)
+    {
+      FATAL("line buffer full");
+    }
+
+  fprintf(f,"--\n%s\n--\n", line_buffer);
+
+  if (syslog_enabled)
+    syslog(LOG_DAEMON | LOG_ERR,"%s", line_buffer);
+
+  if (stdout_enabled)
+    printf("--\n%s\n--\n", line_buffer);
+
+  va_end(ap);
+
+  sig_unlock(); // if lock, unlock. else, nothing changes.
+  sigdie(-1);
+}
+
+
+void
+sigdie(int signo)
+{
+  static int loop = 0;
+
+
+// if loop==1 happens, there's an infinite loop (and a bug somewhere ...). prevent it exiting. better than nothing...
+  if (loop == 0)
+    loop = 1;
+  else
+    exit(1);
+
+// if signo == -1, it's a direct call from function fatal: less output
+// messages looks better.
+
+  if (signo != -1)
+    {
+      LOG(1,1,"--");
+      LOG(1,1,"Caught %s signal (%d), cleaning up...", SIG_NAME(signo), signo);
+      LOG(1,1,"--");
+    }
+
+  cleanup();
+
+  LOG(1,1,"");
+  // questa deve essere l'ultima cosa prima della exit.
+  disable_syslog();
+  close_logfile();
+  disable_stdout();
+
+  exit(signo == SIGTERM ? 0 : 1); // 0 == ok, 1 == err
+}
+
+
+void init_sighandlers()
+{
+  signal(SIGSEGV, sigdie);
+  signal(SIGTERM, sigdie);
+  signal(SIGINT, sigdie);
+  signal(SIGUSR1, sigdie);
+}
+
+
+void sig_lock()
+{
+  signal(SIGTERM, SIG_IGN);
+  signal(SIGINT, SIG_IGN);
+  signal(SIGUSR1, SIG_IGN);
+}
+
+
+void sig_unlock()
+{
+  signal(SIGTERM, sigdie);
+  signal(SIGINT, sigdie);
+  signal(SIGUSR1, sigdie);
+}
+
+
+char *
+strtime(time_t t)
+{
+  struct tm      *mytm;
+  static char s[20];
+
+
+  mytm = localtime(&t);
+  strftime(s, 20, "%d/%m/%Y#%H:%M:%S", mytm);
+  return s;
+}
+
+
+void drop_privs(char *user, char *group)
+{
+  struct passwd *p;
+  struct group *g;
+  int uid, gid;
+
+
+  if (!user && !group)
+    FATAL("(user == NULL && group == NULL)");
+
+  if ((p = getpwnam(user)) == NULL)
+    FATAL("(getpwnam(...) == NULL): user not found");
+
+  uid = p->pw_uid;
+  gid = p->pw_gid;
+
+  if (group)
+    {
+      if ( (g = getgrnam(group)) == NULL)
+        FATAL("(getgrnam(...) == NULL): group not found");
+      gid = g->gr_gid;
+    }
+
+
+  if (setgid(gid) == -1)
+    FATAL("setgid(...): %s",strerror(errno));
+
+  if (setuid(uid) == -1)
+    FATAL("setuid(...): %s",strerror(errno));
+
+  if (setegid(gid) == -1)
+    FATAL("setegid(...): %s",strerror(errno));
+
+  if (seteuid(uid) == -1)
+    FATAL("seteuid(...): %s",strerror(errno));
+}
+
+
+void daemonize()
+{
+  setsid();
+  if (fork())
+    exit(0);
+}
+
+
+int exists(char *pathname)
+{
+  struct stat st;
+  int z;
+
+
+  z = stat(pathname, &st);
+
+  if (z == 0)
+    return 1;
+
+  if (errno == ENOENT)
+    return 0;
+
+  return -1; // maybe exists, maybe perm problems....
+}
+
+
+char *get_next_name(char *directory, char *prefix, char *suffix, int *i)
+{
+  int count;
+  static char pathname[PATH_MAX];
+  struct stat st;
+
+
+  if (directory[0] != '\0' && // if directory specified...
+      !isdirectory(directory))
+    FATAL("'%s' is not a valid directory, check pathname and permissions", directory);
+
+  for (count = 0;;)
+    {
+      snprintf(pathname, PATH_MAX, "%s/%s%d%s", directory, prefix, count, suffix);
+      if (stat(pathname, &st) == -1)
+        {
+          if (errno == ENOENT)
+            break;
+          else
+            {
+              if (i)
+                *i = -1;
+              return NULL;
+            }
+        }
+      count++;
+    }
+
+  if (i)
+    *i = count;
+
+  return pathname;
+}
+
+
+int isdirectory(char *pathname)
+{
+  struct stat st;
+
+  if (stat(pathname, &st) != 0 || !S_ISDIR(st.st_mode))
+    return 0;
+  else return 1;
+}
+
+
+int mystrnstr(char *str1, char *str2, int str1len)
+{
+  int str2len, i;
+
+  str2len = strlen(str2);
+
+  if (str2len > str1len)
+    return -1;
+
+  for (i = 0; i <= str1len - str2len; i++)
+    if (strncmp(str1+i, str2, str2len) == 0)
+      return i;
+
+  return -1;
+}
+
+
+char *trim(char *str)
+{
+  char *p;
+  int i;
+
+//  LOG(1,1,"input is '%s'", str);
+
+  for (p = str;*p != 0 && (*p == ' ' || *p == '\t');p++);
+  if (*p == 0)   // nothing to do!
+    {
+      //    LOG(1,1,"output is '%s'", p);
+      return p;
+    }
+
+  for (i = strlen(p);i >= 0 && (p[i] == 0 || p[i] == '\t' || p[i] == ' ');i--);
+  if (i >= 0 && p[i] != 0)
+    p[i+1] = 0;
+
+//LOG(1,1,"output is '%s'", p);
+
+
+  return p;
+}
+
+
+int parse_token(char *data, u_int32_t datalen, char *delims, char *found)
+{
+  int i,j,l;
+
+//LOG(1,1,"parse_token:");
+//fwrite(data,1, datalen,stdout);
+//LOG(1,1,"-------------");
+
+  l = strlen(delims);
+  for (i = 0; i < datalen; i++)
+    {
+      for (j = 0; j < l; j++)
+        {
+          if (data[i] == delims[j])
+            break;
+        }
+      if (data[i] == delims[j])
+        break; // propagate...
+    }
+
+  if (i == datalen)
+    return -1;
+
+  if (found)
+    *found = data[i];
+
+  data[i] = 0;
+
+  return i+1;
+}
+
+
+int parse_line(char *data, u_int32_t datalen)
+{
+  int i;
+
+
+  if (datalen <= 0)
+    return -1;
+
+  if ((i = parse_token(data, datalen, "\n",NULL)) == -1)
+    return -1;
+
+  if (i > 1 && data[i -2] == '\r')
+    data[i-2] = 0;
+
+  return i;
+}
+
+
+char *str_char(unsigned char c)
+{
+  static char s[8];
+
+
+  if (c >= 32 && 126)
+    {
+      sprintf(s,"'%c' ", c);
+      return s;
+    }
+
+  switch (c)
+    {
+    case '\0':
+      return "'\\0'";
+    case '\r':
+      return "'\\r'";
+    case '\n' :
+      return "'\\n'";
+    default:
+      sprintf(s,"?%.3d", c);
+      return s;
+    }
+
+}
+
+
+void
+logmem(u_int8_t *p, u_int32_t len, u_int32_t cols, int format, char *lh)
+{
+  u_int32_t off,line,col;
+
+
+  if (format == 1 && cols != 1)
+    FATAL("with fmt == 1 you must use cols == 1");
+
+  if (!lh)
+    lh = "";
+
+  LOG(1,0,"%s+ Dumping memory from %p for %d bytes, cols: %d, fmt: ",lh, p,len, cols);
+
+  switch (format)
+    {
+    case 1:
+      LOG(0,1,"hex bin dec chr");
+      break;
+    case 2:
+      LOG(0,1,"hex");
+      break;
+    default:
+      FATAL("undefined format: %d", format);
+    }
+
+  for (off=0,col=0,line=0;off<len;off++)
+    {
+      if (col == 0)
+        {
+          if (line > 0)
+            LOG(0,1,"");
+          LOG(1,0,"%s| %p+%-8d",lh, p,off);
+        }
+
+      switch (format)
+        {
+        case 1:
+          LOG(0,0,"0x%.2x %d%d%d%d%d%d%d%d %.3d %s",p[off],p[off] & 0x80 ? 1 : 0,p[off] & 0x40 ? 1 : 0,p[off] & 0x20 ? 1 : 0,p[off] & 0x10 ? 1 : 0,p[off] & 0x08 ? 1 : 0,p[off] & 0x04 ? 1 : 0,p[off] & 0x02 ? 1 : 0,p[off] & 0x01 ? 1 : 0, p[off], str_char(p[off]));
+          break;
+        case 2:
+          LOG(0,0," %.2x",p[off]);
+          break;
+        default:
+          FATAL("undefined format: %d", format);
+        }
+
+      if (++col >= cols)
+        {
+          col = 0;
+          line++;
+        }
+    }
+
+  LOG(0,1,"");
+  LOG(1,1,"%s+ End", lh);
+}
+
+
+/* EOF*/
+
diff --git a/src/common.h b/src/common.h
new file mode 100644 (file)
index 0000000..385cf00
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * common.h by xenion -- 2008-05-05 -- v.1293c16fff21c9e111936bd906f13e1c
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+
+/* const */
+
+#define LINE_BUFFER_MAX 4096
+
+#ifndef PATH_MAX
+#define PATH_MAX        4096
+#endif
+
+
+/* macros */
+
+// returns 1 if a > b, -1 if a < b, 0 if a == b
+#define TIMEVAL_CMP(a, b) (            \
+   a.tv_sec > b.tv_sec ? 1 :           \
+   a.tv_sec < b.tv_sec ? -1 :          \
+   a.tv_usec > b.tv_usec ? 1 :         \
+   a.tv_usec < b.tv_usec ? -1 : 0 )
+
+#define TIMEVAL_SUB(a, b, result)                          \
+  do {                                                     \
+    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;          \
+    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;       \
+    if ((result)->tv_usec < 0) {                           \
+      --(result)->tv_sec;                                  \
+      (result)->tv_usec += 1000000;                        \
+    }                                                      \
+  } while (0)
+
+#define MAX(x,y) ( (x) > (y) ? (x) : (y))
+#define MIN(x,y) ( (x) < (y) ? (x) : (y))
+
+#define PERCENTAGE(x,y) ((y) == 0 ? 0 : (float)(x) * 100 / (y))
+
+#define LOG(h,n,fmt, ...) do { \
+   logthis(__FILE__, __FUNCTION__, __LINE__,0,h,n,fmt, ## __VA_ARGS__ );   \
+    } while(0)
+
+#define VLOG(h,n,fmt, ...) do { \
+           logthis(__FILE__, __FUNCTION__, __LINE__,1,h,n,fmt, ## __VA_ARGS__ );   \
+            } while(0)
+
+#define FATAL(x, ...) do {                                      \
+                   fatal(__FILE__, __FUNCTION__, __LINE__,x, ## __VA_ARGS__ );   \
+                   } while(0)
+
+#define SAFE_FREE(x) do { if (x) { free(x); x = NULL; }}while(0)
+#define SAFE_CLOSE(x) do { if(x != -1) { close(x) ; x = -1;}}while(0)
+#define SAFE_FCLOSE(x) do { if (x) { fclose(x); x = NULL; }}while(0)
+#define SAFE_FPRINTF(x, ...) do { if(x) fprintf(x, ## __VA_ARGS__ ); } while(0)
+#define SAFE_PDCLOSE(x) do { if (x) { pcap_dump_close(x); x = NULL; }}while(0)
+#define SAFE_STRDUP(x) (*x ? strdup(x) : NULL)
+
+#define SWITCH_VALUES(x,y,tmp) do { tmp=x; x=y; y=tmp; } while(0)
+
+#define STATIC_STRLEN(x) (sizeof(x)-1) // (sizeof("ciao")-1) == 4
+
+#define SIG_NAME(x) x == SIGURG  ? "SIGURG"  : \
+                    x == SIGPIPE ? "SIGPIPE" : \
+                    x == SIGQUIT ? "SIGQUIT" : \
+                    x == SIGINT  ? "SIGINT"  : \
+                    x == SIGTERM ? "SIGTERM" : \
+                    x == SIGHUP  ? "SIGHUP"  : \
+                    x == SIGSEGV ? "SIGSEGV" : \
+                    x == SIGBUS  ? "SIGBUS"  : \
+                    x == SIGUSR1 ? "SIGUSR1" : "UNKNOWN"
+
+
+/* protos */
+
+extern void fatal(char *file, const char *function, int line, const char *fmt, ...);
+extern void logthis(char *file, const char *function, int line, int ifverbose,int h, int n, const char *fmt, ...);
+extern void logmem(u_int8_t *p, u_int32_t len, u_int32_t cols, int format, char *lh);
+extern char *str_char(unsigned char c);
+extern void enable_verbose();
+extern void disable_verbose();
+extern void open_logfile(char *pathname);
+extern void init_sighandlers();
+extern void sig_lock();
+extern void sig_unlock();
+extern void close_logfile();
+extern char *strtime(time_t t);
+extern void drop_privs(char *user, char *group);
+extern void daemonize();
+extern int exists(char *pathname);
+extern void enable_syslog();
+extern void disable_syslog();
+extern void enable_stdout();
+extern void disable_stdout();
+extern char *get_next_name(char *directory, char *prefix, char *suffix, int *i);
+extern int isdirectory(char *pathname);
+extern char *trim(char *str);
+extern int parse_token(char *data, u_int32_t datalen, char *delims, char *found);
+extern int parse_line(char *data, u_int32_t datalen);
+extern int mystrnstr(char *str1, char *str2, int str1len);
+
+#endif
+
+
+/* eof */
+
diff --git a/src/ieee80211.h b/src/ieee80211.h
new file mode 100644 (file)
index 0000000..4bd2565
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * ieee80211.h by xenion -- 2008-05-05 -- v.c486a4662d73aaca28a52ba95febd8b3
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+// adapted from:
+//  $FreeBSD: src/sys/net80211/ieee80211.h,v 1.9.2.2 2006/08/10 06:07:49 sam Exp $
+
+/* does frame have QoS sequence control data */
+#define IEEE80211_QOS_HAS_SEQ(wh) \
+        (((wh)->i_fc[0] & \
+          (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \
+          (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS))
+
+#define IEEE80211_ADDR_LEN      6               /* size of 802.11 address */
+#define IEEE80211_FC0_TYPE_MASK                 0x0c
+#define IEEE80211_FC0_TYPE_DATA                 0x08
+#define IEEE80211_FC1_DIR_MASK                  0x03
+#define IEEE80211_FC1_DIR_DSTODS                0x03    /* AP ->AP  */
+#define IEEE80211_FC0_SUBTYPE_MASK              0xf0
+#define IEEE80211_FC0_SUBTYPE_QOS               0x80
+
+struct ieee80211_frame
+  {
+    u_int8_t        i_fc[2];
+    u_int8_t        i_dur[2];
+    u_int8_t        i_addr1[ETHER_ADDR_LEN];
+    u_int8_t        i_addr2[ETHER_ADDR_LEN];
+    u_int8_t        i_addr3[ETHER_ADDR_LEN];
+    u_int8_t        i_seq[2];
+    /* possibly followed by addr4[ETHER_ADDR_LEN]; */
+  };
+
+
+/* EOF */
+
+
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..3f4b3a7
--- /dev/null
@@ -0,0 +1,1481 @@
+/*
+ * main.c by xenion -- 2008-05-05 -- v.262c5cbb0ef3c107aae3316bca65296f
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+
+/* includes */
+
+#include <time.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+#include "queue.h"
+#include "rtp.h"
+#include "common.h"
+#include "net.h"
+#include "main.h"
+
+
+/* globals */
+
+struct rtp_streams_list rtp_streams;
+pcap_t *mypcap = NULL;
+pcap_dumper_t *pdump_noise = NULL;
+struct timeval pcap_time;
+u_int32_t pktcount = 0;
+int ndxlog = -1;
+int running = 0;
+char errbuf[PCAP_ERRBUF_SIZE];
+OPT o;
+
+
+/* protos */
+
+int dissect_ieee80211(struct pcap_pkt *ppkt, u_int32_t pktoff, u_int32_t pktlen);
+int dissect_eth(struct pcap_pkt *ppkt, u_int32_t pktoff, u_int32_t pktlen);
+int dissect_ip(struct pcap_pkt *ppkt, u_int32_t pktoff, u_int32_t pktlen);
+int dissect_udp(struct pcap_pkt *ppkt,u_int32_t pktoff, u_int32_t pktlen, addrs_t addrs);
+int dissect_rtp(struct pcap_pkt *ppkt,u_int32_t pktoff, u_int32_t pktlen, addrs_t addrs);
+char *find_stream_rtp_pt(int pt, int short_vals);
+void loop(int dlltype, int dllength);
+int main(int argc, char **argv);
+void            init_opt(int argc, char **argv);
+void help();
+void cleanup();
+int timeout(struct timeval *a, struct timeval *b, float t);
+struct rtp_stream_entry *rtp_search_stream(addrs_t addrs, rtp_hdr_t *rtphdr);
+int rtp_stream_ts_seq_check(struct rtp_stream_entry *rtp_stream);
+char *strtime(time_t t);
+void rtp_streams_init();
+void rtp_stream_add_pkt(struct rtp_stream_entry *rtp_stream, pktrtp_t *pktrtp);
+void rtp_stream_flush(struct rtp_stream_entry *rtp_stream, int buf_timeout);
+void rtp_stream_open_files(struct rtp_stream_entry *rtp_stream);
+struct rtp_stream_entry *rtp_stream_add(pktrtp_t *pktrtp, addrs_t addrs);
+void rtp_stream_close(struct rtp_stream_entry *rtp_stream);
+void rtp_streams_close();
+int rtp_pkt_handle(pktrtp_t *pktrtp, addrs_t addrs);
+void rtp_streams_timeout();
+void rtp_stream_search_rev(struct rtp_stream_entry *rtp_stream);
+void sig_stats_handler(int signo);
+void print_stream_stat(struct rtp_stream_entry *rtp_stream);
+
+
+/* extern */
+
+// here because in order to have this function defined,
+// I should add #define _XOPEN_SOURCE=600 that brokens
+// other things.
+float strtof(const char *nptr, char **endptr);
+
+
+/*******************************************/
+
+
+int rtp_stream_ts_seq_check(struct rtp_stream_entry *rtp_stream)
+{
+  struct rtpbuf_entry *rtpbuf;
+  rtp_hdr_t *rtphdr;
+  int64_t prev_ts,v;
+  int32_t prev_seq;
+
+
+  prev_seq = -1;
+  prev_ts = -1;
+
+  LIST_FOREACH(rtpbuf, &rtp_stream->pkts, l)
+  {
+    rtphdr = (rtp_hdr_t *)(rtpbuf->pktrtp.pcap.pkt + rtpbuf->pktrtp.hdroff);
+
+    if (prev_seq != -1 && (u_int16_t)(prev_seq+1) != ntohs(rtphdr->seq))
+      return -1;
+    prev_seq = ntohs(rtphdr->seq);
+
+    v = (u_int32_t)ntohl(rtphdr->ts);
+    if (v < rtp_stream->max_ts_seen) // maybe mod loop!!
+      v += ((u_int32_t)(0-1))+1;
+    //LOG(1,1,"ts: %llu",v);
+    if (prev_ts > v)
+      return -1;
+    prev_ts = v;
+  }
+
+  return 0;
+}
+
+
+int dissect_ieee80211(struct pcap_pkt *ppkt, u_int32_t pktoff, u_int32_t pktlen)
+{
+  struct ieee80211_frame *wh;
+  int32_t len;
+
+
+  if (pktlen < sizeof(struct ieee80211_frame))
+    {
+      LOG(1,1," * warning: broken ieee 802.11 frame");
+    }
+
+  wh = (struct ieee80211_frame *)(ppkt->pkt+pktoff);
+
+  len = sizeof(struct ieee80211_frame);
+
+  if ((wh->i_fc[0]&IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA)
+    return 0;
+
+  if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
+    len += IEEE80211_ADDR_LEN;
+  if (IEEE80211_QOS_HAS_SEQ(wh))
+    len += sizeof(u_int16_t);
+
+  len+=8;
+
+  if (len > pktlen) // this packet is something not interesting
+    {
+      return 0;
+    }
+
+  if ( ntohs(*((int32_t *)&ppkt->pkt[len-2])) == ETHERTYPE_IP)
+    return dissect_ip(ppkt,len,ppkt->hdr.caplen-len);
+
+  return 0;
+}
+
+
+int dissect_eth(struct pcap_pkt *ppkt, u_int32_t pktoff, u_int32_t pktlen)
+{
+  struct libnet_ethernet_hdr *eth;
+
+
+  if (pktlen < sizeof(struct libnet_ethernet_hdr))
+    {
+      LOG(1,1,"broken eth frame");
+      return 0;
+    }
+
+  eth = (struct libnet_ethernet_hdr *)ppkt->pkt+pktoff;
+
+  if (ntohs(eth->ether_type) == ETHERTYPE_IP)
+    return dissect_ip(ppkt,sizeof(struct libnet_ethernet_hdr),ppkt->hdr.caplen-sizeof(struct libnet_ethernet_hdr));
+
+  return 0;
+}
+
+
+int rtp_pkt_handle(pktrtp_t *pktrtp, addrs_t addrs)
+{
+  struct rtp_stream_entry *rtp_stream;
+  rtp_hdr_t *rtphdr;
+
+
+  rtphdr = (rtp_hdr_t *)(pktrtp->pcap.pkt + pktrtp->hdroff);
+
+  if (! (rtp_stream = rtp_search_stream(addrs, rtphdr)))
+    rtp_stream = rtp_stream_add(pktrtp, addrs);
+
+
+  rtp_stream_add_pkt(rtp_stream, pktrtp);
+  rtp_stream_flush(rtp_stream,o.timeout_pkt);
+
+  return 0;
+}
+
+
+int
+dissect_udp(struct pcap_pkt *ppkt, u_int32_t pktoff, u_int32_t pktlen, addrs_t addrs)
+{
+  struct libnet_udp_hdr *pktudp;
+  int32_t len;
+
+
+  if (pktlen < sizeof(struct udphdr))
+    return 0;
+
+  pktudp = (struct libnet_udp_hdr *) (ppkt->pkt +  pktoff);
+
+  len = pktlen - sizeof(struct udphdr);
+
+  if (len != ntohs(pktudp->uh_ulen)-sizeof(struct udphdr))
+    return 0;
+
+  addrs.type = ADDRS_TYPE_UDP;
+  addrs.srcport = ntohs(pktudp->uh_sport);
+  addrs.dstport = ntohs(pktudp->uh_dport);
+
+//  LOG(1,0,"ip: %s:%d > ",INET_NTOA(addrs.srcaddr),addrs.srcport);
+//  LOG(0,1,"%s:%d",INET_NTOA(addrs.dstaddr),addrs.dstport);
+
+  return dissect_rtp(ppkt,pktoff+sizeof(struct libnet_udp_hdr),len,addrs);
+}
+
+
+void
+loop(int dlltype,int dllength)
+{
+  struct pcap_pkt ppkt;
+
+
+  ppkt.dllength = dllength;
+  ppkt.dlltype = dlltype;
+
+  for (;;)
+    {
+      ppkt.pkt = (u_int8_t *)pcap_next(mypcap, &ppkt.hdr);
+
+      if (!ppkt.pkt)
+        {
+          if (o.iface)
+            continue;
+
+          if (o.rxfile)
+            {
+              LOG(1,1," * eof reached.");
+              break;
+            }
+        }
+
+      pktcount++;
+      //      LOG(1,1,"pktcount: %d", pktcount);
+
+      if (ppkt.hdr.caplen != ppkt.hdr.len)
+        {
+          LOG(1,1,"warning: frame length is %d but caplength is %d (should not happen)",
+              ppkt.hdr.len, ppkt.hdr.caplen);
+          continue;
+        }
+
+      if (ppkt.hdr.caplen < dllength)
+        {
+          LOG(1,1,"warning: broken datalink frame");
+          continue;
+        }
+
+
+      pcap_time = ppkt.hdr.ts;
+
+      switch (dlltype)
+        {
+        case AP_DLT_EN10MB:
+          dissect_eth(&ppkt,0,ppkt.hdr.caplen);
+          break;
+        case AP_DLT_IEEE802_11:
+          dissect_ieee80211(&ppkt,0,ppkt.hdr.caplen);
+          break;
+        default:
+          dissect_ip(&ppkt,dllength,ppkt.hdr.caplen-dllength); //skip header and try...
+        }
+
+      rtp_streams_timeout();
+    }
+}
+
+
+void list_rtp_pt()
+{
+  int i;
+
+
+  LOG(1,1,"");
+  LOG(1,1,"[known RTP payload types]");
+  LOG(1,1,"");
+  for (i=0;rtp_payload_type_vals[i].str;i++)
+    LOG(1,1,"%d = %s", rtp_payload_type_vals[i].type, rtp_payload_type_vals[i].str);
+
+  LOG(1,1,"");
+}
+
+
+void cleanup()
+{
+  rtp_streams_close();
+
+
+  if (running)
+    raise(SIGUSR2); // show state...
+
+  SAFE_PCAP_CLOSE(mypcap);
+  SAFE_FREE(o.rxfile);
+  SAFE_FREE(o.iface);
+  SAFE_FREE(o.outdir);
+  SAFE_FREE(o.user);
+  SAFE_FREE(o.mypcap_filter);
+  SAFE_PDCLOSE(pdump_noise);
+}
+
+
+void
+init_opt(int argc, char **argv)
+{
+  int             c;
+  char pathname[PATH_MAX];
+
+
+  o.udp_hdr_even_dst_port = 0;
+  o.udp_hdr_unpriv_ports = 0;
+  o.mypcap_filter = NULL;
+  o.rtp_hdr_pt = -1;
+  o.fill_gaps = 0;
+  o.verbose = 0;
+  o.rxfile = NULL;
+  o.iface = NULL;
+  o.outdir = strdup(DEFAULT_OUTDIR);
+  o.dllength = -1;
+  o.timeout_pkt = PKT_TIMEOUT;
+  o.timeout_pattern = RTP_STREAM_PATTERN_TIMEOUT;
+  o.rtp_payload_length = -1;
+  o.dump_noise = 0;
+  o.pattern_pkts = RTP_STREAM_PATTERN_PKTS;
+  o.user =  NULL;
+  o.daemonize = 0;
+  o.promisc = 0;
+  o.syslog = 0;
+  o.stdout = 1;
+  o.dump_raw = 1;
+  o.dump_pcap = 1;
+
+  if (argc ==1)
+    help();
+
+  opterr = 0;
+
+  while ((c = getopt(argc, argv, "r:i:d:L:y:p:l:t:T:P:Z:unvgekDmFfhwW")) != EOF)
+    switch (c)
+      {
+
+      case 'e':
+        o.udp_hdr_even_dst_port = 1;
+        break;
+
+      case 'p':
+        o.mypcap_filter = strdup(optarg);
+        break;
+
+      case 'y':
+        o.rtp_hdr_pt= atoi(optarg);
+        if (o.rtp_hdr_pt < 0)
+          FATAL("rtp_hdr_pt < 0");
+        break;
+
+      case 'g':
+        o.fill_gaps = 1;
+        break;
+
+      case 'L':
+        o.dllength = atoi(optarg);
+        if (o.dllength <0)
+          FATAL("dllength < 0");
+        break;
+
+      case 'r':
+        SAFE_FREE(o.rxfile);
+        o.rxfile = strdup(optarg);
+        break;
+
+      case 'i':
+        SAFE_FREE(o.iface);
+        o.iface =  strdup(optarg);
+        break;
+
+      case 'v':
+        o.verbose = 1;
+        break;
+
+      case 'd':
+        SAFE_FREE(o.outdir);
+        o.outdir = strdup(optarg);
+        break;
+
+      case 'l':
+        o.rtp_payload_length= atoi(optarg);
+        if (o.rtp_payload_length < 0)
+          FATAL("rtp_payload_length < 0");
+        break;
+
+      case 't':
+        /* from manpage of strtof:
+         * Since 0 can legitimately be returned on both success and failure, the calling  program
+         * should  set  errno  to  0  before the call, and then determine if an error occurred by
+         * checking whether errno has a non-zero value after the call.
+         */
+        errno = 0;
+        o.timeout_pkt = strtof(optarg, NULL);
+        if (errno != 0)
+          FATAL("strtof(): %s", strerror(errno));
+        if (o.timeout_pkt < 0)
+          FATAL("timeout_pkt < 0");
+        break;
+
+      case 'T':
+        errno = 0;
+        o.timeout_pattern = strtof(optarg, NULL);
+        if (errno != 0)
+          FATAL("strtof(): %s", strerror(errno));
+        if (o.timeout_pattern < 0)
+          FATAL("timeout_pattern < 0");
+        break;
+
+      case 'u':
+        o.udp_hdr_unpriv_ports = 1;
+        break;
+
+      case 'n':
+        o.dump_noise =1;
+        break;
+
+      case 'P':
+        o.pattern_pkts = atoi(optarg);
+        if (o.pattern_pkts <=0)
+          FATAL("pattern_pkts <= 0");
+        break;
+
+      case 'k':
+        list_rtp_pt();
+        exit(0);
+
+      case 'Z':
+        SAFE_FREE(o.user);
+        o.user = strdup(optarg);
+        break;
+
+      case 'D':
+        o.daemonize = 1;
+        break;
+
+      case 'm':
+        o.promisc = 1;
+        break;
+
+      case 'F':
+        o.syslog = 1;
+        break;
+
+      case 'f':
+        o.stdout = 0;
+        break;
+
+      case 'h':
+        help();
+        break;
+
+      case 'w':
+        o.dump_raw = 0;
+        break;
+      case 'W':
+        o.dump_pcap = 0;
+        break;
+
+      default:
+        FATAL("option '%c' invalid", optopt);
+      }
+
+  if (o.daemonize)
+    o.stdout = 0;
+
+  if (o.stdout)
+    enable_stdout();
+
+  if (o.verbose)
+    enable_verbose();
+
+  get_next_name(o.outdir, "rtp.",".txt",&ndxlog) ;
+  if (ndxlog == -1)
+    FATAL("get_next_name(...): %s", strerror(errno));
+  snprintf(pathname, PATH_MAX, "%s/rtp.%d.txt", o.outdir, ndxlog);
+  open_logfile(pathname);
+
+  if (o.syslog)
+    enable_syslog();
+
+  if (o.iface && o.rxfile)
+    FATAL("dup packet source: -r or -i");
+
+  if (!o.iface && !o.rxfile)
+    FATAL("packet source required");
+
+  if (o.rxfile)
+    if ( (mypcap = pcap_open_offline(o.rxfile, errbuf)) == NULL)
+      FATAL("pcap_open_offline(): %s", errbuf);
+
+  if (o.iface)
+    if ((mypcap = pcap_open_live(o.iface, 65535, o.promisc, 0, errbuf)) == NULL)
+      FATAL("pcap_open_live(): %s", errbuf);
+
+  if (o.dllength == -1 && sizeof_datalink(mypcap) == -1)
+    FATAL("sizeof_datalink == -1");
+
+  if (o.user)
+    drop_privs(o.user, NULL); // group can be NULL, it's ok!
+
+  if (o.dump_noise)
+    {
+      snprintf(pathname, PATH_MAX, "%s/rtp.%d.noise.pcap", o.outdir, ndxlog);
+      if (!(pdump_noise = pcap_dump_open(mypcap, pathname)))
+        FATAL("pcap_dump_open(): %s", pcap_geterr(mypcap));
+    }
+
+
+  if (o.daemonize)
+    daemonize();
+
+
+  LOG(1,1," + rtpbreak v%s running here!",VERSION);
+  LOG(1,1," + pid: %d, date/time: %s",getpid(),strtime(time(NULL)));
+
+
+  if (o.verbose)
+    {
+      LOG(1,0," + cmd: %s", argv[0]);
+      for (c = 1; c < argc; c++)
+        LOG(0,0," '%s'", argv[c]);
+      LOG(0,1,"");
+    }
+
+  LOG(1,1," + Configuration");
+
+  LOG(1,1,"   + INPUT");
+  LOG(1,0,"     Packet source: ");
+
+  if (o.rxfile)
+    LOG(0,1,"rxfile '%s'", o.rxfile);
+  else
+    LOG(0,1,"iface '%s'", o.iface);
+
+  LOG(1,0,"     Force datalink header length: ");
+  if (o.dllength == -1)
+    LOG(0,1,"disabled");
+  else
+    LOG(0,1,"%d bytes", o.dllength);
+
+  LOG(1,1,"   + OUTPUT");
+
+  LOG(1,1,"     Output directory: '%s'", o.outdir);
+  LOG(1,1,"     RTP raw dumps: %s", o.dump_raw ? "enabled" : "disabled");
+  LOG(1,1,"     RTP pcap dumps: %s", o.dump_pcap ? "enabled" : "disabled");
+
+  if (o.dump_raw)
+    LOG(1,1,"     Fill gaps: %s",o.fill_gaps ? "enabled" : "disabled");
+
+  LOG(1,0,"     Dump noise: ");
+  if (o.dump_noise)
+    LOG(0,1,"'%s/rtp.%d.noise.pcap'", o.outdir, ndxlog);
+  else
+    LOG(0,1,"disabled");
+
+  LOG(1,1,"     Logfile: '%s/rtp.%d.txt'", o.outdir, ndxlog);
+  LOG(1,1,"     Logging to stdout: %s",o.stdout ? "enabled" : "disabled");
+  LOG(1,1,"     Logging to syslog: %s",o.syslog ? "enabled" : "disabled");
+  LOG(1,1,"     Be verbose: %s",o.verbose ? "enabled" : "disabled");
+  LOG(1,1,"   + SELECT");
+  LOG(1,1,"     Sniff packets in promisc mode: %s", o.promisc ?  "enabled" : "disabled");
+
+  LOG(1,0,"     Add pcap filter: ");
+  if (o.mypcap_filter)
+    LOG(0,1,"'%s'", o.mypcap_filter);
+  else
+    LOG(0,1,"disabled");
+
+  LOG(1,1,"     Expecting even destination UDP port: %s",o.udp_hdr_even_dst_port ? "enabled" : "disabled");
+
+  LOG(1,1,"     Expecting unprivileged source/destination UDP ports: %s", o.udp_hdr_unpriv_ports ? "enabled" : "disabled");
+
+  LOG(1,0,"     Expecting RTP payload type: ");
+  if (o.rtp_hdr_pt == -1)
+    LOG(0,1,"any");
+  else
+    LOG(0,1,"%d (%s)", o.rtp_hdr_pt, find_stream_rtp_pt(o.rtp_hdr_pt,0));
+
+  LOG(1,0,"     Expecting RTP payload length: ");
+  if (o.rtp_payload_length == -1)
+    LOG(0,1,"any");
+  else
+    LOG(0,1,"%d bytes",  o.rtp_payload_length);
+
+  LOG(1,1,"     Packet timeout: %.2f seconds", o.timeout_pkt);
+  LOG(1,1,"     Pattern timeout: %.2f seconds", o.timeout_pattern);
+  LOG(1,1,"     Pattern packets: %d", o.pattern_pkts);
+
+  LOG(1,1,"   + EXECUTION");
+  LOG(1,1,"     Running as user/group: %s/%s", getpwuid(getuid())->pw_name,getgrgid(getgid())->gr_name);
+  LOG(1,1,"     Running daemonized: %s",  o.daemonize ? "enabled" : "disabled");
+
+
+}
+
+
+void rtp_streams_init()
+{
+  rtp_streams.list.lh_first = NULL;
+  rtp_streams.max_id = 0;
+  rtp_streams.closed = 0;
+  rtp_streams.nclosed = 0;
+  rtp_streams.active = 0;
+  rtp_streams.pktcount = 0;
+  rtp_streams.pktcount_noise = 0;
+  rtp_streams.pktcount_lost = 0;
+}
+
+
+int
+main(int argc, char **argv)
+{
+  init_sighandlers();
+  signal(SIGUSR2, sig_stats_handler);
+  init_opt(argc, argv);
+  rtp_streams_init();
+
+
+  if (o.mypcap_filter)
+    add_pcap_filter(mypcap,o.mypcap_filter);
+
+  LOG(1,1," * You can dump stats sending me a SIGUSR2 signal");
+
+  LOG(1,1," * Reading packets...");
+
+  running = 1;
+
+  loop(pcap_datalink(mypcap),o.dllength == -1 ? sizeof_datalink(mypcap) : o.dllength);
+
+  raise(SIGTERM);
+  return 0; // never reached
+}
+
+
+int dissect_rtp(struct pcap_pkt *ppkt,u_int32_t pktoff, u_int32_t pktlen, addrs_t addrs)
+{
+  pktrtp_t pktrtp; // rtp packet
+  int32_t len;
+  int32_t off;
+  rtp_hdr_t *rtphdr;
+
+
+// rtcp solitamente gira su porte non privilegiate >1024...
+  if (o.udp_hdr_unpriv_ports)
+    if (addrs.dstport < 1024 || addrs.srcport < 1024)
+      return 0;
+
+  // rtcp gira su porte dispari mentre rtp su porte pari...
+  // skippiamo le dispari.
+
+  if (o.udp_hdr_even_dst_port)
+    if (addrs.dstport % 2 != 0)
+      return 0;
+
+  if (pktlen <= sizeof(rtp_hdr_t))
+    return 0;
+
+  pktrtp.hdroff = pktoff;
+  pktrtp.len = pktlen;
+
+
+  rtphdr = (rtp_hdr_t *)(ppkt->pkt + pktoff);
+
+  pktrtp.pcap = *ppkt;
+
+
+  if (o.rtp_hdr_pt != -1)
+    if (rtphdr->pt !=o.rtp_hdr_pt)
+      return 0;
+
+  if (rtphdr->v != 2)
+    return 0;
+
+  //VLOG(1,1,"pktcount: %d", pktcount);
+
+  off = pktrtp.hdroff + sizeof(rtp_hdr_t);
+  len = pktlen - sizeof(rtp_hdr_t);
+
+  // se il flag per il padding e' 1 allora l'ultimo byte del padding
+  // indica quanti byte di padding sono presenti.
+  // (mai notati, ma non usando encryption e' normale).
+  if (rtphdr->p)
+    len-= ((u_int8_t *)rtphdr)[pktlen-1];
+
+  // seguono i CSRC, ciascuno di 4 byte. il loro numero e' pari a
+  // pktrtp.cc (li ho notati solo in yahoo messenger).
+  if (rtphdr->cc >0)
+    {
+      len -= 4 * rtphdr->cc;
+      off += 4 * rtphdr->cc;
+    }
+
+  if (rtphdr->x)
+    {
+      rtp_extension_hdr_t *rtpext;
+      // l'extension header e' di 4 byte.
+      if (len < 4)
+        return 0;
+
+      // the extension, if present, is after the CSRC list.
+      rtpext = (rtp_extension_hdr_t *)((u_int8_t *)rtphdr+off);
+      off += sizeof(rtp_extension_hdr_t) + rtpext->length;
+      len -= sizeof(rtp_extension_hdr_t) + rtpext->length;
+    }
+
+  if (len < 0)
+    return 0;
+
+  pktrtp.payload.off = off;
+  pktrtp.payload.len = len;
+
+  if ( o.rtp_payload_length != -1)
+    if (pktrtp.payload.len != o.rtp_payload_length)
+      return 0;
+
+  rtp_pkt_handle(&pktrtp,addrs);
+
+  return 0;
+}
+
+
+int dissect_ip(struct pcap_pkt *ppkt, u_int32_t pktoff, u_int32_t pktlen)
+{
+  addrs_t addrs = { 0,0,0,0};
+  struct libnet_ipv4_hdr *pktip;
+  int32_t len;
+
+
+  if (pktlen < sizeof(struct libnet_ipv4_hdr))
+    return 0;
+
+  pktip = (struct libnet_ipv4_hdr *) (ppkt->pkt + pktoff);
+
+  len = ntohs(pktip->ip_len) - (pktip->ip_hl << 2);
+
+  // nota: potrebbe esserci il trailer eth
+
+  if (len < 0 || len > pktlen)
+    return 0;
+
+  addrs.srcaddr = pktip->ip_src.s_addr;
+  addrs.dstaddr = pktip->ip_dst.s_addr;
+
+  if (pktip->ip_p == IPPROTO_UDP)
+    return dissect_udp(ppkt,pktoff+(pktip->ip_hl << 2),len,addrs);
+
+  return 0;
+}
+
+
+struct rtp_stream_entry *rtp_search_stream(addrs_t addrs, rtp_hdr_t *pktrtp)
+  {
+    struct rtp_stream_entry *rtp_stream;
+    int64_t vmin, vmax, v;
+    // non usiamo u_int16_t u_int32_t perche per calcolare vmin,vmax e' possibile uscire dal range, del seq e del ts.
+
+
+    //VLOG(1,1,"searching stream...");
+
+    LIST_FOREACH(rtp_stream, &rtp_streams.list, l)
+    {
+      if (pktrtp->ssrc != rtp_stream->ssrc)
+        continue;
+
+      if (!(addrs.srcaddr == rtp_stream->addrs.srcaddr &&
+            addrs.dstaddr == rtp_stream->addrs.dstaddr &&
+            addrs.srcport == rtp_stream->addrs.srcport &&
+            addrs.dstport == rtp_stream->addrs.dstport))
+        continue;
+
+      // controlliamo il sequence number:
+      // consideriamo appartenenti a questo flusso
+      // i sequence number compresi in una "finestra"
+      // ampia RTP_SEQWINDOW, che ha come valore centrale
+      // l'ultimo sequence number che abbiamo precedentemente
+      // identificato come appartenente allo stream.
+
+      v = ntohs(pktrtp->seq);
+
+      if (rtp_stream->first_pkt.tv_sec != 0) // se none' il primo pkt...
+        if (v < rtp_stream->max_seq_seen) // maybe mod loop!!
+          v += ((u_int16_t)(0-1))+1;
+
+      vmin = ((int64_t)rtp_stream->max_seq_seen) - RTP_SEQWINDOW / 2;
+      vmax = ((int64_t)rtp_stream->max_seq_seen) + RTP_SEQWINDOW / 2;
+
+      //VLOG(1,1,"seqcheck: vmin=%llu v=%llu vmax=%llu", vmin, v, vmax);
+      if (v < vmin && v > vmax)
+        {
+          LOG(1,1,"seqcheck failed:  vmin=%llu v=%llu vmax=%llu", vmin, v, vmax);
+          continue;
+        }
+
+      v = ntohl(pktrtp->ts);
+
+      if (rtp_stream->first_pkt.tv_sec != 0) // se none' il primo pkt...
+        if (v < rtp_stream->max_ts_seen) // maybe mod loop!!
+          v += ((u_int32_t)(0-1))+1;
+
+      vmin = ((int64_t)rtp_stream->max_ts_seen) - RTP_TSWINDOW / 2;
+      vmax = ((int64_t)rtp_stream->max_ts_seen) + RTP_TSWINDOW / 2;
+
+//      LOG(1,1,"tscheck: vmin=%llu v=%llu vmax=%llu", vmin, v, vmax);
+      if (v < vmin && v > vmax)
+        {
+//            LOG(1,1,"tscheck failed");
+          continue;
+        }
+
+      break;
+    }
+
+    /*
+        if(rtp_stream)
+          VLOG(1,1,"found!");
+        else
+          VLOG(1,1,"not found!");
+    */
+
+    return rtp_stream;
+  }
+
+
+void rtp_stream_add_pkt(struct rtp_stream_entry *rtp_stream, pktrtp_t *pktrtp)
+{
+  struct rtpbuf_entry *rtpbuf,*after,*new, *before;
+  rtp_hdr_t *rtphdr, *rtphdr2;
+
+
+  before = NULL;
+  after = NULL;
+  rtpbuf = NULL;
+
+  rtphdr = (rtp_hdr_t *)(pktrtp->pcap.pkt + pktrtp->hdroff);
+
+  if (rtp_stream->pktcount_flhd == 0)
+    rtp_stream->payload_type = rtphdr->pt;
+
+// 65535/2 per evitare possibili pacchetti duplicati ma gia' inseriti!
+// succede anche quando sipcodec sta girando.
+// rtp_stream->first_pkt.tv_sec != 0 ci assicura che non stiamo facendo
+// il check sul primo pkt... che risulta sempre positivo, se il seq parte da 0
+// come ad esempio in linphone.
+
+  if (rtp_stream->first_pkt.tv_sec != 0 && ntohs(rtphdr->seq)+65535/2 < rtp_stream->max_seq_seen)
+    {
+// mod loop!! forziamo il flushing del buffer...
+// e se il pattern none' gia' stato trovato, chiudiamo la sessione.
+// se era una  sessione, verra' ricreata senza
+// cadere in questa situazione. cosi' ci evitiamo di
+// gestirla, che e' una palla e capita di rado.
+      if (!rtp_stream->pattern_found)
+        {
+          rtp_stream_close(rtp_stream);
+          return;
+        }
+
+      rtp_stream_flush(rtp_stream,0);
+
+      if (rtp_stream->pkts.lh_first)
+        FATAL("packets buffer not empty");
+
+      rtp_stream->max_ts_seen = ntohl(rtphdr->ts);
+      rtp_stream->max_seq_seen = ntohs(rtphdr->seq);
+
+    }
+  else
+    {
+
+      if (rtp_stream->first_pkt.tv_sec != 0)
+        if (ntohs(rtphdr->seq)<= rtp_stream->max_seq_seen)
+          return;
+    }
+
+// la lista contiene i pkt ordinati con seq in ordine crescente
+  LIST_FOREACH(rtpbuf, &rtp_stream->pkts, l)
+  {
+    rtphdr2 = (rtp_hdr_t *)(rtpbuf->pktrtp.pcap.pkt + rtpbuf->pktrtp.hdroff);
+
+    if (rtphdr->seq == rtphdr2->seq)
+      {
+//         LOG(1,1,"dup");
+        return;
+      }
+    if (ntohs(rtphdr->seq) < ntohs(rtphdr2->seq))
+      {
+        LOG(1,1,"seq=%u insert before seq=%u", ntohs(rtphdr->seq),ntohs(rtphdr2->seq));
+        before = rtpbuf;
+        // il nuovo pacchetto X ha un seqnum minore di quello
+        // che stiamo osservando nella lista, Y. quindi X va
+        // inserito prima di Y.
+        LOG(1,1,"breaking");
+        break;
+      }
+    after = rtpbuf;
+  }
+
+  sig_lock(); // impediamo ctrl-c,...
+
+  new = (struct rtpbuf_entry *)malloc(sizeof(struct rtpbuf_entry));
+  memcpy(&new->pktrtp, &pktrtp, sizeof(pktrtp_t));
+  new->pktrtp.pcap.hdr = pktrtp->pcap.hdr;
+  new->pktrtp.pcap.pkt = (u_int8_t *)malloc(pktrtp->pcap.hdr.caplen);
+  memcpy(new->pktrtp.pcap.pkt, pktrtp->pcap.pkt, pktrtp->pcap.hdr.caplen);
+  new->pktrtp.len = pktrtp->len;
+  new->pktrtp.hdroff = pktrtp->hdroff;
+  new->pktrtp.payload.off = pktrtp->payload.off;
+  new->pktrtp.payload.len = pktrtp->payload.len;
+
+  if (rtp_stream->pkts.lh_first == NULL)
+    {
+      LIST_INSERT_HEAD(&rtp_stream->pkts, new,l);
+    }
+  else
+    {
+      if (before)
+        {
+          LIST_INSERT_BEFORE(before, new, l);
+        }
+      else
+        {
+          if (after)
+            LIST_INSERT_AFTER(after, new, l);
+          else FATAL("buffer not empty and before,after NULL");
+        }
+    }
+
+  if (rtp_stream->first_pkt.tv_sec == 0)
+    rtp_stream->first_pkt = pktrtp->pcap.hdr.ts;
+  rtp_stream->last_pkt = pktrtp->pcap.hdr.ts;
+
+  rtp_stream->pktcount_inbuf++;
+
+  if (ntohl(rtphdr->ts) == 0 && rtp_stream->max_ts_seen == ((u_int32_t)(0-1)))
+    rtp_stream->max_ts_seen  = 0;
+  rtp_stream->max_ts_seen = MAX(rtp_stream->max_ts_seen, ntohl(rtphdr->ts));
+
+  if (ntohs(rtphdr->seq) == 0 && rtp_stream->max_seq_seen == ((u_int16_t)(0-1)))
+    rtp_stream->max_seq_seen = 0;
+  else
+    rtp_stream->max_seq_seen = MAX(rtp_stream->max_seq_seen, ntohs(rtphdr->seq));
+
+  if (rtp_stream->last_payload_length != -1 &&
+      rtp_stream->last_payload_length != pktrtp->payload.len)
+    rtp_stream->payload_length_fixed = 0;
+  rtp_stream->last_payload_length =  pktrtp->payload.len;
+
+  sig_unlock();
+
+  // we can perform a timestamp check:
+  // (pkt_before.ts <= pkt.ts <= pkt_after.ts)
+
+  if (!rtp_stream->pattern_found)
+    if (rtp_stream->pktcount_inbuf >= o.pattern_pkts)
+      {
+
+// facciamo due controlli: verifichiamo che non
+// ci siano salti fra i seq e che:
+// (pkt_before.ts <= pkt.ts <= pkt_after.ts)
+
+// questi due controlli vengono fatti soltanto
+// se !rtp_stream->pattern_found
+
+        if (rtp_stream_ts_seq_check(rtp_stream) == -1)
+          {
+            rtp_stream_close(rtp_stream);
+            return;
+          }
+
+        rtp_streams.active++;
+
+        rtp_stream->pattern_found=1;
+
+        // "detected!..." nella flush, cosi' abbiamo anche il fid.
+      }
+
+}
+
+
+void rtp_stream_flush(struct rtp_stream_entry *rtp_stream, int buf_timeout)
+{
+  struct rtpbuf_entry *rtpbuf, *rtpbuf2;
+  rtp_hdr_t *rtphdr;
+  int i,j;
+
+
+  if (!rtp_stream->pattern_found)
+    {
+
+      if (buf_timeout != 0)
+        return;
+
+// qui ci finiamo soltanto quando chiudiamo la sessione, un falso positivo.
+
+      LIST_FOREACH_SAFE(rtpbuf, &rtp_stream->pkts, l, rtpbuf2)
+      {
+
+        sig_lock();
+        if (pdump_noise)
+          pcap_dump((u_char *)pdump_noise, &rtpbuf->pktrtp.pcap.hdr, rtpbuf->pktrtp.pcap.pkt);
+
+        rtp_streams.pktcount_noise++;
+
+        LIST_REMOVE(rtpbuf, l);
+        SAFE_FREE(rtpbuf->pktrtp.pcap.pkt);
+        SAFE_FREE(rtpbuf);
+        sig_unlock();
+
+      }
+
+      return;
+    }
+
+  // open log files for entry...
+  if (!rtp_stream->f)
+    {
+
+      rtp_stream_open_files(rtp_stream);
+
+      LOG(1,0," ! [rtp%d] detected: pt=%d(%s) ",rtp_stream->fid,rtp_stream->payload_type,find_stream_rtp_pt(rtp_stream->payload_type,1));
+
+      LOG(0,0,"%s:%d => ",INET_NTOA(rtp_stream->addrs.srcaddr),rtp_stream->addrs.srcport);
+
+      LOG(0,1,"%s:%d",INET_NTOA(rtp_stream->addrs.dstaddr),rtp_stream->addrs.dstport);
+
+      SAFE_FPRINTF(rtp_stream->f,"RTP stream id: rtp.%d.%d\n", ndxlog, rtp_stream->fid);
+      if (o.iface)
+        SAFE_FPRINTF(rtp_stream->f,"Packet source: iface  '%s'\n", o.iface);
+      if (o.rxfile)
+        SAFE_FPRINTF(rtp_stream->f,"Packet source: rxfile '%s'\n", o.rxfile);
+
+      SAFE_FPRINTF(rtp_stream->f,"First seen packet: %s (pcap time)\n", strtime(rtp_stream->first_pkt.tv_sec));
+      SAFE_FPRINTF(rtp_stream->f, "Stream peers: %s:%d => ",INET_NTOA(rtp_stream->addrs.srcaddr),rtp_stream->addrs.srcport);
+      SAFE_FPRINTF(rtp_stream->f,"%s:%d\n",INET_NTOA(rtp_stream->addrs.dstaddr),rtp_stream->addrs.dstport);
+      SAFE_FPRINTF(rtp_stream->f,"RTP ssrc: %u\n", ntohl(rtp_stream->ssrc));
+      SAFE_FPRINTF(rtp_stream->f,"RTP payload type: %d (%s)\n", rtp_stream->payload_type, find_stream_rtp_pt(rtp_stream->payload_type,0));
+
+      rtp_stream_search_rev(rtp_stream);
+
+    }
+
+
+  // la lista contiene i pkt ordinati con seq in ordine crescente.
+  // quindi, dal piu' vecchio all'ultimo. flushiamo i pkt nella lista
+  // fino a quando si verifica almeno una di queste due condizioni:
+  // 1. non ci sono salti fra i sequence (0 pkt persi)
+  // 2. il pkt e' stato nel buffer per un tempo >= di buf_timeout
+
+  LIST_FOREACH_SAFE(rtpbuf, &rtp_stream->pkts, l, rtpbuf2)
+  {
+
+    rtphdr =  (rtp_hdr_t *)(rtpbuf->pktrtp.pcap.pkt+rtpbuf->pktrtp.hdroff);
+
+    // nota: se seq==0, allora il primo prevseq e' 65535 e fallirebbe_
+    // il check se facciamo soltanto seq+1 perche non ce' casting a u_int16_t.
+    // quindi, usiamo (u_int16_t)(seq+1): se seq==65535, risulta 0.
+
+    if (((u_int16_t)(rtp_stream->last_seq_flhd+1) == ntohs(rtphdr->seq)) ||
+        timeout(&pcap_time, &rtpbuf->pktrtp.pcap.hdr.ts,buf_timeout)
+       )
+      {
+        sig_lock();
+
+        // if (sequence ok OR timeout) ..
+
+        if (rtp_stream->pdump)
+          pcap_dump((u_char *)rtp_stream->pdump, &rtpbuf->pktrtp.pcap.hdr, rtpbuf->pktrtp.pcap.pkt);
+        rtp_stream->pktcount_flhd++;
+        rtp_stream->pktcount_inbuf--;
+
+        rtp_streams.pktcount++;
+
+        if (rtp_stream->last_seq_flhd == ((u_int16_t)(0-1)))
+          j = 1;
+        else
+          j=ntohs(rtphdr->seq)-rtp_stream->last_seq_flhd; // usata anche per fill gaps!
+
+        rtp_stream->pktcount_lost += j-1;
+        rtp_streams.pktcount_lost+= j-1;
+
+
+        if (o.dump_raw)
+          {
+            if (o.fill_gaps)
+              {
+                // if j == 1 (state of "no lost packets"), writes the pkt only 1 time
+                for (i=0;i<j;i++)
+                  fwrite(rtpbuf->pktrtp.pcap.pkt +  rtpbuf->pktrtp.payload.off, 1, rtpbuf->pktrtp.payload.len, rtp_stream->raw);
+              }
+            else
+              {
+                //  writes the pkt
+                fwrite(rtpbuf->pktrtp.pcap.pkt +  rtpbuf->pktrtp.payload.off, 1, rtpbuf->pktrtp.payload.len, rtp_stream->raw);
+              }
+          }
+
+        rtp_stream->last_seq_flhd=ntohs(rtphdr->seq);
+        LIST_REMOVE(rtpbuf, l);
+        SAFE_FREE(rtpbuf->pktrtp.pcap.pkt);
+        SAFE_FREE(rtpbuf);
+        sig_unlock();
+
+      }
+    else
+      break;
+
+  }
+
+
+  //VLOG(1,1,"done.");
+
+}
+
+
+char *find_stream_rtp_pt(int pt, int short_vals)
+{
+  int i;
+
+
+  if (short_vals)
+    {
+      for (i=0;rtp_payload_type_short_vals[i].str;i++)
+        if (rtp_payload_type_short_vals[i].type == pt)
+          {
+            return rtp_payload_type_short_vals[i].str;
+          }
+      return "?";
+    }
+  else
+    {
+      for (i=0;rtp_payload_type_vals[i].str;i++)
+        if (rtp_payload_type_vals[i].type == pt)
+          {
+            return rtp_payload_type_vals[i].str;
+          }
+      return "Unknown";
+    }
+  return "Unknown";
+}
+
+
+void
+rtp_stream_open_files(struct rtp_stream_entry *rtp_stream)
+{
+  int count;
+  char pathname[PATH_MAX];
+
+
+  sig_lock();
+
+  snprintf(pathname, PATH_MAX, "rtp.%d.",ndxlog);
+
+  get_next_name(o.outdir, pathname, ".txt", &count);
+
+  if (count == -1)
+    FATAL("get_next_name(...): %s", strerror(errno));
+
+  rtp_stream->fid = count;
+
+  if (o.dump_pcap)
+    {
+      snprintf(pathname, PATH_MAX, "%s/rtp.%d.%d.pcap",o.outdir, ndxlog, rtp_stream->fid );
+      if (!(rtp_stream->pdump = pcap_dump_open(mypcap, pathname)))
+        FATAL("pcap_dump_open(): %s", pcap_geterr(mypcap));
+    }
+
+  snprintf(pathname, PATH_MAX, "%s/rtp.%d.%d.txt",o.outdir, ndxlog, rtp_stream->fid );
+
+  LOG(1,1,"open di %s", pathname);
+
+  if (!(rtp_stream->f = fopen(pathname, "w")))
+    FATAL("fopen(): %s", strerror(errno));
+
+  if (o.dump_raw)
+    {
+      snprintf(pathname, PATH_MAX, "%s/rtp.%d.%d.raw",o.outdir, ndxlog, rtp_stream->fid );
+      if (!(rtp_stream->raw = fopen(pathname, "w")))
+        FATAL("fopen(): %s", strerror(errno));
+    }
+
+  sig_unlock();
+
+}
+
+
+struct rtp_stream_entry * rtp_stream_add(pktrtp_t *pktrtp, addrs_t addrs)
+  {
+    struct rtp_stream_entry *rtp_stream;
+    //signaling_t *signaling;
+    rtp_hdr_t *rtphdr;
+
+
+    rtp_streams.max_id++;
+
+    rtphdr = (rtp_hdr_t *)(pktrtp->pcap.pkt + pktrtp->hdroff);
+
+//    LOG(1,1,"creating and adding stream...");
+    rtp_stream = (struct rtp_stream_entry *)malloc(sizeof(struct rtp_stream_entry));
+    rtp_stream->addrs = addrs;
+    rtp_stream->ssrc = rtphdr->ssrc;
+    rtp_stream->max_seq_seen = ntohs(rtphdr->seq) -1;
+    rtp_stream->last_seq_flhd = ntohs(rtphdr->seq) -1;
+    rtp_stream->max_ts_seen = ntohl(rtphdr->ts); // usiamo questo valore soltanto nel tscheck, quindi anche se none' esatto va bene comunque.
+    rtp_stream->fid = -1;
+    rtp_stream->f = NULL;
+    rtp_stream->raw = NULL;
+    rtp_stream->pdump = NULL;
+    rtp_stream->pattern_found = 0;
+    rtp_stream->pktcount_inbuf = 0;
+    rtp_stream->pktcount_flhd = 0;
+    rtp_stream->pktcount_lost = 0;
+    rtp_stream->pkts.lh_first = NULL;
+    LIST_INSERT_HEAD(&rtp_streams.list,rtp_stream,l);
+    rtp_stream->id = rtp_streams.max_id-1;
+    rtp_stream->last_pkt.tv_sec = 0;
+    rtp_stream->last_pkt.tv_usec = 0;
+    rtp_stream->first_pkt.tv_sec = 0;
+    rtp_stream->first_pkt.tv_usec = 0;
+    rtp_stream->payload_type = -1;
+    rtp_stream->last_payload_length = -1;
+    rtp_stream->payload_length_fixed = 1; // assume yes
+    rtp_stream->rev = NULL;
+
+    return rtp_stream;
+  }
+
+
+void print_stream_stat(struct rtp_stream_entry *rtp_stream)
+{
+  int s;
+
+
+  s =rtp_stream->last_pkt.tv_sec - rtp_stream->first_pkt.tv_sec;
+  LOG(0,1,"packets inbuffer=%d flushed=%d lost=%d(%.2f%%), call_length=%dm%ds", rtp_stream->pktcount_inbuf,rtp_stream->pktcount_flhd, rtp_stream->pktcount_lost, PERCENTAGE(rtp_stream->pktcount_lost, rtp_stream->pktcount_flhd + rtp_stream->pktcount_lost), s/60,s%60);
+}
+
+
+void rtp_stream_close(struct rtp_stream_entry *rtp_stream)
+{
+  int s;
+
+
+  LIST_REMOVE(rtp_stream, l);
+
+  rtp_stream_flush(rtp_stream,0);
+// nota su rtp_stream_flush(rtp_stream,0):
+// se ce' stato un errore durante l'apertura dei file relativi a questo stream
+// rtp, chiamando rtp_stream_flush(rtp_stream,0) viene liberata la memoria
+// tentando di aprire i file (nella rtp_stream_flush). questo comporta un loop
+// nella fatal che comunque viene riconosciuto internamente alla fatal e gestito
+// forzando la terminazione immediata del processo.
+
+  if (rtp_stream->pattern_found)
+    {
+      LOG(1,0," * [rtp%d] closed: ", rtp_stream->fid);
+      print_stream_stat(rtp_stream);
+      rtp_streams.active--;
+      rtp_streams.closed++;
+    }
+  else
+    {
+      rtp_streams.nclosed++;
+    }
+
+  SAFE_PDCLOSE(rtp_stream->pdump);
+  SAFE_FCLOSE(rtp_stream->raw);
+
+
+  SAFE_FPRINTF(rtp_stream->f,"Last seen packet: %s (pcap time)\n", strtime(rtp_stream->last_pkt.tv_sec));
+
+  s =rtp_stream->last_pkt.tv_sec - rtp_stream->first_pkt.tv_sec;
+  SAFE_FPRINTF(rtp_stream->f,"Call length: %dm%ds\n",s / 60,s % 60);
+  SAFE_FPRINTF(rtp_stream->f,"Flushed packets: %d\n",  rtp_stream->pktcount_flhd);
+  SAFE_FPRINTF(rtp_stream->f,"Lost packets: %d (%.2f%%)\n", rtp_stream->pktcount_lost,  PERCENTAGE(rtp_stream->pktcount_lost,rtp_stream->pktcount_flhd + rtp_stream->pktcount_lost));
+  SAFE_FPRINTF(rtp_stream->f,"RTP payload length: %d bytes (%s)\n",rtp_stream->last_payload_length, rtp_stream->payload_length_fixed ? "fixed" : "variable, this is the last seen");
+
+  // after this fclose, no more fprint to file!!
+  SAFE_FCLOSE(rtp_stream->f);
+
+  if (rtp_stream->rev && rtp_stream->rev->rev)
+    rtp_stream->rev->rev = NULL;
+
+  SAFE_FREE(rtp_stream);
+}
+
+
+void rtp_streams_close()
+{
+  VLOG(1,1,"closing streams...");
+
+  while (rtp_streams.list.lh_first)
+    rtp_stream_close(rtp_streams.list.lh_first);
+
+}
+
+
+void help()
+{
+  printf("Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>\n");
+  printf("rtpbreak v%s is free software, covered by the GNU General Public License.\n\n", VERSION);
+  printf("USAGE: rtpbreak (-r|-i) <source> [options]\n");
+
+  printf("\n INPUT\n\n");
+  printf("  -r <str>      Read packets from pcap file <str>\n");
+  printf("  -i <str>      Read packets from network interface <str>\n");
+  printf("  -L <int>      Force datalink header length == <int> bytes\n");
+  printf("\n OUTPUT\n\n");
+  printf("  -d <str>      Set output directory to <str> (def:%s)\n",DEFAULT_OUTDIR);
+  printf("  -w            Disable RTP raw dumps\n");
+  printf("  -W            Disable RTP pcap dumps\n");
+  printf("  -g            Fill gaps in RTP raw dumps (caused by lost packets)\n");
+  printf("  -n            Dump noise packets\n");
+  printf("  -f            Disable stdout logging\n");
+  printf("  -F            Enable syslog logging\n");
+  printf("  -v            Be verbose\n");
+  printf("\n SELECT\n\n");
+  printf("  -m            Sniff packets in promisc mode\n");
+  printf("  -p <str>      Add pcap filter <str>\n");
+  printf("  -e            Expect even destination UDP port\n");
+  printf("  -u            Expect unprivileged source/destination UDP ports (>1024)\n");
+  printf("  -y <int>      Expect RTP payload type == <int>\n");
+  printf("  -l <int>      Expect RTP payload length == <int> bytes\n");
+  printf("  -t <float>    Set packet timeout to <float> seconds (def:%.2f)\n", PKT_TIMEOUT);
+  printf("  -T <float>    Set pattern timeout to <float> seconds (def:%.2f)\n", RTP_STREAM_PATTERN_TIMEOUT);
+  printf("  -P <int>      Set pattern packets count to <int> (def:%d)\n", o.pattern_pkts);
+  printf("\n EXECUTION\n\n");
+  printf("  -Z <str>      Run as user <str>\n");
+  printf("  -D            Run in background (option -f implicit)\n");
+  printf("\n MISC\n\n");
+  printf("  -k            List known RTP payload types\n");
+  printf("  -h            This\n");
+  printf("\n");
+
+  exit(0);
+}
+
+
+void sig_stats_handler(int signo)
+{
+  struct rtp_stream_entry *rtp_stream;
+  int s;
+  int n;
+
+  LOG(1,1," + Status");
+  LOG(1,1,"   Alive RTP Sessions: %d", rtp_streams.active);
+  LOG(1,1,"   Closed RTP Sessions: %d", rtp_streams.closed);
+  LOG(1,1,"   Detected RTP Sessions: %d", rtp_streams.active + rtp_streams.closed);
+  LOG(1,1,"   Flushed RTP packets: %d", rtp_streams.pktcount);
+  LOG(1,1,"   Lost RTP packets: %d (%.2f%%)", rtp_streams.pktcount_lost,
+      PERCENTAGE(rtp_streams.pktcount_lost,rtp_streams.pktcount + rtp_streams.pktcount_lost));
+
+  LOG(1,1,"   Noise (false positive) packets: %d", rtp_streams.pktcount_noise);
+
+  n = 0;
+
+  LIST_FOREACH(rtp_stream, &rtp_streams.list, l)
+  {
+    if (!rtp_stream->pattern_found)
+      continue;
+
+    n++;
+    s =rtp_stream->last_pkt.tv_sec - rtp_stream->first_pkt.tv_sec;
+    LOG(1,0," + [rtp%d] stats: ", rtp_stream->fid);
+    print_stream_stat(rtp_stream);
+  }
+
+  if (n == 0)
+    LOG(1,1," + No active RTP streams");
+
+
+}
+
+
+void rtp_streams_timeout()
+{
+  static struct timeval last_run =
+    {
+      0,0
+    };
+  struct rtp_stream_entry *rtp_stream, *rtp_stream2;
+
+
+  if (!timeout(&pcap_time,&last_run,o.timeout_pattern))
+    return;
+  last_run = pcap_time;
+
+
+  LIST_FOREACH_SAFE(rtp_stream, &rtp_streams.list, l, rtp_stream2)
+  {
+
+    if (rtp_stream->pattern_found)
+      {
+        if (timeout(&pcap_time, &rtp_stream->last_pkt,o.timeout_pkt))
+          {
+            rtp_stream_close(rtp_stream);
+            continue;
+          }
+      }
+    else
+      {
+        if (timeout(&pcap_time, &rtp_stream->last_pkt,o.timeout_pattern))
+          {
+            rtp_stream_close(rtp_stream);
+            continue;
+          }
+      }
+
+  }
+
+//LOG(1,1,"done.");
+}
+
+
+int timeout(struct timeval *a, struct timeval *b, float t)
+{
+  struct timeval c;
+  float r;
+
+
+  TIMEVAL_SUB(a, b, &c);
+
+  r = c.tv_sec + (float)c.tv_usec /1000000;
+
+//LOG(1,1,"a:%f b:%f a-b:%f , a-b:%f", a->tv_sec + (float)a->tv_usec /1000000,b->tv_sec +(float) b->tv_usec /1000000, c.tv_sec + (float)c.tv_usec /1000000,r);
+
+  return r > t ? 1 : 0;
+}
+
+
+void rtp_stream_search_rev(struct rtp_stream_entry *rtp_stream)
+{
+  struct rtp_stream_entry *rtp_stream2;
+
+
+  LIST_FOREACH(rtp_stream2, &rtp_streams.list, l)
+  {
+    if (!rtp_stream2->pattern_found || rtp_stream2->rev)
+      continue;
+    if (rtp_stream2 != rtp_stream &&
+        rtp_stream2->addrs.srcaddr == rtp_stream->addrs.dstaddr &&
+        rtp_stream2->addrs.dstaddr == rtp_stream->addrs.srcaddr)
+      {
+        LOG(1,1," * [rtp%d] probable reverse RTP stream: [rtp%d]",rtp_stream->fid,  rtp_stream2->fid);
+
+        rtp_stream->rev = rtp_stream2;
+        rtp_stream2->rev = rtp_stream;
+
+        SAFE_FPRINTF(rtp_stream->f,"Probable reverse RTP stream id: rtp.%d.%d\n",ndxlog,rtp_stream->rev->fid);
+
+      }
+  }
+
+}
+
+
+/* EOF */
+
diff --git a/src/main.h b/src/main.h
new file mode 100644 (file)
index 0000000..ca31cc8
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * main.h by xenion -- 2008-05-05 -- v.50ea4697a08b7fa64400295ae63b67a1
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+
+/* const */
+
+#define DEFAULT_OUTDIR "."
+
+#define RTP_SEQWINDOW 200
+#define RTP_TSWINDOW (500 * RTP_STREAM_PATTERN_PKTS)
+#define RTP_STREAM_PATTERN_PKTS 5
+
+// se un pkt sta nel buffer un tempo > di PKT_TIMEOUT, viene flushato
+// se non arrivano pkt per un tempo > di PKT_TIMEOUT, la sessione viene
+// considerata conclusa.
+#define PKT_TIMEOUT 10.0
+#define RTP_STREAM_PATTERN_TIMEOUT 0.25
+
+
+/* types */
+
+typedef struct
+  {
+    int verbose;
+    char *rxfile;
+    char *iface;
+    char *outdir;
+    int dllength;
+    int fill_gaps;
+    int rtp_hdr_pt;
+    int udp_hdr_even_dst_port;
+    int udp_hdr_unpriv_ports;
+    char *mypcap_filter;
+    float timeout_pkt;
+    float timeout_pattern;
+    int pattern_pkts;
+    int rtp_payload_length;
+    int dump_noise;
+    char *user;
+    int daemonize;
+    int promisc;
+    int syslog;
+    int stdout;
+    int dump_raw;
+    int dump_pcap;
+  }
+OPT;
+
+
+typedef struct
+  {
+    struct pcap_pkt pcap;
+    u_int32_t len; // length of udp payload (rtp header, extension and codec data).
+    u_int32_t hdroff; // offset to reach the first udp byte, the rtp header.
+    struct
+      {
+        u_int32_t off;
+        u_int32_t len;
+      }
+    payload;
+  }
+pktrtp_t;
+
+
+struct rtpbuf_entry
+  {
+    pktrtp_t pktrtp;
+    LIST_ENTRY(rtpbuf_entry) l;
+  };
+
+
+LIST_HEAD(rtpbuf_head, rtpbuf_entry);
+
+
+typedef struct
+  {
+#define ADDRS_TYPE_UNKNOWN 0
+#define ADDRS_TYPE_IP 1
+#define ADDRS_TYPE_TCP 2
+#define ADDRS_TYPE_UDP 3
+    int type;
+    u_int32_t srcaddr;
+    u_int32_t dstaddr;
+    u_int16_t srcport;
+    u_int16_t dstport;
+  }
+addrs_t;
+
+
+struct rtp_stream_entry
+  {
+    int fid;
+    int id;
+    pcap_dumper_t *pdump;
+    pcap_dumper_t *noise;
+    FILE *f;
+    FILE *raw;
+    addrs_t addrs;
+    u_int32_t ssrc;
+    u_int32_t max_ts_seen; // max last timestamp seen
+    u_int16_t max_seq_seen; // max last sequence seen
+    u_int16_t last_seq_flhd; // last sequence flushed
+    struct rtpbuf_head pkts; // buffered rtp packets
+    struct timeval last_pkt;
+    struct timeval first_pkt;
+    u_int32_t pktcount_flhd;
+    u_int32_t pktcount_inbuf;
+    u_int32_t pktcount_lost;
+    int pattern_found;
+    int payload_type;
+    u_int32_t last_payload_length;
+    int payload_length_fixed;
+    LIST_ENTRY(rtp_stream_entry) l; // list link
+    struct rtp_stream_entry *rev;
+  };
+
+
+LIST_HEAD(rtp_streams_head, rtp_stream_entry);
+
+
+struct rtp_streams_list
+  {
+    u_int32_t max_id;
+    int32_t nclosed; // pattern not found and closed
+    int32_t closed; //  pattern found and closed
+    int32_t active; // active and pattern found
+    u_int32_t pktcount_lost;
+    u_int32_t pktcount_noise;
+    u_int32_t pktcount;
+    struct rtp_streams_head list;
+  };
+
+
+/* EOF */
+
diff --git a/src/net.c b/src/net.c
new file mode 100644 (file)
index 0000000..cfe399d
--- /dev/null
+++ b/src/net.c
@@ -0,0 +1,146 @@
+/*
+ * net.c by xenion -- 2008-05-05 -- v.0e2f795ca3b9af8bf863598b0a729ec4
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+
+#include <libnet.h>
+#include <pcap.h>
+#include "bpf.h"
+#include "common.h"
+#include "net.h"
+
+
+/* macros */
+
+#define CASE(x,y) { case (x): return y; break; }
+
+
+/*******************************************/
+
+
+int
+sizeof_datalink(pcap_t * p)
+{
+  int             dtl;
+
+
+  if ((dtl = pcap_datalink(p)) < 0)
+    FATAL("pcap_datalink(): %s", pcap_geterr(p));
+
+  switch (dtl)
+    {
+
+      CASE(AP_DLT_NULL, 4);
+      CASE(AP_DLT_EN10MB, 14);
+      CASE(AP_DLT_EN3MB, 14);
+      CASE(AP_DLT_AX25, -1);
+      CASE(AP_DLT_PRONET, -1);
+      CASE(AP_DLT_CHAOS, -1);
+      CASE(AP_DLT_IEEE802, 22);
+      CASE(AP_DLT_ARCNET, -1);
+#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) || defined (__BSDI__)
+
+      CASE(AP_DLT_SLIP, 16);
+#else
+
+      CASE(AP_DLT_SLIP, 24);
+#endif
+
+#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__)
+
+      CASE(AP_DLT_PPP, 4);
+#elif defined (__sun)
+
+      CASE(AP_DLT_PPP, 8);
+#else
+
+      CASE(AP_DLT_PPP, 24);
+#endif
+
+      CASE(AP_DLT_FDDI, 21);
+      CASE(AP_DLT_ATM_RFC1483, 8);
+
+      CASE(AP_DLT_LOOP, 4);   /* according to OpenBSD DLT_LOOP */
+      CASE(AP_DLT_RAW, 0);
+
+      CASE(AP_DLT_SLIP_BSDOS, 16);
+      CASE(AP_DLT_PPP_BSDOS, 4);
+      CASE(AP_DLT_ATM_CLIP, -1);
+#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__)
+
+      CASE(AP_DLT_PPP_SERIAL, 4);
+      CASE(AP_DLT_PPP_ETHER, 4);
+#elif defined (__sun)
+
+      CASE(AP_DLT_PPP_SERIAL, 8);
+      CASE(AP_DLT_PPP_ETHER, 8);
+#else
+
+      CASE(AP_DLT_PPP_SERIAL, 24);
+      CASE(AP_DLT_PPP_ETHER, 24);
+#endif
+
+      CASE(AP_DLT_C_HDLC, -1);
+      CASE(AP_DLT_IEEE802_11, 30);
+      CASE(AP_DLT_LINUX_SLL, 16);
+      CASE(AP_DLT_LTALK, -1);
+      CASE(AP_DLT_ECONET, -1);
+      CASE(AP_DLT_IPFILTER, -1);
+      CASE(AP_DLT_PFLOG, -1);
+      CASE(AP_DLT_CISCO_IOS, -1);
+      CASE(AP_DLT_PRISM_HEADER, -1);
+      CASE(AP_DLT_AIRONET_HEADER, -1);
+
+    default:
+      FATAL("unknown datalink type DTL_?=%d", dtl);
+      break;
+    }
+
+  return 0;
+}
+
+
+void
+add_pcap_filter(pcap_t *p, char *s)
+{
+  struct bpf_program bpf_filter;
+
+  if (!s)
+    {
+      LOG(1,1," ! The pcap filter is NULL, ignored");
+      return;
+    }
+
+//  LOG(1,1," * Adding pcap_filter: '%s'", s);
+
+  if (pcap_compile(p, &bpf_filter, s, 0, 0) < 0)
+    FATAL("pcap_compile(): %s", pcap_geterr(p));
+
+  if (pcap_setfilter(p, &bpf_filter) < 0)
+    FATAL("pcap_setfilter(): %s", pcap_geterr(p));
+
+  pcap_freecode(&bpf_filter);
+}
+
+
+/* EOF */
+
+
diff --git a/src/net.h b/src/net.h
new file mode 100644 (file)
index 0000000..54f1a51
--- /dev/null
+++ b/src/net.h
@@ -0,0 +1,63 @@
+/*
+ * net.h by xenion -- 2008-05-05 -- v.9f90fb024b189a85013c576f412984a6
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef NET_H
+#define NET_H
+
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pcap.h>
+#include <libnet.h>
+#include "bpf.h"
+#include "ieee80211.h"
+
+/* macros */
+
+#define INET_NTOA(x) (inet_ntoa(*((struct in_addr *)&(x))))
+
+#define SAFE_PCAP_CLOSE(x) do { if (x) { pcap_close(x); x = NULL; }}while(0)
+#define SAFE_LIBNET_CLOSE(x) do { if (x) { libnet_destroy(x); x = NULL; }}while(0)
+
+
+/* types */
+
+struct pcap_pkt
+  {
+    struct    pcap_pkthdr hdr;
+    u_int8_t *pkt;
+    u_int16_t dllength;
+    u_int16_t dlltype;
+  } ;
+
+
+/* protos */
+
+extern int sizeof_datalink(pcap_t * p);
+extern void add_pcap_filter(pcap_t *p, char *s);
+
+
+#endif
+
+/* EOF */
+
diff --git a/src/queue.h b/src/queue.h
new file mode 100644 (file)
index 0000000..35310dc
--- /dev/null
@@ -0,0 +1,543 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California.  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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 REGENTS OR 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ *
+ * Derived from FreeBSD src/sys/sys/queue.h:1.63.
+ * $P4: //depot/projects/trustedbsd/openbsm/compat/queue.h#3 $
+ */
+
+#ifndef _COMPAT_QUEUE_H_
+#define _COMPAT_QUEUE_H_
+
+#include <sys/cdefs.h>
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *    SLIST LIST STAILQ TAILQ
+ * _HEAD   + + + +
+ * _HEAD_INITIALIZER  + + + +
+ * _ENTRY   + + + +
+ * _INIT   + + + +
+ * _EMPTY   + + + +
+ * _FIRST   + + + +
+ * _NEXT   + + + +
+ * _PREV   - - - +
+ * _LAST   - - + +
+ * _FOREACH   + + + +
+ * _FOREACH_SAFE  + + + +
+ * _FOREACH_REVERSE  - - - +
+ * _FOREACH_REVERSE_SAFE - - - +
+ * _INSERT_HEAD   + + + +
+ * _INSERT_BEFORE  - + - +
+ * _INSERT_AFTER  + + + +
+ * _INSERT_TAIL   - - + +
+ * _CONCAT   - - + +
+ * _REMOVE_HEAD   + - + -
+ * _REMOVE   + + + +
+ *
+ */
+#ifdef QUEUE_MACRO_DEBUG
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace
+  {
+    char * lastfile;
+    int lastline;
+    char * prevfile;
+    int prevline;
+  };
+
+#define TRACEBUF struct qm_trace trace;
+#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
+
+#define QMD_TRACE_HEAD(head) do {     \
+ (head)->trace.prevline = (head)->trace.lastline;  \
+ (head)->trace.prevfile = (head)->trace.lastfile;  \
+ (head)->trace.lastline = __LINE__;    \
+ (head)->trace.lastfile = __FILE__;    \
+} while (0)
+
+#define QMD_TRACE_ELEM(elem) do {     \
+ (elem)->trace.prevline = (elem)->trace.lastline;  \
+ (elem)->trace.prevfile = (elem)->trace.lastfile;  \
+ (elem)->trace.lastline = __LINE__;    \
+ (elem)->trace.lastfile = __FILE__;    \
+} while (0)
+
+#else
+#define QMD_TRACE_ELEM(elem)
+#define QMD_TRACE_HEAD(head)
+#define TRACEBUF
+#define TRASHIT(x)
+#endif /* QUEUE_MACRO_DEBUG */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type)      \
+struct name {        \
+ struct type *slh_first; /* first element */   \
+}
+
+#define SLIST_HEAD_INITIALIZER(head)     \
+ { NULL }
+
+#define SLIST_ENTRY(type)      \
+struct {        \
+ struct type *sle_next; /* next element */   \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field)     \
+ for ((var) = SLIST_FIRST((head));    \
+     (var);       \
+     (var) = SLIST_NEXT((var), field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar)   \
+ for ((var) = SLIST_FIRST((head));    \
+     (var) && ((tvar) = SLIST_NEXT((var), field), 1);  \
+     (var) = (tvar))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field)   \
+ for ((varp) = &SLIST_FIRST((head));    \
+     ((var) = *(varp)) != NULL;     \
+     (varp) = &SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do {      \
+ SLIST_FIRST((head)) = NULL;     \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do {   \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm);    \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do {   \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head));   \
+ SLIST_FIRST((head)) = (elm);     \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do {   \
+ if (SLIST_FIRST((head)) == (elm)) {    \
+  SLIST_REMOVE_HEAD((head), field);   \
+ }        \
+ else {        \
+  struct type *curelm = SLIST_FIRST((head));  \
+  while (SLIST_NEXT(curelm, field) != (elm))  \
+   curelm = SLIST_NEXT(curelm, field);  \
+  SLIST_NEXT(curelm, field) =    \
+      SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
+ }        \
+ TRASHIT((elm)->field.sle_next);     \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do {    \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type)      \
+struct name {        \
+ struct type *stqh_first;/* first element */   \
+ struct type **stqh_last;/* addr of last next element */  \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head)     \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type)      \
+struct {        \
+ struct type *stqe_next; /* next element */   \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_CONCAT(head1, head2) do {    \
+ if (!STAILQ_EMPTY((head2))) {     \
+  *(head1)->stqh_last = (head2)->stqh_first;  \
+  (head1)->stqh_last = (head2)->stqh_last;  \
+  STAILQ_INIT((head2));     \
+ }        \
+} while (0)
+
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field)    \
+ for((var) = STAILQ_FIRST((head));    \
+    (var);       \
+    (var) = STAILQ_NEXT((var), field))
+
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar)   \
+ for ((var) = STAILQ_FIRST((head));    \
+     (var) && ((tvar) = STAILQ_NEXT((var), field), 1);  \
+     (var) = (tvar))
+
+#define STAILQ_INIT(head) do {      \
+ STAILQ_FIRST((head)) = NULL;     \
+ (head)->stqh_last = &STAILQ_FIRST((head));   \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {  \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+  (head)->stqh_last = &STAILQ_NEXT((elm), field);  \
+ STAILQ_NEXT((tqelm), field) = (elm);    \
+} while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do {   \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+  (head)->stqh_last = &STAILQ_NEXT((elm), field);  \
+ STAILQ_FIRST((head)) = (elm);     \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do {   \
+ STAILQ_NEXT((elm), field) = NULL;    \
+ *(head)->stqh_last = (elm);     \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field);   \
+} while (0)
+
+#define STAILQ_LAST(head, type, field)     \
+ (STAILQ_EMPTY((head)) ?      \
+  NULL :       \
+         ((struct type *)     \
+  ((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field) do {   \
+ if (STAILQ_FIRST((head)) == (elm)) {    \
+  STAILQ_REMOVE_HEAD((head), field);   \
+ }        \
+ else {        \
+  struct type *curelm = STAILQ_FIRST((head));  \
+  while (STAILQ_NEXT(curelm, field) != (elm))  \
+   curelm = STAILQ_NEXT(curelm, field);  \
+  if ((STAILQ_NEXT(curelm, field) =   \
+       STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+   (head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+ }        \
+ TRASHIT((elm)->field.stqe_next);    \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do {    \
+ if ((STAILQ_FIRST((head)) =     \
+      STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)  \
+  (head)->stqh_last = &STAILQ_FIRST((head));  \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do {   \
+ if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \
+  (head)->stqh_last = &STAILQ_FIRST((head));  \
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type)      \
+struct name {        \
+ struct type *lh_first; /* first element */   \
+}
+
+#define LIST_HEAD_INITIALIZER(head)     \
+ { NULL }
+
+#define LIST_ENTRY(type)      \
+struct {        \
+ struct type *le_next; /* next element */   \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#if (defined(_KERNEL) && defined(INVARIANTS)) || defined(QUEUE_MACRO_DEBUG)
+#define QMD_LIST_CHECK_HEAD(head, field) do {    \
+ if (LIST_FIRST((head)) != NULL &&    \
+     LIST_FIRST((head))->field.le_prev !=   \
+      &LIST_FIRST((head)))     \
+  panic("Bad list head %p first->prev != head", (head)); \
+} while (0)
+
+#define QMD_LIST_CHECK_NEXT(elm, field) do {    \
+ if (LIST_NEXT((elm), field) != NULL &&    \
+     LIST_NEXT((elm), field)->field.le_prev !=   \
+      &((elm)->field.le_next))     \
+       panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+#define QMD_LIST_CHECK_PREV(elm, field) do {    \
+ if (*(elm)->field.le_prev != (elm))    \
+  panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_LIST_CHECK_HEAD(head, field)
+#define QMD_LIST_CHECK_NEXT(elm, field)
+#define QMD_LIST_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) || QUEUE_MACRO_DEBUG */
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field)     \
+ for ((var) = LIST_FIRST((head));    \
+     (var);       \
+     (var) = LIST_NEXT((var), field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar)   \
+ for ((var) = LIST_FIRST((head));    \
+     (var) && ((tvar) = LIST_NEXT((var), field), 1);  \
+     (var) = (tvar))
+
+#define LIST_INIT(head) do {      \
+ LIST_FIRST((head)) = NULL;     \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {   \
+ QMD_LIST_CHECK_NEXT(listelm, field);    \
+ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+  LIST_NEXT((listelm), field)->field.le_prev =  \
+      &LIST_NEXT((elm), field);    \
+ LIST_NEXT((listelm), field) = (elm);    \
+ (elm)->field.le_prev = &LIST_NEXT((listelm), field);  \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do {   \
+ QMD_LIST_CHECK_PREV(listelm, field);    \
+ (elm)->field.le_prev = (listelm)->field.le_prev;  \
+ LIST_NEXT((elm), field) = (listelm);    \
+ *(listelm)->field.le_prev = (elm);    \
+ (listelm)->field.le_prev = &LIST_NEXT((elm), field);  \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {    \
+ QMD_LIST_CHECK_HEAD((head), field);    \
+ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
+  LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+ LIST_FIRST((head)) = (elm);     \
+ (elm)->field.le_prev = &LIST_FIRST((head));   \
+} while (0)
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field) do {     \
+ QMD_LIST_CHECK_NEXT(elm, field);    \
+ QMD_LIST_CHECK_PREV(elm, field);    \
+ if (LIST_NEXT((elm), field) != NULL)    \
+  LIST_NEXT((elm), field)->field.le_prev =   \
+      (elm)->field.le_prev;    \
+ *(elm)->field.le_prev = LIST_NEXT((elm), field);  \
+ TRASHIT((elm)->field.le_next);     \
+ TRASHIT((elm)->field.le_prev);     \
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type)      \
+struct name {        \
+ struct type *tqh_first; /* first element */   \
+ struct type **tqh_last; /* addr of last next element */  \
+ TRACEBUF       \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)     \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)      \
+struct {        \
+ struct type *tqe_next; /* next element */   \
+ struct type **tqe_prev; /* address of previous next element */ \
+ TRACEBUF       \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_CONCAT(head1, head2, field) do {    \
+ if (!TAILQ_EMPTY(head2)) {     \
+  *(head1)->tqh_last = (head2)->tqh_first;  \
+  (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+  (head1)->tqh_last = (head2)->tqh_last;   \
+  TAILQ_INIT((head2));     \
+  QMD_TRACE_HEAD(head1);     \
+  QMD_TRACE_HEAD(head2);     \
+ }        \
+} while (0)
+
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field)     \
+ for ((var) = TAILQ_FIRST((head));    \
+     (var);       \
+     (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar)   \
+ for ((var) = TAILQ_FIRST((head));    \
+     (var) && ((tvar) = TAILQ_NEXT((var), field), 1);  \
+     (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field)  \
+ for ((var) = TAILQ_LAST((head), headname);   \
+     (var);       \
+     (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST((head), headname);   \
+     (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
+     (var) = (tvar))
+
+#define TAILQ_INIT(head) do {      \
+ TAILQ_FIRST((head)) = NULL;     \
+ (head)->tqh_last = &TAILQ_FIRST((head));   \
+ QMD_TRACE_HEAD(head);      \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {  \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+  TAILQ_NEXT((elm), field)->field.tqe_prev =   \
+      &TAILQ_NEXT((elm), field);    \
+ else {        \
+  (head)->tqh_last = &TAILQ_NEXT((elm), field);  \
+  QMD_TRACE_HEAD(head);     \
+ }        \
+ TAILQ_NEXT((listelm), field) = (elm);    \
+ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);  \
+ QMD_TRACE_ELEM(&(elm)->field);     \
+ QMD_TRACE_ELEM(&listelm->field);    \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do {   \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev;  \
+ TAILQ_NEXT((elm), field) = (listelm);    \
+ *(listelm)->field.tqe_prev = (elm);    \
+ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);  \
+ QMD_TRACE_ELEM(&(elm)->field);     \
+ QMD_TRACE_ELEM(&listelm->field);    \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {   \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
+  TAILQ_FIRST((head))->field.tqe_prev =   \
+      &TAILQ_NEXT((elm), field);    \
+ else        \
+  (head)->tqh_last = &TAILQ_NEXT((elm), field);  \
+ TAILQ_FIRST((head)) = (elm);     \
+ (elm)->field.tqe_prev = &TAILQ_FIRST((head));   \
+ QMD_TRACE_HEAD(head);      \
+ QMD_TRACE_ELEM(&(elm)->field);     \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {   \
+ TAILQ_NEXT((elm), field) = NULL;    \
+ (elm)->field.tqe_prev = (head)->tqh_last;   \
+ *(head)->tqh_last = (elm);     \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field);   \
+ QMD_TRACE_HEAD(head);      \
+ QMD_TRACE_ELEM(&(elm)->field);     \
+} while (0)
+
+#define TAILQ_LAST(head, headname)     \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field)    \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field) do {    \
+ if ((TAILQ_NEXT((elm), field)) != NULL)    \
+  TAILQ_NEXT((elm), field)->field.tqe_prev =   \
+      (elm)->field.tqe_prev;    \
+ else {        \
+  (head)->tqh_last = (elm)->field.tqe_prev;  \
+  QMD_TRACE_HEAD(head);     \
+ }        \
+ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);  \
+ TRASHIT((elm)->field.tqe_next);     \
+ TRASHIT((elm)->field.tqe_prev);     \
+ QMD_TRACE_ELEM(&(elm)->field);     \
+} while (0)
+
+#endif /* !_COMPAT_QUEUE_H_ */
diff --git a/src/rtp.h b/src/rtp.h
new file mode 100644 (file)
index 0000000..457f9fd
--- /dev/null
+++ b/src/rtp.h
@@ -0,0 +1,203 @@
+/*
+ * rtp.h by xenion -- 2008-05-05 -- v.241ba0fea6fe7267cfbb3639b1b3ee3d
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+// modified in order to use the O.S. bit order.
+
+/*
+* rtp.h  --  RTP header file
+* RTP draft: November 1994 version
+*
+* $Id: rtp.h,v 1.3 1995/08/17 13:54:58 hgs Exp $
+*/
+
+#ifndef RTP_H
+#define RTP_H
+
+#include <sys/types.h> // defines byte order for this machine.
+#include "rtp_pt.h"
+
+#define RTP_SEQ_MOD (1<<16)
+#define RTP_TS_MOD  (0xffffffff)
+/*
+* Current type value.
+*/
+#define RTP_VERSION 2
+
+#define RTP_MAX_SDES 256   /* maximum text length for SDES */
+
+typedef enum
+{
+  RTCP_SR   = 200,
+  RTCP_RR   = 201,
+  RTCP_SDES = 202,
+  RTCP_BYE  = 203,
+  RTCP_APP  = 204
+} rtcp_type_t;
+
+typedef enum
+{
+  RTCP_SDES_END    =  0,
+  RTCP_SDES_CNAME  =  1,
+  RTCP_SDES_NAME   =  2,
+  RTCP_SDES_EMAIL  =  3,
+  RTCP_SDES_PHONE  =  4,
+  RTCP_SDES_LOC    =  5,
+  RTCP_SDES_TOOL   =  6,
+  RTCP_SDES_NOTE   =  7,
+  RTCP_SDES_PRIV   =  8,
+  RTCP_SDES_IMG    =  9,
+  RTCP_SDES_DOOR   = 10,
+  RTCP_SDES_SOURCE = 11
+} rtcp_sdes_type_t;
+
+
+typedef struct
+  {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+u_int8_t cc:
+    4;       /* CSRC count */
+u_int8_t x:
+    1;        /* header extension flag */
+u_int8_t p:
+    1;        /* padding flag */
+u_int8_t v:
+    2;  /* protocol version */
+u_int8_t pt:
+    7;       /* payload type */
+u_int8_t m:
+    1;        /* marker bit */
+#elif __BYTE_ORDER == __BIG_ENDIAN
+u_int8_t v:
+    2;  /* protocol version */
+u_int8_t p:
+    1;        /* padding flag */
+u_int8_t x:
+    1;        /* header extension flag */
+u_int8_t cc:
+    4;       /* CSRC count */
+u_int8_t m:
+    1;        /* marker bit */
+u_int8_t pt:
+    7;       /* payload type */
+#else
+# error "Please fix <bits/endian.h>"
+#endif
+
+    u_int16_t seq;             /* sequence number */
+    u_int32_t ts;              /* timestamp */
+    u_int32_t ssrc;            /* synchronization source */
+    u_int32_t csrc[0];         /* optional CSRC list */
+  }
+rtp_hdr_t;
+
+typedef struct
+  {
+    u_int16_t profdef;
+    u_int16_t length; // length of extension in 32bits, this header exluded.
+  }
+rtp_extension_hdr_t;
+
+typedef struct
+  {
+unsigned int version:
+    2;  /* protocol version */
+unsigned int p:
+    1;        /* padding flag */
+unsigned int count:
+    5;    /* varies by payload type */
+unsigned int pt:
+    8;       /* payload type */
+    u_int16_t length;          /* packet length in words, without this word */
+  }
+rtcp_common_t;
+
+/* reception report */
+typedef struct
+  {
+    u_int32_t ssrc;            /* data source being reported */
+unsigned int fraction:
+    8; /* fraction lost since last SR/RR */
+int lost:
+    24;             /* cumulative number of packets lost (signed!) */
+    u_int32_t last_seq;        /* extended last sequence number received */
+    u_int32_t jitter;          /* interarrival jitter */
+    u_int32_t lsr;             /* last SR packet from this source */
+    u_int32_t dlsr;            /* delay since last SR packet */
+  }
+rtcp_rr_t;
+
+typedef struct
+  {
+    u_int8_t type;             /* type of SDES item (rtcp_sdes_type_t) */
+    u_int8_t length;           /* length of SDES item (in octets) */
+    char data[1];            /* text, not zero-terminated */
+  }
+rtcp_sdes_item_t;
+
+/* one RTCP packet */
+typedef struct
+  {
+    rtcp_common_t common;    /* common header */
+    union
+      {
+        /* sender report (SR) */
+        struct
+          {
+            u_int32_t ssrc;        /* source this RTCP packet refers to */
+            u_int32_t ntp_sec;     /* NTP timestamp */
+            u_int32_t ntp_frac;
+            u_int32_t rtp_ts;      /* RTP timestamp */
+            u_int32_t psent;       /* packets sent */
+            u_int32_t osent;       /* octets sent */
+            /* variable-length list */
+            rtcp_rr_t rr[1];
+          }
+        sr;
+
+        /* reception report (RR) */
+        struct
+          {
+            u_int32_t ssrc;        /* source this generating this report */
+            /* variable-length list */
+            rtcp_rr_t rr[1];
+          }
+        rr;
+
+        /* BYE */
+        struct
+          {
+            u_int32_t src[1];      /* list of sources */
+            /* can't express trailing text */
+          }
+        bye;
+
+        /* source description (SDES) */
+        struct rtcp_sdes_t
+          {
+            u_int32_t src;              /* first SSRC/CSRC */
+            rtcp_sdes_item_t item[1]; /* list of SDES items */
+          }
+        sdes;
+      } r;
+  }
+rtcp_t;
+
+#endif
diff --git a/src/rtp_pt.h b/src/rtp_pt.h
new file mode 100644 (file)
index 0000000..2478f83
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * rtp_pt.h by xenion -- 2008-05-05 -- v.4464c61a1c3fe5803ccbaa426c87a448
+ *
+ * Copyright (c) 2007-2008 Dallachiesa Michele <micheleDOTdallachiesaATposteDOTit>
+ *
+ *
+ * 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
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+/*
+ * RTP Payload types, from Wireshark sources.
+ * Table B.2 / H.225.0
+ * Also RFC 1890, and
+ * http://www.iana.org/assignments/rtp-parameters
+ */
+
+
+typedef struct
+  {
+    int type;
+    char *str;
+  }
+value_string;
+
+
+#define PT_PCMU         0       /* RFC 1890 */
+#define PT_1016         1       /* RFC 1890 */
+#define PT_G721         2       /* RFC 1890 */
+#define PT_GSM          3       /* RFC 1890 */
+#define PT_G723         4       /* From Vineet Kumar of Intel; see the Web page */
+#define PT_DVI4_8000    5       /* RFC 1890 */
+#define PT_DVI4_16000   6       /* RFC 1890 */
+#define PT_LPC          7       /* RFC 1890 */
+#define PT_PCMA         8       /* RFC 1890 */
+#define PT_G722         9       /* RFC 1890 */
+#define PT_L16_STEREO   10      /* RFC 1890 */
+#define PT_L16_MONO     11      /* RFC 1890 */
+#define PT_QCELP        12      /* Qualcomm Code Excited Linear Predictive coding? */
+#define PT_CN           13      /* RFC 3389 */
+#define PT_MPA          14      /* RFC 1890, RFC 2250 */
+#define PT_G728         15      /* RFC 1890 */
+#define PT_DVI4_11025   16      /* from Joseph Di Pol of Sun; see the Web page */
+#define PT_DVI4_22050   17      /* from Joseph Di Pol of Sun; see the Web page */
+#define PT_G729         18
+#define PT_CN_OLD       19      /* Payload type reserved (old version Comfort Noise) */
+#define PT_CELB         25      /* RFC 2029 */
+#define PT_JPEG         26      /* RFC 2435 */
+#define PT_NV           28      /* RFC 1890 */
+#define PT_H261         31      /* RFC 2032 */
+#define PT_MPV          32      /* RFC 2250 */
+#define PT_MP2T         33      /* RFC 2250 */
+#define PT_H263         34      /* from Chunrong Zhu of Intel; see the Web page */
+
+
+const  value_string rtp_payload_type_vals[] =
+{
+  {
+    PT_PCMU,      "ITU-T G.711 PCMU"
+  },
+  { PT_1016,      "USA Federal Standard FS-1016" },
+  { PT_G721,      "ITU-T G.721" },
+  { PT_GSM,       "GSM 06.10" },
+  { PT_G723,      "ITU-T G.723" },
+  { PT_DVI4_8000, "DVI4 8000 samples/s" },
+  { PT_DVI4_16000, "DVI4 16000 samples/s" },
+  { PT_LPC,       "Experimental linear predictive encoding from Xerox PARC" },
+  { PT_PCMA,      "ITU-T G.711 PCMA" },
+  { PT_G722,      "ITU-T G.722" },
+  { PT_L16_STEREO, "16-bit uncompressed audio, stereo" },
+  { PT_L16_MONO,  "16-bit uncompressed audio, monaural" },
+  { PT_QCELP,     "Qualcomm Code Excited Linear Predictive coding" },
+  { PT_CN,        "Comfort noise" },
+  { PT_MPA,       "MPEG-I/II Audio"},
+  { PT_G728,      "ITU-T G.728" },
+  { PT_DVI4_11025, "DVI4 11025 samples/s" },
+  { PT_DVI4_22050, "DVI4 22050 samples/s" },
+  { PT_G729,      "ITU-T G.729" },
+  { PT_CN_OLD,    "Comfort noise (old)" },
+  { PT_CELB,      "Sun CellB video encoding" },
+  { PT_JPEG,      "JPEG-compressed video" },
+  { PT_NV,        "'nv' program" },
+  { PT_H261,      "ITU-T H.261" },
+  { PT_MPV,       "MPEG-I/II Video"},
+  { PT_MP2T,      "MPEG-II transport streams"},
+  { PT_H263,      "ITU-T H.263" },
+  { 0,            NULL },
+};
+
+
+const value_string rtp_payload_type_short_vals[] =
+{
+  {
+    PT_PCMU,      "g711U"
+  },
+  { PT_1016,      "fs-1016" },
+  { PT_G721,      "g721" },
+  { PT_GSM,       "GSM" },
+  { PT_G723,      "g723" },
+  { PT_DVI4_8000, "DVI4 8k" },
+  { PT_DVI4_16000, "DVI4 16k" },
+  { PT_LPC,       "Exp. from Xerox PARC" },
+  { PT_PCMA,      "g711A" },
+  { PT_G722,      "g722" },
+  { PT_L16_STEREO, "16-bit audio, stereo" },
+  { PT_L16_MONO,  "16-bit audio, monaural" },
+  { PT_QCELP,     "Qualcomm" },
+  { PT_CN,        "CN" },
+  { PT_MPA,       "MPEG-I/II Audio"},
+  { PT_G728,      "g728" },
+  { PT_DVI4_11025, "DVI4 11k" },
+  { PT_DVI4_22050, "DVI4 22k" },
+  { PT_G729,      "g729" },
+  { PT_CN_OLD,    "CN(old)" },
+  { PT_CELB,      "CellB" },
+  { PT_JPEG,      "JPEG" },
+  { PT_NV,        "NV" },
+  { PT_H261,      "h261" },
+  { PT_MPV,       "MPEG-I/II Video"},
+  { PT_MP2T,      "MPEG-II streams"},
+  { PT_H263,      "h263" },
+  { 0,            NULL },
+};
+
+/* eof */
+