The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
proto_arp_ethernet.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: d19a6ce65eb9da19519d6a6726cddd93103b35a7 $
19 * @file proto_arp_ethernet.c
20 * @brief ARP handler for ethernet
21 *
22 * @copyright 2016 The FreeRADIUS server project.
23 * @copyright 2016 Alan DeKok (aland@deployingradius.com)
24 */
25#include <netdb.h>
26#include <freeradius-devel/server/protocol.h>
27#include <freeradius-devel/server/util.h>
28#include <freeradius-devel/util/trie.h>
29#include <freeradius-devel/io/application.h>
30#include <freeradius-devel/io/listen.h>
31#include <freeradius-devel/io/schedule.h>
32
33#include "proto_arp.h"
34
36
37typedef struct {
38 char const *name; //!< socket name
39 fr_pcap_t *pcap; //!< PCAP handler
41
42typedef struct {
43 CONF_SECTION *cs; //!< our configuration
44 char const *interface; //!< Interface to bind to.
45 char const *filter; //!< Additional PCAP filter
47
48
49/** How to parse an ARP listen section
50 *
51 */
54 interface), .dflt = "eth0" },
55
56 { FR_CONF_OFFSET("filter", proto_arp_ethernet_t, filter) },
57
59};
60
61static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
62{
64 int ret;
65 uint8_t const *data;
66 struct pcap_pkthdr *header;
67 uint8_t const *p, *end;
68 ssize_t len;
69
70 *leftover = 0; /* always for message oriented protocols */
71
72 ret = pcap_next_ex(thread->pcap->handle, &header, &data);
73 if (ret == 0) return 0;
74 if (ret < 0) {
75 DEBUG("Failed getting next PCAP packet");
76 return 0;
77 }
78
79 p = data;
80 end = data + header->caplen;
81
82 len = fr_pcap_link_layer_offset(data, header->caplen, thread->pcap->link_layer);
83 if (len < 0) {
84 DEBUG("Failed determining link layer header offset");
85 return 0;
86 }
87 p += len;
88
89 if ((end - p) < FR_ARP_PACKET_SIZE) {
90 DEBUG("Packet is too small (%d) to be ARP", (int) (end - p));
91 return 0;
92 }
93
94 /*
95 * Shouldn't happen.
96 */
97 if (buffer_len < FR_ARP_PACKET_SIZE) {
98 return 0;
99 }
100
101 memcpy(buffer, p, FR_ARP_PACKET_SIZE);
102
103 // @todo - talloc packet_ctx which is the ethernet header, so we know what kind of VLAN, etc. to encode?
104
105 *recv_time_p = fr_time();
106 return FR_ARP_PACKET_SIZE;
107}
108
109
110static ssize_t mod_write(fr_listen_t *li, UNUSED void *packet_ctx, UNUSED fr_time_t request_time,
111 uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
112{
113 proto_arp_ethernet_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_arp_ethernet_thread_t);
114
115 int ret;
116 uint8_t arp_packet[64] = { 0 };
117 ethernet_header_t *eth_hdr;
118 fr_arp_packet_t *arp;
119 /* Pointer to the current position in the frame */
120 uint8_t *end = arp_packet;
121
122 /*
123 * Don't write anything.
124 */
125 if (buffer_len == 1) return buffer_len;
126
127 /* fill in Ethernet layer (L2) */
128 eth_hdr = (ethernet_header_t *)arp_packet;
129 eth_hdr->ether_type = htons(ETH_TYPE_ARP);
130 end += ETHER_ADDR_LEN + ETHER_ADDR_LEN + sizeof(eth_hdr->ether_type);
131
132 /*
133 * Just copy what FreeRADIUS has encoded for us.
134 */
135 arp = (fr_arp_packet_t *) end;
136 memcpy(arp, buffer, buffer_len);
137
138 /*
139 * Set our MAC address as the ethernet source.
140 *
141 * Set the destination MAC as the target address from
142 * ARP.
143 */
144 memcpy(eth_hdr->src_addr, thread->pcap->ether_addr, ETHER_ADDR_LEN);
145 memcpy(eth_hdr->dst_addr, arp->tha, ETHER_ADDR_LEN);
146
147 /*
148 * If we fail injecting the reply, just ignore it.
149 * Returning <0 means "close the socket", which is likely
150 * not what we want.
151 */
152 ret = pcap_inject(thread->pcap->handle, arp_packet, (end - arp_packet + buffer_len));
153 if (ret < 0) {
154 fr_strerror_printf("Error sending packet with pcap: %d, %s", ret, pcap_geterr(thread->pcap->handle));
155 return 0;
156 }
157
158 /*
159 * @todo - mirror src/protocols/dhcpv4/pcap.c for ARP send / receive.
160 * We will need that functionality for rlm_arp, too.
161 */
162
163 return FR_ARP_PACKET_SIZE;
164}
165
166/** Open a pcap file for ARP
167 *
168 */
169static int mod_open(fr_listen_t *li)
170{
172 proto_arp_ethernet_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_arp_ethernet_thread_t);
173
174 char const *filter;
175 char *our_filter = NULL;
176 int rcode;
177
178 thread->pcap = fr_pcap_init(thread, inst->interface, PCAP_INTERFACE_IN);
179 if (!thread->pcap) {
180 cf_log_err(li->cs, "Failed initializing pcap - %s", fr_strerror());
181 return -1;
182 }
183
184 rad_suid_up();
185 rcode = fr_pcap_open(thread->pcap);
187 if (rcode < 0) {
188 cf_log_err(li->cs, "Failed opening interface %s - %s", inst->interface, fr_strerror());
189 return -1;
190 }
191
192 /*
193 * Ensure that we only get ARP, and an optional additional filter.
194 */
195 if (!inst->filter) {
196 filter = "arp";
197 } else {
198 MEM(filter = our_filter = talloc_asprintf(li, "arp and %s", inst->filter));
199 }
200
201 if (fr_pcap_apply_filter(thread->pcap, filter) < 0) {
202 cf_log_err(li->cs, "Failed applying pcap filter '%s' - %s", filter, fr_strerror());
203 talloc_free(our_filter);
204 return -1;
205 }
206 talloc_free(our_filter);
207
208 li->fd = thread->pcap->fd;
209
210 fr_assert(cf_parent(inst->cs) != NULL); /* listen { ... } */
211
212 thread->name = talloc_asprintf(thread, "arp on interface %s", inst->interface);
213 return 0;
214}
215
216static char const *mod_name(fr_listen_t *li)
217{
218 proto_arp_ethernet_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_arp_ethernet_thread_t);
219
220 return thread->name;
221}
222
223
224static int mod_instantiate(module_inst_ctx_t const *mctx)
225{
226 proto_arp_ethernet_t *inst = talloc_get_type_abort(mctx->mi->data, proto_arp_ethernet_t);
227
228 inst->cs = mctx->mi->conf;
229
230 return 0;
231}
232
234 .common = {
235 .magic = MODULE_MAGIC_INIT,
236 .name = "arp_ethernet",
238 .inst_size = sizeof(proto_arp_ethernet_t),
239 .thread_inst_size = sizeof(proto_arp_ethernet_thread_t),
240 .bootstrap = mod_instantiate
241 },
242 .default_message_size = FR_ARP_PACKET_SIZE,
243
244 .open = mod_open,
245 .read = mod_read,
246 .write = mod_write,
247 .get_name = mod_name,
248};
static int const char char buffer[256]
Definition acutest.h:578
module_t common
Common fields to all loadable modules.
Definition app_io.h:34
Public structure describing an I/O path for a protocol.
Definition app_io.h:33
#define ETH_TYPE_ARP
Definition arp.h:38
uint8_t tha[ETHER_ADDR_LEN]
Target hardware address.
Definition arp.h:63
#define FR_ARP_PACKET_SIZE
Definition arp.h:37
#define UNUSED
Definition build.h:317
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:660
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:283
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:271
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:450
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:597
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:288
#define cf_parent(_cf)
Definition cf_util.h:101
#define MEM(x)
Definition debug.h:36
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
uint8_t dst_addr[ETHER_ADDR_LEN]
Definition ethernet.h:79
uint16_t ether_type
Definition ethernet.h:81
uint8_t src_addr[ETHER_ADDR_LEN]
Definition ethernet.h:80
Structure of a DEC/Intel/Xerox or 802.3 Ethernet header.
Definition ethernet.h:78
talloc_free(hp)
CONF_SECTION * cs
of this listener
Definition listen.h:41
void const * app_io_instance
I/O path configuration context.
Definition listen.h:33
void * thread_instance
thread / socket context
Definition listen.h:34
int fd
file descriptor for this socket - set by open
Definition listen.h:28
void rad_suid_up(void)
Definition util.c:796
void rad_suid_down(void)
Definition util.c:800
long int ssize_t
unsigned char uint8_t
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
#define ETHER_ADDR_LEN
Definition net.h:64
char const * name
socket name
static ssize_t mod_write(fr_listen_t *li, UNUSED void *packet_ctx, UNUSED fr_time_t request_time, uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
char const * filter
Additional PCAP filter.
CONF_SECTION * cs
our configuration
static conf_parser_t const arp_listen_config[]
How to parse an ARP listen section.
static int mod_open(fr_listen_t *li)
Open a pcap file for ARP.
fr_pcap_t * pcap
PCAP handler.
char const * interface
Interface to bind to.
static ssize_t mod_read(fr_listen_t *li, UNUSED void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
fr_app_io_t proto_arp_ethernet
static char const * mod_name(fr_listen_t *li)
static int mod_instantiate(module_inst_ctx_t const *mctx)
#define fr_assert(_expr)
Definition rad_assert.h:38
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:349
void * data
Module's instance data.
Definition module.h:291
conf_parser_t const * config
How to convert a CONF_SECTION to a module instance.
Definition module.h:206
eap_aka_sim_process_conf_t * inst
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
#define talloc_get_type_abort_const
Definition talloc.h:245
"server local" time.
Definition time.h:69
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_slen_t data
Definition value.h:1334