Coverage Report

Created: 2026-07-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/open62541_15/src_generated/mdnsd/1035.c
Line
Count
Source
1
#include "open62541/config.h"
2
/* Standalone DNS parsing, RFC10350
3
 *
4
 * Copyright (c) 2003  Jeremie Miller <jer@jabber.org>
5
 * Copyright (c) 2016-2026  Joachim Wiberg <troglobit@gmail.com>
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions are met:
10
 *     * Redistributions of source code must retain the above copyright
11
 *       notice, this list of conditions and the following disclaimer.
12
 *     * Redistributions in binary form must reproduce the above copyright
13
 *       notice, this list of conditions and the following disclaimer in the
14
 *       documentation and/or other materials provided with the distribution.
15
 *     * Neither the name of the copyright holders nor the names of its
16
 *       contributors may be used to endorse or promote products derived from
17
 *       this software without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
23
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 */
31
32
#include "1035.h"
33
#include <string.h>
34
#include <stdio.h>
35
36
unsigned short int net2short(unsigned char **bufp)
37
2.27M
{
38
2.27M
  unsigned short int i;
39
40
2.27M
  i = **bufp;
41
2.27M
  i <<= 8;
42
2.27M
  i |= *(*bufp + 1);
43
2.27M
  *bufp += 2;
44
45
2.27M
  return i;
46
2.27M
}
47
48
unsigned long int net2long(unsigned char **bufp)
49
320k
{
50
320k
  long int l;
51
52
320k
  l = **bufp;
53
320k
  l <<= 8;
54
320k
  l |= *(*bufp + 1);
55
320k
  l <<= 8;
56
320k
  l |= *(*bufp + 2);
57
320k
  l <<= 8;
58
320k
  l |= *(*bufp + 3);
59
320k
  *bufp += 4;
60
61
320k
  return l;
62
320k
}
63
64
void short2net(unsigned short int i, unsigned char **bufp)
65
0
{
66
0
  *(*bufp + 1) = (unsigned char)i;
67
0
  i >>= 8;
68
0
  **bufp = (unsigned char)i;
69
0
  *bufp += 2;
70
0
}
71
72
void long2net(unsigned long int l, unsigned char **bufp)
73
0
{
74
0
  *(*bufp + 3) = (unsigned char)l;
75
0
  l >>= 8;
76
0
  *(*bufp + 2) = (unsigned char)l;
77
0
  l >>= 8;
78
0
  *(*bufp + 1) = (unsigned char)l;
79
0
  l >>= 8;
80
0
  **bufp = (unsigned char)l;
81
0
  *bufp += 4;
82
0
}
83
84
static unsigned short int _ldecomp(const char *ptr)
85
20.1k
{
86
20.1k
  unsigned short int i;
87
88
20.1k
  i = 0xc0 ^ ptr[0];
89
20.1k
  i <<= 8;
90
20.1k
  i |= (unsigned char)ptr[1];
91
20.1k
  if (i >= 4096)
92
17.6k
    i = 4095;
93
94
20.1k
  return i;
95
20.1k
}
96
97
static int _label(struct message *m, unsigned char **bufp, char **namep)
98
978k
{
99
978k
  int x;
100
978k
  char *label, *name;
101
102
103
  /* Sanity check */
104
978k
  if (m->_len >= (int)sizeof(m->_packet))
105
221
    return 1;
106
107
  /* Set namep to the end of the block */
108
977k
  *namep = name = (char *)m->_packet + m->_len;
109
110
  /* Loop storing label in the block */
111
1.09M
  for (label = (char *)*bufp; *label != 0; name += *label + 1, label += *label + 1) {
112
    /* Skip past any compression pointers, kick out if end encountered (bad data prolly) */
113
113k
    int prevOffset = -1;
114
127k
    while (*label & 0xc0) {
115
20.1k
      unsigned short int offset = _ldecomp(label);
116
20.1k
      if (offset <= prevOffset || offset > m->_len)
117
43
        return 1;
118
20.0k
      if (*(label = (char *)m->_buf + offset) == 0)
119
6.20k
        break;
120
13.8k
      prevOffset = offset;
121
13.8k
    }
122
123
    /* Make sure we're not over the limits, and that the source
124
     * label stays within the packet buffer */
125
113k
    if ((name + *label) - *namep > 255 || m->_len + ((name + *label) - *namep) >= MAX_PACKET_LEN ||
126
113k
        (label + 1 + *label) - (char *)m->_buf > MAX_PACKET_LEN)
127
22
      return 1;
128
129
    /* Copy chars for this label */
130
113k
    memcpy(name, label + 1, (size_t)*label);
131
113k
    name[(size_t)*label] = '.';
132
113k
  }
133
134
  /* Advance buffer */
135
1.05M
  for (label = (char *)*bufp; *label != 0 && !(*label & 0xc0 && label++); label += *label + 1)
136
75.3k
    ;
137
977k
  *bufp = (unsigned char *)(label + 1);
138
139
  /* Terminate name and check for cache or cache it */
140
977k
  *name = '\0';
141
4.66M
  for (x = 0; x < MAX_NUM_LABELS && m->_labels[x]; x++) {
142
4.65M
    if (strcmp(*namep, m->_labels[x]))
143
3.69M
      continue;
144
145
966k
    *namep = m->_labels[x];
146
966k
    return 0;
147
4.65M
  }
148
149
  /* No cache, so cache it if room */
150
11.4k
  if (x < MAX_NUM_LABELS && m->_labels[x] == 0)
151
11.2k
    m->_labels[x] = *namep;
152
11.4k
  m->_len += (int)(name - *namep) + 1;
153
154
11.4k
  return 0;
155
977k
}
156
157
/* Internal label matching */
158
static int _lmatch(const struct message *m, const char *l1, const char *l2)
159
0
{
160
0
  int len;
161
162
  /* Always ensure we get called w/o a pointer */
163
0
  if (*l1 & 0xc0)
164
0
    return _lmatch(m, (char *)m->_buf + _ldecomp(l1), l2);
165
0
  if (*l2 & 0xc0)
166
0
    return _lmatch(m, l1, (char *)m->_buf + _ldecomp(l2));
167
168
  /* Same already? */
169
0
  if (l1 == l2)
170
0
    return 1;
171
172
  /* Compare all label characters */
173
0
  if (*l1 != *l2)
174
0
    return 0;
175
176
  /* Both at the root label, names matched; stop before stepping
177
   * past it, or the checks below read out of bounds (issue #37) */
178
0
  if (*l1 == 0)
179
0
    return 1;
180
181
0
  for (len = 1; len <= *l1; len++) {
182
0
    if (l1[len] != l2[len])
183
0
      return 0;
184
0
  }
185
186
  /* Get new_ labels */
187
0
  l1 += *l1 + 1;
188
0
  l2 += *l2 + 1;
189
190
  /* At the end, all matched */
191
0
  if (*l1 == 0 && *l2 == 0)
192
0
    return 1;
193
194
  /* Try next labels */
195
0
  return _lmatch(m, l1, l2);
196
0
}
197
198
/* Nasty, convert host into label using compression */
199
static int _host(struct message *m, unsigned char **bufp, const char *name)
200
0
{
201
0
  char label[256], *l;
202
0
  int len = 0, x = 1, y = 0, last = 0;
203
204
0
  if (name == 0)
205
0
    return 0;
206
207
  /* Make our label */
208
0
  while (name[y]) {
209
0
    if (name[y] == '.') {
210
0
      if (!name[y + 1])
211
0
        break;
212
0
      label[last] = (char)(x - (last + 1));
213
0
      last = x;
214
0
    } else {
215
0
      label[x] = name[y];
216
0
    }
217
218
0
    if (x++ == 255)
219
0
      return 0;
220
221
0
    y++;
222
0
  }
223
224
0
  label[last] = (char)(x - (last + 1));
225
0
  if (x == 1)
226
0
    x--;   /* Special case, bad names, but handle correctly */
227
0
  len = x + 1;
228
0
  label[x] = 0;   /* Always terminate w/ a 0 */
229
230
  /* Double-loop checking each label against all m->_labels for match */
231
0
  for (x = 0; label[x]; x += label[x] + 1) {
232
0
    for (y = 0; y < MAX_NUM_LABELS && m->_labels[y]; y++) {
233
0
      if (_lmatch(m, label + x, m->_labels[y])) {
234
        /* Matching label, set up pointer */
235
0
        l = label + x;
236
0
        short2net((unsigned char *)m->_labels[y] - m->_packet, (unsigned char **)&l);
237
0
        label[x] |= '\xc0';
238
0
        len = x + 2;
239
0
        break;
240
0
      }
241
0
    }
242
  
243
0
    if (label[x] & 0xc0)
244
0
      break;
245
0
  }
246
247
  /* Copy into buffer, point there now */
248
0
  memcpy(*bufp, label, len);
249
0
  l = (char *)*bufp;
250
0
  *bufp += len;
251
252
  /* For each new_ label, store it's location for future compression */
253
0
  for (x = 0; l[x] && m->_label < MAX_NUM_LABELS; x += l[x] + 1) {
254
0
    if (l[x] & 0xc0)
255
0
      break;
256
257
0
    m->_labels[m->_label++] = l + x;
258
0
  }
259
260
0
  return len;
261
0
}
262
263
static int _rrparse(struct message *m, struct resource *rr, int count, unsigned char **bufp)
264
2.72k
{
265
2.72k
  int i;
266
267
322k
  for (i = 0; i < count; i++) {
268
320k
    if (_label(m, bufp, &(rr[i].name)))
269
233
      return 1;
270
320k
    rr[i].type     = net2short(bufp);
271
320k
    rr[i].clazz    = net2short(bufp);
272
320k
    rr[i].ttl      = net2long(bufp);
273
320k
    rr[i].rdlength = net2short(bufp);
274
//    fprintf(stderr, "Record type %d clazz 0x%2x ttl %lu len %d\n", rr[i].type, rr[i].clazz, rr[i].ttl, rr[i].rdlength);
275
276
    /* If not going to overflow, make copy of source rdata */
277
320k
    if (rr[i].rdlength + (*bufp - m->_buf) > MAX_PACKET_LEN || m->_len + rr[i].rdlength > MAX_PACKET_LEN) {
278
36
      rr[i].rdlength = 0;
279
36
      return 1;
280
36
    }
281
282
    /* For the following records the rdata will be parsed later. So don't set it here:
283
     * NS, CNAME, PTR, DNAME, SOA, MX, AFSDB, RT, KX, RP, PX, SRV, NSEC
284
     * See 18.14 of https://tools.ietf.org/html/rfc6762#page-47 */
285
320k
    if (rr[i].type == QTYPE_NS || rr[i].type == QTYPE_CNAME || rr[i].type == QTYPE_PTR || rr[i].type == QTYPE_SRV) {
286
1.56k
      rr[i].rdlength = 0;
287
318k
    } else {
288
318k
      rr[i].rdata = m->_packet + m->_len;
289
318k
      m->_len += rr[i].rdlength;
290
318k
      memcpy(rr[i].rdata, *bufp, rr[i].rdlength);
291
318k
    }
292
293
294
    /* Parse commonly known ones */
295
320k
    switch (rr[i].type) {
296
522
    case QTYPE_A:
297
522
      if (m->_len + INET_ADDRSTRLEN > MAX_PACKET_LEN)
298
2
        return 1;
299
520
      rr[i].known.a.name = (char *)m->_packet + m->_len;
300
520
      m->_len += INET_ADDRSTRLEN;
301
520
      inet_ntop(AF_INET, *bufp, rr[i].known.a.name, INET_ADDRSTRLEN);
302
520
      memcpy(&(rr[i].known.a.ip.s_addr), *bufp, sizeof(rr[i].known.a.ip.s_addr));
303
520
      *bufp += sizeof(rr[i].known.a.ip.s_addr);
304
520
      break;
305
306
317
    case QTYPE_AAAA:
307
317
      if (m->_len + INET6_ADDRSTRLEN > MAX_PACKET_LEN)
308
2
        return 1;
309
315
      rr[i].known.aaaa.name = (char *)m->_packet + m->_len;
310
315
      m->_len += INET6_ADDRSTRLEN;
311
315
      inet_ntop(AF_INET6, *bufp, rr[i].known.aaaa.name, INET6_ADDRSTRLEN);
312
315
      memcpy(rr[i].known.aaaa.ip6.s6_addr, *bufp, sizeof(rr[i].known.aaaa.ip6.s6_addr));
313
315
      *bufp += sizeof(rr[i].known.aaaa.ip6.s6_addr);
314
315
      break;
315
316
396
    case QTYPE_NS:
317
396
      if (_label(m, bufp, &(rr[i].known.ns.name)))
318
2
        return 1;
319
394
      break;
320
321
493
    case QTYPE_CNAME:
322
493
      if (_label(m, bufp, &(rr[i].known.cname.name)))
323
3
        return 1;
324
490
      break;
325
326
490
    case QTYPE_PTR:
327
405
      if (_label(m, bufp, &(rr[i].known.ptr.name)))
328
2
        return 1;
329
403
      break;
330
331
403
    case QTYPE_SRV:
332
269
      rr[i].known.srv.priority = net2short(bufp);
333
269
      rr[i].known.srv.weight = net2short(bufp);
334
269
      rr[i].known.srv.port = net2short(bufp);
335
269
      if (_label(m, bufp, &(rr[i].known.srv.name)))
336
2
        return 1;
337
267
      break;
338
339
267
    case QTYPE_TXT:
340
317k
    default:
341
317k
      *bufp += rr[i].rdlength;
342
320k
    }
343
320k
  }
344
345
2.44k
  return 0;
346
2.72k
}
347
348
/* Keep all our mem in one (aligned) block for easy freeing */
349
#define my(x,y)         \
350
7.28k
  while (m->_len & 7)     \
351
4.34k
    m->_len++;     \
352
4.34k
  (x) = (void *)(m->_packet + m->_len); \
353
4.34k
  m->_len += (y);
354
355
int message_parse(struct message *m, unsigned char *packet)
356
1.18k
{
357
1.18k
  int i;
358
1.18k
  unsigned char *buf;
359
360
1.18k
  if (packet == 0 || m == 0)
361
0
    return 1;
362
363
  /* Header stuff bit crap */
364
1.18k
  m->_buf = buf = packet;
365
1.18k
  m->id = net2short(&buf);
366
1.18k
  if (buf[0] & 0x80)
367
485
    m->header.qr = 1;
368
1.18k
  m->header.opcode = (buf[0] & 0x78) >> 3;
369
1.18k
  if (buf[0] & 0x04)
370
413
    m->header.aa = 1;
371
1.18k
  if (buf[0] & 0x02)
372
434
    m->header.tc = 1;
373
1.18k
  if (buf[0] & 0x01)
374
683
    m->header.rd = 1;
375
1.18k
  if (buf[1] & 0x80)
376
253
    m->header.ra = 1;
377
1.18k
  m->header.z = (buf[1] & 0x70) >> 4;
378
1.18k
  m->header.rcode = buf[1] & 0x0F;
379
1.18k
  buf += 2;
380
381
1.18k
  m->qdcount = net2short(&buf);
382
1.18k
  if (m->_len + (sizeof(struct question) * m->qdcount) > MAX_PACKET_LEN - 8) {
383
10
    m->qdcount = 0;
384
10
    return 1;
385
10
  }
386
387
1.17k
  m->ancount = net2short(&buf);
388
1.17k
  if (m->_len + (sizeof(struct resource) * m->ancount) > MAX_PACKET_LEN - 8) {
389
19
    m->ancount = 0;
390
19
    return 1;
391
19
  }
392
393
1.15k
  m->nscount = net2short(&buf);
394
1.15k
  if (m->_len + (sizeof(struct resource) * m->nscount) > MAX_PACKET_LEN - 8) {
395
13
    m->nscount = 0;
396
13
    return 1;
397
13
  }
398
399
1.14k
  m->arcount = net2short(&buf);
400
1.14k
  if (m->_len + (sizeof(struct resource) * m->arcount) > MAX_PACKET_LEN - 8) {
401
21
    m->arcount = 0;
402
21
    return 1;
403
21
  }
404
405
  /* Process questions */
406
1.12k
  my(m->qd, sizeof(struct question) * m->qdcount);
407
657k
  for (i = 0; i < m->qdcount; i++) {
408
656k
    if (_label(m, &buf, &(m->qd[i].name)))
409
44
      return 1;
410
655k
    m->qd[i].type  = net2short(&buf);
411
655k
    m->qd[i].clazz = net2short(&buf);
412
655k
  }
413
414
  /* Process rrs */
415
1.07k
  my(m->an, sizeof(struct resource) * m->ancount);
416
1.07k
  my(m->ns, sizeof(struct resource) * m->nscount);
417
1.07k
  my(m->ar, sizeof(struct resource) * m->arcount);
418
1.07k
  if (_rrparse(m, m->an, m->ancount, &buf))
419
230
    return 1;
420
846
  if (_rrparse(m, m->ns, m->nscount, &buf))
421
44
    return 1;
422
802
  if (_rrparse(m, m->ar, m->arcount, &buf))
423
8
    return 1;
424
425
794
  return 0;
426
802
}
427
428
void message_qd(struct message *m, char *name, unsigned short int type, unsigned short int clazz)
429
0
{
430
0
  m->qdcount++;
431
0
  if (m->_buf == 0)
432
0
    m->_buf = m->_packet + 12;
433
0
  _host(m, &(m->_buf), name);
434
0
  short2net(type, &(m->_buf));
435
0
  short2net(clazz, &(m->_buf));
436
0
}
437
438
static void _rrappend(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
439
0
{
440
0
  if (m->_buf == 0)
441
0
    m->_buf = m->_packet + 12;
442
0
  _host(m, &(m->_buf), name);
443
0
  short2net(type, &(m->_buf));
444
0
  short2net(clazz, &(m->_buf));
445
0
  long2net(ttl, &(m->_buf));
446
0
}
447
448
void message_an(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
449
0
{
450
0
  m->ancount++;
451
0
  _rrappend(m, name, type, clazz, ttl);
452
0
}
453
454
void message_ns(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
455
0
{
456
0
  m->nscount++;
457
0
  _rrappend(m, name, type, clazz, ttl);
458
0
}
459
460
void message_ar(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
461
0
{
462
0
  m->arcount++;
463
0
  _rrappend(m, name, type, clazz, ttl);
464
0
}
465
466
void message_rdata_long(struct message *m, unsigned long l)
467
0
{
468
0
  short2net(4, &(m->_buf));
469
0
  long2net(l, &(m->_buf));
470
0
}
471
472
void message_rdata_ipv4(struct message *m, struct in_addr a)
473
0
{
474
0
  short2net(4, &(m->_buf));
475
0
  memcpy(m->_buf, &a.s_addr, 4);
476
0
  m->_buf += 4;
477
0
}
478
479
void message_rdata_ipv6(struct message *m, struct in6_addr a6)
480
0
{
481
0
  short2net(16, &(m->_buf));
482
0
  memcpy(m->_buf, a6.s6_addr, 16);
483
0
  m->_buf += 16;
484
0
}
485
486
void message_rdata_name(struct message *m, char *name)
487
0
{
488
0
  unsigned char *mybuf = m->_buf;
489
490
0
  m->_buf += 2;
491
0
  short2net(_host(m, &(m->_buf), name), &mybuf);
492
0
}
493
494
void message_rdata_srv(struct message *m, unsigned short int priority, unsigned short int weight, unsigned short int port, char *name)
495
0
{
496
0
  unsigned char *mybuf = m->_buf;
497
498
0
  m->_buf += 2;
499
0
  short2net(priority, &(m->_buf));
500
0
  short2net(weight, &(m->_buf));
501
0
  short2net(port, &(m->_buf));
502
0
  short2net(_host(m, &(m->_buf), name) + 6, &mybuf);
503
0
}
504
505
void message_rdata_raw(struct message *m, unsigned char *rdata, unsigned short int rdlength)
506
0
{
507
0
  if ((m->_buf - m->_packet) + rdlength > 4096)
508
0
    rdlength = 0;
509
0
  short2net(rdlength, &(m->_buf));
510
0
  memcpy(m->_buf, rdata, rdlength);
511
0
  m->_buf += rdlength;
512
0
}
513
514
unsigned char *message_packet(struct message *m)
515
0
{
516
0
  unsigned char c, *buf = m->_buf;
517
518
0
  m->_buf = m->_packet;
519
0
  short2net(m->id, &(m->_buf));
520
521
0
  if (m->header.qr)
522
0
    m->_buf[0] |= 0x80;
523
0
  if ((c = m->header.opcode))
524
0
    m->_buf[0] |= (c << 3);
525
0
  if (m->header.aa)
526
0
    m->_buf[0] |= 0x04;
527
0
  if (m->header.tc)
528
0
    m->_buf[0] |= 0x02;
529
0
  if (m->header.rd)
530
0
    m->_buf[0] |= 0x01;
531
0
  if (m->header.ra)
532
0
    m->_buf[1] |= 0x80;
533
0
  if ((c = m->header.z))
534
0
    m->_buf[1] |= (c << 4);
535
0
  if (m->header.rcode)
536
0
    m->_buf[1] |= m->header.rcode;
537
538
0
  m->_buf += 2;
539
0
  short2net(m->qdcount, &(m->_buf));
540
0
  short2net(m->ancount, &(m->_buf));
541
0
  short2net(m->nscount, &(m->_buf));
542
0
  short2net(m->arcount, &(m->_buf));
543
0
  m->_buf = buf;    /* Restore, so packet_len works */
544
545
0
  return m->_packet;
546
0
}
547
548
int message_packet_len(struct message *m)
549
0
{
550
0
  if (m->_buf == 0)
551
0
    return 12;
552
553
0
  return (int)(m->_buf - m->_packet);
554
0
}