blob: 8a8cdec191511bf47b37ca5e9c062c514c54cf13 [file] [log] [blame]
Oliver Smith3a9f2672019-11-20 10:56:35 +01001/* Low level mDNS encoding and decoding functions of the qname IE, header/question sections and resource records,
2 * as described in these RFCs:
3 * - RFC 1035 (Domain names - implementation and specification)
4 * - RFC 3596 (DNS Extensions to Support IP Version 6) */
5
6/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27#include <osmocom/core/msgb.h>
28#include <osmocom/core/bitvec.h>
29#include <osmocom/core/logging.h>
Oliver Smith5decd492022-12-22 17:06:22 +010030#include <osmocom/gsm/apn.h>
Oliver Smith3a9f2672019-11-20 10:56:35 +010031#include <osmocom/mslookup/mdns_rfc.h>
32
33/*
Oliver Smith3a9f2672019-11-20 10:56:35 +010034 * Encode/decode message sections
35 */
36
37/*! Encode header section (RFC 1035 4.1.1).
38 * \param[in] msgb mesage buffer to which the encoded data will be appended.
39 */
40void osmo_mdns_rfc_header_encode(struct msgb *msg, const struct osmo_mdns_rfc_header *hdr)
41{
42 struct osmo_mdns_rfc_header *buf = (struct osmo_mdns_rfc_header *) msgb_put(msg, sizeof(*hdr));
43 memcpy(buf, hdr, sizeof(*hdr));
44
45 osmo_store16be(buf->id, &buf->id);
46 osmo_store16be(buf->qdcount, &buf->qdcount);
47 osmo_store16be(buf->ancount, &buf->ancount);
48 osmo_store16be(buf->nscount, &buf->nscount);
49 osmo_store16be(buf->arcount, &buf->arcount);
50}
51
52/*! Decode header section (RFC 1035 4.1.1). */
53int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_header *hdr)
54{
55 if (data_len != sizeof(*hdr))
56 return -EINVAL;
57
58 memcpy(hdr, data, data_len);
59
60 hdr->id = osmo_load16be(&hdr->id);
61 hdr->qdcount = osmo_load16be(&hdr->qdcount);
62 hdr->ancount = osmo_load16be(&hdr->ancount);
63 hdr->nscount = osmo_load16be(&hdr->nscount);
64 hdr->arcount = osmo_load16be(&hdr->arcount);
65
66 return 0;
67}
68
69/*! Encode question section (RFC 1035 4.1.2).
70 * \param[in] msgb mesage buffer to which the encoded data will be appended.
71 */
Oliver Smithf80ab762022-12-23 13:35:07 +010072int osmo_mdns_rfc_question_encode(struct msgb *msg, const struct osmo_mdns_rfc_question *qst)
Oliver Smith3a9f2672019-11-20 10:56:35 +010073{
Oliver Smith5decd492022-12-22 17:06:22 +010074 uint8_t *buf;
75 size_t buf_len;
Oliver Smith3a9f2672019-11-20 10:56:35 +010076
77 /* qname */
Oliver Smith5decd492022-12-22 17:06:22 +010078 buf_len = strlen(qst->domain) + 1;
79 buf = msgb_put(msg, buf_len);
80 if (osmo_apn_from_str(buf, buf_len, qst->domain) < 0)
Oliver Smith3a9f2672019-11-20 10:56:35 +010081 return -EINVAL;
Oliver Smith5decd492022-12-22 17:06:22 +010082 msgb_put_u8(msg, 0x00);
Oliver Smith3a9f2672019-11-20 10:56:35 +010083
84 /* qtype and qclass */
85 msgb_put_u16(msg, qst->qtype);
86 msgb_put_u16(msg, qst->qclass);
87
88 return 0;
89}
90
91/*! Decode question section (RFC 1035 4.1.2). */
92struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const uint8_t *data, size_t data_len)
93{
94 struct osmo_mdns_rfc_question *ret;
95 size_t qname_len = data_len - 4;
96
97 if (data_len < 6)
98 return NULL;
99
Oliver Smith3a9f2672019-11-20 10:56:35 +0100100 ret = talloc_zero(ctx, struct osmo_mdns_rfc_question);
101 if (!ret)
102 return NULL;
Oliver Smith5decd492022-12-22 17:06:22 +0100103
104 /* qname */
105 ret->domain = talloc_size(ret, qname_len - 1);
106 if (!ret->domain)
107 goto error;
108 if (!osmo_apn_to_str(ret->domain, data, qname_len - 1))
109 goto error;
Oliver Smith3a9f2672019-11-20 10:56:35 +0100110
111 /* qtype and qclass */
112 ret->qtype = osmo_load16be(data + qname_len);
113 ret->qclass = osmo_load16be(data + qname_len + 2);
114
115 return ret;
Oliver Smith5decd492022-12-22 17:06:22 +0100116error:
117 talloc_free(ret);
118 return NULL;
Oliver Smith3a9f2672019-11-20 10:56:35 +0100119}
120
121/*
122 * Encode/decode resource records
123 */
124
125/*! Encode one resource record (RFC 1035 4.1.3).
126 * \param[in] msgb mesage buffer to which the encoded data will be appended.
127 */
Oliver Smithf80ab762022-12-23 13:35:07 +0100128int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_record *rec)
Oliver Smith3a9f2672019-11-20 10:56:35 +0100129{
Oliver Smith3a9f2672019-11-20 10:56:35 +0100130 uint8_t *buf;
Oliver Smith5decd492022-12-22 17:06:22 +0100131 size_t buf_len;
Oliver Smith3a9f2672019-11-20 10:56:35 +0100132
133 /* name */
Oliver Smith5decd492022-12-22 17:06:22 +0100134 buf_len = strlen(rec->domain) + 1;
135 buf = msgb_put(msg, buf_len);
136 if (osmo_apn_from_str(buf, buf_len, rec->domain) < 0)
Oliver Smith3a9f2672019-11-20 10:56:35 +0100137 return -EINVAL;
Oliver Smith5decd492022-12-22 17:06:22 +0100138 msgb_put_u8(msg, 0x00);
Oliver Smith3a9f2672019-11-20 10:56:35 +0100139
140 /* type, class, ttl, rdlength */
141 msgb_put_u16(msg, rec->type);
142 msgb_put_u16(msg, rec->class);
143 msgb_put_u32(msg, rec->ttl);
144 msgb_put_u16(msg, rec->rdlength);
145
146 /* rdata */
147 buf = msgb_put(msg, rec->rdlength);
148 memcpy(buf, rec->rdata, rec->rdlength);
149 return 0;
150}
151
152/*! Decode one resource record (RFC 1035 4.1.3). */
153struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
154 size_t *record_len)
155{
Oliver Smith01155ea2022-12-23 12:51:31 +0100156 struct osmo_mdns_rfc_record *ret;
Oliver Smith3a9f2672019-11-20 10:56:35 +0100157 size_t name_len;
158
Oliver Smith5decd492022-12-22 17:06:22 +0100159 /* name length: represented as a series of labels, and terminated by a
160 * label with zero length (RFC 1035 3.3). A label with zero length is a
161 * NUL byte. */
162 name_len = strnlen((const char *)data, data_len - 10) + 1;
163 if (data[name_len])
164 return NULL;
165
166 /* allocate ret + ret->domain */
Oliver Smith01155ea2022-12-23 12:51:31 +0100167 ret = talloc_zero(ctx, struct osmo_mdns_rfc_record);
168 if (!ret)
169 return NULL;
Oliver Smith5decd492022-12-22 17:06:22 +0100170 ret->domain = talloc_size(ctx, name_len - 1);
Oliver Smith3a9f2672019-11-20 10:56:35 +0100171 if (!ret->domain)
172 goto error;
Oliver Smith5decd492022-12-22 17:06:22 +0100173
174 /* name */
175 if (!osmo_apn_to_str(ret->domain, data, name_len - 1))
Oliver Smith3a9f2672019-11-20 10:56:35 +0100176 goto error;
177
178 /* type, class, ttl, rdlength */
179 ret->type = osmo_load16be(data + name_len);
180 ret->class = osmo_load16be(data + name_len + 2);
181 ret->ttl = osmo_load32be(data + name_len + 4);
182 ret->rdlength = osmo_load16be(data + name_len + 8);
183 if (name_len + 10 + ret->rdlength > data_len)
184 goto error;
185
186 /* rdata */
187 ret->rdata = talloc_memdup(ret, data + name_len + 10, ret->rdlength);
188 if (!ret->rdata)
Oliver Smithc5f034b2022-12-23 12:53:12 +0100189 goto error;
Oliver Smith3a9f2672019-11-20 10:56:35 +0100190
191 *record_len = name_len + 10 + ret->rdlength;
192 return ret;
193error:
194 talloc_free(ret);
195 return NULL;
196}
197