/src/open62541/deps/mdnsd/libmdnsd/1035.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "1035.h" |
2 | | #include <string.h> |
3 | | #include <stdio.h> |
4 | | |
5 | | #if defined(_MSC_VER) && _MSC_VER < 1900 |
6 | | |
7 | | __inline int msnds_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) |
8 | | { |
9 | | int count = -1; |
10 | | |
11 | | if (size != 0) |
12 | | count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); |
13 | | if (count == -1) |
14 | | count = _vscprintf(format, ap); |
15 | | |
16 | | return count; |
17 | | } |
18 | | |
19 | | __inline int msnds_snprintf(char *outBuf, size_t size, const char *format, ...) |
20 | | { |
21 | | int count; |
22 | | va_list ap; |
23 | | |
24 | | va_start(ap, format); |
25 | | count = msnds_vsnprintf(outBuf, size, format, ap); |
26 | | va_end(ap); |
27 | | |
28 | | return count; |
29 | | } |
30 | | |
31 | | #else |
32 | | |
33 | 403 | #define msnds_snprintf snprintf |
34 | | |
35 | | #endif |
36 | | |
37 | | uint16_t net2short(const unsigned char **bufp) |
38 | 41.6k | { |
39 | 41.6k | unsigned short int i; |
40 | 41.6k | memcpy(&i, *bufp, sizeof(short int)); |
41 | 41.6k | *bufp += 2; |
42 | 41.6k | return ntohs(i); |
43 | 41.6k | } |
44 | | |
45 | | uint32_t net2long(const unsigned char **bufp) |
46 | 7.69k | { |
47 | 7.69k | uint32_t l; |
48 | | |
49 | 7.69k | memcpy(&l, *bufp, sizeof(uint32_t)); |
50 | 7.69k | *bufp += 4; |
51 | | |
52 | 7.69k | return ntohl(l); |
53 | 7.69k | } |
54 | | |
55 | | void short2net(uint16_t i, unsigned char **bufp) |
56 | 0 | { |
57 | 0 | uint16_t x = htons(i); |
58 | 0 | memcpy(*bufp, &x, sizeof(uint16_t)); |
59 | 0 | *bufp += 2; |
60 | 0 | } |
61 | | |
62 | | void long2net(uint32_t l, unsigned char **bufp) |
63 | 0 | { |
64 | 0 | uint32_t x = htonl(l); |
65 | 0 | memcpy(*bufp, &x, sizeof(uint32_t)); |
66 | 0 | *bufp += 4; |
67 | 0 | } |
68 | | |
69 | | static unsigned short int _ldecomp(const unsigned char *ptr) |
70 | 2.41k | { |
71 | 2.41k | unsigned short int i; |
72 | | |
73 | 2.41k | i = (unsigned short int)(0xc0 ^ ptr[0]); |
74 | 2.41k | i = (unsigned short int)(i<<8); |
75 | 2.41k | i = (unsigned short int)(i | ptr[1]); |
76 | | |
77 | 2.41k | return i; |
78 | 2.41k | } |
79 | | |
80 | | static bool _label(struct message *m, const unsigned char **bufp, const unsigned char *bufEnd, char **namep) |
81 | 13.9k | { |
82 | 13.9k | int x; |
83 | 13.9k | const unsigned char *label; |
84 | 13.9k | char *name; |
85 | | |
86 | | /* Set namep to the end of the block */ |
87 | 13.9k | *namep = name = (char *)m->_packet + m->_len; |
88 | | |
89 | 13.9k | if (*bufp >= bufEnd) |
90 | 47 | return false; |
91 | | |
92 | | // forward buffer pointer until we find the first compressed label |
93 | 13.9k | bool moveBufp = true; |
94 | | /* Loop storing label in the block */ |
95 | 33.8k | do { |
96 | 33.8k | if (moveBufp) { |
97 | 16.8k | label = *bufp; |
98 | 16.8k | } |
99 | | |
100 | 33.8k | if (label >= bufEnd) { |
101 | 604 | break; |
102 | 604 | } |
103 | | |
104 | | /* Since every domain name ends with the null label of |
105 | | the root, a domain name is terminated by a length byte of zero. */ |
106 | 33.2k | if (*label == 0) { |
107 | 13.1k | if (moveBufp) { |
108 | 11.8k | *bufp += 1; |
109 | 11.8k | } |
110 | 13.1k | break; |
111 | 13.1k | } |
112 | | |
113 | | |
114 | | /* Skip past any compression pointers, kick out if end encountered (bad data prolly) */ |
115 | | |
116 | | /* If a label is compressed, it has following structure of 2 bytes: |
117 | | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
118 | | * | 1 1| OFFSET | |
119 | | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
120 | | * |
121 | | * The OFFSET field specifies an offset from |
122 | | * the start of the message (i.e., the first octet of the ID field in the |
123 | | * domain header). A zero offset specifies the first byte of the ID field, |
124 | | * etc. |
125 | | **/ |
126 | 20.1k | if (*label & 0xc0) { |
127 | 2.41k | if (label + 2 > bufEnd) |
128 | 9 | return false; |
129 | 2.41k | unsigned short int offset = _ldecomp(label); |
130 | 2.41k | if (offset > m->_len) |
131 | 22 | return false; |
132 | 2.38k | if (m->_buf + offset >= bufEnd) |
133 | 10 | return false; |
134 | 2.37k | label = m->_buf + offset; |
135 | | // chek if label is again pointer, then abort. |
136 | 2.37k | if (*label & 0xc0) |
137 | 5 | return false; |
138 | 2.37k | moveBufp = false; |
139 | 2.37k | *bufp += 2; |
140 | 2.37k | } |
141 | | |
142 | | |
143 | | /* Make sure we're not over the limits |
144 | | * See https://tools.ietf.org/html/rfc1035 |
145 | | * 2.3.4. Size limits |
146 | | * */ |
147 | 20.0k | const unsigned char labelLen = (unsigned char)*label; |
148 | 20.0k | if (labelLen > 63) |
149 | | // maximum label length is 63 octets |
150 | 0 | return false; |
151 | 20.0k | if ((name + labelLen) - *namep > 255) |
152 | | // maximum names length is 255 octets |
153 | 3 | return false; |
154 | | |
155 | 20.0k | if (label + 1 + labelLen > bufEnd) { |
156 | 14 | return false; |
157 | 14 | } |
158 | 20.0k | if ((unsigned char*)name + labelLen > m->_packet + MAX_PACKET_LEN) { |
159 | 1 | return false; |
160 | 1 | } |
161 | | /* Copy chars for this label */ |
162 | 20.0k | memcpy(name, label + 1, labelLen); |
163 | 20.0k | name[labelLen] = '.'; |
164 | | |
165 | 20.0k | name += labelLen + 1; |
166 | | |
167 | 20.0k | if (moveBufp) { |
168 | 2.94k | *bufp += labelLen + 1; |
169 | 2.94k | } |
170 | 17.0k | else { |
171 | 17.0k | label += labelLen +1; |
172 | 17.0k | } |
173 | | |
174 | 20.0k | } while (*bufp <= bufEnd); |
175 | | |
176 | 13.8k | if ((unsigned char*)name >= m->_packet + MAX_PACKET_LEN) { |
177 | 4 | return false; |
178 | 4 | } |
179 | | |
180 | | /* Terminate name and check for cache or cache it */ |
181 | 13.8k | *name = '\0'; |
182 | 23.6k | for (x = 0; x < MAX_NUM_LABELS && m->_labels[x]; x++) { |
183 | 20.5k | if (strcmp(*namep, m->_labels[x])) |
184 | 9.82k | continue; |
185 | | |
186 | 10.7k | *namep = m->_labels[x]; |
187 | 10.7k | return true; |
188 | 20.5k | } |
189 | | |
190 | | /* No cache, so cache it if room */ |
191 | 3.12k | if (x < MAX_NUM_LABELS && m->_labels[x] == 0) { |
192 | 2.89k | m->_labels[x] = *namep; |
193 | 2.89k | } |
194 | 3.12k | m->_len += (unsigned long)((name - *namep) + 1); |
195 | | |
196 | 3.12k | return true; |
197 | 13.8k | } |
198 | | |
199 | | /* Internal label matching */ |
200 | | static int _lmatch(struct message *m, const char *l1, const char *l2) |
201 | 0 | { |
202 | 0 | int len; |
203 | | |
204 | | /* Always ensure we get called w/o a pointer */ |
205 | 0 | if (*l1 & 0xc0) |
206 | 0 | return _lmatch(m, (char*)m->_buf + _ldecomp((const unsigned char*)l1), l2); |
207 | 0 | if (*l2 & 0xc0) |
208 | 0 | return _lmatch(m, l1, (char*)m->_buf + _ldecomp((const unsigned char*) l2)); |
209 | | |
210 | | /* Same already? */ |
211 | 0 | if (l1 == l2) |
212 | 0 | return 1; |
213 | | |
214 | | /* Compare all label characters */ |
215 | 0 | if (*l1 != *l2) |
216 | 0 | return 0; |
217 | 0 | for (len = 1; len <= *l1; len++) { |
218 | 0 | if (l1[len] != l2[len]) |
219 | 0 | return 0; |
220 | 0 | } |
221 | | |
222 | | /* Get new labels */ |
223 | 0 | l1 += *l1 + 1; |
224 | 0 | l2 += *l2 + 1; |
225 | | |
226 | | /* At the end, all matched */ |
227 | 0 | if (*l1 == 0 && *l2 == 0) |
228 | 0 | return 1; |
229 | | |
230 | | /* Try next labels */ |
231 | 0 | return _lmatch(m, l1, l2); |
232 | 0 | } |
233 | | |
234 | | /* Nasty, convert host into label using compression */ |
235 | | static int _host(struct message *m, unsigned char **bufp, char *name) |
236 | 0 | { |
237 | 0 | char label[256], *l; |
238 | 0 | int len = 0, x = 1, y = 0, last = 0; |
239 | |
|
240 | 0 | if (name == 0) |
241 | 0 | return 0; |
242 | | |
243 | | /* Make our label */ |
244 | 0 | while (name[y]) { |
245 | 0 | if (name[y] == '.') { |
246 | 0 | if (!name[y + 1]) |
247 | 0 | break; |
248 | 0 | label[last] = (char)(x - (last + 1)); |
249 | 0 | last = x; |
250 | 0 | } else { |
251 | 0 | label[x] = name[y]; |
252 | 0 | } |
253 | | |
254 | 0 | if (x++ == 255) |
255 | 0 | return 0; |
256 | | |
257 | 0 | y++; |
258 | 0 | } |
259 | | |
260 | 0 | label[last] = (char)(x - (last + 1)); |
261 | 0 | if (x == 1) |
262 | 0 | x--; /* Special case, bad names, but handle correctly */ |
263 | 0 | len = x + 1; |
264 | 0 | label[x] = 0; /* Always terminate w/ a 0 */ |
265 | | |
266 | | /* Double-loop checking each label against all m->_labels for match */ |
267 | 0 | for (x = 0; label[x]; x += label[x] + 1) { |
268 | 0 | for (y = 0; y < MAX_NUM_LABELS && m->_labels[y]; y++) { |
269 | 0 | if (_lmatch(m, label + x, m->_labels[y])) { |
270 | | /* Matching label, set up pointer */ |
271 | 0 | l = label + x; |
272 | 0 | short2net((unsigned short)((unsigned char *)m->_labels[y] - m->_packet), (unsigned char **)&l); |
273 | 0 | label[x] = (char)(label[x] | 0xc0); |
274 | 0 | len = x + 2; |
275 | 0 | break; |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | if (label[x] & 0xc0) |
280 | 0 | break; |
281 | 0 | } |
282 | | |
283 | | /* Copy into buffer, point there now */ |
284 | 0 | memcpy(*bufp, label, (size_t)len); |
285 | 0 | l = (char *)*bufp; |
286 | 0 | *bufp += len; |
287 | | |
288 | | /* For each new label, store it's location for future compression */ |
289 | 0 | for (x = 0; l[x] && m->_label < MAX_NUM_LABELS; x += l[x] + 1) { |
290 | 0 | if (l[x] & 0xc0) |
291 | 0 | break; |
292 | | |
293 | 0 | m->_labels[m->_label++] = l + x; |
294 | 0 | } |
295 | |
|
296 | 0 | return len; |
297 | 0 | } |
298 | | |
299 | | static bool _rrparse(struct message *m, struct resource *rr, int count, const unsigned char **bufp, const unsigned char* bufferEnd) |
300 | 3.76k | { |
301 | 3.76k | int i; |
302 | 3.76k | const unsigned char *addr_bytes = NULL; |
303 | | |
304 | 3.76k | if (count == 0) { |
305 | 2.46k | return true; |
306 | 2.46k | } |
307 | | |
308 | 1.29k | if (*bufp >= m->_bufEnd) { |
309 | 14 | return false; |
310 | 14 | } |
311 | | |
312 | 8.90k | for (i = 0; i < count; i++) { |
313 | 7.77k | if (*bufp >= bufferEnd) { |
314 | 32 | return false; |
315 | 32 | } |
316 | | |
317 | 7.73k | if (!_label(m, bufp, bufferEnd, &(rr[i].name))) { |
318 | 25 | return false; |
319 | 25 | } |
320 | 7.71k | if (*bufp + 10 > bufferEnd) { |
321 | 17 | return false; |
322 | 17 | } |
323 | 7.69k | rr[i].type = net2short(bufp); |
324 | 7.69k | rr[i].clazz = net2short(bufp); |
325 | 7.69k | rr[i].ttl = net2long(bufp); |
326 | 7.69k | rr[i].rdlength = net2short(bufp); |
327 | | // fprintf(stderr, "Record type %d class 0x%2x ttl %lu len %d\n", rr[i].type, rr[i].clazz, rr[i].ttl, rr[i].rdlength); |
328 | | |
329 | | /* For the following records the rdata will be parsed later. So don't set it here: |
330 | | * NS, CNAME, PTR, DNAME, SOA, MX, AFSDB, RT, KX, RP, PX, SRV, NSEC |
331 | | * See 18.14 of https://tools.ietf.org/html/rfc6762#page-47 */ |
332 | 7.69k | if (rr[i].type == QTYPE_NS || rr[i].type == QTYPE_CNAME || rr[i].type == QTYPE_PTR || rr[i].type == QTYPE_SRV) { |
333 | 3.34k | rr[i].rdlength = 0; |
334 | 4.35k | } else { |
335 | | /* If not going to overflow, make copy of source rdata */ |
336 | 4.35k | if (*bufp + rr[i].rdlength > bufferEnd) { |
337 | 19 | return false; |
338 | 19 | } |
339 | | |
340 | 4.33k | if (m->_len + rr[i].rdlength > MAX_PACKET_LEN) { |
341 | 2 | return false; |
342 | 2 | } |
343 | 4.33k | rr[i].rdata = m->_packet + m->_len; |
344 | 4.33k | m->_len += rr[i].rdlength; |
345 | 4.33k | memcpy(rr[i].rdata, *bufp, rr[i].rdlength); |
346 | 4.33k | } |
347 | | |
348 | | |
349 | | /* Parse commonly known ones */ |
350 | 7.67k | switch (rr[i].type) { |
351 | 421 | case QTYPE_A: |
352 | 421 | if (m->_len + 16 > MAX_PACKET_LEN) { |
353 | 6 | return false; |
354 | 6 | } |
355 | 415 | rr[i].known.a.name = (char *)m->_packet + m->_len; |
356 | 415 | m->_len += 16; |
357 | 415 | if (*bufp + 4 > bufferEnd) { |
358 | 12 | return false; |
359 | 12 | } |
360 | 403 | msnds_snprintf(rr[i].known.a.name,16, "%d.%d.%d.%d", (*bufp)[0], (*bufp)[1], (*bufp)[2], (*bufp)[3]); |
361 | 403 | addr_bytes = (const unsigned char *) *bufp; |
362 | 403 | rr[i].known.a.ip.s_addr = (in_addr_t) ( |
363 | 403 | ((in_addr_t) addr_bytes[0]) | |
364 | 403 | (((in_addr_t) addr_bytes[1]) << 8) | |
365 | 403 | (((in_addr_t) addr_bytes[2]) << 16) | |
366 | 403 | (((in_addr_t) addr_bytes[3]) << 24)); |
367 | 403 | *bufp += 4; |
368 | 403 | break; |
369 | | |
370 | 230 | case QTYPE_AAAA: |
371 | 230 | if (m->_len + INET6_ADDRSTRLEN > MAX_PACKET_LEN) { |
372 | 6 | return false; |
373 | 6 | } |
374 | 224 | rr[i].known.aaaa.name = (char *)m->_packet + m->_len; |
375 | 224 | m->_len += INET6_ADDRSTRLEN; |
376 | 224 | if (*bufp + rr->rdlength > bufferEnd) { |
377 | 8 | return false; |
378 | 8 | } |
379 | 216 | addr_bytes = (const unsigned char *)*bufp; |
380 | 216 | inet_ntop(AF_INET6,addr_bytes,rr[i].known.aaaa.name,INET6_ADDRSTRLEN); |
381 | 2.95k | for (size_t j = 0; j < rr->rdlength; j++) { |
382 | 2.74k | rr[i].known.aaaa.ip6.s6_addr[j] = addr_bytes[j]; |
383 | 2.74k | } |
384 | 216 | *bufp += rr->rdlength; |
385 | 216 | break; |
386 | | |
387 | 341 | case QTYPE_NS: |
388 | 341 | if (!_label(m, bufp, bufferEnd, &(rr[i].known.ns.name))) { |
389 | 7 | return false; |
390 | 7 | } |
391 | 334 | break; |
392 | | |
393 | 750 | case QTYPE_CNAME: |
394 | 750 | if (!_label(m, bufp, bufferEnd, &(rr[i].known.cname.name))) { |
395 | 5 | return false; |
396 | 5 | } |
397 | 745 | break; |
398 | | |
399 | 745 | case QTYPE_PTR: |
400 | 579 | if (!_label(m, bufp, bufferEnd, &(rr[i].known.ptr.name))) { |
401 | 7 | return false; |
402 | 7 | } |
403 | 572 | break; |
404 | | |
405 | 1.67k | case QTYPE_SRV: |
406 | 1.67k | if (*bufp + 6 > bufferEnd) { |
407 | 6 | return false; |
408 | 6 | } |
409 | 1.66k | rr[i].known.srv.priority = net2short(bufp); |
410 | 1.66k | rr[i].known.srv.weight = net2short(bufp); |
411 | 1.66k | rr[i].known.srv.port = net2short(bufp); |
412 | 1.66k | if (!_label(m, bufp, bufferEnd, &(rr[i].known.srv.name))) { |
413 | 2 | return false; |
414 | 2 | } |
415 | 1.66k | break; |
416 | | |
417 | 1.66k | case QTYPE_TXT: |
418 | 3.68k | default: |
419 | 3.68k | *bufp += rr[i].rdlength; |
420 | 7.67k | } |
421 | 7.67k | } |
422 | | |
423 | 1.13k | return true; |
424 | 1.28k | } |
425 | | |
426 | | /* Keep all our mem in one (aligned) block for easy freeing */ |
427 | | #define my(x,y, cast) \ |
428 | 6.32k | while (m->_len & 7) \ |
429 | 5.81k | m->_len++; \ |
430 | 5.81k | \ |
431 | 5.81k | if (m->_len + y > MAX_PACKET_LEN) { return false; } \ |
432 | 5.81k | x = (cast)(void *)(m->_packet + m->_len); \ |
433 | 5.76k | m->_len += y; |
434 | | |
435 | | bool message_parse(struct message *m, unsigned char *packet, size_t packetLen) |
436 | 1.68k | { |
437 | 1.68k | int i; |
438 | 1.68k | const unsigned char *buf; |
439 | 1.68k | m->_bufEnd = packet + packetLen; |
440 | | |
441 | | /* Message format: https://tools.ietf.org/html/rfc1035 |
442 | | |
443 | | +---------------------+ |
444 | | | Header | |
445 | | +---------------------+ |
446 | | | Question | the question for the name server |
447 | | +---------------------+ |
448 | | | Answer | RRs answering the question |
449 | | +---------------------+ |
450 | | | Authority | RRs pointing toward an authority |
451 | | +---------------------+ |
452 | | | Additional | RRs holding additional information |
453 | | +---------------------+ |
454 | | */ |
455 | | |
456 | 1.68k | if (packet == 0 || m == 0) |
457 | 0 | return false; |
458 | | |
459 | | /* See https://tools.ietf.org/html/rfc1035 |
460 | | 1 1 1 1 1 1 |
461 | | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
462 | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
463 | | | ID | |
464 | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
465 | | |QR| Opcode |AA|TC|RD|RA| Z | RCODE | |
466 | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
467 | | | QDCOUNT | |
468 | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
469 | | | ANCOUNT | |
470 | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
471 | | | NSCOUNT | |
472 | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
473 | | | ARCOUNT | |
474 | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
475 | | */ |
476 | | |
477 | | /* The header always needs to be present. Size = 12 byte */ |
478 | 1.68k | if (packetLen < 12) |
479 | 6 | return false; |
480 | | |
481 | | /* Header stuff bit crap */ |
482 | 1.68k | buf = m->_buf = packet; |
483 | 1.68k | m->id = net2short(&buf); |
484 | 1.68k | if (buf[0] & 0x80) |
485 | 1.28k | m->header.qr = 1; |
486 | 1.68k | m->header.opcode = (unsigned short)(((buf[0] & 0x78) >> 3) & 15); |
487 | 1.68k | if (buf[0] & 0x04) |
488 | 734 | m->header.aa = 1; |
489 | 1.68k | if (buf[0] & 0x02) |
490 | 832 | m->header.tc = 1; |
491 | 1.68k | if (buf[0] & 0x01) |
492 | 651 | m->header.rd = 1; |
493 | 1.68k | if (buf[1] & 0x80) |
494 | 569 | m->header.ra = 1; |
495 | 1.68k | m->header.z = (unsigned short)(((buf[1] & 0x70) >> 4) & 7); |
496 | 1.68k | m->header.rcode = (unsigned short)(buf[1] & 0x0F); |
497 | 1.68k | buf += 2; |
498 | | |
499 | 1.68k | m->qdcount = net2short(&buf); |
500 | 1.68k | m->ancount = net2short(&buf); |
501 | 1.68k | m->nscount = net2short(&buf); |
502 | 1.68k | m->arcount = net2short(&buf); |
503 | | |
504 | | // check if the message has the correct size, i.e. the count matches the number of bytes |
505 | | |
506 | | /* Process questions */ |
507 | 1.68k | my(m->qd, (sizeof(struct question) * m->qdcount), struct question *); |
508 | 4.26k | for (i = 0; i < m->qdcount; i++) { |
509 | 2.87k | if (!_label(m, &buf, m->_bufEnd, &(m->qd[i].name))) { |
510 | 69 | return false; |
511 | 69 | } |
512 | 2.80k | if (buf + 4 > m->_bufEnd) { |
513 | 210 | return false; |
514 | 210 | } |
515 | 2.59k | m->qd[i].type = net2short(&buf); |
516 | 2.59k | m->qd[i].clazz = net2short(&buf); |
517 | 2.59k | } |
518 | 1.39k | if (buf > m->_bufEnd) { |
519 | 0 | return false; |
520 | 0 | } |
521 | | |
522 | | /* Process rrs */ |
523 | 2.76k | my(m->an, (sizeof(struct resource) * m->ancount), struct resource *); |
524 | 2.76k | my(m->ns, (sizeof(struct resource) * m->nscount), struct resource *); |
525 | 1.36k | my(m->ar, (sizeof(struct resource) * m->arcount), struct resource *); |
526 | 1.35k | if (!_rrparse(m, m->an, m->ancount, &buf, m->_bufEnd)) |
527 | 136 | return false; |
528 | 1.21k | if (!_rrparse(m, m->ns, m->nscount, &buf, m->_bufEnd)) |
529 | 21 | return false; |
530 | 1.19k | if (!_rrparse(m, m->ar, m->arcount, &buf, m->_bufEnd)) |
531 | 11 | return false; |
532 | 1.18k | return true; |
533 | 1.19k | } |
534 | | |
535 | | void message_qd(struct message *m, char *name, unsigned short int type, unsigned short int clazz) |
536 | 0 | { |
537 | 0 | m->qdcount++; |
538 | 0 | if (m->_buf == 0) { |
539 | 0 | m->_buf = m->_packet + 12; |
540 | 0 | m->_bufEnd = m->_packet + sizeof(m->_packet); |
541 | 0 | } |
542 | 0 | _host(m, &(m->_buf), name); |
543 | 0 | short2net(type, &(m->_buf)); |
544 | 0 | short2net(clazz, &(m->_buf)); |
545 | 0 | } |
546 | | |
547 | | static void _rrappend(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long ttl) |
548 | 0 | { |
549 | 0 | if (m->_buf == 0) { |
550 | 0 | m->_buf = m->_packet + 12; |
551 | 0 | m->_bufEnd = m->_packet + sizeof(m->_packet); |
552 | 0 | } |
553 | 0 | _host(m, &(m->_buf), name); |
554 | 0 | short2net(type, &(m->_buf)); |
555 | 0 | short2net(clazz, &(m->_buf)); |
556 | 0 | long2net((uint32_t)ttl, &(m->_buf)); |
557 | 0 | } |
558 | | |
559 | | void message_an(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long ttl) |
560 | 0 | { |
561 | 0 | m->ancount++; |
562 | 0 | _rrappend(m, name, type, clazz, ttl); |
563 | 0 | } |
564 | | |
565 | | void message_ns(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long ttl) |
566 | 0 | { |
567 | 0 | m->nscount++; |
568 | 0 | _rrappend(m, name, type, clazz, ttl); |
569 | 0 | } |
570 | | |
571 | | void message_ar(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long ttl) |
572 | 0 | { |
573 | 0 | m->arcount++; |
574 | 0 | _rrappend(m, name, type, clazz, ttl); |
575 | 0 | } |
576 | | |
577 | | void message_rdata_long(struct message *m, struct in_addr l) |
578 | 0 | { |
579 | 0 | short2net(4, &(m->_buf)); |
580 | 0 | long2net(l.s_addr, &(m->_buf)); |
581 | 0 | } |
582 | | |
583 | | void message_rdata_name(struct message *m, char *name) |
584 | 0 | { |
585 | 0 | unsigned char *mybuf = m->_buf; |
586 | |
|
587 | 0 | m->_buf += 2; |
588 | 0 | short2net((unsigned short)_host(m, &(m->_buf), name), &mybuf); |
589 | 0 | } |
590 | | |
591 | | void message_rdata_srv(struct message *m, unsigned short int priority, unsigned short int weight, unsigned short int port, char *name) |
592 | 0 | { |
593 | 0 | unsigned char *mybuf = m->_buf; |
594 | |
|
595 | 0 | m->_buf += 2; |
596 | 0 | short2net(priority, &(m->_buf)); |
597 | 0 | short2net(weight, &(m->_buf)); |
598 | 0 | short2net(port, &(m->_buf)); |
599 | 0 | short2net((unsigned short)(_host(m, &(m->_buf), name) + 6), &mybuf); |
600 | 0 | } |
601 | | |
602 | | void message_rdata_raw(struct message *m, unsigned char *rdata, unsigned short int rdlength) |
603 | 0 | { |
604 | 0 | if (((unsigned char *)m->_buf - m->_packet) + rdlength > 4096) |
605 | 0 | rdlength = 0; |
606 | 0 | short2net(rdlength, &(m->_buf)); |
607 | 0 | memcpy(m->_buf, rdata, rdlength); |
608 | 0 | m->_buf += rdlength; |
609 | 0 | } |
610 | | |
611 | | unsigned char *message_packet(struct message *m) |
612 | 0 | { |
613 | 0 | unsigned char c, *buf = m->_buf, *bufEnd = m->_bufEnd; |
614 | |
|
615 | 0 | m->_buf = m->_packet; |
616 | 0 | m->_bufEnd = m->_packet + sizeof(m->_packet); |
617 | 0 | short2net(m->id, &(m->_buf)); |
618 | |
|
619 | 0 | if (m->header.qr) |
620 | 0 | m->_buf[0] |= 0x80; |
621 | 0 | if ((c = (unsigned char)m->header.opcode)) |
622 | 0 | m->_buf[0] |= (unsigned char)(c << 3); |
623 | 0 | if (m->header.aa) |
624 | 0 | m->_buf[0] |= 0x04; |
625 | 0 | if (m->header.tc) |
626 | 0 | m->_buf[0] |= 0x02; |
627 | 0 | if (m->header.rd) |
628 | 0 | m->_buf[0] |= 0x01; |
629 | 0 | if (m->header.ra) |
630 | 0 | m->_buf[1] |= 0x80; |
631 | 0 | if ((c = (unsigned char)m->header.z)) |
632 | 0 | m->_buf[1] |= (unsigned char)(c << 4); |
633 | 0 | if (m->header.rcode) |
634 | 0 | m->_buf[1] = (unsigned char)(m->_buf[1] | m->header.rcode); |
635 | |
|
636 | 0 | m->_buf += 2; |
637 | 0 | short2net(m->qdcount, &(m->_buf)); |
638 | 0 | short2net(m->ancount, &(m->_buf)); |
639 | 0 | short2net(m->nscount, &(m->_buf)); |
640 | 0 | short2net(m->arcount, &(m->_buf)); |
641 | 0 | m->_buf = buf; /* Restore, so packet_len works */ |
642 | 0 | m->_bufEnd = bufEnd; |
643 | |
|
644 | 0 | return m->_packet; |
645 | 0 | } |
646 | | |
647 | | int message_packet_len(struct message *m) |
648 | 0 | { |
649 | 0 | if (m->_buf == 0) |
650 | 0 | return 12; |
651 | | |
652 | 0 | return (int)((unsigned char *)m->_buf - m->_packet); |
653 | 0 | } |