Use CRITICAL job priority class for long running dispatcher jobs
[strongswan.git] / src / libcharon / plugins / farp / farp_spoofer.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "farp_spoofer.h"
17
18 #include <errno.h>
19 #include <unistd.h>
20 #include <sys/socket.h>
21 #include <linux/if_arp.h>
22 #include <linux/if_ether.h>
23 #include <linux/filter.h>
24 #include <sys/ioctl.h>
25
26 #include <daemon.h>
27 #include <threading/thread.h>
28 #include <processing/jobs/callback_job.h>
29
30 typedef struct private_farp_spoofer_t private_farp_spoofer_t;
31
32 /**
33 * Private data of an farp_spoofer_t object.
34 */
35 struct private_farp_spoofer_t {
36
37 /**
38 * Public farp_spoofer_t interface.
39 */
40 farp_spoofer_t public;
41
42 /**
43 * Listener that knows active addresses
44 */
45 farp_listener_t *listener;
46
47 /**
48 * Callback job to read ARP requests
49 */
50 callback_job_t *job;
51
52 /**
53 * RAW socket for ARP requests
54 */
55 int skt;
56 };
57
58 /**
59 * IP over Ethernet ARP message
60 */
61 typedef struct __attribute__((packed)) {
62 u_int16_t hardware_type;
63 u_int16_t protocol_type;
64 u_int8_t hardware_size;
65 u_int8_t protocol_size;
66 u_int16_t opcode;
67 u_int8_t sender_mac[6];
68 u_int8_t sender_ip[4];
69 u_int8_t target_mac[6];
70 u_int8_t target_ip[4];
71 } arp_t;
72
73 /**
74 * Send faked ARP response
75 */
76 static void send_arp(private_farp_spoofer_t *this,
77 arp_t *arp, struct sockaddr_ll *addr)
78 {
79 struct ifreq req;
80 char tmp[4];
81
82 req.ifr_ifindex = addr->sll_ifindex;
83 if (ioctl(this->skt, SIOCGIFNAME, &req) == 0 &&
84 ioctl(this->skt, SIOCGIFHWADDR, &req) == 0 &&
85 req.ifr_hwaddr.sa_family == ARPHRD_ETHER)
86 {
87 memcpy(arp->target_mac, arp->sender_mac, 6);
88 memcpy(arp->sender_mac, req.ifr_hwaddr.sa_data, 6);
89
90 memcpy(tmp, arp->sender_ip, 4);
91 memcpy(arp->sender_ip, arp->target_ip, 4);
92 memcpy(arp->target_ip, tmp, 4);
93
94 arp->opcode = htons(ARPOP_REPLY);
95
96 sendto(this->skt, arp, sizeof(*arp), 0,
97 (struct sockaddr*)addr, sizeof(*addr));
98 }
99 }
100
101 /**
102 * ARP request receiving
103 */
104 static job_requeue_t receive_arp(private_farp_spoofer_t *this)
105 {
106 struct sockaddr_ll addr;
107 socklen_t addr_len = sizeof(addr);
108 arp_t arp;
109 int oldstate;
110 ssize_t len;
111 host_t *ip;
112
113 oldstate = thread_cancelability(TRUE);
114 len = recvfrom(this->skt, &arp, sizeof(arp), 0,
115 (struct sockaddr*)&addr, &addr_len);
116 thread_cancelability(oldstate);
117
118 if (len == sizeof(arp))
119 {
120 ip = host_create_from_chunk(AF_INET,
121 chunk_create((char*)&arp.target_ip, 4), 0);
122 if (ip)
123 {
124 if (this->listener->is_active(this->listener, ip))
125 {
126 send_arp(this, &arp, &addr);
127 }
128 ip->destroy(ip);
129 }
130 }
131
132 return JOB_REQUEUE_DIRECT;
133 }
134
135 METHOD(farp_spoofer_t, destroy, void,
136 private_farp_spoofer_t *this)
137 {
138 this->job->cancel(this->job);
139 close(this->skt);
140 free(this);
141 }
142
143 /**
144 * See header
145 */
146 farp_spoofer_t *farp_spoofer_create(farp_listener_t *listener)
147 {
148 private_farp_spoofer_t *this;
149 struct sock_filter arp_request_filter_code[] = {
150 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, offsetof(arp_t, protocol_type)),
151 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_P_IP, 0, 9),
152 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, offsetof(arp_t, hardware_size)),
153 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 6, 0, 7),
154 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, offsetof(arp_t, protocol_size)),
155 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 4, 0, 4),
156 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, offsetof(arp_t, opcode)),
157 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REQUEST, 0, 3),
158 BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
159 BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, sizeof(arp_t), 0, 1),
160 BPF_STMT(BPF_RET+BPF_K, sizeof(arp_t)),
161 BPF_STMT(BPF_RET+BPF_K, 0),
162 };
163 struct sock_fprog arp_request_filter = {
164 sizeof(arp_request_filter_code) / sizeof(struct sock_filter),
165 arp_request_filter_code,
166 };
167
168 INIT(this,
169 .public = {
170 .destroy = _destroy,
171 },
172 .listener = listener,
173 );
174
175 this->skt = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
176 if (this->skt == -1)
177 {
178 DBG1(DBG_NET, "opening ARP packet socket failed: %s", strerror(errno));
179 free(this);
180 return NULL;
181 }
182
183 if (setsockopt(this->skt, SOL_SOCKET, SO_ATTACH_FILTER,
184 &arp_request_filter, sizeof(arp_request_filter)) < 0)
185 {
186 DBG1(DBG_NET, "installing ARP packet filter failed: %s", strerror(errno));
187 close(this->skt);
188 free(this);
189 return NULL;
190 }
191
192 this->job = callback_job_create_with_prio((callback_job_cb_t)receive_arp,
193 this, NULL, NULL, JOB_PRIO_CRITICAL);
194 lib->processor->queue_job(lib->processor, (job_t*)this->job);
195
196 return &this->public;
197 }
198