summaryrefslogtreecommitdiff
path: root/osdep/Arp.hpp
blob: 5f0d199a8a68c11acb0fa9fc4e270b8c0edf8280 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 * ZeroTier One - Network Virtualization Everywhere
 * Copyright (C) 2011-2016  ZeroTier, Inc.  https://www.zerotier.com/
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef ZT_ARP_HPP
#define ZT_ARP_HPP

#include <stdint.h>

#include <utility>

#include "../node/Constants.hpp"
#include "../node/Hashtable.hpp"
#include "../node/MAC.hpp"

/**
 * Maximum possible ARP length
 *
 * ARPs are 28 bytes in length, but specify a 128 byte buffer since
 * some weird extensions we may support in the future can pad them
 * out to as long as 72 bytes.
 */
#define ZT_ARP_BUF_LENGTH 128

/**
 * Minimum permitted interval between sending ARP queries for a given IP
 */
#define ZT_ARP_QUERY_INTERVAL 2000

/**
 * Maximum time between query and response, otherwise responses are discarded to prevent poisoning
 */
#define ZT_ARP_QUERY_MAX_TTL 5000

/**
 * ARP expiration time
 */
#define ZT_ARP_EXPIRE 600000

namespace ZeroTier {

/**
 * ARP cache and resolver
 *
 * To implement ARP:
 *
 * (1) Call processIncomingArp() on all ARP packets received and then always
 * check responseLen after calling. If it is non-zero, send the contents
 * of response to responseDest.
 *
 * (2) Call query() to look up IP addresses, and then check queryLen. If it
 * is non-zero, send the contents of query to queryDest (usually broadcast).
 *
 * Note that either of these functions can technically generate a response or
 * a query at any time, so their result parameters for sending ARPs should
 * always be checked.
 *
 * This class is not thread-safe and must be guarded if used in multi-threaded
 * code.
 */
class Arp
{
public:
	Arp();

	/**
	 * Set a local IP entry that we should respond to ARPs for
	 *
	 * @param mac Our local MAC address
	 * @param ip IP in big-endian byte order (sin_addr.s_addr)
	 */
	void addLocal(uint32_t ip,const MAC &mac);

	/**
	 * Delete a local IP entry or a cached ARP entry
	 *
	 * @param ip IP in big-endian byte order (sin_addr.s_addr)
	 */
	void remove(uint32_t ip);

	/**
	 * Process ARP packets
	 *
	 * For ARP queries, a response is generated and responseLen is set to its
	 * frame payload length in bytes.
	 *
	 * For ARP responses, the cache is populated and the IP address entry that
	 * was learned is returned.
	 *
	 * @param arp ARP frame data
	 * @param len Length of ARP frame (usually 28)
	 * @param response Response buffer -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size
	 * @param responseLen Response length, or set to 0 if no response
	 * @param responseDest Destination of response, or set to null if no response
	 * @return IP address learned or 0 if no new IPs in cache
	 */
	uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest);

	/**
	 * Get the MAC corresponding to an IP, generating a query if needed
	 *
	 * This returns a MAC for a remote IP. The local MAC is returned for local
	 * IPs as well. It may also generate a query if the IP is not known or the
	 * entry needs to be refreshed. In this case queryLen will be set to a
	 * non-zero value, so this should always be checked on return even if the
	 * MAC returned is non-null.
	 *
	 * @param localMac Local MAC address of host interface
     * @param localIp Local IP address of host interface
	 * @param targetIp IP to look up
	 * @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size
	 * @param queryLen Length of generated query, or set to 0 if no query generated
	 * @param queryDest Destination of query, or set to null if no query generated
	 * @return MAC or 0 if no cached entry for this IP
	 */
	MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest);

private:
	struct _ArpEntry
	{
		_ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {}
		uint64_t lastQuerySent; // Time last query was sent or 0 for local IP
		uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP
		MAC mac; // MAC address of device responsible for IP or null if not known yet
		bool local; // True if this is a local ARP entry
	};

	Hashtable< uint32_t,_ArpEntry > _cache;
	uint64_t _lastCleaned;
};

} // namespace ZeroTier

#endif