the-tcpdump-group / libpcap

the LIBpcap interface to various kernel packet capture mechanism
https://www.tcpdump.org/
Other
2.72k stars 855 forks source link

rpcapd: Link to shared library rather than statically #955

Open netrounds-fredrik opened 4 years ago

netrounds-fredrik commented 4 years ago

When compiling the rpcapd application on a UNIX system, libpcap is linked statically rather than dynamically (https://github.com/the-tcpdump-group/libpcap/blob/6fedfcefe327395587fe08ce58a80c0fd1bfc09c/rpcapd/CMakeLists.txt#L119).

In a production environment you might want to use the existing libpcap installed on your system in order to get security updates from your Linux distro and to avoid having multiple binary copies of the library, so it would be good it it was possible to build rpcapd without static linking like you would normally build an application.

guyharris commented 4 years ago

In a production environment you might want to use the existing libpcap installed on your system

Which sounds as if there should be a separate repository for rpcapd, so you can build it separately from libpcap.

netrounds-fredrik commented 4 years ago

It would make sense to be able to build rpcapd separate from libpcap as they are not that tightly coupled from an API point of view. They can however still live in the same repo, just like libcurl and the curl command line tool do.

Is there a reason why rpcapd SHOULD link libpcap statically? There might be some low level dependency between them that I'm not aware of.

mcr commented 4 years ago

Fredrik Kers notifications@github.com wrote:

Is there a reason why rpcapd SHOULD link libpcap statically? There might be some low level dependency between them that I'm not aware of.

It is because (i seem recall) most of the support for generated shared objects is in the distro packaging. We don't by default, generate a ".so".

-- ] Never tell me the odds! | ipv6 mesh networks [ ] Michael Richardson, Sandelman Software Works | IoT architect [ ] mcr@sandelman.ca http://www.sandelman.ca/ | ruby on rails [

infrastation commented 4 years ago

Quite the opposite, libpcap does generate a .so by default because that is its main purpose.

Perhaps a good reason to link rpcapd statically for the time being is that rpcapd is still a work in progress and may depend on libpcap features that are still work in progress, so you can try today's rpcapd without introducing a bleeding edge today's version of a shared library into a working system.

Also there is a maintenance effort cost to having one more repository given the software needs to be portable and needs to have two build systems (autotools and CMake).

netrounds-fredrik commented 4 years ago

From what I can see without digging too much into the details it doesn't seem to be too much work to make it possible to build rpcapd against a shared library, still in the same repo. Would you be interested in a PR for this once we get time to look into it?

infrastation commented 4 years ago

Thank you for the offer. It would help to state the problem before working on the solution.

The current state is as follows. There is an rpcapd that is statically linked with libpcap.

A) If it comes from a system package (e.g. "libpcap-utils-static" or some such), it will be updated at the same time as the binary "libpcap" package, because both build from the "libpcap" source package.

B) Otherwise, if it comes from /usr/local as a result of a local source build and make install, after the packaged libpcap.so update it will continue use the compiled-in libpcap and will not have the bugfixes.

The proposed solution, as far as I can understand it, is as follows. There is an rpcapd that is dynamically linked with libpcap in the same build tree as libpcap.

C) If it comes from a system package, it will get the bugfixes during the libpcap binary package update. So C and A are same good.

D) Otherwise, if it comes from /usr/local as a result of a local source build, the libpcap with that it had built is in /usr/local too. After the packaged libpcap.so update the locally built rpcapd will still continue to use the locally built libpcap from /usr/local because that shared library directory has a priority over the directories where packaged shared libraries install the .so files (at least on some Linuxes). Also other software dynamically linked with the same soname will use the non-patched libpcap from /usr/local that the locally built rpcapd had installed. So D is worse than B.

Could you please describe the specific use case that you see and how the proposed change improves it?

mcr commented 4 years ago

If rpcapd is dynamically linked against libpcap, then it will likely use whatever libpcap.so that is in the system search path. That most likely is not the one in ../libpcap.so, so you will regularly be surprised.

netrounds-fredrik commented 4 years ago

To my knowledge there are no distro that currently package rpcapd (checked Debian, Ubuntu, RHEL/Centos), scenario A/C doesn't really exist as of today. In scenario D I would only have rpcapd in /usr/local and let it use libpcap from the distro, and in that way get security updates for free. Then there might of course be important updates to rpcapd, but it's still less code to worry about.

Another good reason to link dynamically is because it's what you would expect. I can not come up with any project that has a library as well as an executable that does not link to the library dynamically when packaged for a distribution. See for example

You could have the exact same arguments about tcpdump. Why is that not linking libpcap statically?

If rpcapd is dynamically linked against libpcap, then it will likely use whatever libpcap.so that is in the system search path. That most likely is not the one in ../libpcap.so, so you will regularly be surprised.

Just as surprised as any other user of libpcap, so not too surprised I hope :)

guyharris commented 4 years ago

To my knowledge there are no distro that currently package rpcapd (checked Debian, Ubuntu, RHEL/Centos), scenario A/C doesn't really exist as of today.

Currently true, but we should not assume it will remain true, or make it difficult for any OS that ships libpcap to ship rpcapd as well.

In scenario D I would only have rpcapd in /usr/local and let it use libpcap from the distro,

That appears to call for an option to build and install only rpcapd, whether it's a separate repository and release tarball for rpcapd or configure-script and CMake options.

(A separate repository has the problem that there are both rpcap clients, such as the libpcap module for rpcap remote capture, and rpcap servers, such as rpcapd. Our implementations share some common headers and code.)

There's also scenario E, where you're building libpcap and rpcapd for testing and development purposes, so a dynamically-linked rpcapd would have to find the libpcap shared library/DLL in the build directory. That's not a top priority, but it'd be helpful if there was some way to make it work.

Another good reason to link dynamically is because it's what you would expect. I can not come up with any project that has a library as well as an executable that does not link to the library dynamically when packaged for a distribution. See for example

You could have the exact same arguments about tcpdump. Why is that not linking libpcap statically?

1) It's a separate package; it's a program that happens to use libpcap, just as Wireshark is a program that happens to use libpcap. A user might just want to build and run the latest tcpdump with the system libpcap, and not want to bother building libpcap (if, for example, they don't care about additional capturing functionality in a newer libpcap release, they just want newer dissection capability in the newer tcpdump release). They're released as separate source tarballs and are in separate repositories.

2) However, we have, at least when using autotools, a special hack for people who are building both libpcap and tcpdump and might not want to install either one, wherein tcpdump can link with a libpcap built in the ../libpcap-{version} directory; that links statically.

netrounds-fredrik commented 4 years ago

Perhaps a good reason to link rpcapd statically for the time being is that rpcapd is still a work in progress and may depend on libpcap features that are still work in progress, so you can try today's rpcapd without introducing a bleeding edge today's version of a shared library into a working system.

Yes, this is the only valid reason as I see it. However, from what I can see it's only the client side libpcap that need to expose the new APIs in pcap-new.c (pcap_findalldevs_ex, pcap_open, etc.) since rpcapd is only using the "standard" APIs (pcap_findalldevs, pcap_open_live, etc.).

guyharris commented 4 years ago

Yes, this is the only valid reason as I see it. However, from what I can see it's only the client side libpcap that need to expose the new APIs in pcap-new.c (pcap_findalldevs_ex, pcap_open, etc.) since rpcapd is only using the "standard" APIs (pcap_findalldevs, pcap_open_live, etc.).

The "new" APIs defined in pcap-new.c are:

so there's no need for rpcapd to use any of those APIs.

However, 1) new libpcap APIs won't be added in pcap-new.c (the name is historical, from WinPcap) and 2) newer versions of the protocol may mean that rpcapd will be using new APIs.

netrounds-fredrik commented 4 years ago

There's also scenario E, where you're building libpcap and rpcapd for testing and development purposes

It could still be possible to build with static linking. I'm not even saying it can not still be the default option.

we should not ... make it difficult for any OS that ships libpcap to ship rpcapd as well.

... tcpdump. Why is that not linking libpcap statically? It's a separate package; it's a program that happens to use libpcap

This was also my point with the examples of the other projects. They build a library and a program from the same repo, which are then distributed as separate packages in the distro. If rpcapd where to be distributed in Debian, it would probably be as a separate package that depends on the existing libpcap that is already in the distro.

mcr commented 4 years ago

Guy Harris notifications@github.com wrote:

There's also scenario E, where you're building libpcap and rpcapd for testing and development purposes, so a dynamically-linked rpcapd would have to find the libpcap shared library/DLL in the build directory. That's not a top priority, but it'd be helpful if there was some way to make it work.

It's annoying and difficult, and makes testing really unpredictable. As long as we can build statically, it makes testing and debugging easiest.

But, if we are going to support shared libraries, then we need to test with shared libraries.

-- ] Never tell me the odds! | ipv6 mesh networks [ ] Michael Richardson, Sandelman Software Works | IoT architect [ ] mcr@sandelman.ca http://www.sandelman.ca/ | ruby on rails [

infrastation commented 4 years ago

Is the consensus to leave this as it is now until dust settles in rpcapd?

lukastribus commented 4 years ago

I've filed a request to enable rpcap support in debians libpcap back in July:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=964985

@guyharris should the debian maintainer go ahead with adding --enable-remote or wait?

netrounds-fredrik commented 4 years ago

I believe that this can be split up into two distinct parts. One is to build rpcapd without having to enable the experimental "remote" API in libpcap and the other is to make rpcapd link to libpcap dynamically.

I have made an attempt to show how this could be solved in these PRs:

  1. https://github.com/the-tcpdump-group/libpcap/pull/961
  2. https://github.com/the-tcpdump-group/libpcap/pull/962