Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-dcc.c
Line
Count
Source
1
/* packet-dcc.c
2
 * Routines for Distributed Checksum Clearinghouse packet dissection
3
 * DCC Home: http://www.rhyolite.com/anti-spam/dcc/
4
 *
5
 * Copyright 1999, Nathan Neulinger <nneul@umr.edu>
6
 *
7
 * Wireshark - Network traffic analyzer
8
 * By Gerald Combs <gerald@wireshark.org>
9
 * Copyright 1998 Gerald Combs
10
 *
11
 * Copied from packet-tftp.c
12
 *
13
 * SPDX-License-Identifier: GPL-2.0-or-later
14
 */
15
16
#include "config.h"
17
18
#include <epan/packet.h>
19
#include "packet-udp.h"
20
21
void proto_register_dcc(void);
22
void proto_reg_handoff_dcc(void);
23
24
static int proto_dcc;
25
static int hf_dcc_len;
26
static int hf_dcc_pkt_vers;
27
static int hf_dcc_op;
28
static int hf_dcc_clientid;
29
static int hf_dcc_opnums_host;
30
static int hf_dcc_opnums_pid;
31
static int hf_dcc_opnums_report;
32
static int hf_dcc_opnums_retrans;
33
34
static int hf_dcc_signature;
35
static int hf_dcc_max_pkt_vers;
36
static int hf_dcc_qdelay_ms;
37
static int hf_dcc_brand;
38
39
static int hf_dcc_ck_type;
40
static int hf_dcc_ck_len;
41
static int hf_dcc_ck_sum;
42
43
static int hf_dcc_date;
44
45
static int hf_dcc_target;
46
static int hf_dcc_response_text;
47
48
static int hf_dcc_adminop;
49
static int hf_dcc_adminval;
50
static int hf_dcc_floodop;
51
static int hf_dcc_trace;
52
static int hf_dcc_trace_admin;
53
static int hf_dcc_trace_anon;
54
static int hf_dcc_trace_client;
55
static int hf_dcc_trace_rlim;
56
static int hf_dcc_trace_query;
57
static int hf_dcc_trace_ridc;
58
static int hf_dcc_trace_flood;
59
60
static int hf_dcc_addr;
61
static int hf_dcc_id;
62
static int hf_dcc_last_used;
63
static int hf_dcc_requests;
64
static int hf_dcc_pad;
65
static int hf_dcc_unused;
66
67
static int ett_dcc;
68
static int ett_dcc_opnums;
69
static int ett_dcc_op;
70
static int ett_dcc_ck;
71
static int ett_dcc_trace;
72
73
74
/* Inserted below is dcc_proto.h from the dcc source distribution, with the
75
  following changes made:
76
77
:%s/u_in*t16_t/uint16_t/g
78
:%s/u_in*t32_t/uint32_t/g
79
:%s/u_ch*ar/unsigned char/g
80
:%s/in*t32_t/int32_t/g
81
82
This includes more than is really necessary, but easier to just include whole
83
header.
84
85
*/
86
87
88
/* Distributed Checksum Clearinghouse protocol
89
 *
90
 * Copyright (c) 2002 by Rhyolite Software
91
 *
92
 * SPDX-License-Identifier: ISC
93
 *
94
 * Rhyolite Software DCC 1.0.53-1.45 $Revision: 1.3 $
95
 */
96
97
#ifndef DCC_PROTO_H
98
#define DCC_PROTO_H
99
100
101
39
#define DCC_PORT    6277    /* default UDP port #, MAPS in DTMF */
102
103
104
/* No client's retransmission can be delayed by more than this
105
 * This matters for how long a DCC server must remember old requests
106
 * to recognize retransmissions */
107
#define DCC_MAX_DELAY_SEC   30
108
109
typedef uint16_t DCC_MS;
110
111
/* anonymous client delay */
112
#define DCC_MAX_QDELAY_MS   (DCC_MAX_DELAY_SEC*1000)
113
#define DCC_DEF_QDELAY_MS   0
114
115
116
/* types of checksums */
117
typedef enum {
118
    DCC_CK_INVALID  =0,     /* deleted from database when seen */
119
    DCC_CK_IP     =1,     /* MD5 of binary source IPv6 address */
120
    DCC_CK_ENV_FROM =2,     /*  "  "  envelope Mail From value */
121
    DCC_CK_FROM     =3,     /*  "  "  header From: line */
122
    DCC_CK_SUB      =4,     /*  "  "  substitute header line */
123
    DCC_CK_MESSAGE_ID=5,    /*  "  "  header Message-ID: line */
124
    DCC_CK_RECEIVED =6,     /*  "  "  last header Received: line */
125
    DCC_CK_BODY     =7,     /*  "  "  body */
126
    DCC_CK_FUZ1     =8,     /*  "  "  filtered body */
127
    DCC_CK_FUZ2     =9,     /*  "  "     "      "   */
128
    DCC_CK_FUZ3     =10,    /*  "  "     "      "   */
129
    DCC_CK_FUZ4     =11,    /*  "  "     "      "   */
130
    DCC_CK_SRVR_ID  =12,    /* hostname for server-ID check */
131
    DCC_CK_ENV_TO   =13     /* MD5 of envelope Rcpt To value */
132
#   define DCC_CK_FLOD_PATH DCC_CK_ENV_TO   /* flooding path in server-IDs */
133
} DCC_CK_TYPES;
134
#define DCC_CK_TYPE_FIRST   DCC_CK_IP
135
50
#define DCC_CK_TYPE_LAST    DCC_CK_ENV_TO
136
#define DCC_NUM_CKS     DCC_CK_TYPE_LAST    /* # of valid types */
137
138
/* DCC_DIM_CKS dimensions arrays of checksum types including DCC_CK_INVALID
139
 * Beware that DCC_DIM_CKS is used in the database header. */
140
100
#define DCC_DIM_CKS     (DCC_CK_TYPE_LAST+1)
141
142
/* Ensure that arrays of DCC_CKs contain an even number so that structures
143
 * containing them will have no extra structure packing */
144
#define DCC_COMP_DIM_CKS    ((((DCC_NUM_CKS+1)+1)/2)*2) /* == DCC_DIM_CKS */
145
146
/* keep in the database longer than others */
147
#define DCC_CK_LONG_TERM(t) ((t) >= DCC_CK_FUZ1 && (t) <= DCC_CK_FUZ4)
148
149
#define DCC_CK_IS_BODY(t) ((t) >= DCC_CK_BODY && (t) <= DCC_CK_FUZ4)
150
151
/* ok for users to talk about */
152
#define DCC_CK_OK_USER(t) ((t) > DCC_CK_INVALID && (t) <= DCC_CK_FUZ4)
153
/* ok in the database */
154
#define DCC_CK_OK_DB(t) ((t) > DCC_CK_INVALID && (t) <= DCC_CK_TYPE_LAST)
155
#define DCC_CK_OK_PROTO(t) DCC_CK_OK_USER(t)  /* ok from clients */
156
#define DCC_CK_OK_FLOD(t) DCC_CK_OK_DB(t)   /* ok in floods */
157
158
typedef unsigned char DCC_CK_TYPE;
159
160
161
typedef enum {
162
    DCC_OP_INVALID=0,
163
    DCC_OP_NOP,       /* see if the server is alive */
164
    DCC_OP_REPORT,      /* client reporting and querying */
165
    DCC_OP_QUERY,     /* client querying */
166
    DCC_OP_QUERY_RESP,      /* server responding */
167
    DCC_OP_ADMN,      /* local control of the server */
168
    DCC_OP_OK,        /* administrative operation ok */
169
    DCC_OP_ERROR,     /* server failing or complaining */
170
    DCC_OP_DELETE     /* delete some checksums */
171
} DCC_OPS;
172
173
typedef uint32_t DCC_CLNT_ID;
174
#define DCC_ID_INVALID      0
175
#define DCC_ID_ANON     1   /* anonymous (non-paying) client */
176
#define DCC_ID_WHITE      2   /* white-listed */
177
#define DCC_ID_COMP     3   /* compressed */
178
#define DCC_SRVR_ID_MIN     100   /* below reserved for special uses */
179
#define DCC_SRVR_ID_MAX     32767 /* below are servers--must be 2**n-1 */
180
#define DCC_CLNT_ID_MIN     (DCC_SRVR_ID_MAX+1)
181
#define DCC_CLNT_ID_MAX     16777215
182
typedef uint16_t DCC_SRVR_ID;
183
#define DCC_SRVR_ID_AUTH (DCC_SRVR_ID_MAX+1)  /* client was authenticated */
184
185
/* client's identification of its transaction */
186
typedef struct {
187
    uint32_t  h;      /* client host ID, e.g. IP address */
188
    uint32_t  p;      /* process ID, serial #, timestamp */
189
    uint32_t  r;      /* report ID */
190
    uint32_t  t;      /* client (re)transmission # */
191
} DCC_OP_NUMS;
192
193
/* The inter-DCC server flooding algorithm depends on unique-per-server
194
 * timestamps to detect duplicates.  That imposes a requirement on
195
 * timestamps that they have resolution enough to separate reports
196
 * from clients arriving at any single server.
197
 * The timestamps are 48 bits consisting of 17 bits of 8's of microseconds
198
 * and 31 bits of seconds.  That's sufficient for the UNIX epoch.
199
 * If the DCC is still around in the 2030's (and in the unlikely case that
200
 * 8 microseconds are still fine enough), we can make the 31 bits be
201
 * an offset in a bigger window.
202
 */
203
#define DCC_TS_USEC_RSHIFT  3
204
#define DCC_TS_USEC_MULT    (1<<DCC_TS_USEC_RSHIFT)
205
#define DCC_TS_SEC_LSHIFT   17
206
#define DCC_TS_USEC_MASK    ((1<<DCC_TS_SEC_LSHIFT) - 1)
207
typedef unsigned char DCC_TS[6];
208
209
/* The start of any DCC packet.
210
 *  The length and version are early, since they are they only fields
211
 *  that are constrained in future versions. */
212
typedef struct {
213
    uint16_t  len;      /* total DCC packet length (for TCP) */
214
    unsigned char pkt_vers;   /* packet protocol version */
215
#    define  DCC_PKT_VERSION  4
216
#    define  DCC_PKT_VERSION_MIN  DCC_PKT_VERSION
217
#    define  DCC_PKT_VERSION_MAX    DCC_PKT_VERSION
218
    unsigned char op;     /* one of DCC_OPS */
219
    /* Identify the transaction.
220
     *      Each client can have many hosts, each host can be multi-homed,
221
     *      and each host can be running many processes talking to the
222
     *      server.  Each packet needs to be uniquely numbered, so that the
223
     *      server can recognize as interchangeable all of the (re)transmissions
224
     *      of a single report (rid) from a client process (pid) on a single
225
     *      host (hid), and the client can know which transmission (tid)
226
     *      produced a given server response to maintain the client's RTT
227
     *      value for the server. */
228
    DCC_CLNT_ID sender;     /* official DCC client-ID */
229
    DCC_OP_NUMS op_nums;    /* op_num.t must be last */
230
} DCC_HDR;
231
232
typedef unsigned char DCC_SIGNATURE[16];
233
234
typedef struct {
235
    DCC_HDR hdr;
236
    DCC_SIGNATURE signature;
237
} DCC_NOP;
238
239
240
/* administrative requests from localhost
241
 *  These can be freely changed, because the administrative tools
242
 *  should match the daemon. */
243
typedef enum {
244
    DCC_AOP_OK=-1,      /* never really sent */
245
    DCC_AOP_STOP=1,     /* stop gracefully */
246
    DCC_AOP_NEW_IDS,      /* load keys and client-IDs */
247
    DCC_AOP_FLOD,     /* start or stop flooding */
248
    DCC_AOP_DB_UNLOCK,      /* start switch to new database */
249
    DCC_AOP_DB_NEW,     /* finish switch to new database */
250
    DCC_AOP_STATS,      /* return counters--val=buffer size */
251
    DCC_AOP_STATS_CLEAR,    /* return and zero counters */
252
    DCC_AOP_TRACE_ON,
253
    DCC_AOP_TRACE_OFF,
254
    DCC_AOP_CUR_CLIENTS     /* some client IP addresses */
255
} DCC_AOPS;
256
257
/* for DCC_AOP_FLOD */
258
typedef enum {
259
    DCC_AOP_FLOD_CHECK=0,
260
    DCC_AOP_FLOD_SHUTDOWN,
261
    DCC_AOP_FLOD_HALT,
262
    DCC_AOP_FLOD_RESUME,
263
    DCC_AOP_FLOD_REWIND,
264
    DCC_AOP_FLOD_LIST,
265
    DCC_AOP_FLOD_STATS,
266
    DCC_AOP_FLOD_STATS_CLEAR
267
} DCC_AOP_FLODS;
268
269
typedef struct {      /* with operation DCC_OP_ADMN */
270
    DCC_HDR hdr;
271
    int32_t date;     /* seconds since epoch on caller */
272
    uint32_t  val;      /* request type, buffer size, etc. */
273
    unsigned char aop;      /* one of DCC_AOPS */
274
    unsigned char pad[3];
275
    DCC_SIGNATURE signature;
276
} DCC_ADMN_REQ;
277
278
/* noisy response to some DCC_AOPS with operation DCC_OP_ADMN */
279
typedef struct {
280
    unsigned char addr[16];
281
    DCC_CLNT_ID id;
282
    uint32_t  last_used;
283
    uint32_t  requests;
284
} DCC_ADMN_RESP_CLIENTS;
285
typedef union {
286
    char  string[80*22];
287
    DCC_ADMN_RESP_CLIENTS clients[1];
288
} DCC_ADMN_RESP_VAL;
289
typedef struct {
290
    DCC_HDR hdr;
291
    DCC_ADMN_RESP_VAL val;
292
    DCC_SIGNATURE signature;
293
} DCC_ADMN_RESP;
294
295
296
#define DCC_TRACE_ADMN_BIT  0x0001  /* administrative requests */
297
#define DCC_TRACE_ANON_BIT  0x0002  /* anonymous client errors */
298
#define DCC_TRACE_CLNT_BIT  0x0004  /* authenticated client errors */
299
#define DCC_TRACE_RLIM_BIT  0x0008  /* rate limited messages */
300
#define DCC_TRACE_QUERY_BIT 0x0010  /* all queries and reports */
301
#define DCC_TRACE_RIDC_BIT  0x0020  /* RID cache messages */
302
#define DCC_TRACE_FLOD_BIT  0x0040  /* input and output flooding */
303
/* INFO must always be on */
304
#define DCC_TRACE_ALL_BITS  (DCC_TRACE_ADMN_BIT | DCC_TRACE_ANON_BIT  \
305
           | DCC_TRACE_CLNT_BIT | DCC_TRACE_RLIM_BIT  \
306
           | DCC_TRACE_QUERY_BIT | DCC_TRACE_RIDC_BIT \
307
           | DCC_TRACE_FLOD_BIT)
308
309
310
typedef char DCC_BRAND[64];
311
312
/* administrative or NOP ok */
313
typedef struct {
314
    DCC_HDR hdr;
315
    unsigned char max_pkt_vers;   /* can handle this version */
316
    unsigned char unused;
317
    DCC_MS  qdelay_ms;
318
    DCC_BRAND brand;      /* identity or brandname of sender */
319
    DCC_SIGNATURE signature;
320
} DCC_OK;
321
322
323
/* a reported checksum from a client */
324
typedef unsigned char DCC_SUM[16];    /* for now all have 16 bytes */
325
typedef struct {
326
    DCC_CK_TYPE type;
327
    unsigned char len;      /* total length of this checksum */
328
    DCC_SUM sum;
329
} DCC_CK;
330
331
typedef uint32_t DCC_TGTS;    /* database is limited to 24 bits */
332
#define DCC_TGTS_TOO_MANY   0x00fffff0  /* >= 16777200 targets */
333
#define DCC_TGTS_OK     0x00fffff1  /* certified not spam */
334
#define DCC_TGTS_OK2      0x00fffff2  /* half certified not spam */
335
#define DCC_TGTS_DEL      0x00fffff3  /* a deleted checksum */
336
#define DCC_TGTS_INVALID    0x01000000
337
338
/* query or query/report packet from client to server */
339
typedef struct {
340
    DCC_HDR hdr;
341
    DCC_TGTS  tgts;     /* # of addressees */
342
50
#    define  DCC_QUERY_MAX DCC_DIM_CKS
343
    DCC_CK  cks[DCC_QUERY_MAX]; /* even to prevent structure padding */
344
    DCC_SIGNATURE signature;
345
} DCC_QUERY_REPORT;
346
347
348
typedef struct {
349
    DCC_TGTS  tgts[DCC_QUERY_MAX];  /* individual answers */
350
} DCC_QUERY_RESP_BODY;
351
352
/* response to a query or query/report */
353
typedef struct {
354
    DCC_HDR hdr;
355
    DCC_QUERY_RESP_BODY body;
356
    DCC_SIGNATURE signature;
357
} DCC_QUERY_RESP;
358
359
360
/* DCC_OP_DELETE request to delete checksums */
361
typedef struct {
362
    DCC_HDR hdr;
363
    int32_t date;     /* seconds since epoch on caller */
364
    DCC_CK  ck;
365
    unsigned char pad[2];     /* structure padding */
366
    DCC_SIGNATURE signature;
367
} DCC_DELETE;
368
369
370
/* error response from server to client */
371
typedef struct {
372
    DCC_HDR hdr;
373
#    define  DCC_ERROR_MSG_LEN  128
374
    char  msg[DCC_ERROR_MSG_LEN];
375
    DCC_SIGNATURE signature;
376
} DCC_ERROR;
377
378
379
/* sender's position or serial number
380
 *  Only the sender understands sender positions except for these
381
 *  special values.  However, the special values imply that the position
382
 *  must be big endian. */
383
typedef unsigned char DCC_FLOD_POS[8];
384
/* special cases sent by the receiver back to the sender */
385
#define DCC_FLOD_POS_END  0 /* receiver closing with message */
386
#define DCC_FLOD_POS_END_REQ  1 /* receiver wants to stop */
387
#define DCC_FLOD_POS_NOTE 2 /* receiver has a tracing message */
388
#define DCC_FLOD_POS_COMPLAINT  3 /* receiver has a problem message */
389
#define DCC_FLOD_POS_REWIND 4 /* receiver's database emptied */
390
#define DCC_FLOD_POS_MIN  10
391
392
#define DCC_FLOD_OK_STR     "DCC flod ok: "
393
#define DCC_FLOD_MAX_RESP   200
394
395
/* report forwarded among servers */
396
typedef struct {
397
    DCC_FLOD_POS pos;
398
    unsigned char tgts[sizeof(DCC_TGTS)];
399
    unsigned char srvr_id_auth[sizeof(DCC_SRVR_ID)];  /* receiving server */
400
    DCC_TS  ts;     /* date reported */
401
    unsigned char num_cks;
402
    DCC_CK  cks[DCC_QUERY_MAX];
403
} DCC_FLOD;
404
405
/* record of path taken by a report */
406
#define DCC_NUM_FLOD_PATH ((int)(sizeof(DCC_SUM)/sizeof(DCC_SRVR_ID)))
407
typedef struct {
408
    unsigned char hi, lo;
409
} DCC_FLOD_PATH_ID;
410
411
typedef struct {
412
    DCC_FLOD_POS z;
413
    char    msg[DCC_FLOD_MAX_RESP];
414
    char    null;
415
} FLOD_END;
416
typedef struct {
417
    DCC_FLOD_POS    op;
418
    unsigned char     len;
419
    char      str[DCC_FLOD_MAX_RESP];
420
} FLOD_NOTE;
421
#define FLOD_NOTE_OVHD ((int)sizeof(FLOD_NOTE)-DCC_FLOD_MAX_RESP)
422
423
#define DCC_FLOD_VERSION_STR_BASE   "DCC flod version "
424
#define DCC_FLOD_VERSION5_STR     DCC_FLOD_VERSION_STR_BASE"5"
425
#define DCC_FLOD_VERSION5     5
426
#define DCC_FLOD_VERSION6_STR     DCC_FLOD_VERSION_STR_BASE"6"
427
#define DCC_FLOD_VERSION6     6
428
#define DCC_FLOD_VERSION7_STR     DCC_FLOD_VERSION_STR_BASE"7"
429
#define DCC_FLOD_VERSION7     7
430
#define DCC_FLOD_VERSION_DEF      0
431
#define DCC_FLOD_VERSION_CUR_STR    DCC_FLOD_VERSION7_STR
432
#define DCC_FLOD_VERSION_CUR      DCC_FLOD_VERSION7
433
typedef struct {
434
#    define DCC_FLOD_VERSION_STR_LEN 64
435
    char  str[DCC_FLOD_VERSION_STR_LEN];
436
    DCC_SRVR_ID sender_srvr_id;
437
    unsigned char turn;
438
    unsigned char unused[3];
439
} DCC_FLOD_VERSION_BODY;
440
typedef struct {
441
    DCC_FLOD_VERSION_BODY body;
442
    char  pad[256-sizeof(DCC_FLOD_VERSION_BODY)-sizeof(DCC_SIGNATURE)];
443
    DCC_SIGNATURE signature;
444
} DCC_FLOD_VERSION_HDR;
445
446
447
#endif /* DCC_PROTO_H */
448
449
450
451
452
453
454
455
456
/* Lookup string tables */
457
static const value_string dcc_op_vals[] = {
458
  {DCC_OP_INVALID,    "Invalid Op"},
459
  {DCC_OP_NOP,      "No-Op"},
460
  {DCC_OP_REPORT,     "Report and Query"},
461
  {DCC_OP_QUERY,      "Query"},
462
  {DCC_OP_QUERY_RESP, "Server Response"},
463
  {DCC_OP_ADMN,     "Admin"},
464
  {DCC_OP_OK,     "Ok"},
465
  {DCC_OP_ERROR,      "Server Failing"},
466
  {DCC_OP_DELETE,     "Delete Checksum(s)"},
467
  {0, NULL}
468
};
469
470
static const value_string dcc_cktype_vals[] = {
471
  {DCC_CK_INVALID,    "Invalid/Deleted from DB when seen"},
472
  {DCC_CK_IP,     "MD5 of binary source IPv6 address"},
473
  {DCC_CK_ENV_FROM,   "MD5 of envelope Mail From value"},
474
  {DCC_CK_FROM,     "MD5 of header From: line"},
475
  {DCC_CK_SUB,      "MD5 of substitute header line"},
476
  {DCC_CK_MESSAGE_ID, "MD5 of header Message-ID: line"},
477
  {DCC_CK_RECEIVED,   "MD5 of last header Received: line"},
478
  {DCC_CK_BODY,     "MD5 of body"},
479
  {DCC_CK_FUZ1,     "MD5 of filtered body - FUZ1"},
480
  {DCC_CK_FUZ2,     "MD5 of filtered body - FUZ2"},
481
  {DCC_CK_FUZ3,     "MD5 of filtered body - FUZ3"},
482
  {DCC_CK_FUZ4,     "MD5 of filtered body - FUZ4"},
483
  {DCC_CK_SRVR_ID,    "hostname for server-ID check "},
484
  {DCC_CK_ENV_TO,     "MD5 of envelope Rcpt To value"},
485
  {0, NULL},
486
};
487
488
static const value_string dcc_adminop_vals[] = {
489
  {DCC_AOP_OK,        "Never sent"},
490
  {DCC_AOP_STOP,        "Stop Gracefully"},
491
  {DCC_AOP_NEW_IDS,     "Load keys and client IDs"},
492
  {DCC_AOP_FLOD,        "Flood control"},
493
  {DCC_AOP_DB_UNLOCK,   "Start Switch to new database"},
494
  {DCC_AOP_DB_NEW,      "Finish Switch to new database"},
495
  {DCC_AOP_STATS,       "Return counters"},
496
  {DCC_AOP_STATS_CLEAR, "Return and zero counters"},
497
  {DCC_AOP_TRACE_ON,    "Enable tracing"},
498
  {DCC_AOP_TRACE_OFF,   "Disable tracing"},
499
  {DCC_AOP_CUR_CLIENTS, "List clients"},
500
  {0, NULL},
501
};
502
503
static const value_string dcc_target_vals[] = {
504
  {DCC_TGTS_TOO_MANY, "Targets (>= 16777200)"},
505
  {DCC_TGTS_OK,     "Certified not spam"},
506
  {DCC_TGTS_OK2,      "Half certified not spam"},
507
  {DCC_TGTS_DEL,      "Deleted checksum"},
508
  {DCC_TGTS_INVALID,  "Invalid"},
509
  {0, NULL},
510
};
511
512
static const value_string dcc_floodop_vals[] = {
513
  {DCC_AOP_FLOD_CHECK,     "Check"},
514
  {DCC_AOP_FLOD_SHUTDOWN,    "Shutdown"},
515
  {DCC_AOP_FLOD_HALT,    "Halt"},
516
  {DCC_AOP_FLOD_RESUME,    "Resume"},
517
  {DCC_AOP_FLOD_REWIND,    "Rewind"},
518
  {DCC_AOP_FLOD_LIST,    "List"},
519
  {DCC_AOP_FLOD_STATS,     "Stats"},
520
  {DCC_AOP_FLOD_STATS_CLEAR, "Clear Stats"},
521
  {0,NULL},
522
};
523
524
static int* const trace_flags[] = {
525
    &hf_dcc_trace_admin,
526
    &hf_dcc_trace_anon,
527
    &hf_dcc_trace_client,
528
    &hf_dcc_trace_rlim,
529
    &hf_dcc_trace_query,
530
    &hf_dcc_trace_ridc,
531
    &hf_dcc_trace_flood,
532
    NULL
533
};
534
535
static int
536
dissect_dcc_pdu(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
537
23
{
538
23
  proto_tree *dcc_tree, *dcc_optree, *dcc_opnumtree, *ti;
539
23
  uint32_t packet_length, op;
540
23
  unsigned offset = 0;
541
23
  int client_is_le = 0;
542
23
  int i;
543
23
  bool is_response = (pinfo->srcport == DCC_PORT);
544
545
23
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCC");
546
547
23
  col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
548
23
    is_response ? "Response" : "Request",
549
23
    val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset+3),
550
23
       dcc_op_vals, "Unknown Op: %u"));
551
552
23
  ti = proto_tree_add_item(tree, proto_dcc, tvb, offset, -1, ENC_NA);
553
23
  dcc_tree = proto_item_add_subtree(ti, ett_dcc);
554
555
23
  proto_tree_add_item_ret_uint(dcc_tree, hf_dcc_len, tvb, offset, 2, ENC_BIG_ENDIAN, &packet_length);
556
23
  offset += 2;
557
558
23
  proto_tree_add_item(dcc_tree, hf_dcc_pkt_vers, tvb, offset, 1, ENC_BIG_ENDIAN);
559
23
  offset += 1;
560
561
23
  proto_tree_add_item_ret_uint(dcc_tree, hf_dcc_op, tvb, offset, 1, ENC_BIG_ENDIAN, &op);
562
23
  offset += 1;
563
564
23
  proto_tree_add_item(dcc_tree, hf_dcc_clientid, tvb, offset, 4, ENC_BIG_ENDIAN);
565
23
  offset += 4;
566
567
23
  dcc_opnumtree = proto_tree_add_subtree(dcc_tree, tvb, offset, -1, ett_dcc_opnums, NULL, "Operation Numbers (Opaque to Server)");
568
569
  /* Note - these are indeterminate - they are sortof considered opaque to the client */
570
  /* Make some attempt to figure out if this data is little endian, not guaranteed to be
571
  correct if connection went through a firewall or similar. */
572
573
  /* Very hokey check - if all three of pid/report/retrans look like little-endian
574
    numbers, host is probably little endian. Probably inaccurate on super-heavily-used
575
    DCC clients though. This should be good enough for now. */
576
23
  client_is_le = (( (tvb_get_uint8(tvb, offset+4) | tvb_get_uint8(tvb, offset+5)) &&
577
18
            (tvb_get_uint8(tvb, offset+8) | tvb_get_uint8(tvb, offset+9)) &&
578
17
            (tvb_get_uint8(tvb, offset+12) | tvb_get_uint8(tvb, offset+13)) )) ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN;
579
580
23
  proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_host, tvb, offset, 4, client_is_le);
581
23
  offset += 4;
582
583
23
  proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_pid, tvb, offset, 4, client_is_le);
584
23
  offset += 4;
585
586
23
  proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_report, tvb, offset, 4, client_is_le);
587
23
  offset += 4;
588
589
23
  proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_retrans, tvb, offset, 4, client_is_le);
590
23
  offset += 4;
591
592
23
  dcc_optree = proto_tree_add_subtree_format(dcc_tree, tvb, offset, -1, ett_dcc_op, NULL,
593
23
    "Operation: %s", val_to_str(pinfo->pool, op, dcc_op_vals, "Unknown Op: %u"));
594
595
23
  switch(op) {
596
2
    case DCC_OP_NOP:
597
2
      proto_tree_add_item(dcc_optree, hf_dcc_signature, tvb, offset, (int)sizeof(DCC_SIGNATURE), ENC_NA);
598
2
      break;
599
600
3
    case DCC_OP_REPORT:
601
3
      proto_tree_add_item(dcc_optree, hf_dcc_target, tvb, offset, (int)sizeof(DCC_TGTS), ENC_BIG_ENDIAN);
602
3
      offset += (int)sizeof(DCC_TGTS);
603
604
18
      for (i = 0; i <= DCC_QUERY_MAX && (tvb_reported_length_remaining(tvb, offset + sizeof(DCC_SIGNATURE)) > 0); i++)
605
15
      {
606
15
        proto_tree* cktree;
607
15
        cktree = proto_tree_add_subtree_format(dcc_optree, tvb, offset, (int)sizeof(DCC_CK),
608
15
          ett_dcc_ck, NULL, "Checksum - %s",
609
15
          val_to_str(pinfo->pool, tvb_get_uint8(tvb, offset), dcc_cktype_vals, "Unknown Type: %u"));
610
15
        proto_tree_add_item(cktree, hf_dcc_ck_type, tvb, offset, 1, ENC_BIG_ENDIAN);
611
15
        offset += 1;
612
15
        proto_tree_add_item(cktree, hf_dcc_ck_len, tvb, offset, 1, ENC_BIG_ENDIAN);
613
15
        offset += 1;
614
15
        proto_tree_add_item(cktree, hf_dcc_ck_sum, tvb, offset, (int)sizeof(DCC_SUM), ENC_NA);
615
15
        offset += (int)sizeof(DCC_SUM);
616
15
      }
617
3
      proto_tree_add_item(dcc_optree, hf_dcc_signature, tvb, offset, (int)sizeof(DCC_SIGNATURE), ENC_NA);
618
3
      break;
619
620
2
    case DCC_OP_QUERY_RESP:
621
32
      for (i=0; i<=DCC_QUERY_MAX && (tvb_reported_length_remaining(tvb, offset+sizeof(DCC_SIGNATURE)) > 0); i++)
622
30
      {
623
30
        proto_tree_add_item(dcc_optree, hf_dcc_target, tvb, offset, (int)sizeof(DCC_TGTS), ENC_BIG_ENDIAN);
624
30
        offset += (int)sizeof(DCC_TGTS);
625
30
      }
626
2
      proto_tree_add_item(dcc_optree, hf_dcc_signature, tvb, offset, (int)sizeof(DCC_SIGNATURE), ENC_NA);
627
2
      break;
628
629
6
    case DCC_OP_ADMN:
630
6
      if ( is_response )
631
6
      {
632
6
        unsigned left_local = tvb_reported_length_remaining(tvb, offset) - (int)sizeof(DCC_SIGNATURE);
633
6
        if ( left_local == sizeof(DCC_ADMN_RESP_CLIENTS) )
634
0
        {
635
0
          proto_tree_add_item(dcc_optree, hf_dcc_addr, tvb, offset, 16, ENC_NA);
636
0
          offset += 16;
637
0
          proto_tree_add_item(dcc_optree, hf_dcc_id, tvb, offset, (int)sizeof(DCC_CLNT_ID), ENC_BIG_ENDIAN);
638
0
          offset += (int)sizeof(DCC_CLNT_ID);
639
0
          proto_tree_add_item(dcc_optree, hf_dcc_last_used, tvb, offset, 4, ENC_BIG_ENDIAN);
640
0
          offset += 4;
641
0
          proto_tree_add_item(dcc_optree, hf_dcc_requests, tvb, offset, 4, ENC_BIG_ENDIAN);
642
0
          offset += 4;
643
0
        }
644
6
        else
645
6
        {
646
6
          unsigned next_offset, left;
647
24
          while (tvb_reported_length_remaining(tvb, offset+(int)sizeof(DCC_SIGNATURE)) > 0) {
648
18
            left = tvb_reported_length_remaining(tvb,offset) - (int)sizeof(DCC_SIGNATURE);
649
18
            tvb_find_line_end_length(tvb, offset, left, NULL, &next_offset);
650
18
            proto_tree_add_item(dcc_optree, hf_dcc_response_text, tvb, offset,
651
18
              next_offset - offset, ENC_ASCII);
652
18
            offset = next_offset;
653
18
          }
654
6
        }
655
6
        proto_tree_add_item(dcc_optree, hf_dcc_signature, tvb, offset, (int)sizeof(DCC_SIGNATURE), ENC_NA);
656
6
      }
657
0
      else
658
0
      {
659
0
        uint32_t aop;
660
661
0
        proto_tree_add_item(dcc_optree, hf_dcc_date, tvb, offset, 4, ENC_TIME_SECS | ENC_BIG_ENDIAN);
662
0
        offset += 4;
663
664
0
        proto_tree_add_item_ret_uint(dcc_optree, hf_dcc_adminop, tvb, offset+4, 1, ENC_BIG_ENDIAN, &aop);
665
0
        col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
666
0
          val_to_str(pinfo->pool, aop, dcc_adminop_vals, "Unknown (%u)"));
667
668
0
        if (aop == DCC_AOP_TRACE_ON || aop == DCC_AOP_TRACE_OFF )
669
0
        {
670
0
          proto_tree_add_bitmask(dcc_optree, tvb, offset, hf_dcc_trace, ett_dcc_trace, trace_flags, ENC_BIG_ENDIAN);
671
0
        }
672
0
        else if ( aop == DCC_AOP_FLOD )
673
0
        {
674
0
          uint32_t floodop;
675
0
          proto_tree_add_item_ret_uint(dcc_optree, hf_dcc_floodop, tvb, offset, 4, ENC_BIG_ENDIAN, &floodop);
676
0
          col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
677
0
            val_to_str(pinfo->pool, floodop, dcc_floodop_vals, "Unknown (%u)"));
678
0
        }
679
0
        else
680
0
        {
681
0
          proto_tree_add_item(dcc_optree, hf_dcc_adminval, tvb, offset, 4, ENC_BIG_ENDIAN);
682
0
        }
683
0
        offset += 4;
684
685
0
        offset += 1; /* admin op we did in reverse order */
686
687
0
        proto_tree_add_item(dcc_optree, hf_dcc_pad, tvb, offset, 3, ENC_NA);
688
0
        offset += 3;
689
0
        proto_tree_add_item(dcc_optree, hf_dcc_signature, tvb, offset, (int)sizeof(DCC_SIGNATURE), ENC_NA);
690
0
      }
691
6
      break;
692
693
1
    case DCC_OP_OK:
694
1
      proto_tree_add_item(dcc_optree, hf_dcc_max_pkt_vers, tvb,
695
1
        offset, 1, ENC_BIG_ENDIAN);
696
1
      offset += 1;
697
698
1
      proto_tree_add_item(dcc_optree, hf_dcc_unused, tvb, offset, 1, ENC_NA);
699
1
      offset += 1;
700
701
1
      proto_tree_add_item(dcc_optree, hf_dcc_qdelay_ms, tvb, offset, 2, ENC_BIG_ENDIAN);
702
1
      offset += 2;
703
704
1
      proto_tree_add_item(dcc_optree, hf_dcc_brand, tvb, offset, (int)sizeof(DCC_BRAND), ENC_ASCII);
705
1
      offset += (int)sizeof(DCC_BRAND);
706
707
1
      proto_tree_add_item(dcc_optree, hf_dcc_signature, tvb, offset, (int)sizeof(DCC_SIGNATURE), ENC_NA);
708
1
      break;
709
710
7
    default:
711
      /* do nothing */
712
7
      break;
713
23
  }
714
715
13
  return tvb_captured_length(tvb);
716
23
}
717
718
static unsigned
719
dissect_dcc_pdu_len(packet_info* pinfo _U_, tvbuff_t* tvb, int offset, void* data _U_)
720
24
{
721
24
  return tvb_get_ntohs(tvb, offset);
722
24
}
723
724
static int
725
dissect_dcc_udp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
726
15
{
727
15
  udp_dissect_pdus(tvb, pinfo, tree, sizeof(DCC_HDR), NULL,
728
15
    dissect_dcc_pdu_len, dissect_dcc_pdu, data);
729
15
  return tvb_captured_length(tvb);
730
15
}
731
732
void
733
proto_register_dcc(void)
734
16
{
735
16
  static hf_register_info hf[] = {
736
16
      { &hf_dcc_len, {
737
16
        "Packet Length", "dcc.len", FT_UINT16, BASE_DEC,
738
16
        NULL, 0, NULL, HFILL }},
739
740
16
      { &hf_dcc_pkt_vers, {
741
16
        "Packet Version", "dcc.pkt_vers", FT_UINT16, BASE_DEC,
742
16
        NULL, 0, NULL, HFILL }},
743
744
16
      { &hf_dcc_op, {
745
16
        "Operation Type", "dcc.op", FT_UINT8, BASE_DEC,
746
16
        VALS(dcc_op_vals), 0, NULL, HFILL }},
747
748
16
      { &hf_dcc_clientid, {
749
16
        "Client ID", "dcc.clientid", FT_UINT32, BASE_DEC,
750
16
        NULL, 0, NULL, HFILL }},
751
752
16
      { &hf_dcc_opnums_host, {
753
16
        "Host", "dcc.opnums.host", FT_UINT32, BASE_DEC,
754
16
        NULL, 0, NULL, HFILL }},
755
756
16
      { &hf_dcc_opnums_pid, {
757
16
        "Process ID", "dcc.opnums.pid", FT_UINT32, BASE_DEC,
758
16
        NULL, 0, NULL, HFILL }},
759
760
16
      { &hf_dcc_opnums_report, {
761
16
        "Report", "dcc.opnums.report", FT_UINT32, BASE_DEC,
762
16
        NULL, 0, NULL, HFILL }},
763
764
16
      { &hf_dcc_opnums_retrans, {
765
16
        "Retransmission", "dcc.opnums.retrans", FT_UINT32, BASE_DEC,
766
16
        NULL, 0, NULL, HFILL }},
767
768
16
      { &hf_dcc_signature, {
769
16
        "Signature", "dcc.signature", FT_BYTES, BASE_NONE,
770
16
        NULL, 0, NULL, HFILL }},
771
772
16
      { &hf_dcc_max_pkt_vers, {
773
16
        "Maximum Packet Version", "dcc.max_pkt_vers", FT_UINT8, BASE_DEC,
774
16
        NULL, 0, NULL, HFILL }},
775
776
16
      { &hf_dcc_qdelay_ms, {
777
16
        "Client Delay", "dcc.qdelay_ms", FT_UINT16, BASE_DEC,
778
16
        NULL, 0, NULL, HFILL }},
779
780
16
      { &hf_dcc_brand, {
781
16
        "Server Brand", "dcc.brand", FT_STRING, BASE_NONE,
782
16
        NULL, 0, NULL, HFILL }},
783
784
16
      { &hf_dcc_ck_type, {
785
16
        "Type", "dcc.checksum.type", FT_UINT8, BASE_DEC,
786
16
        VALS(dcc_cktype_vals), 0, "Checksum Type", HFILL }},
787
788
16
      { &hf_dcc_ck_len, {
789
16
        "Length", "dcc.checksum.length", FT_UINT8, BASE_DEC,
790
16
        NULL, 0, "Checksum Length", HFILL }},
791
792
16
      { &hf_dcc_ck_sum, {
793
16
        "Sum", "dcc.checksum.sum", FT_BYTES, BASE_NONE,
794
16
        NULL, 0, "Checksum", HFILL }},
795
796
16
      { &hf_dcc_target, {
797
16
        "Target", "dcc.target", FT_UINT32, BASE_HEX,
798
16
        VALS(dcc_target_vals), 0, NULL, HFILL }},
799
800
16
      { &hf_dcc_response_text, {
801
16
        "Response Text", "dcc.response_text", FT_STRING, BASE_NONE,
802
16
        NULL, 0, NULL, HFILL }},
803
804
16
      { &hf_dcc_date, {
805
16
        "Date", "dcc.date", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
806
16
        NULL, 0, NULL, HFILL }},
807
808
16
      { &hf_dcc_adminop, {
809
16
        "Admin Op", "dcc.adminop", FT_UINT8, BASE_DEC,
810
16
        VALS(dcc_adminop_vals), 0, NULL, HFILL }},
811
812
16
      { &hf_dcc_adminval, {
813
16
        "Admin Value", "dcc.adminval", FT_UINT32, BASE_DEC,
814
16
        NULL, 0, NULL, HFILL }},
815
816
16
      { &hf_dcc_trace, {
817
16
        "Trace Bits", "dcc.trace", FT_UINT32, BASE_HEX,
818
16
        NULL, 0, NULL, HFILL }},
819
820
16
      { &hf_dcc_trace_admin, {
821
16
        "Admin Requests", "dcc.trace.admin", FT_BOOLEAN, 32,
822
16
        NULL, 0x00000001, NULL, HFILL }},
823
824
16
      { &hf_dcc_trace_anon, {
825
16
        "Anonymous Requests", "dcc.trace.anon", FT_BOOLEAN, 32,
826
16
        NULL, 0x00000002, NULL, HFILL }},
827
828
16
      { &hf_dcc_trace_client, {
829
16
        "Authenticated Client Requests", "dcc.trace.client", FT_BOOLEAN, 32,
830
16
        NULL, 0x00000004, NULL, HFILL }},
831
832
16
      { &hf_dcc_trace_rlim, {
833
16
        "Rate-Limited Requests", "dcc.trace.rlim", FT_BOOLEAN, 32,
834
16
        NULL, 0x00000008, NULL, HFILL }},
835
836
16
      { &hf_dcc_trace_query, {
837
16
        "Queries and Reports", "dcc.trace.query", FT_BOOLEAN, 32,
838
16
        NULL, 0x00000010, NULL, HFILL }},
839
840
16
      { &hf_dcc_trace_ridc, {
841
16
        "RID Cache Messages", "dcc.trace.ridc", FT_BOOLEAN, 32,
842
16
        NULL, 0x00000020, NULL, HFILL }},
843
844
16
      { &hf_dcc_trace_flood, {
845
16
        "Input/Output Flooding", "dcc.trace.flood", FT_BOOLEAN, 32,
846
16
        NULL, 0x00000040, NULL, HFILL }},
847
848
16
      { &hf_dcc_floodop, {
849
16
        "Flood Control Operation", "dcc.floodop", FT_UINT32, BASE_DEC,
850
16
        VALS(dcc_floodop_vals), 0, NULL, HFILL }},
851
852
16
      { &hf_dcc_id, {
853
16
        "Id", "dcc.id", FT_UINT32, BASE_DEC,
854
16
        NULL, 0, NULL, HFILL }},
855
856
16
      { &hf_dcc_last_used, {
857
16
        "Last Used", "dcc.last_used", FT_UINT32, BASE_DEC,
858
16
        NULL, 0, NULL, HFILL }},
859
860
16
      { &hf_dcc_requests, {
861
16
        "Requests", "dcc.requests", FT_UINT32, BASE_DEC,
862
16
        NULL, 0, NULL, HFILL }},
863
864
16
      { &hf_dcc_addr, {
865
16
        "Addr", "dcc.addr", FT_BYTES, BASE_NONE,
866
16
        NULL, 0, NULL, HFILL }},
867
868
16
      { &hf_dcc_pad, {
869
16
        "Pad", "dcc.pad", FT_BYTES, BASE_NONE,
870
16
        NULL, 0, NULL, HFILL }},
871
872
16
      { &hf_dcc_unused, {
873
16
        "Unused", "dcc.unused", FT_BYTES, BASE_NONE,
874
16
        NULL, 0, NULL, HFILL }},
875
16
    };
876
877
16
  static int *ett[] = {
878
16
    &ett_dcc,
879
16
    &ett_dcc_op,
880
16
    &ett_dcc_ck,
881
16
    &ett_dcc_opnums,
882
16
    &ett_dcc_trace,
883
16
  };
884
885
16
  proto_dcc = proto_register_protocol("Distributed Checksum Clearinghouse protocol", "DCC", "dcc");
886
887
16
  proto_register_field_array(proto_dcc, hf, array_length(hf));
888
16
  proto_register_subtree_array(ett, array_length(ett));
889
16
}
890
891
void
892
proto_reg_handoff_dcc(void)
893
16
{
894
16
  dissector_handle_t udp_handle = register_dissector("dcc_udp", dissect_dcc_udp, proto_dcc);
895
16
  dissector_add_uint_with_preference("udp.port", DCC_PORT, udp_handle);
896
16
}
897
898
/*
899
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
900
 *
901
 * Local variables:
902
 * c-basic-offset: 8
903
 * tab-width: 8
904
 * indent-tabs-mode: t
905
 * End:
906
 *
907
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
908
 * :indentSize=8:tabSize=8:noTabs=false:
909
 */