Skip to content

Commit

Permalink
feat(sockutls): Add support for gethostname()
Browse files Browse the repository at this point in the history
  • Loading branch information
david-cermak committed Dec 9, 2024
1 parent 32387f7 commit b71bfa9
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 0 deletions.
1 change: 1 addition & 0 deletions components/sock_utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ idf_component_register(SRCS "src/getnameinfo.c"
"src/ifaddrs.c"
"src/gai_strerror.c"
"src/socketpair.c"
"src/gethostname.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES lwip esp_netif)
51 changes: 51 additions & 0 deletions components/sock_utils/include/gethostname.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

#include <unistd.h>
#include "sdkconfig.h"

#ifdef CONFIG_IDF_TARGET_LINUX
// namespace with esp_ on linux to avoid conflict of symbols
#define gethostname esp_gethostname
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Retrieves the hostname of the device.
*
* This function provides the hostname associated with the network interface.
* Unlike the standard behavior where the hostname represents a system-wide name,
* this implementation returns lwip netif hostname (used as a hostname in DHCP packets)
*
* @param[out] name A pointer to a buffer where the hostname will be stored.
* The buffer must be allocated by the caller.
* @param[in] len The size of the buffer pointed to by @p name. The hostname,
* including the null-terminator, must fit within this size.
*
* @return
* - 0 on success
* - -1 on error, with `errno` set to indicate the error:
* - `EINVAL`: Invalid argument, name is NULL, or hostname is too long
*
* @note This implementation retrieves the hostname associated with the network
* interface using the `esp_netif_get_hostname()` function, which in turn
* returns lwip netif hostname used in DHCP packets if LWIP_NETIF_HOSTNAME=1 (hardcoded)
* in ESP-IDF lwip port.
* As there could be multiple network interfaces in the system, the logic tries
* to find the default (active) netif first, then it looks for any (inactive) netif
* with highest route priority. If none of the above found or esp_netif_get_hostname() fails
* for the selected interface, this API returns the default value of `CONFIG_LWIP_LOCAL_HOSTNAME`,
* the local hostname from lwip component configuration menu.
*/
int gethostname(char *name, size_t len);

#ifdef __cplusplus
}
#endif
45 changes: 45 additions & 0 deletions components/sock_utils/src/gethostname.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "gethostname.h"
#include "esp_netif.h"
#include "errno.h"
#include "esp_log.h"


static bool highest_prio_netif(esp_netif_t *netif, void *ctx)
{
esp_netif_t **highest_so_far = ctx;
if (esp_netif_get_route_prio(netif) > esp_netif_get_route_prio(*highest_so_far)) {
*highest_so_far = netif;
}
return false; // go over the entire list to find the netif with the highest route-prio
}

int gethostname(char *name, size_t len)
{
if (name == NULL) {
errno = EINVAL;
return -1;
}
const char *netif_hostname = CONFIG_LWIP_LOCAL_HOSTNAME; // default value from Kconfig

// Find the default netif
esp_netif_t *default_netif = esp_netif_get_default_netif();
if (default_netif == NULL) { // if no netif is active/up -> find the highest prio netif
esp_netif_find_if(highest_prio_netif, &default_netif);
}
// now the `default_netif` could be NULL and/or the esp_netif_get_hostname() could fail
// but we ignore the return code, as if it fails, the `netif_hostname` still holds the default value
esp_netif_get_hostname(default_netif, &netif_hostname);

if (netif_hostname == NULL || len < strlen(netif_hostname) + 1) { // including the NULL terminator
errno = EINVAL;
return -1;
}
strcpy(name, netif_hostname);

Check warning

Code scanning / clang-tidy

Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119 [clang-analyzer-security.insecureAPI.strcpy] Warning

Call to function 'strcpy' is insecure as it does not provide bounding of the memory buffer. Replace unbounded copy functions with analogous functions that support length arguments such as 'strlcpy'. CWE-119 [clang-analyzer-security.insecureAPI.strcpy]
return 0;
}
25 changes: 25 additions & 0 deletions components/sock_utils/test/host/main/test_sock_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "gethostname.h"
#include "ifaddrs.h"
#include "esp_netif.h"
#include "esp_event.h"
Expand Down Expand Up @@ -148,6 +149,30 @@ TEST_CASE("gai_strerror()", "[sock_utils]")
CHECK(str_error != NULL);
}

TEST_CASE("gethostname()", "[sock_utils]")
{
const char *test_netif_name = "station";
char hostname[32];
int ret;

// expect failure
ret = gethostname(hostname, strlen(CONFIG_LWIP_LOCAL_HOSTNAME) - 1);
CHECK(ret == -1);

// happy flow with the default name
ret = gethostname(hostname, sizeof(hostname));
CHECK(ret == 0);
CHECK(strcmp(hostname, CONFIG_LWIP_LOCAL_HOSTNAME) == 0);

// happy flow with the netif name
esp_netif_t *esp_netif = create_test_netif(test_netif_name, 1);
REQUIRE(esp_netif != NULL);
CHECK(esp_netif_set_hostname(esp_netif, test_netif_name) == ESP_OK);
ret = gethostname(hostname, sizeof(hostname));
CHECK(ret == 0);
CHECK(strcmp(hostname, test_netif_name) == 0);
esp_netif_destroy(esp_netif);
}

extern "C" void app_main(void)
{
Expand Down

0 comments on commit b71bfa9

Please sign in to comment.