26RCSID(
"$Id: e117e926279ba26426a55d52e293b23a72a8e86f $")
28#include <freeradius-devel/util/net.h>
29#include <freeradius-devel/util/struct.h>
30#include <freeradius-devel/util/syserror.h>
31#include <freeradius-devel/io/test_point.h>
34#ifdef HAVE_LINUX_IF_PACKET_H
35# include <linux/if_packet.h>
36# include <linux/if_ether.h>
39#include <net/if_arp.h>
44#include <netlink/netlink.h>
45#include <netlink/netlink_route.h>
46#include <netlink/netlink_snl.h>
47#include <netlink/netlink_snl_route.h>
49#include <sys/linker.h>
50#include <sys/module.h>
78 [3] =
"Reverse-Request",
79 [4] =
"Reverse-Reply",
81 [5] =
"DRARP-Request",
84 [8] =
"InARP-Request",
87 [11] =
"MARS-Request",
96 [20] =
"MARS-Grouplist-Request",
97 [21] =
"MARS-Grouplist-Reply",
98 [22] =
"MARS-Redirect-MAP",
120 struct sockaddr_in *sin;
128 memset(&req, 0,
sizeof(req));
129 sin = (
struct sockaddr_in *) &req.arp_pa;
130 sin->sin_family = AF_INET;
131 memcpy(&sin->sin_addr.s_addr, ipaddr, 4);
133 strlcpy(req.arp_dev, interface,
sizeof(req.arp_dev));
135 memcpy(&req.arp_ha.sa_data, macaddr, 6);
137 req.arp_flags = ATF_COM;
138 if (ioctl(fd, SIOCSARP, &req) < 0) {
159 struct sockaddr_in sin;
160 struct sockaddr_dl sdl;
161 struct snl_state state;
162 struct snl_writer nw;
163 struct nlmsghdr *msghdr;
165 struct snl_errmsg_data errmsg = {};
172 sin.sin_family = AF_INET;
173 memcpy(&sin.sin_addr.s_addr, ipaddr, 4);
175 sdl = (
struct sockaddr_dl){
176 .sdl_len =
sizeof(sdl),
182 if (!snl_init(&state, NETLINK_ROUTE)) {
183 if (modfind(
"netlink") == -1 && errno == ENOENT) {
184 if (kldload(
"netlink") == -1) {
192 if (!snl_init(&state, NETLINK_ROUTE))
goto open_error;
195 snl_init_writer(&state, &nw);
196 msghdr = snl_create_msg_request(&nw, RTM_NEWNEIGH);
197 msghdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
199 msg = snl_reserve_msg_object(&nw,
struct ndmsg);
206 msg->ndm_family = AF_INET;
207 msg->ndm_ifindex = ifindex;
208 msg->ndm_state = NUD_PERMANENT;
209 msg->ndm_flags = NTF_STICKY;
211 snl_add_msg_attr_ip(&nw, NDA_DST, (
struct sockaddr *)&sin);
212 snl_add_msg_attr(&nw, NDA_LLADDR, sdl.sdl_alen, LLADDR(&sdl));
214 if (!(msghdr = snl_finalize_msg(&nw)) || !snl_send_message(&state, msghdr)) {
219 snl_read_reply_code(&state, msghdr->nlmsg_seq, &errmsg);
220 if (errmsg.error != 0) {
221 fr_strerror_printf(
"Failed adding ARP table entry: %s (%s)", strerror(errmsg.error), errmsg.error_str);
269 if (slen <= 0)
return slen;
278 if ((arp->
htype[0] == 0) && (arp->
htype[1] == 0)) arp->
htype[1] = FR_HARDWARE_FORMAT_VALUE_ETHERNET;
279 if ((arp->
ptype[0] == 0) && (arp->
ptype[1] == 0)) arp->
ptype[0] = (FR_PROTOCOL_FORMAT_VALUE_IPV4 >> 8);
292#define COPY(_a, _b) do { \
293 if (memcmp(arp->_a, zeros, sizeof(arp->_a)) == 0) { \
294 memcpy(arp->_a, our_original->_b, sizeof(arp->_a)); \
322 if ((arp->
htype[0] != 0) || (arp->
htype[1] != 1)) {
327 if ((arp->
ptype[0] != 8) || (arp->
ptype[1] != 0)) {
332 if (arp->
hlen != 6) {
337 if (arp->
plen != 4) {
384 .default_type_size = 4,
385 .default_type_length = 0,
403 if (!test_ctx)
return -1;
uint8_t hlen
Length of hardware address.
uint8_t plen
Length of protocol address.
uint8_t htype[2]
Format of hardware address.
uint8_t ptype[2]
Format of protocol address.
#define FR_ARP_PACKET_SIZE
char const * fr_arp_packet_codes[FR_ARP_CODE_MAX]
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
#define fr_dict_autofree(_to_free)
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
#define fr_dict_autoload(_to_load)
char const * name
name of this protocol
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Structures and functions for parsing ethernet headers.
static uint32_t instance_count
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
static fr_dict_t const * dict_arp
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
static ssize_t fr_arp_encode_proto(UNUSED TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, UNUSED void *proto_ctx)
void fr_arp_global_free(void)
int fr_arp_global_init(void)
int fr_arp_entry_add(UNUSED int fd, UNUSED char const *interface, UNUSED uint8_t ipaddr[static 4], UNUSED uint8_t macaddr[static 6])
fr_dict_attr_t const * attr_arp_packet
static uint8_t const zeros[6]
fr_dict_protocol_t libfreeradius_arp_dict_protocol
static int encode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict)
ssize_t fr_arp_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *packet, size_t packet_len)
Decode a raw ARP packet into VPs.
fr_dict_autoload_t libfreeradius_arp_dict[]
fr_dict_attr_autoload_t libfreeradius_arp_dict_attr[]
static ssize_t fr_arp_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
fr_test_point_proto_encode_t arp_tp_encode_proto
fr_test_point_proto_decode_t arp_tp_decode_proto
ssize_t fr_arp_encode(fr_dbuff_t *dbuff, uint8_t const *original, fr_pair_list_t *vps)
Encode VPS into a raw ARP packet.
size_t strlcpy(char *dst, char const *src, size_t siz)
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *parent_cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
Convert a STRUCT to one or more VPs.
Stores an attribute, a value and various bits of other data.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Entry point for protocol decoders.
Entry point for protocol encoders.
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
#define fr_pair_dcursor_by_ancestor_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes descended from the specified fr_dict_attr_t.
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Structure for holding the stack of dictionary attributes being encoded.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static size_t char ** out