aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-01-12 16:25:47 +0100
committerHarald Welte <laforge@osmocom.org>2020-01-12 16:27:42 +0100
commit110a49f69f29fed844d8743b76fd748f4a14812a (patch)
treefa46259f4cc310bcf79275729d9b3fb045b07eec /src
parent41fe3625915c456513544b99ba8c057c0f650b3c (diff)
Revert "add mDNS lookup method to libosmo-mslookup"
This reverts commit f10463c5fc6d9e786ab7c648d99f7450f9a25906, as it causes all OBS osmo-hlr builds to fail in the mslookup_client_mdns test. Change-Id: I5aec5b59f304c7f732c4a31131beedf29c966d9d
Diffstat (limited to 'src')
-rw-r--r--src/mslookup/Makefile.am5
-rw-r--r--src/mslookup/mdns.c425
-rw-r--r--src/mslookup/mdns_msg.c261
-rw-r--r--src/mslookup/mdns_rfc.c265
-rw-r--r--src/mslookup/mdns_sock.c144
-rw-r--r--src/mslookup/mslookup_client_mdns.c235
6 files changed, 0 insertions, 1335 deletions
diff --git a/src/mslookup/Makefile.am b/src/mslookup/Makefile.am
index 07fb6f4..01be401 100644
--- a/src/mslookup/Makefile.am
+++ b/src/mslookup/Makefile.am
@@ -10,14 +10,9 @@ AM_LDFLAGS = $(COVERAGE_LDFLAGS)
lib_LTLIBRARIES = libosmo-mslookup.la
libosmo_mslookup_la_SOURCES = \
- mdns.c \
- mdns_msg.c \
- mdns_rfc.c \
- mdns_sock.c \
mslookup.c \
mslookup_client.c \
mslookup_client_fake.c \
- mslookup_client_mdns.c \
$(NULL)
libosmo_mslookup_la_LDFLAGS = -version-info $(LIBVERSION)
diff --git a/src/mslookup/mdns.c b/src/mslookup/mdns.c
deleted file mode 100644
index 4742a7c..0000000
--- a/src/mslookup/mdns.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/* mslookup specific functions for encoding and decoding mslookup queries/results into mDNS packets, using the high
- * level functions from mdns_msg.c and mdns_record.c to build the request/answer messages. */
-
-/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <osmocom/hlr/logging.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/mslookup/mslookup.h>
-#include <osmocom/mslookup/mdns_msg.h>
-#include <osmocom/mslookup/mdns_rfc.h>
-#include <errno.h>
-#include <inttypes.h>
-
-static struct msgb *osmo_mdns_msgb_alloc(const char *label)
-{
- return msgb_alloc(1024, label);
-}
-
-/*! Combine the mslookup query service, ID and ID type into a domain string.
- * \param[in] domain_suffix is appended to each domain in the queries to avoid colliding with the top-level domains
- * administrated by IANA. Example: "mdns.osmocom.org"
- * \returns allocated buffer with the resulting domain (i.e. "sip.voice.123.msisdn.mdns.osmocom.org") on success,
- * NULL on failure.
- */
-static char *domain_from_query(void *ctx, const struct osmo_mslookup_query *query, const char *domain_suffix)
-{
- const char *id;
-
- /* Get id from query */
- switch (query->id.type) {
- case OSMO_MSLOOKUP_ID_IMSI:
- id = query->id.imsi;
- break;
- case OSMO_MSLOOKUP_ID_MSISDN:
- id = query->id.msisdn;
- break;
- default:
- LOGP(DMSLOOKUP, LOGL_ERROR, "can't encode mslookup query id type %i", query->id.type);
- return NULL;
- }
-
- return talloc_asprintf(ctx, "%s.%s.%s.%s", query->service, id, osmo_mslookup_id_type_name(query->id.type),
- domain_suffix);
-}
-
-/*! Split up query service, ID and ID type from a domain string into a mslookup query.
- * \param[in] domain with domain_suffix, e.g. "sip.voice.123.msisdn.mdns.osmocom.org"
- * \param[in] domain_suffix is appended to each domain in the queries to avoid colliding with the top-level domains
- * administrated by IANA. It is not part of the resulting struct osmo_mslookup_query, so we
- * remove it in this function. Example: "mdns.osmocom.org"
- */
-int query_from_domain(struct osmo_mslookup_query *query, const char *domain, const char *domain_suffix)
-{
- int domain_len = strlen(domain) - strlen(domain_suffix) - 1;
- char domain_buf[OSMO_MDNS_RFC_MAX_NAME_LEN];
-
- if (domain_len <= 0 || domain_len >= sizeof(domain_buf))
- return -EINVAL;
-
- if (domain[domain_len] != '.' || strcmp(domain + domain_len + 1, domain_suffix) != 0)
- return -EINVAL;
-
- memcpy(domain_buf, domain, domain_len);
- domain_buf[domain_len] = '\0';
- return osmo_mslookup_query_init_from_domain_str(query, domain_buf);
-}
-
-/*! Encode a mslookup query into a mDNS packet.
- * \param[in] domain_suffix is appended to each domain in the queries to avoid colliding with the top-level domains
- * administrated by IANA. Example: "mdns.osmocom.org"
- * \returns msgb, or NULL on error.
- */
-struct msgb *osmo_mdns_query_encode(void *ctx, uint16_t packet_id, const struct osmo_mslookup_query *query,
- const char *domain_suffix)
-{
- struct osmo_mdns_msg_request req = {0};
- struct msgb *msg = osmo_mdns_msgb_alloc(__func__);
-
- req.id = packet_id;
- req.type = OSMO_MDNS_RFC_RECORD_TYPE_ALL;
- req.domain = domain_from_query(ctx, query, domain_suffix);
- if (!req.domain)
- goto error;
- if (osmo_mdns_msg_request_encode(ctx, msg, &req))
- goto error;
- talloc_free(req.domain);
- return msg;
-error:
- msgb_free(msg);
- talloc_free(req.domain);
- return NULL;
-}
-
-/*! Decode a mDNS request packet into a mslookup query.
- * \param[out] packet_id the result must be sent with the same packet_id.
- * \param[in] domain_suffix is appended to each domain in the queries to avoid colliding with the top-level domains
- * administrated by IANA. Example: "mdns.osmocom.org"
- * \returns allocated mslookup query on success, NULL on error.
- */
-struct osmo_mslookup_query *osmo_mdns_query_decode(void *ctx, const uint8_t *data, size_t data_len,
- uint16_t *packet_id, const char *domain_suffix)
-{
- struct osmo_mdns_msg_request *req = NULL;
- struct osmo_mslookup_query *query = NULL;
-
- req = osmo_mdns_msg_request_decode(ctx, data, data_len);
- if (!req)
- return NULL;
-
- query = talloc_zero(ctx, struct osmo_mslookup_query);
- OSMO_ASSERT(query);
- if (query_from_domain(query, req->domain, domain_suffix) < 0)
- goto error_free;
-
- *packet_id = req->id;
- talloc_free(req);
- return query;
-error_free:
- talloc_free(req);
- talloc_free(query);
- return NULL;
-}
-
-/*! Parse sockaddr_str from mDNS record, so the mslookup result can be filled with it.
- * \param[out] sockaddr_str resulting IPv4 or IPv6 sockaddr_str.
- * \param[in] rec single record of the abstracted list of mDNS records
- * \returns 0 on success, -EINVAL on error.
- */
-static int sockaddr_str_from_mdns_record(struct osmo_sockaddr_str *sockaddr_str, struct osmo_mdns_record *rec)
-{
- switch (rec->type) {
- case OSMO_MDNS_RFC_RECORD_TYPE_A:
- if (rec->length != 4) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "unexpected length of A record\n");
- return -EINVAL;
- }
- osmo_sockaddr_str_from_32(sockaddr_str, *(uint32_t *)rec->data, 0);
- break;
- case OSMO_MDNS_RFC_RECORD_TYPE_AAAA:
- if (rec->length != 16) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "unexpected length of AAAA record\n");
- return -EINVAL;
- }
- osmo_sockaddr_str_from_in6_addr(sockaddr_str, (struct in6_addr*)rec->data, 0);
- break;
- default:
- LOGP(DMSLOOKUP, LOGL_ERROR, "unexpected record type\n");
- return -EINVAL;
- }
- return 0;
-}
-
-/*! Encode a successful mslookup result, along with the original query and packet_id into one mDNS answer packet.
- *
- * The records in the packet are ordered as follows:
- * 1) "age", ip_v4/v6, "port" (only IPv4 or IPv6 present) or
- * 2) "age", ip_v4, "port", ip_v6, "port" (both IPv4 and v6 present).
- * "age" and "port" are TXT records, ip_v4 is an A record, ip_v6 is an AAAA record.
- *
- * \param[in] packet_id as received in osmo_mdns_query_decode().
- * \param[in] query the original query, so we can send the domain back in the answer (i.e. "sip.voice.1234.msisdn").
- * \param[in] result holds the age, IPs and ports of the queried service.
- * \param[in] domain_suffix is appended to each domain in the queries to avoid colliding with the top-level domains
- * administrated by IANA. Example: "mdns.osmocom.org"
- * \returns msg on success, NULL on error.
- */
-struct msgb *osmo_mdns_result_encode(void *ctx, uint16_t packet_id, const struct osmo_mslookup_query *query,
- const struct osmo_mslookup_result *result, const char *domain_suffix)
-{
- struct osmo_mdns_msg_answer ans = {};
- struct osmo_mdns_record *rec_age = NULL;
- struct osmo_mdns_record rec_ip_v4 = {0};
- struct osmo_mdns_record rec_ip_v6 = {0};
- struct osmo_mdns_record *rec_ip_v4_port = NULL;
- struct osmo_mdns_record *rec_ip_v6_port = NULL;
- struct in_addr rec_ip_v4_in;
- struct in6_addr rec_ip_v6_in;
- struct msgb *msg = osmo_mdns_msgb_alloc(__func__);
- char buf[256];
-
- ctx = talloc_named(ctx, 0, "osmo_mdns_result_encode");
-
- /* Prepare answer (ans) */
- ans.domain = domain_from_query(ctx, query, domain_suffix);
- if (!ans.domain)
- goto error;
- ans.id = packet_id;
- INIT_LLIST_HEAD(&ans.records);
-
- /* Record for age */
- rec_age = osmo_mdns_record_txt_keyval_encode(ctx, "age", "%"PRIu32, result->age);
- OSMO_ASSERT(rec_age);
- llist_add_tail(&rec_age->list, &ans.records);
-
- /* Records for IPv4 */
- if (osmo_sockaddr_str_is_set(&result->host_v4)) {
- if (osmo_sockaddr_str_to_in_addr(&result->host_v4, &rec_ip_v4_in) < 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "failed to encode ipv4: %s\n",
- osmo_mslookup_result_name_b(buf, sizeof(buf), query, result));
- goto error;
- }
- rec_ip_v4.type = OSMO_MDNS_RFC_RECORD_TYPE_A;
- rec_ip_v4.data = (uint8_t *)&rec_ip_v4_in;
- rec_ip_v4.length = sizeof(rec_ip_v4_in);
- llist_add_tail(&rec_ip_v4.list, &ans.records);
-
- rec_ip_v4_port = osmo_mdns_record_txt_keyval_encode(ctx, "port", "%"PRIu16, result->host_v4.port);
- OSMO_ASSERT(rec_ip_v4_port);
- llist_add_tail(&rec_ip_v4_port->list, &ans.records);
- }
-
- /* Records for IPv6 */
- if (osmo_sockaddr_str_is_set(&result->host_v6)) {
- if (osmo_sockaddr_str_to_in6_addr(&result->host_v6, &rec_ip_v6_in) < 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "failed to encode ipv6: %s\n",
- osmo_mslookup_result_name_b(buf, sizeof(buf), query, result));
- goto error;
- }
- rec_ip_v6.type = OSMO_MDNS_RFC_RECORD_TYPE_AAAA;
- rec_ip_v6.data = (uint8_t *)&rec_ip_v6_in;
- rec_ip_v6.length = sizeof(rec_ip_v6_in);
- llist_add_tail(&rec_ip_v6.list, &ans.records);
-
- rec_ip_v6_port = osmo_mdns_record_txt_keyval_encode(ctx, "port", "%"PRIu16, result->host_v6.port);
- OSMO_ASSERT(rec_ip_v6_port);
- llist_add_tail(&rec_ip_v6_port->list, &ans.records);
- }
-
- if (osmo_mdns_msg_answer_encode(ctx, msg, &ans)) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "failed to encode mDNS answer: %s\n",
- osmo_mslookup_result_name_b(buf, sizeof(buf), query, result));
- goto error;
- }
- talloc_free(ctx);
- return msg;
-error:
- msgb_free(msg);
- talloc_free(ctx);
- return NULL;
-}
-
-static int decode_uint32_t(const char *str, uint32_t *val)
-{
- long long int lld;
- char *endptr = NULL;
- *val = 0;
- errno = 0;
- lld = strtoll(str, &endptr, 10);
- if (errno || !endptr || *endptr)
- return -EINVAL;
- if (lld < 0 || lld > UINT32_MAX)
- return -EINVAL;
- *val = lld;
- return 0;
-}
-
-static int decode_port(const char *str, uint16_t *port)
-{
- uint32_t val;
- if (decode_uint32_t(str, &val))
- return -EINVAL;
- if (val > 65535)
- return -EINVAL;
- *port = val;
- return 0;
-}
-
-/*! Read expected mDNS records into mslookup result.
- *
- * The records in the packet must be ordered as follows:
- * 1) "age", ip_v4/v6, "port" (only IPv4 or IPv6 present) or
- * 2) "age", ip_v4, "port", ip_v6, "port" (both IPv4 and v6 present).
- * "age" and "port" are TXT records, ip_v4 is an A record, ip_v6 is an AAAA record.
- *
- * \param[out] result holds the age, IPs and ports of the queried service.
- * \param[in] ans abstracted mDNS answer with a list of resource records.
- * \returns 0 on success, -EINVAL on error.
- */
-int osmo_mdns_result_from_answer(struct osmo_mslookup_result *result, const struct osmo_mdns_msg_answer *ans)
-{
- struct osmo_mdns_record *rec;
- char txt_key[64];
- char txt_value[64];
- bool found_age = false;
- bool found_ip_v4 = false;
- bool found_ip_v6 = false;
- struct osmo_sockaddr_str *expect_port_for = NULL;
-
- *result = (struct osmo_mslookup_result){};
-
- result->rc = OSMO_MSLOOKUP_RC_NONE;
-
- llist_for_each_entry(rec, &ans->records, list) {
- switch (rec->type) {
- case OSMO_MDNS_RFC_RECORD_TYPE_A:
- if (expect_port_for) {
- LOGP(DMSLOOKUP, LOGL_ERROR,
- "'A' record found, but still expecting a 'port' value first\n");
- return -EINVAL;
- }
- if (found_ip_v4) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "'A' record found twice in mDNS answer\n");
- return -EINVAL;
- }
- found_ip_v4 = true;
- expect_port_for = &result->host_v4;
- if (sockaddr_str_from_mdns_record(expect_port_for, rec)) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "'A' record with invalid address data\n");
- return -EINVAL;
- }
- break;
- case OSMO_MDNS_RFC_RECORD_TYPE_AAAA:
- if (expect_port_for) {
- LOGP(DMSLOOKUP, LOGL_ERROR,
- "'AAAA' record found, but still expecting a 'port' value first\n");
- return -EINVAL;
- }
- if (found_ip_v6) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "'AAAA' record found twice in mDNS answer\n");
- return -EINVAL;
- }
- found_ip_v6 = true;
- expect_port_for = &result->host_v6;
- if (sockaddr_str_from_mdns_record(expect_port_for, rec) != 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "'AAAA' record with invalid address data\n");
- return -EINVAL;
- }
- break;
- case OSMO_MDNS_RFC_RECORD_TYPE_TXT:
- if (osmo_mdns_record_txt_keyval_decode(rec, txt_key, sizeof(txt_key),
- txt_value, sizeof(txt_value)) != 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "failed to decode txt record\n");
- return -EINVAL;
- }
- if (strcmp(txt_key, "age") == 0) {
- if (found_age) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "duplicate 'TXT' record for 'age'\n");
- return -EINVAL;
- }
- found_age = true;
- if (decode_uint32_t(txt_value, &result->age)) {
- LOGP(DMSLOOKUP, LOGL_ERROR,
- "'TXT' record: invalid 'age' value ('age=%s')\n", txt_value);
- return -EINVAL;
- }
- } else if (strcmp(txt_key, "port") == 0) {
- if (!expect_port_for) {
- LOGP(DMSLOOKUP, LOGL_ERROR,
- "'TXT' record for 'port' without previous 'A' or 'AAAA' record\n");
- return -EINVAL;
- }
- if (decode_port(txt_value, &expect_port_for->port)) {
- LOGP(DMSLOOKUP, LOGL_ERROR,
- "'TXT' record: invalid 'port' value ('port=%s')\n", txt_value);
- return -EINVAL;
- }
- expect_port_for = NULL;
- } else {
- LOGP(DMSLOOKUP, LOGL_ERROR, "unexpected key '%s' in TXT record\n", txt_key);
- return -EINVAL;
- }
- break;
- default:
- LOGP(DMSLOOKUP, LOGL_ERROR, "unexpected record type\n");
- return -EINVAL;
- }
- }
-
- /* Check if everything was found */
- if (!found_age || !(found_ip_v4 || found_ip_v6) || expect_port_for) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "missing resource records in mDNS answer\n");
- return -EINVAL;
- }
-
- result->rc = OSMO_MSLOOKUP_RC_RESULT;
- return 0;
-}
-
-/*! Decode a mDNS answer packet into a mslookup result, query and packet_id.
- * \param[out] packet_id same ID as sent in the request packet.
- * \param[out] query the original query (service, ID, ID type).
- * \param[out] result holds the age, IPs and ports of the queried service.
- * \param[in] domain_suffix is appended to each domain in the queries to avoid colliding with the top-level domains
- * administrated by IANA. Example: "mdns.osmocom.org"
- * \returns 0 on success, -EINVAL on error.
- */
-int osmo_mdns_result_decode(void *ctx, const uint8_t *data, size_t data_len, uint16_t *packet_id,
- struct osmo_mslookup_query *query, struct osmo_mslookup_result *result,
- const char *domain_suffix)
-{
- int rc = -EINVAL;
- struct osmo_mdns_msg_answer *ans;
- ans = osmo_mdns_msg_answer_decode(ctx, data, data_len);
- if (!ans)
- goto exit_free;
-
- if (query_from_domain(query, ans->domain, domain_suffix) < 0)
- goto exit_free;
-
- if (osmo_mdns_result_from_answer(result, ans) < 0)
- goto exit_free;
-
- *packet_id = ans->id;
- rc = 0;
-
-exit_free:
- talloc_free(ans);
- return rc;
-}
diff --git a/src/mslookup/mdns_msg.c b/src/mslookup/mdns_msg.c
deleted file mode 100644
index da65fef..0000000
--- a/src/mslookup/mdns_msg.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/* High level mDNS encoding and decoding functions for whole messages:
- * Request message (header, question)
- * Answer message (header, resource record 1, ... resource record N)*/
-
-/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <string.h>
-#include <osmocom/hlr/logging.h>
-#include <osmocom/mslookup/mdns_msg.h>
-
-/*! Encode request message into one mDNS packet, consisting of the header section and one question section.
- * \returns 0 on success, -EINVAL on error.
- */
-int osmo_mdns_msg_request_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_msg_request *req)
-{
- struct osmo_mdns_rfc_header hdr = {0};
- struct osmo_mdns_rfc_question qst = {0};
-
- hdr.id = req->id;
- hdr.qdcount = 1;
- osmo_mdns_rfc_header_encode(msg, &hdr);
-
- qst.domain = req->domain;
- qst.qtype = req->type;
- qst.qclass = OSMO_MDNS_RFC_CLASS_IN;
- if (osmo_mdns_rfc_question_encode(ctx, msg, &qst) != 0)
- return -EINVAL;
-
- return 0;
-}
-
-/*! Decode request message from a mDNS packet, consisting of the header section and one question section.
- * \returns allocated request message on success, NULL on error.
- */
-struct osmo_mdns_msg_request *osmo_mdns_msg_request_decode(void *ctx, const uint8_t *data, size_t data_len)
-{
- struct osmo_mdns_rfc_header hdr = {0};
- size_t hdr_len = sizeof(struct osmo_mdns_rfc_header);
- struct osmo_mdns_rfc_question* qst = NULL;
- struct osmo_mdns_msg_request *ret = NULL;
-
- if (data_len < hdr_len || osmo_mdns_rfc_header_decode(data, hdr_len, &hdr) != 0 || hdr.qr != 0)
- return NULL;
-
- qst = osmo_mdns_rfc_question_decode(ctx, data + hdr_len, data_len - hdr_len);
- if (!qst)
- return NULL;
-
- ret = talloc_zero(ctx, struct osmo_mdns_msg_request);
- ret->id = hdr.id;
- ret->domain = talloc_strdup(ret, qst->domain);
- ret->type = qst->qtype;
-
- talloc_free(qst);
- return ret;
-}
-
-/*! Initialize the linked list for resource records in a answer message. */
-void osmo_mdns_msg_answer_init(struct osmo_mdns_msg_answer *ans)
-{
- *ans = (struct osmo_mdns_msg_answer){};
- INIT_LLIST_HEAD(&ans->records);
-}
-
-/*! Encode answer message into one mDNS packet, consisting of the header section and N resource records.
- *
- * To keep things simple, this sends the domain with each resource record. Other DNS implementations make use of
- * "message compression", which would send a question section with the domain before the resource records, and then
- * point inside each resource record with an offset back to the domain in the question section (RFC 1035 4.1.4).
- * \returns 0 on success, -EINVAL on error.
- */
-int osmo_mdns_msg_answer_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_msg_answer *ans)
-{
- struct osmo_mdns_rfc_header hdr = {0};
- struct osmo_mdns_record *ans_record;
-
- hdr.id = ans->id;
- hdr.qr = 1;
- hdr.ancount = llist_count(&ans->records);
- osmo_mdns_rfc_header_encode(msg, &hdr);
-
- llist_for_each_entry(ans_record, &ans->records, list) {
- struct osmo_mdns_rfc_record rec = {0};
-
- rec.domain = ans->domain;
- rec.type = ans_record->type;
- rec.class = OSMO_MDNS_RFC_CLASS_IN;
- rec.ttl = 0;
- rec.rdlength = ans_record->length;
- rec.rdata = ans_record->data;
-
- if (osmo_mdns_rfc_record_encode(ctx, msg, &rec) != 0)
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*! Decode answer message from a mDNS packet.
- *
- * Answer messages must consist of one header and one or more resource records. An additional question section or
- * message compression (RFC 1035 4.1.4) are not supported.
-* \returns allocated answer message on success, NULL on error.
- */
-struct osmo_mdns_msg_answer *osmo_mdns_msg_answer_decode(void *ctx, const uint8_t *data, size_t data_len)
-{
- struct osmo_mdns_rfc_header hdr = {};
- size_t hdr_len = sizeof(struct osmo_mdns_rfc_header);
- struct osmo_mdns_msg_answer *ret = talloc_zero(ctx, struct osmo_mdns_msg_answer);
-
- /* Parse header section */
- if (data_len < hdr_len || osmo_mdns_rfc_header_decode(data, hdr_len, &hdr) != 0 || hdr.qr != 1)
- goto error;
- ret->id = hdr.id;
- data_len -= hdr_len;
- data += hdr_len;
-
- /* Parse resource records */
- INIT_LLIST_HEAD(&ret->records);
- while (data_len) {
- size_t record_len;
- struct osmo_mdns_rfc_record *rec;
- struct osmo_mdns_record* ret_record;
-
- rec = osmo_mdns_rfc_record_decode(ret, data, data_len, &record_len);
- if (!rec)
- goto error;
-
- /* Copy domain to ret */
- if (ret->domain) {
- if (strcmp(ret->domain, rec->domain) != 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "domain mismatch in resource records ('%s' vs '%s')\n",
- ret->domain, rec->domain);
- goto error;
- }
- }
- else
- ret->domain = talloc_strdup(ret, rec->domain);
-
- /* Add simplified record to ret */
- ret_record = talloc_zero(ret, struct osmo_mdns_record);
- ret_record->type = rec->type;
- ret_record->length = rec->rdlength;
- ret_record->data = talloc_memdup(ret_record, rec->rdata, rec->rdlength);
- llist_add_tail(&ret_record->list, &ret->records);
-
- data += record_len;
- data_len -= record_len;
- talloc_free(rec);
- }
-
- /* Verify record count */
- if (llist_count(&ret->records) != hdr.ancount) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "amount of parsed records (%i) doesn't match count in header (%i)\n",
- llist_count(&ret->records), hdr.ancount);
- goto error;
- }
-
- return ret;
-error:
- talloc_free(ret);
- return NULL;
-}
-
-/*! Get a TXT resource record, which stores a key=value string.
- * \returns allocated resource record on success, NULL on error.
- */
-static struct osmo_mdns_record *_osmo_mdns_record_txt_encode(void *ctx, const char *key, const char *value)
-{
- struct osmo_mdns_record *ret = talloc_zero(ctx, struct osmo_mdns_record);
- size_t len = strlen(key) + 1 + strlen(value);
-
- if (len > OSMO_MDNS_RFC_MAX_CHARACTER_STRING_LEN - 1)
- return NULL;
-
- /* redundant len is required, see RFC 1035 3.3.14 and 3.3. */
- ret->data = (uint8_t *)talloc_asprintf(ctx, "%c%s=%s", (char)len, key, value);
- if (!ret->data)
- return NULL;
- ret->type = OSMO_MDNS_RFC_RECORD_TYPE_TXT;
- ret->length = len + 1;
- return ret;
-}
-
-/*! Get a TXT resource record, which stores a key=value string, but build value from a format string.
- * \returns allocated resource record on success, NULL on error.
- */
-struct osmo_mdns_record *osmo_mdns_record_txt_keyval_encode(void *ctx, const char *key, const char *value_fmt, ...)
-{
- va_list ap;
- char *value = NULL;
- struct osmo_mdns_record *r;
-
- if (!value_fmt)
- return _osmo_mdns_record_txt_encode(ctx, key, "");
-
- va_start(ap, value_fmt);
- value = talloc_vasprintf(ctx, value_fmt, ap);
- if (!value)
- return NULL;
- va_end(ap);
- r = _osmo_mdns_record_txt_encode(ctx, key, value);
- talloc_free(value);
- return r;
-}
-
-/*! Decode a TXT resource record, which stores a key=value string.
- * \returns 0 on success, -EINVAL on error.
- */
-int osmo_mdns_record_txt_keyval_decode(const struct osmo_mdns_record *rec,
- char *key_buf, size_t key_size, char *value_buf, size_t value_size)
-{
- const char *key_value;
- const char *key_value_end;
- const char *sep;
- const char *value;
-
- if (rec->type != OSMO_MDNS_RFC_RECORD_TYPE_TXT)
- return -EINVAL;
-
- key_value = (const char *)rec->data;
- key_value_end = key_value + rec->length;
-
- /* Verify and then skip the redundant string length byte */
- if (*key_value != rec->length - 1)
- return -EINVAL;
- key_value++;
-
- if (key_value >= key_value_end)
- return -EINVAL;
-
- /* Find equals sign */
- sep = osmo_strnchr(key_value, key_value_end - key_value, '=');
- if (!sep)
- return -EINVAL;
-
- /* Parse key */
- osmo_print_n(key_buf, key_size, key_value, sep - key_value);
-
- /* Parse value */
- value = sep + 1;
- osmo_print_n(value_buf, value_size, value, key_value_end - value);
- return 0;
-}
diff --git a/src/mslookup/mdns_rfc.c b/src/mslookup/mdns_rfc.c
deleted file mode 100644
index e1fc184..0000000
--- a/src/mslookup/mdns_rfc.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Low level mDNS encoding and decoding functions of the qname IE, header/question sections and resource records,
- * as described in these RFCs:
- * - RFC 1035 (Domain names - implementation and specification)
- * - RFC 3596 (DNS Extensions to Support IP Version 6) */
-
-/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/bitvec.h>
-#include <osmocom/core/logging.h>
-#include <osmocom/mslookup/mdns_rfc.h>
-
-/*
- * Encode/decode IEs
- */
-
-/*! Encode a domain string as qname (RFC 1035 4.1.2).
- * \param[in] domain multiple labels separated by dots, e.g. "sip.voice.1234.msisdn".
- * \returns allocated buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...), NULL on error.
- */
-char *osmo_mdns_rfc_qname_encode(void *ctx, const char *domain)
-{
- char *domain_dup;
- char *domain_iter;
- char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 2] = ""; /* len(qname) is len(domain) +1 */
- struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
- char *label;
-
- if (strlen(domain) > OSMO_MDNS_RFC_MAX_NAME_LEN)
- return NULL;
-
- domain_iter = domain_dup = talloc_strdup(ctx, domain);
- while ((label = strsep(&domain_iter, "."))) {
- size_t len = strlen(label);
-
- /* Empty domain, dot at start, two dots in a row, or ending with a dot */
- if (!len)
- goto error;
-
- OSMO_STRBUF_PRINTF(sb, "%c%s", (char)len, label);
- }
-
- talloc_free(domain_dup);
- return talloc_strdup(ctx, buf);
-
-error:
- talloc_free(domain_dup);
- return NULL;
-}
-
-/*! Decode a domain string from a qname (RFC 1035 4.1.2).
- * \param[in] qname buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...)
- * \param[in] qname_max_len amount of bytes that can be read at most from the memory location that qname points to.
- * \returns allocated buffer with domain string, multiple labels separated by dots (e.g. "sip.voice.1234.msisdn"),
- * NULL on error.
- */
-char *osmo_mdns_rfc_qname_decode(void *ctx, const char *qname, size_t qname_max_len)
-{
- const char *next_label, *qname_end = qname + qname_max_len;
- char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 1];
- int i = 0;
-
- if (qname_max_len < 1)
- return NULL;
-
- while (*qname) {
- size_t len = *qname;
- next_label = qname + len + 1;
-
- if (next_label >= qname_end || i + len > OSMO_MDNS_RFC_MAX_NAME_LEN)
- return NULL;
-
- if (i) {
- /* Two dots in a row is not allowed */
- if (buf[i - 1] == '.')
- return NULL;
-
- buf[i] = '.';
- i++;
- }
-
- memcpy(buf + i, qname + 1, len);
- i += len;
- qname = next_label;
- }
- buf[i] = '\0';
-
- return talloc_strdup(ctx, buf);
-}
-
-/*
- * Encode/decode message sections
- */
-
-/*! Encode header section (RFC 1035 4.1.1).
- * \param[in] msgb mesage buffer to which the encoded data will be appended.
- */
-void osmo_mdns_rfc_header_encode(struct msgb *msg, const struct osmo_mdns_rfc_header *hdr)
-{
- struct osmo_mdns_rfc_header *buf = (struct osmo_mdns_rfc_header *) msgb_put(msg, sizeof(*hdr));
- memcpy(buf, hdr, sizeof(*hdr));
-
- osmo_store16be(buf->id, &buf->id);
- osmo_store16be(buf->qdcount, &buf->qdcount);
- osmo_store16be(buf->ancount, &buf->ancount);
- osmo_store16be(buf->nscount, &buf->nscount);
- osmo_store16be(buf->arcount, &buf->arcount);
-}
-
-/*! Decode header section (RFC 1035 4.1.1). */
-int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_header *hdr)
-{
- if (data_len != sizeof(*hdr))
- return -EINVAL;
-
- memcpy(hdr, data, data_len);
-
- hdr->id = osmo_load16be(&hdr->id);
- hdr->qdcount = osmo_load16be(&hdr->qdcount);
- hdr->ancount = osmo_load16be(&hdr->ancount);
- hdr->nscount = osmo_load16be(&hdr->nscount);
- hdr->arcount = osmo_load16be(&hdr->arcount);
-
- return 0;
-}
-
-/*! Encode question section (RFC 1035 4.1.2).
- * \param[in] msgb mesage buffer to which the encoded data will be appended.
- */
-int osmo_mdns_rfc_question_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_question *qst)
-{
- char *qname;
- size_t qname_len;
- uint8_t *qname_buf;
-
- /* qname */
- qname = osmo_mdns_rfc_qname_encode(ctx, qst->domain);
- if (!qname)
- return -EINVAL;
- qname_len = strlen(qname) + 1;
- qname_buf = msgb_put(msg, qname_len);
- memcpy(qname_buf, qname, qname_len);
- talloc_free(qname);
-
- /* qtype and qclass */
- msgb_put_u16(msg, qst->qtype);
- msgb_put_u16(msg, qst->qclass);
-
- return 0;
-}
-
-/*! Decode question section (RFC 1035 4.1.2). */
-struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const uint8_t *data, size_t data_len)
-{
- struct osmo_mdns_rfc_question *ret;
- size_t qname_len = data_len - 4;
-
- if (data_len < 6)
- return NULL;
-
- /* qname */
- ret = talloc_zero(ctx, struct osmo_mdns_rfc_question);
- if (!ret)
- return NULL;
- ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, qname_len);
- if (!ret->domain) {
- talloc_free(ret);
- return NULL;
- }
-
- /* qtype and qclass */
- ret->qtype = osmo_load16be(data + qname_len);
- ret->qclass = osmo_load16be(data + qname_len + 2);
-
- return ret;
-}
-
-/*
- * Encode/decode resource records
- */
-
-/*! Encode one resource record (RFC 1035 4.1.3).
- * \param[in] msgb mesage buffer to which the encoded data will be appended.
- */
-int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_record *rec)
-{
- char *name;
- size_t name_len;
- uint8_t *buf;
-
- /* name */
- name = osmo_mdns_rfc_qname_encode(ctx, rec->domain);
- if (!name)
- return -EINVAL;
- name_len = strlen(name) + 1;
- buf = msgb_put(msg, name_len);
- memcpy(buf, name, name_len);
- talloc_free(name);
-
- /* type, class, ttl, rdlength */
- msgb_put_u16(msg, rec->type);
- msgb_put_u16(msg, rec->class);
- msgb_put_u32(msg, rec->ttl);
- msgb_put_u16(msg, rec->rdlength);
-
- /* rdata */
- buf = msgb_put(msg, rec->rdlength);
- memcpy(buf, rec->rdata, rec->rdlength);
- return 0;
-}
-
-/*! Decode one resource record (RFC 1035 4.1.3). */
-struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
- size_t *record_len)
-{
- struct osmo_mdns_rfc_record *ret = talloc_zero(ctx, struct osmo_mdns_rfc_record);
- size_t name_len;
-
- /* name */
- ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, data_len - 10);
- if (!ret->domain)
- goto error;
- name_len = strlen(ret->domain) + 2;
- if (name_len + 10 > data_len)
- goto error;
-
- /* type, class, ttl, rdlength */
- ret->type = osmo_load16be(data + name_len);
- ret->class = osmo_load16be(data + name_len + 2);
- ret->ttl = osmo_load32be(data + name_len + 4);
- ret->rdlength = osmo_load16be(data + name_len + 8);
- if (name_len + 10 + ret->rdlength > data_len)
- goto error;
-
- /* rdata */
- ret->rdata = talloc_memdup(ret, data + name_len + 10, ret->rdlength);
- if (!ret->rdata)
- return NULL;
-
- *record_len = name_len + 10 + ret->rdlength;
- return ret;
-error:
- talloc_free(ret);
- return NULL;
-}
-
diff --git a/src/mslookup/mdns_sock.c b/src/mslookup/mdns_sock.c
deleted file mode 100644
index 5291660..0000000
--- a/src/mslookup/mdns_sock.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <stdbool.h>
-#include <talloc.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/select.h>
-#include <osmocom/hlr/logging.h>
-#include <osmocom/mslookup/mdns_sock.h>
-
-/*! Open socket to send and receive multicast data.
- *
- * The socket is opened with SO_REUSEADDR, so we can bind to the same IP and port multiple times. This socket receives
- * everything sent to that multicast IP/port, including its own data data sent from osmo_mdns_sock_send(). So whenever
- * sending something, the receive callback will be called with the same data and should discard it.
- *
- * \param[in] ip multicast IPv4 or IPv6 address.
- * \param[in] port port number.
- * \param[in] cb callback for incoming data that will be passed to osmo_fd_setup (should read from osmo_fd->fd).
- * \param[in] data userdata passed to osmo_fd (available in cb as osmo_fd->data).
- * \param[in] priv_nr additional userdata integer passed to osmo_fd (available in cb as osmo_fd->priv_nr).
- * \returns allocated osmo_mdns_sock, NULL on error.
- */
-struct osmo_mdns_sock *osmo_mdns_sock_init(void *ctx, const char *ip, unsigned int port,
- int (*cb)(struct osmo_fd *fd, unsigned int what),
- void *data, unsigned int priv_nr)
-{
- struct osmo_mdns_sock *ret;
- int sock, rc;
- struct addrinfo hints = {0};
- struct ip_mreq multicast_req = {0};
- in_addr_t iface = INADDR_ANY;
- char portbuf[10];
- int y = 1;
-
- snprintf(portbuf, sizeof(portbuf) -1, "%u", port);
- ret = talloc_zero(ctx, struct osmo_mdns_sock);
- OSMO_ASSERT(ret);
-
- /* Fill addrinfo */
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = (AI_PASSIVE | AI_NUMERICHOST);
- rc = getaddrinfo(ip, portbuf, &hints, &ret->ai);
- if (rc != 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: getaddrinfo: %s\n", gai_strerror(rc));
- ret->ai = NULL;
- goto error;
- }
-
- /* Open socket */
- sock = socket(ret->ai->ai_family, ret->ai->ai_socktype, 0);
- if (sock == -1) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: socket: %s\n", strerror(errno));
- goto error;
- }
-
- /* Set multicast options */
- rc = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char*)&iface, sizeof(iface));
- if (rc == -1) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
- goto error;
- }
- memcpy(&multicast_req.imr_multiaddr, &((struct sockaddr_in*)(ret->ai->ai_addr))->sin_addr,
- sizeof(multicast_req.imr_multiaddr));
- multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
- rc = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicast_req, sizeof(multicast_req));
- if (rc == -1) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
- goto error;
- }
-
- /* Always allow binding the same IP and port twice. This is needed in OsmoHLR (where the code becomes cleaner by
- * just using a different socket for server and client code) and in the mslookup_client_mdns_test. Also for
- * osmo-mslookup-client if it is running multiple times in parallel (i.e. two incoming calls almost at the same
- * time need to be resolved with the simple dialplan example that just starts new processes). */
- rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&y, sizeof(y));
- if (rc == -1) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
- goto error;
- }
-
- /* Bind and register osmo_fd callback */
- rc = bind(sock, ret->ai->ai_addr, ret->ai->ai_addrlen);
- if (rc == -1) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: bind: %s\n", strerror(errno));
- goto error;
- }
- osmo_fd_setup(&ret->osmo_fd, sock, OSMO_FD_READ, cb, data, priv_nr);
- if (osmo_fd_register(&ret->osmo_fd) != 0)
- goto error;
-
- return ret;
-error:
- if (ret->ai)
- freeaddrinfo(ret->ai);
- talloc_free(ret);
- return NULL;
-}
-
-/*! Send msgb over mdns_sock and consume msgb.
- * \returns 0 on success, -1 on error.
- */
-int osmo_mdns_sock_send(const struct osmo_mdns_sock *mdns_sock, struct msgb *msg)
-{
- size_t len = msgb_length(msg);
- int rc = sendto(mdns_sock->osmo_fd.fd, msgb_data(msg), len, 0, mdns_sock->ai->ai_addr,
- mdns_sock->ai->ai_addrlen);
- msgb_free(msg);
- return (rc == len) ? 0 : -1;
-}
-
-/*! Tear down osmo_mdns_sock. */
-void osmo_mdns_sock_cleanup(struct osmo_mdns_sock *mdns_sock)
-{
- osmo_fd_close(&mdns_sock->osmo_fd);
- freeaddrinfo(mdns_sock->ai);
- talloc_free(mdns_sock);
-}
diff --git a/src/mslookup/mslookup_client_mdns.c b/src/mslookup/mslookup_client_mdns.c
deleted file mode 100644
index 7ba3502..0000000
--- a/src/mslookup/mslookup_client_mdns.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <errno.h>
-#include <osmocom/core/select.h>
-#include <osmocom/gsm/gsm_utils.h>
-#include <osmocom/hlr/logging.h>
-#include <osmocom/mslookup/mdns.h>
-#include <osmocom/mslookup/mdns_sock.h>
-#include <osmocom/mslookup/mslookup_client.h>
-#include <osmocom/mslookup/mslookup_client_mdns.h>
-
-struct osmo_mdns_method_state {
- /* Parameters passed by _add_method_dns() */
- struct osmo_sockaddr_str bind_addr;
- const char *domain_suffix;
-
- struct osmo_mdns_sock *mc;
-
- struct osmo_mslookup_client *client;
- struct llist_head requests;
- uint16_t next_packet_id;
-};
-
-struct osmo_mdns_method_request {
- struct llist_head entry;
- uint32_t request_handle;
- struct osmo_mslookup_query query;
- uint16_t packet_id;
-};
-
-static int request_handle_by_query(uint32_t *request_handle, struct osmo_mdns_method_state *state,
- struct osmo_mslookup_query *query, uint16_t packet_id)
-{
- struct osmo_mdns_method_request *request;
-
- llist_for_each_entry(request, &state->requests, entry) {
- if (strcmp(request->query.service, query->service) != 0)
- continue;
- if (osmo_mslookup_id_cmp(&request->query.id, &query->id) != 0)
- continue;
-
- /* Match! */
- *request_handle = request->request_handle;
- return 0;
- }
- return -1;
-}
-
-static int mdns_method_recv(struct osmo_fd *osmo_fd, unsigned int what)
-{
- struct osmo_mdns_method_state *state = osmo_fd->data;
- struct osmo_mslookup_result result;
- struct osmo_mslookup_query query;
- uint16_t packet_id;
- int n;
- uint8_t buffer[1024];
- uint32_t request_handle = 0;
- void *ctx = state;
-
- n = read(osmo_fd->fd, buffer, sizeof(buffer));
- if (n < 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "failed to read from socket\n");
- return n;
- }
-
- if (osmo_mdns_result_decode(ctx, buffer, n, &packet_id, &query, &result, state->domain_suffix) < 0)
- return -EINVAL;
-
- if (request_handle_by_query(&request_handle, state, &query, packet_id) != 0)
- return -EINVAL;
-
- osmo_mslookup_client_rx_result(state->client, request_handle, &result);
- return n;
-}
-
-static void mdns_method_request(struct osmo_mslookup_client_method *method, const struct osmo_mslookup_query *query,
- uint32_t request_handle)
-{
- char buf[256];
- struct osmo_mdns_method_state *state = method->priv;
- struct msgb *msg;
- struct osmo_mdns_method_request *r = talloc_zero(method->client, struct osmo_mdns_method_request);
-
- *r = (struct osmo_mdns_method_request){
- .request_handle = request_handle,
- .query = *query,
- .packet_id = state->next_packet_id,
- };
- llist_add(&r->entry, &state->requests);
- state->next_packet_id++;
-
- msg = osmo_mdns_query_encode(method->client, r->packet_id, query, state->domain_suffix);
- if (!msg) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "Cannot encode request: %s\n",
- osmo_mslookup_result_name_b(buf, sizeof(buf), query, NULL));
- }
-
- /* Send over the wire */
- LOGP(DMSLOOKUP, LOGL_DEBUG, "sending mDNS query: %s.%s\n", query->service,
- osmo_mslookup_id_name_b(buf, sizeof(buf), &query->id));
- if (osmo_mdns_sock_send(state->mc, msg) == -1)
- LOGP(DMSLOOKUP, LOGL_ERROR, "sending mDNS query failed\n");
-}
-
-static void mdns_method_request_cleanup(struct osmo_mslookup_client_method *method, uint32_t request_handle)
-{
- struct osmo_mdns_method_state *state = method->priv;
-
- /* Tear down any state associated with this handle. */
- struct osmo_mdns_method_request *r;
- llist_for_each_entry(r, &state->requests, entry) {
- if (r->request_handle != request_handle)
- continue;
- llist_del(&r->entry);
- talloc_free(r);
- return;
- }
-}
-
-static void mdns_method_destruct(struct osmo_mslookup_client_method *method)
-{
- struct osmo_mdns_method_state *state = method->priv;
- struct osmo_mdns_method_request *e, *n;
- if (!state)
- return;
-
- /* Drop all DNS lookup request state. Triggering a timeout event and cleanup for mslookup client users will
- * happen in the mslookup_client.c, we will simply stop responding from this lookup method. */
- llist_for_each_entry_safe(e, n, &state->requests, entry) {
- llist_del(&e->entry);
- }
-
- osmo_mdns_sock_cleanup(state->mc);
-}
-
-/*! Initialize the mDNS lookup method.
- * \param[in] client the client to attach the method to.
- * \param[in] ip IPv4 or IPv6 address string.
- * \param[in] port The port to bind to.
- * \param[in] initial_packet_id Used in the first mslookup query, then increased by one in each following query. All
- * servers answer to each query with the same packet ID. Set to -1 to use a random
- * initial ID (recommended unless you need deterministic output). This ID is for visually
- * distinguishing the packets in packet sniffers, the mslookup client uses not just the
- * ID, but all query parameters (service type, ID, ID type), to determine if a reply is
- * relevant.
- * \param[in] domain_suffix is appended to each domain in the queries to avoid colliding with the top-level domains
- * administrated by IANA. Example: "mdns.osmocom.org" */
-struct osmo_mslookup_client_method *osmo_mslookup_client_add_mdns(struct osmo_mslookup_client *client, const char *ip,
- uint16_t port, int initial_packet_id,
- const char *domain_suffix)
-{
- struct osmo_mdns_method_state *state;
- struct osmo_mslookup_client_method *m;
-
- m = talloc_zero(client, struct osmo_mslookup_client_method);
- OSMO_ASSERT(m);
-
- state = talloc_zero(m, struct osmo_mdns_method_state);
- OSMO_ASSERT(state);
- INIT_LLIST_HEAD(&state->requests);
- if (osmo_sockaddr_str_from_str(&state->bind_addr, ip, port)) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "mslookup mDNS: invalid address/port: %s %u\n",
- ip, port);
- goto error_cleanup;
- }
-
- if (initial_packet_id == -1) {
- if (osmo_get_rand_id((uint8_t *)&state->next_packet_id, 2) < 0) {
- LOGP(DMSLOOKUP, LOGL_ERROR, "mslookup mDNS: failed to generate random initial packet ID\n");
- goto error_cleanup;
- }
- } else
- state->next_packet_id = initial_packet_id;
-
- state->client = client;
- state->domain_suffix = domain_suffix;
-
- state->mc = osmo_mdns_sock_init(state, ip, port, mdns_method_recv, state, 0);
- if (!state->mc)
- goto error_cleanup;
-
- *m = (struct osmo_mslookup_client_method){
- .name = "mDNS",
- .priv = state,
- .request = mdns_method_request,
- .request_cleanup = mdns_method_request_cleanup,
- .destruct = mdns_method_destruct,
- };
-
- osmo_mslookup_client_method_add(client, m);
- return m;
-
-error_cleanup:
- talloc_free(m);
- return NULL;
-}
-
-const struct osmo_sockaddr_str *osmo_mslookup_client_method_mdns_get_bind_addr(struct osmo_mslookup_client_method *dns_method)
-{
- struct osmo_mdns_method_state *state;
- if (!dns_method || !dns_method->priv)
- return NULL;
- state = dns_method->priv;
- return &state->bind_addr;
-}
-
-const char *osmo_mslookup_client_method_mdns_get_domain_suffix(struct osmo_mslookup_client_method *dns_method)
-{
- struct osmo_mdns_method_state *state;
- if (!dns_method || !dns_method->priv)
- return NULL;
- state = dns_method->priv;
- return state->domain_suffix;
-}