*/
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
*
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);
# include <sodium.h>
#endif
+#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
+# include <ws2tcpip.h>
+#elif UDPC_PLATFORM == UDPC_PLATFORM_MAC || UDPC_PLATFORM_LINUX
+# include <netdb.h>
+#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)
#if UDPC_PLATFORM == UDPC_PLATFORM_WINDOWS
#include <netioapi.h>
-
-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 <sys/ioctl.h>
#include <net/if.h>
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()) {
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);
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;
}
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);
+}
puts("-ll <addr> - listen addr");
puts("-lp <port> - listen port");
puts("-cl <addr> - connection addr (client only)");
+ puts("-clh <hostname> - connection hostname (client only)");
puts("-cp <port> - connection port (client only)");
puts("-t <tick_count>");
puts("-n - do not add payload to packets");
puts("-ck <pubkey_file> - add pubkey to whitelist");
puts("-sk <pubkey> <seckey> - start with pub/sec key pair");
puts("-p <\"fallback\" or \"strict\"> - set auth policy");
+ puts("--hostname <hostname> - dont run test, just lookup hostname");
}
void sleep_seconds(unsigned int seconds) {
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;
} 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];
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();
} 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");
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) {