Coverage Report

Created: 2026-05-16 06:54

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-2022  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
1.78M
{
38
1.78M
  unsigned short int i;
39
40
1.78M
  i = **bufp;
41
1.78M
  i <<= 8;
42
1.78M
  i |= *(*bufp + 1);
43
1.78M
  *bufp += 2;
44
45
1.78M
  return i;
46
1.78M
}
47
48
unsigned long int net2long(unsigned char **bufp)
49
232k
{
50
232k
  long int l;
51
52
232k
  l = **bufp;
53
232k
  l <<= 8;
54
232k
  l |= *(*bufp + 1);
55
232k
  l <<= 8;
56
232k
  l |= *(*bufp + 2);
57
232k
  l <<= 8;
58
232k
  l |= *(*bufp + 3);
59
232k
  *bufp += 4;
60
61
232k
  return l;
62
232k
}
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
3.94k
{
86
3.94k
  unsigned short int i;
87
88
3.94k
  i = 0xc0 ^ ptr[0];
89
3.94k
  i <<= 8;
90
3.94k
  i |= (unsigned char)ptr[1];
91
3.94k
  if (i >= 4096)
92
1.65k
    i = 4095;
93
94
3.94k
  return i;
95
3.94k
}
96
97
static int _label(struct message *m, unsigned char **bufp, char **namep)
98
771k
{
99
771k
  int x;
100
771k
  char *label, *name;
101
102
103
  /* Sanity check */
104
771k
  if (m->_len > (int)sizeof(m->_packet))
105
209
    return 1;
106
107
  /* Set namep to the end of the block */
108
771k
  *namep = name = (char *)m->_packet + m->_len;
109
110
  /* Loop storing label in the block */
111
780k
  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
9.45k
    int prevOffset = -1;
114
10.4k
    while (*label & 0xc0) {
115
3.94k
      unsigned short int offset = _ldecomp(label);
116
3.94k
      if (offset <= prevOffset || offset > m->_len)
117
52
        return 1;
118
3.89k
      if (*(label = (char *)m->_buf + offset) == 0)
119
2.87k
        break;
120
1.02k
      prevOffset = offset;
121
1.02k
    }
122
123
    /* Make sure we're not over the limits */
124
9.40k
    if ((name + *label) - *namep > 255 || m->_len + ((name + *label) - *namep) >= MAX_PACKET_LEN)
125
28
      return 1;
126
127
    /* Copy chars for this label */
128
9.37k
    memcpy(name, label + 1, (size_t)*label);
129
9.37k
    name[(size_t)*label] = '.';
130
9.37k
  }
131
132
  /* Advance buffer */
133
775k
  for (label = (char *)*bufp; *label != 0 && !(*label & 0xc0 && label++); label += *label + 1)
134
3.81k
    ;
135
771k
  *bufp = (unsigned char *)(label + 1);
136
137
  /* Terminate name and check for cache or cache it */
138
771k
  *name = '\0';
139
1.35M
  for (x = 0; x < MAX_NUM_LABELS && m->_labels[x]; x++) {
140
1.35M
    if (strcmp(*namep, m->_labels[x]))
141
581k
      continue;
142
143
768k
    *namep = m->_labels[x];
144
768k
    return 0;
145
1.35M
  }
146
147
  /* No cache, so cache it if room */
148
2.37k
  if (x < MAX_NUM_LABELS && m->_labels[x] == 0)
149
2.37k
    m->_labels[x] = *namep;
150
2.37k
  m->_len += (int)(name - *namep) + 1;
151
152
2.37k
  return 0;
153
771k
}
154
155
/* Internal label matching */
156
static int _lmatch(const struct message *m, const char *l1, const char *l2)
157
0
{
158
0
  int len;
159
160
  /* Always ensure we get called w/o a pointer */
161
0
  if (*l1 & 0xc0)
162
0
    return _lmatch(m, (char *)m->_buf + _ldecomp(l1), l2);
163
0
  if (*l2 & 0xc0)
164
0
    return _lmatch(m, l1, (char *)m->_buf + _ldecomp(l2));
165
166
  /* Same already? */
167
0
  if (l1 == l2)
168
0
    return 1;
169
170
  /* Compare all label characters */
171
0
  if (*l1 != *l2)
172
0
    return 0;
173
0
  for (len = 1; len <= *l1; len++) {
174
0
    if (l1[len] != l2[len])
175
0
      return 0;
176
0
  }
177
178
  /* Get new_ labels */
179
0
  l1 += *l1 + 1;
180
0
  l2 += *l2 + 1;
181
182
  /* At the end, all matched */
183
0
  if (*l1 == 0 && *l2 == 0)
184
0
    return 1;
185
186
  /* Try next labels */
187
0
  return _lmatch(m, l1, l2);
188
0
}
189
190
/* Nasty, convert host into label using compression */
191
static int _host(struct message *m, unsigned char **bufp, const char *name)
192
0
{
193
0
  char label[256], *l;
194
0
  int len = 0, x = 1, y = 0, last = 0;
195
196
0
  if (name == 0)
197
0
    return 0;
198
199
  /* Make our label */
200
0
  while (name[y]) {
201
0
    if (name[y] == '.') {
202
0
      if (!name[y + 1])
203
0
        break;
204
0
      label[last] = (char)(x - (last + 1));
205
0
      last = x;
206
0
    } else {
207
0
      label[x] = name[y];
208
0
    }
209
210
0
    if (x++ == 255)
211
0
      return 0;
212
213
0
    y++;
214
0
  }
215
216
0
  label[last] = (char)(x - (last + 1));
217
0
  if (x == 1)
218
0
    x--;   /* Special case, bad names, but handle correctly */
219
0
  len = x + 1;
220
0
  label[x] = 0;   /* Always terminate w/ a 0 */
221
222
  /* Double-loop checking each label against all m->_labels for match */
223
0
  for (x = 0; label[x]; x += label[x] + 1) {
224
0
    for (y = 0; y < MAX_NUM_LABELS && m->_labels[y]; y++) {
225
0
      if (_lmatch(m, label + x, m->_labels[y])) {
226
        /* Matching label, set up pointer */
227
0
        l = label + x;
228
0
        short2net((unsigned char *)m->_labels[y] - m->_packet, (unsigned char **)&l);
229
0
        label[x] |= '\xc0';
230
0
        len = x + 2;
231
0
        break;
232
0
      }
233
0
    }
234
  
235
0
    if (label[x] & 0xc0)
236
0
      break;
237
0
  }
238
239
  /* Copy into buffer, point there now */
240
0
  memcpy(*bufp, label, len);
241
0
  l = (char *)*bufp;
242
0
  *bufp += len;
243
244
  /* For each new_ label, store it's location for future compression */
245
0
  for (x = 0; l[x] && m->_label < MAX_NUM_LABELS; x += l[x] + 1) {
246
0
    if (l[x] & 0xc0)
247
0
      break;
248
249
0
    m->_labels[m->_label++] = l + x;
250
0
  }
251
252
0
  return len;
253
0
}
254
255
static int _rrparse(struct message *m, struct resource *rr, int count, unsigned char **bufp)
256
2.78k
{
257
2.78k
  int i;
258
259
235k
  for (i = 0; i < count; i++) {
260
233k
    if (_label(m, bufp, &(rr[i].name)))
261
226
      return 1;
262
232k
    rr[i].type     = net2short(bufp);
263
232k
    rr[i].clazz    = net2short(bufp);
264
232k
    rr[i].ttl      = net2long(bufp);
265
232k
    rr[i].rdlength = net2short(bufp);
266
//    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);
267
268
    /* If not going to overflow, make copy of source rdata */
269
232k
    if (rr[i].rdlength + (*bufp - m->_buf) > MAX_PACKET_LEN || m->_len + rr[i].rdlength > MAX_PACKET_LEN) {
270
36
      rr[i].rdlength = 0;
271
36
      return 1;
272
36
    }
273
274
    /* For the following records the rdata will be parsed later. So don't set it here:
275
     * NS, CNAME, PTR, DNAME, SOA, MX, AFSDB, RT, KX, RP, PX, SRV, NSEC
276
     * See 18.14 of https://tools.ietf.org/html/rfc6762#page-47 */
277
232k
    if (rr[i].type == QTYPE_NS || rr[i].type == QTYPE_CNAME || rr[i].type == QTYPE_PTR || rr[i].type == QTYPE_SRV) {
278
956
      rr[i].rdlength = 0;
279
231k
    } else {
280
231k
      rr[i].rdata = m->_packet + m->_len;
281
231k
      m->_len += rr[i].rdlength;
282
231k
      memcpy(rr[i].rdata, *bufp, rr[i].rdlength);
283
231k
    }
284
285
286
    /* Parse commonly known ones */
287
232k
    switch (rr[i].type) {
288
275
    case QTYPE_A:
289
275
      if (m->_len + INET_ADDRSTRLEN > MAX_PACKET_LEN)
290
3
        return 1;
291
272
      rr[i].known.a.name = (char *)m->_packet + m->_len;
292
272
      m->_len += INET_ADDRSTRLEN;
293
272
      inet_ntop(AF_INET, *bufp, rr[i].known.a.name, INET_ADDRSTRLEN);
294
272
      memcpy(&(rr[i].known.a.ip.s_addr), *bufp, sizeof(rr[i].known.a.ip.s_addr));
295
272
      *bufp += sizeof(rr[i].known.a.ip.s_addr);
296
272
      break;
297
298
198
    case QTYPE_AAAA:
299
198
      if (m->_len + INET6_ADDRSTRLEN > MAX_PACKET_LEN)
300
3
        return 1;
301
195
      rr[i].known.aaaa.name = (char *)m->_packet + m->_len;
302
195
      m->_len += INET6_ADDRSTRLEN;
303
195
      inet_ntop(AF_INET6, *bufp, rr[i].known.aaaa.name, INET6_ADDRSTRLEN);
304
195
      memcpy(rr[i].known.aaaa.ip6.s6_addr, *bufp, sizeof(rr[i].known.aaaa.ip6.s6_addr));
305
195
      *bufp += sizeof(rr[i].known.aaaa.ip6.s6_addr);
306
195
      break;
307
308
174
    case QTYPE_NS:
309
174
      if (_label(m, bufp, &(rr[i].known.ns.name)))
310
3
        return 1;
311
171
      break;
312
313
362
    case QTYPE_CNAME:
314
362
      if (_label(m, bufp, &(rr[i].known.cname.name)))
315
2
        return 1;
316
360
      break;
317
318
360
    case QTYPE_PTR:
319
282
      if (_label(m, bufp, &(rr[i].known.ptr.name)))
320
2
        return 1;
321
280
      break;
322
323
280
    case QTYPE_SRV:
324
138
      rr[i].known.srv.priority = net2short(bufp);
325
138
      rr[i].known.srv.weight = net2short(bufp);
326
138
      rr[i].known.srv.port = net2short(bufp);
327
138
      if (_label(m, bufp, &(rr[i].known.srv.name)))
328
2
        return 1;
329
136
      break;
330
331
136
    case QTYPE_TXT:
332
231k
    default:
333
231k
      *bufp += rr[i].rdlength;
334
232k
    }
335
232k
  }
336
337
2.51k
  return 0;
338
2.78k
}
339
340
/* Keep all our mem in one (aligned) block for easy freeing */
341
#define my(x,y)         \
342
7.00k
  while (m->_len & 7)     \
343
4.42k
    m->_len++;     \
344
4.42k
  (x) = (void *)(m->_packet + m->_len); \
345
4.42k
  m->_len += (y);
346
347
int message_parse(struct message *m, unsigned char *packet)
348
1.21k
{
349
1.21k
  int i;
350
1.21k
  unsigned char *buf;
351
352
1.21k
  if (packet == 0 || m == 0)
353
0
    return 1;
354
355
  /* Header stuff bit crap */
356
1.21k
  m->_buf = buf = packet;
357
1.21k
  m->id = net2short(&buf);
358
1.21k
  if (buf[0] & 0x80)
359
599
    m->header.qr = 1;
360
1.21k
  m->header.opcode = (buf[0] & 0x78) >> 3;
361
1.21k
  if (buf[0] & 0x04)
362
529
    m->header.aa = 1;
363
1.21k
  if (buf[0] & 0x02)
364
588
    m->header.tc = 1;
365
1.21k
  if (buf[0] & 0x01)
366
635
    m->header.rd = 1;
367
1.21k
  if (buf[1] & 0x80)
368
229
    m->header.ra = 1;
369
1.21k
  m->header.z = (buf[1] & 0x70) >> 4;
370
1.21k
  m->header.rcode = buf[1] & 0x0F;
371
1.21k
  buf += 2;
372
373
1.21k
  m->qdcount = net2short(&buf);
374
1.21k
  if (m->_len + (sizeof(struct question) * m->qdcount) > MAX_PACKET_LEN - 8) {
375
11
    m->qdcount = 0;
376
11
    return 1;
377
11
  }
378
379
1.20k
  m->ancount = net2short(&buf);
380
1.20k
  if (m->_len + (sizeof(struct resource) * m->ancount) > MAX_PACKET_LEN - 8) {
381
31
    m->ancount = 0;
382
31
    return 1;
383
31
  }
384
385
1.17k
  m->nscount = net2short(&buf);
386
1.17k
  if (m->_len + (sizeof(struct resource) * m->nscount) > MAX_PACKET_LEN - 8) {
387
16
    m->nscount = 0;
388
16
    return 1;
389
16
  }
390
391
1.15k
  m->arcount = net2short(&buf);
392
1.15k
  if (m->_len + (sizeof(struct resource) * m->arcount) > MAX_PACKET_LEN - 8) {
393
12
    m->arcount = 0;
394
12
    return 1;
395
12
  }
396
397
  /* Process questions */
398
1.14k
  my(m->qd, sizeof(struct question) * m->qdcount);
399
538k
  for (i = 0; i < m->qdcount; i++) {
400
537k
    if (_label(m, &buf, &(m->qd[i].name)))
401
54
      return 1;
402
537k
    m->qd[i].type  = net2short(&buf);
403
537k
    m->qd[i].clazz = net2short(&buf);
404
537k
  }
405
406
  /* Process rrs */
407
1.09k
  my(m->an, sizeof(struct resource) * m->ancount);
408
1.09k
  my(m->ns, sizeof(struct resource) * m->nscount);
409
1.09k
  my(m->ar, sizeof(struct resource) * m->arcount);
410
1.09k
  if (_rrparse(m, m->an, m->ancount, &buf))
411
233
    return 1;
412
860
  if (_rrparse(m, m->ns, m->nscount, &buf))
413
26
    return 1;
414
834
  if (_rrparse(m, m->ar, m->arcount, &buf))
415
18
    return 1;
416
417
816
  return 0;
418
834
}
419
420
void message_qd(struct message *m, char *name, unsigned short int type, unsigned short int clazz)
421
0
{
422
0
  m->qdcount++;
423
0
  if (m->_buf == 0)
424
0
    m->_buf = m->_packet + 12;
425
0
  _host(m, &(m->_buf), name);
426
0
  short2net(type, &(m->_buf));
427
0
  short2net(clazz, &(m->_buf));
428
0
}
429
430
static void _rrappend(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
431
0
{
432
0
  if (m->_buf == 0)
433
0
    m->_buf = m->_packet + 12;
434
0
  _host(m, &(m->_buf), name);
435
0
  short2net(type, &(m->_buf));
436
0
  short2net(clazz, &(m->_buf));
437
0
  long2net(ttl, &(m->_buf));
438
0
}
439
440
void message_an(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
441
0
{
442
0
  m->ancount++;
443
0
  _rrappend(m, name, type, clazz, ttl);
444
0
}
445
446
void message_ns(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
447
0
{
448
0
  m->nscount++;
449
0
  _rrappend(m, name, type, clazz, ttl);
450
0
}
451
452
void message_ar(struct message *m, char *name, unsigned short int type, unsigned short int clazz, unsigned long int ttl)
453
0
{
454
0
  m->arcount++;
455
0
  _rrappend(m, name, type, clazz, ttl);
456
0
}
457
458
void message_rdata_long(struct message *m, unsigned long l)
459
0
{
460
0
  short2net(4, &(m->_buf));
461
0
  long2net(l, &(m->_buf));
462
0
}
463
464
void message_rdata_ipv4(struct message *m, struct in_addr a)
465
0
{
466
0
  short2net(4, &(m->_buf));
467
0
  memcpy(m->_buf, &a.s_addr, 4);
468
0
  m->_buf += 4;
469
0
}
470
471
void message_rdata_ipv6(struct message *m, struct in6_addr a6)
472
0
{
473
0
  short2net(16, &(m->_buf));
474
0
  memcpy(m->_buf, a6.s6_addr, 16);
475
0
  m->_buf += 16;
476
0
}
477
478
void message_rdata_name(struct message *m, char *name)
479
0
{
480
0
  unsigned char *mybuf = m->_buf;
481
482
0
  m->_buf += 2;
483
0
  short2net(_host(m, &(m->_buf), name), &mybuf);
484
0
}
485
486
void message_rdata_srv(struct message *m, unsigned short int priority, unsigned short int weight, unsigned short int port, char *name)
487
0
{
488
0
  unsigned char *mybuf = m->_buf;
489
490
0
  m->_buf += 2;
491
0
  short2net(priority, &(m->_buf));
492
0
  short2net(weight, &(m->_buf));
493
0
  short2net(port, &(m->_buf));
494
0
  short2net(_host(m, &(m->_buf), name) + 6, &mybuf);
495
0
}
496
497
void message_rdata_raw(struct message *m, unsigned char *rdata, unsigned short int rdlength)
498
0
{
499
0
  if ((m->_buf - m->_packet) + rdlength > 4096)
500
0
    rdlength = 0;
501
0
  short2net(rdlength, &(m->_buf));
502
0
  memcpy(m->_buf, rdata, rdlength);
503
0
  m->_buf += rdlength;
504
0
}
505
506
unsigned char *message_packet(struct message *m)
507
0
{
508
0
  unsigned char c, *buf = m->_buf;
509
510
0
  m->_buf = m->_packet;
511
0
  short2net(m->id, &(m->_buf));
512
513
0
  if (m->header.qr)
514
0
    m->_buf[0] |= 0x80;
515
0
  if ((c = m->header.opcode))
516
0
    m->_buf[0] |= (c << 3);
517
0
  if (m->header.aa)
518
0
    m->_buf[0] |= 0x04;
519
0
  if (m->header.tc)
520
0
    m->_buf[0] |= 0x02;
521
0
  if (m->header.rd)
522
0
    m->_buf[0] |= 0x01;
523
0
  if (m->header.ra)
524
0
    m->_buf[1] |= 0x80;
525
0
  if ((c = m->header.z))
526
0
    m->_buf[1] |= (c << 4);
527
0
  if (m->header.rcode)
528
0
    m->_buf[1] |= m->header.rcode;
529
530
0
  m->_buf += 2;
531
0
  short2net(m->qdcount, &(m->_buf));
532
0
  short2net(m->ancount, &(m->_buf));
533
0
  short2net(m->nscount, &(m->_buf));
534
0
  short2net(m->arcount, &(m->_buf));
535
0
  m->_buf = buf;    /* Restore, so packet_len works */
536
537
0
  return m->_packet;
538
0
}
539
540
int message_packet_len(struct message *m)
541
0
{
542
0
  if (m->_buf == 0)
543
0
    return 12;
544
545
0
  return (int)(m->_buf - m->_packet);
546
0
}