diff --git a/core/CAPI.cpp b/core/CAPI.cpp index 34e9391e6..1862b3d15 100644 --- a/core/CAPI.cpp +++ b/core/CAPI.cpp @@ -100,7 +100,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( void *tptr, int64_t now, int64_t localSocket, - const struct sockaddr_storage *remoteAddress, + const ZT_InetAddress *remoteAddress, const void *packetData, unsigned int packetLength, int isZtBuffer, @@ -108,7 +108,7 @@ enum ZT_ResultCode ZT_Node_processWirePacket( { try { ZeroTier::SharedPtr< ZeroTier::Buf > buf((isZtBuffer) ? ZT_PTRTOBUF(packetData) : new ZeroTier::Buf(packetData, packetLength & ZT_BUF_MEM_MASK)); - return reinterpret_cast(node)->processWirePacket(tptr, now, localSocket, remoteAddress, buf, packetLength, nextBackgroundTaskDeadline); + return reinterpret_cast(node)->processWirePacket(tptr, now, localSocket, ZT_InetAddress_ptr_cast_const_sockaddr_storage_ptr(remoteAddress), buf, packetLength, nextBackgroundTaskDeadline); } catch (std::bad_alloc &exc) { return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; } catch (...) { @@ -755,4 +755,79 @@ int ZT_Fingerprint_fromString(ZT_Fingerprint *fp, const char *s) /********************************************************************************************************************/ +void ZT_InetAddress_clear(ZT_InetAddress *ia) +{ + if (likely(ia != nullptr)) + ZeroTier::Utils::zero(ia); +} + +char *ZT_InetAddress_toString(const ZT_InetAddress *ia, char *buf, unsigned int cap) +{ + if (likely((cap > 0)&&(buf != nullptr))) { + if (likely((ia != nullptr)&&(cap >= ZT_INETADDRESS_STRING_SIZE_MAX))) { + reinterpret_cast(ia)->toString(buf); + } else { + buf[0] = 0; + } + } + return buf; +} + +int ZT_InetAddress_fromString(ZT_InetAddress *ia, const char *str) +{ + if (likely((ia != nullptr)&&(str != nullptr))) { + return (int)reinterpret_cast(ia)->fromString(str); + } + return 0; +} + +void ZT_InetAddress_set(ZT_InetAddress *ia, const void *saddr) +{ + if (likely(ia != nullptr)) + (*reinterpret_cast(ia)) = reinterpret_cast(saddr); +} + +void ZT_InetAddress_setIpBytes(ZT_InetAddress *ia, const void *ipBytes, unsigned int ipLen, unsigned int port) +{ + if (likely(ia != nullptr)) + reinterpret_cast(ia)->set(ipBytes, ipLen, port); +} + +void ZT_InetAddress_setPort(ZT_InetAddress *ia, unsigned int port) +{ + if (likely(ia != nullptr)) + reinterpret_cast(ia)->setPort(port); +} + +unsigned int ZT_InetAddress_port(const ZT_InetAddress *ia) +{ + if (likely(ia != nullptr)) + return reinterpret_cast(ia)->port(); + return 0; +} + +int ZT_InetAddress_isNil(const ZT_InetAddress *ia) +{ + return (int)( (ia == nullptr) || ((reinterpret_cast(ia))->ss_family == 0) ); +} + +int ZT_InetAddress_isV4(const ZT_InetAddress *ia) +{ + return (int)( (ia != nullptr) && ((reinterpret_cast(ia))->ss_family == AF_INET) ); +} + +int ZT_InetAddress_isV6(const ZT_InetAddress *ia) +{ + return (int)( (ia != nullptr) && ((reinterpret_cast(ia))->ss_family == AF_INET6) ); +} + +enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress *ia) +{ + if (likely(ia != nullptr)) + return reinterpret_cast(ia)->ipScope(); + return ZT_IP_SCOPE_NONE; +} + +/********************************************************************************************************************/ + } // extern "C" diff --git a/core/Constants.hpp b/core/Constants.hpp index 771f49478..6da562cec 100644 --- a/core/Constants.hpp +++ b/core/Constants.hpp @@ -14,9 +14,13 @@ #ifndef ZT_CONSTANTS_HPP #define ZT_CONSTANTS_HPP -#include "zerotier.h" -#include "OS.hpp" +/** + * Indicates to some parts of zerotier.h that we are building the core + */ +#define ZT_CORE 1 +#include "OS.hpp" +#include "zerotier.h" #include "version.h" /** diff --git a/core/InetAddress.cpp b/core/InetAddress.cpp index 058107ae4..baea687b8 100644 --- a/core/InetAddress.cpp +++ b/core/InetAddress.cpp @@ -19,6 +19,10 @@ namespace ZeroTier { +static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(sockaddr_storage), "ZT_SOCKADDR_STORAGE_SIZE is incorrect on this platform, must be size of sockaddr_storage"); +static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(InetAddress), "ZT_SOCKADDR_STORAGE_SIZE should equal InetAddress, which should equal size of sockaddr_storage"); +static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(ZT_InetAddress), "ZT_SOCKADDR_STORAGE_SIZE should equal ZT_InetAddress, which should equal size of sockaddr_storage"); + const InetAddress InetAddress::LO4((const void *) ("\x7f\x00\x00\x01"), 4, 0); const InetAddress InetAddress::LO6((const void *) ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0); const InetAddress InetAddress::NIL; @@ -31,11 +35,11 @@ InetAddress::IpScope InetAddress::ipScope() const noexcept const uint32_t ip = Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr); switch (ip >> 24U) { case 0x00: - return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) + return ZT_IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) case 0x06: - return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) + return ZT_IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) case 0x0a: - return IP_SCOPE_PRIVATE; // 10.0.0.0/8 + return ZT_IP_SCOPE_PRIVATE; // 10.0.0.0/8 case 0x0b: //return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD) case 0x15: //return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN) case 0x16: //return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA) @@ -47,65 +51,65 @@ InetAddress::IpScope InetAddress::ipScope() const noexcept case 0x33: //return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security) case 0x37: //return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD) case 0x38: // 56.0.0.0/8 (US Postal Service) - return IP_SCOPE_PSEUDOPRIVATE; + return ZT_IP_SCOPE_PSEUDOPRIVATE; case 0x64: - if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE; // 100.64.0.0/10 + if ((ip & 0xffc00000) == 0x64400000) return ZT_IP_SCOPE_PRIVATE; // 100.64.0.0/10 break; case 0x7f: - return IP_SCOPE_LOOPBACK; // 127.0.0.0/8 + return ZT_IP_SCOPE_LOOPBACK; // 127.0.0.0/8 case 0xa9: - if ((ip & 0xffff0000) == 0xa9fe0000) return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 + if ((ip & 0xffff0000) == 0xa9fe0000) return ZT_IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 break; case 0xac: - if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12 + if ((ip & 0xfff00000) == 0xac100000) return ZT_IP_SCOPE_PRIVATE; // 172.16.0.0/12 break; case 0xc0: - if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16 - if ((ip & 0xffffff00) == 0xc0000200) return IP_SCOPE_PRIVATE; // 192.0.2.0/24 + if ((ip & 0xffff0000) == 0xc0a80000) return ZT_IP_SCOPE_PRIVATE; // 192.168.0.0/16 + if ((ip & 0xffffff00) == 0xc0000200) return ZT_IP_SCOPE_PRIVATE; // 192.0.2.0/24 break; case 0xc6: - if ((ip & 0xfffe0000) == 0xc6120000) return IP_SCOPE_PRIVATE; // 198.18.0.0/15 - if ((ip & 0xffffff00) == 0xc6336400) return IP_SCOPE_PRIVATE; // 198.51.100.0/24 + if ((ip & 0xfffe0000) == 0xc6120000) return ZT_IP_SCOPE_PRIVATE; // 198.18.0.0/15 + if ((ip & 0xffffff00) == 0xc6336400) return ZT_IP_SCOPE_PRIVATE; // 198.51.100.0/24 break; case 0xcb: - if ((ip & 0xffffff00) == 0xcb007100) return IP_SCOPE_PRIVATE; // 203.0.113.0/24 + if ((ip & 0xffffff00) == 0xcb007100) return ZT_IP_SCOPE_PRIVATE; // 203.0.113.0/24 break; case 0xff: - return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) + return ZT_IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) } switch (ip >> 28U) { case 0xe: - return IP_SCOPE_MULTICAST; // 224.0.0.0/4 + return ZT_IP_SCOPE_MULTICAST; // 224.0.0.0/4 case 0xf: - return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable) + return ZT_IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable) } - return IP_SCOPE_GLOBAL; + return ZT_IP_SCOPE_GLOBAL; } case AF_INET6: { const uint8_t *const ip = as.sa_in6.sin6_addr.s6_addr; if ((ip[0] & 0xf0U) == 0xf0) { - if (ip[0] == 0xff) return IP_SCOPE_MULTICAST; // ff00::/8 + if (ip[0] == 0xff) return ZT_IP_SCOPE_MULTICAST; // ff00::/8 if ((ip[0] == 0xfe) && ((ip[1] & 0xc0U) == 0x80)) { unsigned int k = 2; while ((!ip[k]) && (k < 15)) ++k; if ((k == 15) && (ip[15] == 0x01)) - return IP_SCOPE_LOOPBACK; // fe80::1/128 - else return IP_SCOPE_LINK_LOCAL; // fe80::/10 + return ZT_IP_SCOPE_LOOPBACK; // fe80::1/128 + else return ZT_IP_SCOPE_LINK_LOCAL; // fe80::/10 } - if ((ip[0] & 0xfeU) == 0xfc) return IP_SCOPE_PRIVATE; // fc00::/7 + if ((ip[0] & 0xfeU) == 0xfc) return ZT_IP_SCOPE_PRIVATE; // fc00::/7 } unsigned int k = 0; while ((!ip[k]) && (k < 15)) ++k; if (k == 15) { // all 0's except last byte - if (ip[15] == 0x01) return IP_SCOPE_LOOPBACK; // ::1/128 - if (ip[15] == 0x00) return IP_SCOPE_NONE; // ::/128 + if (ip[15] == 0x01) return ZT_IP_SCOPE_LOOPBACK; // ::1/128 + if (ip[15] == 0x00) return ZT_IP_SCOPE_NONE; // ::/128 } - return IP_SCOPE_GLOBAL; + return ZT_IP_SCOPE_GLOBAL; } } - return IP_SCOPE_NONE; + return ZT_IP_SCOPE_NONE; } void InetAddress::set(const void *ipBytes, unsigned int ipLen, unsigned int port) noexcept diff --git a/core/InetAddress.hpp b/core/InetAddress.hpp index 8ad556d03..b74316f66 100644 --- a/core/InetAddress.hpp +++ b/core/InetAddress.hpp @@ -59,17 +59,7 @@ public: * MUST remain that way or Path must be changed to reflect. Also be sure * to change ZT_INETADDRESS_MAX_SCOPE if the max changes. */ - enum IpScope - { - IP_SCOPE_NONE = 0, // NULL or not an IP address - IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs - IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. - IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted" - IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others) - IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL - IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges - IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc. - }; + typedef ZT_InetAddress_IpScope IpScope; // Hasher for unordered sets and maps in C++11 struct Hasher @@ -130,52 +120,52 @@ public: ZT_INLINE InetAddress &operator=(const sockaddr_in &sa) noexcept { + memoryZero(this); as.sa_in = sa; return *this; } ZT_INLINE InetAddress &operator=(const sockaddr_in *sa) noexcept { + memoryZero(this); if (sa) as.sa_in = *sa; - else memoryZero(this); return *this; } ZT_INLINE InetAddress &operator=(const sockaddr_in6 &sa) noexcept { + memoryZero(this); as.sa_in6 = sa; return *this; } ZT_INLINE InetAddress &operator=(const sockaddr_in6 *sa) noexcept { + memoryZero(this); if (sa) as.sa_in6 = *sa; - else memoryZero(this); return *this; } ZT_INLINE InetAddress &operator=(const sockaddr &sa) noexcept { + memoryZero(this); if (sa.sa_family == AF_INET) as.sa_in = *reinterpret_cast(&sa); else if (sa.sa_family == AF_INET6) as.sa_in6 = *reinterpret_cast(&sa); - else memoryZero(this); return *this; } ZT_INLINE InetAddress &operator=(const sockaddr *sa) noexcept { + memoryZero(this); if (sa) { if (sa->sa_family == AF_INET) as.sa_in = *reinterpret_cast(sa); else if (sa->sa_family == AF_INET6) as.sa_in6 = *reinterpret_cast(sa); - else memoryZero(this); - } else { - memoryZero(this); } return *this; } @@ -625,6 +615,9 @@ static ZT_INLINE InetAddress *asInetAddress(sockaddr *const p) noexcept static ZT_INLINE InetAddress *asInetAddress(sockaddr_storage *const p) noexcept { return reinterpret_cast(p); } +static ZT_INLINE InetAddress *asInetAddress(ZT_InetAddress *const p) noexcept +{ return reinterpret_cast(p); } + static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_in *const p) noexcept { return reinterpret_cast(p); } @@ -637,6 +630,9 @@ static ZT_INLINE const InetAddress *asInetAddress(const sockaddr *const p) noexc static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_storage *const p) noexcept { return reinterpret_cast(p); } +static ZT_INLINE const InetAddress *asInetAddress(const ZT_InetAddress *const p) noexcept +{ return reinterpret_cast(p); } + static ZT_INLINE InetAddress &asInetAddress(sockaddr_in &p) noexcept { return *reinterpret_cast(&p); } @@ -649,6 +645,9 @@ static ZT_INLINE InetAddress &asInetAddress(sockaddr &p) noexcept static ZT_INLINE InetAddress &asInetAddress(sockaddr_storage &p) noexcept { return *reinterpret_cast(&p); } +static ZT_INLINE InetAddress &asInetAddress(ZT_InetAddress &p) noexcept +{ return *reinterpret_cast(&p); } + static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_in &p) noexcept { return *reinterpret_cast(&p); } @@ -661,6 +660,9 @@ static ZT_INLINE const InetAddress &asInetAddress(const sockaddr &p) noexcept static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_storage &p) noexcept { return *reinterpret_cast(&p); } +static ZT_INLINE const InetAddress &asInetAddress(const ZT_InetAddress &p) noexcept +{ return *reinterpret_cast(&p); } + } // namespace ZeroTier #endif diff --git a/core/Node.cpp b/core/Node.cpp index 7ac0832e3..cc7a291c9 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -703,7 +703,7 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr, const Identity &id, const id.address().toInt(), (const ZT_Identity *)&id, localSocket, - reinterpret_cast(&remoteAddress)) != 0); + reinterpret_cast(&remoteAddress)) != 0); } return true; @@ -719,7 +719,7 @@ bool Node::externalPathLookup(void *tPtr, const Identity &id, int family, InetAd id.address().toInt(), reinterpret_cast(&id), family, - reinterpret_cast(&addr)) == ZT_RESULT_OK); + reinterpret_cast(&addr)) == ZT_RESULT_OK); } return false; } diff --git a/core/Node.hpp b/core/Node.hpp index a38a167c9..2cc9fb99a 100644 --- a/core/Node.hpp +++ b/core/Node.hpp @@ -178,7 +178,7 @@ public: m_uPtr, tPtr, localSocket, - &addr.as.ss, + reinterpret_cast(&addr.as.ss), data, len, ttl) == 0); diff --git a/core/OS.hpp b/core/OS.hpp index dad99fa1a..da3c74b36 100644 --- a/core/OS.hpp +++ b/core/OS.hpp @@ -58,6 +58,13 @@ #endif /* Microsoft Windows */ +#ifndef __WINDOWS__ +#include +#include +#include +#include +#endif /* NOT Microsoft Windows */ + #include #include #include diff --git a/core/SelfAwareness.cpp b/core/SelfAwareness.cpp index cadca4ad2..f0dd3d1b8 100644 --- a/core/SelfAwareness.cpp +++ b/core/SelfAwareness.cpp @@ -53,7 +53,7 @@ void SelfAwareness::iam(void *tPtr, const Identity &reporter, const int64_t rece { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); - if ((scope != reporterPhysicalAddress.ipScope()) || (scope == InetAddress::IP_SCOPE_NONE) || (scope == InetAddress::IP_SCOPE_LOOPBACK) || (scope == InetAddress::IP_SCOPE_MULTICAST)) + if ((scope != reporterPhysicalAddress.ipScope()) || (scope == ZT_IP_SCOPE_NONE) || (scope == ZT_IP_SCOPE_LOOPBACK) || (scope == ZT_IP_SCOPE_MULTICAST)) return; Mutex::Lock l(m_phy_l); diff --git a/core/zerotier.h b/core/zerotier.h index ffe120e30..ad210c763 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -18,19 +18,6 @@ #ifndef ZT_ZEROTIER_API_H #define ZT_ZEROTIER_API_H -#if defined(_WIN32) || defined(_WIN64) -#include -#include -#include -#else - -#include -#include -#include -#include - -#endif - #include #include @@ -281,6 +268,34 @@ typedef void ZT_Identity; */ typedef void ZT_Locator; +#define ZT_SOCKADDR_STORAGE_SIZE 128 + +/** + * InetAddress holds a socket address + * + * This is a sized placeholder for InetAddress in the C++ code or the + * sockaddr_storage structure. Its size is checked at compile time in + * InetAddress.cpp against sizeof(sockaddr_storage) to ensure that it + * is correct for the platform. If it's not correct, a platform ifdef + * will be needed. + */ +typedef struct { uint64_t bits[ZT_SOCKADDR_STORAGE_SIZE / 8]; } ZT_InetAddress; + +/** + * IP scope types as identified by InetAddress. + */ +enum ZT_InetAddress_IpScope +{ + ZT_IP_SCOPE_NONE = 0, // NULL or not an IP address + ZT_IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs + ZT_IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. + ZT_IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted" + ZT_IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others) + ZT_IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL + ZT_IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges + ZT_IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc. +}; + /** * Full identity fingerprint with address and 384-bit hash of public key(s) */ @@ -1311,12 +1326,12 @@ typedef struct /** * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default */ - struct sockaddr_storage target; + ZT_InetAddress target; /** * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) */ - struct sockaddr_storage via; + ZT_InetAddress via; /** * Route flags @@ -1439,7 +1454,7 @@ typedef struct * This is only used for ZeroTier-managed address assignments sent by the * virtual network's configuration master. */ - struct sockaddr_storage assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; + ZT_InetAddress assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; /** * Number of ZT-pushed routes @@ -1471,7 +1486,7 @@ typedef struct /** * IP and port as would be reachable by external nodes */ - struct sockaddr_storage address; + ZT_InetAddress address; /** * If nonzero this address is static and can be incorporated into this node's Locator @@ -1491,6 +1506,15 @@ typedef struct union { + /** + * ZT_InetAddress, which is identically sized to sockaddr_storage. + * + * The ZT_InetAddress conversion macros can be used to get this in the + * form of a sockaddr, sockaddr_in, etc. + */ + ZT_InetAddress ia; + +#ifdef ZT_CORE /** * Socket address generic buffer */ @@ -1510,6 +1534,7 @@ typedef struct * IPv6 address, for all ZT_ENDPOINT_TYPE_IP types if family is AF_INET6 */ struct sockaddr_in6 sa_in6; +#endif /** * MAC address (least significant 48 bites) for ZT_ENDPOINT_TYPE_ETHERNET and other MAC addressed types @@ -1875,7 +1900,7 @@ typedef int (*ZT_WirePacketSendFunction)( void *, /* User ptr */ void *, /* Thread ptr */ int64_t, /* Local socket */ - const struct sockaddr_storage *, /* Remote address */ + const ZT_InetAddress *, /* Remote address */ const void *, /* Packet data */ unsigned int, /* Packet length */ unsigned int); /* TTL or 0 to use default */ @@ -1909,7 +1934,7 @@ typedef int (*ZT_PathCheckFunction)( uint64_t, /* ZeroTier address */ const ZT_Identity *, /* Full identity of node */ int64_t, /* Local socket or -1 if unknown */ - const struct sockaddr_storage *); /* Remote address */ + const ZT_InetAddress *); /* Remote address */ /** * Function to get physical addresses for ZeroTier peers @@ -1934,7 +1959,7 @@ typedef int (*ZT_PathLookupFunction)( uint64_t, /* ZeroTier address (40 bits) */ const ZT_Identity *, /* Full identity of node */ int, /* Desired ss_family or -1 for any */ - struct sockaddr_storage *); /* Result buffer */ + ZT_InetAddress *); /* Result buffer */ /* ---------------------------------------------------------------------------------------------------------------- */ @@ -2071,7 +2096,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( void *tptr, int64_t now, int64_t localSocket, - const struct sockaddr_storage *remoteAddress, + const ZT_InetAddress *remoteAddress, const void *packetData, unsigned int packetLength, int isZtBuffer, @@ -2892,6 +2917,65 @@ ZT_SDK_API int ZT_Fingerprint_fromString(ZT_Fingerprint *fp, const char *s); /* ---------------------------------------------------------------------------------------------------------------- */ +/* + * InetAddress casting macros depend on the relevant struct being defined. + * System headers with sockaddr, sockaddr_in, etc. must have already been + * included. + */ + +#define ZT_InetAddress_ptr_cast_sockaddr_ptr(a) ((struct sockaddr *)(a)) +#define ZT_InetAddress_ptr_cast_sockaddr_in_ptr(a) ((struct sockaddr_in *)(a)) +#define ZT_InetAddress_ptr_cast_sockaddr_in6_ptr(a) ((struct sockaddr_in6 *)(a)) +#define ZT_InetAddress_ptr_cast_sockaddr_storage_ptr(a) ((struct sockaddr_storage *)(a)) + +#define ZT_InetAddress_ptr_cast_const_sockaddr_ptr(a) ((const struct sockaddr *)(a)) +#define ZT_InetAddress_ptr_cast_const_sockaddr_in_ptr(a) ((const struct sockaddr_in *)(a)) +#define ZT_InetAddress_ptr_cast_const_sockaddr_in6_ptr(a) ((const struct sockaddr_in6 *)(a)) +#define ZT_InetAddress_ptr_cast_const_sockaddr_storage_ptr(a) ((const struct sockaddr_storage *)(a)) + +#define ZT_InetAddress_cast_sockaddr_ptr(a) ((struct sockaddr *)(&(a))) +#define ZT_InetAddress_cast_sockaddr_in_ptr(a) ((struct sockaddr_in *)(&(a))) +#define ZT_InetAddress_cast_sockaddr_in6_ptr(a) ((struct sockaddr_in6 *)(&(a))) +#define ZT_InetAddress_cast_sockaddr_storage_ptr(a) ((struct sockaddr_storage *)(&(a))) + +#define ZT_InetAddress_cast_const_sockaddr_ptr(a) ((const struct sockaddr *)(&(a))) +#define ZT_InetAddress_cast_const_sockaddr_in_ptr(a) ((const struct sockaddr_in *)(&(a))) +#define ZT_InetAddress_cast_const_sockaddr_in6_ptr(a) ((const struct sockaddr_in6 *)(&(a))) +#define ZT_InetAddress_cast_const_sockaddr_storage_ptr(a) ((const struct sockaddr_storage *)(&(a))) + +ZT_SDK_API void ZT_InetAddress_clear(ZT_InetAddress *ia); + +/** + * Convert an IP/port pair to a string + * + * @param ia InetAddress to convert + * @param buf Buffer to store result + * @param cap Size of buffer, must be at least 64 bytes + * @return 'buf' is returned + */ +ZT_SDK_API char *ZT_InetAddress_toString(const ZT_InetAddress *ia, char *buf, unsigned int cap); + +ZT_SDK_API int ZT_InetAddress_fromString(ZT_InetAddress *ia, const char *str); + +ZT_SDK_API void ZT_InetAddress_set(ZT_InetAddress *ia, const void *saddr); + +ZT_SDK_API void ZT_InetAddress_setIpBytes(ZT_InetAddress *ia, const void *ipBytes, unsigned int ipLen, unsigned int port); + +ZT_SDK_API void ZT_InetAddress_setPort(ZT_InetAddress *ia, unsigned int port); + +ZT_SDK_API unsigned int ZT_InetAddress_port(const ZT_InetAddress *ia); + +ZT_SDK_API int ZT_InetAddress_isNil(const ZT_InetAddress *ia); + +ZT_SDK_API int ZT_InetAddress_isV4(const ZT_InetAddress *ia); + +ZT_SDK_API int ZT_InetAddress_isV6(const ZT_InetAddress *ia); + +ZT_SDK_API enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress *ia); + +/* ---------------------------------------------------------------------------------------------------------------- */ + + #ifdef __cplusplus } #endif diff --git a/rust-zerotier-core/Cargo.lock b/rust-zerotier-core/Cargo.lock index 8b2048737..52c15d043 100644 --- a/rust-zerotier-core/Cargo.lock +++ b/rust-zerotier-core/Cargo.lock @@ -6,12 +6,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "hex" version = "0.4.2" @@ -24,12 +18,6 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -[[package]] -name = "libc" -version = "0.2.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" - [[package]] name = "num-derive" version = "0.3.3" @@ -77,7 +65,6 @@ dependencies = [ "num-traits", "serde", "serde_json", - "socket2", ] [[package]] @@ -117,17 +104,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e0e9fd577458a4f61fb91fcb559ea2afecc54c934119421f9f5d3d5b1a1057" -dependencies = [ - "cfg-if", - "libc", - "winapi", -] - [[package]] name = "syn" version = "1.0.54" @@ -144,25 +120,3 @@ name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust-zerotier-core/Cargo.toml b/rust-zerotier-core/Cargo.toml index 433654a24..0f0156ea8 100644 --- a/rust-zerotier-core/Cargo.toml +++ b/rust-zerotier-core/Cargo.toml @@ -4,12 +4,9 @@ version = "0.1.0" authors = ["Adam Ierymenko "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] num-traits = "0.2.14" num-derive = "0.3.3" serde = { version = "1", features = ["derive"] } serde_json = "1" hex = "0.4.2" -socket2 = "0.3.18" diff --git a/rust-zerotier-core/src/endpoint.rs b/rust-zerotier-core/src/endpoint.rs index 5d15f3052..7022bf81b 100644 --- a/rust-zerotier-core/src/endpoint.rs +++ b/rust-zerotier-core/src/endpoint.rs @@ -1,6 +1,6 @@ -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use std::mem::MaybeUninit; -use std::os::raw::{c_char, c_int}; +use std::os::raw::{c_char, c_int, c_void}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; @@ -35,9 +35,14 @@ impl Endpoint { } pub fn new_from_string(s: &str) -> Result { + let cs = CString::new(s); + if cs.is_err() { + return Err(ResultCode::ErrorBadParameter); + } + let cs = cs.unwrap(); unsafe { let mut cep: MaybeUninit = MaybeUninit::uninit(); - let ec = ztcore::ZT_Endpoint_fromString(cep.as_mut_ptr(), s.as_ptr() as *const c_char) as i32; + let ec = ztcore::ZT_Endpoint_fromString(cep.as_mut_ptr(), cs.as_ptr()) as i32; if ec == 0 { let epi = cep.assume_init(); return Ok(Endpoint{ @@ -48,6 +53,18 @@ impl Endpoint { return Err(ResultCode::from_i32(ec).unwrap()); } } + + /// Get a reference to the InetAddress in this endpoint or None if this is not of a relevant type. + pub fn as_inetaddress(&self) -> Option<&InetAddress> { + match self.type_ { + EndpointType::Ip | EndpointType::IpUdp | EndpointType::IpTcp | EndpointType::IpHttp => { + unsafe { + Some(InetAddress::transmute_capi(&self.capi.value.ia)) + } + }, + _ => None + } + } } impl ToString for Endpoint { diff --git a/rust-zerotier-core/src/fingerprint.rs b/rust-zerotier-core/src/fingerprint.rs index 7cd7367ea..14e7c96e0 100644 --- a/rust-zerotier-core/src/fingerprint.rs +++ b/rust-zerotier-core/src/fingerprint.rs @@ -1,7 +1,7 @@ use crate::*; use crate::bindings::capi as ztcore; use std::os::raw::{c_char, c_int}; -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use std::mem::MaybeUninit; pub struct Fingerprint { @@ -19,9 +19,14 @@ impl Fingerprint { } pub fn new_from_string(s: &str) -> Result { + let cs = CString::new(s); + if cs.is_err() { + return Err(ResultCode::ErrorBadParameter); + } + let cs = cs.unwrap(); + let mut cfp: MaybeUninit = MaybeUninit::uninit(); unsafe { - let mut cfp: MaybeUninit = MaybeUninit::uninit(); - if ztcore::ZT_Fingerprint_fromString(cfp.as_mut_ptr(), s.as_ptr() as *const c_char) != 0 { + if ztcore::ZT_Fingerprint_fromString(cfp.as_mut_ptr(), cs.as_ptr()) != 0 { let fp = cfp.assume_init(); return Ok(Fingerprint{ address: Address(fp.address), @@ -43,7 +48,7 @@ impl ToString for Fingerprint { }, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int).is_null() { return String::from("(invalid)"); } - return String::from(CStr::from_bytes_with_nul(buf.as_ref()).unwrap().to_str().unwrap()); + return cstr_to_string(buf.as_ptr() as *const c_char, 256); } } } diff --git a/rust-zerotier-core/src/identity.rs b/rust-zerotier-core/src/identity.rs index 76ec78779..eb1069bac 100644 --- a/rust-zerotier-core/src/identity.rs +++ b/rust-zerotier-core/src/identity.rs @@ -1,4 +1,4 @@ -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use std::mem::MaybeUninit; use std::os::raw::*; @@ -49,7 +49,12 @@ impl Identity { /// Construct from a string representation of this identity. pub fn new_from_string(s: &str) -> Result { unsafe { - let id = ztcore::ZT_Identity_fromString(s.as_ptr() as *const c_char); + let cs = CString::new(s); + if cs.is_err() { + return Err(ResultCode::ErrorBadParameter); + } + let cs = cs.unwrap(); + let id = ztcore::ZT_Identity_fromString(cs.as_ptr()); if id.is_null() { return Err(ResultCode::ErrorBadParameter); } diff --git a/rust-zerotier-core/src/inetaddress.rs b/rust-zerotier-core/src/inetaddress.rs new file mode 100644 index 000000000..37d18e91c --- /dev/null +++ b/rust-zerotier-core/src/inetaddress.rs @@ -0,0 +1,140 @@ +use std::ffi::CString; +use std::mem::{MaybeUninit, transmute, size_of}; + +use serde::{Deserialize, Serialize}; + +use crate::*; +use crate::bindings::capi as ztcore; + +/// Opaque structure that can hold an IPv4 or IPv6 address. +pub struct InetAddress { + // This must be the same size as ZT_InetAddress in zerotier.h. This is + // checked in tests. + bits: [u64; (ztcore::ZT_SOCKADDR_STORAGE_SIZE / 8) as usize] +} + +impl InetAddress { + #[inline(always)] + pub fn new() -> InetAddress { + InetAddress { + bits: [0; (ztcore::ZT_SOCKADDR_STORAGE_SIZE / 8) as usize] + } + } + + pub fn new_from_string(s: &str) -> Option { + let mut a = InetAddress::new(); + let cs = CString::new(s); + if cs.is_ok() { + let cs = cs.unwrap(); + unsafe { + if ztcore::ZT_InetAddress_fromString(a.as_mut_ptr(), cs.as_ptr()) == 0 { + return None + } + } + } + Some(a) + } + + #[inline(always)] + pub(crate) unsafe fn transmute_capi(a: &ztcore::ZT_InetAddress) -> &InetAddress { + unsafe { + transmute(a) + } + } + + pub(crate) fn new_from_capi(a: ztcore::ZT_InetAddress) -> Option { + if a.bits[0] != 0 { + Some(InetAddress { + bits: a.bits + }) + } else { + None + } + } + + pub fn clear(&mut self) { + for i in self.bits.iter_mut() { + *i = 0; + } + } + + #[inline(always)] + pub fn is_nil(&self) -> bool { + self.bits[0] == 0 // if ss_family != 0, this will not be zero + } + + #[inline(always)] + pub(crate) fn as_ptr(&self) -> *const ztcore::ZT_InetAddress { + unsafe { + transmute(self as *const InetAddress) + } + } + + #[inline(always)] + pub(crate) fn as_mut_ptr(&mut self) -> *mut ztcore::ZT_InetAddress { + unsafe { + transmute(self as *mut InetAddress) + } + } +} + +impl ToString for InetAddress { + fn to_string(&self) -> String { + let mut buf: MaybeUninit<[c_char; 128]> = MaybeUninit::uninit(); + unsafe { + return cstr_to_string(ztcore::ZT_InetAddress_toString(self.as_ptr(), (*buf.as_mut_ptr()).as_mut_ptr(), 128), 128); + } + } +} + +impl From<&str> for InetAddress { + fn from(s: &str) -> InetAddress { + let a = InetAddress::new_from_string(s); + if a.is_none() { + return InetAddress::new(); + } + a.unwrap() + } +} + +impl serde::Serialize for InetAddress { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { + serializer.serialize_str(self.to_string().as_str()) + } +} + +struct InetAddressVisitor; + +impl<'de> serde::de::Visitor<'de> for InetAddressVisitor { + type Value = InetAddress; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("InetAddress value in string form") + } + + fn visit_str(self, s: &str) -> Result where E: serde::de::Error { + let id = InetAddress::new_from_string(s); + if id.is_none() { + return Err(serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self)); + } + return Ok(id.unwrap() as Self::Value); + } +} + +impl<'de> serde::Deserialize<'de> for InetAddress { + fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { + deserializer.deserialize_str(InetAddressVisitor) + } +} + +#[cfg(test)] +mod tests { + use std::mem::{size_of, zeroed}; + + use crate::*; + + #[test] + fn type_sizes() { + assert_eq!(size_of::(), size_of::()); + } +} diff --git a/rust-zerotier-core/src/lib.rs b/rust-zerotier-core/src/lib.rs index 1c0e33f96..78a48c5b5 100644 --- a/rust-zerotier-core/src/lib.rs +++ b/rust-zerotier-core/src/lib.rs @@ -1,3 +1,5 @@ +#[link(name = ":../../build/core/libzt_core.a")] + use std::os::raw::{c_char, c_int}; use num_derive::{FromPrimitive, ToPrimitive}; @@ -9,6 +11,7 @@ mod fingerprint; mod endpoint; mod certificate; mod networkid; +mod inetaddress; mod locator; mod path; mod peer; @@ -26,6 +29,7 @@ pub use fingerprint::Fingerprint; pub use endpoint::*; pub use certificate::*; pub use networkid::NetworkId; +pub use inetaddress::*; pub use locator::*; pub use path::Path; pub use peer::Peer; diff --git a/rust-zerotier-core/src/locator.rs b/rust-zerotier-core/src/locator.rs index a0d7a0052..a00ad30e7 100644 --- a/rust-zerotier-core/src/locator.rs +++ b/rust-zerotier-core/src/locator.rs @@ -1,7 +1,7 @@ use crate::*; use crate::bindings::capi as ztcore; use std::os::raw::{c_char, c_int, c_uint}; -use std::ffi::CStr; +use std::ffi::CString; pub struct Locator { pub(crate) capi: *const ztcore::ZT_Locator, @@ -19,7 +19,12 @@ impl Locator { pub fn new_from_string(s: &str) -> Result { unsafe { - let l = ztcore::ZT_Locator_fromString(s.as_ptr() as *const c_char); + let cs = CString::new(s); + if cs.is_err() { + return Err(ResultCode::ErrorBadParameter); + } + let cs = cs.unwrap(); + let l = ztcore::ZT_Locator_fromString(cs.as_ptr()); if l.is_null() { return Err(ResultCode::ErrorBadParameter); } @@ -72,7 +77,7 @@ impl ToString for Locator { if ztcore::ZT_Locator_toString(self.capi, buf.as_mut_ptr() as *mut c_char, buf.len() as c_int).is_null() { return String::from("(invalid)"); } - return String::from(CStr::from_bytes_with_nul(buf.as_ref()).unwrap().to_str().unwrap()); + return cstr_to_string(buf.as_ptr() as *const c_char, 4096); } } } diff --git a/rust-zerotier-core/src/node.rs b/rust-zerotier-core/src/node.rs index fd154fe7a..12402bd7f 100644 --- a/rust-zerotier-core/src/node.rs +++ b/rust-zerotier-core/src/node.rs @@ -8,15 +8,16 @@ use std::sync::*; use std::sync::atomic::*; use std::time::Duration; +use serde::{Deserialize, Serialize}; use num_traits::FromPrimitive; -use socket2::SockAddr; use crate::*; use crate::bindings::capi as ztcore; +use crate::inetaddress::InetAddress; const NODE_BACKGROUND_MIN_DELAY: i64 = 250; -#[allow(non_snake_case)] +#[derive(Serialize, Deserialize)] pub struct NodeStatus { pub address: Address, pub identity: Identity, @@ -110,7 +111,7 @@ extern "C" fn zt_wire_packet_send_function( uptr: *mut c_void, tptr: *mut c_void, local_socket: i64, - sock_addr: *const ztcore::sockaddr_storage, + sock_addr: *const ztcore::ZT_InetAddress, data: *const c_void, data_size: c_uint, packet_ttl: c_uint @@ -124,7 +125,7 @@ extern "C" fn zt_path_check_function( address: u64, identity: *const ztcore::ZT_Identity, local_socket: i64, - sock_addr: *const ztcore::sockaddr_storage + sock_addr: *const ztcore::ZT_InetAddress ) {} #[no_mangle] @@ -135,7 +136,7 @@ extern "C" fn zt_path_lookup_function( address: u64, identity: *const ztcore::ZT_Identity, sock_family: c_int, - sock_addr: *mut ztcore::sockaddr_storage + sock_addr: *mut ztcore::ZT_InetAddress ) {} impl Node { @@ -248,11 +249,11 @@ impl Node { } #[inline(always)] - pub fn process_wire_packet(&self, local_socket: i64, remote_address: &SockAddr, data: &mut Buffer) -> ResultCode { + pub fn process_wire_packet(&self, local_socket: i64, remote_address: &InetAddress, data: &mut Buffer) -> ResultCode { let current_time = self.now.get(); let mut next_task_deadline: i64 = current_time; unsafe { - return ResultCode::from_u32(ztcore::ZT_Node_processWirePacket(self.capi.get(), null_mut(), current_time, local_socket, remote_address.as_ptr() as *const ztcore::sockaddr_storage, data.zt_core_buf as *const c_void, data.data_size as u32, 1, &mut next_task_deadline as *mut i64) as u32).unwrap_or(ResultCode::ErrorInternalNonFatal); + return ResultCode::from_u32(ztcore::ZT_Node_processWirePacket(self.capi.get(), null_mut(), current_time, local_socket, remote_address.as_ptr() as *const ztcore::ZT_InetAddress, data.zt_core_buf as *const c_void, data.data_size as u32, 1, &mut next_task_deadline as *mut i64) as u32).unwrap_or(ResultCode::ErrorInternalNonFatal); } } diff --git a/rust-zerotier-core/src/virtualnetworkconfig.rs b/rust-zerotier-core/src/virtualnetworkconfig.rs index b1eae7428..7a562c19d 100644 --- a/rust-zerotier-core/src/virtualnetworkconfig.rs +++ b/rust-zerotier-core/src/virtualnetworkconfig.rs @@ -1,20 +1,75 @@ -use std::ffi::CStr; use std::mem::{size_of, transmute, zeroed}; -use std::os::raw::{c_void, c_char}; +use serde::{Deserialize, Serialize}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; -use socket2::SockAddr; use crate::*; use crate::bindings::capi as ztcore; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(FromPrimitive,ToPrimitive)] pub enum VirtualNetworkType { Private = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PRIVATE as isize, Public = ztcore::ZT_VirtualNetworkType_ZT_NETWORK_TYPE_PUBLIC as isize } +impl VirtualNetworkType { + pub fn to_str(&self) -> &str { + match *self { + //VirtualNetworkType::Private => "PRIVATE", + VirtualNetworkType::Public => "PUBLIC", + _ => "PRIVATE" + } + } +} + +impl From<&str> for VirtualNetworkType { + fn from(s: &str) -> VirtualNetworkType { + match s.to_ascii_lowercase().as_str() { + //"requesting_configuration" | "requestingconfiguration" => VirtualNetworkStatus::RequestingConfiguration, + "public" => VirtualNetworkType::Public, + _ => VirtualNetworkType::Private + } + } +} + +impl ToString for VirtualNetworkType { + #[inline(always)] + fn to_string(&self) -> String { + String::from(self.to_str()) + } +} + +impl serde::Serialize for VirtualNetworkType { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { + serializer.serialize_str(self.to_str()) + } +} + +struct VirtualNetworkTypeVisitor; + +impl<'de> serde::de::Visitor<'de> for VirtualNetworkTypeVisitor { + type Value = VirtualNetworkType; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("VirtualNetworkType value in string form") + } + + fn visit_str(self, s: &str) -> Result where E: serde::de::Error { + Ok(VirtualNetworkType::from(s)) + } +} + +impl<'de> serde::Deserialize<'de> for VirtualNetworkType { + fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { + deserializer.deserialize_str(VirtualNetworkTypeVisitor) + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(FromPrimitive,ToPrimitive)] pub enum VirtualNetworkRuleType { ActionDrop = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_ACTION_DROP as isize, @@ -54,6 +109,8 @@ pub enum VirtualNetworkRuleType { MatchIntegerRange = ztcore::ZT_VirtualNetworkRuleType_ZT_NETWORK_RULE_MATCH_INTEGER_RANGE as isize } +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(FromPrimitive,ToPrimitive)] pub enum VirtualNetworkConfigOperation { Up = ztcore::ZT_VirtualNetworkConfigOperation_ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP as isize, @@ -62,6 +119,8 @@ pub enum VirtualNetworkConfigOperation { Destroy = ztcore::ZT_VirtualNetworkConfigOperation_ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY as isize } +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #[derive(FromPrimitive,ToPrimitive)] pub enum VirtualNetworkStatus { RequestingConfiguration = ztcore::ZT_VirtualNetworkStatus_ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION as isize, @@ -70,14 +129,73 @@ pub enum VirtualNetworkStatus { NotFound = ztcore::ZT_VirtualNetworkStatus_ZT_NETWORK_STATUS_NOT_FOUND as isize } +impl VirtualNetworkStatus { + pub fn to_str(&self) -> &str { + match *self { + VirtualNetworkStatus::RequestingConfiguration => "REQUESTING_CONFIGURATION", + VirtualNetworkStatus::Ok => "OK", + VirtualNetworkStatus::AccessDenied => "ACCESS_DENIED", + VirtualNetworkStatus::NotFound => "NOT_FOUND" + } + } +} + +impl From<&str> for VirtualNetworkStatus { + fn from(s: &str) -> VirtualNetworkStatus { + match s.to_ascii_lowercase().as_str() { + //"requesting_configuration" | "requestingconfiguration" => VirtualNetworkStatus::RequestingConfiguration, + "ok" => VirtualNetworkStatus::Ok, + "access_denied" | "accessdenied" => VirtualNetworkStatus::AccessDenied, + "not_found" | "notfound" => VirtualNetworkStatus::NotFound, + _ => VirtualNetworkStatus::RequestingConfiguration + } + } +} + +impl ToString for VirtualNetworkStatus { + #[inline(always)] + fn to_string(&self) -> String { + String::from(self.to_str()) + } +} + +impl serde::Serialize for VirtualNetworkStatus { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { + serializer.serialize_str(self.to_str()) + } +} + +struct VirtualNetworkStatusVisitor; + +impl<'de> serde::de::Visitor<'de> for VirtualNetworkStatusVisitor { + type Value = VirtualNetworkStatus; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("VirtualNetworkStatus value in string form") + } + + fn visit_str(self, s: &str) -> Result where E: serde::de::Error { + Ok(VirtualNetworkStatus::from(s)) + } +} + +impl<'de> serde::Deserialize<'de> for VirtualNetworkStatus { + fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { + deserializer.deserialize_str(VirtualNetworkStatusVisitor) + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#[derive(Serialize, Deserialize)] pub struct VirtualNetworkRoute { - pub target: Option, - pub via: Option, + pub target: Option, + pub via: Option, pub flags: u16, pub metric: u16 } -#[allow(non_snake_case)] +#[derive(Serialize, Deserialize)] pub struct VirtualNetworkConfig { pub nwid: NetworkId, pub mac: MAC, @@ -92,63 +210,45 @@ pub struct VirtualNetworkConfig { #[serde(rename = "netconfRevision")] pub netconf_revision: u64, #[serde(rename = "assignedAddresses")] - pub assigned_addresses: Vec, + pub assigned_addresses: Vec, pub routes: Vec } -const SIZEOF_SOCKADDR_IN: ztcore::socklen_t = size_of::() as ztcore::socklen_t; -const SIZEOF_SOCKADDR_IN6: ztcore::socklen_t = size_of::() as ztcore::socklen_t; - -/// Obtain a socket2::SockAddr from a C struct sockaddr_storage as used in the ZeroTier core. -pub(crate) fn sockaddr_from_capi(ss: &ztcore::sockaddr_storage) -> Option { - // The transmute() calls in here are to work around the fact that socket2 - // uses sockaddr_storage from the libc crate, while ztcore uses it as - // generated from bindgen from the system headers. It's the same thing but - // Rust's type system doesn't know that. - match ss.ss_family as u32 { - ztcore::AF_INET => { unsafe { Some(SockAddr::from_raw_parts(transmute(ss as *const ztcore::sockaddr_storage), transmute(SIZEOF_SOCKADDR_IN))) } }, - ztcore::AF_INET6 => { unsafe { Some(SockAddr::from_raw_parts(transmute(ss as *const ztcore::sockaddr_storage), transmute(SIZEOF_SOCKADDR_IN6))) } }, - _ => None - } -} - impl VirtualNetworkConfig { pub(crate) fn new_from_capi(vnc: &ztcore::ZT_VirtualNetworkConfig) -> VirtualNetworkConfig { - unsafe { - let mut aa: Vec = Vec::new(); - let saptr = vnc.assignedAddresses.as_ptr(); - for i in 0..vnc.assignedAddressCount as isize { - let sa = sockaddr_from_capi(&*saptr.offset(i)); - if sa.is_some() { - aa.push(sa.unwrap()); - } + let mut aa: Vec = Vec::new(); + let saptr = vnc.assignedAddresses.as_ptr(); + for i in 0..vnc.assignedAddressCount as isize { + let a = InetAddress::new_from_capi(unsafe { *saptr.offset(i) }); + if a.is_some() { + aa.push(a.unwrap()); } + } - let mut rts: Vec = Vec::new(); - let rtptr = vnc.routes.as_ptr(); - for i in 0..vnc.routeCount as isize { - let r = *rtptr.offset(i); - rts.push(VirtualNetworkRoute{ - target: sockaddr_from_capi(&r.target), - via: sockaddr_from_capi(&r.via), - flags: r.flags, - metric: r.metric - }) - } + let mut rts: Vec = Vec::new(); + let rtptr = vnc.routes.as_ptr(); + for i in 0..vnc.routeCount as isize { + let r = unsafe { *rtptr.offset(i) }; + rts.push(VirtualNetworkRoute{ + target: InetAddress::new_from_capi(r.target), + via: InetAddress::new_from_capi(r.via), + flags: r.flags, + metric: r.metric + }) + } - return VirtualNetworkConfig{ - nwid: NetworkId(vnc.nwid), - mac: MAC(vnc.mac), - name: String::from(CStr::from_ptr(vnc.name.as_ptr() as *const c_char).to_str().unwrap_or("")), - status: FromPrimitive::from_u32(vnc.status as u32).unwrap(), - type_: FromPrimitive::from_u32(vnc.type_ as u32).unwrap(), - mtu: vnc.mtu as u32, - bridge: vnc.bridge != 0, - broadcast_enabled: vnc.broadcastEnabled != 0, - netconf_revision: vnc.netconfRevision as u64, - assigned_addresses: aa, - routes: rts - } + return VirtualNetworkConfig{ + nwid: NetworkId(vnc.nwid), + mac: MAC(vnc.mac), + name: unsafe { cstr_to_string(vnc.name.as_ptr(), vnc.name.len() as isize) }, + status: FromPrimitive::from_u32(vnc.status as u32).unwrap(), + type_: FromPrimitive::from_u32(vnc.type_ as u32).unwrap(), + mtu: vnc.mtu as u32, + bridge: vnc.bridge != 0, + broadcast_enabled: vnc.broadcastEnabled != 0, + netconf_revision: vnc.netconfRevision as u64, + assigned_addresses: aa, + routes: rts } } }