Commit cf8b7d71 authored by Jukka Rissanen's avatar Jukka Rissanen Committed by Anas Nashif
Browse files

net: dns: Add service discovery support

Allow PTR queries with dns_resolve_service() API.

Signed-off-by: default avatarJukka Rissanen <jukka.rissanen@nordicsemi.no>
parent a8683502
Loading
Loading
Loading
Loading
+42 −2
Changes for include/zephyr/net/dns_resolve.h: 42 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -45,9 +45,11 @@ enum dns_query_type {
};

/** Max size of the resolved name. */
#ifndef DNS_MAX_NAME_SIZE
#if defined(CONFIG_DNS_RESOLVER_MAX_NAME_LEN)
#define DNS_MAX_NAME_SIZE CONFIG_DNS_RESOLVER_MAX_NAME_LEN
#else
#define DNS_MAX_NAME_SIZE 20
#endif
#endif /* CONFIG_DNS_RESOLVER_MAX_NAME_LEN */

/** @cond INTERNAL_HIDDEN */

@@ -628,6 +630,44 @@ int dns_resolve_name(struct dns_resolve_context *ctx,
		     void *user_data,
		     int32_t timeout);

/**
 * @brief Resolve DNS service.
 *
 * @details This function can be used to resolve service records needed in
 * DNS-SD service discovery.
 * Note that this is an asynchronous call, the function will return immediately
 * and the system will call the callback after resolving has finished or a timeout
 * has occurred.
 * We might send the query to multiple servers (if there are more than one
 * server configured), but we only use the result of the first received
 * response.
 *
 * @param ctx DNS context
 * @param query What the caller wants to resolve.
 * @param dns_id DNS id is returned to the caller. This is needed if one
 * wishes to cancel the query. This can be set to NULL if there is no need
 * to cancel the query.
 * @param cb Callback to call after the resolving has finished or timeout
 * has happened.
 * @param user_data The user data.
 * @param timeout The timeout value for the query. Possible values:
 * SYS_FOREVER_MS: the query is tried forever, user needs to cancel it
 *            manually if it takes too long time to finish
 * >0: start the query and let the system timeout it after specified ms
 *
 * @return 0 if resolving was started ok, < 0 otherwise
 */
static inline int dns_resolve_service(struct dns_resolve_context *ctx,
				      const char *query,
				      uint16_t *dns_id,
				      dns_resolve_cb_t cb,
				      void *user_data,
				      int32_t timeout)
{
	return dns_resolve_name(ctx, query, DNS_QUERY_TYPE_PTR,
				dns_id, cb, user_data, timeout);
}

/**
 * @brief Get default DNS context.
 *
+10 −0
Changes for subsys/net/lib/dns/Kconfig: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -69,6 +69,16 @@ config DNS_RESOLVER_MAX_QUERY_LEN
	  Max length of a DNS query that should be looked up including the
	  trailing 0. So e.g. "example.com" would have a query len of 12.

config DNS_RESOLVER_MAX_NAME_LEN
	int "Max length of the resolved DNS name"
	range 1 $(UINT8_MAX)
	default 128 if DNS_SD
	default 20
	help
	  Max length of a buffer that is used to store information returned from
	  DNS server. For example if we query a DNS-SD service, then this value should
	  be long enough to store the returned string.

menuconfig DNS_SERVER_IP_ADDRESSES
	bool "Set DNS server IP addresses"
	help
+7 −2
Changes for subsys/net/lib/dns/dns_pack.c: 7 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -166,6 +166,10 @@ int dns_unpack_answer(struct dns_msg_t *dns_msg, int dname_ptr, uint32_t *ttl,
		set_dns_msg_response(dns_msg, DNS_RESPONSE_IP, pos, len);
		return 0;

	case DNS_RR_TYPE_PTR:
		set_dns_msg_response(dns_msg, DNS_RESPONSE_DATA, pos, len);
		return 0;

	case DNS_RR_TYPE_CNAME:
		set_dns_msg_response(dns_msg, DNS_RESPONSE_CNAME_NO_IP,
				     pos, len);
@@ -346,7 +350,8 @@ int dns_unpack_response_query(struct dns_msg_t *dns_msg)

	buf = dns_query + qname_size;
	if (dns_unpack_query_qtype(buf) != DNS_RR_TYPE_A &&
	    dns_unpack_query_qtype(buf) != DNS_RR_TYPE_AAAA) {
	    dns_unpack_query_qtype(buf) != DNS_RR_TYPE_AAAA &&
	    dns_unpack_query_qtype(buf) != DNS_RR_TYPE_PTR) {
		return -EINVAL;
	}

@@ -482,7 +487,7 @@ int mdns_unpack_query_header(struct dns_msg_t *msg, uint16_t *src_id)
}

/* Returns the length of the unpacked name */
static int dns_unpack_name(const uint8_t *msg, int maxlen, const uint8_t *src,
int dns_unpack_name(const uint8_t *msg, int maxlen, const uint8_t *src,
		    struct net_buf *buf, const uint8_t **eol)
{
	int dest_size = net_buf_tailroom(buf);
+4 −0
Changes for subsys/net/lib/dns/dns_pack.h: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ enum dns_rr_type {
enum dns_response_type {
	DNS_RESPONSE_INVALID = -EINVAL,
	DNS_RESPONSE_IP,
	DNS_RESPONSE_DATA,
	DNS_RESPONSE_CNAME_WITH_IP,
	DNS_RESPONSE_CNAME_NO_IP
};
@@ -473,4 +474,7 @@ int dns_unpack_query(struct dns_msg_t *dns_msg, struct net_buf *buf,
 */
const char *dns_qtype_to_str(enum dns_rr_type qtype);

int dns_unpack_name(const uint8_t *msg, int maxlen, const uint8_t *src,
		    struct net_buf *buf, const uint8_t **eol);

#endif
+46 −0
Changes for subsys/net/lib/dns/resolve.c: 46 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -1097,6 +1097,7 @@ int dns_validate_msg(struct dns_resolve_context *ctx,
		}

		switch (dns_msg->response_type) {
		case DNS_RESPONSE_DATA:
		case DNS_RESPONSE_IP: {
			int query_name_len;

@@ -1205,11 +1206,55 @@ rr_qtype_aaaa:
					ret = DNS_EAI_ADDRFAMILY;
					goto quit;
				}

			} else if (ctx->queries[*query_idx].query_type ==
							DNS_QUERY_TYPE_PTR) {
				/* Synthesize a reply and place the returned info
				 * in to the ai_canonname field. Use AF_LOCAL address
				 * family as this is not a real address.
				 */
				struct net_buf *result;
				uint8_t *pos;

				address_size = MIN(dns_msg->response_length,
						   DNS_MAX_NAME_SIZE);

				/* Temporary buffer that is needed by dns_unpack_name()
				 * to unpack the resolved name.
				 */
				result = net_buf_alloc(&dns_qname_pool, ctx->buf_timeout);
				if (result == NULL) {
					NET_DBG("Cannot allocate buffer for DNS query result");
					ret = DNS_EAI_MEMORY;
					goto quit;
				}

				pos = dns_msg->msg + dns_msg->response_position;
				ret = dns_unpack_name(dns_msg->msg, dns_msg->msg_size, pos,
						      result, NULL);
				if (ret < 0) {
					errno = -ret;
					ret = DNS_EAI_SYSTEM;
					net_buf_unref(result);
					goto quit;
				}

				info.ai_family = AF_LOCAL;
				info.ai_addrlen = MIN(result->len, DNS_MAX_NAME_SIZE);
				memcpy(&info.ai_canonname, result->data, info.ai_addrlen);
				info.ai_canonname[info.ai_addrlen] = '\0';

				net_buf_unref(result);

			} else {
				ret = DNS_EAI_FAMILY;
				goto quit;
			}

			if (ctx->queries[*query_idx].query_type ==
							DNS_QUERY_TYPE_A ||
			    ctx->queries[*query_idx].query_type ==
							DNS_QUERY_TYPE_AAAA) {
				if (dns_msg->response_length < address_size) {
					/* it seems this is a malformed message */
					errno = EMSGSIZE;
@@ -1227,6 +1272,7 @@ rr_qtype_aaaa:

				src = dns_msg->msg + dns_msg->response_position;
				memcpy(addr, src, address_size);
			}

			invoke_query_callback(DNS_EAI_INPROGRESS, &info,
					      &ctx->queries[*query_idx]);