Coverage Report

Created: 2026-06-16 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ndpi/src/lib/protocols/dns.c
Line
Count
Source
1
/*
2
 * dns.c
3
 *
4
 * Copyright (C) 2012-22 - ntop.org
5
 *
6
 * This file is part of nDPI, an open source deep packet inspection
7
 * library based on the OpenDPI and PACE technology by ipoque GmbH
8
 *
9
 * nDPI is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * nDPI is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with nDPI.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
#include "ndpi_protocol_ids.h"
25
26
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_DNS
27
28
#include "ndpi_api.h"
29
#include "ndpi_private.h"
30
31
270k
#define FLAGS_MASK 0x8000
32
33
/* #define DNS_DEBUG 1 */
34
35
18.6M
#define DNS_PORT   53
36
6.85M
#define LLMNR_PORT 5355
37
20.5M
#define MDNS_PORT  5353
38
39
151k
#define PKT_LEN_ALERT 512
40
41
42
static void search_dns(struct ndpi_detection_module_struct *ndpi_struct,
43
           struct ndpi_flow_struct *flow);
44
45
/* *********************************************** */
46
47
static void ndpi_check_dns_type(struct ndpi_detection_module_struct *ndpi_struct,
48
                                struct ndpi_flow_struct *flow,
49
326k
        u_int16_t dns_type) {
50
  /* https://en.wikipedia.org/wiki/List_of_DNS_record_types */
51
52
326k
  switch(dns_type) {
53
    /* Obsolete record types */
54
1.02k
  case 3:
55
2.74k
  case 4:
56
3.37k
  case 254:
57
4.15k
  case 7:
58
6.61k
  case 8:
59
7.38k
  case 9:
60
8.23k
  case 14:
61
9.08k
  case 253:
62
9.73k
  case 11:
63
    /* case 33: */ /* SRV */
64
10.7k
  case 10:
65
11.4k
  case 38:
66
12.4k
  case 30:
67
13.0k
  case 25:
68
14.3k
  case 24:
69
15.1k
  case 13:
70
15.7k
  case 17:
71
16.7k
  case 19:
72
17.7k
  case 20:
73
18.4k
  case 21:
74
19.8k
  case 22:
75
20.4k
  case 23:
76
21.2k
  case 26:
77
22.0k
  case 31:
78
22.9k
  case 32:
79
23.4k
  case 34:
80
24.3k
  case 42:
81
25.1k
  case 40:
82
25.8k
  case 27:
83
27.2k
  case 100:
84
27.8k
  case 101:
85
28.3k
  case 102:
86
29.2k
  case 103:
87
29.8k
  case 99:
88
30.3k
  case 56:
89
30.8k
  case 57:
90
31.8k
  case 58:
91
32.4k
  case 104:
92
33.1k
  case 105:
93
33.9k
  case 106:
94
34.6k
  case 107:
95
35.1k
  case 259:
96
35.1k
    ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_SUSPICIOUS_TRAFFIC, "Obsolete DNS record type");
97
35.1k
    break;
98
326k
  }
99
326k
}
100
101
/* *********************************************** */
102
103
481k
static u_int16_t checkPort(u_int16_t port) {
104
481k
  switch(port) {
105
209k
  case DNS_PORT:
106
209k
    return(NDPI_PROTOCOL_DNS);
107
17.1k
  case LLMNR_PORT:
108
17.1k
    return(NDPI_PROTOCOL_LLMNR);
109
23.6k
  case MDNS_PORT:
110
23.6k
    return(NDPI_PROTOCOL_MDNS);
111
481k
  }
112
113
231k
  return(0);
114
481k
}
115
116
/* *********************************************** */
117
118
static int isMDNSMulticastAddress(struct ndpi_packet_struct * const packet)
119
10.4k
{
120
10.4k
  return (packet->iph && ntohl(packet->iph->daddr) == 0xE00000FB /* multicast: 224.0.0.251 */) ||
121
6.92k
         (packet->iphv6 && ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[0]) == 0xFF020000 &&
122
6.92k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[1]) == 0x00000000 &&
123
6.92k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[2]) == 0x00000000 &&
124
6.92k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[3]) == 0x000000FB /* multicast: FF02::FB */);
125
10.4k
}
126
127
static int isLLMNRMulticastAddress(struct ndpi_packet_struct *const packet)
128
20.0k
{
129
20.0k
  return (packet->iph && ntohl(packet->iph->daddr) == 0xE00000FC /* multicast: 224.0.0.252 */) ||
130
11.4k
         (packet->iphv6 && ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[0]) == 0xFF020000 &&
131
11.4k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[1]) == 0x00000000 &&
132
11.4k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[2]) == 0x00000000 &&
133
11.4k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[3]) == 0x00010003 /* multicast: FF02::1:3 */);
134
20.0k
}
135
136
/* *********************************************** */
137
138
253k
static u_int16_t checkDNSSubprotocol(u_int16_t sport, u_int16_t dport) {
139
253k
  u_int16_t rc = checkPort(sport);
140
141
253k
  if(rc == 0)
142
228k
    return(checkPort(dport));
143
24.4k
  else
144
24.4k
    return(rc);
145
253k
}
146
147
/* *********************************************** */
148
149
1.01M
static u_int16_t get16(u_int *i, const u_int8_t *payload) {
150
1.01M
  u_int16_t v = *(u_int16_t*)&payload[*i];
151
152
1.01M
  (*i) += 2;
153
154
1.01M
  return(ntohs(v));
155
1.01M
}
156
157
/* *********************************************** */
158
159
2.18M
static u_int getNameLength(u_int i, const u_int8_t *payload, u_int payloadLen) {
160
2.18M
  if(i >= payloadLen)
161
47.5k
    return(0);
162
2.14M
  else if(payload[i] == 0x00)
163
433k
    return(1);
164
1.70M
  else if((payload[i] & 0xC0)== 0xC0)
165
284k
    return(2);
166
1.42M
  else {
167
1.42M
    u_int8_t len = payload[i];
168
1.42M
    u_int8_t off = len + 1;
169
170
1.42M
    return(off + getNameLength(i+off, payload, payloadLen));
171
1.42M
  }
172
2.18M
}
173
/*
174
  See
175
  - RFC 1035
176
  - https://learn.microsoft.com/en-us/troubleshoot/windows-server/identity/naming-conventions-for-computer-domain-site-ou
177
178
  Allowed chars for dns names A-Z 0-9 _ -
179
  Perl script for generation map:
180
  my @M;
181
  for(my $ch=0; $ch < 256; $ch++) {
182
  $M[$ch >> 5] |= 1 << ($ch & 0x1f) if chr($ch) =~ /[a-z0-9_-]/i;
183
  }
184
  print join(',', map { sprintf "0x%08x",$_ } @M),"\n";
185
*/
186
187
static uint32_t dns_validchar[8] = {
188
  0x00000000,0x03ff2000,0x87fffffe,0x07fffffe,0,0,0,0
189
};
190
191
/* *********************************************** */
192
193
7.52k
static char* dns_error_code2string(u_int16_t error_code, char *buf, u_int buf_len) {
194
7.52k
  switch(error_code) {
195
1.42k
  case 1: return((char*)"FORMERR");
196
914
  case 2: return((char*)"SERVFAIL");
197
1.93k
  case 3: return((char*)"NXDOMAIN");
198
342
  case 4: return((char*)"NOTIMP");
199
106
  case 5: return((char*)"REFUSED");
200
407
  case 6: return((char*)"YXDOMAIN");
201
134
  case 7: return((char*)"XRRSET");
202
142
  case 8: return((char*)"NOTAUTH");
203
114
  case 9: return((char*)"NOTZONE");
204
205
1.99k
  default:
206
1.99k
    snprintf(buf, buf_len, "%u", error_code);
207
1.99k
    return(buf);
208
7.52k
  }
209
7.52k
}
210
211
/* *********************************************** */
212
213
4.67M
u_int64_t fpc_dns_cache_key_from_flow(struct ndpi_flow_struct *flow) {
214
4.67M
  u_int64_t key;
215
216
4.67M
  if(flow->is_ipv6)
217
142k
    key = ndpi_quick_hash64((const char *)flow->s_address.v6, 16);
218
4.53M
  else
219
4.53M
    key = (u_int64_t)(flow->s_address.v4);
220
221
4.67M
  return key;
222
4.67M
}
223
224
/* *********************************************** */
225
226
97.4k
static u_int64_t fpc_dns_cache_key_from_packet(const unsigned char *ip, int ip_len) {
227
97.4k
  u_int64_t key;
228
229
97.4k
  if(ip_len == 16)
230
3.16k
    key = ndpi_quick_hash64((const char *)ip, 16);
231
94.3k
  else
232
94.3k
    key = (u_int64_t)(*(u_int32_t *)ip);
233
234
97.4k
  return key;
235
97.4k
}
236
237
/* *********************************************** */
238
239
static u_int8_t ndpi_grab_dns_name(struct ndpi_packet_struct *packet,
240
           u_int *off /* payload offset */,
241
           char *_hostname, u_int max_len,
242
           u_int *_hostname_len,
243
236k
           u_int8_t ignore_checks) {
244
236k
  u_int8_t hostname_is_valid = 1;
245
236k
  u_int j = 0;
246
247
236k
  max_len--;
248
249
898k
  while((j < max_len)
250
897k
  && ((*off) < packet->payload_packet_len)
251
897k
  && (packet->payload[(*off)] != '\0')) {
252
709k
    u_int8_t c, cl = packet->payload[*off];
253
254
709k
    if(((cl & 0xc0) != 0) || // we not support compressed names in query
255
667k
       (((*off)+1) + cl  >= packet->payload_packet_len)) {
256
      /* Don't update the offset */
257
48.2k
      j = 0;
258
48.2k
      break;
259
48.2k
    }
260
261
661k
    (*off)++;
262
263
661k
    if(j && (j < max_len)) _hostname[j++] = '.';
264
265
4.36M
    while((j < max_len) && (cl != 0)) {
266
3.70M
      c = packet->payload[(*off)++];
267
268
3.70M
      if(ignore_checks)
269
390k
  _hostname[j++] = tolower(c);
270
3.31M
      else {
271
3.31M
  u_int32_t shift;
272
273
3.31M
  shift = ((u_int32_t) 1) << (c & 0x1f);
274
275
3.31M
  if((dns_validchar[c >> 5] & shift)) {
276
2.99M
    _hostname[j++] = tolower(c);
277
2.99M
  } else {
278
    /* printf("---?? '%c'\n", c); */
279
280
320k
    hostname_is_valid = 0;
281
282
320k
    if (ndpi_isprint(c) == 0) {
283
268k
      _hostname[j++] = '?';
284
268k
    } else {
285
52.0k
      _hostname[j++] = '_';
286
52.0k
    }
287
320k
  }
288
3.31M
      }
289
290
3.70M
      cl--;
291
3.70M
    }
292
661k
  }
293
294
236k
  _hostname[j] = '\0', *_hostname_len = j;
295
296
236k
  return(hostname_is_valid);
297
236k
}
298
299
/* *********************************************** */
300
301
static int process_queries(struct ndpi_detection_module_struct *ndpi_struct,
302
                           struct ndpi_flow_struct *flow,
303
                           struct ndpi_dns_packet_header *dns_header,
304
238k
                           u_int payload_offset) {
305
238k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
306
238k
  u_int x = payload_offset;
307
238k
  u_int16_t rsp_type;
308
238k
  u_int16_t num;
309
310
456k
  for(num = 0; num < dns_header->num_queries; num++) {
311
254k
    u_int16_t data_len;
312
313
254k
    if((data_len = getNameLength(x, packet->payload,
314
254k
                                 packet->payload_packet_len)) == 0) {
315
735
      return -1;
316
735
    } else
317
253k
      x += data_len;
318
319
253k
    if(data_len > 253)
320
2.69k
      ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Query Lenght");
321
322
253k
    if((x+4) > packet->payload_packet_len) {
323
35.4k
      ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Query Lenght");
324
35.4k
      return -1;
325
35.4k
    }
326
327
217k
    rsp_type = get16(&x, packet->payload);
328
329
#ifdef DNS_DEBUG
330
    printf("[DNS] [response (query)] response_type=%d\n", rsp_type);
331
#endif
332
217k
    if(flow->protos.dns.query_type == 0) {
333
      /* In case we missed the query packet... */
334
126k
      flow->protos.dns.query_type = rsp_type;
335
126k
    }
336
337
    /* here x points to the response "class" field */
338
217k
    x += 2; /* Skip class */
339
217k
  }
340
341
202k
  return x;
342
238k
}
343
344
static int process_answers(struct ndpi_detection_module_struct *ndpi_struct,
345
                           struct ndpi_flow_struct *flow,
346
                           struct ndpi_dns_packet_header *dns_header,
347
                           u_int payload_offset,
348
73.8k
                           ndpi_master_app_protocol *proto) {
349
73.8k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
350
73.8k
  u_int x = payload_offset;
351
73.8k
  u_int16_t rsp_type;
352
73.8k
  u_int32_t rsp_ttl;
353
73.8k
  u_int16_t num;
354
73.8k
  u_int8_t found = 0;
355
73.8k
  int ignore_checks;
356
357
73.8k
  ignore_checks = (proto->master_protocol == NDPI_PROTOCOL_MDNS);
358
359
409k
  for(num = 0; num < dns_header->num_answers; num++) {
360
362k
    u_int16_t data_len;
361
362
362k
    if((data_len = getNameLength(x, packet->payload,
363
362k
                                 packet->payload_packet_len)) == 0) {
364
935
      return -1;
365
935
    } else
366
361k
      x += data_len;
367
368
361k
    if((x+8) >= packet->payload_packet_len) {
369
14.8k
      return -1;
370
14.8k
    }
371
372
346k
    rsp_type = get16(&x, packet->payload);
373
346k
    rsp_ttl  = ntohl(*((u_int32_t*)&packet->payload[x+2]));
374
375
346k
    if(rsp_ttl == 0)
376
55.4k
      ndpi_set_risk(ndpi_struct, flow, NDPI_MINOR_ISSUES, "DNS Record with zero TTL");
377
378
#ifdef DNS_DEBUG
379
    printf("[DNS] Date len %u; TTL = %u\n", data_len, rsp_ttl);
380
    printf("[DNS] [response] response_type=%d\n", rsp_type);
381
#endif
382
383
346k
    if(found == 0) {
384
326k
      ndpi_check_dns_type(ndpi_struct, flow, rsp_type);
385
326k
      flow->protos.dns.rsp_type = rsp_type;
386
326k
    }
387
388
    /* x points to the response "class" field */
389
346k
    if((x+12) <= packet->payload_packet_len) {
390
341k
      u_int32_t ttl = ntohl(*((u_int32_t*)&packet->payload[x+2]));
391
392
341k
      x += 6;
393
341k
      data_len = get16(&x, packet->payload);
394
395
341k
      if((x + data_len) <= packet->payload_packet_len) {
396
#ifdef DNS_DEBUG
397
        printf("[DNS] [rsp_type: %u][data_len: %u]\n", rsp_type, data_len);
398
#endif
399
400
269k
        if(rsp_type == 0x05 /* CNAME */) {
401
28.8k
          ;
402
240k
        } else if(rsp_type == 0x0C /* PTR */) {
403
8.20k
          u_int16_t ptr_len = (packet->payload[x-2] << 8) + packet->payload[x-1];
404
405
8.20k
          if((x + ptr_len) <= packet->payload_packet_len) {
406
8.20k
            if(found == 0) {
407
4.61k
              u_int len, orig_x;
408
409
4.61k
              orig_x = x;
410
4.61k
              ndpi_grab_dns_name(packet, &x,
411
4.61k
                                 flow->protos.dns.ptr_domain_name,
412
4.61k
                                 sizeof(flow->protos.dns.ptr_domain_name), &len,
413
4.61k
                                 ignore_checks);
414
              /* ndpi_grab_dns_name doesn't update the offset if it failed.
415
                 We unconditionally update it at the end of the for loop */
416
4.61k
              x = orig_x;
417
4.61k
              found = 1;
418
4.61k
            }
419
8.20k
          }
420
232k
        } else if((((rsp_type == 0x1) && (data_len == 4)) /* A */
421
97.6k
                   || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */
422
232k
                   )) {
423
140k
          if(found == 0) {
424
425
134k
            if(flow->protos.dns.num_rsp_addr < MAX_NUM_DNS_RSP_ADDRESSES) {
426
              /* Necessary for IP address comparison */
427
134k
              memset(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], 0, sizeof(ndpi_ip_addr_t));
428
429
134k
              memcpy(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], packet->payload + x, data_len);
430
134k
              flow->protos.dns.is_rsp_addr_ipv6[flow->protos.dns.num_rsp_addr] = (data_len == 16) ? 1 : 0;
431
134k
              flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr] = ttl;
432
433
134k
              if(ndpi_struct->cfg.address_cache_size)
434
129k
                ndpi_cache_address(ndpi_struct,
435
129k
                                   flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr],
436
129k
                                   flow->host_server_name,
437
129k
                                   packet->current_time_ms/1000,
438
129k
                                   flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr]);
439
440
134k
        if(ndpi_struct->cfg.hostname_dns_check_enabled)
441
127k
    ndpi_cache_hostname_ip(ndpi_struct,
442
127k
               &flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr],
443
127k
               flow->host_server_name);
444
445
134k
              ++flow->protos.dns.num_rsp_addr;
446
134k
            }
447
448
134k
            if(flow->protos.dns.num_rsp_addr >= MAX_NUM_DNS_RSP_ADDRESSES)
449
9.14k
              found = 1;
450
134k
          }
451
452
          /* Add (all addresses) to FPC DNS cache */
453
140k
          if(ndpi_struct->cfg.fpc_enabled &&
454
140k
             proto->app_protocol != NDPI_PROTOCOL_UNKNOWN &&
455
98.3k
             proto->app_protocol != proto->master_protocol &&
456
97.5k
             ndpi_struct->fpc_dns_cache) {
457
97.4k
            ndpi_lru_add_to_cache(ndpi_struct->fpc_dns_cache,
458
97.4k
                                  fpc_dns_cache_key_from_packet(packet->payload + x, data_len),
459
97.4k
                                  proto->app_protocol,
460
97.4k
                                  ndpi_get_current_time(flow));
461
462
97.4k
            NDPI_LOG_DBG(ndpi_struct, "Adding entry to fpc_dns: %s proto %d\n",
463
97.4k
                         data_len == 4 ? "ipv4" : "ipv6", proto->app_protocol);
464
97.4k
          }
465
140k
        }
466
467
269k
        x += data_len;
468
269k
      }
469
341k
    }
470
471
346k
    if(found && (dns_header->additional_rrs == 0)) {
472
      /*
473
        In case we have RR we need to iterate
474
        all the answers and not just consider the
475
        first one as we need to properly move 'x'
476
        to the right offset
477
      */
478
11.1k
      break;
479
11.1k
    }
480
346k
  }
481
482
58.1k
  return x;
483
73.8k
}
484
485
static int process_additionals(struct ndpi_detection_module_struct *ndpi_struct,
486
                               struct ndpi_flow_struct *flow,
487
                               struct ndpi_dns_packet_header *dns_header,
488
58.1k
                               u_int payload_offset) {
489
58.1k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
490
58.1k
  u_int x = payload_offset;
491
492
  /*
493
    Dissect the rest of the packet only if there are
494
    additional_rrs as we need to check for:
495
     * EDNS(0)
496
     * NSID
497
498
    In this case we need to go through the whole packet
499
    as we need to update the 'x' offset
500
  */
501
502
58.1k
  if(dns_header->additional_rrs == 0)
503
47.2k
    return x;
504
505
10.8k
  if(dns_header->authority_rrs > 0) {
506
#ifdef DNS_DEBUG
507
    u_int16_t rsp_type;
508
#endif
509
4.42k
    u_int16_t num;
510
511
29.2k
    for(num = 0; num < dns_header->authority_rrs; num++) {
512
27.1k
      u_int16_t data_len;
513
514
27.1k
      if((x+6) >= packet->payload_packet_len) {
515
610
        return -1;
516
610
      }
517
518
26.5k
      if((data_len = getNameLength(x, packet->payload,
519
26.5k
                                   packet->payload_packet_len)) == 0) {
520
1
        return -1;
521
1
      } else
522
26.5k
        x += data_len;
523
524
26.5k
      if((x+8) >= packet->payload_packet_len) {
525
1.63k
        return -1;
526
1.63k
      }
527
528
      /* To avoid warning: variable ‘rsp_type’ set but not used [-Wunused-but-set-variable] */
529
#ifdef DNS_DEBUG
530
      rsp_type = get16(&x, packet->payload);
531
#else
532
24.8k
      get16(&x, packet->payload);
533
24.8k
#endif
534
535
#ifdef DNS_DEBUG
536
      printf("[DNS] [RRS response] response_type=%d\n", rsp_type);
537
#endif
538
539
      /* here x points to the response "class" field */
540
24.8k
      if((x+12) <= packet->payload_packet_len) {
541
24.0k
        x += 6;
542
24.0k
        data_len = get16(&x, packet->payload);
543
544
24.0k
        if((x + data_len) <= packet->payload_packet_len)
545
17.3k
          x += data_len;
546
24.0k
      }
547
24.8k
    }
548
4.42k
  }
549
550
8.65k
  if(dns_header->additional_rrs > 0) {
551
8.65k
    u_int16_t rsp_type;
552
8.65k
    u_int16_t num;
553
554
68.5k
    for(num = 0; num < dns_header->additional_rrs; num++) {
555
64.4k
      u_int16_t data_len, rdata_len, opt_code, opt_len;
556
64.4k
      const unsigned char *opt;
557
558
#ifdef DNS_DEBUG
559
      printf("[DNS] [RR response %d/%d]\n", num + 1, dns_header->additional_rrs);
560
#endif
561
562
64.4k
      if((x+6) > packet->payload_packet_len) {
563
2.04k
        return -1;
564
2.04k
      }
565
566
62.4k
      if((data_len = getNameLength(x, packet->payload, packet->payload_packet_len)) == 0) {
567
1
        return -1;
568
1
      } else
569
62.4k
        x += data_len;
570
571
62.4k
      if((x+10) > packet->payload_packet_len) {
572
2.54k
        return -1;
573
2.54k
      }
574
575
59.8k
      rsp_type = get16(&x, packet->payload);
576
577
#ifdef DNS_DEBUG
578
      printf("[DNS] [RR response] response_type=%d\n", rsp_type);
579
#endif
580
581
59.8k
      if(rsp_type == 41 /* OPT */) {
582
        /* https://en.wikipedia.org/wiki/Extension_Mechanisms_for_DNS */
583
8.91k
        flow->protos.dns.edns0_udp_payload_size = ntohs(*((u_int16_t*)&packet->payload[x])); /* EDNS(0) */
584
585
#ifdef DNS_DEBUG
586
        printf("[DNS] [response] edns0_udp_payload_size: %u\n", flow->protos.dns.edns0_udp_payload_size);
587
#endif
588
8.91k
        x += 6;
589
590
8.91k
        rdata_len = ntohs(*((u_int16_t *)&packet->payload[x]));
591
#ifdef DNS_DEBUG
592
        printf("[DNS] [response] rdata len: %u\n", rdata_len);
593
#endif
594
8.91k
        if(rdata_len > 0 &&
595
7.49k
           x + 6 <= packet->payload_packet_len) {
596
7.36k
          opt_code = ntohs(*((u_int16_t *)&packet->payload[x + 2]));
597
7.36k
          opt_len = ntohs(*((u_int16_t *)&packet->payload[x + 4]));
598
7.36k
          opt = &packet->payload[x + 6];
599
          /* TODO: parse the TLV list */
600
7.36k
          if(opt_code == 0x03 &&
601
5.27k
             opt_len <= rdata_len + 4 &&
602
4.27k
             opt_len > 6 &&
603
3.77k
             x + 6 + opt_len <= packet->payload_packet_len) {
604
#ifdef DNS_DEBUG
605
            printf("[DNS] NSID: [%.*s]\n", opt_len, opt);
606
#endif
607
2.49k
            if(memcmp(opt, "gpdns-", 6) == 0) {
608
#ifdef DNS_DEBUG
609
              printf("[DNS] NSID Airport code [%.*s]\n", opt_len - 6, opt + 6);
610
#endif
611
1.13k
              memcpy(flow->protos.dns.geolocation_iata_code, opt + 6,
612
1.13k
                     ndpi_min(opt_len - 6, (int)sizeof(flow->protos.dns.geolocation_iata_code) - 1));
613
1.13k
            }
614
2.49k
          }
615
616
7.36k
        }
617
50.9k
      } else {
618
50.9k
        x += 6;
619
50.9k
      }
620
621
59.8k
      if((data_len = getNameLength(x, packet->payload, packet->payload_packet_len)) == 0) {
622
1
        return -1;
623
1
      } else
624
59.8k
        x += data_len;
625
59.8k
    }
626
8.65k
  }
627
628
4.06k
  return x;
629
8.65k
}
630
631
static int is_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
632
      struct ndpi_flow_struct *flow,
633
      struct ndpi_dns_packet_header *dns_header,
634
270k
      u_int payload_offset, u_int8_t *is_query) {
635
270k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
636
637
270k
  if(packet->payload_packet_len < sizeof(struct ndpi_dns_packet_header) + payload_offset)
638
475
    return 0;
639
640
270k
  memcpy(dns_header, (struct ndpi_dns_packet_header*)&packet->payload[payload_offset],
641
270k
   sizeof(struct ndpi_dns_packet_header));
642
643
270k
  dns_header->tr_id = ntohs(dns_header->tr_id);
644
270k
  dns_header->flags = ntohs(dns_header->flags);
645
270k
  dns_header->num_queries = ntohs(dns_header->num_queries);
646
270k
  dns_header->num_answers = ntohs(dns_header->num_answers);
647
270k
  dns_header->authority_rrs = ntohs(dns_header->authority_rrs);
648
270k
  dns_header->additional_rrs = ntohs(dns_header->additional_rrs);
649
650
270k
  if((dns_header->flags & FLAGS_MASK) == 0x0000)
651
177k
    *is_query = 1;
652
92.6k
  else
653
92.6k
    *is_query = 0;
654
655
270k
  if(*is_query) {
656
177k
    if(dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS &&
657
       /* dns_header->num_answers == 0 && */
658
160k
       ((dns_header->flags & 0x2800) == 0x2800 /* Dynamic DNS Update */ ||
659
158k
  (dns_header->flags & 0xFCF0) == 0x00 /* Standard Query */ ||
660
8.79k
  (dns_header->flags & 0xFCFF) == 0x0800 /* Inverse query */ ||
661
157k
  (dns_header->num_answers == 0 && dns_header->authority_rrs == 0))) {
662
      /* This is a good query */
663
157k
      return 1;
664
157k
    }
665
177k
  } else {
666
92.6k
    if(((dns_header->num_queries > 0 && dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS) || /* Don't assume that num_queries must be zero */
667
15.0k
        (checkDNSSubprotocol(ntohs(flow->c_port), ntohs(flow->s_port)) == NDPI_PROTOCOL_MDNS && dns_header->num_queries == 0)) &&
668
83.0k
       ((dns_header->num_answers > 0 && dns_header->num_answers <= NDPI_MAX_DNS_REQUESTS) ||
669
15.2k
        (dns_header->authority_rrs > 0 && dns_header->authority_rrs <= NDPI_MAX_DNS_REQUESTS) ||
670
10.3k
        (dns_header->additional_rrs > 0 && dns_header->additional_rrs <= NDPI_MAX_DNS_REQUESTS) ||
671
80.3k
        (dns_header->num_answers == 0 && dns_header->authority_rrs == 0 && dns_header->additional_rrs == 0))) {
672
      /* This is a good reply */
673
80.3k
      return 1;
674
80.3k
    }
675
12.2k
    if(dns_header->num_queries == 0 && dns_header->num_answers == 0 &&
676
1.14k
       dns_header->authority_rrs == 0 && dns_header->additional_rrs == 0 &&
677
548
       packet->payload_packet_len == sizeof(struct ndpi_dns_packet_header)) {
678
      /* This is a good empty reply */
679
210
      return 1;
680
210
    }
681
12.2k
  }
682
32.2k
  return 0;
683
270k
}
684
685
/* *********************************************** */
686
687
static int keep_extra_dissection(struct ndpi_flow_struct *flow)
688
220k
{
689
  /* As a general rule, we wait for a valid response
690
     (in the ideal world, we want to process the request/response pair) */
691
220k
  return !(!flow->protos.dns.is_query && flow->protos.dns.num_answers != 0);
692
220k
}
693
694
/* *********************************************** */
695
696
106k
static int search_dns_again(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
697
106k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
698
699
106k
  if(packet->tcp_retransmission || packet->payload_packet_len == 0)
700
931
    return keep_extra_dissection(flow);
701
702
  /* possibly dissect the DNS reply */
703
106k
  search_dns(ndpi_struct, flow);
704
705
106k
  return keep_extra_dissection(flow);
706
106k
}
707
708
/* *********************************************** */
709
710
static int process_hostname(struct ndpi_detection_module_struct *ndpi_struct,
711
                            struct ndpi_flow_struct *flow,
712
                            struct ndpi_dns_packet_header *dns_header,
713
238k
                            ndpi_master_app_protocol *proto) {
714
238k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
715
238k
  char *dot;
716
238k
  u_int len, is_mdns, off = sizeof(struct ndpi_dns_packet_header) + (packet->tcp ? 2 : 0);
717
238k
  char _hostname[256];
718
238k
  u_int8_t hostname_is_valid;
719
720
238k
  proto->master_protocol = checkDNSSubprotocol(ntohs(flow->c_port), ntohs(flow->s_port));
721
238k
  proto->app_protocol = flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN ? flow->detected_protocol_stack[0] : NDPI_PROTOCOL_UNKNOWN;
722
723
  /* We try to get hostname only from "standard" query/answer */
724
238k
  if(dns_header->num_queries == 0 && dns_header->num_answers == 0)
725
6.10k
    return -1;
726
727
232k
  is_mdns = (proto->master_protocol == NDPI_PROTOCOL_MDNS);
728
729
  /* TODO: should we overwrite existing hostname?
730
     For the time being, keep the old/current behavior */
731
732
232k
  hostname_is_valid = ndpi_grab_dns_name(packet, &off, _hostname, sizeof(_hostname), &len, is_mdns);
733
734
#ifdef DNS_DEBUG
735
  printf("[DNS] [%s]\n", _hostname);
736
#endif
737
738
232k
  ndpi_hostname_sni_set(flow, (const u_int8_t *)_hostname, len, is_mdns ? NDPI_HOSTNAME_NORM_LC : NDPI_HOSTNAME_NORM_ALL);
739
740
232k
  if (hostname_is_valid == 0)
741
44.7k
    ndpi_set_risk(ndpi_struct, flow, NDPI_INVALID_CHARACTERS, "Invalid chars detected in domain name");
742
743
  /* Ignore reverse DNS queries */
744
232k
  if(strstr(_hostname, ".in-addr.") == NULL) {
745
225k
    dot = strchr(_hostname, '.');
746
747
225k
    if(dot) {
748
147k
      uintptr_t first_element_len = dot - _hostname;
749
750
147k
      if((first_element_len > 48) && (!is_mdns)) {
751
        /*
752
          The length of the first element in the query is very long
753
          and this might be an issue or indicate an exfiltration
754
        */
755
756
763
        if(ends_with(ndpi_struct, _hostname, "multi.surbl.org")
757
763
           || ends_with(ndpi_struct, _hostname, "spamhaus.org")
758
762
           || ends_with(ndpi_struct, _hostname, "rackcdn.com")
759
761
           || ends_with(ndpi_struct, _hostname, "akamaiedge.net")
760
680
           || ends_with(ndpi_struct, _hostname, "mx-verification.google.com")
761
680
           || ends_with(ndpi_struct, _hostname, "amazonaws.com")
762
763
           )
763
136
          ; /* Check common domain exceptions [TODO: if the list grows too much use a different datastructure] */
764
627
        else
765
627
          ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_SUSPICIOUS_TRAFFIC, "Long DNS host name");
766
763
      }
767
147k
    }
768
225k
  }
769
770
232k
  if(strlen(flow->host_server_name) > 0) {
771
172k
    ndpi_protocol_match_result ret_match;
772
773
172k
    if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN) {
774
151k
      proto->app_protocol = ndpi_match_host_subprotocol(ndpi_struct, flow,
775
151k
                                                        flow->host_server_name,
776
151k
                                                        strlen(flow->host_server_name),
777
151k
                                                        &ret_match,
778
151k
                                                        proto->master_protocol,
779
                                                        /* Avoid updating classification if subclassification is disabled */
780
151k
                                                        ndpi_struct->cfg.dns_subclassification_enabled ? 1 : 0);
781
151k
    }
782
783
172k
    ndpi_check_dga_name(ndpi_struct, flow, flow->host_server_name, 1, 0, proto->app_protocol != NDPI_PROTOCOL_UNKNOWN);
784
172k
  }
785
786
232k
  return 0;
787
238k
}
788
789
270k
static void search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
790
270k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
791
270k
  int payload_offset = 0;
792
270k
  u_int8_t is_query;
793
270k
  struct ndpi_dns_packet_header dns_header;
794
270k
  u_int off;
795
270k
  ndpi_master_app_protocol proto;
796
270k
  int rc;
797
798
270k
  if(packet->udp != NULL) {
799
257k
    payload_offset = 0;
800
257k
  } else if(packet->tcp != NULL) {
801
13.6k
    payload_offset = 2;
802
13.6k
  }
803
804
270k
  if(!is_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query)) {
805
#ifdef DNS_DEBUG
806
    printf("[DNS] invalid packet\n");
807
#endif
808
32.6k
    if(flow->extra_packets_func == NULL) {
809
23.5k
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
810
23.5k
    } else {
811
9.18k
      ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Header");
812
9.18k
    }
813
32.6k
    return;
814
32.6k
  }
815
816
238k
  process_hostname(ndpi_struct, flow, &dns_header, &proto);
817
818
238k
  off = sizeof(struct ndpi_dns_packet_header) + payload_offset;
819
820
238k
  if(is_query) {
821
157k
    flow->protos.dns.is_query = 1;
822
157k
    flow->protos.dns.transaction_id = dns_header.tr_id;
823
824
157k
    rc = process_queries(ndpi_struct, flow, &dns_header, off);
825
#ifdef DNS_DEBUG
826
    if(rc == -1)
827
      printf("[DNS] Error queries (query msg)\n");
828
#endif
829
157k
  } else {
830
80.6k
    flow->protos.dns.is_query = 0;
831
80.6k
    flow->protos.dns.transaction_id = dns_header.tr_id;
832
80.6k
    flow->protos.dns.reply_code = dns_header.flags & 0x0F;
833
80.6k
    flow->protos.dns.num_queries = dns_header.num_queries;
834
80.6k
    flow->protos.dns.num_answers = dns_header.num_answers + dns_header.authority_rrs + dns_header.additional_rrs;
835
836
80.6k
    if(flow->protos.dns.reply_code != 0) {
837
8.33k
      if(is_flowrisk_info_enabled(ndpi_struct, NDPI_ERROR_CODE_DETECTED)) {
838
7.52k
        char str[32], buf[16];
839
840
7.52k
        snprintf(str, sizeof(str), "DNS Error Code %s",
841
7.52k
                 dns_error_code2string(flow->protos.dns.reply_code, buf, sizeof(buf)));
842
7.52k
        ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, str);
843
7.52k
      } else {
844
811
        ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, NULL);
845
811
      }
846
72.2k
    } else {
847
72.2k
      if(ndpi_isset_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN)) {
848
2.46k
        ndpi_set_risk(ndpi_struct, flow, NDPI_RISKY_DOMAIN, "DGA Name Query with no Error Code");
849
2.46k
      }
850
72.2k
    }
851
852
80.6k
    rc = process_queries(ndpi_struct, flow, &dns_header, off);
853
80.6k
    if(rc == -1) {
854
#ifdef DNS_DEBUG
855
      printf("[DNS] Error queries (response msg)\n");
856
#endif
857
73.8k
    } else {
858
73.8k
      off = rc;
859
73.8k
      rc = process_answers(ndpi_struct, flow, &dns_header, off, &proto);
860
73.8k
      if(rc == -1) {
861
#ifdef DNS_DEBUG
862
        printf("[DNS] Error answers\n");
863
#endif
864
58.1k
      } else {
865
58.1k
        off = rc;
866
58.1k
        rc = process_additionals(ndpi_struct, flow, &dns_header, off);
867
#ifdef DNS_DEBUG
868
        if(rc == -1)
869
          printf("[DNS] Error additionals\n");
870
#endif
871
58.1k
      }
872
73.8k
    }
873
874
80.6k
    if(proto.master_protocol == NDPI_PROTOCOL_DNS &&
875
      /* TODO: add support to RFC6891 to avoid some false positives */
876
72.9k
       packet->udp &&
877
70.3k
       packet->payload_packet_len > PKT_LEN_ALERT &&
878
4.27k
       packet->payload_packet_len > flow->protos.dns.edns0_udp_payload_size) {
879
4.04k
      if(is_flowrisk_info_enabled(ndpi_struct, NDPI_DNS_LARGE_PACKET)) {
880
3.17k
        char str[48];
881
882
3.17k
        snprintf(str, sizeof(str), "%u Bytes DNS Packet", packet->payload_packet_len);
883
3.17k
        ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_LARGE_PACKET, str);
884
3.17k
      } else {
885
872
        ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_LARGE_PACKET, NULL);
886
872
      }
887
4.04k
    }
888
889
80.6k
    NDPI_LOG_DBG2(ndpi_struct, "Response: [num_queries=%d][num_answers=%d][reply_code=%u][rsp_type=%u][host_server_name=%s]\n",
890
80.6k
                  flow->protos.dns.num_queries, flow->protos.dns.num_answers,
891
80.6k
                  flow->protos.dns.reply_code, flow->protos.dns.rsp_type, flow->host_server_name);
892
80.6k
  }
893
894
238k
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) {
895
112k
    if(ndpi_struct->cfg.dns_subclassification_enabled)
896
96.5k
      ndpi_set_detected_protocol(ndpi_struct, flow, proto.app_protocol, proto.master_protocol, NDPI_CONFIDENCE_DPI);
897
16.0k
    else
898
16.0k
      ndpi_set_detected_protocol(ndpi_struct, flow,
899
16.0k
         (proto.master_protocol == NDPI_PROTOCOL_UNKNOWN) ? NDPI_PROTOCOL_DNS : proto.master_protocol,
900
16.0k
         NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
901
112k
  }
902
  /* Category is always NDPI_PROTOCOL_CATEGORY_NETWORK, regardless of the subprotocol. Same for the breed */
903
238k
  flow->category = NDPI_PROTOCOL_CATEGORY_NETWORK;
904
238k
  flow->breed = NDPI_PROTOCOL_ACCEPTABLE;
905
906
238k
  if(!flow->extra_packets_func &&
907
141k
     ndpi_struct->cfg.dns_parse_response_enabled &&
908
     /* We have never triggered extra-dissection for LLMNR. Keep the old behavior */
909
128k
     flow->detected_protocol_stack[0] != NDPI_PROTOCOL_LLMNR &&
910
113k
     flow->detected_protocol_stack[1] != NDPI_PROTOCOL_LLMNR) {
911
113k
    if(keep_extra_dissection(flow)) {
912
86.0k
      NDPI_LOG_DBG(ndpi_struct, "Enabling extra dissection\n");
913
86.0k
      flow->max_extra_packets_to_check = 5;
914
86.0k
      flow->extra_packets_func = search_dns_again;
915
86.0k
    }
916
113k
  }
917
918
  /* The bigger packets are usually the replies, but it shouldn't harm
919
     to check the requests, too */
920
238k
  if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DNS)
921
204k
     || (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) {
922
923
204k
    if(packet->iph != NULL) {
924
      /* IPv4 */
925
200k
      u_int8_t flags = ((u_int8_t*)packet->iph)[6];
926
927
      /* 0: fragmented; 1: not fragmented */
928
200k
      if((flags & 0x20)
929
198k
   || (iph_is_valid_and_not_fragmented(ndpi_struct, packet->iph, packet->l3_packet_len) == 0)) {
930
3.81k
  ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_FRAGMENTED, NULL);
931
3.81k
      }
932
200k
    } else if(packet->iphv6 != NULL) {
933
      /* IPv6 */
934
3.99k
      const struct ndpi_ip6_hdrctl *ip6_hdr = &packet->iphv6->ip6_hdr;
935
936
3.99k
      if(ip6_hdr->ip6_un1_nxt == 0x2C /* Next Header: Fragment Header for IPv6 (44) */) {
937
220
  ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_FRAGMENTED, NULL);
938
220
      }
939
3.99k
    }
940
204k
  }
941
238k
}
942
943
/* *********************************************** */
944
945
4.62M
void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
946
4.62M
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
947
4.62M
  u_int16_t s_port = 0, d_port = 0;
948
4.62M
  int payload_offset = 0;
949
950
4.62M
  NDPI_LOG_DBG(ndpi_struct, "search DNS\n");
951
952
4.62M
  if(packet->udp != NULL) {
953
1.18M
    s_port = ntohs(packet->udp->source);
954
1.18M
    d_port = ntohs(packet->udp->dest);
955
1.18M
    payload_offset = 0;
956
957
    /* For MDNS/LLMNR: If the packet is not a response, dest addr needs to be multicast. */
958
1.18M
    if ((d_port == MDNS_PORT && isMDNSMulticastAddress(packet) == 0) ||
959
1.18M
        (d_port == LLMNR_PORT && isLLMNRMulticastAddress(packet) == 0))
960
9.63k
    {
961
9.63k
      if (packet->payload_packet_len > 5 &&
962
9.63k
          ntohs(get_u_int16_t(packet->payload, 2)) != 0 &&
963
9.63k
          ntohs(get_u_int16_t(packet->payload, 4)) != 0)
964
1.71k
      {
965
1.71k
        NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
966
1.71k
        return;
967
1.71k
      }
968
9.63k
    }
969
3.43M
  } else if(packet->tcp != NULL) {
970
3.43M
    s_port = ntohs(packet->tcp->source);
971
3.43M
    d_port = ntohs(packet->tcp->dest);
972
3.43M
    payload_offset = 2;
973
3.43M
  }
974
975
  /* We are able to detect DNS/MDNS/LLMNR only on standard ports (see #1788) */
976
4.62M
  if(!(s_port == DNS_PORT || d_port == DNS_PORT ||
977
4.48M
       s_port == MDNS_PORT || d_port == MDNS_PORT ||
978
4.47M
       d_port == LLMNR_PORT)) {
979
4.45M
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
980
4.45M
    return;
981
4.45M
  }
982
983
  /* Since:
984
      UDP: every packet must contains a complete/valid DNS message;
985
      TCP: we are not able to handle DNS messages spanning multiple TCP packets;
986
     we must be able to detect these protocols on the first packet
987
  */
988
170k
  if(packet->payload_packet_len < sizeof(struct ndpi_dns_packet_header) + payload_offset) {
989
5.24k
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
990
5.24k
    return;
991
5.24k
  }
992
993
164k
  search_dns(ndpi_struct, flow);
994
164k
}
995
996
/* *********************************************** */
997
998
20.4k
void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct) {
999
20.4k
  ndpi_register_dissector("DNS", ndpi_struct,
1000
20.4k
                     ndpi_search_dns,
1001
20.4k
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
1002
20.4k
                     1, NDPI_PROTOCOL_DNS);
1003
20.4k
}