diff --git a/tests/posix_netdb/Makefile b/tests/posix_netdb/Makefile new file mode 100644 index 0000000000000..217229de9e696 --- /dev/null +++ b/tests/posix_netdb/Makefile @@ -0,0 +1,43 @@ +include ../Makefile.tests_common + +WIFI_SSID ?= "WIFI_SSID" +WIFI_PASS ?= "WIFI_PASS" + +USEMODULE += ztimer +USEMODULE += ztimer_sec + +USEMODULE += posix_netdb + +USEMODULE += auto_init_sock_dns + +LWIP_IPV4 ?= 1 +LWIP_IPV6 ?= 1 + +USEMODULE += lwip +USEMODULE += lwip_netdev + +ifneq (0,$(LWIP_IPV4)) + USEMODULE += ipv4_addr + USEMODULE += lwip_arp + USEMODULE += lwip_ipv4 + USEMODULE += lwip_dhcp_auto + CFLAGS += -DETHARP_SUPPORT_STATIC_ENTRIES=1 +endif + +ifneq (0,$(LWIP_IPV6)) + USEMODULE += ipv6_addr + USEMODULE += lwip_ipv6 + USEMODULE += lwip_ipv6_autoconfig +endif + +# The test requires some setup (active internet connection) so it cannot +# currently be run +TEST_ON_CI_BLACKLIST += all + +include $(RIOTBASE)/Makefile.include + +# needs to be put after "include $(RIOTBASE)/Makefile.include" +ifneq (,$(filter arch_esp,$(FEATURES_USED))) + CFLAGS += -DESP_WIFI_SSID=\"$(WIFI_SSID)\" + CFLAGS += -DESP_WIFI_PASS=\"$(WIFI_PASS)\" +endif diff --git a/tests/posix_netdb/Makefile.board.dep b/tests/posix_netdb/Makefile.board.dep new file mode 100644 index 0000000000000..4000952c2801c --- /dev/null +++ b/tests/posix_netdb/Makefile.board.dep @@ -0,0 +1,9 @@ +# Put board specific dependencies here + +ifneq (,$(filter arch_esp,$(FEATURES_USED))) + USEMODULE += esp_wifi +endif + +ifeq ($(BOARD),native) + USEMODULE += netdev_default +endif diff --git a/tests/posix_netdb/README.md b/tests/posix_netdb/README.md new file mode 100644 index 0000000000000..3dd44692dd1f9 --- /dev/null +++ b/tests/posix_netdb/README.md @@ -0,0 +1,11 @@ +# Test for the posix module *netdb* + +## Overview + +This test application tests the *posix_netdb* module. + +## Run the test + +The test needs an upstream connection to the internet. This is easily done with +the module *esp_wifi* on an esp32. To run the test on an esp32 you can run:\ +`WIFI_SSID='"Your WiFi SSID"' WIFI_PASS='"Your WiFi Password"' BOARD=esp32-wroom-32 make flash test` diff --git a/tests/posix_netdb/main.c b/tests/posix_netdb/main.c new file mode 100644 index 0000000000000..a85941ad3388e --- /dev/null +++ b/tests/posix_netdb/main.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2022 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Posix netdb test application + * + * @author Hendrik van Essen + * + * @} + */ + +#include + +#include +#include + +#include "test_utils/expect.h" +#include "net/sock/dns.h" +#include "ztimer.h" + +#define CALL(fn) puts("Calling " # fn); fn; + +#define HOST_NAME "example.com" +#define HOST_IPV4 "93.184.216.34" +#define HOST_IPV6 "2606:2800:220:1:248:1893:25c8:1946" + +static void test_posix_netdb_getaddrinfo__EAI_BADFLAGS(void) +{ + struct addrinfo *result = NULL; + struct addrinfo hints; + + /* non-existing flag */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= 0xff; + expect(EAI_BADFLAGS == getaddrinfo(HOST_NAME, NULL, &hints, &result)); + freeaddrinfo(result); + + /* invalid combination: AI_CANONNAME && nodename == NULL */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_CANONNAME; + expect(EAI_BADFLAGS == getaddrinfo(NULL, "0", &hints, &result)); + freeaddrinfo(result); +} + +static void test_posix_netdb_getaddrinfo__EAI_FAIL(void) +{ + struct addrinfo *result = NULL; + struct addrinfo hints = { 0 }; + + /* res = NULL */ + expect(EAI_FAIL == getaddrinfo(HOST_NAME, NULL, &hints, NULL)); + + /* nodename too long */ + char nodename[2 * SOCK_DNS_MAX_NAME_LEN] = { 0 }; + for (size_t i = 0; i < sizeof(nodename) - 1; i++) { + nodename[i] = 'a'; + } + expect(EAI_FAIL == getaddrinfo(nodename, NULL, &hints, &result)); + freeaddrinfo(result); +} + +static void test_posix_netdb_getaddrinfo__EAI_FAMILY(void) +{ + struct addrinfo *result = NULL; + struct addrinfo hints; + + /* non-supported address family */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC + AF_INET + AF_INET6; + expect(EAI_FAMILY == getaddrinfo(HOST_NAME, NULL, &hints, &result)); + freeaddrinfo(result); +} + +static void test_posix_netdb_getaddrinfo__EAI_NONAME(void) +{ + struct addrinfo *result = NULL; + struct addrinfo hints; + + /* neither nodename nor servname given */ + memset(&hints, 0, sizeof(struct addrinfo)); + expect(EAI_NONAME == getaddrinfo(NULL, NULL, &hints, &result)); + freeaddrinfo(result); + + /* nodename and servname are empty strings */ + memset(&hints, 0, sizeof(struct addrinfo)); + expect(EAI_NONAME == getaddrinfo("", "", &hints, &result)); + freeaddrinfo(result); + + /* invalid IPv4 address */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_family = AF_INET; + expect(EAI_NONAME == getaddrinfo("1.2.3.4.5", + NULL, &hints, &result)); + freeaddrinfo(result); + + /* invalid IPv6 address */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_family = AF_INET6; + expect(EAI_NONAME == getaddrinfo("1:2:3:4:5:6:7:8:9", + NULL, &hints, &result)); + freeaddrinfo(result); +} + +static void test_posix_netdb_getaddrinfo__EAI_SERVICE(void) +{ + struct addrinfo *result = NULL; + struct addrinfo hints; + + /* non-numeric port */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICSERV; + expect(EAI_SERVICE == getaddrinfo(NULL, "abc", &hints, &result)); + freeaddrinfo(result); + + /* invalid port ( port < 0 ) */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICSERV; + expect(EAI_SERVICE == getaddrinfo(NULL, "-1", &hints, &result)); + freeaddrinfo(result); + + /* invalid port ( port > 65535 ) */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICSERV; + expect(EAI_SERVICE == getaddrinfo(NULL, "70000", &hints, &result)); + freeaddrinfo(result); +} + +static void test_posix_netdb_getaddrinfo__AI_NUMERICHOST(void) +{ + struct addrinfo *result = NULL; + struct addrinfo hints; + +#ifdef MODULE_IPV4_ADDR + char* test_ipv4 = "1.2.3.4"; + char addr4_str[INET_ADDRSTRLEN]; + + /* explicit IPv4 address */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_family = AF_INET; + expect(0 == getaddrinfo(test_ipv4, NULL, &hints, &result)); + expect(result != NULL); + expect(result->ai_family == AF_INET); + expect(NULL != inet_ntop(AF_INET, &((struct sockaddr_in*)(result->ai_addr))->sin_addr, + addr4_str, sizeof(addr4_str))); + expect(strcmp(addr4_str, test_ipv4) == 0); + freeaddrinfo(result); + + /* auto-detect IPv4 address */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + expect(0 == getaddrinfo(test_ipv4, NULL, &hints, &result)); + expect(result != NULL); + expect(result->ai_family == AF_INET); + expect(NULL != inet_ntop(AF_INET, &((struct sockaddr_in*)(result->ai_addr))->sin_addr, + addr4_str, sizeof(addr4_str))); + expect(strcmp(addr4_str, test_ipv4) == 0); + freeaddrinfo(result); +#endif + +#ifdef MODULE_IPV6_ADDR + char* test_ipv6 = "1:2:3:4:5:6:7:8"; + char addr6_str[INET6_ADDRSTRLEN]; + + /* explicit IPv6 address */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_family = AF_INET6; + expect(0 == getaddrinfo(test_ipv6, NULL, &hints, &result)); + expect(result != NULL); + expect(result->ai_family == AF_INET6); + expect(NULL != inet_ntop(AF_INET6, &((struct sockaddr_in6*)(result->ai_addr))->sin6_addr, + addr6_str, sizeof(addr6_str))); + expect(strcmp(addr6_str, test_ipv6) == 0); + freeaddrinfo(result); + + /* auto-detect IPv6 address */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + expect(0 == getaddrinfo(test_ipv6, NULL, &hints, &result)); + expect(result != NULL); + expect(result->ai_family == AF_INET6); + expect(NULL != inet_ntop(AF_INET6, &((struct sockaddr_in6*)(result->ai_addr))->sin6_addr, + addr6_str, sizeof(addr6_str))); + expect(strcmp(addr6_str, test_ipv6) == 0); + freeaddrinfo(result); +#endif +} + +static void test_posix_netdb_getaddrinfo__AI_NUMERICSERV(void) +{ + struct addrinfo *result = NULL; + struct addrinfo hints = { 0 }; + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_flags |= AI_NUMERICSERV; + +#if defined(MODULE_IPV4_ADDR) + char* ip_addr = "1.2.3.4"; + hints.ai_family = AF_INET; +#elif defined(MODULE_IPV6_ADDR) + char* ip_addr = "1:2:3:4:5:6:7:8"; + hints.ai_family = AF_INET6; +#endif + + expect(0 == getaddrinfo(ip_addr, "12345", &hints, &result)); + expect(result != NULL); + /* sockaddr_in or sockaddr_in6 does not matter if we only access the port */ + expect(ntohs(((struct sockaddr_in *)result->ai_addr)->sin_port) == 12345); + freeaddrinfo(result); +} + +static void _test_posix_netdb_getaddrinfo__ai_family(int family) +{ + expect(family == AF_UNSPEC + || family == AF_INET + || family == AF_INET6); + + struct addrinfo *result = NULL; + struct addrinfo hints = { 0 }; + hints.ai_family = family; + + expect(0 == getaddrinfo(HOST_NAME, NULL, &hints, &result)); + expect(result != NULL); + + if (hints.ai_family != AF_UNSPEC) { + expect(result->ai_family == hints.ai_family); + } + + char addr_str[INET6_ADDRSTRLEN]; + + switch (result->ai_family) { + #ifdef MODULE_IPV4_ADDR + case AF_INET: + inet_ntop(AF_INET, &((struct sockaddr_in*)(result->ai_addr))->sin_addr, + addr_str, sizeof(addr_str)); + + expect(strcmp(addr_str, HOST_IPV4) == 0); + break; + #endif + #ifdef MODULE_IPV6_ADDR + case AF_INET6: + inet_ntop(AF_INET6, &((struct sockaddr_in6*)(result->ai_addr))->sin6_addr, + addr_str, sizeof(addr_str)); + + expect(strcmp(addr_str, HOST_IPV6) == 0); + break; + #endif + default: + expect(false); + } + + freeaddrinfo(result); +} + +static void test_posix_netdb_getaddrinfo__AF_UNSPEC(void) +{ +#if defined(MODULE_IPV4_ADDR) && defined(MODULE_IPV6_ADDR) + _test_posix_netdb_getaddrinfo__ai_family(AF_UNSPEC); +#endif +} + +static void test_posix_netdb_getaddrinfo__AF_INET(void) +{ +#ifdef MODULE_IPV4_ADDR + _test_posix_netdb_getaddrinfo__ai_family(AF_INET); +#endif +} + +static void test_posix_netdb_getaddrinfo__AF_INET6(void) +{ +#ifdef MODULE_IPV6_ADDR + _test_posix_netdb_getaddrinfo__ai_family(AF_INET6); +#endif +} + +int main(void) +{ + /* wait until connection has been established */ + ztimer_sleep(ZTIMER_SEC, 5); + + /* test error return values */ + CALL(test_posix_netdb_getaddrinfo__EAI_BADFLAGS()); + CALL(test_posix_netdb_getaddrinfo__EAI_FAIL()); + CALL(test_posix_netdb_getaddrinfo__EAI_FAMILY()); + CALL(test_posix_netdb_getaddrinfo__EAI_NONAME()); + CALL(test_posix_netdb_getaddrinfo__EAI_SERVICE()); + + /* test input flags */ + CALL(test_posix_netdb_getaddrinfo__AI_NUMERICHOST()); + CALL(test_posix_netdb_getaddrinfo__AI_NUMERICSERV()); + /* If the requirements are not met (enabled IPv4, IPv6 or both) some of + * these tests will be simply skipped such that the python test script does + * not need to be adjusted. */ + CALL(test_posix_netdb_getaddrinfo__AF_UNSPEC()); + CALL(test_posix_netdb_getaddrinfo__AF_INET()); + CALL(test_posix_netdb_getaddrinfo__AF_INET6()); + + puts("ALL TESTS SUCCESSFUL"); + + return 0; +} diff --git a/tests/posix_netdb/tests/01-run.py b/tests/posix_netdb/tests/01-run.py new file mode 100755 index 0000000000000..5fa0ced5d5c16 --- /dev/null +++ b/tests/posix_netdb/tests/01-run.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2022 Freie Universität Berlin +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact("Calling test_posix_netdb_getaddrinfo__EAI_BADFLAGS()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__EAI_FAIL()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__EAI_FAMILY()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__EAI_NONAME()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__EAI_SERVICE()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__AI_NUMERICHOST()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__AI_NUMERICSERV()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__AF_UNSPEC()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__AF_INET()") + child.expect_exact("Calling test_posix_netdb_getaddrinfo__AF_INET6()") + child.expect_exact("ALL TESTS SUCCESSFUL") + + +if __name__ == "__main__": + sys.exit(run(testfunc))