Implemented ARP sniffing and spoofing functionality
This commit is contained in:
@@ -10,6 +10,6 @@ plugin_LTLIBRARIES = libstrongswan-farp.la
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
libstrongswan_farp_la_SOURCES = farp_plugin.h farp_plugin.c \
|
libstrongswan_farp_la_SOURCES = farp_plugin.h farp_plugin.c \
|
||||||
farp_listener.h farp_listener.c
|
farp_listener.h farp_listener.c farp_spoofer.h farp_spoofer.c
|
||||||
|
|
||||||
libstrongswan_farp_la_LDFLAGS = -module -avoid-version
|
libstrongswan_farp_la_LDFLAGS = -module -avoid-version
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "farp_plugin.h"
|
#include "farp_plugin.h"
|
||||||
|
|
||||||
#include "farp_listener.h"
|
#include "farp_listener.h"
|
||||||
|
#include "farp_spoofer.h"
|
||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
|
|
||||||
@@ -35,11 +36,17 @@ struct private_farp_plugin_t {
|
|||||||
* Listener registering active virtual IPs
|
* Listener registering active virtual IPs
|
||||||
*/
|
*/
|
||||||
farp_listener_t *listener;
|
farp_listener_t *listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spoofer listening and spoofing ARP messages
|
||||||
|
*/
|
||||||
|
farp_spoofer_t *spoofer;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(plugin_t, destroy, void,
|
METHOD(plugin_t, destroy, void,
|
||||||
private_farp_plugin_t *this)
|
private_farp_plugin_t *this)
|
||||||
{
|
{
|
||||||
|
DESTROY_IF(this->spoofer);
|
||||||
charon->bus->remove_listener(charon->bus, &this->listener->listener);
|
charon->bus->remove_listener(charon->bus, &this->listener->listener);
|
||||||
this->listener->destroy(this->listener);
|
this->listener->destroy(this->listener);
|
||||||
free(this);
|
free(this);
|
||||||
@@ -59,6 +66,12 @@ plugin_t *farp_plugin_create()
|
|||||||
|
|
||||||
charon->bus->add_listener(charon->bus, &this->listener->listener);
|
charon->bus->add_listener(charon->bus, &this->listener->listener);
|
||||||
|
|
||||||
|
this->spoofer = farp_spoofer_create(this->listener);
|
||||||
|
if (!this->spoofer)
|
||||||
|
{
|
||||||
|
destroy(this);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return &this->public.plugin;
|
return &this->public.plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Martin Willi
|
||||||
|
* Copyright (C) 2010 revosec AG
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "farp_spoofer.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/if_arp.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/filter.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <daemon.h>
|
||||||
|
#include <threading/thread.h>
|
||||||
|
#include <processing/jobs/callback_job.h>
|
||||||
|
|
||||||
|
typedef struct private_farp_spoofer_t private_farp_spoofer_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data of an farp_spoofer_t object.
|
||||||
|
*/
|
||||||
|
struct private_farp_spoofer_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public farp_spoofer_t interface.
|
||||||
|
*/
|
||||||
|
farp_spoofer_t public;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that knows active addresses
|
||||||
|
*/
|
||||||
|
farp_listener_t *listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback job to read ARP requests
|
||||||
|
*/
|
||||||
|
callback_job_t *job;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RAW socket for ARP requests
|
||||||
|
*/
|
||||||
|
int skt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP over Ethernet ARP message
|
||||||
|
*/
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
u_int16_t hardware_type;
|
||||||
|
u_int16_t protocol_type;
|
||||||
|
u_int8_t hardware_size;
|
||||||
|
u_int8_t protocol_size;
|
||||||
|
u_int16_t opcode;
|
||||||
|
u_int8_t sender_mac[6];
|
||||||
|
u_int8_t sender_ip[4];
|
||||||
|
u_int8_t target_mac[6];
|
||||||
|
u_int8_t target_ip[4];
|
||||||
|
} arp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send faked ARP response
|
||||||
|
*/
|
||||||
|
static void send_arp(private_farp_spoofer_t *this,
|
||||||
|
arp_t *arp, struct sockaddr_ll *addr)
|
||||||
|
{
|
||||||
|
struct ifreq req;
|
||||||
|
char tmp[4];
|
||||||
|
|
||||||
|
req.ifr_ifindex = addr->sll_ifindex;
|
||||||
|
if (ioctl(this->skt, SIOCGIFNAME, &req) == 0 &&
|
||||||
|
ioctl(this->skt, SIOCGIFHWADDR, &req) == 0 &&
|
||||||
|
req.ifr_hwaddr.sa_family == ARPHRD_ETHER)
|
||||||
|
{
|
||||||
|
memcpy(arp->target_mac, arp->sender_mac, 6);
|
||||||
|
memcpy(arp->sender_mac, req.ifr_hwaddr.sa_data, 6);
|
||||||
|
|
||||||
|
memcpy(tmp, arp->sender_ip, 4);
|
||||||
|
memcpy(arp->sender_ip, arp->target_ip, 4);
|
||||||
|
memcpy(arp->target_ip, tmp, 4);
|
||||||
|
|
||||||
|
arp->opcode = htons(ARPOP_REPLY);
|
||||||
|
|
||||||
|
sendto(this->skt, arp, sizeof(*arp), 0,
|
||||||
|
(struct sockaddr*)addr, sizeof(*addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ARP request receiving
|
||||||
|
*/
|
||||||
|
static job_requeue_t receive_arp(private_farp_spoofer_t *this)
|
||||||
|
{
|
||||||
|
struct sockaddr_ll addr;
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
arp_t arp;
|
||||||
|
int oldstate;
|
||||||
|
ssize_t len;
|
||||||
|
host_t *ip;
|
||||||
|
|
||||||
|
oldstate = thread_cancelability(TRUE);
|
||||||
|
len = recvfrom(this->skt, &arp, sizeof(arp), 0,
|
||||||
|
(struct sockaddr*)&addr, &addr_len);
|
||||||
|
thread_cancelability(oldstate);
|
||||||
|
|
||||||
|
if (len == sizeof(arp))
|
||||||
|
{
|
||||||
|
ip = host_create_from_chunk(AF_INET,
|
||||||
|
chunk_create((char*)&arp.target_ip, 4), 0);
|
||||||
|
if (ip)
|
||||||
|
{
|
||||||
|
if (this->listener->is_active(this->listener, ip))
|
||||||
|
{
|
||||||
|
send_arp(this, &arp, &addr);
|
||||||
|
}
|
||||||
|
ip->destroy(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JOB_REQUEUE_DIRECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(farp_spoofer_t, destroy, void,
|
||||||
|
private_farp_spoofer_t *this)
|
||||||
|
{
|
||||||
|
this->job->cancel(this->job);
|
||||||
|
close(this->skt);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See header
|
||||||
|
*/
|
||||||
|
farp_spoofer_t *farp_spoofer_create(farp_listener_t *listener)
|
||||||
|
{
|
||||||
|
private_farp_spoofer_t *this;
|
||||||
|
struct sock_filter arp_request_filter_code[] = {
|
||||||
|
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, offsetof(arp_t, protocol_type)),
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_P_IP, 0, 9),
|
||||||
|
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, offsetof(arp_t, hardware_size)),
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 6, 0, 7),
|
||||||
|
BPF_STMT(BPF_LD+BPF_B+BPF_ABS, offsetof(arp_t, protocol_size)),
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 4, 0, 4),
|
||||||
|
BPF_STMT(BPF_LD+BPF_H+BPF_ABS, offsetof(arp_t, opcode)),
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REQUEST, 0, 3),
|
||||||
|
BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
|
||||||
|
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 28, 0, 1),
|
||||||
|
BPF_STMT(BPF_RET+BPF_A, 0),
|
||||||
|
BPF_STMT(BPF_RET+BPF_K, 0),
|
||||||
|
};
|
||||||
|
struct sock_fprog arp_request_filter = {
|
||||||
|
sizeof(arp_request_filter_code) / sizeof(struct sock_filter),
|
||||||
|
arp_request_filter_code,
|
||||||
|
};
|
||||||
|
|
||||||
|
INIT(this,
|
||||||
|
.public = {
|
||||||
|
.destroy = _destroy,
|
||||||
|
},
|
||||||
|
.listener = listener,
|
||||||
|
);
|
||||||
|
|
||||||
|
this->skt = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
|
||||||
|
if (this->skt == -1)
|
||||||
|
{
|
||||||
|
DBG1(DBG_NET, "opening ARP packet socket failed: %s", strerror(errno));
|
||||||
|
free(this);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(this->skt, SOL_SOCKET, SO_ATTACH_FILTER,
|
||||||
|
&arp_request_filter, sizeof(arp_request_filter)) < 0)
|
||||||
|
{
|
||||||
|
DBG1(DBG_NET, "installing ARP packet filter failed: %s", strerror(errno));
|
||||||
|
close(this->skt);
|
||||||
|
free(this);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->job = callback_job_create((callback_job_cb_t)receive_arp,
|
||||||
|
this, NULL, NULL);
|
||||||
|
charon->processor->queue_job(charon->processor, (job_t*)this->job);
|
||||||
|
|
||||||
|
return &this->public;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Martin Willi
|
||||||
|
* Copyright (C) 2010 revosec AG
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup farp_spoofer farp_spoofer
|
||||||
|
* @{ @ingroup farp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FARP_SPOOFER_H_
|
||||||
|
#define FARP_SPOOFER_H_
|
||||||
|
|
||||||
|
#include "farp_listener.h"
|
||||||
|
|
||||||
|
typedef struct farp_spoofer_t farp_spoofer_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to ARP requests and spoof responses, if required.
|
||||||
|
*/
|
||||||
|
struct farp_spoofer_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a farp_spoofer_t.
|
||||||
|
*/
|
||||||
|
void (*destroy)(farp_spoofer_t *this);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a farp_spoofer instance.
|
||||||
|
*
|
||||||
|
* @param listener listener to check for addresses to spoof
|
||||||
|
* @return spoofer instance
|
||||||
|
*/
|
||||||
|
farp_spoofer_t *farp_spoofer_create(farp_listener_t *listener);
|
||||||
|
|
||||||
|
#endif /** FARP_SPOOFER_H_ @}*/
|
||||||
Reference in New Issue
Block a user