ProtoCore
v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
dns_wire.h
Go to the documentation of this file.
1
// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2
// SPDX-License-Identifier: AGPL-3.0-or-later
3
4
/**
5
* @file dns_wire.h
6
* @brief The DNS name on the wire (RFC 1035 sec 3.1, sec 4.1.4): labels in, dotted string out.
7
*
8
* RFC 1035 sec 3.1: a domain name is a sequence of labels, each one a length octet followed by that
9
* many octets, ending in the null label of the root, which is a zero length octet. The high order
10
* two bits of a length octet are 00 for a label. RFC 1035 sec 4.1.4 gives 11 to a pointer, a two
11
* octet sequence whose remaining fourteen bits are the OFFSET of a prior occurrence of the same name
12
* in the message, and reserves 10 and 01.
13
*
14
* Every DNS-shaped protocol carries that encoding, so it is written once here: the unicast server
15
* answering a query and the multicast responder advertising a service read and write names through
16
* this handle.
17
*
18
* Names compare case-insensitively (RFC 1035 sec 2.3.3), which is a property of the encoding rather
19
* than of either caller, so the comparison sits here too.
20
*
21
* Pure: no state, no allocation, no I/O.
22
*
23
* @author Douglas Quigg (dstroy0)
24
* @date 2026
25
*/
26
27
#ifndef PROTOCORE_DNS_WIRE_H
28
#define PROTOCORE_DNS_WIRE_H
29
30
#include "
protocore_config.h
"
31
32
PROTOCORE_BEGIN_DECLS
33
34
/** @brief Longest label a name may carry, the six bits a length octet leaves (RFC 1035 sec 2.3.4). */
35
#define PROTOCORE_DNS_LABEL_MAX 63u
36
37
/** @brief Pointers one name may follow before it is read as a loop (RFC 1035 sec 4.1.4). */
38
#define PROTOCORE_DNS_PTR_HOPS 8u
39
40
/**
41
* @brief The message a name is read out of, and where its dotted text lands (RFC 1035 sec 4.1).
42
*/
43
typedef
struct
44
{
45
const
uint8_t *
pkt
;
///< the message the name sits in
46
size_t
len
;
///< octets in that message
47
size_t
off
;
///< where the name's first length octet sits
48
char
*
out
;
///< where the dotted, NUL-terminated name is written
49
size_t
out_cap
;
///< octets that buffer holds
50
proto_bool
allow_ptr
;
///< follow a pointer (RFC 1035 sec 4.1.4); false makes one a decode failure
51
}
DnsWireMsgArgs
;
52
53
/**
54
* @brief The dotted name to write, and where its label sequence lands (RFC 1035 sec 3.1).
55
*/
56
typedef
struct
57
{
58
const
char
*
dotted
;
///< the name as text, labels separated by dots, trailing root dot optional
59
uint8_t *
out
;
///< where the labels and the root octet are written
60
size_t
out_cap
;
///< octets that buffer holds
61
}
DnsWireTextArgs
;
62
63
/** @brief The pair a case-insensitive compare judges (RFC 1035 sec 2.3.3). */
64
typedef
struct
65
{
66
const
char
*
a
;
///< the left dotted name
67
const
char
*
b
;
///< the right dotted name
68
}
DnsWireCmpArgs
;
69
70
/**
71
* @brief The DNS name codec: labels to a dotted string, a dotted string to labels, and the compare.
72
*
73
* A caller sets the members a call takes, invokes it through ::DnsWire, and reads the outcome off
74
* the same handle.
75
*
76
* @var DnsWireNs::msg the message a decode reads, and where its dotted text lands
77
* @var DnsWireNs::text the dotted name an encode writes, and where its labels land
78
* @var DnsWireNs::cmp the pair a compare judges
79
* @var DnsWireNs::ok a decode's or a compare's true/false outcome
80
* @var DnsWireNs::next offset just past the name as it sits at @c msg.off, 0 on a failed decode
81
* @var DnsWireNs::n octets an encode wrote, 0 when it wrote none
82
* @var DnsWireNs::decode read the name at @c msg.off into @c msg.out as a dotted string
83
* @var DnsWireNs::encode write @c text.dotted into @c text.out as labels plus the root octet
84
* @var DnsWireNs::eq compare two dotted names ignoring ASCII case (RFC 1035 sec 2.3.3)
85
*
86
* decode follows pointers only with @c msg.allow_ptr, at most ::PROTOCORE_DNS_PTR_HOPS of them, so a
87
* message that points at itself terminates. The first name in a message has nothing earlier to point
88
* at, which makes a pointer in a question malformed by construction: the unicast server clears the
89
* flag, the responder reading answers sets it. @c next is where the name ends as it sits at
90
* @c msg.off, so a name ending in a pointer reports two octets past the pointer rather than the end
91
* of what it pointed at, and the caller keeps walking the record the name came from.
92
*
93
* decode reports false on a truncated name, a reserved label type, a label over
94
* ::PROTOCORE_DNS_LABEL_MAX, a name that does not fit @c msg.out_cap, or more than
95
* ::PROTOCORE_DNS_PTR_HOPS pointers.
96
*
97
* encode writes no pointer: an OFFSET is meaningful against one particular message, so composing one
98
* belongs to whoever lays that message out. An empty name is the root octet alone. It reports 0 when
99
* the name does not fit @c text.out_cap, carries an empty label, or carries one over
100
* ::PROTOCORE_DNS_LABEL_MAX.
101
*
102
* No storage member: every octet a call touches belongs to the caller, so nothing survives a call.
103
*/
104
typedef
struct
105
{
106
DnsWireMsgArgs
msg
;
///< what a decode reads (RFC 1035 sec 4.1.4)
107
DnsWireTextArgs
text
;
///< what an encode writes (RFC 1035 sec 3.1)
108
DnsWireCmpArgs
cmp
;
///< what a compare judges (RFC 1035 sec 2.3.3)
109
proto_bool
ok
;
110
size_t
next
;
111
size_t
n
;
112
}
DnsWireVars
;
113
114
/** @brief The operands and the outcome. */
115
extern
DnsWireVars
DnsWireV
;
116
117
/** @brief The entries. */
118
typedef
struct
119
{
120
void (*
const
decode)(uint8_t *work);
121
void (*
const
encode)(uint8_t *work);
122
void (*
const
eq)(uint8_t *work);
123
}
DnsWireNs
;
124
125
// What the table binds, defined once in the .c and taking one parameter each: everything
126
// else an entry needs is an operand in DnsWireV or a region of the borrow at a fixed offset.
127
void
protocore_dns_wire_decode
(uint8_t *work);
128
void
protocore_dns_wire_encode
(uint8_t *work);
129
void
protocore_dns_wire_eq
(uint8_t *work);
130
131
// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
132
// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
133
// `DnsWire.decode(work)` resolves to a named function and becomes a DIRECT call. An extern table
134
// leaves the call indirect and the symbol live at every level, -O2 -flto included.
135
static
const
DnsWireNs
DnsWire __attribute__((unused)) = {
136
.
decode
=
protocore_dns_wire_decode
,
137
.encode =
protocore_dns_wire_encode
,
138
.eq =
protocore_dns_wire_eq
,
139
};
140
141
PROTOCORE_END_DECLS
142
143
#endif
// PROTOCORE_DNS_WIRE_H
protocore_dns_wire_decode
void protocore_dns_wire_decode(uint8_t *work)
protocore_dns_wire_encode
void protocore_dns_wire_encode(uint8_t *work)
DnsWireV
DnsWireVars DnsWireV
The operands and the outcome.
protocore_dns_wire_eq
void protocore_dns_wire_eq(uint8_t *work)
protocore_config.h
DnsWireCmpArgs
The pair a case-insensitive compare judges (RFC 1035 sec 2.3.3).
Definition
dns_wire.h:65
DnsWireCmpArgs::a
const char * a
the left dotted name
Definition
dns_wire.h:66
DnsWireCmpArgs::b
const char * b
the right dotted name
Definition
dns_wire.h:67
DnsWireMsgArgs
The message a name is read out of, and where its dotted text lands (RFC 1035 sec 4....
Definition
dns_wire.h:44
DnsWireMsgArgs::pkt
const uint8_t * pkt
the message the name sits in
Definition
dns_wire.h:45
DnsWireMsgArgs::len
size_t len
octets in that message
Definition
dns_wire.h:46
DnsWireMsgArgs::out_cap
size_t out_cap
octets that buffer holds
Definition
dns_wire.h:49
DnsWireMsgArgs::out
char * out
where the dotted, NUL-terminated name is written
Definition
dns_wire.h:48
DnsWireMsgArgs::allow_ptr
proto_bool allow_ptr
follow a pointer (RFC 1035 sec 4.1.4); false makes one a decode failure
Definition
dns_wire.h:50
DnsWireMsgArgs::off
size_t off
where the name's first length octet sits
Definition
dns_wire.h:47
DnsWireNs
The entries.
Definition
dns_wire.h:119
DnsWireNs::decode
void(*const decode)(uint8_t *work)
Definition
dns_wire.h:120
DnsWireTextArgs
The dotted name to write, and where its label sequence lands (RFC 1035 sec 3.1).
Definition
dns_wire.h:57
DnsWireTextArgs::out_cap
size_t out_cap
octets that buffer holds
Definition
dns_wire.h:60
DnsWireTextArgs::dotted
const char * dotted
the name as text, labels separated by dots, trailing root dot optional
Definition
dns_wire.h:58
DnsWireTextArgs::out
uint8_t * out
where the labels and the root octet are written
Definition
dns_wire.h:59
DnsWireVars
Definition
dns_wire.h:105
DnsWireVars::next
size_t next
Definition
dns_wire.h:110
DnsWireVars::text
DnsWireTextArgs text
what an encode writes (RFC 1035 sec 3.1)
Definition
dns_wire.h:107
DnsWireVars::ok
proto_bool ok
Definition
dns_wire.h:109
DnsWireVars::msg
DnsWireMsgArgs msg
what a decode reads (RFC 1035 sec 4.1.4)
Definition
dns_wire.h:106
DnsWireVars::n
size_t n
Definition
dns_wire.h:111
DnsWireVars::cmp
DnsWireCmpArgs cmp
what a compare judges (RFC 1035 sec 2.3.3)
Definition
dns_wire.h:108
PROTOCORE_BEGIN_DECLS
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition
types.h:96
proto_bool
_Bool proto_bool
The truth value.
Definition
types.h:64
PROTOCORE_END_DECLS
#define PROTOCORE_END_DECLS
Definition
types.h:97
src
network_drivers
network
dns
dns_wire
dns_wire.h
Generated by
1.9.8