mgmt: hawkbit: interface support for ip addresses and domain name

Previously, hawkbit interface only supported a url/hostname and a port,
and internally it resolves to an IP address. This does not work for
network layers that rely on NAT64, like OpenThread.  Zephyr's
implementation of `getaddrinfo` is not aware of NAT64.  DNS will resolve
an IPV4 address that needs to be converted to IPV6 with the NAT64
prefix.

This commit alters the Hawkbit interface to allow providing an explicit
domain name as a string via `server_domain`, and an already resolved IP
address as `server_addr`.

This commit changes the usage of `hawkbit_runtime_config.server_addr` to
point to either an IP address or domain name. It adds a new Kconfig
(`HAWKBIT_USE_DOMAIN_NAME`) to specify an explicit domain name and adds
a new variable `hawkbit_runtime_config.server_domain`. If
`HAWKBIT_USE_DOMAIN_NAME` is enabled and a user provides an IP address
to `server_addr`, the user must provide a domain name to
`server_domain`.

Signed-off-by: Neal Jackson <neal@blueirislabs.com>
This commit is contained in:
Neal Jackson 2025-05-01 10:03:26 -06:00 committed by Benjamin Cabé
parent d718b46ddb
commit 2ef1ddea73
3 changed files with 110 additions and 9 deletions

View File

@ -29,8 +29,13 @@
* settings.
*/
struct hawkbit_runtime_config {
/** Server address */
/**
* Server address (domain name or IP address if
* CONFIG_HAWKBIT_USE_DOMAIN_NAME is enabled)
*/
char *server_addr;
/** Server domain name */
char *server_domain;
/** Server port */
uint16_t server_port;
/** Security token */
@ -56,6 +61,27 @@ int hawkbit_set_config(struct hawkbit_runtime_config *config);
*/
struct hawkbit_runtime_config hawkbit_get_config(void);
/**
* @brief Set the hawkBit server hostname.
*
* @param domain_str Server hostname to set.
* @retval 0 on success.
* @retval -EINVAL if string length mismatch for server_domain
* @retval -EAGAIN if probe is currently running.
*/
static inline int hawkbit_set_server_domain(char *domain_str)
{
struct hawkbit_runtime_config set_config = {
.server_addr = NULL,
.server_domain = domain_str,
.server_port = 0,
.auth_token = NULL,
.tls_tag = 0,
};
return hawkbit_set_config(&set_config);
}
/**
* @brief Set the hawkBit server address.
*
@ -68,6 +94,7 @@ static inline int hawkbit_set_server_addr(char *addr_str)
{
struct hawkbit_runtime_config set_config = {
.server_addr = addr_str,
.server_domain = NULL,
.server_port = 0,
.auth_token = NULL,
.tls_tag = 0,
@ -87,6 +114,7 @@ static inline int hawkbit_set_server_port(uint16_t port)
{
struct hawkbit_runtime_config set_config = {
.server_addr = NULL,
.server_domain = NULL,
.server_port = port,
.auth_token = NULL,
.tls_tag = 0,
@ -106,6 +134,7 @@ static inline int hawkbit_set_ddi_security_token(char *token)
{
struct hawkbit_runtime_config set_config = {
.server_addr = NULL,
.server_domain = NULL,
.server_port = 0,
.auth_token = token,
.tls_tag = 0,
@ -125,6 +154,7 @@ static inline int hawkbit_set_tls_tag(sec_tag_t tag)
{
struct hawkbit_runtime_config set_config = {
.server_addr = NULL,
.server_domain = NULL,
.server_port = 0,
.auth_token = NULL,
.tls_tag = tag,
@ -143,6 +173,16 @@ static inline char *hawkbit_get_server_addr(void)
return hawkbit_get_config().server_addr;
}
/**
* @brief Get the hawkBit server hostname.
*
* @return Server hostname.
*/
static inline char *hawkbit_get_server_domain(void)
{
return hawkbit_get_config().server_domain;
}
/**
* @brief Get the hawkBit server port.
*

View File

@ -70,6 +70,22 @@ config HAWKBIT_SET_SETTINGS_RUNTIME
help
Enable to set hawkbit settings at runtime.
config HAWKBIT_USE_DOMAIN_NAME
bool "Use server_domain for domain name instead of server_addr"
depends on HAWKBIT_SET_SETTINGS_RUNTIME
help
Enable to use the server_domain field for TLS and HTTP. If enabled,
server_addr can accept an already resolved IP address, and the domain name
can be provided via server_domain.
config HAWKBIT_DOMAIN_NAME_MAX_LEN
int "The buffer size for storing the domain name string"
default DNS_RESOLVER_MAX_QUERY_LEN if DNS_RESOLVER
default 255
depends on HAWKBIT_USE_DOMAIN_NAME
help
The size for the internal buffer used to hold the domain name string.
choice HAWKBIT_DDI_SECURITY
prompt "hawkBit DDI API authentication modes"
default HAWKBIT_DDI_NO_SECURITY

View File

@ -86,6 +86,9 @@ static struct hawkbit_config {
int32_t action_id;
#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
char server_addr[SERVER_ADDR_LEN + 1];
#ifdef CONFIG_HAWKBIT_USE_DOMAIN_NAME
char server_domain[CONFIG_HAWKBIT_DOMAIN_NAME_MAX_LEN + 1];
#endif
char server_port[sizeof(STRINGIFY(__UINT16_MAX__))];
#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
char ddi_security_token[DDI_SECURITY_TOKEN_SIZE + 1];
@ -97,11 +100,17 @@ static struct hawkbit_config {
} hb_cfg;
#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
#define HAWKBIT_SERVER hb_cfg.server_addr
#ifdef CONFIG_HAWKBIT_USE_DOMAIN_NAME
#define HAWKBIT_SERVER_DOMAIN hb_cfg.server_domain
#else
#define HAWKBIT_SERVER_DOMAIN hb_cfg.server_addr
#endif /* CONFIG_HAWKBIT_USE_DOMAIN_NAME */
#define HAWKBIT_SERVER_ADDR hb_cfg.server_addr
#define HAWKBIT_PORT hb_cfg.server_port
#define HAWKBIT_PORT_INT atoi(hb_cfg.server_port)
#else
#define HAWKBIT_SERVER CONFIG_HAWKBIT_SERVER
#define HAWKBIT_SERVER_ADDR CONFIG_HAWKBIT_SERVER
#define HAWKBIT_SERVER_DOMAIN CONFIG_HAWKBIT_SERVER
#define HAWKBIT_PORT STRINGIFY(CONFIG_HAWKBIT_PORT)
#define HAWKBIT_PORT_INT CONFIG_HAWKBIT_PORT
#endif /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
@ -306,6 +315,22 @@ static int hawkbit_settings_set(const char *name, size_t len, settings_read_cb r
return rc;
}
#ifdef CONFIG_HAWKBIT_USE_DOMAIN_NAME
if (settings_name_steq(name, "server_domain", &next) && !next) {
if (len != sizeof(hb_cfg.server_domain)) {
return -EINVAL;
}
rc = read_cb(cb_arg, &hb_cfg.server_domain, sizeof(hb_cfg.server_domain));
LOG_DBG("<%s> = %s", "hawkbit/server_domain", hb_cfg.server_domain);
if (rc >= 0) {
return 0;
}
return rc;
}
#endif /* CONFIG_HAWKBIT_USE_DOMAIN_NAME */
if (settings_name_steq(name, "server_port", &next) && !next) {
if (len != sizeof(uint16_t)) {
return -EINVAL;
@ -344,6 +369,9 @@ static int hawkbit_settings_set(const char *name, size_t len, settings_read_cb r
}
#else /* CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME */
if (settings_name_steq(name, "server_addr", NULL) ||
#ifdef CONFIG_HAWKBIT_USE_DOMAIN_NAME
settings_name_steq(name, "server_domain", NULL) ||
#endif /* CONFIG_HAWKBIT_USE_DOMAIN_NAME */
settings_name_steq(name, "server_port", NULL) ||
settings_name_steq(name, "ddi_token", NULL)) {
rc = read_cb(cb_arg, NULL, 0);
@ -367,6 +395,9 @@ static int hawkbit_settings_export(int (*cb)(const char *name, const void *value
(void)cb("hawkbit/action_id", &hb_cfg.action_id, sizeof(hb_cfg.action_id));
#ifdef CONFIG_HAWKBIT_SET_SETTINGS_RUNTIME
(void)cb("hawkbit/server_addr", &hb_cfg.server_addr, strlen(hb_cfg.server_addr) + 1);
#ifdef CONFIG_HAWKBIT_USE_DOMAIN_NAME
(void)cb("hawkbit/server_domain", &hb_cfg.server_domain, sizeof(hb_cfg.server_domain));
#endif /* CONFIG_HAWKBIT_USE_DOMAIN_NAME */
uint16_t hawkbit_port = atoi(hb_cfg.server_port);
(void)cb("hawkbit/server_port", &hawkbit_port, sizeof(hawkbit_port));
#ifndef CONFIG_HAWKBIT_DDI_NO_SECURITY
@ -447,7 +478,7 @@ static bool start_http_client(int *hb_sock)
}
while (resolve_attempts--) {
ret = zsock_getaddrinfo(HAWKBIT_SERVER, HAWKBIT_PORT, &hints, &addr);
ret = zsock_getaddrinfo(HAWKBIT_SERVER_ADDR, HAWKBIT_PORT, &hints, &addr);
if (ret == 0) {
break;
}
@ -477,8 +508,8 @@ static bool start_http_client(int *hb_sock)
goto err_sock;
}
if (zsock_setsockopt(*hb_sock, SOL_TLS, TLS_HOSTNAME, HAWKBIT_SERVER,
sizeof(CONFIG_HAWKBIT_SERVER)) < 0) {
if (zsock_setsockopt(*hb_sock, SOL_TLS, TLS_HOSTNAME, HAWKBIT_SERVER_DOMAIN,
sizeof(HAWKBIT_SERVER_DOMAIN)) < 0) {
goto err_sock;
}
#endif /* CONFIG_HAWKBIT_USE_TLS */
@ -798,6 +829,20 @@ int hawkbit_set_config(struct hawkbit_runtime_config *config)
sizeof(hb_cfg.server_addr));
LOG_DBG("configured %s: %s", "hawkbit/server_addr", hb_cfg.server_addr);
}
#ifdef CONFIG_HAWKBIT_USE_DOMAIN_NAME
if (config->server_domain != NULL) {
if (strnlen(config->server_domain, CONFIG_HAWKBIT_DOMAIN_NAME_MAX_LEN + 1)
> CONFIG_HAWKBIT_DOMAIN_NAME_MAX_LEN) {
LOG_ERR("%s too long: %s", "hawkbit/server_domain",
config->server_domain);
return -EINVAL;
}
strncpy(hb_cfg.server_domain, config->server_domain,
sizeof(hb_cfg.server_domain));
LOG_DBG("configured %s: %s", "hawkbit/server_domain",
hb_cfg.server_domain);
}
#endif /* CONFIG_HAWKBIT_USE_DOMAIN_NAME */
if (config->server_port != 0) {
snprintf(hb_cfg.server_port, sizeof(hb_cfg.server_port), "%u",
config->server_port);
@ -831,7 +876,7 @@ int hawkbit_set_config(struct hawkbit_runtime_config *config)
struct hawkbit_runtime_config hawkbit_get_config(void)
{
struct hawkbit_runtime_config config = {
.server_addr = HAWKBIT_SERVER,
.server_addr = HAWKBIT_SERVER_ADDR,
.server_port = HAWKBIT_PORT_INT,
.auth_token = HAWKBIT_DDI_SECURITY_TOKEN,
.tls_tag = HAWKBIT_CERT_TAG,
@ -1059,7 +1104,7 @@ static bool send_request(struct hawkbit_context *hb_context, enum hawkbit_http_r
#endif /* CONFIG_HAWKBIT_DDI_NO_SECURITY */
http_req.url = url_buffer;
http_req.host = HAWKBIT_SERVER;
http_req.host = HAWKBIT_SERVER_DOMAIN;
http_req.port = HAWKBIT_PORT;
http_req.protocol = "HTTP/1.1";
http_req.response = response_cb;
@ -1173,7 +1218,7 @@ void hawkbit_reboot(void)
static bool check_hawkbit_server(void)
{
if (strlen(HAWKBIT_SERVER) == 0) {
if (strlen(HAWKBIT_SERVER_ADDR) == 0) {
if (sizeof(CONFIG_HAWKBIT_SERVER) > 1) {
hawkbit_set_server_addr(CONFIG_HAWKBIT_SERVER);
} else {