join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
arp.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_FABRIC_ARP_HPP
26#define JOIN_FABRIC_ARP_HPP
27
28// libjoin.
30#include <join/macaddress.hpp>
31#include <join/condition.hpp>
32#include <join/socket.hpp>
33
34// C++.
35#include <unordered_map>
36#include <string>
37
38// C.
39#include <linux/filter.h>
40#include <net/if_arp.h>
41#include <net/if.h>
42
43namespace join
44{
48 class Arp : public Raw::Socket
49 {
50 public:
54 Arp () = delete;
55
61 Arp (const std::string& interface, NeighborManager* neighbors = nullptr);
62
67 Arp (const Arp& other) = delete;
68
73 Arp (Arp&& other) = delete;
74
80 Arp& operator= (const Arp& other) = delete;
81
87 Arp& operator= (Arp&& other) = delete;
88
92 ~Arp () = default;
93
100 template <typename Rep, typename Period>
101 MacAddress get (const IpAddress& ip, std::chrono::duration<Rep, Period> timeout)
102 {
103 if (ip.family () != AF_INET)
104 {
106 return {};
107 }
108
109 if (ip == IpAddress::ipv4Address (_interface))
110 {
111 return MacAddress::address (_interface);
112 }
113
114 MacAddress mac = cache (ip);
115
116 return mac.isWildcard () ? request (ip, timeout) : mac;
117 }
118
125 {
126 return get (ip, std::chrono::seconds (5));
127 }
128
136 template <typename Rep, typename Period>
137 static MacAddress get (const std::string& interface, const IpAddress& ip,
138 std::chrono::duration<Rep, Period> timeout)
139 {
140 return Arp (interface).get (ip, timeout);
141 }
142
149 static MacAddress get (const std::string& interface, const IpAddress& ip)
150 {
151 return get (interface, ip, std::chrono::seconds (5));
152 }
153
160 template <typename Rep, typename Period>
161 MacAddress request (const IpAddress& ip, std::chrono::duration<Rep, Period> timeout)
162 {
163 if (ip.family () != AF_INET)
164 {
166 return {};
167 }
168
169 if (bind (_interface) == -1 || setOption (Raw::Socket::Broadcast, 1) == -1)
170 {
171 return {};
172 }
173
174 // accept only ARP replies.
175 struct sock_filter code[] = {
176 {0x28, 0, 0, 0x0000000c}, {0x15, 0, 3, 0x00000806}, {0x28, 0, 0, 0x00000014},
177 {0x15, 0, 1, 0x00000002}, {0x6, 0, 0, 0x00040000}, {0x6, 0, 0, 0x00000000},
178 };
179
180 struct sock_fprog bpf;
181 bpf.len = 6;
182 bpf.filter = code;
183
184 // best effort, validation is done in onReceive anyway.
185 ::setsockopt (handle (), SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof (bpf));
186
187 Packet out = {};
188 const MacAddress srcMac = MacAddress::address (_interface);
189 const IpAddress srcIp = IpAddress::ipv4Address (_interface);
190
191 ::memcpy (out.eth.h_dest, MacAddress::broadcast.addr (), ETH_ALEN);
192 ::memcpy (out.eth.h_source, srcMac.addr (), ETH_ALEN);
193 out.eth.h_proto = ::htons (ETH_P_ARP);
194
195 out.arp.ar_hrd = ::htons (ARPHRD_ETHER);
196 out.arp.ar_pro = ::htons (ETH_P_IP);
197 out.arp.ar_hln = ETH_ALEN;
198 out.arp.ar_pln = 4;
199 out.arp.ar_op = ::htons (ARPOP_REQUEST);
200 ::memcpy (out.arp.ar_sha, srcMac.addr (), ETH_ALEN);
201 ::memcpy (&out.arp.ar_sip, srcIp.addr (), sizeof (uint32_t));
202 ::memcpy (out.arp.ar_tha, MacAddress::wildcard.addr (), ETH_ALEN);
203 ::memcpy (&out.arp.ar_tip, ip.addr (), sizeof (uint32_t));
204
205 ScopedLock<Mutex> lock (_syncMutex);
206
207 if (write (reinterpret_cast<const char*> (&out), sizeof (Packet)) == -1)
208 {
209 close ();
210 return {};
211 }
212
213 _reactor->addHandler (handle (), this);
214 MacAddress mac = waitResponse (lock, out.arp.ar_tip, timeout);
215 _reactor->delHandler (handle ());
216
217 close ();
218 return mac;
219 }
220
227 {
228 return request (ip, std::chrono::seconds (5));
229 }
230
238 template <typename Rep, typename Period>
239 static MacAddress request (const std::string& interface, const IpAddress& ip,
240 std::chrono::duration<Rep, Period> timeout)
241 {
242 return Arp (interface).request (ip, timeout);
243 }
244
251 static MacAddress request (const std::string& interface, const IpAddress& ip)
252 {
253 return request (interface, ip, std::chrono::seconds (5));
254 }
255
262 int add (const MacAddress& mac, const IpAddress& ip);
263
271 static int add (const std::string& interface, const MacAddress& mac, const IpAddress& ip);
272
278 int remove (const IpAddress& ip);
279
286 static int remove (const std::string& interface, const IpAddress& ip);
287
293 MacAddress cache (const IpAddress& ip);
294
301 static MacAddress cache (const std::string& interface, const IpAddress& ip);
302
303 private:
307 struct __attribute__ ((packed)) ArpPacket
308 {
309 uint16_t ar_hrd;
310 uint16_t ar_pro;
311 uint8_t ar_hln;
312 uint8_t ar_pln;
313 uint16_t ar_op;
314 uint8_t ar_sha[ETH_ALEN];
315 uint32_t ar_sip;
316 uint8_t ar_tha[ETH_ALEN];
317 uint32_t ar_tip;
318 };
319
323 struct __attribute__ ((packed)) Packet
324 {
325 struct ethhdr eth;
326 ArpPacket arp;
327 };
328
336 template <typename Rep, typename Period>
337 MacAddress waitResponse (ScopedLock<Mutex>& lock, uint32_t tip, std::chrono::duration<Rep, Period> timeout)
338 {
339 auto inserted = _pending.emplace (tip, std::make_unique<PendingRequest> ());
340 if (!inserted.second)
341 {
342 // LCOV_EXCL_START
344 return {};
345 // LCOV_EXCL_STOP
346 }
347
348 if (!inserted.first->second->cond.timedWait (lock, timeout))
349 {
350 _pending.erase (inserted.first);
351 lastError = std::make_error_code (std::errc::no_such_device_or_address);
352 return {};
353 }
354
355 MacAddress mac = inserted.first->second->mac;
356 _pending.erase (inserted.first);
357
358 return mac;
359 }
360
365 void onReceive (int fd) noexcept override;
366
368 static constexpr size_t _bufferSize = 4096;
369
373 struct PendingRequest
374 {
375 Condition cond;
376 MacAddress mac;
377 };
378
380 std::unordered_map<uint32_t, std::unique_ptr<PendingRequest>> _pending;
381
383 Mutex _syncMutex;
384
386 const std::string _interface;
387
389 NeighborManager* _neighbors = nullptr;
390
392 Reactor* const _reactor = nullptr;
393 };
394}
395
396#endif
ARP protocol class.
Definition arp.hpp:49
~Arp()=default
destroy the Arp instance.
static MacAddress request(const std::string &interface, const IpAddress &ip)
get the MAC address for the given IP address using ARP request.
Definition arp.hpp:251
int add(const MacAddress &mac, const IpAddress &ip)
add entry the MAC address of the given IP address to ARP cache.
Definition arp.cpp:56
MacAddress request(const IpAddress &ip, std::chrono::duration< Rep, Period > timeout)
get the MAC address for the given IP address using ARP request.
Definition arp.hpp:161
Arp(const Arp &other)=delete
create instance by copy.
static MacAddress request(const std::string &interface, const IpAddress &ip, std::chrono::duration< Rep, Period > timeout)
get the MAC address for the given IP address using ARP request.
Definition arp.hpp:239
static MacAddress get(const std::string &interface, const IpAddress &ip)
discover the MAC address for the given internet layer address.
Definition arp.hpp:149
static MacAddress get(const std::string &interface, const IpAddress &ip, std::chrono::duration< Rep, Period > timeout)
discover the MAC address for the given internet layer address.
Definition arp.hpp:137
Arp()=delete
create the Arp instance.
MacAddress get(const IpAddress &ip, std::chrono::duration< Rep, Period > timeout)
get the MAC address for the given IP address using netlink neighbor cache or ARP request.
Definition arp.hpp:101
int remove(const IpAddress &ip)
remove the MAC address of the given IP address from ARP cache.
Definition arp.cpp:87
MacAddress cache(const IpAddress &ip)
get the MAC address for the given IP address using ARP cache.
Definition arp.cpp:118
Arp & operator=(const Arp &other)=delete
assign instance by copy.
MacAddress request(const IpAddress &ip)
get the MAC address for the given IP address using ARP request.
Definition arp.hpp:226
MacAddress get(const IpAddress &ip)
get the MAC address for the given IP address using ARP cache or ARP request.
Definition arp.hpp:124
Arp(Arp &&other)=delete
create instance by move.
basic socket class.
Definition socket.hpp:60
virtual int setOption(Option option, int value) noexcept
set the given option to the given value.
Definition socket.hpp:407
virtual void close() noexcept
close the socket.
Definition socket.hpp:223
virtual int bind(const Endpoint &endpoint) noexcept
assigns the specified endpoint to the socket.
Definition socket.hpp:238
@ Broadcast
Definition socket.hpp:89
int handle() const noexcept
get socket native handle.
Definition socket.hpp:534
virtual int write(const char *data, unsigned long maxSize) noexcept
write data.
Definition socket.hpp:352
friend class Reactor
friendship with reactor.
Definition reactor.hpp:113
IPv6, IPv4 address class.
Definition ipaddress.hpp:51
int family() const
get address family.
Definition ipaddress.cpp:1250
static IpAddress ipv4Address(const std::string &interface)
get the specified interface IPv4 address.
Definition ipaddress.cpp:1526
const void * addr() const
get the internal address structure.
Definition ipaddress.cpp:1259
MAC address class.
Definition macaddress.hpp:46
static const MacAddress broadcast
broadcast MAC address.
Definition macaddress.hpp:309
bool isWildcard() const
check if MAC address is a wildcard address.
Definition macaddress.cpp:182
static const MacAddress wildcard
wildcard MAC address.
Definition macaddress.hpp:306
static MacAddress address(const std::string &interface)
get the specified interface MAC address.
Definition macaddress.cpp:355
const uint8_t * addr() const
get the internal MAC address array address.
Definition macaddress.cpp:164
ARP / NDP neighbor manager class.
Definition neighbormanager.hpp:138
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:150
int addHandler(int fd, EventHandler *handler, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:94
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:246
Definition acceptor.hpp:32
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:150