/* Copyright (c) 2007 by Errata Security, All Rights Reserved * Copyright (c) 2017 by Robert David Graham * Programmer(s): Robert David Graham [rdg] */ /* LIBPCAP INTERFACE This VERY MESSY code is a hack to load the 'libpcap' library at runtime rather than compile time. This reason for this mess is that it gets rid of a dependency when compiling this project. Otherwise, developers would have to download the 'libpcap-dev' dependency in order to build this project. Almost every platform these days (OpenBSD, FreeBSD, macOS, Debian, RedHat) comes with a "libpcap.so" library already installed by default with a known BINARY interface. Thus, we can include the data structures definitions directly in this project, then load the library dynamically. For those systems without libpcap.so already installed, the user can either install those on the system, or compile this project in "STATIC" mode, which will link to the static libpcap.a library. */ #include "util-logger.h" #if defined(_MSC_VER) #pragma warning(disable:4115 4201) #pragma warning(disable:4100) /* unreferenced formal parameter */ //#include #endif #include "stub-pcap.h" #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #else #include #endif #include #include #include #ifndef UNUSEDPARM #ifdef __GNUC__ #define UNUSEDPARM(x) #else #define UNUSEDPARM(x) x=(x) #endif #endif struct pcap_if { struct pcap_if *next; char *name; /* name to hand to "pcap_open_live()" */ char *description; /* textual description of interface, or NULL */ void *addresses; unsigned flags; /* PCAP_IF_ interface flags */ }; static void seterr(char *errbuf, const char *msg) { size_t length = strlen(msg); if (length > PCAP_ERRBUF_SIZE-1) length = PCAP_ERRBUF_SIZE-1; memcpy(errbuf, msg, length); errbuf[length] = '\0'; } static void null_PCAP_CLOSE(void *hPcap) { #ifdef STATICPCAP pcap_close(hPcap); return; #endif UNUSEDPARM(hPcap); } #ifdef STATICPCAP static pcap_t *(*null_PCAP_CREATE)(const char *source, char *errbuf); static int (*null_PCAP_SET_SNAPLEN)(pcap_t *p, int snaplen); static int (*null_PCAP_SET_PROMISC)(pcap_t *p, int promisc); static int (*null_PCAP_SET_TIMEOUT)(pcap_t *p, int to_ms); static int (*null_PCAP_SET_IMMEDIATE_MODE)(pcap_t *p, int immediate_mode); static int (*null_PCAP_SET_BUFFER_SIZE)(pcap_t *p, int buffer_size); static int (*null_PCAP_SET_RFMON)(pcap_t *p, int rfmon); static int (*null_PCAP_CAN_SET_RFMON)(pcap_t *p); static int (*null_PCAP_ACTIVATE)(pcap_t *p); #else static pcap_t *null_PCAP_CREATE(const char *source, char *errbuf) {return 0;} static int null_PCAP_SET_SNAPLEN(pcap_t *p, int snaplen) {return 0;} static int null_PCAP_SET_PROMISC(pcap_t *p, int promisc) {return 0;} static int null_PCAP_SET_TIMEOUT(pcap_t *p, int to_ms) {return 0;} static int null_PCAP_SET_IMMEDIATE_MODE(pcap_t *p, int immediate_mode) {return 0;} static int null_PCAP_SET_BUFFER_SIZE(pcap_t *p, int buffer_size) {return 0;} static int null_PCAP_SET_RFMON(pcap_t *p, int rfmon) {return 0;} static int null_PCAP_CAN_SET_RFMON(pcap_t *p) {return 0;} static int null_PCAP_ACTIVATE(pcap_t *p) {return 0;} #endif static unsigned null_PCAP_DATALINK(void *hPcap) { #ifdef STATICPCAP return pcap_datalink(hPcap); #endif UNUSEDPARM(hPcap); return 0; } static unsigned null_PCAP_DISPATCH(void *hPcap, unsigned how_many_packets, PCAP_HANDLE_PACKET handler, void *handle_data) { #ifdef STATICPCAP return pcap_dispatch(hPcap, how_many_packets, handler, handle_data); #endif UNUSEDPARM(hPcap);UNUSEDPARM(how_many_packets);UNUSEDPARM(handler);UNUSEDPARM(handle_data); return 0; } static int null_PCAP_FINDALLDEVS(pcap_if_t **alldevs, char *errbuf) { #ifdef STATICPCAP return pcap_findalldevs(alldevs, errbuf); #endif *alldevs = 0; seterr(errbuf, "libpcap not loaded"); return -1; } static void null_PCAP_FREEALLDEVS(pcap_if_t *alldevs) { #ifdef STATICPCAP return pcap_freealldevs(alldevs); #endif UNUSEDPARM(alldevs); return; } static char *null_PCAP_LOOKUPDEV(char *errbuf) { #ifdef STATICPCAP return pcap_lookupdev(errbuf); #endif seterr(errbuf, "libpcap not loaded"); return ""; } static void * null_PCAP_OPEN_LIVE(const char *devicename, unsigned snap_length, unsigned is_promiscuous, unsigned read_timeout, char *errbuf) { #ifdef STATICPCAP return pcap_open_live(devicename, snap_length, is_promiscuous, read_timeout, errbuf); #endif seterr(errbuf, "libpcap not loaded"); UNUSEDPARM(devicename);UNUSEDPARM(snap_length);UNUSEDPARM(is_promiscuous);UNUSEDPARM(read_timeout); return NULL; } static int null_PCAP_MAJOR_VERSION(void *p) { #ifdef STATICPCAP return pcap_major_version(p); #endif UNUSEDPARM(p); return 0; } static int null_PCAP_MINOR_VERSION(void *p) { #ifdef STATICPCAP return pcap_minor_version(p); #endif UNUSEDPARM(p); return 0; } static const char *null_PCAP_LIB_VERSION(void) { #ifdef STATICPCAP return pcap_lib_version(); #endif return "stub/0.0"; } struct PcapFunctions PCAP = { 0,0,0,0,0, null_PCAP_CLOSE, }; static void *my_null(int x, ...) { UNUSEDPARM(x); printf("%.*s", 0, "a"); /* Remove warnings about no effects */ return 0; } static pcap_t *null_PCAP_OPEN_OFFLINE(const char *fname, char *errbuf) { #ifdef STATICPCAP return pcap_open_offline(fname, errbuf); #endif return my_null(2, fname, errbuf); } static int null_PCAP_SENDPACKET(pcap_t *p, const unsigned char *buf, int size) { #ifdef STATICPCAP return pcap_sendpacket(p, buf, size); #endif my_null(3, p, buf, size); return 0; } static const unsigned char *null_PCAP_NEXT(pcap_t *p, struct pcap_pkthdr *h) { #ifdef STATICPCAP return pcap_next(p, h); #endif my_null(3, p, h); return 0; } static int null_PCAP_SETDIRECTION(pcap_t *p, pcap_direction_t d) { #ifdef STATICPCAP return pcap_setdirection(p, d); #endif my_null(2, p, d); return 0; } static const char *null_PCAP_DATALINK_VAL_TO_NAME(int dlt) { #ifdef STATICPCAP return pcap_datalink_val_to_name(dlt); #endif my_null(1, dlt); return 0; } static void null_PCAP_PERROR(pcap_t *p, char *prefix) { #ifdef STATICPCAP pcap_perror(p, prefix); return; #endif UNUSEDPARM(p); fprintf(stderr, "%s\n", prefix); perror("pcap"); } static const char*null_PCAP_GETERR(pcap_t *p) { #ifdef STATICPCAP return pcap_geterr(p); #endif UNUSEDPARM(p); return "(unknown)"; } static const char *null_PCAP_DEV_NAME(const pcap_if_t *dev) { return dev->name; } static const char *null_PCAP_DEV_DESCRIPTION(const pcap_if_t *dev) { return dev->description; } static const pcap_if_t *null_PCAP_DEV_NEXT(const pcap_if_t *dev) { return dev->next; } /* * Some Windows-specific functions to improve speed */ #if defined(WIN32) static pcap_send_queue *null_PCAP_SENDQUEUE_ALLOC(size_t size) { UNUSEDPARM(size); return 0; } static unsigned null_PCAP_SENDQUEUE_TRANSMIT(pcap_t *p, pcap_send_queue *queue, int sync) { my_null(3, p, queue, sync); return 0; } static void null_PCAP_SENDQUEUE_DESTROY(pcap_send_queue *queue) { my_null(1, queue); UNUSEDPARM(queue); } static int null_PCAP_SENDQUEUE_QUEUE(pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const unsigned char *pkt_data) { my_null(4, queue, pkt_header, pkt_data); return 0; } #endif /*WIN32*/ /** * Runtime-load the libpcap shared-object or the winpcap DLL. We * load at runtime rather than loadtime to allow this program to * be used to process offline content, and to provide more helpful * messages to people who don't realize they need to install PCAP. */ int pcap_init(void) { struct PcapFunctions *pl = &PCAP; #ifdef WIN32 void * hPacket; void * hLibpcap; pl->is_available = 0; pl->is_printing_debug = 1; /* Look for the Packet.dll */ hPacket = LoadLibraryA("NPcap\\Packet.dll"); if (hPacket == NULL) hPacket = LoadLibraryA("Packet.dll"); if (hPacket == NULL) { if (pl->is_printing_debug) switch (GetLastError()) { case ERROR_MOD_NOT_FOUND: fprintf(stderr, "%s: not found\n", "Packet.dll"); fprintf(stderr, " HINT: you must install either WinPcap or Npcap\n"); return -1; default: fprintf(stderr, "%s: couldn't load %d\n", "Packet.dll", (int)GetLastError()); return -1; } } /* Look for the winpcap.dll */ hLibpcap = LoadLibraryA("Npcap\\wpcap.dll"); if (hLibpcap == NULL) hLibpcap = LoadLibraryA("wpcap.dll"); if (hLibpcap == NULL) { if (pl->is_printing_debug) fprintf(stderr, "%s: couldn't load %d\n", "wpcap.dll", (int)GetLastError()); return -1; } #define DOLINK(PCAP_DATALINK, datalink) \ pl->datalink = (PCAP_DATALINK)GetProcAddress(hLibpcap, "pcap_"#datalink); \ if (pl->datalink == NULL) pl->func_err=1, pl->datalink = null_##PCAP_DATALINK; #endif #ifndef WIN32 #ifndef STATICPCAP void *hLibpcap; pl->is_available = 0; pl->is_printing_debug = 1; { static const char *possible_names[] = { "libpcap.so", "libpcap.A.dylib", "libpcap.dylib", "libpcap.so.1", "libpcap.so.0.9.5", "libpcap.so.0.9.4", "libpcap.so.0.8", 0 }; unsigned i; for (i=0; possible_names[i]; i++) { hLibpcap = dlopen(possible_names[i], RTLD_LAZY); if (hLibpcap) { LOG(1, "[+] pcap: found library: %s\n", possible_names[i]); break; } else { LOG(1, "[-] pcap: failed to load: %s\n", possible_names[i]); } } if (hLibpcap == NULL) { LOG(0, "[-] FAIL: failed to load libpcap shared library\n"); LOG(0, " [hint]: you must install libpcap or WinPcap\n"); } } #define DOLINK(PCAP_DATALINK, datalink) \ pl->datalink = (PCAP_DATALINK)dlsym(hLibpcap, "pcap_"#datalink); \ if (pl->datalink == NULL) LOG(1, "pcap: pcap_%s: failed\n", #datalink); \ if (pl->datalink == NULL) pl->func_err=1, pl->datalink = null_##PCAP_DATALINK; #else #define DOLINK(PCAP_DATALINK, datalink) \ pl->func_err=0, pl->datalink = null_##PCAP_DATALINK; #endif #endif DOLINK(PCAP_CLOSE , close); DOLINK(PCAP_DATALINK , datalink); DOLINK(PCAP_DISPATCH , dispatch); DOLINK(PCAP_FINDALLDEVS , findalldevs); DOLINK(PCAP_FREEALLDEVS , freealldevs); DOLINK(PCAP_LIB_VERSION , lib_version); DOLINK(PCAP_LOOKUPDEV , lookupdev); DOLINK(PCAP_MAJOR_VERSION , major_version); DOLINK(PCAP_MINOR_VERSION , minor_version); DOLINK(PCAP_OPEN_LIVE , open_live); DOLINK(PCAP_OPEN_OFFLINE , open_offline); DOLINK(PCAP_SENDPACKET , sendpacket); DOLINK(PCAP_NEXT , next); DOLINK(PCAP_SETDIRECTION , setdirection); DOLINK(PCAP_DATALINK_VAL_TO_NAME , datalink_val_to_name); DOLINK(PCAP_PERROR , perror); DOLINK(PCAP_GETERR , geterr); /* pseudo functions that don't exist in the libpcap interface */ pl->dev_name = null_PCAP_DEV_NAME; pl->dev_description = null_PCAP_DEV_DESCRIPTION; pl->dev_next = null_PCAP_DEV_NEXT; /* windows-only functions that might improve speed */ #if defined(WIN32) DOLINK(PCAP_SENDQUEUE_ALLOC , sendqueue_alloc); DOLINK(PCAP_SENDQUEUE_TRANSMIT , sendqueue_transmit); DOLINK(PCAP_SENDQUEUE_DESTROY , sendqueue_destroy); DOLINK(PCAP_SENDQUEUE_QUEUE , sendqueue_queue); #endif DOLINK(PCAP_CREATE , create); DOLINK(PCAP_SET_SNAPLEN , set_snaplen); DOLINK(PCAP_SET_PROMISC , set_promisc); DOLINK(PCAP_SET_TIMEOUT , set_timeout); DOLINK(PCAP_SET_IMMEDIATE_MODE , set_immediate_mode); DOLINK(PCAP_SET_BUFFER_SIZE , set_buffer_size); DOLINK(PCAP_SET_RFMON , set_rfmon); DOLINK(PCAP_CAN_SET_RFMON , can_set_rfmon); DOLINK(PCAP_ACTIVATE , activate); if (!pl->func_err) pl->is_available = 1; else pl->is_available = 0; return 0; }