masscan-mark-ii/src/rawsock.c

1005 lines
30 KiB
C
Executable File

/*
portable interface to "raw sockets"
This uses both "libpcap" on systems, but on Linux, we try to use the
basic raw sockets, bypassing libpcap for better performance.
*/
#include "rawsock.h"
#include "templ-pkt.h"
#include "util-logger.h"
#include "main-ptrace.h"
#include "util-safefunc.h"
#include "stub-pcap.h"
#include "stub-pfring.h"
#include "pixie-timer.h"
#include "main-globals.h"
#include "proto-preprocess.h"
#include "stack-arpv4.h"
#include "stack-ndpv6.h"
#include "unusedparm.h"
#include "util-malloc.h"
#include <assert.h>
#include <ctype.h>
static int is_pcap_file = 0;
#ifdef WIN32
#include <winsock.h>
#include <iphlpapi.h>
#if defined(_MSC_VER)
#pragma comment(lib, "IPHLPAPI.lib")
#endif
#elif defined(__GNUC__)
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#else
#endif
#include "rawsock-adapter.h"
#define SENDQ_SIZE 65536 * 8
struct AdapterNames
{
char *easy_name;
char *hard_name;
};
struct AdapterNames adapter_names[64];
unsigned adapter_name_count = 0;
/***************************************************************************
***************************************************************************/
#ifdef WIN32
int pcap_setdirection(pcap_t *pcap, pcap_direction_t direction)
{
static int (*real_setdirection)(pcap_t *, pcap_direction_t) = 0;
if (real_setdirection == 0) {
void* h = LoadLibraryA("wpcap.dll");
if (h == NULL) {
fprintf(stderr, "couldn't load wpcap.dll: %u\n",
(unsigned)GetLastError());
return -1;
}
real_setdirection = (int (*)(pcap_t*,pcap_direction_t))
GetProcAddress(h, "pcap_setdirection");
if (real_setdirection == 0) {
fprintf(stderr, "couldn't find pcap_setdirection(): %u\n",
(unsigned)GetLastError());
return -1;
}
}
return real_setdirection(pcap, direction);
}
#endif
/***************************************************************************
***************************************************************************/
void
rawsock_init(void)
{
#ifdef WIN32
/* Declare and initialize variables */
// It is possible for an adapter to have multiple
// IPv4 addresses, gateways, and secondary WINS servers
// assigned to the adapter.
//
// Note that this sample code only prints out the
// first entry for the IP address/mask, and gateway, and
// the primary and secondary WINS server for each adapter.
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
UINT i;
/* variables used to print DHCP time info */
//struct tm newtime;
//char buffer[32];
ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof (IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return;
}
// Make an initial call to GetAdaptersInfo to get
// the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
if (pAdapterInfo == NULL) {
printf("Error allocating memory needed to call GetAdaptersinfo\n");
return;
}
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
for (pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) {
if (pAdapter->Type != MIB_IF_TYPE_ETHERNET)
continue;
//printf("\tComboIndex: \t%d\n", pAdapter->ComboIndex);
//printf("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
{
size_t name_len = strlen(pAdapter->AdapterName) + 12 + 1;
char *name = (char*)malloc(name_len);
size_t addr_len = pAdapter->AddressLength * 3 + 1;
char *addr = (char*)malloc(addr_len);
if (name == NULL || addr == NULL)
exit(1);
snprintf(name, name_len, "\\Device\\NPF_%s", pAdapter->AdapterName);
//printf("\tAdapter Desc: \t%s\n", pAdapter->Description);
//printf("\tAdapter Addr: \t");
for (i = 0; i < pAdapter->AddressLength; i++) {
if (i == (pAdapter->AddressLength - 1))
snprintf(addr+i*3, addr_len-i*3, "%.2X", pAdapter->Address[i]);
else
snprintf(addr+i*3, addr_len-i*3, "%.2X-", pAdapter->Address[i]);
}
//printf("%s -> %s\n", addr, name);
adapter_names[adapter_name_count].easy_name = addr;
adapter_names[adapter_name_count].hard_name = name;
adapter_name_count++;
}
//printf("\tIndex: \t%d\n", pAdapter->Index);
{
size_t name_len = strlen(pAdapter->AdapterName) + 12 + 1;
char *name = (char*)malloc(name_len);
size_t addr_len = strlen(pAdapter->IpAddressList.IpAddress.String) + 1;
char *addr = (char*)malloc(addr_len);
if (name == NULL || addr == NULL)
exit(1);
snprintf(name, name_len, "\\Device\\NPF_%s", pAdapter->AdapterName);
snprintf(addr, addr_len, "%s", pAdapter->IpAddressList.IpAddress.String);
//printf("%s -> %s\n", addr, name);
adapter_names[adapter_name_count].easy_name = addr;
adapter_names[adapter_name_count].hard_name = name;
adapter_name_count++;
}
}
} else {
printf("GetAdaptersInfo failed with error: %u\n",
(unsigned)dwRetVal);
}
if (pAdapterInfo)
free(pAdapterInfo);
#else
PFRING_init();
#endif
return;
}
/***************************************************************************
* This function prints to the command line a list of all the network
* interfaces/devices.
***************************************************************************/
void
rawsock_list_adapters(void)
{
pcap_if_t *alldevs;
char errbuf[PCAP_ERRBUF_SIZE];
if (PCAP.findalldevs(&alldevs, errbuf) != -1) {
int i;
const pcap_if_t *d;
i=0;
if (alldevs == NULL) {
fprintf(stderr, "ERR:libpcap: no adapters found, are you sure you are root?\n");
}
/* Print the list */
for(d=alldevs; d; d=PCAP.dev_next(d)) {
fprintf(stderr, " %d %s \t", i++, PCAP.dev_name(d));
if (PCAP.dev_description(d))
fprintf(stderr, "(%s)\n", PCAP.dev_description(d));
else
fprintf(stderr, "(No description available)\n");
}
fprintf(stderr,"\n");
PCAP.freealldevs(alldevs);
} else {
fprintf(stderr, "%s\n", errbuf);
}
}
/***************************************************************************
***************************************************************************/
static const char *
adapter_from_index(unsigned index)
{
pcap_if_t *alldevs;
char errbuf[PCAP_ERRBUF_SIZE];
int x;
x = PCAP.findalldevs(&alldevs, errbuf);
if (x != -1) {
const pcap_if_t *d;
if (alldevs == NULL) {
fprintf(stderr, "ERR:libpcap: no adapters found, are you sure you are root?\n");
}
/* Print the list */
for(d=alldevs; d; d=PCAP.dev_next(d)) {
if (index-- == 0)
return PCAP.dev_name(d);
}
return 0;
} else {
return 0;
}
}
/***************************************************************************
* Some methods of transmit queue multiple packets in a buffer then
* send all queued packets at once. At the end of a scan, we might have
* some pending packets that haven't been transmitted yet. Therefore,
* we'll have to flush them.
***************************************************************************/
void
rawsock_flush(struct Adapter *adapter)
{
if (adapter->sendq) {
PCAP.sendqueue_transmit(adapter->pcap, adapter->sendq, 0);
/* Dude, I totally forget why this step is necessary. I vaguely
* remember there's a good reason for it though */
PCAP.sendqueue_destroy(adapter->sendq);
adapter->sendq = PCAP.sendqueue_alloc(SENDQ_SIZE);
}
}
/***************************************************************************
* wrapper for libpcap's sendpacket
*
* PORTABILITY: WINDOWS and PF_RING
* For performance, Windows and PF_RING can queue up multiple packets, then
* transmit them all in a chunk. If we stop and wait for a bit, we need
* to flush the queue to force packets to be transmitted immediately.
***************************************************************************/
int
rawsock_send_packet(
struct Adapter *adapter,
const unsigned char *packet,
unsigned length,
unsigned flush)
{
/* Why: this happens in "offline mode", when we are benchmarking the
* core algorithms without sending packets. */
if (adapter == 0)
return 0;
/* Print --packet-trace if debugging */
if (adapter->is_packet_trace) {
packet_trace(stdout, adapter->pt_start, packet, length, 1);
}
/* PF_RING */
if (adapter->ring) {
int err = PF_RING_ERROR_NO_TX_SLOT_AVAILABLE;
while (err == PF_RING_ERROR_NO_TX_SLOT_AVAILABLE) {
err = PFRING.send(adapter->ring, packet, length, (unsigned char)flush);
}
if (err < 0)
LOG(1, "pfring:xmit: ERROR %d\n", err);
return err;
}
/* WINDOWS PCAP */
if (adapter->sendq) {
int err;
struct pcap_pkthdr hdr;
hdr.len = length;
hdr.caplen = length;
err = PCAP.sendqueue_queue(adapter->sendq, &hdr, packet);
if (err) {
rawsock_flush(adapter);
PCAP.sendqueue_queue(adapter->sendq, &hdr, packet);
}
if (flush) {
rawsock_flush(adapter);
}
return 0;
}
/* LIBPCAP */
if (adapter->pcap)
return PCAP.sendpacket(adapter->pcap, packet, length);
return 0;
}
/***************************************************************************
***************************************************************************/
int rawsock_recv_packet(
struct Adapter *adapter,
unsigned *length,
unsigned *secs,
unsigned *usecs,
const unsigned char **packet)
{
if (adapter->ring) {
/* This is for doing libpfring instead of libpcap */
struct pfring_pkthdr hdr;
int err;
again:
err = PFRING.recv(adapter->ring,
(unsigned char**)packet,
0, /* zero-copy */
&hdr,
0 /* return immediately */
);
if (err == PF_RING_ERROR_NO_PKT_AVAILABLE || hdr.caplen == 0) {
PFRING.poll(adapter->ring, 1);
if (is_tx_done)
return 1;
goto again;
}
if (err)
return 1;
*length = hdr.caplen;
*secs = (unsigned)hdr.ts.tv_sec;
*usecs = (unsigned)hdr.ts.tv_usec;
} else if (adapter->pcap) {
struct pcap_pkthdr hdr;
*packet = PCAP.next(adapter->pcap, &hdr);
if (*packet == NULL) {
if (is_pcap_file) {
//pixie_time_set_offset(10*100000);
is_tx_done = 1;
is_rx_done = 1;
}
return 1;
}
*length = hdr.caplen;
*secs = (unsigned)hdr.ts.tv_sec;
*usecs = (unsigned)hdr.ts.tv_usec;
}
return 0;
}
/***************************************************************************
* Sends the TCP SYN probe packet.
*
* Step 1: format the packet
* Step 2: send it in a portable manner
***************************************************************************/
void
rawsock_send_probe_ipv4(
struct Adapter *adapter,
ipv4address ip_them, unsigned port_them,
ipv4address ip_me, unsigned port_me,
unsigned seqno, unsigned flush,
struct TemplateSet *tmplset)
{
unsigned char px[2048];
size_t packet_length;
/*
* Construct the destination packet
*/
template_set_target_ipv4(tmplset, ip_them, port_them, ip_me, port_me, seqno,
px, sizeof(px), &packet_length);
/*
* Send it
*/
rawsock_send_packet(adapter, px, (unsigned)packet_length, flush);
}
void
rawsock_send_probe_ipv6(
struct Adapter *adapter,
ipv6address ip_them, unsigned port_them,
ipv6address ip_me, unsigned port_me,
unsigned seqno, unsigned flush,
struct TemplateSet *tmplset)
{
unsigned char px[2048];
size_t packet_length;
/*
* Construct the destination packet
*/
template_set_target_ipv6(tmplset, ip_them, port_them, ip_me, port_me, seqno,
px, sizeof(px), &packet_length);
/*
* Send it
*/
rawsock_send_packet(adapter, px, (unsigned)packet_length, flush);
}
/***************************************************************************
* Used on Windows: network adapters have horrible names, so therefore we
* use numeric indexes instead. You can which adapter you are looking for
* by typing "--iflist" as an option.
***************************************************************************/
static int
is_numeric_index(const char *ifname)
{
int result = 1;
int i;
/* empty strings aren't numbers */
if (ifname[0] == '\0')
return 0;
/* 'true' if all digits */
for (i=0; ifname[i]; i++) {
char c = ifname[i];
if (c < '0' || '9' < c)
result = 0;
}
return result;
}
/***************************************************************************
* Used on Windows: if the adapter name is a numeric index, convert it to
* the full name.
***************************************************************************/
const char *
rawsock_win_name(const char *ifname)
{
if (is_numeric_index(ifname)) {
const char *new_adapter_name;
new_adapter_name = adapter_from_index(atoi(ifname));
if (new_adapter_name)
return new_adapter_name;
}
return ifname;
}
/***************************************************************************
* Configure the socket to not capture transmitted packets. This is needed
* because we transmit packets at a rate of millions per second, which will
* overwhelm the receive thread.
*
* PORTABILITY: Windows doesn't seem to support this feature, so instead
* what we do is apply a BPF filter to ignore the transmits, so that they
* still get filtered at a low level.
***************************************************************************/
void
rawsock_ignore_transmits(struct Adapter *adapter, const char *ifname)
{
if (adapter->ring) {
/* PORTABILITY: don't do anything for PF_RING, because it's
* actually done when we create the adapter, because we can't
* reconfigure the adapter after it's been activated. */
return;
}
if (adapter->pcap) {
int err;
err = PCAP.setdirection(adapter->pcap, PCAP_D_IN);
if (err) {
; //PCAP.perror(adapter->pcap, "if: pcap_setdirection(IN)");
} else {
LOG(2, "if:%s: not receiving transmits\n", ifname);
}
}
}
/***************************************************************************
***************************************************************************/
static void
rawsock_close_adapter(struct Adapter *adapter)
{
if (adapter->ring) {
PFRING.close(adapter->ring);
}
if (adapter->pcap) {
PCAP.close(adapter->pcap);
}
if (adapter->sendq) {
PCAP.sendqueue_destroy(adapter->sendq);
}
free(adapter);
}
/***************************************************************************
* Does the name look like a PF_RING DNA adapter? Common names are:
* dna0
* dna1
* dna0@1
*
***************************************************************************/
static int
is_pfring_dna(const char *name)
{
if (strlen(name) < 4)
return 0;
if (memcmp(name, "zc:", 3) == 0)
return 1;
if (memcmp(name, "dna", 3) != 0)
return 0;
name +=3;
if (!isdigit(name[0]&0xFF))
return 0;
while (isdigit(name[0]&0xFF))
name++;
if (name[0] == '\0')
return 1;
if (name[0] != '@')
return 0;
else
name++;
if (!isdigit(name[0]&0xFF))
return 0;
while (isdigit(name[0]&0xFF))
name++;
if (name[0] == '\0')
return 1;
else
return 0;
}
/***************************************************************************
***************************************************************************/
struct Adapter *
rawsock_init_adapter(const char *adapter_name,
unsigned is_pfring,
unsigned is_sendq,
unsigned is_packet_trace,
unsigned is_offline,
const char *bpf_filter,
unsigned is_vlan,
unsigned vlan_id)
{
struct Adapter *adapter;
char errbuf[PCAP_ERRBUF_SIZE] = "pcap";
/* BPF filter not supported on some platforms, so ignore this compiler
* warning when unused */
UNUSEDPARM(bpf_filter);
adapter = CALLOC(1, sizeof(*adapter));
adapter->is_packet_trace = is_packet_trace;
adapter->pt_start = 1.0 * pixie_gettime() / 1000000.0;
adapter->is_vlan = is_vlan;
adapter->vlan_id = vlan_id;
if (is_offline)
return adapter;
/*----------------------------------------------------------------
* PORTABILITY: WINDOWS
* If is all digits index, then look in indexed list
*----------------------------------------------------------------*/
if (is_numeric_index(adapter_name)) {
const char *new_adapter_name;
new_adapter_name = adapter_from_index(atoi(adapter_name));
if (new_adapter_name == 0) {
fprintf(stderr, "pcap_open_live(%s) error: bad index\n",
adapter_name);
return 0;
} else
adapter_name = new_adapter_name;
}
/*----------------------------------------------------------------
* PORTABILITY: PF_RING
* If we've been told to use --pfring, then attempt to open the
* network adapter using the PF_RING API rather than libpcap.
* Since a lot of things can go wrong, we do a lot of extra
* logging here.
*----------------------------------------------------------------*/
if(is_pfring && !is_pfring_dna(adapter_name)){ /*First ensure pfring dna adapter is available*/
fprintf(stderr,"No pfring adapter available. Please install pfring or run masscan without the --pfring option.\n");
return 0;
}
if (is_pfring_dna(adapter_name)) {
int err;
unsigned version;
/*
* Open
*
* TODO: Do we need the PF_RING_REENTRANT flag? We only have one
* transmit and one receive thread, so I don't think we need it.
* Also, this reduces performance in half, from 12-mpps to
* 6-mpps.
* NOTE: I don't think it needs the "re-entrant" flag, because it
* transmit and receive are separate functions?
*/
LOG(2, "pfring:'%s': opening...\n", adapter_name);
adapter->ring = PFRING.open(adapter_name, 1500, 0);//PF_RING_REENTRANT);
adapter->pcap = (pcap_t*)adapter->ring;
adapter->link_type = 1;
if (adapter->ring == NULL) {
LOG(0, "pfring:'%s': OPEN ERROR: %s\n",
adapter_name, strerror(errno));
return 0;
} else
LOG(1, "pfring:'%s': successfully opened\n", adapter_name);
/*
* Housekeeping
*/
PFRING.set_application_name(adapter->ring, "masscan");
PFRING.version(adapter->ring, &version);
LOG(1, "pfring: version %d.%d.%d\n",
(version >> 16) & 0xFFFF,
(version >> 8) & 0xFF,
(version >> 0) & 0xFF);
LOG(2, "pfring:'%s': setting direction\n", adapter_name);
err = PFRING.set_direction(adapter->ring, rx_only_direction);
if (err) {
fprintf(stderr, "pfring:'%s': setdirection = %d\n",
adapter_name, err);
} else
LOG(2, "pfring:'%s': direction success\n", adapter_name);
/*
* Activate
*
* PF_RING requires a separate activation step.
*/
LOG(2, "pfring:'%s': activating\n", adapter_name);
err = PFRING.enable_ring(adapter->ring);
if (err != 0) {
LOG(0, "pfring: '%s': ENABLE ERROR: %s\n",
adapter_name, strerror(errno));
PFRING.close(adapter->ring);
adapter->ring = 0;
return 0;
} else
LOG(1, "pfring:'%s': successfully enabled\n", adapter_name);
return adapter;
}
/*----------------------------------------------------------------
* Kludge: for using files
*----------------------------------------------------------------*/
if (memcmp(adapter_name, "file:", 5) == 0) {
LOG(1, "pcap: file: %s\n", adapter_name+5);
is_pcap_file = 1;
adapter->pcap = PCAP.open_offline(adapter_name+5, errbuf);
adapter->link_type = PCAP.datalink(adapter->pcap);
}
/*----------------------------------------------------------------
* PORTABILITY: LIBPCAP
*
* This is the standard that should work everywhere.
*----------------------------------------------------------------*/
{
int err;
LOG(1, "[+] if(%s): pcap: %s\n", adapter_name, PCAP.lib_version());
LOG(2, "[+] if(%s): opening...\n", adapter_name);
/* This reserves resources, but doesn't actually open the
* adapter until we call pcap_activate */
adapter->pcap = PCAP.create(adapter_name, errbuf);
if (adapter->pcap == NULL) {
adapter->pcap = PCAP.open_live(
adapter_name, /* interface name */
65536, /* max packet size */
8, /* promiscuous mode */
1000, /* read timeout in milliseconds */
errbuf);
if (adapter->pcap == NULL) {
LOG(0, "FAIL:%s: can't open adapter: %s\n", adapter_name, errbuf);
if (strstr(errbuf, "perm")) {
LOG(0, "FAIL: permission denied\n");
LOG(0, " [hint] need to sudo or run as root or something\n");
}
return 0;
}
} else {
err = PCAP.set_snaplen(adapter->pcap, 65536);
if (err) {
PCAP.perror(adapter->pcap, "if: set_snaplen");
goto pcap_error;
}
err = PCAP.set_promisc(adapter->pcap, 8);
if (err) {
PCAP.perror(adapter->pcap, "if: set_promisc");
goto pcap_error;
}
err = PCAP.set_timeout(adapter->pcap, 1000);
if (err) {
PCAP.perror(adapter->pcap, "if: set_timeout");
goto pcap_error;
}
err = PCAP.set_immediate_mode(adapter->pcap, 1);
if (err) {
PCAP.perror(adapter->pcap, "if: set_immediate_mode");
goto pcap_error;
}
/* If errors happen, they aren't likely to happen above, but will
* happen where when they are applied */
err = PCAP.activate(adapter->pcap);
switch (err) {
case 0:
/* drop down below */
break;
case PCAP_ERROR_PERM_DENIED:
LOG(0, "[-] FAIL: permission denied\n");
LOG(0, " [hint] need to sudo or run as root or something\n");
goto pcap_error;
default:
LOG(0, "[-] if(%s): activate:%d: %s\n", adapter_name, err, PCAP.geterr(adapter->pcap));
if (err < 0)
goto pcap_error;
}
}
LOG(1, "[+] if(%s): successfully opened\n", adapter_name);
/* Figure out the link-type. We suport Ethernet and IP */
adapter->link_type = PCAP.datalink(adapter->pcap);
switch (adapter->link_type) {
case -1:
PCAP.perror(adapter->pcap, "if: datalink");
goto pcap_error;
case 0: /* Null/Loopback [VPN tunnel] */
LOG(1, "[+] if(%s): VPN tunnel interface found\n", adapter_name);
break;
case 1: /* Ethernet */
case 12: /* IP Raw */
break;
default:
LOG(0, "[-] if(%s): unknown data link type: %u(%s)\n",
adapter_name,
adapter->link_type,
PCAP.datalink_val_to_name(adapter->link_type));
break;
}
}
/*----------------------------------------------------------------
* PORTABILITY: WINDOWS
*
* The transmit rate on Windows is really slow, like 40-kpps.
* The speed can be increased by using the "sendqueue" feature
* to roughly 300-kpps.
*----------------------------------------------------------------*/
adapter->sendq = 0;
#if defined(WIN32)
if (is_sendq)
adapter->sendq = PCAP.sendqueue_alloc(SENDQ_SIZE);
#endif
return adapter;
pcap_error:
if (adapter->pcap) {
PCAP.close(adapter->pcap);
adapter->pcap = NULL;
}
if (adapter->pcap == NULL) {
if (strcmp(adapter_name, "vmnet1") == 0) {
LOG(0, " [hint] VMware on Macintosh doesn't support masscan\n");
}
return 0;
}
return NULL;
}
/***************************************************************************
* for testing when two Windows adapters have the same name. Sometimes
* the \Device\NPF_ string is prepended, sometimes not.
***************************************************************************/
int
rawsock_is_adapter_names_equal(const char *lhs, const char *rhs)
{
if (memcmp(lhs, "\\Device\\NPF_", 12) == 0)
lhs += 12;
if (memcmp(rhs, "\\Device\\NPF_", 12) == 0)
rhs += 12;
return strcmp(lhs, rhs) == 0;
}
/***************************************************************************
* Runs some tests when the "--debug if" option is given on the
* command-line. This is useful to figure out why the interface you
* are accessing doesn't work.
***************************************************************************/
int
rawsock_selftest_if(const char *ifname)
{
int err;
ipv4address_t ipv4 = 0;
ipv6address_t ipv6;
ipv4address_t router_ipv4 = 0;
macaddress_t source_mac = {{0,0,0,0,0,0}};
struct Adapter *adapter;
char ifname2[246];
ipaddress_formatted_t fmt;
/*
* Get the interface
*/
if (ifname == NULL || ifname[0] == 0) {
err = rawsock_get_default_interface(ifname2, sizeof(ifname2));
if (err) {
printf("[-] if = not found (err=%d)\n", err);
return -1;
}
ifname = ifname2;
}
printf("[+] if = %s\n", ifname);
/*
* Initialize the adapter.
*/
adapter = rawsock_init_adapter(ifname, 0, 0, 0, 0, 0, 0, 0);
if (adapter == 0) {
printf("[-] pcap = failed\n");
return -1;
} else {
printf("[+] pcap = opened\n");
}
/* IPv4 address */
ipv4 = rawsock_get_adapter_ip(ifname);
if (ipv4 == 0) {
printf("[-] source-ipv4 = not found (err)\n");
} else {
fmt = ipv4address_fmt(ipv4);
printf("[+] source-ipv4 = %s\n", fmt.string);
}
/* IPv6 address */
ipv6 = rawsock_get_adapter_ipv6(ifname);
if (ipv6address_is_zero(ipv6)) {
printf("[-] source-ipv6 = not found\n");
} else {
fmt = ipv6address_fmt(ipv6);
printf("[+] source-ipv6 = [%s]\n", fmt.string);
}
/* MAC address */
err = rawsock_get_adapter_mac(ifname, source_mac.addr);
if (err) {
printf("[-] source-mac = not found (err=%d)\n", err);
} else {
fmt = macaddress_fmt(source_mac);
printf("[+] source-mac = %s\n", fmt.string);
}
switch (adapter->link_type) {
case 0:
printf("[+] router-ip = implicit\n");
printf("[+] router-mac = implicit\n");
break;
default:
/* IPv4 router IP address */
err = rawsock_get_default_gateway(ifname, &router_ipv4);
if (err) {
fprintf(stderr, "[-] router-ip = not found(err=%d)\n", err);
} else {
fmt = ipv4address_fmt(router_ipv4);
printf("[+] router-ip = %s\n", fmt.string);
}
/* IPv4 router MAC address */
{
macaddress_t router_mac = {{0,0,0,0,0,0}};
stack_arp_resolve(
adapter,
ipv4,
source_mac,
router_ipv4,
&router_mac);
if (macaddress_is_zero(router_mac)) {
printf("[-] router-mac-ipv4 = not found\n");
} else {
fmt = macaddress_fmt(router_mac);
printf("[+] router-mac-ipv4 = %s\n", fmt.string);
}
}
/*
* IPv6 router MAC address.
* If it's not configured, then we need to send a (synchronous) query
* to the network in order to discover the location of routers on
* the local network
*/
if (!ipv6address_is_zero(ipv6)) {
macaddress_t router_mac = {{0,0,0,0,0,0}};
stack_ndpv6_resolve(
adapter,
ipv6,
source_mac,
&router_mac);
if (macaddress_is_zero(router_mac)) {
printf("[-] router-mac-ipv6 = not found\n");
} else {
fmt = macaddress_fmt(router_mac);
printf("[+] router-mac-ipv6 = %s\n", fmt.string);
}
}
}
rawsock_close_adapter(adapter);
return 0;
}
/***************************************************************************
***************************************************************************/
int
rawsock_selftest()
{
return 0;
}