tcpdump mailing list archives

Re: Using libnetdissect in other code, outside tcpdump source tree


From: Guy Harris via tcpdump-workers <tcpdump-workers () lists tcpdump org>
Date: Wed, 12 Aug 2020 13:31:36 -0700

--- Begin Message --- From: Guy Harris <gharris () sonic net>
Date: Wed, 12 Aug 2020 13:31:36 -0700
On Aug 11, 2020, at 4:55 AM, Bill Fenner via tcpdump-workers <tcpdump-workers () lists tcpdump org> wrote:

Is there a plan for a public face for libnetdissect?

At some point we should probably do that.

(Back in the late '90's, I discovered a program called tcpview, which was a Motif(!)-based GUI network analyzer based 
on modified tcpdump code, so people *have* used tcpdump's dissection code in their own programs.)

I've tried teasing it
out, and I ended up having to install:
funcattrs.h print.h config.h netdissect.h ip.h ip6.h compiler-tests.h
status-exit-codes.h
in /usr/include/tcpdump/ in order to compile a libnetdissect-using program
outside of the tcpdump source tree.

netdissect.h is the library's main API-declaration header.  print.h also declares functions that I'd consider part of 
libnetdissect's API; status-exit-codes.h is also part of that API.

For funcattrs.h and compiler-tests.h, libpcap installs equivalents in the include/pcap directory, for use by pcap.h.

We should probably have an include/libnetdissect directory in which we install netdissect.h and the headers it requires.

However, API-declaring headers should *NEVER* require config.h (there was a particularly horrible case with OpenBSD's 
version of libz, forcing a painful workaround in Wireshark:

/*
 * OK, now this is tricky.
 *
 * At least on FreeBSD 3.2, "/usr/include/zlib.h" includes
 * "/usr/include/zconf.h", which, if HAVE_UNISTD_H is defined,
 * #defines "z_off_t" to be "off_t", and if HAVE_UNISTD_H is
 * not defined, #defines "z_off_t" to be "long" if it's not
 * already #defined.
 *
 * In 4.4-Lite-derived systems such as FreeBSD, "off_t" is
 * "long long int", not "long int", so the definition of "z_off_t" -
 * and therefore the types of the arguments to routines such as
 * "gzseek()", as declared, with prototypes, in "zlib.h" - depends
 * on whether HAVE_UNISTD_H is defined prior to including "zlib.h"!
 *
 * It's not defined in the FreeBSD 3.2 "zlib", so if we include "zlib.h"
 * after defining HAVE_UNISTD_H, we get a misdeclaration of "gzseek()",
 * and, if we're building with "zlib" support, anything that seeks
 * on a file may not work.
 *
 * Other BSDs may have the same problem, if they haven't done something
 * such as defining HAVE_UNISTD_H in "zconf.h".
 *
 * "config.h" defines HAVE_UNISTD_H, on all systems that have it, and all
 * 4.4-Lite-derived BSDs have it.  Therefore, given that "zlib.h" is included
 * by "file_wrappers.h", that means that unless we include "zlib.h" before
 * we include "config.h", we get a misdeclaration of "gzseek()".
 *
 * Unfortunately, it's "config.h" that tells us whether we have "zlib"
 * in the first place, so we don't know whether to include "zlib.h"
 * until we include "config.h"....
 *
 * A similar problem appears to occur with "gztell()", at least on
 * NetBSD.
 *
 * To add further complication, on recent versions, at least, of OpenBSD,
 * the Makefile for zlib defines HAVE_UNISTD_H.
 *
 * So what we do is, on all OSes other than OpenBSD, *undefine* HAVE_UNISTD_H
 * before including "wtap-int.h" (it handles including "zlib.h" if HAVE_ZLIB
 * is defined, and it includes "wtap.h", which we include to get the
 * WTAP_ERR_ZLIB values), and, if we have zlib, make "file_seek()" and
 * "file_tell()" subroutines, so that the only calls to "gzseek()" and
 * "gztell()" are in this file, which, by dint of the hackery described
 * above, manages to correctly declare "gzseek()" and "gztell()".
 *
 * On OpenBSD, we forcibly *define* HAVE_UNISTD_H if it's not defined.
 *
 * Hopefully, the BSDs will, over time, remove the test for HAVE_UNISTD_H
 * from "zconf.h", so that "gzseek()" and "gztell()" will be declared
 * with the correct signature regardless of whether HAVE_UNISTD_H is
 * defined, so that if they change the signature we don't have to worry
 * about making sure it's defined or not defined.
 *
 * DO NOT, UNDER ANY CIRCUMSTANCES, REMOVE THE FOLLOWING LINES, OR MOVE
 * THEM AFTER THE INCLUDE OF "wtap-int.h"!  Doing so will cause any program
 * using Wiretap to read capture files to fail miserably on a FreeBSD
 * 3.2 or 3.3 system - and possibly some other BSD systems - if zlib is
 * installed.  If you *must* have HAVE_UNISTD_H defined before including
 * "wtap-int.h", put "file_error()" into a file by itself, which can
 * cheerfully include "wtap.h" and get "gzseek()" misdeclared, and include
 * just "zlib.h" in this file - *after* undefining HAVE_UNISTD_H.
 */

Furthermore, the result of config.h may *also* reflect:

        the compiler being used when it was generated, which means that it may not be appropriate on platforms with 
multiple compilers that would produce different config.h results, if you're compiling with a compiler other than the 
one used to generate config.h;

        the instruction set used as the target when config.h was generated, which means that it may not be appropriate 
on platforms that support fat binaries, such as macOS (Apple now only support little-endian 64-bit platforms, and that 
will continue, so it's less of an issue, but it could have been an issue back when you could build a fat binary for 
32-bit big-endian PowerPC, 64-bit big-endian PowerPC, 32-bit little-endian x86, and 64-bit little-endian x86);

        the OS used as the target when config.h was generated, which means that it may be a pain to provide a 
cross-development SDK (build for small embedded Linux on a non-Linux platform - or possibly either on another Linux 
platform);

so if anything in netdissect.h depends on config.h definitions, we should try to fix that.  (This is why the 
compiler-test.h stuff exists - to depend on the compiler being used when building the program using the library, rather 
than the compiler being used when configuring and building the library.)

That leaves ip.h and ip6.h; I'd have to check to see whether they should be considered part of the API or not.

Also, netdissect.h likes to #define min() and max() macros, which makes
life interesting when you have, say, a struct with min and max elements.

It should probably define ND_MIN() and ND_MAX() instead.

--- End Message ---
_______________________________________________
tcpdump-workers mailing list
tcpdump-workers () lists tcpdump org
https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers

Current thread: