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: 63b09eddaf43fa36efcf0f75215eaffdc43a7312 $
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/util/trie.h>
28#include <freeradius-devel/io/application.h>
29#include <freeradius-devel/io/listen.h>
30#include <freeradius-devel/io/schedule.h>
31
32#include "proto_arp.h"
33
35
36typedef struct {
37 char const *name; //!< socket name
38 fr_pcap_t *pcap; //!< PCAP handler
40
41typedef struct {
42 CONF_SECTION *cs; //!< our configuration
43 char const *interface; //!< Interface to bind to.
44 char const *filter; //!< Additional PCAP filter
46
47
48/** How to parse an ARP listen section
49 *
50 */
53 interface), .dflt = "eth0" },
54
55 { FR_CONF_OFFSET("filter", proto_arp_ethernet_t, filter) },
56
58};
59
60static 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)
61{
63 int ret;
64 uint8_t const *data;
65 struct pcap_pkthdr *header;
66 uint8_t const *p, *end;
67 ssize_t len;
68
69 *leftover = 0; /* always for message oriented protocols */
70
71 ret = pcap_next_ex(thread->pcap->handle, &header, &data);
72 if (ret == 0) return 0;
73 if (ret < 0) {
74 DEBUG("Failed getting next PCAP packet");
75 return 0;
76 }
77
78 p = data;
79 end = data + header->caplen;
80
81 len = fr_pcap_link_layer_offset(data, header->caplen, thread->pcap->link_layer);
82 if (len < 0) {
83 DEBUG("Failed determining link layer header offset");
84 return 0;
85 }
86 p += len;
87
88 if ((end - p) < FR_ARP_PACKET_SIZE) {
89 DEBUG("Packet is too small (%d) to be ARP", (int) (end - p));
90 return 0;
91 }
92
93 /*
94 * Shouldn't happen.
95 */
96 if (buffer_len < FR_ARP_PACKET_SIZE) {
97 return 0;
98 }
99
100 memcpy(buffer, p, FR_ARP_PACKET_SIZE);
101
102 // @todo - talloc packet_ctx which is the ethernet header, so we know what kind of VLAN, etc. to encode?
103
104 *recv_time_p = fr_time();
105 return FR_ARP_PACKET_SIZE;
106}
107
108
109static ssize_t mod_write(fr_listen_t *li, UNUSED void *packet_ctx, UNUSED fr_time_t request_time,
110 uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
111{
112 proto_arp_ethernet_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_arp_ethernet_thread_t);
113
114 int ret;
115 uint8_t arp_packet[64] = { 0 };
116 ethernet_header_t *eth_hdr;
117 fr_arp_packet_t *arp;
118 /* Pointer to the current position in the frame */
119 uint8_t *end = arp_packet;
120
121 /*
122 * Don't write anything.
123 */
124 if (buffer_len == 1) return buffer_len;
125
126 /* fill in Ethernet layer (L2) */
127 eth_hdr = (ethernet_header_t *)arp_packet;
128 eth_hdr->ether_type = htons(ETH_TYPE_ARP);
129 end += ETHER_ADDR_LEN + ETHER_ADDR_LEN + sizeof(eth_hdr->ether_type);
130
131 /*
132 * Just copy what FreeRADIUS has encoded for us.
133 */
134 arp = (fr_arp_packet_t *) end;
135 memcpy(arp, buffer, buffer_len);
136
137 /*
138 * Set our MAC address as the ethernet source.
139 *
140 * Set the destination MAC as the target address from
141 * ARP.
142 */
143 memcpy(eth_hdr->src_addr, thread->pcap->ether_addr, ETHER_ADDR_LEN);
144 memcpy(eth_hdr->dst_addr, arp->tha, ETHER_ADDR_LEN);
145
146 /*
147 * If we fail injecting the reply, just ignore it.
148 * Returning <0 means "close the socket", which is likely
149 * not what we want.
150 */
151 ret = pcap_inject(thread->pcap->handle, arp_packet, (end - arp_packet + buffer_len));
152 if (ret < 0) {
153 fr_strerror_printf("Error sending packet with pcap: %d, %s", ret, pcap_geterr(thread->pcap->handle));
154 return 0;
155 }
156
157 /*
158 * @todo - mirror src/protocols/dhcpv4/pcap.c for ARP send / receive.
159 * We will need that functionality for rlm_arp, too.
160 */
161
162 return FR_ARP_PACKET_SIZE;
163}
164
165/** Open a pcap file for ARP
166 *
167 */
168static int mod_open(fr_listen_t *li)
169{
171 proto_arp_ethernet_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_arp_ethernet_thread_t);
172
173 char const *filter;
174 char *our_filter = NULL;
175
176 thread->pcap = fr_pcap_init(thread, inst->interface, PCAP_INTERFACE_IN);
177 if (!thread->pcap) {
178 PERROR("Failed initializing pcap handle.");
179 return -1;
180 }
181
182 if (fr_pcap_open(thread->pcap) < 0) {
183 PERROR("Failed opening interface %s", inst->interface);
184 return -1;
185 }
186
187 /*
188 * Ensure that we only get ARP, and an optional additional filter.
189 */
190 if (!inst->filter) {
191 filter = "arp";
192 } else {
193 MEM(filter = our_filter = talloc_asprintf(li, "arp and %s", inst->filter));
194 }
195
196 if (fr_pcap_apply_filter(thread->pcap, filter) < 0) {
197 PERROR("Failed applying pcap filter '%s'", filter);
198 talloc_free(our_filter);
199 return -1;
200 }
201 talloc_free(our_filter);
202
203 li->fd = thread->pcap->fd;
204
205 fr_assert(cf_parent(inst->cs) != NULL); /* listen { ... } */
206
207 thread->name = talloc_asprintf(thread, "arp on interface %s", inst->interface);
208 return 0;
209}
210
211static char const *mod_name(fr_listen_t *li)
212{
213 proto_arp_ethernet_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_arp_ethernet_thread_t);
214
215 return thread->name;
216}
217
218
219static int mod_instantiate(module_inst_ctx_t const *mctx)
220{
221 proto_arp_ethernet_t *inst = talloc_get_type_abort(mctx->mi->data, proto_arp_ethernet_t);
222
223 inst->cs = mctx->mi->conf;
224
225 return 0;
226}
227
229 .common = {
230 .magic = MODULE_MAGIC_INIT,
231 .name = "arp_ethernet",
233 .inst_size = sizeof(proto_arp_ethernet_t),
234 .thread_inst_size = sizeof(proto_arp_ethernet_thread_t),
235 .bootstrap = mod_instantiate
236 },
237 .default_message_size = FR_ARP_PACKET_SIZE,
238
239 .open = mod_open,
240 .read = mod_read,
241 .write = mod_write,
242 .get_name = mod_name,
243};
static int const char char buffer[256]
Definition acutest.h:576
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:59
#define FR_ARP_PACKET_SIZE
Definition arp.h:37
#define UNUSED
Definition build.h:315
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#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:268
#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:256
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:433
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#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
void const * app_io_instance
I/O path configuration context.
Definition listen.h:32
void * thread_instance
thread / socket context
Definition listen.h:33
int fd
file descriptor for this socket - set by open
Definition listen.h:28
#define PERROR(_fmt,...)
Definition log.h:228
talloc_free(reap)
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:329
void * data
Module's instance data.
Definition module.h:271
conf_parser_t const * config
How to convert a CONF_SECTION to a module instance.
Definition module.h:198
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:282
"server local" time.
Definition time.h:69
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_slen_t data
Definition value.h:1265