Coverage Report

Created: 2026-04-20 06:19

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
279k
#define FLAGS_MASK 0x8000
32
33
/* #define DNS_DEBUG 1 */
34
35
19.3M
#define DNS_PORT   53
36
6.94M
#define LLMNR_PORT 5355
37
21.1M
#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
327k
        u_int16_t dns_type) {
50
  /* https://en.wikipedia.org/wiki/List_of_DNS_record_types */
51
52
327k
  switch(dns_type) {
53
    /* Obsolete record types */
54
896
  case 3:
55
2.44k
  case 4:
56
2.72k
  case 254:
57
3.22k
  case 7:
58
5.67k
  case 8:
59
6.25k
  case 9:
60
6.91k
  case 14:
61
7.38k
  case 253:
62
7.83k
  case 11:
63
    /* case 33: */ /* SRV */
64
8.60k
  case 10:
65
8.98k
  case 38:
66
9.65k
  case 30:
67
10.0k
  case 25:
68
10.8k
  case 24:
69
11.1k
  case 13:
70
11.8k
  case 17:
71
12.7k
  case 19:
72
13.4k
  case 20:
73
14.0k
  case 21:
74
15.2k
  case 22:
75
15.6k
  case 23:
76
16.1k
  case 26:
77
16.7k
  case 31:
78
17.2k
  case 32:
79
17.7k
  case 34:
80
18.3k
  case 42:
81
18.8k
  case 40:
82
19.4k
  case 27:
83
20.3k
  case 100:
84
20.8k
  case 101:
85
21.1k
  case 102:
86
21.6k
  case 103:
87
22.0k
  case 99:
88
22.3k
  case 56:
89
22.6k
  case 57:
90
23.2k
  case 58:
91
23.4k
  case 104:
92
23.9k
  case 105:
93
24.6k
  case 106:
94
25.1k
  case 107:
95
25.5k
  case 259:
96
25.5k
    ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_SUSPICIOUS_TRAFFIC, "Obsolete DNS record type");
97
25.5k
    break;
98
327k
  }
99
327k
}
100
101
/* *********************************************** */
102
103
497k
static u_int16_t checkPort(u_int16_t port) {
104
497k
  switch(port) {
105
216k
  case DNS_PORT:
106
216k
    return(NDPI_PROTOCOL_DNS);
107
19.8k
  case LLMNR_PORT:
108
19.8k
    return(NDPI_PROTOCOL_LLMNR);
109
25.0k
  case MDNS_PORT:
110
25.0k
    return(NDPI_PROTOCOL_MDNS);
111
497k
  }
112
113
235k
  return(0);
114
497k
}
115
116
/* *********************************************** */
117
118
static int isMDNSMulticastAddress(struct ndpi_packet_struct * const packet)
119
11.1k
{
120
11.1k
  return (packet->iph && ntohl(packet->iph->daddr) == 0xE00000FB /* multicast: 224.0.0.251 */) ||
121
7.40k
         (packet->iphv6 && ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[0]) == 0xFF020000 &&
122
7.40k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[1]) == 0x00000000 &&
123
7.40k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[2]) == 0x00000000 &&
124
7.40k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[3]) == 0x000000FB /* multicast: FF02::FB */);
125
11.1k
}
126
127
static int isLLMNRMulticastAddress(struct ndpi_packet_struct *const packet)
128
23.2k
{
129
23.2k
  return (packet->iph && ntohl(packet->iph->daddr) == 0xE00000FC /* multicast: 224.0.0.252 */) ||
130
12.9k
         (packet->iphv6 && ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[0]) == 0xFF020000 &&
131
12.9k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[1]) == 0x00000000 &&
132
12.9k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[2]) == 0x00000000 &&
133
12.9k
                           ntohl(packet->iphv6->ip6_dst.u6_addr.u6_addr32[3]) == 0x00010003 /* multicast: FF02::1:3 */);
134
23.2k
}
135
136
/* *********************************************** */
137
138
261k
static u_int16_t checkDNSSubprotocol(u_int16_t sport, u_int16_t dport) {
139
261k
  u_int16_t rc = checkPort(sport);
140
141
261k
  if(rc == 0)
142
235k
    return(checkPort(dport));
143
25.6k
  else
144
25.6k
    return(rc);
145
261k
}
146
147
/* *********************************************** */
148
149
997k
static u_int16_t get16(u_int *i, const u_int8_t *payload) {
150
997k
  u_int16_t v = *(u_int16_t*)&payload[*i];
151
152
997k
  (*i) += 2;
153
154
997k
  return(ntohs(v));
155
997k
}
156
157
/* *********************************************** */
158
159
1.60M
static u_int getNameLength(u_int i, const u_int8_t *payload, u_int payloadLen) {
160
1.60M
  if(i >= payloadLen)
161
46.8k
    return(0);
162
1.56M
  else if(payload[i] == 0x00)
163
398k
    return(1);
164
1.16M
  else if((payload[i] & 0xC0)== 0xC0)
165
279k
    return(2);
166
883k
  else {
167
883k
    u_int8_t len = payload[i];
168
883k
    u_int8_t off = len + 1;
169
170
883k
    return(off + getNameLength(i+off, payload, payloadLen));
171
883k
  }
172
1.60M
}
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
5.89k
static char* dns_error_code2string(u_int16_t error_code, char *buf, u_int buf_len) {
194
5.89k
  switch(error_code) {
195
1.09k
  case 1: return((char*)"FORMERR");
196
693
  case 2: return((char*)"SERVFAIL");
197
1.93k
  case 3: return((char*)"NXDOMAIN");
198
329
  case 4: return((char*)"NOTIMP");
199
68
  case 5: return((char*)"REFUSED");
200
42
  case 6: return((char*)"YXDOMAIN");
201
106
  case 7: return((char*)"XRRSET");
202
82
  case 8: return((char*)"NOTAUTH");
203
91
  case 9: return((char*)"NOTZONE");
204
205
1.45k
  default:
206
1.45k
    snprintf(buf, buf_len, "%u", error_code);
207
1.45k
    return(buf);
208
5.89k
  }
209
5.89k
}
210
211
/* *********************************************** */
212
213
4.85M
u_int64_t fpc_dns_cache_key_from_flow(struct ndpi_flow_struct *flow) {
214
4.85M
  u_int64_t key;
215
216
4.85M
  if(flow->is_ipv6)
217
139k
    key = ndpi_quick_hash64((const char *)flow->s_address.v6, 16);
218
4.71M
  else
219
4.71M
    key = (u_int64_t)(flow->s_address.v4);
220
221
4.85M
  return key;
222
4.85M
}
223
224
/* *********************************************** */
225
226
99.1k
static u_int64_t fpc_dns_cache_key_from_packet(const unsigned char *ip, int ip_len) {
227
99.1k
  u_int64_t key;
228
229
99.1k
  if(ip_len == 16)
230
1.92k
    key = ndpi_quick_hash64((const char *)ip, 16);
231
97.2k
  else
232
97.2k
    key = (u_int64_t)(*(u_int32_t *)ip);
233
234
99.1k
  return key;
235
99.1k
}
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
244k
           u_int8_t ignore_checks) {
244
244k
  u_int8_t hostname_is_valid = 1;
245
244k
  u_int j = 0;
246
247
244k
  max_len--;
248
249
932k
  while((j < max_len)
250
931k
  && ((*off) < packet->payload_packet_len)
251
931k
  && (packet->payload[(*off)] != '\0')) {
252
737k
    u_int8_t c, cl = packet->payload[*off];
253
254
737k
    if(((cl & 0xc0) != 0) || // we not support compressed names in query
255
693k
       (((*off)+1) + cl  >= packet->payload_packet_len)) {
256
      /* Don't update the offset */
257
49.9k
      j = 0;
258
49.9k
      break;
259
49.9k
    }
260
261
687k
    (*off)++;
262
263
687k
    if(j && (j < max_len)) _hostname[j++] = '.';
264
265
4.53M
    while((j < max_len) && (cl != 0)) {
266
3.84M
      c = packet->payload[(*off)++];
267
268
3.84M
      if(ignore_checks)
269
419k
  _hostname[j++] = tolower(c);
270
3.43M
      else {
271
3.43M
  u_int32_t shift;
272
273
3.43M
  shift = ((u_int32_t) 1) << (c & 0x1f);
274
275
3.43M
  if((dns_validchar[c >> 5] & shift)) {
276
3.10M
    _hostname[j++] = tolower(c);
277
3.10M
  } else {
278
    /* printf("---?? '%c'\n", c); */
279
280
321k
    hostname_is_valid = 0;
281
282
321k
    if (ndpi_isprint(c) == 0) {
283
272k
      _hostname[j++] = '?';
284
272k
    } else {
285
48.6k
      _hostname[j++] = '_';
286
48.6k
    }
287
321k
  }
288
3.43M
      }
289
290
3.84M
      cl--;
291
3.84M
    }
292
687k
  }
293
294
244k
  _hostname[j] = '\0', *_hostname_len = j;
295
296
244k
  return(hostname_is_valid);
297
244k
}
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
246k
                           u_int payload_offset) {
305
246k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
306
246k
  u_int x = payload_offset;
307
246k
  u_int16_t rsp_type;
308
246k
  u_int16_t num;
309
310
471k
  for(num = 0; num < dns_header->num_queries; num++) {
311
261k
    u_int16_t data_len;
312
313
261k
    if((data_len = getNameLength(x, packet->payload,
314
261k
                                 packet->payload_packet_len)) == 0) {
315
643
      return -1;
316
643
    } else
317
260k
      x += data_len;
318
319
260k
    if(data_len > 253)
320
2.95k
      ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Query Lenght");
321
322
260k
    if((x+4) > packet->payload_packet_len) {
323
34.7k
      ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Query Lenght");
324
34.7k
      return -1;
325
34.7k
    }
326
327
225k
    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
225k
    if(flow->protos.dns.query_type == 0) {
333
      /* In case we missed the query packet... */
334
130k
      flow->protos.dns.query_type = rsp_type;
335
130k
    }
336
337
    /* here x points to the response "class" field */
338
225k
    x += 2; /* Skip class */
339
225k
  }
340
341
210k
  return x;
342
246k
}
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.4k
                           ndpi_master_app_protocol *proto) {
349
73.4k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
350
73.4k
  u_int x = payload_offset;
351
73.4k
  u_int16_t rsp_type;
352
73.4k
  u_int32_t rsp_ttl;
353
73.4k
  u_int16_t num;
354
73.4k
  u_int8_t found = 0;
355
73.4k
  int ignore_checks;
356
357
73.4k
  ignore_checks = (proto->master_protocol == NDPI_PROTOCOL_MDNS);
358
359
407k
  for(num = 0; num < dns_header->num_answers; num++) {
360
359k
    u_int16_t data_len;
361
362
359k
    if((data_len = getNameLength(x, packet->payload,
363
359k
                                 packet->payload_packet_len)) == 0) {
364
824
      return -1;
365
824
    } else
366
359k
      x += data_len;
367
368
359k
    if((x+8) >= packet->payload_packet_len) {
369
13.6k
      return -1;
370
13.6k
    }
371
372
345k
    rsp_type = get16(&x, packet->payload);
373
345k
    rsp_ttl  = ntohl(*((u_int32_t*)&packet->payload[x+2]));
374
375
345k
    if(rsp_ttl == 0)
376
63.0k
      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
345k
    if(found == 0) {
384
327k
      ndpi_check_dns_type(ndpi_struct, flow, rsp_type);
385
327k
      flow->protos.dns.rsp_type = rsp_type;
386
327k
    }
387
388
    /* x points to the response "class" field */
389
345k
    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
276k
        if(rsp_type == 0x05 /* CNAME */) {
401
30.3k
          ;
402
245k
        } else if(rsp_type == 0x0C /* PTR */) {
403
8.55k
          u_int16_t ptr_len = (packet->payload[x-2] << 8) + packet->payload[x-1];
404
405
8.55k
          if((x + ptr_len) <= packet->payload_packet_len) {
406
8.55k
            if(found == 0) {
407
5.00k
              u_int len, orig_x;
408
409
5.00k
              orig_x = x;
410
5.00k
              ndpi_grab_dns_name(packet, &x,
411
5.00k
                                 flow->protos.dns.ptr_domain_name,
412
5.00k
                                 sizeof(flow->protos.dns.ptr_domain_name), &len,
413
5.00k
                                 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
5.00k
              x = orig_x;
417
5.00k
              found = 1;
418
5.00k
            }
419
8.55k
          }
420
237k
        } else if((((rsp_type == 0x1) && (data_len == 4)) /* A */
421
100k
                   || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */
422
237k
                   )) {
423
140k
          if(found == 0) {
424
425
136k
            if(flow->protos.dns.num_rsp_addr < MAX_NUM_DNS_RSP_ADDRESSES) {
426
              /* Necessary for IP address comparison */
427
136k
              memset(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], 0, sizeof(ndpi_ip_addr_t));
428
429
136k
              memcpy(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], packet->payload + x, data_len);
430
136k
              flow->protos.dns.is_rsp_addr_ipv6[flow->protos.dns.num_rsp_addr] = (data_len == 16) ? 1 : 0;
431
136k
              flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr] = ttl;
432
433
136k
              if(ndpi_struct->cfg.address_cache_size)
434
132k
                ndpi_cache_address(ndpi_struct,
435
132k
                                   flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr],
436
132k
                                   flow->host_server_name,
437
132k
                                   packet->current_time_ms/1000,
438
132k
                                   flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr]);
439
440
136k
        if(ndpi_struct->cfg.hostname_dns_check_enabled)
441
129k
    ndpi_cache_hostname_ip(ndpi_struct,
442
129k
               &flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr],
443
129k
               flow->host_server_name);
444
445
136k
              ++flow->protos.dns.num_rsp_addr;
446
136k
            }
447
448
136k
            if(flow->protos.dns.num_rsp_addr >= MAX_NUM_DNS_RSP_ADDRESSES)
449
9.22k
              found = 1;
450
136k
          }
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
99.9k
             proto->app_protocol != proto->master_protocol &&
456
99.2k
             ndpi_struct->fpc_dns_cache) {
457
99.1k
            ndpi_lru_add_to_cache(ndpi_struct->fpc_dns_cache,
458
99.1k
                                  fpc_dns_cache_key_from_packet(packet->payload + x, data_len),
459
99.1k
                                  proto->app_protocol,
460
99.1k
                                  ndpi_get_current_time(flow));
461
462
99.1k
            NDPI_LOG_DBG(ndpi_struct, "Adding entry to fpc_dns: %s proto %d\n",
463
99.1k
                         data_len == 4 ? "ipv4" : "ipv6", proto->app_protocol);
464
99.1k
          }
465
140k
        }
466
467
276k
        x += data_len;
468
276k
      }
469
341k
    }
470
471
345k
    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.5k
      break;
479
11.5k
    }
480
345k
  }
481
482
59.0k
  return x;
483
73.4k
}
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
59.0k
                               u_int payload_offset) {
489
59.0k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
490
59.0k
  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
59.0k
  if(dns_header->additional_rrs == 0)
503
48.2k
    return x;
504
505
10.7k
  if(dns_header->authority_rrs > 0) {
506
#ifdef DNS_DEBUG
507
    u_int16_t rsp_type;
508
#endif
509
4.36k
    u_int16_t num;
510
511
28.5k
    for(num = 0; num < dns_header->authority_rrs; num++) {
512
26.1k
      u_int16_t data_len;
513
514
26.1k
      if((x+6) >= packet->payload_packet_len) {
515
450
        return -1;
516
450
      }
517
518
25.6k
      if((data_len = getNameLength(x, packet->payload,
519
25.6k
                                   packet->payload_packet_len)) == 0) {
520
0
        return -1;
521
0
      } else
522
25.6k
        x += data_len;
523
524
25.6k
      if((x+8) >= packet->payload_packet_len) {
525
1.46k
        return -1;
526
1.46k
      }
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.1k
      get16(&x, packet->payload);
533
24.1k
#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.1k
      if((x+12) <= packet->payload_packet_len) {
541
23.4k
        x += 6;
542
23.4k
        data_len = get16(&x, packet->payload);
543
544
23.4k
        if((x + data_len) <= packet->payload_packet_len)
545
17.1k
          x += data_len;
546
23.4k
      }
547
24.1k
    }
548
4.36k
  }
549
550
8.81k
  if(dns_header->additional_rrs > 0) {
551
8.81k
    u_int16_t rsp_type;
552
8.81k
    u_int16_t num;
553
554
46.2k
    for(num = 0; num < dns_header->additional_rrs; num++) {
555
41.7k
      u_int16_t data_len, rdata_len, opt_code, opt_len;
556
41.7k
      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
41.7k
      if((x+6) > packet->payload_packet_len) {
563
1.73k
        return -1;
564
1.73k
      }
565
566
39.9k
      if((data_len = getNameLength(x, packet->payload, packet->payload_packet_len)) == 0) {
567
0
        return -1;
568
0
      } else
569
39.9k
        x += data_len;
570
571
39.9k
      if((x+10) > packet->payload_packet_len) {
572
2.51k
        return -1;
573
2.51k
      }
574
575
37.4k
      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
37.4k
      if(rsp_type == 41 /* OPT */) {
582
        /* https://en.wikipedia.org/wiki/Extension_Mechanisms_for_DNS */
583
5.31k
        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
5.31k
        x += 6;
589
590
5.31k
        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
5.31k
        if(rdata_len > 0 &&
595
4.22k
           x + 6 <= packet->payload_packet_len) {
596
4.12k
          opt_code = ntohs(*((u_int16_t *)&packet->payload[x + 2]));
597
4.12k
          opt_len = ntohs(*((u_int16_t *)&packet->payload[x + 4]));
598
4.12k
          opt = &packet->payload[x + 6];
599
          /* TODO: parse the TLV list */
600
4.12k
          if(opt_code == 0x03 &&
601
2.51k
             opt_len <= rdata_len + 4 &&
602
2.10k
             opt_len > 6 &&
603
1.81k
             x + 6 + opt_len <= packet->payload_packet_len) {
604
#ifdef DNS_DEBUG
605
            printf("[DNS] NSID: [%.*s]\n", opt_len, opt);
606
#endif
607
1.20k
            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
805
              memcpy(flow->protos.dns.geolocation_iata_code, opt + 6,
612
805
                     ndpi_min(opt_len - 6, (int)sizeof(flow->protos.dns.geolocation_iata_code) - 1));
613
805
            }
614
1.20k
          }
615
616
4.12k
        }
617
32.1k
      } else {
618
32.1k
        x += 6;
619
32.1k
      }
620
621
37.4k
      if((data_len = getNameLength(x, packet->payload, packet->payload_packet_len)) == 0) {
622
0
        return -1;
623
0
      } else
624
37.4k
        x += data_len;
625
37.4k
    }
626
8.81k
  }
627
628
4.56k
  return x;
629
8.81k
}
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
280k
      u_int payload_offset, u_int8_t *is_query) {
635
280k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
636
637
280k
  if(packet->payload_packet_len < sizeof(struct ndpi_dns_packet_header) + payload_offset)
638
482
    return 0;
639
640
279k
  memcpy(dns_header, (struct ndpi_dns_packet_header*)&packet->payload[payload_offset],
641
279k
   sizeof(struct ndpi_dns_packet_header));
642
643
279k
  dns_header->tr_id = ntohs(dns_header->tr_id);
644
279k
  dns_header->flags = ntohs(dns_header->flags);
645
279k
  dns_header->num_queries = ntohs(dns_header->num_queries);
646
279k
  dns_header->num_answers = ntohs(dns_header->num_answers);
647
279k
  dns_header->authority_rrs = ntohs(dns_header->authority_rrs);
648
279k
  dns_header->additional_rrs = ntohs(dns_header->additional_rrs);
649
650
279k
  if((dns_header->flags & FLAGS_MASK) == 0x0000)
651
187k
    *is_query = 1;
652
92.5k
  else
653
92.5k
    *is_query = 0;
654
655
279k
  if(*is_query) {
656
187k
    if(dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS &&
657
       /* dns_header->num_answers == 0 && */
658
169k
       ((dns_header->flags & 0x2800) == 0x2800 /* Dynamic DNS Update */ ||
659
167k
  (dns_header->flags & 0xFCF0) == 0x00 /* Standard Query */ ||
660
9.19k
  (dns_header->flags & 0xFCFF) == 0x0800 /* Inverse query */ ||
661
166k
  (dns_header->num_answers == 0 && dns_header->authority_rrs == 0))) {
662
      /* This is a good query */
663
166k
      return 1;
664
166k
    }
665
187k
  } else {
666
92.5k
    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.3k
        (checkDNSSubprotocol(ntohs(flow->c_port), ntohs(flow->s_port)) == NDPI_PROTOCOL_MDNS && dns_header->num_queries == 0)) &&
668
82.5k
       ((dns_header->num_answers > 0 && dns_header->num_answers <= NDPI_MAX_DNS_REQUESTS) ||
669
13.9k
        (dns_header->authority_rrs > 0 && dns_header->authority_rrs <= NDPI_MAX_DNS_REQUESTS) ||
670
9.79k
        (dns_header->additional_rrs > 0 && dns_header->additional_rrs <= NDPI_MAX_DNS_REQUESTS) ||
671
79.5k
        (dns_header->num_answers == 0 && dns_header->authority_rrs == 0 && dns_header->additional_rrs == 0))) {
672
      /* This is a good reply */
673
79.5k
      return 1;
674
79.5k
    }
675
12.9k
    if(dns_header->num_queries == 0 && dns_header->num_answers == 0 &&
676
1.10k
       dns_header->authority_rrs == 0 && dns_header->additional_rrs == 0 &&
677
533
       packet->payload_packet_len == sizeof(struct ndpi_dns_packet_header)) {
678
      /* This is a good empty reply */
679
201
      return 1;
680
201
    }
681
12.9k
  }
682
33.8k
  return 0;
683
279k
}
684
685
/* *********************************************** */
686
687
static int keep_extra_dissection(struct ndpi_flow_struct *flow)
688
226k
{
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
226k
  return !(!flow->protos.dns.is_query && flow->protos.dns.num_answers != 0);
692
226k
}
693
694
/* *********************************************** */
695
696
111k
static int search_dns_again(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
697
111k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
698
699
111k
  if(packet->tcp_retransmission || packet->payload_packet_len == 0)
700
829
    return keep_extra_dissection(flow);
701
702
  /* possibly dissect the DNS reply */
703
110k
  search_dns(ndpi_struct, flow);
704
705
110k
  return keep_extra_dissection(flow);
706
111k
}
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
246k
                            ndpi_master_app_protocol *proto) {
714
246k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
715
246k
  char *dot;
716
246k
  u_int len, is_mdns, off = sizeof(struct ndpi_dns_packet_header) + (packet->tcp ? 2 : 0);
717
246k
  char _hostname[256];
718
246k
  u_int8_t hostname_is_valid;
719
720
246k
  proto->master_protocol = checkDNSSubprotocol(ntohs(flow->c_port), ntohs(flow->s_port));
721
246k
  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
246k
  if(dns_header->num_queries == 0 && dns_header->num_answers == 0)
725
6.68k
    return -1;
726
727
239k
  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
239k
  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
239k
  ndpi_hostname_sni_set(flow, (const u_int8_t *)_hostname, len, is_mdns ? NDPI_HOSTNAME_NORM_LC : NDPI_HOSTNAME_NORM_ALL);
739
740
239k
  if (hostname_is_valid == 0)
741
44.5k
    ndpi_set_risk(ndpi_struct, flow, NDPI_INVALID_CHARACTERS, "Invalid chars detected in domain name");
742
743
  /* Ignore reverse DNS queries */
744
239k
  if(strstr(_hostname, ".in-addr.") == NULL) {
745
232k
    dot = strchr(_hostname, '.');
746
747
232k
    if(dot) {
748
151k
      uintptr_t first_element_len = dot - _hostname;
749
750
151k
      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
614
        if(ends_with(ndpi_struct, _hostname, "multi.surbl.org")
757
614
           || ends_with(ndpi_struct, _hostname, "spamhaus.org")
758
614
           || ends_with(ndpi_struct, _hostname, "rackcdn.com")
759
614
           || ends_with(ndpi_struct, _hostname, "akamaiedge.net")
760
536
           || ends_with(ndpi_struct, _hostname, "mx-verification.google.com")
761
536
           || ends_with(ndpi_struct, _hostname, "amazonaws.com")
762
614
           )
763
113
          ; /* Check common domain exceptions [TODO: if the list grows too much use a different datastructure] */
764
501
        else
765
501
          ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_SUSPICIOUS_TRAFFIC, "Long DNS host name");
766
614
      }
767
151k
    }
768
232k
  }
769
770
239k
  if(strlen(flow->host_server_name) > 0) {
771
179k
    ndpi_protocol_match_result ret_match;
772
773
179k
    if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN) {
774
156k
      proto->app_protocol = ndpi_match_host_subprotocol(ndpi_struct, flow,
775
156k
                                                        flow->host_server_name,
776
156k
                                                        strlen(flow->host_server_name),
777
156k
                                                        &ret_match,
778
156k
                                                        proto->master_protocol,
779
                                                        /* Avoid updating classification if subclassification is disabled */
780
156k
                                                        ndpi_struct->cfg.dns_subclassification_enabled ? 1 : 0);
781
156k
    }
782
783
179k
    ndpi_check_dga_name(ndpi_struct, flow, flow->host_server_name, 1, 0, proto->app_protocol != NDPI_PROTOCOL_UNKNOWN);
784
179k
  }
785
786
239k
  return 0;
787
246k
}
788
789
280k
static void search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
790
280k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
791
280k
  int payload_offset = 0;
792
280k
  u_int8_t is_query;
793
280k
  struct ndpi_dns_packet_header dns_header;
794
280k
  u_int off;
795
280k
  ndpi_master_app_protocol proto;
796
280k
  int rc;
797
798
280k
  if(packet->udp != NULL) {
799
267k
    payload_offset = 0;
800
267k
  } else if(packet->tcp != NULL) {
801
12.9k
    payload_offset = 2;
802
12.9k
  }
803
804
280k
  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
34.2k
    if(flow->extra_packets_func == NULL) {
809
24.4k
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
810
24.4k
    } else {
811
9.79k
      ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Header");
812
9.79k
    }
813
34.2k
    return;
814
34.2k
  }
815
816
246k
  process_hostname(ndpi_struct, flow, &dns_header, &proto);
817
818
246k
  off = sizeof(struct ndpi_dns_packet_header) + payload_offset;
819
820
246k
  if(is_query) {
821
166k
    flow->protos.dns.is_query = 1;
822
166k
    flow->protos.dns.transaction_id = dns_header.tr_id;
823
824
166k
    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
166k
  } else {
830
79.7k
    flow->protos.dns.is_query = 0;
831
79.7k
    flow->protos.dns.transaction_id = dns_header.tr_id;
832
79.7k
    flow->protos.dns.reply_code = dns_header.flags & 0x0F;
833
79.7k
    flow->protos.dns.num_queries = dns_header.num_queries;
834
79.7k
    flow->protos.dns.num_answers = dns_header.num_answers + dns_header.authority_rrs + dns_header.additional_rrs;
835
836
79.7k
    if(flow->protos.dns.reply_code != 0) {
837
6.76k
      if(is_flowrisk_info_enabled(ndpi_struct, NDPI_ERROR_CODE_DETECTED)) {
838
5.89k
        char str[32], buf[16];
839
840
5.89k
        snprintf(str, sizeof(str), "DNS Error Code %s",
841
5.89k
                 dns_error_code2string(flow->protos.dns.reply_code, buf, sizeof(buf)));
842
5.89k
        ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, str);
843
5.89k
      } else {
844
870
        ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, NULL);
845
870
      }
846
73.0k
    } else {
847
73.0k
      if(ndpi_isset_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN)) {
848
2.19k
        ndpi_set_risk(ndpi_struct, flow, NDPI_RISKY_DOMAIN, "DGA Name Query with no Error Code");
849
2.19k
      }
850
73.0k
    }
851
852
79.7k
    rc = process_queries(ndpi_struct, flow, &dns_header, off);
853
79.7k
    if(rc == -1) {
854
#ifdef DNS_DEBUG
855
      printf("[DNS] Error queries (response msg)\n");
856
#endif
857
73.4k
    } else {
858
73.4k
      off = rc;
859
73.4k
      rc = process_answers(ndpi_struct, flow, &dns_header, off, &proto);
860
73.4k
      if(rc == -1) {
861
#ifdef DNS_DEBUG
862
        printf("[DNS] Error answers\n");
863
#endif
864
59.0k
      } else {
865
59.0k
        off = rc;
866
59.0k
        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
59.0k
      }
872
73.4k
    }
873
874
79.7k
    if(proto.master_protocol == NDPI_PROTOCOL_DNS &&
875
      /* TODO: add support to RFC6891 to avoid some false positives */
876
73.8k
       packet->udp &&
877
71.4k
       packet->payload_packet_len > PKT_LEN_ALERT &&
878
5.04k
       packet->payload_packet_len > flow->protos.dns.edns0_udp_payload_size) {
879
4.84k
      if(is_flowrisk_info_enabled(ndpi_struct, NDPI_DNS_LARGE_PACKET)) {
880
3.69k
        char str[48];
881
882
3.69k
        snprintf(str, sizeof(str), "%u Bytes DNS Packet", packet->payload_packet_len);
883
3.69k
        ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_LARGE_PACKET, str);
884
3.69k
      } else {
885
1.14k
        ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_LARGE_PACKET, NULL);
886
1.14k
      }
887
4.84k
    }
888
889
79.7k
    NDPI_LOG_DBG2(ndpi_struct, "Response: [num_queries=%d][num_answers=%d][reply_code=%u][rsp_type=%u][host_server_name=%s]\n",
890
79.7k
                  flow->protos.dns.num_queries, flow->protos.dns.num_answers,
891
79.7k
                  flow->protos.dns.reply_code, flow->protos.dns.rsp_type, flow->host_server_name);
892
79.7k
  }
893
894
246k
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) {
895
115k
    if(ndpi_struct->cfg.dns_subclassification_enabled)
896
100k
      ndpi_set_detected_protocol(ndpi_struct, flow, proto.app_protocol, proto.master_protocol, NDPI_CONFIDENCE_DPI);
897
15.1k
    else
898
15.1k
      ndpi_set_detected_protocol(ndpi_struct, flow,
899
15.1k
         (proto.master_protocol == NDPI_PROTOCOL_UNKNOWN) ? NDPI_PROTOCOL_DNS : proto.master_protocol,
900
15.1k
         NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
901
115k
  }
902
  /* Category is always NDPI_PROTOCOL_CATEGORY_NETWORK, regardless of the subprotocol. Same for the breed */
903
246k
  flow->category = NDPI_PROTOCOL_CATEGORY_NETWORK;
904
246k
  flow->breed = NDPI_PROTOCOL_ACCEPTABLE;
905
906
246k
  if(!flow->extra_packets_func &&
907
145k
     ndpi_struct->cfg.dns_parse_response_enabled &&
908
     /* We have never triggered extra-dissection for LLMNR. Keep the old behavior */
909
132k
     flow->detected_protocol_stack[0] != NDPI_PROTOCOL_LLMNR &&
910
115k
     flow->detected_protocol_stack[1] != NDPI_PROTOCOL_LLMNR) {
911
115k
    if(keep_extra_dissection(flow)) {
912
87.6k
      NDPI_LOG_DBG(ndpi_struct, "Enabling extra dissection\n");
913
87.6k
      flow->max_extra_packets_to_check = 5;
914
87.6k
      flow->extra_packets_func = search_dns_again;
915
87.6k
    }
916
115k
  }
917
918
  /* The bigger packets are usually the replies, but it shouldn't harm
919
     to check the requests, too */
920
246k
  if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DNS)
921
207k
     || (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) {
922
923
207k
    if(packet->iph != NULL) {
924
      /* IPv4 */
925
204k
      u_int8_t flags = ((u_int8_t*)packet->iph)[6];
926
927
      /* 0: fragmented; 1: not fragmented */
928
204k
      if((flags & 0x20)
929
202k
   || (iph_is_valid_and_not_fragmented(ndpi_struct, packet->iph, packet->l3_packet_len) == 0)) {
930
1.29k
  ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_FRAGMENTED, NULL);
931
1.29k
      }
932
204k
    } else if(packet->iphv6 != NULL) {
933
      /* IPv6 */
934
3.74k
      const struct ndpi_ip6_hdrctl *ip6_hdr = &packet->iphv6->ip6_hdr;
935
936
3.74k
      if(ip6_hdr->ip6_un1_nxt == 0x2C /* Next Header: Fragment Header for IPv6 (44) */) {
937
278
  ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_FRAGMENTED, NULL);
938
278
      }
939
3.74k
    }
940
207k
  }
941
246k
}
942
943
/* *********************************************** */
944
945
4.78M
static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
946
4.78M
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
947
4.78M
  u_int16_t s_port = 0, d_port = 0;
948
4.78M
  int payload_offset = 0;
949
950
4.78M
  NDPI_LOG_DBG(ndpi_struct, "search DNS\n");
951
952
4.78M
  if(packet->udp != NULL) {
953
1.15M
    s_port = ntohs(packet->udp->source);
954
1.15M
    d_port = ntohs(packet->udp->dest);
955
1.15M
    payload_offset = 0;
956
957
    /* For MDNS/LLMNR: If the packet is not a response, dest addr needs to be multicast. */
958
1.15M
    if ((d_port == MDNS_PORT && isMDNSMulticastAddress(packet) == 0) ||
959
1.14M
        (d_port == LLMNR_PORT && isLLMNRMulticastAddress(packet) == 0))
960
10.1k
    {
961
10.1k
      if (packet->payload_packet_len > 5 &&
962
10.1k
          ntohs(get_u_int16_t(packet->payload, 2)) != 0 &&
963
10.1k
          ntohs(get_u_int16_t(packet->payload, 4)) != 0)
964
1.60k
      {
965
1.60k
        NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
966
1.60k
        return;
967
1.60k
      }
968
10.1k
    }
969
3.63M
  } else if(packet->tcp != NULL) {
970
3.63M
    s_port = ntohs(packet->tcp->source);
971
3.63M
    d_port = ntohs(packet->tcp->dest);
972
3.63M
    payload_offset = 2;
973
3.63M
  }
974
975
  /* We are able to detect DNS/MDNS/LLMNR only on standard ports (see #1788) */
976
4.78M
  if(!(s_port == DNS_PORT || d_port == DNS_PORT ||
977
4.64M
       s_port == MDNS_PORT || d_port == MDNS_PORT ||
978
4.63M
       d_port == LLMNR_PORT)) {
979
4.61M
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
980
4.61M
    return;
981
4.61M
  }
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
174k
  if(packet->payload_packet_len < sizeof(struct ndpi_dns_packet_header) + payload_offset) {
989
5.08k
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
990
5.08k
    return;
991
5.08k
  }
992
993
169k
  search_dns(ndpi_struct, flow);
994
169k
}
995
996
/* *********************************************** */
997
998
14.2k
void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct) {
999
14.2k
  ndpi_register_dissector("DNS", ndpi_struct,
1000
14.2k
                     ndpi_search_dns,
1001
14.2k
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
1002
14.2k
                     1, NDPI_PROTOCOL_DNS);
1003
14.2k
}