Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-lwres.c
Line
Count
Source
1
/* packet-lwres.c
2
 * Routines for lightweight resolver (lwresd, formerly part of BIND9) packet disassembly
3
 * lwresd was removed in Bind 9.12. It ran on the IPv4 loopback interface only.
4
 *
5
 * Copyright (c) 2003 by Oleg Terletsky <oleg.terletsky@comverse.com>
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1999 Gerald Combs
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
#include "config.h"
15
16
17
#include <epan/packet.h>
18
#include <epan/to_str.h>
19
#include <epan/strutil.h>
20
21
#include "packet-dns.h"
22
23
void proto_register_lwres(void);
24
void proto_reg_handoff_lwres(void);
25
26
static dissector_handle_t lwres_handle;
27
28
0
#define LWRES_LWPACKET_LENGTH           (4 * 5 + 2 * 4)
29
0
#define LWRES_LWPACKETFLAG_RESPONSE     0x0001U /* if set, pkt is a response */
30
#define LWRES_LWPACKETVERSION_0         0
31
32
0
#define LW_LENGTH_OFFSET         0
33
0
#define LW_VERSION_OFFSET        4
34
0
#define LW_PKTFLASG_OFFSET       6
35
0
#define LW_SERIAL_OFFSET         8
36
0
#define LW_OPCODE_OFFSET        12
37
0
#define LW_RESULT_OFFSET        16
38
0
#define LW_RECVLEN_OFFSET       20
39
0
#define LW_AUTHTYPE_OFFSET      24
40
0
#define LW_AUTHLEN_OFFSET       26
41
42
0
#define LWRES_OPCODE_NOOP               0x00000000U
43
0
#define LWRES_OPCODE_GETADDRSBYNAME     0x00010001U
44
0
#define LWRES_OPCODE_GETNAMEBYADDR      0x00010002U
45
0
#define LWRES_OPCODE_GETRDATABYNAME     0x00010003U
46
47
static const value_string opcode_values[] = {
48
    { LWRES_OPCODE_NOOP,            "Noop" },
49
    { LWRES_OPCODE_GETADDRSBYNAME,  "getaddrbyname" },
50
    { LWRES_OPCODE_GETNAMEBYADDR,   "getnamebyaddr" },
51
    { LWRES_OPCODE_GETRDATABYNAME,  "getrdatabyname" },
52
    { 0, NULL },
53
};
54
55
56
#define LWRES_R_SUCCESS                  0
57
#define LWRES_R_NOMEMORY                 1
58
#define LWRES_R_TIMEOUT                  2
59
#define LWRES_R_NOTFOUND                 3
60
#define LWRES_R_UNEXPECTEDEND            4       /* unexpected end of input */
61
#define LWRES_R_FAILURE                  5       /* generic failure */
62
#define LWRES_R_IOERROR                  6
63
#define LWRES_R_NOTIMPLEMENTED           7
64
#define LWRES_R_UNEXPECTED               8
65
#define LWRES_R_TRAILINGDATA             9
66
#define LWRES_R_INCOMPLETE              10
67
#define LWRES_R_RETRY                   11
68
#define LWRES_R_TYPENOTFOUND            12
69
#define LWRES_R_TOOLARGE                13
70
71
0
#define T_A     1
72
0
#define T_NS    2
73
0
#define T_MX    15
74
0
#define T_SRV   33
75
76
77
static const value_string t_types[] = {
78
    { T_A,      "T_A" },
79
    { T_NS,     "T_NS" },
80
    { T_MX,     "T_MX" },
81
    { T_SRV,    "T_SRV" },
82
    { 0,        NULL },
83
};
84
85
86
87
88
static const value_string result_values[]  = {
89
    { LWRES_R_SUCCESS,          "Success" },
90
    { LWRES_R_NOMEMORY,         "No memory" },
91
    { LWRES_R_TIMEOUT,          "Timeout" },
92
    { LWRES_R_NOTFOUND,         "Not found" },
93
    { LWRES_R_UNEXPECTEDEND,    "Unexpected end of input" },
94
    { LWRES_R_FAILURE,          "Generic failure" },
95
    { LWRES_R_IOERROR,          "I/O Error" },
96
    { LWRES_R_NOTIMPLEMENTED,   "Not Implemented"},
97
    { LWRES_R_UNEXPECTED,       "Unexpected" },
98
    { LWRES_R_TRAILINGDATA,     "Trailing data" },
99
    { LWRES_R_INCOMPLETE,       "Incomplete" },
100
    { LWRES_R_RETRY,            "Retry" },
101
    { LWRES_R_TYPENOTFOUND,     "Type not found" },
102
    { LWRES_R_TOOLARGE,         "Too large" },
103
    { 0,                        NULL },
104
};
105
106
static int hf_length;
107
static int hf_version;
108
static int hf_flags;
109
static int hf_serial;
110
static int hf_opcode;
111
static int hf_result;
112
static int hf_recvlen;
113
static int hf_authtype;
114
static int hf_authlen;
115
116
static int hf_rflags;
117
static int hf_rdclass;
118
static int hf_rdtype;
119
static int hf_namelen;
120
static int hf_req_name;
121
122
static int hf_ttl;
123
static int hf_nrdatas;
124
static int hf_nsigs;
125
static int hf_realnamelen;
126
static int hf_realname;
127
128
129
static int hf_a_record;
130
static int hf_a_rec_len;
131
static int hf_srv_prio;
132
static int hf_srv_weight;
133
static int hf_srv_port;
134
static int hf_srv_dname;
135
136
static int hf_adn_flags;
137
static int hf_adn_addrtype;
138
static int hf_adn_namelen;
139
static int hf_adn_name;
140
141
static int hf_adn_realname;
142
static int hf_adn_aliasname;
143
144
static int hf_adn_naddrs;
145
static int hf_adn_naliases;
146
static int hf_adn_family;
147
static int hf_adn_addr_len;
148
static int hf_adn_addr_addr;
149
150
static int hf_ns_dname;
151
152
static int ett_lwres;
153
static int ett_rdata_req;
154
static int ett_rdata_resp;
155
static int ett_a_rec;
156
static int ett_a_rec_addr;
157
static int ett_srv_rec;
158
static int ett_srv_rec_item;
159
static int ett_adn_request;
160
static int ett_adn_resp;
161
static int ett_adn_alias;
162
static int ett_adn_addr;
163
static int ett_nba_request;
164
static int ett_nba_resp;
165
static int ett_noop;
166
167
static int ett_mx_rec;
168
static int ett_mx_rec_item;
169
170
static int ett_ns_rec;
171
static int ett_ns_rec_item;
172
173
174
#if 0
175
#define LWRES_UDP_PORT 921 /* Not IANA registered */
176
#endif
177
178
/* Define the lwres proto */
179
static int proto_lwres;
180
181
182
/* Define many many headers for mgcp */
183
184
static const value_string message_types_values[] = {
185
    { 1,        "REQUEST " },
186
    { 2,        "RESPONSE" },
187
    { 0,        NULL },
188
};
189
190
static void dissect_getnamebyaddr_request(tvbuff_t* tvb, packet_info *pinfo, proto_tree* lwres_tree)
191
0
{
192
0
    uint32_t flags,family;
193
0
    unsigned   addrlen, slen;
194
0
    const char* addrs;
195
196
0
    proto_tree* nba_request_tree;
197
198
0
    flags = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH);
199
0
    family = tvb_get_ntohl(tvb, LWRES_LWPACKET_LENGTH + 4);
200
0
    addrlen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 8);
201
0
    addrs = tvb_ip_to_str(pinfo->pool, tvb, LWRES_LWPACKET_LENGTH + 10);
202
0
    slen = (int)strlen(addrs);
203
204
0
    if (lwres_tree == NULL)
205
0
        return;
206
207
0
    nba_request_tree = proto_tree_add_subtree(lwres_tree,tvb,LWRES_LWPACKET_LENGTH,LWRES_LWPACKET_LENGTH+14,
208
0
                                        ett_nba_request,NULL,"getnamebyaddr parameters");
209
210
0
    proto_tree_add_uint(nba_request_tree, hf_adn_flags, tvb,
211
0
                LWRES_LWPACKET_LENGTH, 4, flags);
212
213
0
    proto_tree_add_uint(nba_request_tree, hf_adn_family, tvb,
214
0
                LWRES_LWPACKET_LENGTH + 4, 4, family);
215
216
0
    proto_tree_add_uint(nba_request_tree, hf_adn_addr_len, tvb,
217
0
                LWRES_LWPACKET_LENGTH + 8, 2, addrlen);
218
219
0
    proto_tree_add_string(nba_request_tree, hf_adn_addr_addr, tvb,
220
0
                  LWRES_LWPACKET_LENGTH + 10, slen, addrs);
221
222
0
}
223
224
static void dissect_getnamebyaddr_response(tvbuff_t* tvb, packet_info *pinfo, proto_tree* lwres_tree)
225
0
{
226
0
    uint32_t i, offset;
227
0
    uint16_t naliases,realnamelen,aliaslen;
228
0
    char *aliasname;
229
230
0
    proto_tree* nba_resp_tree;
231
0
    proto_tree* alias_tree;
232
233
0
    if(lwres_tree == NULL)
234
0
        return;
235
236
0
    nba_resp_tree = proto_tree_add_subtree(lwres_tree, tvb, LWRES_LWPACKET_LENGTH, 10, ett_nba_resp, NULL, "getnamebyaddr records");
237
238
0
    naliases = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 4);
239
0
    realnamelen = tvb_get_ntohs(tvb,LWRES_LWPACKET_LENGTH + 4 + 2);
240
241
0
    proto_tree_add_item(nba_resp_tree,
242
0
                        hf_adn_flags,
243
0
                        tvb,
244
0
                        LWRES_LWPACKET_LENGTH,
245
0
                        4,
246
0
                        ENC_BIG_ENDIAN);
247
0
    proto_tree_add_item(nba_resp_tree,
248
0
                        hf_adn_naliases,
249
0
                        tvb,
250
0
                        LWRES_LWPACKET_LENGTH + 4,
251
0
                        2,
252
0
                        ENC_BIG_ENDIAN);
253
254
0
    proto_tree_add_item(nba_resp_tree,
255
0
                        hf_adn_namelen,
256
0
                        tvb,
257
0
                        LWRES_LWPACKET_LENGTH + 6,
258
0
                        2,
259
0
                        ENC_BIG_ENDIAN);
260
261
0
    proto_tree_add_item(nba_resp_tree,
262
0
                        hf_adn_realname,
263
0
                        tvb,
264
0
                        LWRES_LWPACKET_LENGTH + 8,
265
0
                        realnamelen,
266
0
                        ENC_ASCII);
267
268
0
    offset=LWRES_LWPACKET_LENGTH + 8 + realnamelen;
269
270
0
    if(naliases)
271
0
    {
272
0
        for(i=0; i<naliases; i++)
273
0
        {
274
0
            aliaslen = tvb_get_ntohs(tvb, offset);
275
0
            aliasname = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset + 2, aliaslen, ENC_ASCII);
276
277
0
            alias_tree = proto_tree_add_subtree_format(nba_resp_tree, tvb, offset, 2 + aliaslen,
278
0
                                ett_adn_alias, NULL, "Alias %s",aliasname);
279
280
0
            proto_tree_add_item(alias_tree,
281
0
                                hf_adn_namelen,
282
0
                                tvb,
283
0
                                offset,
284
0
                                2,
285
0
                                ENC_BIG_ENDIAN);
286
287
0
            proto_tree_add_item(alias_tree,
288
0
                                hf_adn_aliasname,
289
0
                                tvb,
290
0
                                offset + 2,
291
0
                                aliaslen,
292
0
                                ENC_ASCII);
293
294
0
            offset+=(2 + aliaslen + 1);
295
0
        }
296
0
    }
297
0
}
298
299
static void dissect_getaddrsbyname_request(tvbuff_t* tvb, proto_tree* lwres_tree)
300
0
{
301
0
    uint16_t namelen;
302
303
0
    proto_tree* adn_request_tree;
304
305
0
    namelen  = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 8);
306
307
0
    if(lwres_tree == NULL)
308
0
        return;
309
310
0
    adn_request_tree = proto_tree_add_subtree(lwres_tree,tvb,
311
0
                    LWRES_LWPACKET_LENGTH,10+namelen+1,
312
0
                    ett_adn_request, NULL,
313
0
                    "getaddrbyname parameters");
314
315
0
    proto_tree_add_item(adn_request_tree,
316
0
                hf_adn_flags,
317
0
                tvb,
318
0
                LWRES_LWPACKET_LENGTH+0,
319
0
                sizeof(uint32_t),
320
0
                ENC_BIG_ENDIAN);
321
322
0
    proto_tree_add_item(adn_request_tree,
323
0
                hf_adn_addrtype,
324
0
                tvb,
325
0
                LWRES_LWPACKET_LENGTH+4,
326
0
                sizeof(uint32_t),
327
0
                ENC_BIG_ENDIAN);
328
329
0
    proto_tree_add_item(adn_request_tree,
330
0
                hf_adn_namelen,
331
0
                tvb,
332
0
                LWRES_LWPACKET_LENGTH+8,
333
0
                sizeof(uint16_t),
334
0
                ENC_BIG_ENDIAN);
335
336
0
    proto_tree_add_item(adn_request_tree,
337
0
                hf_adn_name,
338
0
                tvb,
339
0
                LWRES_LWPACKET_LENGTH+10,
340
0
                namelen,
341
0
                ENC_ASCII);
342
343
0
}
344
345
346
static void dissect_getaddrsbyname_response(tvbuff_t* tvb, packet_info *pinfo, proto_tree* lwres_tree)
347
0
{
348
0
    uint32_t family ,i, offset;
349
0
    uint16_t naliases, naddrs, realnamelen, length, aliaslen;
350
0
    const char* addrs;
351
0
    unsigned slen;
352
0
    char *aliasname;
353
354
0
    proto_tree *adn_resp_tree;
355
0
    proto_tree *alias_tree;
356
0
    proto_tree *addr_tree;
357
358
359
360
0
    if(lwres_tree == NULL)
361
0
        return;
362
363
0
    adn_resp_tree = proto_tree_add_subtree(lwres_tree, tvb, LWRES_LWPACKET_LENGTH, 10,
364
0
                                        ett_adn_resp, NULL, "getaddrbyname records");
365
366
0
    naliases = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 4);
367
0
    naddrs   = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 6);
368
0
    realnamelen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH + 8);
369
370
371
0
    proto_tree_add_item(adn_resp_tree, hf_adn_flags, tvb,
372
0
                LWRES_LWPACKET_LENGTH, 4, ENC_BIG_ENDIAN);
373
374
0
    proto_tree_add_item(adn_resp_tree, hf_adn_naliases, tvb,
375
0
                LWRES_LWPACKET_LENGTH + 4, 2, ENC_BIG_ENDIAN);
376
377
0
    proto_tree_add_item(adn_resp_tree, hf_adn_naddrs, tvb,
378
0
                LWRES_LWPACKET_LENGTH + 6, 2, ENC_BIG_ENDIAN);
379
380
0
    proto_tree_add_item(adn_resp_tree, hf_adn_namelen, tvb,
381
0
                LWRES_LWPACKET_LENGTH + 8, 2, ENC_BIG_ENDIAN);
382
383
0
    proto_tree_add_item(adn_resp_tree, hf_adn_realname, tvb,
384
0
                LWRES_LWPACKET_LENGTH + 10, realnamelen, ENC_ASCII);
385
386
0
    offset = LWRES_LWPACKET_LENGTH + 10 + realnamelen + 1;
387
388
0
    if(naliases)
389
0
    {
390
0
        for(i=0; i<naliases; i++)
391
0
        {
392
0
            aliaslen = tvb_get_ntohs(tvb, offset);
393
0
            aliasname = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset + 2, aliaslen, ENC_ASCII);
394
395
0
            alias_tree = proto_tree_add_subtree_format(adn_resp_tree, tvb, offset, 2 + aliaslen,
396
0
                                                        ett_adn_alias, NULL, "Alias %s",aliasname);
397
398
0
            proto_tree_add_uint(alias_tree, hf_adn_namelen, tvb,
399
0
                        offset, 2, aliaslen);
400
401
0
            proto_tree_add_item(alias_tree, hf_adn_aliasname, tvb,
402
0
                        offset + 2, aliaslen, ENC_ASCII);
403
404
0
            offset+=(2 + aliaslen + 1);
405
0
        }
406
0
    }
407
408
0
    if(naddrs)
409
0
    {
410
0
        for(i=0; i < naddrs; i++)
411
0
        {
412
0
            family = tvb_get_ntohl(tvb, offset);
413
0
            length = tvb_get_ntohs(tvb, offset + 4);
414
0
            addrs = tvb_ip_to_str(pinfo->pool, tvb, offset + 6);
415
0
            slen = (int)strlen(addrs);
416
417
0
            addr_tree = proto_tree_add_subtree_format(adn_resp_tree,tvb, offset, 4+2+4, ett_adn_addr, NULL, "Address %s", addrs);
418
419
0
            proto_tree_add_uint(addr_tree, hf_adn_family, tvb,
420
0
                        offset, 4, family);
421
422
0
            proto_tree_add_uint(addr_tree, hf_adn_addr_len, tvb,
423
0
                        offset + 4, 2, length);
424
425
0
            proto_tree_add_string(addr_tree, hf_adn_addr_addr, tvb,
426
0
                          offset + 6, slen, addrs);
427
428
0
            offset+= 4 + 2 + 4;
429
0
        }
430
0
    }
431
432
433
0
}
434
435
static void dissect_a_records(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree,uint32_t nrec,int offset)
436
0
{
437
0
    uint32_t i, curr;
438
0
    const char* addrs;
439
0
    proto_tree* a_rec_tree;
440
0
    proto_tree* addr_tree;
441
442
0
    if(tree == NULL)
443
0
        return;
444
445
0
    a_rec_tree = proto_tree_add_subtree(tree,tvb,offset,
446
0
                (int)((sizeof(uint32_t) + sizeof(uint16_t)) * nrec),
447
0
                ett_a_rec, NULL, "A records");
448
449
0
    for(i=0; i<nrec; i++)
450
0
    {
451
452
0
        curr = offset + (int)((sizeof(uint32_t)+sizeof(uint16_t)) * i);
453
454
0
        addrs = tvb_ip_to_str(pinfo->pool, tvb, curr+2);
455
456
0
        addr_tree = proto_tree_add_subtree_format(a_rec_tree, tvb, curr,
457
0
                            6, ett_a_rec_addr, NULL, "Address %s", addrs);
458
459
0
        proto_tree_add_item(addr_tree, hf_a_rec_len, tvb, curr,
460
0
                    sizeof(uint16_t), ENC_BIG_ENDIAN);
461
462
0
        proto_tree_add_item(addr_tree, hf_a_record, tvb, curr + 2, 4, ENC_BIG_ENDIAN);
463
0
    }
464
465
0
}
466
467
static void dissect_srv_records(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree,uint32_t nrec,int offset)
468
0
{
469
0
    uint32_t i, curr;
470
0
    uint16_t /*len, namelen,*/ priority, weight, port;
471
0
    int dlen;
472
0
    unsigned used_bytes;
473
0
    const char *dname;
474
475
0
    proto_item* srv_rec_tree, *rec_tree;
476
477
0
    if(tree == NULL)
478
0
        return;
479
480
0
    srv_rec_tree = proto_tree_add_subtree_format(tree, tvb, offset, offset, ett_srv_rec, NULL, "SRV records (%d)", nrec);
481
482
0
    curr = offset;
483
484
0
    for(i=0; i < nrec; i++)
485
0
    {
486
        /*len =      tvb_get_ntohs(tvb, curr);*/
487
0
        priority = tvb_get_ntohs(tvb, curr + 2);
488
0
        weight   = tvb_get_ntohs(tvb, curr + 4);
489
0
        port     = tvb_get_ntohs(tvb, curr + 6);
490
        /*namelen = len - 8;*/
491
492
0
        used_bytes = get_dns_name(pinfo->pool, tvb, curr + 8, 0, curr + 8, &dname, &dlen);
493
494
0
        rec_tree = proto_tree_add_subtree_format(srv_rec_tree, tvb, curr, 6,
495
0
                    ett_srv_rec_item, NULL,
496
0
                    "SRV record:pri=%d,w=%d,port=%d,dname=%s",
497
0
                    priority, weight, port, format_text(pinfo->pool, dname, dlen));
498
499
0
        proto_tree_add_uint(rec_tree,
500
0
                        hf_srv_prio,
501
0
                        tvb,
502
0
                        curr + 2,
503
0
                        2,
504
0
                        priority);
505
506
0
        proto_tree_add_uint(rec_tree,
507
0
                        hf_srv_weight,
508
0
                        tvb,
509
0
                        curr + 4,
510
0
                        2,
511
0
                        weight);
512
513
0
        proto_tree_add_uint(rec_tree,
514
0
                        hf_srv_port,
515
0
                        tvb,
516
0
                        curr + 6,
517
0
                        2,
518
0
                        port);
519
520
521
0
        proto_tree_add_string(rec_tree,
522
0
                            hf_srv_dname,
523
0
                            tvb,
524
0
                            curr + 8,
525
0
                            used_bytes,
526
0
                            format_text(pinfo->pool, dname, dlen));
527
528
0
        curr+=(int)((sizeof(short)*4) + used_bytes);
529
530
0
    }
531
532
0
}
533
534
static void dissect_mx_records(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, uint32_t nrec, int offset)
535
0
{
536
537
0
    unsigned i, curr;
538
0
    unsigned priority;
539
0
    int dlen;
540
0
    unsigned used_bytes;
541
0
    const char *dname;
542
543
0
    proto_tree* mx_rec_tree, *rec_tree;
544
545
546
0
    if(tree == NULL)
547
0
        return;
548
549
0
    mx_rec_tree = proto_tree_add_subtree_format(tree, tvb, offset, offset, ett_mx_rec, NULL, "MX records (%d)", nrec);
550
551
0
    curr = offset;
552
0
    for(i=0; i < nrec; i++)
553
0
    {
554
        /*len =       tvb_get_ntohs(tvb, curr);*/
555
0
        priority = tvb_get_ntohs(tvb, curr + 2);
556
        /*namelen  =  len - 4;*/
557
558
0
        used_bytes  = get_dns_name(pinfo->pool, tvb, curr + 4, 0, curr + 4, &dname, &dlen);
559
560
0
        rec_tree = proto_tree_add_subtree_format(mx_rec_tree, tvb, curr,6,ett_mx_rec_item,NULL,
561
0
                        "MX record: pri=%d,dname=%s", priority,
562
0
                        format_text(pinfo->pool, dname, dlen));
563
564
565
0
        proto_tree_add_item(rec_tree,
566
0
                            hf_srv_prio,
567
0
                            tvb,
568
0
                            curr + 2,
569
0
                            2,
570
0
                            ENC_BIG_ENDIAN);
571
572
0
        proto_tree_add_string(rec_tree,
573
0
                            hf_srv_dname,
574
0
                            tvb,
575
0
                            curr + 4,
576
0
                            used_bytes,
577
0
                            format_text(pinfo->pool, dname, dlen));
578
579
0
        curr+=(int)((sizeof(short)*2) + used_bytes);
580
581
582
0
    }
583
584
0
}
585
586
static void dissect_ns_records(tvbuff_t* tvb, packet_info *pinfo, proto_tree* tree, uint32_t nrec, int offset)
587
0
{
588
0
    unsigned i, curr;
589
0
    int dlen;
590
0
    const char *dname;
591
0
    unsigned used_bytes;
592
593
0
    proto_tree* ns_rec_tree, *rec_tree;
594
595
0
    if(tree == NULL)
596
0
        return;
597
598
0
    ns_rec_tree = proto_tree_add_subtree_format(tree, tvb, offset, offset, ett_ns_rec, NULL, "NS record (%d)", nrec);
599
600
0
    curr=offset;
601
602
0
    for(i=0;i<nrec;i++)
603
0
    {
604
        /*len = tvb_get_ntohs(tvb, curr);*/
605
        /*namelen = len - 2;*/
606
607
0
        used_bytes = get_dns_name(pinfo->pool, tvb, curr + 2, 0, curr + 2, &dname, &dlen);
608
609
0
        rec_tree = proto_tree_add_subtree_format(ns_rec_tree, tvb, curr,4, ett_ns_rec_item, NULL, "NS record: dname=%s",
610
0
                        format_text(pinfo->pool, dname, dlen));
611
612
0
        proto_tree_add_string(rec_tree,
613
0
                            hf_ns_dname,
614
0
                            tvb,
615
0
                            curr + 2,
616
0
                            used_bytes,
617
0
                            format_text(pinfo->pool, dname, dlen));
618
0
        curr+=(int)(sizeof(short) + used_bytes);
619
620
0
    }
621
622
623
0
}
624
625
static void dissect_rdata_request(tvbuff_t* tvb, proto_tree* lwres_tree)
626
0
{
627
0
    uint16_t namelen;
628
629
0
    proto_tree* rdata_request_tree;
630
631
0
    namelen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+8);
632
633
0
    if(lwres_tree == NULL)
634
0
        return;
635
636
0
    rdata_request_tree =
637
0
            proto_tree_add_subtree(lwres_tree,tvb,LWRES_LWPACKET_LENGTH,10+namelen+1,ett_rdata_req,NULL,"RDATA request parameters");
638
639
0
    proto_tree_add_item(rdata_request_tree,
640
0
            hf_rflags,
641
0
            tvb,
642
0
            LWRES_LWPACKET_LENGTH+0,
643
0
            sizeof(uint32_t),
644
0
            ENC_BIG_ENDIAN);
645
646
0
    proto_tree_add_item(rdata_request_tree,
647
0
            hf_rdclass,
648
0
            tvb,
649
0
            LWRES_LWPACKET_LENGTH+4,
650
0
            sizeof(uint16_t),
651
0
            ENC_BIG_ENDIAN);
652
653
0
    proto_tree_add_item(rdata_request_tree,
654
0
            hf_rdtype,
655
0
            tvb,
656
0
            LWRES_LWPACKET_LENGTH+6,
657
0
            sizeof(uint16_t),
658
0
            ENC_BIG_ENDIAN);
659
660
0
    proto_tree_add_item(rdata_request_tree,
661
0
            hf_namelen,
662
0
            tvb,
663
0
            LWRES_LWPACKET_LENGTH+8,
664
0
            sizeof(uint16_t),
665
0
            ENC_BIG_ENDIAN);
666
667
0
    proto_tree_add_item(rdata_request_tree,
668
0
            hf_req_name,
669
0
            tvb,
670
0
            LWRES_LWPACKET_LENGTH+10,
671
0
            namelen,
672
0
                ENC_ASCII);
673
674
0
}
675
676
static void dissect_rdata_response(tvbuff_t* tvb, packet_info *pinfo, proto_tree* lwres_tree)
677
0
{
678
0
    unsigned offset;
679
0
    unsigned rdtype, nrdatas, realnamelen;
680
681
0
    proto_tree* rdata_resp_tree;
682
683
0
    rdtype =  tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+6);
684
0
    nrdatas = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH+12);
685
0
    realnamelen = tvb_get_ntohs(tvb,LWRES_LWPACKET_LENGTH+16);
686
687
0
    offset = LWRES_LWPACKET_LENGTH + 18 + realnamelen + 1;
688
689
0
    if(lwres_tree == NULL)
690
0
        return;
691
692
0
    rdata_resp_tree = proto_tree_add_subtree(lwres_tree,tvb,LWRES_LWPACKET_LENGTH, 18+realnamelen+1,ett_rdata_resp,NULL,"RDATA response");
693
694
0
    proto_tree_add_item(rdata_resp_tree,
695
0
                        hf_rflags,
696
0
                        tvb,
697
0
                        LWRES_LWPACKET_LENGTH+0,
698
0
                        sizeof(uint32_t),
699
0
                        ENC_BIG_ENDIAN);
700
701
0
    proto_tree_add_item(rdata_resp_tree,
702
0
                        hf_rdclass,
703
0
                        tvb,
704
0
                        LWRES_LWPACKET_LENGTH+4,
705
0
                        sizeof(uint16_t),
706
0
                        ENC_BIG_ENDIAN);
707
708
0
    proto_tree_add_item(rdata_resp_tree,
709
0
                        hf_rdtype,
710
0
                        tvb,
711
0
                        LWRES_LWPACKET_LENGTH+6,
712
0
                        sizeof(uint16_t),
713
0
                        ENC_BIG_ENDIAN);
714
715
0
    proto_tree_add_item(rdata_resp_tree,
716
0
            hf_ttl,
717
0
            tvb,
718
0
            LWRES_LWPACKET_LENGTH+8,
719
0
            sizeof(uint32_t),
720
0
            ENC_BIG_ENDIAN);
721
722
0
    proto_tree_add_item(rdata_resp_tree,
723
0
            hf_nrdatas,
724
0
            tvb,
725
0
            LWRES_LWPACKET_LENGTH+12,
726
0
            sizeof(uint16_t),
727
0
            ENC_BIG_ENDIAN);
728
729
0
    proto_tree_add_item(rdata_resp_tree,
730
0
            hf_nsigs,
731
0
            tvb,
732
0
            LWRES_LWPACKET_LENGTH+14,
733
0
            sizeof(uint16_t),
734
0
            ENC_BIG_ENDIAN);
735
736
0
    proto_tree_add_item(rdata_resp_tree,
737
0
            hf_realnamelen,
738
0
            tvb,
739
0
            LWRES_LWPACKET_LENGTH+16,
740
0
            sizeof(uint16_t),
741
0
            ENC_BIG_ENDIAN);
742
743
0
    proto_tree_add_item(rdata_resp_tree,
744
0
                        hf_realname,
745
0
                        tvb,
746
0
                        LWRES_LWPACKET_LENGTH+18,
747
0
                        realnamelen,
748
0
                ENC_ASCII);
749
750
0
    switch(rdtype)
751
0
    {
752
0
        case T_A:
753
0
            dissect_a_records(tvb,pinfo,rdata_resp_tree,nrdatas,offset);
754
0
        break;
755
756
0
        case T_SRV:
757
0
            dissect_srv_records(tvb,pinfo,rdata_resp_tree,nrdatas, offset);
758
0
        break;
759
760
0
        case T_MX:
761
0
            dissect_mx_records(tvb,pinfo,rdata_resp_tree,nrdatas, offset);
762
0
        break;
763
764
0
        case T_NS:
765
0
            dissect_ns_records(tvb,pinfo,rdata_resp_tree,nrdatas, offset);
766
0
        break;
767
0
    }
768
769
0
}
770
771
static void dissect_noop(tvbuff_t* tvb, proto_tree* lwres_tree)
772
0
{
773
0
    uint16_t datalen;
774
775
0
    proto_tree* noop_tree;
776
777
0
    datalen = tvb_get_ntohs(tvb, LWRES_LWPACKET_LENGTH);
778
779
0
    if(lwres_tree == NULL)
780
0
        return;
781
782
0
    noop_tree = proto_tree_add_subtree(lwres_tree, tvb, LWRES_LWPACKET_LENGTH, 10, ett_noop, NULL, "Noop record");
783
784
0
    proto_tree_add_uint(noop_tree, hf_length, tvb,
785
0
                LWRES_LWPACKET_LENGTH, sizeof(uint16_t), datalen);
786
787
0
    tvb_ensure_bytes_exist(tvb, LWRES_LWPACKET_LENGTH, datalen);
788
789
0
}
790
791
static void dissect_getaddrsbyname(tvbuff_t* tvb, packet_info *pinfo, proto_tree* lwres_tree, int type)
792
0
{
793
0
    if(type == 1)
794
0
        dissect_getaddrsbyname_request(tvb, lwres_tree);
795
0
    else
796
0
        dissect_getaddrsbyname_response(tvb, pinfo, lwres_tree);
797
0
}
798
799
static void dissect_getnamebyaddr(tvbuff_t* tvb, packet_info *pinfo, proto_tree* lwres_tree, int type)
800
0
{
801
0
    if(type == 1)
802
0
        dissect_getnamebyaddr_request(tvb, pinfo, lwres_tree);
803
0
    else
804
0
        dissect_getnamebyaddr_response(tvb, pinfo, lwres_tree);
805
0
}
806
807
static void dissect_getrdatabyname(tvbuff_t* tvb, packet_info *pinfo _U_, proto_tree* lwres_tree, int type)
808
0
{
809
0
    if(type == 1)
810
0
        dissect_rdata_request(tvb, lwres_tree);
811
0
    else
812
0
        dissect_rdata_response(tvb, pinfo, lwres_tree);
813
0
}
814
815
static int
816
dissect_lwres(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
817
0
{
818
0
    uint16_t version, flags, authtype, authlength ;
819
0
    uint32_t length, opcode, result, recvlength, serial;
820
0
    uint32_t message_type;
821
822
0
    proto_item* lwres_item;
823
0
    proto_tree* lwres_tree;
824
825
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "lw_res");
826
0
    length = tvb_get_ntohl(tvb, LW_LENGTH_OFFSET);
827
0
    version = tvb_get_ntohs(tvb, LW_VERSION_OFFSET);
828
0
    flags = tvb_get_ntohs(tvb, LW_PKTFLASG_OFFSET);
829
0
    serial = tvb_get_ntohl(tvb, LW_SERIAL_OFFSET);
830
0
    opcode = tvb_get_ntohl(tvb,LW_OPCODE_OFFSET);
831
0
    result = tvb_get_ntohl(tvb, LW_RESULT_OFFSET);
832
0
    recvlength = tvb_get_ntohl(tvb, LW_RECVLEN_OFFSET);
833
0
    authtype = tvb_get_ntohs(tvb, LW_AUTHTYPE_OFFSET);
834
0
    authlength = tvb_get_ntohs(tvb, LW_AUTHLEN_OFFSET);
835
836
0
    message_type = (flags & LWRES_LWPACKETFLAG_RESPONSE) ? 2 : 1;
837
838
0
    if(flags & LWRES_LWPACKETFLAG_RESPONSE)
839
0
    {
840
0
        col_add_fstr(pinfo->cinfo, COL_INFO,
841
0
            "%s, opcode=%s, serial=0x%x, result=%s",
842
0
                val_to_str_const((uint32_t)message_type,message_types_values,"unknown"),
843
0
                val_to_str_const(opcode, opcode_values, "unknown"),
844
0
                serial,
845
0
                val_to_str_const(result,result_values,"unknown"));
846
0
    }
847
0
    else
848
0
    {
849
0
        col_add_fstr(pinfo->cinfo, COL_INFO,
850
0
                "%s, opcode=%s, serial=0x%x",
851
0
                val_to_str_const((uint32_t)message_type,message_types_values,"unknown"),
852
0
                val_to_str_const(opcode, opcode_values, "unknown"),
853
0
        serial);
854
0
    }
855
856
0
    if(tree == NULL)
857
0
        return tvb_captured_length(tvb);
858
859
0
    lwres_item = proto_tree_add_item(tree,proto_lwres, tvb,0, -1, ENC_NA);
860
0
    lwres_tree = proto_item_add_subtree(lwres_item, ett_lwres);
861
862
0
    proto_tree_add_uint(lwres_tree,
863
0
            hf_length,
864
0
            tvb,
865
0
            LW_LENGTH_OFFSET,
866
0
            sizeof(uint32_t),
867
0
            length);
868
869
870
0
    proto_tree_add_uint(lwres_tree,
871
0
                hf_version,
872
0
                tvb,
873
0
                LW_VERSION_OFFSET,
874
0
                sizeof(uint16_t),
875
0
                version);
876
877
878
879
880
0
    proto_tree_add_uint(lwres_tree,
881
0
                hf_flags,
882
0
                tvb,
883
0
                LW_PKTFLASG_OFFSET,
884
0
                sizeof(uint16_t),
885
0
                flags);
886
887
0
    proto_tree_add_uint(lwres_tree,
888
0
                hf_serial,
889
0
                tvb,
890
0
                LW_SERIAL_OFFSET,
891
0
                sizeof(uint32_t),
892
0
                serial);
893
894
0
    proto_tree_add_uint(lwres_tree,
895
0
                hf_opcode,
896
0
                tvb,
897
0
                LW_OPCODE_OFFSET,
898
0
                sizeof(uint32_t),
899
0
                opcode);
900
901
0
    proto_tree_add_uint(lwres_tree,
902
0
                hf_result,
903
0
                tvb,
904
0
                LW_RESULT_OFFSET,
905
0
                sizeof(uint32_t),
906
0
                result);
907
908
0
    proto_tree_add_uint(lwres_tree,
909
0
                hf_recvlen,
910
0
                tvb,
911
0
                LW_RECVLEN_OFFSET,
912
0
                sizeof(uint32_t),
913
0
                recvlength);
914
915
0
    proto_tree_add_uint(lwres_tree,
916
0
                hf_authtype,
917
0
                tvb,
918
0
                LW_AUTHTYPE_OFFSET,
919
0
                sizeof(uint16_t),
920
0
                authtype);
921
922
0
    proto_tree_add_uint(lwres_tree,
923
0
                hf_authlen,
924
0
                tvb,
925
0
                LW_AUTHLEN_OFFSET,
926
0
                sizeof(uint16_t),
927
0
                authlength);
928
929
0
    if(!result)
930
0
    {
931
0
        switch(opcode)
932
0
        {
933
0
            case LWRES_OPCODE_NOOP:
934
0
                dissect_noop(tvb, lwres_tree);
935
0
            break;
936
937
0
            case LWRES_OPCODE_GETADDRSBYNAME:
938
0
                dissect_getaddrsbyname(tvb, pinfo, lwres_tree, message_type);
939
0
            break;
940
941
0
            case LWRES_OPCODE_GETNAMEBYADDR:
942
0
                dissect_getnamebyaddr(tvb, pinfo, lwres_tree, message_type);
943
0
            break;
944
945
0
            case LWRES_OPCODE_GETRDATABYNAME:
946
0
                dissect_getrdatabyname(tvb, pinfo, lwres_tree, message_type);
947
0
            break;
948
0
        }
949
0
    }
950
0
    return tvb_captured_length(tvb);
951
0
}
952
953
954
void
955
proto_register_lwres(void)
956
15
{
957
15
    static hf_register_info hf[] = {
958
15
        { &hf_length,
959
15
          { "Length", "lwres.length", FT_UINT32, BASE_DEC, NULL, 0x0,
960
15
            "lwres length", HFILL }},
961
962
15
        { &hf_version,
963
15
          { "Version", "lwres.version", FT_UINT16, BASE_DEC, NULL, 0x0,
964
15
            "lwres version", HFILL }},
965
966
15
        { &hf_flags,
967
15
          { "Packet Flags", "lwres.flags", FT_UINT16, BASE_HEX, NULL, 0x0,
968
15
            "lwres flags", HFILL }},
969
970
15
        { &hf_serial,
971
15
          { "Serial", "lwres.serial", FT_UINT32, BASE_HEX, NULL, 0x0,
972
15
            "lwres serial", HFILL }},
973
974
15
        { &hf_opcode,
975
15
          { "Operation code", "lwres.opcode", FT_UINT32, BASE_DEC, VALS(opcode_values), 0x0,
976
15
            "lwres opcode", HFILL }},
977
978
15
        { &hf_result,
979
15
          { "Result", "lwres.result", FT_UINT32, BASE_DEC, VALS(result_values), 0x0,
980
15
            "lwres result", HFILL }},
981
982
15
        { &hf_recvlen,
983
15
          { "Received length", "lwres.recvlen", FT_UINT32, BASE_DEC, NULL, 0x0,
984
15
            "lwres recvlen", HFILL }},
985
986
15
        { &hf_authtype,
987
15
          { "Auth. type", "lwres.authtype", FT_UINT16, BASE_DEC, NULL, 0x0,
988
15
            "lwres authtype", HFILL }},
989
990
15
        { &hf_authlen,
991
15
          { "Auth. length", "lwres.authlen", FT_UINT16, BASE_DEC, NULL, 0x0,
992
15
            "lwres authlen", HFILL }},
993
994
15
        { &hf_rflags,
995
15
          { "Flags", "lwres.rflags", FT_UINT32, BASE_HEX, NULL, 0x0,
996
15
            "lwres rflags", HFILL }},
997
15
        { &hf_rdclass,
998
15
          { "Class", "lwres.class", FT_UINT16, BASE_DEC, NULL, 0x0,
999
15
            "lwres class", HFILL }},
1000
1001
15
        { &hf_rdtype,
1002
15
          { "Type", "lwres.type", FT_UINT16, BASE_DEC, VALS(t_types), 0x0,
1003
15
            "lwres type", HFILL }},
1004
1005
15
        { &hf_namelen,
1006
15
          { "Name length", "lwres.namelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1007
15
            "lwres namelen", HFILL }},
1008
1009
15
        { &hf_req_name,
1010
15
          { "Domain name", "lwres.reqdname", FT_STRING, BASE_NONE, NULL, 0x0,
1011
15
            "lwres reqdname", HFILL }},
1012
1013
15
        { &hf_ttl,
1014
15
          { "Time To Live", "lwres.ttl", FT_UINT32, BASE_DEC, NULL, 0x0,
1015
15
            "lwres ttl", HFILL }},
1016
1017
15
        { &hf_nrdatas,
1018
15
          { "Number of rdata records", "lwres.nrdatas", FT_UINT16, BASE_DEC, NULL, 0x0,
1019
15
            "lwres nrdatas", HFILL }},
1020
1021
15
        { &hf_nsigs,
1022
15
          { "Number of signature records", "lwres.nsigs", FT_UINT16, BASE_DEC, NULL, 0x0,
1023
15
            "lwres nsigs", HFILL }},
1024
1025
15
        { &hf_realnamelen,
1026
15
          { "Real name length", "lwres.realnamelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1027
15
            "lwres realnamelen", HFILL }},
1028
1029
15
        { &hf_realname,
1030
15
          { "Real doname name", "lwres.realname", FT_STRING, BASE_NONE, NULL, 0x0,
1031
15
            "lwres realname", HFILL }},
1032
1033
15
        { &hf_a_record,
1034
15
          { "IPv4 Address", "lwres.arecord", FT_UINT32, BASE_DEC, NULL, 0x0,
1035
15
            "lwres arecord", HFILL }},
1036
1037
15
        { &hf_a_rec_len,
1038
15
          { "Length", "lwres.areclen", FT_UINT16, BASE_DEC, NULL, 0x0,
1039
15
            "lwres areclen", HFILL }},
1040
1041
15
        { &hf_srv_prio,
1042
15
          { "Priority", "lwres.srv.priority", FT_UINT16, BASE_DEC, NULL, 0x0,
1043
15
            "lwres srv prio", HFILL }},
1044
1045
15
        { &hf_srv_weight,
1046
15
          { "Weight", "lwres.srv.weight", FT_UINT16, BASE_DEC, NULL, 0x0,
1047
15
            "lwres srv weight", HFILL }},
1048
1049
15
        { &hf_srv_port,
1050
15
          { "Port", "lwres.srv.port", FT_UINT16, BASE_DEC, NULL, 0x0,
1051
15
            "lwres srv port", HFILL }},
1052
1053
15
        { &hf_srv_dname,
1054
15
          { "DNAME", "lwres.srv.dname", FT_STRING, BASE_NONE, NULL, 0x0,
1055
15
            NULL, HFILL }},
1056
1057
15
        { &hf_adn_flags,
1058
15
          { "Flags", "lwres.adn.flags", FT_UINT32, BASE_HEX, NULL, 0x0,
1059
15
            "lwres adn flags", HFILL }},
1060
1061
15
        { &hf_adn_addrtype,
1062
15
          { "Address type", "lwres.adn.addrtype", FT_UINT32, BASE_DEC, NULL, 0x0,
1063
15
            "lwres adn addrtype", HFILL }},
1064
1065
15
        { &hf_adn_namelen,
1066
15
          { "Name length", "lwres.adn.namelen", FT_UINT16, BASE_DEC, NULL, 0x0,
1067
15
            "lwres adn namelen", HFILL }},
1068
1069
15
        { &hf_adn_name,
1070
15
          { "Name", "lwres.adn.name", FT_STRING, BASE_NONE, NULL, 0x0,
1071
15
            "lwres adn name", HFILL }},
1072
1073
15
        { &hf_adn_naliases,
1074
15
          { "Number of aliases", "lwres.adn.naliases", FT_UINT16, BASE_DEC, NULL, 0x0,
1075
15
            "lwres adn naliases", HFILL }},
1076
1077
15
        { &hf_adn_naddrs,
1078
15
          { "Number of addresses", "lwres.adn.naddrs", FT_UINT16, BASE_DEC, NULL, 0x0,
1079
15
            "lwres adn naddrs", HFILL }},
1080
1081
15
        { &hf_adn_realname,
1082
15
          { "Real name", "lwres.adn.realname", FT_STRING, BASE_NONE, NULL, 0x0,
1083
15
            "lwres adn realname", HFILL }},
1084
1085
15
        { &hf_adn_aliasname,
1086
15
          { "Alias name", "lwres.adn.aliasname", FT_STRING, BASE_NONE, NULL, 0x0,
1087
15
            "lwres adn aliasname", HFILL }},
1088
1089
15
        { &hf_adn_family,
1090
15
          { "Address family", "lwres.adn.addr.family", FT_UINT32, BASE_DEC, NULL, 0x0,
1091
15
            "lwres adn addr family", HFILL }},
1092
1093
15
        { &hf_adn_addr_len,
1094
15
          { "Address length", "lwres.adn.addr.length", FT_UINT16, BASE_DEC, NULL, 0x0,
1095
15
            "lwres adn addr length", HFILL }},
1096
1097
15
        { &hf_adn_addr_addr,
1098
15
          { "IP Address", "lwres.adn.addr.addr", FT_STRING, BASE_NONE, NULL, 0x0,
1099
15
            "lwres adn addr addr", HFILL }},
1100
1101
15
        { &hf_ns_dname,
1102
15
          { "Name", "lwres.ns.dname", FT_STRING, BASE_NONE, NULL, 0x0,
1103
15
            NULL, HFILL }},
1104
1105
        /* Add more fields here */
1106
15
    };
1107
1108
15
    static int *ett[] = {
1109
15
        &ett_lwres,
1110
15
        &ett_rdata_req,
1111
15
        &ett_rdata_resp,
1112
15
        &ett_a_rec,
1113
15
        &ett_a_rec_addr,
1114
15
        &ett_srv_rec,
1115
15
        &ett_srv_rec_item,
1116
15
        &ett_adn_request,
1117
15
        &ett_adn_resp,
1118
15
        &ett_adn_alias,
1119
15
        &ett_adn_addr,
1120
15
        &ett_nba_request,
1121
15
        &ett_nba_resp,
1122
15
        &ett_mx_rec,
1123
15
        &ett_mx_rec_item,
1124
15
        &ett_ns_rec,
1125
15
        &ett_ns_rec_item,
1126
15
        &ett_noop,
1127
15
    };
1128
1129
15
    proto_lwres = proto_register_protocol("Light Weight DNS RESolver (BIND9)", "LWRES", "lwres");
1130
1131
15
    proto_register_field_array(proto_lwres, hf, array_length(hf));
1132
15
    proto_register_subtree_array(ett, array_length(ett));
1133
1134
15
    lwres_handle = register_dissector("lwres", dissect_lwres, proto_lwres);
1135
15
}
1136
1137
/* The registration hand-off routine */
1138
void
1139
proto_reg_handoff_lwres(void)
1140
15
{
1141
15
    dissector_add_for_decode_as_with_preference("udp.port", lwres_handle);
1142
15
}
1143
1144
/*
1145
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1146
 *
1147
 * Local variables:
1148
 * c-basic-offset: 4
1149
 * tab-width: 8
1150
 * indent-tabs-mode: nil
1151
 * End:
1152
 *
1153
 * vi: set shiftwidth=4 tabstop=8 expandtab:
1154
 * :indentSize=4:tabSize=8:noTabs=true:
1155
 */