/* * Copyright (c)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * * Change Date: 2024-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. */ /****/ #include "Endpoint.hpp" namespace ZeroTier { bool Endpoint::operator==(const Endpoint &ep) const { if (_t == ep._t) { switch(_t) { default: return true; case TYPE_ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0)); case TYPE_DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0)); case TYPE_URL: return (strcmp(_v.url,ep._v.url) == 0); case TYPE_ETHERNET: return (_v.eth == ep._v.eth); case TYPE_INETADDR_V4: case TYPE_INETADDR_V6: return (inetAddr() == ep.inetAddr()); } } return false; } bool Endpoint::operator<(const Endpoint &ep) const { if ((int)_t < (int)ep._t) { return true; } else if (_t == ep._t) { int ncmp; switch(_t) { case TYPE_ZEROTIER: return (_v.zt.a < ep._v.zt.a) ? true : ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) < 0)); case TYPE_DNSNAME: ncmp = strcmp(_v.dns.name,ep._v.dns.name); return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port)); case TYPE_URL: return (strcmp(_v.url,ep._v.url) < 0); case TYPE_ETHERNET: return (_v.eth < ep._v.eth); case TYPE_INETADDR_V4: case TYPE_INETADDR_V6: return (inetAddr() < ep.inetAddr()); default: return false; } } return false; } int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept { int p; data[0] = (uint8_t)_t; Utils::storeBigEndian(data + 1,(int16_t)_l[0]); Utils::storeBigEndian(data + 3,(int16_t)_l[1]); Utils::storeBigEndian(data + 5,(int16_t)_l[2]); switch(_t) { case TYPE_ZEROTIER: data[7] = (uint8_t)(_v.zt.a >> 32U); data[8] = (uint8_t)(_v.zt.a >> 24U); data[9] = (uint8_t)(_v.zt.a >> 16U); data[10] = (uint8_t)(_v.zt.a >> 8U); data[11] = (uint8_t)_v.zt.a; memcpy(data + 12,_v.zt.idh,ZT_IDENTITY_HASH_SIZE); return ZT_IDENTITY_HASH_SIZE + 12; case TYPE_DNSNAME: p = 7; for (;;) { if ((data[p] = (uint8_t)_v.dns.name[p-1]) == 0) break; ++p; if (p == (ZT_ENDPOINT_MAX_NAME_SIZE+1)) return -1; } data[p++] = (uint8_t)(_v.dns.port >> 8U); data[p++] = (uint8_t)_v.dns.port; return p; case TYPE_URL: p = 7; for (;;) { if ((data[p] = (uint8_t)_v.url[p-1]) == 0) break; ++p; if (p == (ZT_ENDPOINT_MAX_NAME_SIZE+1)) return -1; } return p; case TYPE_ETHERNET: data[7] = (uint8_t)(_v.eth >> 40U); data[8] = (uint8_t)(_v.eth >> 32U); data[9] = (uint8_t)(_v.eth >> 24U); data[10] = (uint8_t)(_v.eth >> 16U); data[11] = (uint8_t)(_v.eth >> 8U); data[12] = (uint8_t)_v.eth; return 13; case TYPE_INETADDR_V4: case TYPE_INETADDR_V6: p = asInetAddress(_v.sa).marshal(data + 7); if (p < 0) return p; return 7 + p; default: data[0] = (uint8_t)TYPE_NIL; return 7; } } int Endpoint::unmarshal(const uint8_t *restrict data,const int len) noexcept { if (len < 7) return -1; int p; _t = (Type)data[0]; _l[0] = Utils::loadBigEndian(data + 1); _l[1] = Utils::loadBigEndian(data + 3); _l[2] = Utils::loadBigEndian(data + 5); switch(_t) { case TYPE_NIL: return 7; case TYPE_ZEROTIER: if (len < (12 + ZT_IDENTITY_HASH_SIZE)) return -1; _v.zt.a = ((uint64_t)data[7]) << 32U; _v.zt.a |= ((uint64_t)data[8]) << 24U; _v.zt.a |= ((uint64_t)data[9]) << 16U; _v.zt.a |= ((uint64_t)data[10]) << 8U; _v.zt.a |= (uint64_t)data[11]; memcpy(_v.zt.idh,data + 12,ZT_IDENTITY_HASH_SIZE); return 60; case TYPE_DNSNAME: if (len < 10) return -1; p = 7; for (;;) { if ((_v.dns.name[p-1] = (char)data[p]) == 0) { ++p; break; } ++p; if ((p >= (ZT_ENDPOINT_MARSHAL_SIZE_MAX-2))||(p >= (len-2))) return -1; } _v.dns.port = (uint16_t)(((unsigned int)data[p++]) << 8U); _v.dns.port |= (uint16_t)data[p++]; return p; case TYPE_URL: if (len < 8) return -1; p = 7; for (;;) { if ((_v.url[p-1] = (char)data[p]) == 0) { ++p; break; } ++p; if ((p >= (ZT_ENDPOINT_MAX_NAME_SIZE+1))||(p >= len)) return -1; } return p; case TYPE_ETHERNET: if (len < 13) return -1; _v.eth = ((uint64_t)data[7]) << 40U; _v.eth |= ((uint64_t)data[8]) << 32U; _v.eth |= ((uint64_t)data[9]) << 24U; _v.eth |= ((uint64_t)data[10]) << 16U; _v.eth |= ((uint64_t)data[11]) << 8U; _v.eth |= (uint64_t)data[12]; return 13; case TYPE_INETADDR_V4: case TYPE_INETADDR_V6: p = asInetAddress(_v.sa).unmarshal(data + 7,len - 7); if (p <= 0) return -1; return 7 + p; default: // Unrecognized endpoint types not yet specified must start with a 16-bit // length so that older versions of ZeroTier can skip them. if (len < 9) return -1; p = 9 + (int)Utils::loadBigEndian(data + 7); return (p > len) ? -1 : p; } } } // namespace ZeroTier