diff options
Diffstat (limited to 'src/mslookup/mdns_msg.c')
-rw-r--r-- | src/mslookup/mdns_msg.c | 261 |
1 files changed, 0 insertions, 261 deletions
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; -} |