Browse Source

Import upstream version 1.4.99.15+hg127

Christoph Biedl 4 years ago
commit
29fe5b13c9
25 changed files with 6276 additions and 0 deletions
  1. 1 0
      .cvsignore
  2. 6 0
      .hg_archival.txt
  3. 19 0
      .hgignore
  4. 9 0
      .hgtags
  5. 309 0
      COPYING
  6. 208 0
      ChangeLog
  7. 64 0
      Makefile.in
  8. 8 0
      README
  9. 1856 0
      bgpdump.c
  10. 60 0
      bgpdump.spec.in
  11. 226 0
      bgpdump_attr.h
  12. 267 0
      bgpdump_formats.h
  13. 1484 0
      bgpdump_lib.c
  14. 64 0
      bgpdump_lib.h
  15. 103 0
      bgpdump_mstream.c
  16. 49 0
      bgpdump_mstream.h
  17. 5 0
      bootstrap.sh
  18. 551 0
      cfile_tools.c
  19. 91 0
      cfile_tools.h
  20. 41 0
      configure.in
  21. 433 0
      example.c
  22. 259 0
      inet_ntop.c
  23. 25 0
      test.sh
  24. 93 0
      util.c
  25. 45 0
      util.h

+ 1 - 0
.cvsignore

@@ -0,0 +1 @@
+.project

+ 6 - 0
.hg_archival.txt

@@ -0,0 +1,6 @@
+repo: fc85b5d83c23266299237988401380dcb3d3c4f3
+node: cfcbe1f5bfc5da2f634ae576809acd0e91f8ff09
+branch: default
+latesttag: 1.4.99.15
+latesttagdistance: 14
+changessincelatesttag: 14

+ 19 - 0
.hgignore

@@ -0,0 +1,19 @@
+\.o$
+\.pbxuser$
+\.mode1v3$
+\.swp$
+^bgpdump-config.h$
+^config.log$
+^config.status$
+^bgpdump$
+^testbgpdump$
+^libbgpdump.a$
+^libbgpdump.so$
+^Makefile$
+^test_out/.*
+^build/
+^bgpdump.spec$
+~$
+^libbgpdump-.*\.tgz$
+^autom4te.cache/
+.DS_Store

+ 9 - 0
.hgtags

@@ -0,0 +1,9 @@
+6271706a4a0e495b2cc5e48822d0d73abfc55807 1.4.98.7
+e9617d1b0fa959ad3436797701d027958b335667 1.4.99.8
+aeead79922f7eeac5d8e678b43101deef02cf847 1.4.99.9
+397bfe76c57fe46694ac06735843575683c772e6 1.4.99.10
+4cce25d5026009a1ba2924afa8b10907ecf4498e 1.4.99.11
+9fe2f50927688e4560941e655b3c970c4b668540 1.4.99.12
+b8e3ed2b370ca220f46bfa59193665dfdee5d5ef 1.4.99.13
+c4c53146f09af40a0068992d67a345a05ac54514 1.4.99.14
+d8e8bcf60eb4c7ce065b2744d6a32003c728d8b2 1.4.99.15

+ 309 - 0
COPYING

@@ -0,0 +1,309 @@
+
+Copyright (C) 2007 - 2011 RIPE NCC
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of the author not be used in advertising or
+publicity pertaining to distribution of the software without specific,
+written prior permission.
+
+THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+
+----------------------------------------------------------------------------
+
+Parts of this code have been engineered after analiyzing GNU Zebra's
+source code and therefore might contain declarations/code from GNU
+Zebra, Copyright (C) 1999 Kunihiro Ishiguro. Zebra is a free routing
+software, distributed under the GNU General Public License. A copy of
+this license is included with libbgpdump.
+
+----------------------------------------------------------------------------
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, 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 Library 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
+

+ 208 - 0
ChangeLog

@@ -0,0 +1,208 @@
+==========================================================
+The current maintainer of this library is the
+RIPE NCC information services department.
+
+You can reach us at https://bitbucket.org/ripencc/bgpdump
+
+PLEASE DO NOT E-MAIL INDIVIDUAL DEVELOPERS ABOUT
+ISSUES, AS YOUR E-MAIL MAY BE LOST
+==========================================================
+2015-10-08 Alexis Fasquel <alexis@pch.net>
+	* Adding support for Extended Timestamp MRT Header corresponding to MRT type BGP4MP_ET
+	  Note that this changes the semantics of the output of bgpdump - when a messages
+	  with Extended Timestamp MRT Header is parsed, the microseconds attribute
+	  is appended to the timestamp (.xxxxxx)
+
+2015-09-19 Colin Petrie <cpetrie@ripe.net>
+	* Adding support for BGP4MP_MESSAGE_LOCAL and BGP4MP_MESSAGE_AS4_LOCAL subtypes
+	  Note that this changes the semantics of the output of bgpdump - when an entry is
+	  prefixed by BG4MP_LOCAL (-m/-M) then the output fields are the *destination* IP/AS
+	  rather than the source.
+
+2015-07-16 Max Lapan <mlapan@ripe.net>
+	* -p option to show packet index
+
+2011-01-25 Devin Bayer <dbayer@ripe.net>
+	* move development to bitbucket
+
+2010-10-21 Devin Bayer <dbayer@ripe.net> v1.4.99.13
+	* fix configure script for Darwin
+
+2010-09-24 Devin Bayer <dbayer@ripe.net> v1.4.99.12
+	* Remove --disable-ipv6 flag
+        * Fix parsing of IPv6 NEXT_HOP attributes
+        * Add clearer command-line options
+        * Add logging to STDERR
+        * Add dumping to files instead of STDOUT
+        * Add regression test suite
+
+2009-11-24 Roman Kalyakin <roman@ripe.net> v1.4.99.11
+	* Fixed incorrect output when running with -m which was
+	  introduced by a change in one of the previous versions.
+	  (issue IS-439)
+
+2009-10-13 Ruben van Staveren <ruben@ripe.net>
+	* Fix segfaults with empty AS path on -m/-M 
+	  (issue IS-292)
+	  Patch contributed by Lorenzo Colitti <lorenzo@google.com> 
+
+2009-07-29 Erik Romijn <eromijn@ripe.net>
+	* Fixing incorrect as path length count in case of AS_(CONFED_)SEQUENCE
+	  (issue IS-141)
+	  Patch contributed by Toby Ehrenkranz <tehrenkr@cs.uoregon.edu>
+	* Added support for the ORIGINATOR_ID and CLUSTER_LIST attributes
+	  (issue IS-181)
+	  Patch contributed by Maurizio Pizzonia <pizzonia@dia.uniroma3.it>
+	* Fixed signedness of MED and localpref (issue IS-180)
+	  Patch contributed by Steve Hill <cheesy@sackheads.org>
+	* Implemented conditional checking for compression libraries (issue IS-179)
+	  Patch contributed by Steve Hill <cheesy@sackheads.org>
+
+2009-07-27 Ruben van Staveren <ruben@ripe.net>
+	* Enabled extra compiler warnings
+	* Fixed some potentially unsafe constructs (pointer arithmetic,
+	  signed/unsigned comparisons, shadowed variables) 
+
+2009-07-22 Ruben van Staveren <ruben@ripe.net>
+	* Fixed a case where during -M dumps aspaths where printed for entries that
+	  did not have their BGP_ATTR_AS_PATH flag set. Such entries will now print
+	  an empty field. Reported by many people.
+	* Changed -fpic to -fPIC: newer gccs coerce -fpic to -fPIC any way.
+	  difference is that with -fpic the global offset table has a maximum size
+	* Fixed nit in getopt handling
+	* Added distclean target
+	* In bgpdump_free_mp_info(), set pointers to NULL after freeing them.
+	  Reported by Robert Kisteleki <robertk@ripe.net>
+	* Default output for 32bit ASN numbers is now ASPLAIN
+
+2008-02-01 Erik Romijn <eromijn@ripe.net>
+	* Fixed a few memleaks based on a patch from
+	  Antony Antony <antony@phenome.org>
+	  (Ticket NCC#2007064868)
+	* Fixed compiling with --disable-ipv6 based on a patch
+	  from Haniff Rahbari <hnrahbari@yahoo.com>
+	  (Ticket NCC#2007111325)
+	* Fixed a few warnings, mostly based on a patch from
+	  Bruno Quoitin <bruno.quoitin@uclouvain.be>
+	  (Ticket NCC#2007123069)
+	* Made bgpdump's usage message nicer
+
+2007-06-21 Erik Romijn <eromijn@ripe.net>
+    * Fixed incorrect dump time display for some cases
+
+2007-06-06 Erik Romijn <eromijn@ripe.net>
+    * Set proper compile options to work on Mac OS X 10.4
+
+2007-06-01 Erik Romijn <eromijn@ripe.net>
+    * Fixed several bugs in 64-bit PC support and added
+	  bzip2 support, credit goes to
+	  Bernhard Tellenbach <betellen@tik.ee.ethz.ch>
+	  for providing patches.
+	* Fixed incorrect IPv6 nexthops in -M/-m output
+
+2007-03-29 Erik Romijn <eromijn@ripe.net>
+	* Fixed a serious segfault in the insertion of update dumps
+
+2007-03-28 Erik Romijn <eromijn@ripe.net>
+	* Fixed a large memory leak in TABLE_DUMP_V2 processing
+
+2007-03-27 Erik Romijn <eromijn@ripe.net>
+	* Fixed a bug causing segfaults on processing some MP_REACH_NLRI's
+
+2007-03-09 Erik Romijn <eromijn@ripe.net>
+	* Updated TABLE_DUMP_V2 support to comply with draft-ietf-grow-mrt-04
+
+2007-03-07 Erik Romijn <eromijn@ripe.net>
+	* Built in TABLE_DUMP_V2 support
+	* Rename ..MESSAGE32 to ..MESSAGE_AS4
+	* Fixed bug where -M always crashed
+
+2007-02-01 Erik Romijn <eromijn@ripe.net>
+	* Minor fix in ASN32 support
+
+2006-10-20 Lorenzo Colitti <lorenzo@ripe.net>
+	* Implement ASN32 support
+
+2005-11-08 Young Hyun <youngh@caida.org>
+	* IPv6 prefixes were not printed properly by bgpdump.
+
+2004-02-10 Lorenzo Colitti <lorenzo@ripe.net>
+	* Fix a stupid crash when reading truncated prefixes.
+
+2004-02-09 Lorenzo Colitti <lorenzo@ripe.net>
+	* Decode unknown attributes properly.
+	* Fix a crash when reading truncated prefixes.
+
+2004-02-04 Hong-wei Kong  <hong-wei_kong@agilent.com>
+        * Add a new option (-t dump|change) to bgpdump. If '-t dump' is 
+	  specified, then the decoding result with '-m' / '-M' option will
+	  show the timestamp when these routes are dumped. If '-t change' is
+	  specified, then the decoding result with '-m' / '-M' option will
+	  show the timestamp when the routes were last time changed. This 
+	  option only works with routing table dumps.
+
+2004-01-16 Lorenzo Colitti <lorenzo@ripe.net>
+	* Fix compile errors under cygwin (only IPv4 works though)
+
+2003-12-18 Hong-Wei Kong <hong-wei_kong@agilent.com>
+	* Added support for dumping BGP routing table entries in
+	  machine-readable format (-m). Previously -m was only supported
+	  for BGP messages
+
+2003-12-16 Shufu Mao <msf98@mails.tsinghua.edu.cn>
+	* Revised the decoding of BGP routing table dump to make the result
+	  identical to route_btoa
+
+2003-12-15  Lorenzo Colitti <lorenzo@ripe.net>
+	* Proper autoconf support: check for features instead of target
+	  systems, remove extra .h files and only use configure.in, use
+	  Makefile.in instead of Make.include, link both static and
+	  shared library, check for ar and ranlib, etc.
+	* Changed INET6 to BGPDUMP_HAVE_IPV6
+	  (N.B. Docs are not updated yet)
+	* Fixed possible endianness issues on Sparc.
+	* Fixed a crash while decoding NOTIFICATION messages
+
+2003-11-26  Shufu Mao <msf98@mails.tsinghua.edu.cn>
+
+	* Workaround for zebra "NOIP" bug
+	* Preliminary autoconf support (./configure; make)
+	* Added option to disable IPv6. If this option is specified to
+	  ./configure, the library is compiled without IPv6 support.
+	  The default is to turn on IPv6 if the necessary headers are
+	  available.
+
+2003-11-25  Lorenzo Colitti <lorenzo@ripe.net>
+
+	* Added support for OPEN and NOTIFICATION messages.
+	* Better workarounds for corrupt data produced by zebra/quagga bugs.
+	* The library now keeps track of how many records were parsed and how
+	  many were successfully parsed.
+	* Better error reporting. Now an error will be logged through syslog
+	  whenever a record cannot be decoded.
+	* Agilent Labs contributed bgpdump, a tool which emulates route_btoa
+	  using libbgpdump. This should be a drop-in replacement for people
+	  currently using route_btoa and supports IPv6 on all platforms.
+
+2003-10-15  Lorenzo Colitti <lorenzo@ripe.net>
+
+	* 1.3.1 beta released
+	* Added support for reading from gzipped input files and gzipped stdin.
+	  NOTE: this means you must now link with zlib!
+	* Changed Makefile to build a shared library by default.
+	* Renamed test program from test2 to testbgpdump.
+
+2003-10-15  Lorenzo Colitti <lorenzo@ripe.net>
+
+	* 1.3 beta released
+	* Added IPv6 support. Note that this changes some interfaces!
+	  See README.ipv6 for details.
+	* Set announce and withdraw arrays to NULL to avoid segfaults if there
+	  is a parse error.
+	* Change mstream behaviour so it always returns zero bytes if reading
+	  past the end of a packet. This eliminates non-deterministic
+	  behaviour (random segfaults, infinite loops, ...) when parsing
+	  corrupt data, including the consequences of the zebra "update packet
+	  truncated at 4096 bytes" bug.
+	* Other fixes to handle corrupt data better.
+	* Other miscellaneous fixes.

+ 64 - 0
Makefile.in

@@ -0,0 +1,64 @@
+
+CC	= @CC@ -fPIC
+CFLAGS	= @CFLAGS@
+COMPILE  = $(CC) $(CFLAGS) $(INCLUDES)
+
+LD	= @CC@
+LDFLAGS	= @LDFLAGS@
+RANLIB	= @RANLIB@
+
+SYS_LIBS= @LIBS@
+
+prefix   = @prefix@
+exec_prefix = @exec_prefix@
+bindir   = @bindir@
+libdir   = @libdir@
+includedir = @includedir@
+
+LIB_H	 = bgpdump_attr.h bgpdump_formats.h bgpdump_lib.h bgpdump_mstream.h
+LIB_O	 = bgpdump_lib.o bgpdump_mstream.o cfile_tools.o util.o inet_ntop.o
+OTHER    = *.in configure bgpdump.spec README* ChangeLog License*
+
+all: libbgpdump.so bgpdump 
+
+libbgpdump.a: $(LIB_H) $(LIB_O) Makefile cfile_tools.h util.h
+	ar r libbgpdump.a $(LIB_O)
+	$(RANLIB) libbgpdump.a
+
+libbgpdump.so: libbgpdump.a
+	$(COMPILE) $(LDFLAGS) -o libbgpdump.so $(LIB_O) $(SYS_LIBS)
+
+example: example.c libbgpdump.a
+	$(COMPILE) -o example example.c libbgpdump.a $(SYS_LIBS)
+
+bgpdump: bgpdump.c libbgpdump.a
+	$(COMPILE) -o bgpdump bgpdump.c libbgpdump.a $(SYS_LIBS)
+
+check-clean:
+	rm -f test_out/*.bgp.gz
+
+check: check-clean bgpdump
+	./test.sh
+
+clean: check-clean
+	rm -f libbgpdump.so libbgpdump.a example bgpdump $(LIB_O)
+
+distclean: clean
+	rm -Rf config.log config.status *.dSYM core *.core autom4te.cache bgpdump-config.h Makefile
+	rm -Rf $(PKG)
+
+install: all
+	install -d $(bindir) $(includedir) $(libdir)
+	install bgpdump $(bindir)
+	install $(LIB_H) $(includedir)
+	install libbgpdump.so libbgpdump.a $(libdir)
+
+PKG=@PACKAGE_NAME@-@PACKAGE_VERSION@
+dist:
+	mkdir $(PKG)
+	ln *.h *.c $(OTHER) $(PKG)
+	tar -czf $(PKG).tgz $(PKG)
+	rm $(PKG)/* && rmdir $(PKG)
+
+rpm: dist
+	rpmbuild -v -ta $(PKG).tgz

+ 8 - 0
README

@@ -0,0 +1,8 @@
+== libBGPdump ==
+
+A C library designed to help with analyzing dump
+files produced by Zebra/Quagga or MRT. Documenation
+is available at:
+
+https://bitbucket.org/ripencc/bgpdump/wiki/Home
+

File diff suppressed because it is too large
+ 1856 - 0
bgpdump.c


+ 60 - 0
bgpdump.spec.in

@@ -0,0 +1,60 @@
+Summary: MRT file reader
+Name: @PACKAGE_NAME@
+Version: @PACKAGE_VERSION@
+Release: 1
+License: GPL
+URL: http://www.ris.ripe.net/source/
+Vendor: RIPE NCC Information Services department
+Group: System Environment/Libraries
+Source: @PACKAGE_NAME@-@PACKAGE_VERSION@.tgz
+BuildRoot: /var/tmp/%{name}-root
+BuildRequires: bzip2-devel zlib-devel
+
+%description
+This library reads MRT files as, amongst others, produced
+by the RIPE NCC routing information service.
+
+This library is maintained by the RIPE NCC Information
+Services department: ris@ripe.net
+
+%package devel
+Summary: Libraries, includes to develop applications with %{name}.
+Group: Development/Libraries
+Requires: %{name} = %{version}
+
+%description devel
+The %{name}-devel package contains the header files and static libraries for
+building applications which use %{name}.
+
+
+%prep
+%setup
+
+%build
+%configure
+make CFLAGS="$RPM_OPT_FLAGS"
+
+%install
+rm -rf %{buildroot}
+%makeinstall
+
+%clean
+rm -rf %{buildroot}
+
+%files
+%defattr(0755,root,root)
+%{_bindir}/bgpdump
+%defattr(-,root,root)
+%{_libdir}/libbgpdump.a
+%{_libdir}/libbgpdump.so
+
+%files devel
+%defattr(-,root,root)
+%{_includedir}/bgpdump_attr.h
+%{_includedir}/bgpdump_formats.h
+%{_includedir}/bgpdump_lib.h
+%{_includedir}/bgpdump_mstream.h
+
+%changelog
+* Wed Jul 04 2008 Erik Romijn <eromijn@ripe.net> 1.4.99.9-1
+- Initial release

+ 226 - 0
bgpdump_attr.h

@@ -0,0 +1,226 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ 
+Parts of this code have been engineered after analiyzing GNU Zebra's
+source code and therefore might contain declarations/code from GNU
+Zebra, Copyright (C) 1999 Kunihiro Ishiguro. Zebra is a free routing
+software, distributed under the GNU General Public License. A copy of
+this license is included with libbgpdump.
+
+Original Author: Dan Ardelean (dan@ripe.net)
+*/
+
+#ifndef _BGPDUMP_ATTR_H
+#define _BGPDUMP_ATTR_H
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/* BGP Attribute flags. */
+#define BGP_ATTR_FLAG_OPTIONAL  0x80	/* Attribute is optional. */
+#define BGP_ATTR_FLAG_TRANS     0x40	/* Attribute is transitive. */
+#define BGP_ATTR_FLAG_PARTIAL   0x20	/* Attribute is partial. */
+#define BGP_ATTR_FLAG_EXTLEN    0x10	/* Extended length flag. */
+
+/* BGP attribute type codes.  */
+#define BGP_ATTR_ORIGIN                    1
+#define BGP_ATTR_AS_PATH                   2
+#define BGP_ATTR_NEXT_HOP                  3
+#define BGP_ATTR_MULTI_EXIT_DISC           4
+#define BGP_ATTR_LOCAL_PREF                5
+#define BGP_ATTR_ATOMIC_AGGREGATE          6
+#define BGP_ATTR_AGGREGATOR                7
+#define BGP_ATTR_COMMUNITIES               8
+#define BGP_ATTR_ORIGINATOR_ID             9
+#define BGP_ATTR_CLUSTER_LIST             10
+#define BGP_ATTR_DPA                      11
+#define BGP_ATTR_ADVERTISER               12
+#define BGP_ATTR_RCID_PATH                13
+#define BGP_ATTR_MP_REACH_NLRI            14
+#define BGP_ATTR_MP_UNREACH_NLRI          15
+#define BGP_ATTR_EXT_COMMUNITIES          16
+#define BGP_ATTR_NEW_AS_PATH              17
+#define BGP_ATTR_NEW_AGGREGATOR           18
+
+/* Flag macro */
+#define ATTR_FLAG_BIT(X)  (1 << ((X) - 1))
+
+/* BGP ASPATH attribute defines */
+#define AS_HEADER_SIZE        2	 
+
+#define AS_SET             1
+#define AS_SEQUENCE        2
+#define AS_CONFED_SEQUENCE 3
+#define AS_CONFED_SET      4
+
+#define AS_SEG_START 0
+#define AS_SEG_END 1
+
+#define ASPATH_STR_DEFAULT_LEN 32
+#define ASPATH_STR_ERROR       "! Error !"
+
+/* BGP COMMUNITY attribute defines */
+
+#define COMMUNITY_NO_EXPORT             0xFFFFFF01
+#define COMMUNITY_NO_ADVERTISE          0xFFFFFF02
+#define COMMUNITY_NO_EXPORT_SUBCONFED   0xFFFFFF03
+#define COMMUNITY_LOCAL_AS              0xFFFFFF03
+
+#define com_nthval(X,n)  ((X)->val + (n))
+
+/* MP-BGP address families */
+#ifdef BGPDUMP_HAVE_IPV6
+#define AFI_IP 1
+#define AFI_IP6 2
+#define BGPDUMP_MAX_AFI AFI_IP6
+#else
+#define AFI_IP 1
+#define BGPDUMP_MAX_AFI AFI_IP
+#endif
+
+#define SAFI_UNICAST		1
+#define SAFI_MULTICAST		2
+#define SAFI_UNICAST_MULTICAST	3
+#define BGPDUMP_MAX_SAFI SAFI_UNICAST_MULTICAST
+
+struct unknown_attr
+{
+	int	flag;
+	int	type;
+	int	len;
+	u_char *raw;
+};
+
+typedef u_int32_t as_t;
+
+typedef struct attr attributes_t;
+struct attr
+{
+  /* Flag of attribute is set or not. */
+  u_int32_t flag;
+
+  /* Attributes. */
+  int                   origin;
+  struct in_addr 	nexthop;
+  u_int32_t 		med;
+  u_int32_t 		local_pref;
+  as_t 			aggregator_as;
+  struct in_addr 	aggregator_addr;
+  u_int32_t 		weight;
+  struct in_addr 	originator_id;
+  struct cluster_list	*cluster;
+
+  struct aspath 	*aspath;
+  struct community 	*community;
+  struct ecommunity 	*ecommunity;
+  struct transit 	*transit;
+  
+  /* libbgpdump additions */
+  
+  struct mp_info	*mp_info;
+  u_int16_t		len;
+  caddr_t		data;
+
+  u_int16_t		unknown_num;
+  struct unknown_attr	*unknown;
+
+  /* ASN32 support */
+  struct aspath 	*new_aspath;
+  struct aspath 	*old_aspath;
+  as_t			new_aggregator_as;
+  as_t			old_aggregator_as;
+  struct in_addr 	new_aggregator_addr;
+  struct in_addr 	old_aggregator_addr;
+};
+
+struct community 
+{
+  int 			size;
+  u_int32_t 		*val;
+  char			*str;
+};
+
+struct cluster_list
+{
+  int			length;
+  struct in_addr 	*list;
+};
+
+struct transit
+{
+  int 			length;
+  u_char 		*val;
+};
+
+struct aspath 
+{
+  u_int8_t		asn_len;
+  int 			length;
+  int 			count;
+  caddr_t 		data;
+  char 			*str;
+};
+
+struct assegment
+{
+  u_char type;
+  u_char length;
+  char data[0];
+};
+
+struct mp_info {
+  /* AFI and SAFI start from 1, so the arrays must be 1-based */
+  struct mp_nlri	*withdraw[BGPDUMP_MAX_AFI+1][BGPDUMP_MAX_SAFI+1];
+  struct mp_nlri	*announce[BGPDUMP_MAX_AFI+1][BGPDUMP_MAX_SAFI+1];
+};
+
+#ifdef BGPDUMP_HAVE_IPV6
+#define MP_IPV6_ANNOUNCE(m) ((m)->announce[AFI_IP6][SAFI_UNICAST])
+#define MP_IPV6_WITHDRAW(m) ((m)->withdraw[AFI_IP6][SAFI_UNICAST])
+#endif
+
+typedef union union_BGPDUMP_IP_ADDRESS {
+    struct in_addr	v4_addr;
+    struct in6_addr	v6_addr;
+} BGPDUMP_IP_ADDRESS;
+
+
+#define BGPDUMP_ADDRSTRLEN 46
+
+#define ASN16_LEN sizeof(u_int16_t)
+#define ASN32_LEN sizeof(u_int32_t)
+
+#define AS_TRAN 23456
+
+struct prefix {
+    BGPDUMP_IP_ADDRESS	address;
+    u_char		len;
+};
+
+#define MAX_PREFIXES 2050
+struct mp_nlri {
+  u_char		nexthop_len;
+
+  BGPDUMP_IP_ADDRESS	nexthop;
+  BGPDUMP_IP_ADDRESS 	nexthop_local;
+
+  u_int16_t		prefix_count;
+  struct prefix		nlri[MAX_PREFIXES];
+};
+
+#endif /* _BGPDUMP_ATTR_H */

+ 267 - 0
bgpdump_formats.h

@@ -0,0 +1,267 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Parts of this code have been engineered after analiyzing GNU Zebra's
+source code and therefore might contain declarations/code from GNU
+Zebra, Copyright (C) 1999 Kunihiro Ishiguro. Zebra is a free routing
+software, distributed under the GNU General Public License. A copy of
+this license is included with libbgpdump.
+
+Original Author: Dan Ardelean (dan@ripe.net)
+*/
+
+#ifndef _BGPDUMP_FORMATS_H
+#define _BGPDUMP_FORMATS_H
+
+#include "bgpdump_attr.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <netinet/in.h>
+
+/* type and subtypes values */
+/* RFC6396 */
+#define BGPDUMP_TYPE_MRTD_BGP			5
+#define BGPDUMP_SUBTYPE_MRTD_BGP_NULL		0
+#define BGPDUMP_SUBTYPE_MRTD_BGP_UPDATE		1
+#define BGPDUMP_SUBTYPE_MRTD_BGP_PREFUPDATE	2
+#define BGPDUMP_SUBTYPE_MRTD_BGP_STATE_CHANGE	3
+#define BGPDUMP_SUBTYPE_MRTD_BGP_SYNC		4
+#define BGPDUMP_SUBTYPE_MRTD_BGP_OPEN		5
+#define BGPDUMP_SUBTYPE_MRTD_BGP_NOTIFICATION	6
+#define BGPDUMP_SUBTYPE_MRTD_BGP_KEEPALIVE	7
+#define BGPDUMP_SUBTYPE_MRTD_BGP_ROUT_REFRESH	133
+
+#define BGPDUMP_TYPE_MRTD_TABLE_DUMP				12
+#define BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP			1
+#define BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6			2
+#define BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP_32BIT_AS		3
+#define BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6_32BIT_AS	4
+
+#define BGPDUMP_TYPE_TABLE_DUMP_V2                       13
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_PEER_INDEX_TABLE    1
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_UNICAST    2
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV4_MULTICAST  3
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_UNICAST    4
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_IPV6_MULTICAST  5
+#define BGPDUMP_SUBTYPE_TABLE_DUMP_V2_RIB_GENERIC         6
+#define BGPDUMP_PEERTYPE_TABLE_DUMP_V2_AFI_IP             0
+#define BGPDUMP_PEERTYPE_TABLE_DUMP_V2_AFI_IP6            1
+#define BGPDUMP_PEERTYPE_TABLE_DUMP_V2_AS2                0
+#define BGPDUMP_PEERTYPE_TABLE_DUMP_V2_AS4                2
+#define BGPDUMP_TYPE_TABLE_DUMP_V2_MAX_VIEWNAME_LEN     255
+
+/* Zebra record types */
+#define BGPDUMP_TYPE_ZEBRA_BGP			16 /* MSG_PROTOCOL_BGP4MP */
+#define BGPDUMP_TYPE_ZEBRA_BGP_ET       17 /* MSG_PROTOCOL_BGP4MP_ET */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_STATE_CHANGE	0  /* BGP4MP_STATE_CHANGE */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE	1  /* BGP4MP_MESSAGE */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_ENTRY		2  /* BGP4MP_ENTRY */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_SNAPSHOT	3  /* BGP4MP_SNAPSHOT */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4	4  /* BGP4MP_MESSAGE_AS4 */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_STATE_CHANGE_AS4	5  /* BGP4MP_STATE_CHANGE_AS4 */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_LOCAL	6  /* BGP4MP_MESSAGE_LOCAL */
+#define BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4_LOCAL	7  /* BGP4MP_MESSAGE_AS4_LOCAL */
+
+/* BGP state - defined in RFC1771 */
+#define BGP_STATE_IDLE		1
+#define BGP_STATE_CONNECT	2
+#define BGP_STATE_ACTIVE	3
+#define BGP_STATE_OPENSENT	4
+#define BGP_STATE_OPENCONFIRM	5
+#define BGP_STATE_ESTABLISHED	6
+
+/* BGP message types */
+#define	BGP_MSG_OPEN		           1
+#define	BGP_MSG_UPDATE		           2
+#define	BGP_MSG_NOTIFY		           3
+#define	BGP_MSG_KEEPALIVE	           4
+#define BGP_MSG_ROUTE_REFRESH_01           5
+#define BGP_MSG_ROUTE_REFRESH	         128
+
+typedef struct struct_BGPDUMP_MRTD_TABLE_DUMP {
+    u_int16_t		view;
+    u_int16_t		sequence;
+    BGPDUMP_IP_ADDRESS	prefix;
+    u_char		mask;
+    u_char		status;
+    time_t		uptime;
+    BGPDUMP_IP_ADDRESS	peer_ip;
+    as_t		peer_as;
+    u_int16_t		attr_len;
+} BGPDUMP_MRTD_TABLE_DUMP;
+
+
+typedef struct struct_BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE_ENTRY {
+	u_char              afi;
+	BGPDUMP_IP_ADDRESS  peer_ip;
+	struct in_addr      peer_bgp_id;
+	as_t                peer_as;
+} BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE_ENTRY;
+
+typedef struct struct_BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE {
+	struct in_addr      local_bgp_id;
+	char                view_name[BGPDUMP_TYPE_TABLE_DUMP_V2_MAX_VIEWNAME_LEN];
+	uint16_t            peer_count;
+	BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE_ENTRY  *entries;
+} BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE;
+
+typedef struct struct_BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY {
+	uint16_t            peer_index;
+	uint32_t            originated_time;
+	BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE_ENTRY *peer;
+        attributes_t        *attr;
+} BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY;
+
+typedef struct struct_BGPDUMP_TABLE_DUMP_V2_PREFIX {
+	uint32_t            seq;
+	uint16_t            afi;
+	uint8_t             safi;
+	u_char              prefix_length;
+	BGPDUMP_IP_ADDRESS  prefix;
+	uint16_t            entry_count;
+	BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY *entries;
+} BGPDUMP_TABLE_DUMP_V2_PREFIX;
+
+
+
+/* For Zebra BGP4MP_STATE_CHANGE */
+typedef struct struct_BGPDUMP_ZEBRA_STATE_CHANGE {
+    as_t		source_as;
+    as_t		destination_as;
+    u_int16_t		interface_index;
+    u_int16_t		address_family;
+    BGPDUMP_IP_ADDRESS	source_ip;
+    BGPDUMP_IP_ADDRESS	destination_ip;
+    u_int16_t		old_state;
+    u_int16_t		new_state;
+} BGPDUMP_ZEBRA_STATE_CHANGE;
+
+struct zebra_incomplete {
+    u_int16_t afi;
+    u_int8_t orig_len;
+    struct prefix prefix;
+};
+
+/* For Zebra BGP4MP_MESSAGE */
+typedef struct struct_BGPDUMP_ZEBRA_MESSAGE {
+    /* Zebra header */
+    as_t		source_as;
+    as_t		destination_as;
+    u_int16_t		interface_index;
+    u_int16_t		address_family;
+    BGPDUMP_IP_ADDRESS	source_ip;
+    BGPDUMP_IP_ADDRESS	destination_ip;
+
+    /* BGP packet header fields */
+    u_int16_t		size;
+    u_char		type;
+
+    /* For OPEN packets */
+    u_char	version;
+    as_t	my_as;
+    u_int16_t	hold_time;
+    struct	in_addr bgp_id;
+    u_char	opt_len;
+    u_char	*opt_data;
+
+    /* For UPDATE packets */
+    u_int16_t		withdraw_count;
+    u_int16_t		announce_count;
+    struct prefix	withdraw[MAX_PREFIXES];
+    struct prefix	announce[MAX_PREFIXES];
+
+    /* For corrupt update dumps */
+    u_int16_t cut_bytes;
+    struct zebra_incomplete incomplete;
+
+    /* For NOTIFY packets */
+    u_char error_code;
+    u_char sub_error_code;
+    u_int16_t notify_len;
+    u_char *notify_data;
+
+} BGPDUMP_ZEBRA_MESSAGE;
+
+/* For Zebra BGP4MP_ENTRY */
+typedef struct struct_BGPDUMP_ZEBRA_ENTRY {
+    u_int16_t	view;
+    u_int16_t	status;
+    time_t	time_last_change;
+    u_int16_t	address_family;
+    u_char	SAFI;
+    u_char	next_hop_len;
+    u_char	prefix_length;
+    u_char	*address_prefix;
+    u_int16_t	empty;
+    u_char	*bgp_atribute;
+} BGPDUMP_ZEBRA_ENTRY;
+
+/* For Zebra BGP4MP_SNAPSHOT */
+typedef struct struct_BGPDUMP_ZEBRA_SNAPSHOT {
+    u_int16_t	view;
+    u_int16_t	file;
+} BGPDUMP_ZEBRA_SNAPSHOT;
+
+typedef struct struct_BGPDUMP_MRTD_MESSAGE {
+    u_int16_t		source_as;
+    struct in_addr	source_ip;
+    u_int16_t		destination_as;
+    struct in_addr	destination_ip;
+
+    u_int16_t		withdraw_count;
+    u_int16_t		announce_count;
+    struct prefix	withdraw[MAX_PREFIXES];
+    struct prefix	announce[MAX_PREFIXES];
+
+    /* For corrupt update dumps */
+    struct zebra_incomplete incomplete;
+} BGPDUMP_MRTD_MESSAGE;
+
+typedef struct struct_BGPDUMP_MRTD_STATE_CHANGE {
+    u_int16_t           destination_as;
+    struct in_addr      destination_ip;
+    u_int16_t           old_state;
+    u_int16_t           new_state;
+} BGPDUMP_MRTD_STATE_CHANGE;
+
+typedef union union_BGPDUMP_BODY {
+	BGPDUMP_MRTD_MESSAGE		mrtd_message;
+        BGPDUMP_MRTD_STATE_CHANGE       mrtd_state_change;
+	BGPDUMP_MRTD_TABLE_DUMP		mrtd_table_dump;
+	BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE		mrtd_table_dump_v2_peer_table;
+	BGPDUMP_TABLE_DUMP_V2_PREFIX		mrtd_table_dump_v2_prefix;
+	BGPDUMP_ZEBRA_STATE_CHANGE	zebra_state_change;
+	BGPDUMP_ZEBRA_MESSAGE		zebra_message;
+	BGPDUMP_ZEBRA_ENTRY		zebra_entry;
+	BGPDUMP_ZEBRA_SNAPSHOT		zebra_snapshot;
+} BGPDUMP_BODY;
+
+/* The MRT header. Common to all records. */
+typedef struct struct_BGPDUMP_ENTRY {
+    time_t time;
+    long ms;
+    u_int16_t type;
+    u_int16_t subtype;
+    u_int32_t length;
+    attributes_t *attr;
+    BGPDUMP_BODY body;
+} BGPDUMP_ENTRY;
+
+#endif

File diff suppressed because it is too large
+ 1484 - 0
bgpdump_lib.c


+ 64 - 0
bgpdump_lib.h

@@ -0,0 +1,64 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ 
+Parts of this code have been engineered after analiyzing GNU Zebra's
+source code and therefore might contain declarations/code from GNU
+Zebra, Copyright (C) 1999 Kunihiro Ishiguro. Zebra is a free routing
+software, distributed under the GNU General Public License. A copy of
+this license is included with libbgpdump.
+
+Original Author: Dan Ardelean (dan@ripe.net)
+*/
+
+#ifndef _BGPDUMP_LIB_H
+#define _BGPDUMP_LIB_H
+
+#include <stdio.h>
+
+#define BGPDUMP_HAVE_IPV6
+
+#include "bgpdump_attr.h"
+#include "bgpdump_formats.h"
+
+#define BGPDUMP_MAX_FILE_LEN	1024
+#define BGPDUMP_MAX_AS_PATH_LEN	2000
+
+// if you include cfile_tools.h, include it first
+#ifndef _CFILE_TOOLS_DEFINES
+typedef struct _CFRFILE CFRFILE;
+#endif
+
+typedef struct struct_BGPDUMP {
+    CFRFILE	*f;
+    int		f_type;
+    int		eof;
+    char	filename[BGPDUMP_MAX_FILE_LEN];
+    int		parsed;
+    int		parsed_ok;
+} BGPDUMP;
+
+/* prototypes */
+
+BGPDUMP *bgpdump_open_dump(const char *filename);
+void	bgpdump_close_dump(BGPDUMP *dump);
+BGPDUMP_ENTRY*	bgpdump_read_next(BGPDUMP *dump);
+void	bgpdump_free_mem(BGPDUMP_ENTRY *entry);
+
+char *bgpdump_version(void);
+
+#endif

+ 103 - 0
bgpdump_mstream.c

@@ -0,0 +1,103 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ 
+Parts of this code have been engineered after analiyzing GNU Zebra's
+source code and therefore might contain declarations/code from GNU
+Zebra, Copyright (C) 1999 Kunihiro Ishiguro. Zebra is a free routing
+software, distributed under the GNU General Public License. A copy of
+this license is included with libbgpdump.
+
+Original Author: Dan Ardelean (dan@ripe.net)
+*/
+
+#include "bgpdump-config.h"
+#include "bgpdump_mstream.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+void mstream_init(struct mstream *s, u_char *buffer, u_int32_t len) {
+    s->start=buffer;
+    s->position=0;
+    s->len=len;
+}
+
+u_char mstream_getc(struct mstream *s, u_char *d) {
+    u_char data;
+
+    mstream_get(s, &data, sizeof(data));
+    if(d!=NULL) memcpy(d,&data,sizeof(data));
+    return data;
+}
+
+u_int16_t mstream_getw(struct mstream *s, u_int16_t *d) {
+    u_int16_t data;
+
+    mstream_get(s, &data, sizeof(data));
+    data=ntohs(data);
+    if(d!=NULL) memcpy(d,&data,sizeof(data));
+    return data;
+}
+
+u_int32_t mstream_getl(struct mstream *s, u_int32_t *d) {
+    u_int32_t data;
+
+    mstream_get(s, &data, sizeof(data));
+    data=ntohl(data);
+    if(d!=NULL) memcpy(d,&data,sizeof(data));
+    return data;
+}
+
+struct in_addr mstream_get_ipv4(struct mstream *s) {
+    struct in_addr addr;
+
+    mstream_get(s, &addr.s_addr, 4);
+    return addr;
+}
+
+u_int32_t mstream_can_read(struct mstream *s) {
+    return s->len - s->position;
+}
+
+// construct a partial mstream
+mstream_t mstream_copy(mstream_t *s, int len) {
+    mstream_t copy = {0};
+    copy.start = s->start + s->position;
+    copy.len = mstream_get(s, NULL, len);
+    return copy;
+}
+
+u_int32_t mstream_get (struct mstream *s, void *d, u_int32_t len) {
+    int room = mstream_can_read(s);
+
+    if(room >= len) {
+	if(d) memcpy(d, s->start + s->position, len);
+	s->position += len;
+	return len;
+    } else {
+	/* Reading past end of buffer!
+	   Zero out extra bytes and set position to end of buffer */
+	if(d) {
+	    memcpy(d, s->start + s->position, room);
+	    memset((char *)d + room, 0, len - room);
+	}
+	s->position = s->len;
+	return room;
+    }
+}

+ 49 - 0
bgpdump_mstream.h

@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ 
+Parts of this code have been engineered after analiyzing GNU Zebra's
+source code and therefore might contain declarations/code from GNU
+Zebra, Copyright (C) 1999 Kunihiro Ishiguro. Zebra is a free routing
+software, distributed under the GNU General Public License. A copy of
+this license is included with libbgpdump.
+
+Original Author: Dan Ardelean (dan@ripe.net)
+*/
+
+#ifndef _BGPDUMP_MSTREAM_H
+#define _BGPDUMP_MSTREAM_H
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef struct mstream {
+    u_char	*start;
+    u_int16_t	position;
+    u_int32_t	len;
+} mstream_t;
+
+void      mstream_init(struct mstream *s, u_char *buffer,u_int32_t len);
+u_char    mstream_getc(struct mstream *s, u_char *d);
+u_int16_t mstream_getw(struct mstream *s, u_int16_t *d);
+u_int32_t mstream_getl(struct mstream *s, u_int32_t *d);
+struct in_addr mstream_get_ipv4(struct mstream *s);
+u_int32_t mstream_can_read(struct mstream *s);
+u_int32_t mstream_get (struct mstream *s, void *d, u_int32_t len);
+mstream_t mstream_copy(mstream_t *s, int len);
+
+#endif

+ 5 - 0
bootstrap.sh

@@ -0,0 +1,5 @@
+#!/bin/sh
+
+autoheader
+autoconf
+./configure

+ 551 - 0
cfile_tools.c

@@ -0,0 +1,551 @@
+/** 
+  cfile_tools.c
+ 
+  A library to deal transparently with possibly compressed files.  
+  Documentation in the function headers and in cfile_tools.h
+
+  Copyright (C) 2004 by Arno Wagner <arno.wagner@acm.org> 
+  Distributed under the Gnu Public License version 2 or the modified
+  BSD license (see file COPYING)
+
+  Support for gzip added by Bernhard Tellenbach <bernhard.tellenbach@gmail.com>   
+*/
+
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+//#ifndef DONT_HAVE_BZ2
+//#include <bzlib.h>
+//#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "cfile_tools.h"
+
+// Concrete formats. remember to adjust CFR_NUM_FORMATS if changed!
+// Note: 0, 1 are special entries.
+
+const char * cfr_formats[CFR_NUM_FORMATS] = {
+  "not open",     //  0
+  "uncompressed", //  1
+#ifndef DONT_HAVE_BZ2
+  "bzip2",         //  2
+#endif
+#ifndef DONT_HAVE_GZ
+  "gzip",         //  3
+#endif
+};
+
+const char * cfr_extensions[CFR_NUM_FORMATS] = {
+  "",             //  0
+  "",             //  1
+#ifndef DONT_HAVE_BZ2
+  ".bz2",          //  2
+#endif
+#ifndef DONT_HAVE_GZ
+  ".gz"          //  3
+#endif
+};
+
+
+// Prototypes of non API functions (don't use these from outside this file)
+const char * _cfr_compressor_strerror(int format, int err);
+const char * _bz2_strerror(int err);
+
+
+// API Functions 
+
+CFRFILE *cfr_open(const char *path) {
+  /*******************************/
+  // Analog to 'fopen'. Error in result has to be tested using
+  // 'cfr_error' on the result!
+  // Note: The user needs to free the reurn value!
+  // Opens a possibly compressed file for reading.
+  // File type is determined by file name ending
+
+  int format, ext_len, name_len;
+  CFRFILE * retval = NULL;
+
+  // determine file format
+  name_len = strlen(path);
+  format = 2;  // skip specials 0, 1 
+
+  // Do action dependent on file format
+  retval = (CFRFILE *) calloc(1,sizeof(CFRFILE));
+  retval->eof = 0;
+  retval->error1 = 0;
+  retval->error2 = 0;
+
+
+#ifndef DONT_HAVE_GZ
+  if((path == NULL) || (strcmp(path, "-") == 0)) {
+	/* dump from stdin */
+	gzFile *f;
+	while (format < CFR_NUM_FORMATS) {
+		if (strcmp(cfr_extensions[format], ".gz") == 0)
+        		break;
+    		format ++;
+  	}
+	f = gzdopen(0, "r");
+	if(f == NULL) {
+		free(retval);
+		return (NULL);
+    	}
+        retval->data2 = f;
+	retval->format = format;
+	return (retval);
+  }
+#endif
+  while (format < CFR_NUM_FORMATS) {
+    ext_len = strlen(cfr_extensions[format]);
+    if (strncmp(cfr_extensions[format],
+                path+(name_len-ext_len),
+                ext_len) == 0
+        ) break;
+    format ++;
+  }
+  if (format >= CFR_NUM_FORMATS) 
+	format = 1;  // uncompressed 
+  retval->format = format;
+
+  switch (format) {
+  case 1:  // uncompressed
+    { 
+      FILE * in;
+      in = fopen(path,"r");
+      if (in == NULL) { 
+	free(retval);
+        return(NULL);
+      }
+      retval->data1 = in;
+      return(retval);
+    }
+    break;
+#ifndef DONT_HAVE_BZ2
+  case 2:  // bzip2
+    { 
+      int bzerror;
+      BZFILE * bzin;
+      FILE * in;
+      
+      retval->bz2_stream_end = 0;
+      
+      // get file
+      in = fopen(path,"r");
+      if (in == NULL) { 
+        free(retval);
+        return(NULL);
+      }
+      retval->data1 = in;
+      
+      // bzip2ify file
+      bzin = BZ2_bzReadOpen( &bzerror, in, 0, 0, NULL, 0); 
+      if (bzerror != BZ_OK) {
+        errno = bzerror;
+        BZ2_bzReadClose( &bzerror, bzin);
+        fclose(in);
+	free(retval);
+        return(NULL);
+      }
+      retval->data2 = bzin;
+      return(retval);
+    }
+    break;
+#endif
+#ifndef DONT_HAVE_GZ
+  case 3:  // gzip
+    { 
+	gzFile *f;
+      	// get file 
+	f = gzopen(path, "r");
+	if(f == NULL) {
+		free(retval);
+		return (NULL);
+    	}
+        retval->data2 = f;
+	return (retval);
+   }
+   break;
+#endif
+  default:  // this is an internal error, no diag yet.
+    fprintf(stderr,"illegal format '%d' in cfr_open!\n", format);
+    exit(1);
+  }
+  return NULL;
+} 
+
+
+
+int cfr_close(CFRFILE *stream) {
+  /**************************/
+  // Analog to 'fclose'.
+  // FIXME - why is stream->* set, then freed?
+  if (stream == NULL || stream->closed) {
+      errno = EBADF;
+      return -1;
+  }
+    
+  int retval = -1;
+  
+  switch (stream->format) {
+  case 1:  // uncompressed
+      retval = fclose((FILE *)(stream->data1));
+      stream->error1 = retval;
+      break;
+  case 2: // bzip2
+      #ifndef DONT_HAVE_BZ2
+      BZ2_bzReadClose( &stream->error2, (BZFILE *)stream->data2);
+      stream->error1 = retval = fclose((FILE *)(stream->data1));
+      break;
+      #endif
+  case 3:  // gzip
+      #ifndef DONT_HAVE_GZ
+      if(stream->data2!=NULL)
+          retval = gzclose(stream->data2);
+      stream->error2 = retval;
+      break;
+      #endif
+    default:  // internal error
+          assert("illegal stream->format" && 0);
+  }
+  free(stream);
+  return(retval);
+}
+
+size_t cfr_read_n(CFRFILE *stream, void *ptr, size_t bytes) {
+  /******************************************************************/
+  // Wrapper, will return either 'bytes' (the number of bytes to read) or 0 
+  return(cfr_read(ptr, bytes, 1, stream)*bytes);
+}
+
+size_t cfr_read(void *ptr, size_t size, size_t nmemb, CFRFILE *stream) {
+  /******************************************************************/
+  // Analog to 'fread'. Will not return with partial elements, only
+  // full ones. Hence calling this function with one large element
+  // size will result in a complete or no read.
+  
+  size_t retval = 0;
+  if (stream == NULL) return(0);
+
+  // shortcut
+  if (stream->eof) return(0);
+
+  switch (stream->format) {
+  case 1:  // uncompressed
+    { 
+      FILE * in;
+      in = (FILE *)(stream->data1);
+      retval = fread(ptr, size, nmemb, in);
+      if (retval != nmemb) {
+        // fprintf(stderr,"short read!!!\n");
+        stream->eof = feof(in);
+        stream->error1 = ferror(in);
+	retval = 0;
+      }
+      return (retval);
+    }
+    break;
+#ifndef DONT_HAVE_BZ2    
+   case 2:  // bzip2
+    { 
+      BZFILE * bzin; 
+      int bzerror;
+      int buffsize;
+
+      if (stream->bz2_stream_end == 1) {
+        // feof-behaviour: Last read did consume last byte but not more
+        stream->eof = 1;
+        return(0);
+      }
+
+      bzerror = BZ_OK;
+      bzin = (BZFILE *) (stream->data2);
+      buffsize = size * nmemb;
+
+      retval = BZ2_bzRead(&bzerror, bzin, ptr, buffsize);
+
+      if (bzerror == BZ_STREAM_END ) {
+        stream->bz2_stream_end = 1;
+        stream->error2 = bzerror;
+        if (retval == buffsize) {
+          // feof-behaviour: no eof yet
+        } else {
+          // feof-behaviour: read past end, set eof
+          stream->eof = 1;
+	  retval = 0;
+        }
+        return(retval/size);
+      }
+      if (bzerror == BZ_OK) {
+        // Normal case, no error.
+        // A short read here is an error, so catch it
+        if (retval == buffsize) {
+          return(retval/size);
+        }
+      }
+
+      // Other error...
+      stream->error2 = bzerror;
+      BZ2_bzReadClose( &bzerror, bzin );
+      if (bzerror != BZ_OK) {
+        stream->error2 = bzerror;
+      }
+      retval = fclose((FILE *)(stream->data1));
+      stream->error1 = retval;
+      stream->closed = 1;
+      return(0);
+    }
+    break;
+#endif    
+#ifndef DONT_HAVE_GZ
+  case 3:  // gzip
+    { 
+      gzFile * in;
+      in = (gzFile *)(stream->data2);
+      retval = gzread(in, ptr, size*nmemb);
+      if (retval != nmemb*size) {
+        // fprintf(stderr,"short read!!!\n");
+        stream->eof = gzeof(in);
+        stream->error2 = errno;
+	retval = 0;
+      }
+      return (retval/size);
+    }
+    break;
+#endif
+  default:  // this is an internal error, no diag yet.
+    fprintf(stderr,"illegal format '%d' in cfr_read!\n",stream->format);
+    exit(1);
+  }
+} 
+
+
+
+
+
+ssize_t cfr_getline(char **lineptr, size_t *n, CFRFILE *stream) {
+  /************************************************************/
+  // May not be very efficient, since it uses single-char reads
+  // for formats where there is no native getline in the library.
+  // For bzip2 the speedup for additional buffering was only 5%
+  // so I dropped it.
+  // Returns -1 in case of an error.
+  
+  if (stream == NULL) return(-1);  
+
+  switch (stream->format) {
+  case 1:  // uncompressed
+    { 
+      if (fgets(*lineptr, *n, (FILE *)(stream->data1)) == NULL) {
+        stream->error1 = errno;
+	return -1;
+      }
+      return 0;
+    }
+    break;
+
+#ifndef DONT_HAVE_BZ2
+  case 2:  // bzip2  
+    {                
+      size_t count;
+      char c;
+      size_t ret;
+
+	  //bzin = (BZFILE *) (stream->data2);
+
+      // allocate initial buffer if none was passed or size was zero
+      if (*lineptr == NULL) {
+        *lineptr = (char *) calloc(120, 1);
+        *n = 120;
+      }
+      if (*n == 0) {
+        *n = 120;
+        *lineptr = (char *) realloc(*lineptr, *n); // to avoid memory-leaks
+      }
+
+      count = 0;
+      // read until '\n'
+      do {
+        ret = cfr_read(&c, 1, 1, stream);
+        if (ret != 1) {
+          return(-1);
+        }
+        count ++;
+        if (count >= *n) {
+          *n = 2 * *n;
+          *lineptr = (char *) realloc(*lineptr, *n);
+          if (*lineptr == NULL) {
+            stream->error1 = errno;
+            return(-1);
+          }
+        }
+        (*lineptr)[count-1] = c;
+      } while (c != '\n');
+      (*lineptr)[count] = 0;
+      return(count);
+    }
+    break;
+#endif
+#ifndef DONT_HAVE_GZ
+  case 3:  // gzip
+    { 
+      char * return_ptr = gzgets((gzFile *)(stream->data2), *lineptr, *n );
+      if (return_ptr == Z_NULL) {
+        stream->error2 = errno;
+        return(-1);
+      }
+      return *n;
+  
+    }
+    break;
+#endif
+  default:  // this is an internal error, no diag yet.
+    fprintf(stderr,"illegal format '%d' in cfr_getline!\n",stream->format);
+    exit(1);
+    return(-1);
+  }     
+}
+
+
+
+int cfr_eof(CFRFILE *stream) {
+  // Returns true on end of file/end of compressed data.
+  // The end of the compressed data is regarded as end of file
+  // in this library, embedded or multiple compressed data per 
+  // file is not supported by this library.
+  //
+  // Note: The sematics is that cfr_eof is true only after
+  // the first byte after the end of file was read. Some compressors
+  // report EOF already when the last availale character has been 
+  // read (far more sensible IMO), but for consistency we follow the
+  // convention of the standard c library here.
+
+  return(stream->eof);
+}
+
+
+
+int cfr_error(CFRFILE *stream) {
+  // Returns true on error.
+  // Errors can be ordinary errors from fopen.fclose/fread
+  // or can originate from the underlying compression.
+  // This function just returns 0 when there is no error or
+  // 1 in case of error.
+  // To get a more detailed report cfr_strerror will try to
+  // come up with a description of the whole situation.
+  // For numeric details, more query functions would need to be
+  // implemented.
+  
+  if (stream == NULL) return(1);
+  return(stream->error1 || stream->error2);
+}
+
+
+char * cfr_strerror(CFRFILE *stream) {
+  // Result is "stream-i/o: <stream-error> <compressor>[: <compressor error>]"
+  // Do not modify result. 
+  // Result may change on subsequent call to this function.
+
+  static char res[120];
+  char * msg, * msg2;
+
+  if (stream == NULL) {
+    asprintf(&msg,"Error: stream is NULL, i.e. not opened");
+    return(msg);
+  }
+
+  asprintf(&msg,
+           "stream-i/o: %s, %s  [%s]",
+           stream->eof?"EOF":"",
+           strerror(stream->error1),
+           cfr_compressor_str(stream));
+  if (stream->format == 2) {
+    asprintf(&msg2, 
+             "%s: %s",
+             msg, 
+             _cfr_compressor_strerror(stream->format, stream->error2));
+    free(msg);
+    msg = msg2;
+  } 
+  if (stream->format == 3) {
+    asprintf(&msg2, 
+             "%s: %s",
+             msg, 
+             gzerror((gzFile*)(stream->data2), &(stream->error2)));
+    free(msg);
+    msg = msg2;
+  }
+  snprintf(res, 120, "%s", msg);
+  res[119] = 0;
+  free(msg); 
+  return(res);
+}
+
+const char * cfr_compressor_str(CFRFILE *stream) {
+  // Returns the name of the compressor used
+
+  if ((stream->format < 0) || (stream->format >= CFR_NUM_FORMATS)) {
+    return("undefined compression type");
+  } else {
+    return (cfr_formats[stream->format]);
+  }
+}
+
+
+// Utility functions for compressor errors. 
+// * Not part of the API, do not call directly as they may change! *
+
+const char * _cfr_compressor_strerror(int format, int err) {
+  // Transforms error code to string for all compressors
+  
+  switch (format) {
+  case 0: 
+    return("file not open");
+    break;
+
+  case 1:
+    return("file not compressed");
+    break;
+    
+#ifndef DONT_HAVE_BZ2
+  case 2:
+    return(_bz2_strerror(err));
+    break;
+#endif          
+#ifndef DONT_HAVE_GZ
+  case 3:
+    return NULL;
+    break;
+#endif          
+  default:
+    return("unknowen compressor code");
+  }  
+}
+    
+#ifndef DONT_HAVE_BZ2
+const char * _bz2_strerror(int err) {
+  // Since bzlib does not have strerror, we do it here manually.
+  // This works for version 1.0 of 21 March 2000 of bzlib.h
+  
+  switch (err) {
+  case BZ_OK: return("BZ_OK");
+  case BZ_RUN_OK: return("BZ_RUN_OK");
+  case BZ_FLUSH_OK: return("BZ_FLUSH_OK");
+  case BZ_FINISH_OK: return("BZ_FINISH_OK");
+  case BZ_STREAM_END: return("BZ_STREAM_END");
+  case BZ_SEQUENCE_ERROR: return("BZ_SEQUENCE_ERROR");
+  case BZ_PARAM_ERROR: return("BZ_PARAM_ERROR");
+  case BZ_MEM_ERROR: return("BZ_MEM_ERROR");
+  case BZ_DATA_ERROR: return("BZ_DATA_ERROR");
+  case BZ_DATA_ERROR_MAGIC: return("BZ_DATA_ERROR_MAGIC");
+  case BZ_IO_ERROR: return("BZ_IO_ERROR");
+  case BZ_UNEXPECTED_EOF: return("BZ_UNEXPECTED_EOF");
+  case BZ_OUTBUFF_FULL: return("BZ_OUTBUFF_FULL");
+  case BZ_CONFIG_ERROR: return("BZ_CONFIG_ERROR");
+  default: return("unknowen bzip2 error code");
+  }
+}
+#endif
+    

+ 91 - 0
cfile_tools.h

@@ -0,0 +1,91 @@
+/** 
+  cfile_tools.h
+  A small library containing tools for dealing with files
+  that are compressed with different compressors or not compressed
+  at all. The idea is to recognize the compression automagically
+  and transparently. Files can be opened for reading or writing,
+  but not both. Reading and writing is by different function classes.
+  Access is sequential only.
+
+  Copyright (C) 2004 by Arno Wagner <arno.wagner@acm.org> 
+  Distributed under the Gnu Public License version 2 or the modified
+  BSD license (see file COPYING)
+
+  Support for gzip added by Bernhard Tellenbach <bernhard.tellenbach@gmail.com>
+
+  Function prefixes are: 
+     cfr_ = compressed file read   
+
+  Supported:
+  Reading: 
+  - type recognition from file name extension 
+  - standard input (filename: '-' )
+  - no compression
+  - bzip2  
+  - gzip
+*/
+
+#ifndef _CFILE_TOOLS_DEFINES
+#define _CFILE_TOOLS_DEFINES
+
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef DONT_HAVE_BZ2
+#include <bzlib.h>
+#endif
+
+#ifndef DONT_HAVE_GZ
+#include <zlib.h>
+#endif
+
+// Types
+
+struct _CFRFILE {
+  int format;       // 0 = not open, 1 = uncompressed, 2 = bzip2, 3 = gzip
+  int eof;          // 0 = not eof 
+  int closed;       // indicates whether fclose has been called, 0 = not yet
+  int error1;       // errors from the sytem, 0 = no error
+  int error2;       // for error messages from the compressor
+  FILE * data1;     // for filehandle of the system 
+  void * data2;     // addtional handle(s) of the compressor
+  // compressor specific stuff 
+  int bz2_stream_end; // True when a bz2 stream has ended. Needed since
+                      // further reading returns error and not eof.
+};
+
+typedef struct _CFRFILE CFRFILE;
+
+// Formats
+
+#ifndef DONT_HAVE_BZ2
+  #ifndef DONT_HAVE_GZ
+	#define CFR_NUM_FORMATS 4
+  #else
+	#define CFR_NUM_FORMATS 3
+  #endif
+#else
+	#define CFR_NUM_FORMATS 2
+#endif
+
+// Functions
+
+CFRFILE    * cfr_open(const char *path); 
+int          cfr_close(CFRFILE *stream);
+size_t       cfr_read(void *ptr, size_t size, size_t nmemb, CFRFILE *stream);
+size_t       cfr_read_n(CFRFILE *stream, void *ptr, size_t bytes);
+ssize_t      cfr_getline(char **lineptr, size_t *n, CFRFILE *stream);
+int          cfr_eof(CFRFILE *stream);
+int          cfr_error(CFRFILE *stream);
+char       * cfr_strerror(CFRFILE *stream);
+const char * cfr_compressor_str(CFRFILE *stream);
+
+#ifndef DONT_HAVE_BZ2
+const char * _bz2_strerror(int err);
+#endif
+
+
+#endif

+ 41 - 0
configure.in

@@ -0,0 +1,41 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_REVISION($Revision$)
+
+AC_INIT([libbgpdump], 1.4.99.15, [ris@ripe.net])
+AC_CONFIG_SRCDIR([bgpdump_lib.c])
+AC_CONFIG_HEADERS([bgpdump-config.h])
+
+CFLAGS="-g -O3 $CFLAGS -Wall"
+CFLAGS="$CFLAGS -Wsystem-headers -Wno-format-y2k -Wno-sign-compare -Wcast-align"
+CFLAGS="$CFLAGS -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wswitch -Wshadow"
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_RANLIB
+
+# Checks for header files.
+AC_CHECK_HEADERS([arpa/inet.h netinet/in.h syslog.h])
+AC_STRUCT_TM
+
+# Check for u_*_t
+AC_CHECK_TYPE(u_char_t, , AC_DEFINE(u_char_t, uchar_t, [Define if system headers do not define u_char_t]))
+AC_CHECK_TYPE(u_int8_t, , AC_DEFINE(u_int8_t, uint8_t, [Define if system headers do not define u_int8_t]))
+AC_CHECK_TYPE(u_int16_t, , AC_DEFINE(u_int16_t, uint16_t, [Define if system headers do not define u_int16_t]))
+AC_CHECK_TYPE(u_int32_t, , AC_DEFINE(u_int32_t, uint32_t, [Define if system headers do not define u_int32_t]))
+
+AC_CHECK_LIB(z, gzopen, [], AC_DEFINE(DONT_HAVE_GZ, 1, Define if libz not present))
+AC_CHECK_LIB(bz2, BZ2_bzReadOpen, [], AC_DEFINE(DONT_HAVE_BZ2, 1, Define if libbzip2 not present))
+
+# Check for inet_ntoa in -lnsl if not found (Solaris)
+AC_CHECK_FUNCS(inet_ntoa, [], AC_CHECK_LIB(nsl, inet_ntoa, [], AC_MSG_ERROR([inet_ntoa not found],1)))
+AC_CHECK_FUNCS(inet_ntop, [], AC_CHECK_LIB(nsl, inet_ntop, [], AC_MSG_ERROR([inet_ntop not found],1)))
+
+case `uname` in
+	Darwin*) LDFLAGS="$LDFLAGS -dynamiclib" ;;
+	*)       LDFLAGS="$LDFLAGS -shared" ;;
+esac
+
+AC_SUBST(CFLAGS)
+AC_SUBST(LIBS)
+
+AC_OUTPUT([bgpdump.spec Makefile])

+ 433 - 0
example.c

@@ -0,0 +1,433 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ 
+Parts of this code have been engineered after analiyzing GNU Zebra's
+source code and therefore might contain declarations/code from GNU
+Zebra, Copyright (C) 1999 Kunihiro Ishiguro. Zebra is a free routing
+software, distributed under the GNU General Public License. A copy of
+this license is included with libbgpdump.
+
+Author: Dan Ardelean (dan@ripe.net)
+*/
+
+#include "bgpdump_lib.h"
+#include <time.h>
+
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+    void process(BGPDUMP_ENTRY *entry);
+    void show_attr(attributes_t *attr);
+    void show_prefixes(int count,struct prefix *prefix);
+#ifdef BGPDUMP_HAVE_IPV6
+    void show_v6_prefixes(int count, struct prefix *prefix);
+#endif
+
+int main(int argc, char **argv) {  
+    BGPDUMP *my_dump;
+    BGPDUMP_ENTRY *my_entry=NULL;
+
+    if(argc>1) {
+	my_dump=bgpdump_open_dump(argv[1]);
+    } else {
+	my_dump=bgpdump_open_dump("dumps/updates.20020701.0032");
+    }
+
+    if(my_dump==NULL) {
+	printf("Error opening dump file ...\n");
+	exit(1);
+    }
+
+    do {
+//fprintf(stdout, "Offset: %d\n", gztell(my_dump->f));
+	my_entry=bgpdump_read_next(my_dump);
+	if(my_entry!=NULL) {
+	    process(my_entry);
+	    bgpdump_free_mem(my_entry);
+	}
+    } while(my_dump->eof==0);
+
+    bgpdump_close_dump(my_dump);
+//fprintf(stderr, "%s: OK=%d, BAD=%d (%f%% OK)\n", my_dump->filename, my_dump->parsed_ok, my_dump->parsed - my_dump->parsed_ok, (float) my_dump->parsed_ok / my_dump->parsed * 100);
+    
+ return 0;
+}
+
+char *bgp_state_name[] = {
+    "Unknown",
+    "IDLE",
+    "CONNECT",
+    "ACTIVE",
+    "OPEN_SENT",
+    "OPEN_CONFIRM",
+    "ESTABLISHED",
+    NULL
+};
+
+char *bgp_message_types[] = {
+    "Unknown",
+    "Open",
+    "Update/Withdraw",
+    "Notification",
+    "Keepalive"
+};
+
+char *notify_codes[] = {
+    "Unknown",
+    "Message Header Error",
+    "OPEN Message Error",
+    "UPDATE Message Error",
+    "Hold Timer Expired",
+    "Finite State Machine Error",
+    "Cease"
+};
+
+char *notify_subcodes[][12] = {
+    { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+    /* Message Header Error */
+    {
+	"None",
+ 	"Connection Not Synchronized",
+	"Bad Message Length",
+	"Bad Message Type",
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 
+    },
+    /* OPEN Message Error */
+    {
+	"None",
+	"Unsupported Version Number",
+	"Bad Peer AS",
+	"Bad BGP Identifier",
+	"Unsupported Optional Parameter",
+	"Authentication Failure",
+	"Unacceptable Hold Time",
+	NULL, NULL, NULL, NULL, NULL
+    },
+    /* UPDATE Message Error */
+    {
+	"None",
+	"Malformed Attribute List",
+	"Unrecognized Well-known Attribute",
+	"Missing Well-known Attribute",
+	"Attribute Flags Error",
+	"Attribute Length Error",
+	"Invalid ORIGIN Attribute",
+	"AS Routing Loop",
+	"Invalid NEXT_HOP Attribute",
+	"Optional Attribute Error",
+	"Invalid Network Field",
+	"Malformed AS_PATH"
+    },
+    /* Hold Timer Expired */
+    { "None", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+    /* Finite State Machine Error */
+    { "None", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+    /* Cease */
+    { "None", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+
+};
+
+void process(BGPDUMP_ENTRY *entry) {
+    char prefix[BGPDUMP_ADDRSTRLEN], peer_ip[BGPDUMP_ADDRSTRLEN];
+    char source_ip[BGPDUMP_ADDRSTRLEN], destination_ip[BGPDUMP_ADDRSTRLEN];
+    struct mp_nlri *mp_announce, *mp_withdraw;
+    int i, code, subcode;
+	BGPDUMP_TABLE_DUMP_V2_PREFIX *e;
+
+if(entry->type == BGPDUMP_TYPE_ZEBRA_BGP && entry->subtype == BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE && entry->body.zebra_message.type == BGP_MSG_KEEPALIVE) return;
+if(entry->type == BGPDUMP_TYPE_ZEBRA_BGP && entry->subtype == BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE && entry->body.zebra_message.type == BGP_MSG_OPEN) return;
+if(entry->type == BGPDUMP_TYPE_ZEBRA_BGP && entry->subtype == BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE && entry->body.zebra_message.type == BGP_MSG_NOTIFY) return;
+if(entry->type == BGPDUMP_TYPE_ZEBRA_BGP && entry->subtype == BGPDUMP_SUBTYPE_ZEBRA_BGP_STATE_CHANGE && entry->length == 8) return;
+
+    printf("TIME            : %s",asctime(gmtime(&entry->time)));
+    printf("LENGTH          : %u\n", entry->length);
+    switch(entry->type) {
+	case BGPDUMP_TYPE_MRTD_TABLE_DUMP:
+	    if(entry->subtype == AFI_IP) {
+		strcpy(prefix, inet_ntoa(entry->body.mrtd_table_dump.prefix.v4_addr));
+		strcpy(peer_ip, inet_ntoa(entry->body.mrtd_table_dump.peer_ip.v4_addr));
+#ifdef BGPDUMP_HAVE_IPV6
+	    } else if(entry->subtype == AFI_IP6) {
+		inet_ntop(AF_INET6, &entry->body.mrtd_table_dump.prefix.v6_addr, prefix,
+			  sizeof(prefix));
+		inet_ntop(AF_INET6, &entry->body.mrtd_table_dump.peer_ip.v6_addr, peer_ip,
+			  sizeof(peer_ip));
+#endif
+	    } else {
+		*prefix = '\0';
+		*peer_ip = '\0';
+	    }
+	    printf("TYPE            : BGP Table Dump Entry\n");
+	    printf("    VIEW        : %d\n",entry->body.mrtd_table_dump.view);
+	    printf("    SEQUENCE    : %d\n",entry->body.mrtd_table_dump.sequence);
+	    printf("    PREFIX      : %s/%d\n",prefix,entry->body.mrtd_table_dump.mask);
+	    printf("    STATUS      : %d\n",entry->body.mrtd_table_dump.status);
+	    printf("    UPTIME      : %s",asctime(gmtime(&entry->body.mrtd_table_dump.uptime)));
+	    printf("    PEER IP     : %s\n",peer_ip);
+	    printf("    PEER AS     : %u\n",entry->body.mrtd_table_dump.peer_as);
+    	show_attr(entry->attr);
+	    break;
+
+	case BGPDUMP_TYPE_TABLE_DUMP_V2:
+
+		e = &entry->body.mrtd_table_dump_v2_prefix;
+
+	    if(e->afi == AFI_IP) {
+			strcpy(prefix, inet_ntoa(e->prefix.v4_addr));
+#ifdef BGPDUMP_HAVE_IPV6
+	    } else if(e->afi == AFI_IP6) {
+			inet_ntop(AF_INET6, &e->prefix.v6_addr, prefix, INET6_ADDRSTRLEN);
+#endif
+	    } else {
+			printf("Error: BGP table dump version 2 entry with unknown subtype\n");
+			break;
+	    }
+
+		for(i = 0; i < e->entry_count; i++){
+			if(i){
+    			printf("\nTIME            : %s",asctime(gmtime(&entry->time)));
+    			printf("LENGTH          : %u\n", entry->length);
+			}
+
+
+    		printf("TYPE            : BGP Table Dump version 2 Entry\n");
+    		printf("    SEQUENCE    : %d\n",e->seq);
+    		printf("    PREFIX      : %s/%d\n",prefix,e->prefix_length);
+
+			if(e->entries[i].peer->afi == AFI_IP){
+				inet_ntop(AF_INET, &e->entries[i].peer->peer_ip, peer_ip, INET6_ADDRSTRLEN);
+#ifdef BGPDUMP_HAVE_IPV6
+			} else if (e->entries[i].peer->afi == AFI_IP6){
+				inet_ntop(AF_INET6, &e->entries[i].peer->peer_ip, peer_ip, INET6_ADDRSTRLEN);
+#endif
+			} else {
+				sprintf(peer_ip, "N/A, unsupported AF");
+			}
+    		printf("    PEER IP     : %s\n",peer_ip);
+    		printf("    PEER AS     : %u\n",e->entries[i].peer->peer_as);
+
+   			show_attr(e->entries[i].attr);
+		}
+
+	    break;
+
+	case BGPDUMP_TYPE_ZEBRA_BGP:
+	    printf("TYPE            : Zebra BGP \n");
+		if(entry->body.zebra_message.address_family == AFI_IP) {
+		    strcpy(source_ip, inet_ntoa(entry->body.zebra_message.source_ip.v4_addr));
+		    strcpy(destination_ip, inet_ntoa(entry->body.zebra_message.destination_ip.v4_addr));
+#ifdef BGPDUMP_HAVE_IPV6
+		} else if(entry->body.zebra_message.address_family == AFI_IP6) {
+		    inet_ntop(AF_INET6, &entry->body.zebra_message.source_ip.v6_addr, source_ip,
+			      sizeof(source_ip));
+		    inet_ntop(AF_INET6, &entry->body.zebra_message.destination_ip.v6_addr, destination_ip,
+			      sizeof(destination_ip));
+#endif
+		} else {
+		    *source_ip = '\0';
+		    *destination_ip = '\0';
+		}
+	    switch(entry->subtype) {
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE:
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4:
+		    printf("SUBTYPE         : Zebra BGP Message");
+		    if(entry->subtype == BGPDUMP_SUBTYPE_ZEBRA_BGP_MESSAGE_AS4) {
+		      printf(" (32-bit ASN)\n");
+		    } else {
+		      printf("\n");
+		    }
+		    printf("    SOURCE_AS   : %u\n",entry->body.zebra_message.source_as);
+		    printf("    DEST_AS     : %u\n",entry->body.zebra_message.destination_as);
+		    printf("    INTERFACE   : %d\n",entry->body.zebra_message.interface_index);
+		    printf("    SOURCE_IP   : %s\n",source_ip);
+		    printf("    DEST_IP     : %s\n",destination_ip);
+
+		    if(entry->body.zebra_message.type > sizeof(bgp_message_types) / sizeof(bgp_message_types[0]))
+			printf("MESSAGE TYPE    : Unknown\n");
+		    else
+			printf("MESSAGE TYPE    : %s\n", bgp_message_types[entry->body.zebra_message.type]);
+
+		    switch(entry->body.zebra_message.type) {
+			case BGP_MSG_UPDATE:
+			    printf("WITHDRAW        :\n");
+			    show_prefixes(entry->body.zebra_message.withdraw_count,entry->body.zebra_message.withdraw);
+#ifdef BGPDUMP_HAVE_IPV6
+			    if(entry->attr->mp_info &&
+			       (mp_withdraw = MP_IPV6_WITHDRAW(entry->attr->mp_info)) != NULL) {
+				show_v6_prefixes(mp_withdraw->prefix_count, mp_withdraw->nlri);
+			    }
+#endif
+			    printf("ANNOUNCE        :\n");
+			    show_prefixes(entry->body.zebra_message.announce_count,entry->body.zebra_message.announce);
+#ifdef BGPDUMP_HAVE_IPV6
+			    if(entry->attr->mp_info &&
+			       (mp_announce = MP_IPV6_ANNOUNCE(entry->attr->mp_info)) != NULL) {
+				show_v6_prefixes(mp_announce->prefix_count, mp_announce->nlri);
+			    }
+#endif
+			    break;
+			case BGP_MSG_KEEPALIVE:
+			    /* Nothing to do */
+			    break;
+			case BGP_MSG_OPEN:
+			    printf("    VERSION     : %d\n",entry->body.zebra_message.version);
+			    printf("    MY_ASN      : %u\n",entry->body.zebra_message.my_as);
+			    printf("    HOLD_TIME   : %d\n",entry->body.zebra_message.hold_time);
+			    printf("    ROUTER_ID   : %s\n",inet_ntoa(entry->body.zebra_message.bgp_id));
+			    printf("    OPTION_LEN  : %d\n",entry->body.zebra_message.opt_len);
+			    printf("    OPTION_DATA :");
+			    for(i = 0; i < entry->body.zebra_message.opt_len; i++) {
+				printf(" %02x", entry->body.zebra_message.opt_data[i]);
+			    }
+			    printf("\n");
+			    break;
+			case BGP_MSG_NOTIFY:
+			    code = entry->body.zebra_message.error_code;
+			    subcode = entry->body.zebra_message.sub_error_code;
+
+			    printf("    CODE        : %d", code);
+			    if(code >= sizeof(notify_codes) / sizeof(notify_codes[0]))
+				printf(" (Unknown)\n");
+			    else
+				printf(" (%s)\n", notify_codes[code]);
+
+			    printf("    SUBCODE     : %d", subcode);
+			    if(code >= sizeof(notify_codes) / sizeof(notify_codes[0]) ||
+			       subcode >= sizeof(notify_subcodes[0]) / sizeof(notify_subcodes[0][0]) ||
+			       notify_subcodes[code][subcode] == NULL)
+				printf(" (Unknown)\n");
+			    else
+				printf(" (%s)\n", notify_subcodes[code][subcode]);
+
+			    printf("    DATA        :");
+			    for(i = 0; i < entry->body.zebra_message.notify_len; i++) {
+				printf(" %02x", entry->body.zebra_message.notify_data[i]);
+			    }
+			    printf("\n");
+			    break;
+			default:
+			    break;
+		    }
+		    break;
+
+		case BGPDUMP_SUBTYPE_ZEBRA_BGP_STATE_CHANGE:
+		    printf("SUBTYPE         : Zebra BGP State Change\n");
+		    printf("    SOURCE_AS   : %u\n",entry->body.zebra_state_change.source_as);
+		    printf("    DEST_AS     : %u\n",entry->body.zebra_state_change.destination_as);
+		    printf("    INTERFACE   : %d\n",entry->body.zebra_state_change.interface_index);
+		    printf("    SOURCE_IP   : %s\n",source_ip);
+		    printf("    DEST_IP     : %s\n",destination_ip);
+		    printf("    OLD_STATE   : %s\n",bgp_state_name[entry->body.zebra_state_change.old_state]);
+		    printf("    NEW_STATE   : %s\n",bgp_state_name[entry->body.zebra_state_change.new_state]);
+    		show_attr(entry->attr);
+		    break;
+
+		default:
+		    printf("SUBTYPE         : Unknown %d\n", entry->subtype);
+	    }
+    	show_attr(entry->attr);
+	    break;
+	default:
+	    printf("TYPE            : Unknown %d\n", entry->type);
+    	show_attr(entry->attr);
+	    
+    }
+    printf("\n");
+}
+
+void show_attr(attributes_t *attr) {
+    int have_nexthop = 0;
+    printf("ATTRIBUTES      :\n");
+    
+    if(attr != NULL) {
+	    printf("   ATTR_LEN     : %d\n",attr->len);
+
+	    if( (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGIN) ) !=0 )		printf("   ORIGIN       : %d\n",attr->origin);
+	    else printf("   ORIGIN       : N/A\n");
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AS_PATH) ) !=0)		printf("   ASPATH       : %s\n",attr->aspath->str);
+	    else printf("   ASPATH       : N/A\n");
+
+	    printf("   NEXT_HOP     : ");
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP) ) !=0) {
+		have_nexthop = 1;
+		printf("%s", inet_ntoa(attr->nexthop));
+	    }
+
+#ifdef BGPDUMP_HAVE_IPV6
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) &&
+	         MP_IPV6_ANNOUNCE(attr->mp_info) != NULL) {
+		char addr[INET6_ADDRSTRLEN];
+		struct mp_nlri *mp_nlri = MP_IPV6_ANNOUNCE(attr->mp_info);
+		u_int8_t len = mp_nlri->nexthop_len;
+
+		if(have_nexthop)
+		    printf(" ");
+
+		have_nexthop = 1;
+		printf("%s", inet_ntop(AF_INET6, &mp_nlri->nexthop, addr, sizeof(addr)));
+		if(len == 32)
+		    printf(" %s", inet_ntop(AF_INET6, &mp_nlri->nexthop_local, addr, sizeof(addr)));
+	    }
+#endif
+
+	    printf(have_nexthop ? "\n" : "N/A\n");
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC) ) !=0)	printf("   MED          : %d\n",attr->med);
+	    else printf("   MED          : N/A\n");
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) ) !=0)		printf("   LOCAL_PREF   : %d\n",attr->local_pref);
+	    else printf("   LOCAL_PREF   : N/A\n");
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE) ) !=0)	printf("   ATOMIC_AGREG : Present\n");
+	    else printf("   ATOMIC_AGREG : N/A\n");
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR) ) !=0)		printf("   AGGREGATOR   : %s AS%u\n",inet_ntoa(attr->aggregator_addr),attr->aggregator_as);
+	    else printf("   AGGREGATOR   : N/A\n");
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES) ) !=0)	printf("   COMMUNITIES  : %s\n",attr->community->str);
+	    else printf("   COMMUNITIES  : N/A\n");
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEW_AS_PATH) ) !=0) {
+		printf("   NEW_ASPATH   : %s\n",attr->new_aspath->str);
+	    	printf("   OLD_ASPATH   : %s\n",attr->old_aspath->str);
+	    }
+
+	    if( (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEW_AGGREGATOR) ) !=0)	printf("   NEW_AGGREGTR : %s AS%u\n",inet_ntoa(attr->new_aggregator_addr),attr->new_aggregator_as);
+    }
+}
+
+void show_prefixes(int count,struct prefix *prefix) {
+    int i;
+    for(i=0;i<count;i++)
+	printf("      %s/%d\n",inet_ntoa(prefix[i].address.v4_addr),prefix[i].len);
+}
+
+#ifdef BGPDUMP_HAVE_IPV6
+void show_v6_prefixes(int count, struct prefix *prefix) {
+    int i;
+    char str[INET6_ADDRSTRLEN];
+
+    for(i=0;i<count;i++){
+	inet_ntop(AF_INET6, &prefix[i].address.v6_addr, str, sizeof(str));
+	printf("      %s/%d\n",str, prefix[i].len);
+    }
+}
+#endif

+ 259 - 0
inet_ntop.c

@@ -0,0 +1,259 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright 1994, 1995 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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.
+ */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "util.h"
+
+const char OCTETS[][4] = {        
+     "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9", "10", "11", "12", "13", "14", "15",
+    "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31",
+    "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47",
+    "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63",
+    "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
+    "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95",
+    "96", "97", "98", "99",
+    "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
+    "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122",
+    "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135",
+    "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148",
+    "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161",
+    "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174",
+    "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", 
+    "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200",
+    "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213",
+    "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226",
+    "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
+    "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252",
+    "253", "254", "255"
+};
+
+char *fmt_ipv4(BGPDUMP_IP_ADDRESS addr, char *buffer)
+{
+    assert(buffer);
+    uint8_t *ap = (uint8_t *)&addr.v4_addr.s_addr;
+    
+    int pos = 0;
+    int i;
+    for(i = 0; i < 4; ++i) {
+        const char *octet = OCTETS[ap[i]];
+        buffer[pos++] = octet[0];
+        octet[1] ? buffer[pos++] = octet[1] : (void)0;
+        octet[2] ? buffer[pos++] = octet[2] : (void)0;
+        buffer[pos++] = '.';
+    }
+    
+    buffer[pos - 1] = '\0';
+    
+    return buffer;
+}
+
+char *fmt_ipv6(BGPDUMP_IP_ADDRESS addr, char *buffer)
+{    
+    static const char hexchars[] = "0123456789abcdef";
+
+    assert(buffer);
+        
+    /*  check for mapped or compat addresses */
+    bool m = IN6_IS_ADDR_V4MAPPED(&addr.v6_addr);
+    bool c = IN6_IS_ADDR_V4COMPAT(&addr.v6_addr);
+    if (m || c) {
+        char buffer2[100];
+        BGPDUMP_IP_ADDRESS mapped = { .v4_addr.s_addr = ((uint32_t *)addr.v6_addr.s6_addr)[3] };
+        
+        sprintf(buffer, "::%s%s", m ? "ffff:" : "", fmt_ipv4(mapped, buffer2));
+        return buffer;
+    }
+    
+    char hexa[8][5];
+    int zr[8];
+    size_t len;
+    uint8_t x8, hx8;
+    uint16_t x16;
+    
+    int i, k = 0;
+    for (i = 0; i < 16; i += 2) {
+        int j = 0;
+        bool skip = 1;
+        
+        memset(hexa[k], 0, 5);
+        
+        x8 = addr.v6_addr.s6_addr[i];
+        
+        hx8 = x8 >> 4;
+        if (hx8 != 0)
+        {
+            skip = 0;
+            hexa[k][j++] = hexchars[hx8];
+        }
+        
+        hx8 = x8 & 0x0f;
+        if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
+        {
+            skip = 0;
+            hexa[k][j++] = hexchars[hx8];
+        }
+        
+        x8 = addr.v6_addr.s6_addr[i + 1];
+        
+        hx8 = x8 >> 4;
+        if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
+        {
+            hexa[k][j++] = hexchars[hx8];
+        }
+        
+        hx8 = x8 & 0x0f;
+        hexa[k][j] = hexchars[hx8];
+        
+        k++;
+    }
+    
+    /* find runs of zeros for :: convention */
+    int j = 0;
+    for (i = 7; i >= 0; i--)
+    {
+        zr[i] = j;
+        x16 = ((uint16_t *)addr.v6_addr.s6_addr)[i];
+        if (x16 == 0) j++;
+        else j = 0;
+        zr[i] = j;
+    }
+    
+    /* find longest run of zeros */
+    k = -1;
+    j = 0;
+    for(i = 0; i < 8; i++)
+    {
+        if (zr[i] > j)
+        {
+            k = i;
+            j = zr[i];
+        }
+    }
+    
+    for(i = 0; i < 8; i++)
+    {
+        if (i != k) zr[i] = 0;
+    }
+    
+    len = 0;
+    for (i = 0; i < 8; i++)
+    {
+        if (zr[i] != 0)
+        {
+            /* check for leading zero */
+            if (i == 0)
+                buffer[len++] = ':';
+            buffer[len++] = ':';
+            i += (zr[i] - 1);
+            continue;
+        }
+        for (j = 0; hexa[i][j] != '\0'; j++)
+            buffer[len++] = hexa[i][j];
+        if (i != 7)
+            buffer[len++] = ':';
+    }
+    
+    buffer[len] = '\0';
+    
+    return buffer;
+}
+
+static void test_roundtrip(char *str)
+{
+    BGPDUMP_IP_ADDRESS addr;
+    inet_pton(AF_INET6, str, &addr.v6_addr);
+    char tmp[1000];
+    fmt_ipv6(addr, tmp);
+    printf("%s -> %s [%s]\n", str, tmp, strcmp(str, tmp) ? "ERROR" : "ok");
+}
+
+void test_fmt_ip()
+{
+    test_roundtrip("fe80::");
+    test_roundtrip("2001:db8::1");
+    test_roundtrip("::ffff:192.168.2.1");
+    test_roundtrip("::192.168.1.2");
+    test_roundtrip("2001:7f8:30::2:1:0:8447");
+}

+ 25 - 0
test.sh

@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+FAILURES=0
+
+mkdir -p test_out
+
+echo "Running Regression Tests..."
+for mrt in `ls test_data`; do
+    echo -n "      testing $mrt..."
+    OUT=$mrt.bgp.gz
+    ./bgpdump -vm test_data/$mrt > test_out/$OUT
+    gzcat test_expect/$OUT | diff -q test_out/$OUT -
+    if [ $? == 0 ]; then
+        echo "success"
+    else
+        FAILURES=$(( $FAILURES + 1 ))
+    fi
+done
+
+if [ $FAILURES != 0 ]; then
+    echo !!! $FAILURES failures !!!
+    exit 1
+else
+    exit 0
+fi

+ 93 - 0
util.c

@@ -0,0 +1,93 @@
+/*
+ Copyright (c) 2007 - 2010 RIPE NCC - All Rights Reserved
+ 
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted, provided
+ that the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation, and that the name of the author not be used in advertising or
+ publicity pertaining to distribution of the software without specific,
+ written prior permission.
+ 
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
+ AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+ DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ 
+ Created by Devin Bayer on 9/1/10.
+*/
+
+#include "util.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <syslog.h>
+#include <time.h>
+#include <string.h>
+
+static bool use_syslog = true;
+
+void log_to_syslog() {
+    use_syslog = true;
+}
+
+void log_to_stderr() {
+    use_syslog = false;
+}
+
+#define log(lvl, lvl_str) \
+    va_list args; \
+    va_start(args, fmt); \
+    _log(LOG_##lvl, #lvl_str, fmt, args)
+
+static char *now_str() {
+    static char buffer[1000];
+    time_t now = time(0);
+    strftime(buffer, sizeof buffer, "%Y-%m-%d %H:%M:%S", localtime(&now));
+    return buffer;
+}
+
+static void _log(int lvl, char *lvl_str, const char *fmt, va_list args) {
+    if(use_syslog) {
+        syslog(lvl, fmt, args);
+    } else {
+        char prefix[strlen(fmt) + 1000];
+        sprintf(prefix, "%s [%s] %s\n", now_str(), lvl_str, fmt);
+        vfprintf(stderr, prefix, args);
+    }
+}
+
+void err(const char *fmt, ...) { log(ERR, error); }
+void warn(const char *fmt, ...) { log(WARNING, warn); }
+void debug(const char *fmt, ...) { log(INFO, info); }
+
+void time2str(struct tm* date,char *time_str)
+{
+    sprintf(time_str, "%02d/%02d/%02d %02d:%02d:%02d", date->tm_mon+1, date->tm_mday, date->tm_year%100,
+            date->tm_hour, date->tm_min, date->tm_sec);
+}
+
+int int2str(uint32_t value, char* str)
+{
+    return sprintf(str, "%u", value);
+}
+
+static void ti2s(uint32_t value) {
+    char buf[100], ref[100];
+    sprintf(ref, "%u", value);
+    int len = int2str(value, buf);
+    printf("%s =?= %s (%i)\n", ref, buf, len);
+}
+
+void test_utils()
+{
+    ti2s(0);
+    ti2s(99999);
+    ti2s(4294967295L);
+}