diff options
author | Martin Willi <martin@revosec.ch> | 2010-03-19 16:56:21 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2010-03-25 14:39:32 +0100 |
commit | f8e99e012ad8094b942a42d0eee2b4a2542ca4a3 (patch) | |
tree | 0c95929b0dfe71a2ff10b905159403c33d7efc5d /src | |
parent | dc70a5bb0bb9e9291b6f593a56d8240cf63c542b (diff) | |
download | strongswan-f8e99e012ad8094b942a42d0eee2b4a2542ca4a3.tar.bz2 strongswan-f8e99e012ad8094b942a42d0eee2b4a2542ca4a3.tar.xz |
Implemented ARP sniffing and spoofing functionality
Diffstat (limited to 'src')
-rw-r--r-- | src/libcharon/plugins/farp/Makefile.am | 2 | ||||
-rw-r--r-- | src/libcharon/plugins/farp/farp_plugin.c | 13 | ||||
-rw-r--r-- | src/libcharon/plugins/farp/farp_spoofer.c | 198 | ||||
-rw-r--r-- | src/libcharon/plugins/farp/farp_spoofer.h | 47 |
4 files changed, 259 insertions, 1 deletions
diff --git a/src/libcharon/plugins/farp/Makefile.am b/src/libcharon/plugins/farp/Makefile.am index 632218918..6da64509f 100644 --- a/src/libcharon/plugins/farp/Makefile.am +++ b/src/libcharon/plugins/farp/Makefile.am @@ -10,6 +10,6 @@ plugin_LTLIBRARIES = libstrongswan-farp.la endif 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 diff --git a/src/libcharon/plugins/farp/farp_plugin.c b/src/libcharon/plugins/farp/farp_plugin.c index 82f1fb2aa..01c2a39c8 100644 --- a/src/libcharon/plugins/farp/farp_plugin.c +++ b/src/libcharon/plugins/farp/farp_plugin.c @@ -16,6 +16,7 @@ #include "farp_plugin.h" #include "farp_listener.h" +#include "farp_spoofer.h" #include <daemon.h> @@ -35,11 +36,17 @@ struct private_farp_plugin_t { * Listener registering active virtual IPs */ farp_listener_t *listener; + + /** + * Spoofer listening and spoofing ARP messages + */ + farp_spoofer_t *spoofer; }; METHOD(plugin_t, destroy, void, private_farp_plugin_t *this) { + DESTROY_IF(this->spoofer); charon->bus->remove_listener(charon->bus, &this->listener->listener); this->listener->destroy(this->listener); free(this); @@ -59,6 +66,12 @@ plugin_t *farp_plugin_create() 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; } diff --git a/src/libcharon/plugins/farp/farp_spoofer.c b/src/libcharon/plugins/farp/farp_spoofer.c new file mode 100644 index 000000000..29e64e32d --- /dev/null +++ b/src/libcharon/plugins/farp/farp_spoofer.c @@ -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; +} + diff --git a/src/libcharon/plugins/farp/farp_spoofer.h b/src/libcharon/plugins/farp/farp_spoofer.h new file mode 100644 index 000000000..c91fb3b96 --- /dev/null +++ b/src/libcharon/plugins/farp/farp_spoofer.h @@ -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_ @}*/ |