droe / sslsplit

Transparent SSL/TLS interception
https://www.roe.ch/SSLsplit
BSD 2-Clause "Simplified" License
1.73k stars 327 forks source link

Libnet init for PCAP logging fails on active OpenVPN tun0 #232

Closed droe closed 5 years ago

droe commented 5 years ago

When initializing libnet for PCAP logging while OpenVPN has tun0 open, sslsplit fails with:

Failed to init pcap libnet: unknown physical layer type 0xfffe                
/usr/local/bin/sslsplit: failed to preinit logging.

When shutting down OpenVPN, or when not using PCAP logging, the issue disappears. The following patch against libnet also fixes the issue:

--- libnet-1.1.6+dfsg.orig/src/libnet_link_linux.c
+++ libnet-1.1.6+dfsg/src/libnet_link_linux.c
@@ -68,6 +68,10 @@
 #include "../include/os-proto.h"                                               
 #endif                                                                         

+#ifndef ARPHRD_NONE
+#define ARPHRD_NONE 0xFFFE
+#endif

 int
 libnet_open_link(libnet_t *l)
@@ -125,6 +129,7 @@ libnet_open_link(libnet_t *l)
         case ARPHRD_SLIP6:
         case ARPHRD_CSLIP6:
         case ARPHRD_PPP:
+        case ARPHRD_NONE:
             l->link_type = DLT_RAW;
             break;
         case ARPHRD_FDDI:

We should get the above patch into upstream libnet and/or as port/package patch into as many relevant distributions as possible. Additionally, we will want to consider the following two options:

  1. Tell libnet to use a specific interface when calling libnet_init() for PCAP logging; this needs to be an interface type that leads to good PCAPs and no portability issues. Doable, but requires some portability effort and likely will need root privileges. Untested if it reliably resolves the issue. Tell libnet not to open any interface.
  2. Get rid of libnet in PCAP logging mode: In PCAP mode, we only use libnet to construct the TCP/IP/Ether headers and calculate the checksums. We could construct the headers manually, like we construct the PCAP headers, reducing the use of libnet to only mirroring mode. This would be an inherently portable approach. It also has the potential to be a little faster, avoiding some memory allocations and state juggling of the libnet packet construction code.
droe commented 5 years ago

This is a follow-up bug of #215.

sonertari commented 5 years ago

I cannot reproduce this issue on OpenBSD 6.3 or Linux Mint 19.

My OpenVPN setup uses tun0 for server and tun1 for client: e.g. Tue Oct 9 22:07:17 2018 TUN/TAP device tun0 opened. But I've used a simple configuration to start client and server on the same machine and interface, just to reproduce the issue, so the client and server successfully connect, but nobody uses them. I have used the same setup for both OpenBSD and Linux, using the client and server conf files on UTMFW.

I had both http and https proxy spec on sslsplit with both pcap and mirror logging on, mirror logging on both the same interface as and a different interface from openvpn. Btw, both sslsplit and openvpn were running as root on Linux, as I didn't have special users for them. I started sslsplit after openvpn.

Is it some configuration causing this issue? Do you think I need a more realistic openvpn configuration?

jgelens commented 5 years ago

@sonertari I will paste the sslsplit & OpenVPN config later. This issue occurred on Ubuntu Xenial and I was able to reproduce it as well. I believe both run as a normal user. sslsplit is configured with PcapLog, ConnectLog and ContentLog only.

droe commented 5 years ago

I believe I found a simple way to avoid the issue in libnet: We can use LIBNET_NONE instead of LIBNET_LINK for the PCAP log libnet instance. This causes libnet to not open any interface; based on my reading of the libnet source code, this should avoid the issue entirely. Quick tests indicate that PCAP writing is still fully functional with LIBNET_NONE, we generate type 1 (LINKTYPE_ETHERNET) PCAP records.

@sonertari Can you test drive the above linked commit? @jgelens Can you confirm this fixes the issue for you with an unpatched libnet?

jgelens commented 5 years ago

@droe sure will try tomorrow! (11 Oct. CEST)

sonertari commented 5 years ago

@droe I remember trying LIBNET_NONE on OpenBSD, but I had given up because libnet on OpenBSD does not define it. And if I define it myself with the same value as in Linux, sslsplit gives:

Failed to init pcap libnet: libnet_init(): unsupported injection type

./sslsplit: failed to preinit logging.

Btw, libnet appends a new line at the end of error messages already as above (libpcap doesn't), that is why I wasn't appending new lines to libnet log_err_printf() calls :).

Please note again that I couldn't reproduce the issue earlier.

droe commented 5 years ago

I believe OpenBSD has a very different version of libnet than Debian/Ubuntu. For instance, I cannot see any newlines in the error messages produced by https://github.com/sam-github/libnet/blob/master/libnet/src/libnet_init.c . We can #ifdef __OpenBSD__, or better, #ifdef based on libnet version, or existence of LIBNET_NONE. The latter is probably the best approach for now.

droe commented 5 years ago

Ah, found the commit. The newlines were removed in November 2012: https://github.com/sam-github/libnet/commit/1f39883bc656605ecde816fc1f5238ff86b83e53 The problem with libnet is that there are different forks with slight differences such as these.

jgelens commented 5 years ago

I believe I found a simple way to avoid the issue in libnet: We can use LIBNET_NONE instead of LIBNET_LINK for the PCAP log libnet instance. This causes libnet to not open any interface; based on my reading of the libnet source code, this should avoid the issue entirely. Quick tests indicate that PCAP writing is still fully functional with LIBNET_NONE, we generate type 1 (LINKTYPE_ETHERNET) PCAP records. @jgelens Can you confirm this fixes the issue for you with an unpatched libnet?

This also fixes the issue! Thanks a lot. My libnet patch was accepted as well, but it will probably take forever to end up in various Linux distro's.

droe commented 5 years ago

Thanks for confirming; I’ll take care of finalizing this portably on our side as soon as I am back on decent Internet tonight.

sonertari commented 5 years ago

So, are we going to #define LIBNET_NONE LIBNET_LINK on OpenBSD? Otherwise, it is an unsupported injection type.

droe commented 5 years ago

I was thinking of this:

#ifdef LIBNET_NONE
libnet_init(LIBNET_NONE, NULL, errbuf);
#else
libnet_init(LIBNET_LINK, NULL, errbuf);
#endif

On OpenBSD effectively the same as mapping LIBNET_NONE to LIBNET_LINK, but more explicit and less misleading.

sonertari commented 5 years ago

Hm, ok. And thanks for searching the newline issue. No need to worry about it, as the libnet version on OpenBSD is 1.1.2.1 from 2005.

droe commented 5 years ago

Merged to develop. I will open a follow-up issue to perhaps get rid of libnet for PCAP logging, removing the drawbacks of LIBNET_LINK where LIBNET_NONE is not available.