diff --git a/src/UDPC.h b/src/UDPC.h index 2e6f451..89e67e5 100644 --- a/src/UDPC.h +++ b/src/UDPC.h @@ -281,6 +281,8 @@ UDPC_ConnectionId UDPC_create_id_anyaddr(uint16_t port); */ UDPC_ConnectionId UDPC_create_id_easy(const char *addrString, uint16_t port); +UDPC_ConnectionId UDPC_create_id_hostname(const char *hostname, uint16_t port); + /*! * \brief Creates an UDPC_HContext that holds state for connections * @@ -678,6 +680,8 @@ UDPC_IPV6_ADDR_TYPE UDPC_strtoa(const char *addrStr); UDPC_IPV6_ADDR_TYPE UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out); +UDPC_IPV6_ADDR_TYPE UDPC_a4toa6(uint32_t a4_be); + int UDPC_is_big_endian(); uint16_t UDPC_no16i(uint16_t i); uint32_t UDPC_no32i(uint32_t i); diff --git a/src/UDPC_Defines.hpp b/src/UDPC_Defines.hpp index f97dc12..ff57201 100644 --- a/src/UDPC_Defines.hpp +++ b/src/UDPC_Defines.hpp @@ -39,6 +39,12 @@ # include #endif +#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS +# include +#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM_LINUX +# include +#endif + #define UDPC_MIN_HEADER_SIZE 20 #define UDPC_CON_HEADER_SIZE (UDPC_MIN_HEADER_SIZE+4) #define UDPC_CCL_HEADER_SIZE (UDPC_MIN_HEADER_SIZE+4+crypto_sign_PUBLICKEYBYTES+12) diff --git a/src/UDPConnection.cpp b/src/UDPConnection.cpp index 39ff0ac..0829ed2 100644 --- a/src/UDPConnection.cpp +++ b/src/UDPConnection.cpp @@ -19,21 +19,8 @@ #if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS #include - -static const UDPC_IPV6_ADDR_TYPE in6addr_any = UDPC_IPV6_ADDR_TYPE{{ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 -}}; -static const UDPC_IPV6_ADDR_TYPE in6addr_loopback = UDPC_IPV6_ADDR_TYPE{{ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1 -}}; - typedef int socklen_t; + #elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX #include #include @@ -319,6 +306,12 @@ void UDPC::Context::update_impl() { switch(event.type) { case UDPC_ET_REQUEST_CONNECT: { + if(!isAcceptNewConnections.load()) { + UDPC_CHECK_LOG(this, UDPC_LoggingType::UDPC_WARNING, + "Ignoring connection request because " + "accept-new-connections flag is false"); + break; + } unsigned char *sk = nullptr; unsigned char *pk = nullptr; if(keysSet.load()) { @@ -1942,6 +1935,51 @@ UDPC_ConnectionId UDPC_create_id_easy(const char *addrString, uint16_t port) { return result; } +UDPC_ConnectionId UDPC_create_id_hostname(const char *hostname, uint16_t port) { + UDPC_ConnectionId result; + std::memset(&result, 0, sizeof(UDPC_ConnectionId)); + result.port = port; + +#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS + WORD wVersionRequested = MAKEWORD(2, 2); + WSADATA wsaData; + if(WSAStartup(wVersionRequested, &wsaData) != 0) { + fprintf(stderr, "Failed to initialize Winsock\n"); + return result; + } +#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM == UDPC_PLATFORM_LINUX +#endif + addrinfo hints; + std::memset(&hints, 0, sizeof(addrinfo)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + addrinfo *lookupResult; + int error = getaddrinfo(hostname, nullptr, &hints, &lookupResult); + + if(error == 0) { + if(lookupResult->ai_family == AF_INET) { + sockaddr_in *a4 = (sockaddr_in*)lookupResult->ai_addr; + result.addr = UDPC_a4toa6(a4->sin_addr.s_addr); + } else if(lookupResult->ai_family == AF_INET6) { + sockaddr_in6 *a6 = (sockaddr_in6*)lookupResult->ai_addr; + result.addr = a6->sin6_addr; + } else { + result.addr = in6addr_loopback; + } + freeaddrinfo(lookupResult); + } else { + result.addr = in6addr_loopback; + } + +#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS + WSACleanup(); +#endif + + return result; +} + UDPC_HContext UDPC_init(UDPC_ConnectionId listenId, int isClient, int isUsingLibsodium) { UDPC::Context *ctx = new UDPC::Context(false); ctx->flags.set(1, isClient != 0); @@ -3013,6 +3051,31 @@ UDPC_IPV6_ADDR_TYPE UDPC_strtoa_link(const char *addrStr, uint32_t *linkId_out) return result; } +UDPC_IPV6_ADDR_TYPE UDPC_a4toa6(uint32_t a4_be) { + if(a4_be == 0) { + return in6addr_any; + } + + uint32_t a4 = ntohl(a4_be); + + if(a4 == 0x7F000001) { + return in6addr_loopback; + } + + UDPC_IPV6_ADDR_TYPE result; + for(unsigned int i = 0; i < 10; ++i) { + UDPC_IPV6_ADDR_SUB(result)[i] = 0; + } + UDPC_IPV6_ADDR_SUB(result)[10] = 0xFF; + UDPC_IPV6_ADDR_SUB(result)[11] = 0xFF; + + for(unsigned int i = 0; i < 4; ++i) { + UDPC_IPV6_ADDR_SUB(result)[12 + i] = *((uint8_t*)&a4 + (3 - i)); + } + + return result; +} + int UDPC_is_big_endian() { return UDPC::isBigEndian() ? 1 : 0; } diff --git a/src/test/TestUDPC.cpp b/src/test/TestUDPC.cpp index 6c7ecd6..e0e0f76 100644 --- a/src/test/TestUDPC.cpp +++ b/src/test/TestUDPC.cpp @@ -318,3 +318,13 @@ TEST(UDPC, NetworkOrderEndianness) { EXPECT_EQ(ll, 0x4000001010008040); } } + +TEST(UDPC, a4toa6) { + EXPECT_EQ(UDPC_a4toa6(0), in6addr_any); + uint32_t a4 = htonl(0x7F000001); + EXPECT_EQ(UDPC_a4toa6(a4), in6addr_loopback); + + UDPC_IPV6_ADDR_TYPE a6 = UDPC_strtoa("::FFFF:0102:0304"); + a4 = htonl(0x01020304); + EXPECT_EQ(UDPC_a4toa6(a4), a6); +} diff --git a/src/test/UDPC_NetworkTest.c b/src/test/UDPC_NetworkTest.c index 7b6c2db..b6d2cbc 100644 --- a/src/test/UDPC_NetworkTest.c +++ b/src/test/UDPC_NetworkTest.c @@ -19,6 +19,7 @@ void usage() { puts("-ll - listen addr"); puts("-lp - listen port"); puts("-cl - connection addr (client only)"); + puts("-clh - connection hostname (client only)"); puts("-cp - connection port (client only)"); puts("-t "); puts("-n - do not add payload to packets"); @@ -28,6 +29,7 @@ void usage() { puts("-ck - add pubkey to whitelist"); puts("-sk - start with pub/sec key pair"); puts("-p <\"fallback\" or \"strict\"> - set auth policy"); + puts("--hostname - dont run test, just lookup hostname"); } void sleep_seconds(unsigned int seconds) { @@ -48,6 +50,7 @@ int main(int argc, char **argv) { const char *listenAddr = NULL; const char *listenPort = NULL; const char *connectionAddr = NULL; + const char *connectionHostname = NULL; const char *connectionPort = NULL; unsigned int tickLimit = 15; int noPayload = 0; @@ -77,6 +80,9 @@ int main(int argc, char **argv) { } else if(strcmp(argv[0], "-cl") == 0 && argc > 1) { --argc; ++argv; connectionAddr = argv[0]; + } else if(strcmp(argv[0], "-clh") == 0 && argc > 1) { + --argc; ++argv; + connectionHostname = argv[0]; } else if(strcmp(argv[0], "-cp") == 0 && argc > 1) { --argc; ++argv; connectionPort = argv[0]; @@ -137,6 +143,16 @@ int main(int argc, char **argv) { usage(); return 1; } + } else if(strcmp(argv[0], "--hostname") == 0 && argc > 1) { + --argc; ++argv; + UDPC_ConnectionId id = UDPC_create_id_hostname(argv[0], 9000); + + UDPC_HContext ctx = UDPC_init(UDPC_create_id_easy("::1", 9000), 0, 0); + const char *str = UDPC_atostr(ctx, id.addr); + printf("Got addr \"%s\" for hostname \"%s\"\n", str, argv[0]); + UDPC_destroy(ctx); + + return 0; } else { printf("ERROR: invalid argument \"%s\"\n", argv[0]); usage(); @@ -204,8 +220,8 @@ int main(int argc, char **argv) { } else if(!listenPort) { puts("ERROR: listenPort was not specified"); return 1; - } else if(isClient && !connectionAddr) { - puts("ERROR: connectionAddr was not specified"); + } else if(isClient && !connectionAddr && !connectionHostname) { + puts("ERROR: connectionAddr or connectionHostname was not specified"); return 1; } else if(isClient && !connectionPort) { puts("ERROR: connectionPort was not specified"); @@ -220,7 +236,15 @@ int main(int argc, char **argv) { listenId = UDPC_create_id_easy(listenAddr, atoi(listenPort)); } if(isClient) { - connectionId = UDPC_create_id_easy(connectionAddr, atoi(connectionPort)); + if(connectionAddr) { + connectionId = UDPC_create_id_easy(connectionAddr, atoi(connectionPort)); + } else /* if(connectionHostname) */ { + connectionId = UDPC_create_id_hostname(connectionHostname, atoi(connectionPort)); + if(memcmp(&connectionId.addr, &in6addr_loopback, 16) == 0) { + puts("ERROR: Failed to resolve hostname"); + return 1; + } + } } UDPC_HContext context = UDPC_init(listenId, isClient, isLibSodiumEnabled); if(!context) {