1 /* 2 * Copyright (c)2019 ZeroTier, Inc. 3 * 4 * Use of this software is governed by the Business Source License included 5 * in the LICENSE.TXT file in the project's root directory. 6 * 7 * Change Date: 2025-01-01 8 * 9 * On the date above, in accordance with the Business Source License, use 10 * of this software will be governed by version 2.0 of the Apache License. 11 */ 12 /****/ 13 14 #ifndef ZT_ARP_HPP 15 #define ZT_ARP_HPP 16 17 #include <stdint.h> 18 19 #include <utility> 20 21 #include "../node/Constants.hpp" 22 #include "../node/Hashtable.hpp" 23 #include "../node/MAC.hpp" 24 25 /** 26 * Maximum possible ARP length 27 * 28 * ARPs are 28 bytes in length, but specify a 128 byte buffer since 29 * some weird extensions we may support in the future can pad them 30 * out to as long as 72 bytes. 31 */ 32 #define ZT_ARP_BUF_LENGTH 128 33 34 /** 35 * Minimum permitted interval between sending ARP queries for a given IP 36 */ 37 #define ZT_ARP_QUERY_INTERVAL 2000 38 39 /** 40 * Maximum time between query and response, otherwise responses are discarded to prevent poisoning 41 */ 42 #define ZT_ARP_QUERY_MAX_TTL 5000 43 44 /** 45 * ARP expiration time 46 */ 47 #define ZT_ARP_EXPIRE 600000 48 49 namespace ZeroTier { 50 51 /** 52 * ARP cache and resolver 53 * 54 * To implement ARP: 55 * 56 * (1) Call processIncomingArp() on all ARP packets received and then always 57 * check responseLen after calling. If it is non-zero, send the contents 58 * of response to responseDest. 59 * 60 * (2) Call query() to look up IP addresses, and then check queryLen. If it 61 * is non-zero, send the contents of query to queryDest (usually broadcast). 62 * 63 * Note that either of these functions can technically generate a response or 64 * a query at any time, so their result parameters for sending ARPs should 65 * always be checked. 66 * 67 * This class is not thread-safe and must be guarded if used in multi-threaded 68 * code. 69 */ 70 class Arp 71 { 72 public: 73 Arp(); 74 75 /** 76 * Set a local IP entry that we should respond to ARPs for 77 * 78 * @param mac Our local MAC address 79 * @param ip IP in big-endian byte order (sin_addr.s_addr) 80 */ 81 void addLocal(uint32_t ip,const MAC &mac); 82 83 /** 84 * Delete a local IP entry or a cached ARP entry 85 * 86 * @param ip IP in big-endian byte order (sin_addr.s_addr) 87 */ 88 void remove(uint32_t ip); 89 90 /** 91 * Process ARP packets 92 * 93 * For ARP queries, a response is generated and responseLen is set to its 94 * frame payload length in bytes. 95 * 96 * For ARP responses, the cache is populated and the IP address entry that 97 * was learned is returned. 98 * 99 * @param arp ARP frame data 100 * @param len Length of ARP frame (usually 28) 101 * @param response Response buffer -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size 102 * @param responseLen Response length, or set to 0 if no response 103 * @param responseDest Destination of response, or set to null if no response 104 * @return IP address learned or 0 if no new IPs in cache 105 */ 106 uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest); 107 108 /** 109 * Get the MAC corresponding to an IP, generating a query if needed 110 * 111 * This returns a MAC for a remote IP. The local MAC is returned for local 112 * IPs as well. It may also generate a query if the IP is not known or the 113 * entry needs to be refreshed. In this case queryLen will be set to a 114 * non-zero value, so this should always be checked on return even if the 115 * MAC returned is non-null. 116 * 117 * @param localMac Local MAC address of host interface 118 * @param localIp Local IP address of host interface 119 * @param targetIp IP to look up 120 * @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size 121 * @param queryLen Length of generated query, or set to 0 if no query generated 122 * @param queryDest Destination of query, or set to null if no query generated 123 * @return MAC or 0 if no cached entry for this IP 124 */ 125 MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest); 126 127 private: 128 struct _ArpEntry 129 { _ArpEntryZeroTier::Arp::_ArpEntry130 _ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {} 131 uint64_t lastQuerySent; // Time last query was sent or 0 for local IP 132 uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP 133 MAC mac; // MAC address of device responsible for IP or null if not known yet 134 bool local; // True if this is a local ARP entry 135 }; 136 137 Hashtable< uint32_t,_ArpEntry > _cache; 138 uint64_t _lastCleaned; 139 }; 140 141 } // namespace ZeroTier 142 143 #endif 144