12
12
#include < stdio.h>
13
13
#include < ctype.h>
14
14
15
- namespace mlibc {
16
-
17
15
namespace {
18
- constexpr unsigned int RECORD_A = 1 ;
19
- constexpr unsigned int RECORD_CNAME = 5 ;
20
- constexpr unsigned int RECORD_PTR = 12 ;
21
- }
22
16
23
- static frg::string<MemoryAllocator> read_dns_name (char *buf, char *&it) {
17
+ enum class DnsClass : uint16_t {
18
+ IN = 1 ,
19
+ };
20
+
21
+ enum class ResourceRecord : uint16_t {
22
+ A = 1 ,
23
+ NS = 2 ,
24
+ CNAME = 5 ,
25
+ PTR = 12 ,
26
+ TXT = 16 ,
27
+ AAAA = 28 ,
28
+ OPT = 41 ,
29
+ };
30
+
31
+ frg::optional<frg::string<MemoryAllocator>> read_dns_name (frg::span<uint8_t > buf, size_t &offset) {
24
32
frg::string<MemoryAllocator> res{getAllocator ()};
25
- while (true ) {
26
- char code = *it++;
27
- if ((code & 0xC0 ) == 0xC0 ) {
33
+ while (offset < buf.size ()) {
34
+ uint8_t code = buf[offset++];
35
+
36
+ if ((code & 0xC0 ) == 0xC0 ) {
28
37
// pointer
29
- uint8_t offset = ((code & 0x3F ) << 8 ) | *it++;
30
- auto offset_it = buf + offset;
31
- return res + read_dns_name (buf, offset_it);
32
- } else if (!(code & 0xC0 )) {
33
- if (!code)
34
- break ;
38
+ if (offset + 1 > buf.size ()) {
39
+ return frg::null_opt;
40
+ }
41
+
42
+ uint8_t pointer_offset = ((code & 0x3F ) << 8 ) | buf[offset++];
43
+ if (pointer_offset >= buf.size ()) {
44
+ return frg::null_opt;
45
+ }
46
+
47
+ size_t sub_offset = pointer_offset;
48
+ auto sub_name = read_dns_name (buf, sub_offset);
49
+ if (!sub_name) {
50
+ return frg::null_opt;
51
+ }
52
+
53
+ return res + *sub_name;
54
+ } else if (!(code & 0xC0 )) {
55
+ if (!code) {
56
+ return res;
57
+ } else if (offset + code > buf.size ()) {
58
+ return frg::null_opt;
59
+ }
35
60
36
- for (int i = 0 ; i < code; i++)
37
- res += (*it++);
61
+ for (int i = 0 ; i < code; i++) {
62
+ res += buf[offset++];
63
+ }
38
64
39
- if (*it)
65
+ if (offset < buf. size () && buf[offset]) {
40
66
res += ' .' ;
67
+ }
41
68
} else {
42
- break ;
69
+ return frg::null_opt ;
43
70
}
44
71
}
45
72
46
- return res;
73
+ return frg::null_opt;
74
+ }
75
+
76
+ void writeUint16 (frg::string<MemoryAllocator> &request, uint16_t val) {
77
+ request += static_cast <char >(val >> 8 );
78
+ request += static_cast <char >(val & 0xFF );
79
+ };
80
+
81
+ uint16_t readUint16 (frg::span<uint8_t > buf, size_t offset) {
82
+ uint16_t val = 0 ;
83
+ memcpy (&val, buf.data () + offset, sizeof (val));
84
+ return ntohs (val);
47
85
}
48
86
87
+ } // namespace
88
+
89
+ namespace mlibc {
90
+
49
91
int lookup_name_dns (struct lookup_result &buf, const char *name,
50
92
frg::string<MemoryAllocator> &canon_name) {
51
93
frg::string<MemoryAllocator> request{getAllocator ()};
@@ -73,12 +115,8 @@ int lookup_name_dns(struct lookup_result &buf, const char *name,
73
115
}
74
116
75
117
request += char (0 );
76
- // set question type to fetch A records
77
- request += 0 ;
78
- request += 1 ;
79
- // set CLASS to IN
80
- request += 0 ;
81
- request += 1 ;
118
+ writeUint16 (request, static_cast <uint16_t >(ResourceRecord::A));
119
+ writeUint16 (request, static_cast <uint16_t >(DnsClass::IN));
82
120
83
121
struct sockaddr_in sin = {};
84
122
sin.sin_family = AF_INET;
@@ -105,48 +143,69 @@ int lookup_name_dns(struct lookup_result &buf, const char *name,
105
143
return -EAI_SYSTEM;
106
144
}
107
145
108
- char response[256 ];
146
+ uint8_t response[512 ];
109
147
ssize_t rlen;
110
148
int num_ans = 0 ;
111
- while ((rlen = recvfrom (fd, response, 256 , 0 , NULL , NULL )) >= 0 ) {
149
+ while ((rlen = recvfrom (fd, response, sizeof (response) , 0 , NULL , NULL )) >= 0 ) {
112
150
if ((size_t )rlen < sizeof (struct dns_header ))
113
151
continue ;
114
- auto response_header = reinterpret_cast <struct dns_header *>(response);
152
+ auto response_header = reinterpret_cast <struct dns_header *>(response);
115
153
if (response_header->identification != header.identification )
116
154
return -EAI_FAIL;
117
155
118
- auto it = response + sizeof (struct dns_header );
156
+ auto view = frg::span<uint8_t >{response, static_cast <size_t >(rlen)};
157
+ size_t offset = sizeof (struct dns_header );
158
+
119
159
for (int i = 0 ; i < ntohs (response_header->no_q ); i++) {
120
- auto dns_name = read_dns_name (response, it);
121
- (void ) dns_name;
122
- it += 4 ;
160
+ auto dns_name = read_dns_name (view, offset);
161
+ if (!dns_name)
162
+ return -EAI_FAIL;
163
+
164
+ // skip type and class
165
+ offset += 4 ;
123
166
}
124
167
125
168
for (int i = 0 ; i < ntohs (response_header->no_ans ); i++) {
169
+ auto dns_name = read_dns_name (view, offset);
170
+ if (!dns_name) {
171
+ return -EAI_FAIL;
172
+ } else if (offset + 10 > view.size ()) {
173
+ return -EAI_FAIL;
174
+ }
175
+
176
+ ResourceRecord rrType{readUint16 (view, offset + 0 )};
177
+ DnsClass rrClass{readUint16 (view, offset + 2 )};
178
+ // ignore TTL
179
+ uint16_t rrLength = readUint16 (view, offset + 8 );
180
+ offset += 10 ;
181
+
182
+ if (rrClass != DnsClass::IN || offset + rrLength > view.size ()) {
183
+ return -EAI_FAIL;
184
+ }
185
+
126
186
struct dns_addr_buf buffer;
127
- auto dns_name = read_dns_name (response, it);
128
-
129
- uint16_t rr_type = (it[0 ] << 8 ) | it[1 ];
130
- uint16_t rr_class = (it[2 ] << 8 ) | it[3 ];
131
- uint16_t rr_length = (it[8 ] << 8 ) | it[9 ];
132
- it += 10 ;
133
- (void )rr_class;
134
-
135
- switch (rr_type) {
136
- case RECORD_A:
137
- memcpy (buffer.addr , it, rr_length);
138
- it += rr_length;
187
+ switch (rrType) {
188
+ case ResourceRecord::A:
189
+ memcpy (buffer.addr , &view[offset], rrLength);
190
+ offset += rrLength;
139
191
buffer.family = AF_INET;
140
- buffer.name = std::move (dns_name);
192
+ buffer.name = std::move (* dns_name);
141
193
buf.buf .push (std::move (buffer));
142
194
break ;
143
- case RECORD_CNAME:
144
- canon_name = read_dns_name (response, it);
145
- buf.aliases .push (std::move (dns_name));
195
+ case ResourceRecord::CNAME: {
196
+ size_t suboffset = offset;
197
+ auto cname = read_dns_name (view, suboffset);
198
+ if (!cname) {
199
+ return -EAI_FAIL;
200
+ }
201
+ canon_name = std::move (*cname);
202
+ buf.aliases .push (std::move (*dns_name));
203
+ offset = suboffset;
146
204
break ;
205
+ }
147
206
default :
148
207
mlibc::infoLogger () << " lookup_name_dns: unknown rr type "
149
- << rr_type << frg::endlog;
208
+ << static_cast < uint16_t >(rrType) << frg::endlog;
150
209
break ;
151
210
}
152
211
}
@@ -175,7 +234,7 @@ int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int fam
175
234
request.resize (sizeof (header));
176
235
memcpy (request.data (), &header, sizeof (header));
177
236
178
- char addr_str[64 ];
237
+ char addr_str[INET6_ADDRSTRLEN ];
179
238
if (!inet_ntop (family, addr.data (), addr_str, sizeof (addr_str))) {
180
239
switch (errno) {
181
240
case EAFNOSUPPORT:
@@ -201,13 +260,8 @@ int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int fam
201
260
} while (ptr != 0 );
202
261
203
262
request += char (0 );
204
- // set question type to fetch PTR records
205
- request += 0 ;
206
- request += 12 ;
207
- // set CLASS to IN
208
- request += 0 ;
209
- request += 1 ;
210
-
263
+ writeUint16 (request, static_cast <uint16_t >(ResourceRecord::PTR));
264
+ writeUint16 (request, static_cast <uint16_t >(DnsClass::IN));
211
265
212
266
struct sockaddr_in sin = {};
213
267
sin.sin_family = AF_INET;
@@ -234,48 +288,62 @@ int lookup_addr_dns(frg::span<char> name, frg::array<uint8_t, 16> &addr, int fam
234
288
return -EAI_SYSTEM;
235
289
}
236
290
237
- char response[256 ];
291
+ uint8_t response[512 ];
238
292
ssize_t rlen;
239
293
int num_ans = 0 ;
240
- while ((rlen = recvfrom (fd, response, 256 , 0 , NULL , NULL )) >= 0 ) {
294
+ while ((rlen = recvfrom (fd, response, sizeof (response) , 0 , NULL , NULL )) >= 0 ) {
241
295
if ((size_t )rlen < sizeof (struct dns_header ))
242
296
continue ;
243
297
auto response_header = reinterpret_cast <struct dns_header *>(response);
244
298
if (response_header->identification != header.identification )
245
299
return -EAI_FAIL;
246
300
247
- auto it = response + sizeof (struct dns_header );
301
+ frg::span<uint8_t > view{response, static_cast <size_t >(rlen)};
302
+ size_t offset = sizeof (struct dns_header );
303
+
248
304
for (int i = 0 ; i < ntohs (response_header->no_q ); i++) {
249
- auto dns_name = read_dns_name (response, it);
250
- (void ) dns_name;
251
- it += 4 ;
305
+ auto dns_name = read_dns_name (view, offset);
306
+ if (!dns_name)
307
+ return -EAI_FAIL;
308
+
309
+ offset += 4 ;
252
310
}
253
311
254
312
for (int i = 0 ; i < ntohs (response_header->no_ans ); i++) {
255
- struct dns_addr_buf buffer;
256
- auto dns_name = read_dns_name (response, it);
313
+ auto dns_name = read_dns_name (view, offset);
314
+ if (!dns_name) {
315
+ return -EAI_FAIL;
316
+ } else if (offset + 10 > view.size ()) {
317
+ return -EAI_FAIL;
318
+ }
257
319
258
- uint16_t rr_type = (it[0 ] << 8 ) | it[1 ];
259
- uint16_t rr_class = (it[2 ] << 8 ) | it[3 ];
260
- uint16_t rr_length = (it[8 ] << 8 ) | it[9 ];
261
- it += 10 ;
262
- (void )rr_class;
263
- (void )rr_length;
320
+ ResourceRecord rrType{readUint16 (view, offset + 0 )};
321
+ DnsClass rrClass{readUint16 (view, offset + 2 )};
322
+ // ignore TTL
323
+ uint16_t rrLength = readUint16 (view, offset + 8 );
264
324
265
- ( void )dns_name ;
325
+ offset += 10 ;
266
326
267
- switch (rr_type) {
268
- case RECORD_PTR: {
269
- auto ptr_name = read_dns_name (response, it);
270
- if (ptr_name.size () >= name.size ())
327
+ if (rrClass != DnsClass::IN || offset + rrLength > view.size ()) {
328
+ return -EAI_FAIL;
329
+ }
330
+
331
+ struct dns_addr_buf buffer;
332
+ switch (rrType) {
333
+ case ResourceRecord::PTR: {
334
+ auto ptr_name = read_dns_name (view, offset);
335
+ if (!ptr_name) {
336
+ return -EAI_FAIL;
337
+ } else if (ptr_name->size () >= name.size ()) {
271
338
return -EAI_OVERFLOW;
272
- std::copy (ptr_name.begin (), ptr_name.end (), name.data ());
273
- name.data ()[ptr_name.size ()] = ' \0 ' ;
339
+ }
340
+ std::copy (ptr_name->begin (), ptr_name->end (), name.data ());
341
+ name.data ()[ptr_name->size ()] = ' \0 ' ;
274
342
return 1 ;
275
343
}
276
344
default :
277
345
mlibc::infoLogger () << " lookup_addr_dns: unknown rr type "
278
- << rr_type << frg::endlog;
346
+ << static_cast < uint16_t >(rrType) << frg::endlog;
279
347
break ;
280
348
}
281
349
num_ans += ntohs (response_header->no_ans );
0 commit comments