459 lines
12 KiB
C
459 lines
12 KiB
C
|
/* 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 <winerror.h>
|
||
|
#endif
|
||
|
|
||
|
#include "stub-pcap.h"
|
||
|
|
||
|
|
||
|
#ifdef WIN32
|
||
|
#define WIN32_LEAN_AND_MEAN
|
||
|
#include <windows.h>
|
||
|
#else
|
||
|
#include <dlfcn.h>
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
#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;
|
||
|
}
|
||
|
|