Skip to content

mgmt: hawkbit: change hawkbit interface to support directly supplying server ip address #89374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

nealjack
Copy link

@nealjack nealjack commented May 1, 2025

The hawkbit subsystem assumes that getaddrinfo will supply a valid, usable IP address. This isn't the case when using a network layer that depends on NAT64 for IPv4 traffic, like OpenThread. A DNS address obtained while behind a NAT64 requires conversion to IPv6 and adding the NAT64 prefix. As of now, getaddrinfo is not aware of NAT64 and does not handle this. In this case it can be better for the application itself to handle DNS resolution and provide properly prefixed IP addresses to the hawkbit subsystem.

This pull request adds an additional interface field (server_hostname) for the server hostname and changes server_addr to optionally point to an IP address. This is a potentially less confusing naming scheme, as hawkbit does not currently work if an address is provided to server_addr instead of a hostname.

This commit also increases the default DNS name length slightly to accommodate larger hostnames longer than 20 bytes, i.e. (hawkbit.yourcompany.com). I also added some error handling in case a hostname is too long, so the hawkbit interface returns an error instead of quietly using a truncated and incorrect hostname.

This commit also changes how the controllerId is generated based on device id, and disentangles the two. The controllerId is what hawkbit uses to uniquely identify a device, and is not necessarily the same as the device id, and should be fully customizable by the user if needed. Previously, all custom device ids were being prepended with CONFIG_BOARD. When a user selects CONFIG_HAWKBIT_CUSTOM_DEVICE_ID, they should be able to specify the full controllerId used with hawkbit.

@carlescufi
Copy link
Member

Thanks for the PR! Please take a look at our commit message guidelines to find out how to format your commit messages, and at our contribution workflow to understand how to update your Pull Request.

Copy link

github-actions bot commented May 1, 2025

Hello @nealjack, and thank you very much for your first pull request to the Zephyr project!
Our Continuous Integration pipeline will execute a series of checks on your Pull Request commit messages and code, and you are expected to address any failures by updating the PR. Please take a look at our commit message guidelines to find out how to format your commit messages, and at our contribution workflow to understand how to update your Pull Request. If you haven't already, please make sure to review the project's Contributor Expectations and update (by amending and force-pushing the commits) your pull request if necessary.
If you are stuck or need help please join us on Discord and ask your question there. Additionally, you can escalate the review when applicable. 😊

Copy link
Member

@jukkar jukkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the subsys: prefix from commit subject of the both commits, it is not needed

@nealjack nealjack force-pushed the hawkbit_interface branch from 437b27e to c776b00 Compare May 2, 2025 15:40
@maass-hamburg
Copy link
Collaborator

The hawkbit subsystem assumes that getaddrinfo will supply a valid, usable IP address. This isn't the case when using a network layer that depends on NAT64 for IPv4 traffic, like OpenThread. A DNS address obtained while behind a NAT64 requires conversion to IPv6 and adding the NAT64 prefix. As of now, getaddrinfo is not aware of NAT64 and does not handle this. In this case it can be better for the application itself to handle DNS resolution and provide properly prefixed IP addresses to the hawkbit subsystem.

From what I know, when using a NAT64 and you want you want to resolve DNS addresses you should also have a DNS64 server, that will do the transition for you. You could even use a public DNS64 server like the one from Google (https://developers.google.com/speed/public-dns/docs/dns64) for that. The application and the end device should not care and therefore also not know, that there is even a NAT64 with a DNS64 in place. If that's not possible, I think it's better to implement some DNS64 resolver in zsock_getaddrinfo() that can be activated via Kconfig, your proposed way seems like a like a workaround, that is probably bringing more problems. For example changing the meaning of the setting "hawkbit/server_addr" and replacing it with "hawkbit/server_hostname" would lead to braking configurations of users that use that and then update to newest newest zephyr version. As the maintainer of the hawkbit subsystem, I'd like to not have such changes, if they are not necessary.

@maass-hamburg
Copy link
Collaborator

This commit also changes how the controllerId is generated based on device id, and disentangles the two. The controllerId is what hawkbit uses to uniquely identify a device, and is not necessarily the same as the device id, and should be fully customizable by the user if needed. Previously, all custom device ids were being prepended with CONFIG_BOARD. When a user selects CONFIG_HAWKBIT_CUSTOM_DEVICE_ID, they should be able to specify the full controllerId used with hawkbit.

Please note, that changes that are not directly related to each other, should at least go into their own commit.

This is even more unrelated and I recommend splitting it into it's own PR.

@rlubos
Copy link
Collaborator

rlubos commented May 5, 2025

As of now, getaddrinfo is not aware of NAT64 and does not handle this.
I think it's better to implement some DNS64 resolver in zsock_getaddrinfo()

Should it be though? https://man7.org/linux/man-pages/man3/getaddrinfo.3.html makes no mention of DNS64, there is AI_V4MAPPED flag, but it's a different kind of mapping. IMHO I agree that it should be the server responsibility to synthesize the DNS64 AAAA records. Otherwise, we'd be inventing some new, non-standardized API.

@rlubos
Copy link
Collaborator

rlubos commented May 5, 2025

For example changing the meaning of the setting "hawkbit/server_addr" and replacing it with "hawkbit/server_hostname" would lead to braking configurations of users that use that and then update to newest newest zephyr version. As the maintainer of the hawkbit subsystem, I'd like to not have such changes, if they are not necessary.

I agree we should avoid API changes, although I also see a need to be able to specify hostname when using numeric address representation for TLS purposes.

How about we simplify the change set, I. e. keep the current configuration as is (use server_addr for address resolving) to maintain backwards compatibility, but allow to specify server_hostname separately for TLS case, with a fallback to server_addr if not set?

@nealjack
Copy link
Author

nealjack commented May 5, 2025

From what I know, when using a NAT64 and you want you want to resolve DNS addresses you should also have a DNS64 server, that will do the transition for you. You could even use a public DNS64 server like the one from Google (https://developers.google.com/speed/public-dns/docs/dns64) for that.

Unfortunately, the openthread border router implementation does not use a static, well-known NAT64 prefix (https://openthread.io/codelabs/openthread-border-router-nat64#1). It is dynamically generated and potentially different for every network. End devices must query for the prefix and synthesize an IPv6 address using otNat64SynthesizeIp6Address(). Using DNS64 would be arduous as the server would have to know beforehand what the dynamically generated prefix is. For Openthread, it is better to do the NAT64 translation locally.

I could see a world where zephyr's implementation of getaddrinfo does the translation if using Openthread as the L2 layer, but as @rlubos mentions, it would result in a non-standard getaddrinfo implementation.

How about we simplify the change set, I. e. keep the current configuration as is (use server_addr for address resolving) to maintain backwards compatibility, but allow to specify server_hostname separately for TLS case, with a fallback to server_addr if not set?

I agree with this proposal.

@nealjack
Copy link
Author

nealjack commented May 5, 2025

This commit also changes how the controllerId is generated based on device id, and disentangles the two. The controllerId is what hawkbit uses to uniquely identify a device, and is not necessarily the same as the device id, and should be fully customizable by the user if needed. Previously, all custom device ids were being prepended with CONFIG_BOARD. When a user selects CONFIG_HAWKBIT_CUSTOM_DEVICE_ID, they should be able to specify the full controllerId used with hawkbit.

Please note, that changes that are not directly related to each other, should at least go into their own commit.

This is even more unrelated and I recommend splitting it into it's own PR.

I will work on splitting the PR to address this.

@maass-hamburg
Copy link
Collaborator

I agree we should avoid API changes, although I also see a need to be able to specify hostname when using numeric address representation for TLS purposes.

For that it's fine, but it should be put behind a Kconfig, which is disabled by default.

@maass-hamburg
Copy link
Collaborator

I could see a world where zephyr's implementation of getaddrinfo does the translation if using Openthread as the L2 layer, but as @rlubos mentions, it would result in a non-standard getaddrinfo implementation.

Put it behind a Kconfig, then it can be implemented and activated for only that use case.

@nealjack nealjack force-pushed the hawkbit_interface branch from c776b00 to b551d00 Compare May 5, 2025 20:16
@nealjack nealjack force-pushed the hawkbit_interface branch from b551d00 to 27a1b82 Compare May 5, 2025 20:19
@nealjack
Copy link
Author

nealjack commented May 5, 2025

I split up this PR into three (#89500, #89497, and this one).

I have updated this PR to address specifically adding a server_domain field that can be enabled via Kconfig flag HAWKBIT_USE_DOMAIN_NAME which allows explicitly providing a domain name, and allowing server_addr to take an IP address instead of a domain name.

Yes, this is a workaround due to the Zephyr OS not providing support for NAT64 translation, especially with the dynamic NAT64 prefix generation that Openthread does. I don't think there was consensus about whether to alter getaddrinfo. I agree with @rlubos's reservations about altering a posix compliant implementation of getaddrinfo.

However, I am wondering if it would be more appropriate to alter Zephyr's DNS Resolve Library to be Openthread/NAT64 aware, as it is a zephyr-specific library above lower level posix calls. It allows users to provide a list of DNS servers at runtime and could be altered to accept a NAT64 prefix for translation at runtime too. This would require changing the hawkbit subsystem to use the async DNS resolve library.

I'm open to any ideas or thoughts.

@jukkar
Copy link
Member

jukkar commented May 6, 2025

However, I am wondering if it would be more appropriate to alter Zephyr's DNS Resolve Library to be Openthread/NAT64 aware, as it is a zephyr-specific library above lower level posix calls.

Note that getaddrinfo is using the zephyr dns resolver lib and not the other way around.

@maass-hamburg
Copy link
Collaborator

@nealjack please check the compliance checks. you f.e. forgot the <> around your email in the signed off

@maass-hamburg
Copy link
Collaborator

@nealjack please remove the unrelated samples: sensor: lps22hh: fix title commit

@nealjack nealjack force-pushed the hawkbit_interface branch 4 times, most recently from 374d1e1 to a6d7986 Compare May 7, 2025 16:52
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 <[email protected]>
@nealjack nealjack force-pushed the hawkbit_interface branch from a6d7986 to 5512401 Compare May 7, 2025 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants