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-couchbase.c
Line
Count
Source
1
/* packet-couchbase.c
2
 *
3
 * Routines for Couchbase Protocol
4
 *
5
 * Copyright 2019, Trond Norbye <trond@couchbase.com>
6
 * Copyright 2018, Jim Walker <jim@couchbase.com>
7
 * Copyright 2015-2016, Dave Rigby <daver@couchbase.com>
8
 * Copyright 2011, Sergey Avseyev <sergey.avseyev@gmail.com>
9
 *
10
 * With contributions from Mark Woosey <mark@markwoosey.com>
11
 *
12
 *
13
 * Based on packet-memcache.c: mecmcache binary protocol.
14
 *
15
 * Routines for Memcache Binary Protocol
16
 * http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
17
 *
18
 * Copyright 2009, Stig Bjorlykke <stig@bjorlykke.org>
19
 *
20
 * Routines for Memcache Textual Protocol
21
 * https://github.com/memcached/memcached/blob/master/doc/protocol.txt
22
 *
23
 * Copyright 2009, Rama Chitta <rama@gear6.com>
24
 *
25
 * Wireshark - Network traffic analyzer
26
 * By Gerald Combs <gerald@wireshark.org>
27
 * Copyright 1998 Gerald Combs
28
 *
29
 * SPDX-License-Identifier: GPL-2.0-or-later
30
 */
31
32
#include "config.h"
33
34
35
#include <epan/packet.h>
36
#include <epan/prefs.h>
37
#include <epan/expert.h>
38
#include <epan/tfs.h>
39
#include <epan/unit_strings.h>
40
41
#ifdef HAVE_SNAPPY
42
#include <snappy-c.h>
43
#endif
44
45
#include "packet-tcp.h"
46
#include "packet-tls.h"
47
48
#include <math.h>
49
50
15
#define COUCHBASE_DEFAULT_PORT        "11210"
51
431
#define COUCHBASE_HEADER_LEN   24
52
53
/* Magic Byte */
54
enum {
55
  /**
56
   * The magic used for a normal request sent from the client to the
57
   * server. Layout described in:
58
   * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#request-header
59
   */
60
  MAGIC_CLIENT_REQUEST = 0x80,
61
  /**
62
   * The magic used for a normal response sent from the server to
63
   * the client. Layout described in:
64
   * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#response-header
65
   */
66
  MAGIC_CLIENT_RESPONSE = 0x81,
67
  /**
68
   * The magic used when the client want to inject a set of extensions
69
   * to the command sent to the server. Layout described in:
70
   * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#request-header-with-flexible-framing-extras
71
   */
72
  MAGIC_CLIENT_RESPONSE_FLEX = 0x18,
73
  /**
74
   * The magic used by the server when the server needs to inject a set of
75
   * extensions in the response packet. Layout described in:
76
   * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#response-header-with-flexible-framing-extras
77
   */
78
  MAGIC_CLIENT_REQUEST_FLEX = 0x08,
79
  /**
80
   * The magic used for server initiated push requests. These packets
81
   * use the same layout as client flex request packets (with a different
82
   * namespace for the frame id's)
83
   */
84
  MAGIC_SERVER_REQUEST = 0x82,
85
  /**
86
   * The magic used for responses to server initiated push requests. These
87
   * packets use the same layout as client flex response packet (with
88
   * a different namespace for the frame id's)
89
   */
90
  MAGIC_SERVER_RESPONSE = 0x83
91
};
92
93
/** Does the magic represent a flex encoded packet type */
94
1.40k
static bool is_flex_encoded(uint8_t magic) {
95
1.40k
  switch (magic) {
96
280
    case MAGIC_CLIENT_RESPONSE_FLEX:
97
748
    case MAGIC_CLIENT_REQUEST_FLEX:
98
758
    case MAGIC_SERVER_REQUEST:
99
758
    case MAGIC_SERVER_RESPONSE:
100
758
      return true;
101
102
5
    case MAGIC_CLIENT_REQUEST:
103
20
    case MAGIC_CLIENT_RESPONSE:
104
651
    default:
105
651
      return false;
106
1.40k
  }
107
1.40k
}
108
109
/** Does the magic represent server initiated packet types */
110
470
static bool is_server_magic(uint8_t magic) {
111
470
  switch (magic) {
112
3
    case MAGIC_SERVER_REQUEST:
113
3
    case MAGIC_SERVER_RESPONSE:
114
3
      return true;
115
116
72
    case MAGIC_CLIENT_RESPONSE_FLEX:
117
219
    case MAGIC_CLIENT_REQUEST_FLEX:
118
221
    case MAGIC_CLIENT_REQUEST:
119
226
    case MAGIC_CLIENT_RESPONSE:
120
467
    default:
121
467
      return false;
122
470
  }
123
470
}
124
125
/** Does the magic represent a request or a response */
126
750
static bool is_request_magic(uint8_t magic) {
127
750
  switch (magic) {
128
3
    case MAGIC_SERVER_REQUEST:
129
342
    case MAGIC_CLIENT_REQUEST_FLEX:
130
345
    case MAGIC_CLIENT_REQUEST:
131
345
      return true;
132
133
0
    case MAGIC_SERVER_RESPONSE:
134
156
    case MAGIC_CLIENT_RESPONSE_FLEX:
135
164
    case MAGIC_CLIENT_RESPONSE:
136
405
    default:
137
405
      return false;
138
750
  }
139
750
}
140
141
 /* Response Status */
142
0
#define STATUS_SUCCESS            0x00
143
#define STATUS_KEY_ENOENT         0x01
144
#define STATUS_KEY_EEXISTS        0x02
145
#define STATUS_E2BIG              0x03
146
#define STATUS_EINVAL             0x04
147
#define STATUS_NOT_STORED         0x05
148
#define STATUS_DELTA_BADVAL       0x06
149
16
#define STATUS_NOT_MY_VBUCKET     0x07
150
#define STATUS_NO_VBUCKET         0x08
151
#define STATUS_LOCKED             0x09
152
#define STATUS_DCP_STREAM_NOT_FOUND 0x0a
153
#define STATUS_OPAQUE_NO_MATCH    0x0b
154
#define STATUS_EWOULDTHROTTLE     0x0c
155
#define STATUS_ECONFIGONLY        0x0d
156
#define STATUS_NOT_LOCKED         0x0e
157
#define STATUS_AUTH_STALE         0x1f
158
#define STATUS_AUTH_ERROR         0x20
159
#define STATUS_AUTH_CONTINUE      0x21
160
#define STATUS_ERANGE             0x22
161
#define STATUS_ROLLBACK           0x23
162
#define STATUS_EACCESS            0x24
163
#define STATUS_NOT_INITIALIZED    0x25
164
#define STATUS_RATELIMITED_NETWORK_INGRESS 0x30
165
#define STATUS_RATELIMITED_NETWORK_EGRESS 0x31
166
#define STATUS_RATELIMITED_MAX_CONNECTIONS 0x32
167
#define STATUS_RATELIMITED_MAX_COMMANDS 0x33
168
#define STATUS_SCOPE_SIZE_LIMIT_EXCEEDED 0x34
169
#define STATUS_UNKNOWN_COMMAND    0x81
170
#define STATUS_ENOMEM             0x82
171
#define STATUS_NOT_SUPPORTED      0x83
172
#define STATUS_EINTERNAL          0x84
173
#define STATUS_EBUSY              0x85
174
#define STATUS_ETMPFAIL           0x86
175
#define STATUS_XATTR_EINVAL       0x87
176
#define STATUS_UNKNOWN_COLLECTION         0x88
177
#define STATUS_NO_COLLECTIONS_MANIFEST    0x89
178
#define STATUS_CANNOT_APPLY_MANIFEST      0x8a
179
#define STATUS_MANIFEST_IS_AHEAD          0x8b
180
#define STATUS_UNKNOWN_SCOPE              0x8c
181
#define STATUS_DCP_STREAMID_INVALID       0x8d
182
#define STATUS_DURABILITY_INVALID_LEVEL         0xa0
183
#define STATUS_DURABILITY_IMPOSSIBLE            0xa1
184
#define STATUS_SYNC_WRITE_IN_PROGRESS           0xa2
185
#define STATUS_SYNC_WRITE_AMBIGUOUS             0xa3
186
#define STATUS_SYNC_WRITE_RECOMMIT_IN_PROGRESS  0xa4
187
#define STATUS_RANGE_SCAN_CANCELLED 0xa5
188
#define STATUS_RANGE_SCAN_MORE 0xa6
189
#define STATUS_RANGE_SCAN_COMPLETE 0xa7
190
#define STATUS_VBUUID_NOT_EQUAL 0xa8
191
#define STATUS_SUBDOC_PATH_ENOENT         0xc0
192
#define STATUS_SUBDOC_PATH_MISMATCH       0xc1
193
#define STATUS_SUBDOC_PATH_EINVAL         0xc2
194
#define STATUS_SUBDOC_PATH_E2BIG          0xc3
195
#define STATUS_SUBDOC_DOC_E2DEEP          0xc4
196
#define STATUS_SUBDOC_VALUE_CANTINSERT    0xc5
197
#define STATUS_SUBDOC_DOC_NOTJSON         0xc6
198
#define STATUS_SUBDOC_NUM_ERANGE          0xc7
199
#define STATUS_SUBDOC_DELTA_ERANGE        0xc8
200
#define STATUS_SUBDOC_PATH_EEXISTS        0xc9
201
#define STATUS_SUBDOC_VALUE_ETOODEEP      0xca
202
#define STATUS_SUBDOC_INVALID_COMBO       0xcb
203
0
#define STATUS_SUBDOC_MULTI_PATH_FAILURE  0xcc
204
#define STATUS_SUBDOC_SUCCESS_DELETED            0xcd
205
#define STATUS_SUBDOC_XATTR_INVALID_FLAG_COMBO   0xce
206
#define STATUS_SUBDOC_XATTR_INVALID_KEY_COMBO    0xcf
207
#define STATUS_SUBDOC_XATTR_UNKNOWN_MACRO        0xd0
208
#define STATUS_SUBDOC_XATTR_UNKNOWN_VATTR        0xd1
209
#define STATUS_SUBDOC_XATTR_CANT_MODIFY_VATTR    0xd2
210
#define STATUS_SUBDOC_MULTI_PATH_FAILURE_DELETED 0xd3
211
#define STATUS_SUBDOC_INVALID_XATTR_ORDER        0xd4
212
#define STATUS_SUBDOC_XATTR_UNKNOWN_VATTR_MACRO  0xd5
213
#define STATUS_SUBDOC_CAN_ONLY_REVIVE_DELETED_DOCUMENTS 0xd6
214
#define STATUS_SUBDOC_DELETED_DOCUMENT_CANT_HAVE_VALUE  0xd7
215
216
 /* Command Opcodes */
217
100
#define CLIENT_OPCODE_GET                     0x00
218
95
#define CLIENT_OPCODE_SET                     0x01
219
99
#define CLIENT_OPCODE_ADD                     0x02
220
101
#define CLIENT_OPCODE_REPLACE                 0x03
221
97
#define CLIENT_OPCODE_DELETE                  0x04
222
112
#define CLIENT_OPCODE_INCREMENT               0x05
223
108
#define CLIENT_OPCODE_DECREMENT               0x06
224
13
#define CLIENT_OPCODE_QUIT                    0x07
225
22
#define CLIENT_OPCODE_FLUSH                   0x08
226
101
#define CLIENT_OPCODE_GETQ                    0x09
227
18
#define CLIENT_OPCODE_NOOP                    0x0a
228
13
#define CLIENT_OPCODE_VERSION                 0x0b
229
101
#define CLIENT_OPCODE_GETK                    0x0c
230
101
#define CLIENT_OPCODE_GETKQ                   0x0d
231
9
#define CLIENT_OPCODE_APPEND                  0x0e
232
9
#define CLIENT_OPCODE_PREPEND                 0x0f
233
1
#define CLIENT_OPCODE_STAT                    0x10
234
98
#define CLIENT_OPCODE_SETQ                    0x11
235
100
#define CLIENT_OPCODE_ADDQ                    0x12
236
101
#define CLIENT_OPCODE_REPLACEQ                0x13
237
102
#define CLIENT_OPCODE_DELETEQ                 0x14
238
101
#define CLIENT_OPCODE_INCREMENTQ              0x15
239
102
#define CLIENT_OPCODE_DECREMENTQ              0x16
240
5
#define CLIENT_OPCODE_QUITQ                   0x17
241
26
#define CLIENT_OPCODE_FLUSHQ                  0x18
242
11
#define CLIENT_OPCODE_APPENDQ                 0x19
243
11
#define CLIENT_OPCODE_PREPENDQ                0x1a
244
12
#define CLIENT_OPCODE_VERBOSITY               0x1b
245
#define CLIENT_OPCODE_TOUCH                   0x1c
246
#define CLIENT_OPCODE_GAT                     0x1d
247
#define CLIENT_OPCODE_GATQ                    0x1e
248
50
#define CLIENT_OPCODE_HELLO                   0x1f
249
250
 /* SASL operations */
251
0
#define CLIENT_OPCODE_SASL_LIST_MECHS         0x20
252
3
#define CLIENT_OPCODE_SASL_AUTH               0x21
253
4
#define CLIENT_OPCODE_SASL_STEP               0x22
254
255
/* Control */
256
4
#define CLIENT_OPCODE_IOCTL_GET               0x23
257
4
#define CLIENT_OPCODE_IOCTL_SET               0x24
258
1
#define CLIENT_OPCODE_CONFIG_VALIDATE         0x25
259
1
#define CLIENT_OPCODE_CONFIG_RELOAD           0x26
260
1
#define CLIENT_OPCODE_AUDIT_PUT               0x27
261
1
#define CLIENT_OPCODE_AUDIT_CONFIG_RELOAD     0x28
262
1
#define CLIENT_OPCODE_SHUTDOWN                0x29
263
264
#define CLIENT_OPCODE_SET_ACTIVE_ENCRYPTION_KEYS 0x2d
265
#define CLIENT_OPCODE_PRUNE_ENCRYPTION_KEYS   0x2e
266
267
 /* Range operations.
268
  * These commands are used for range operations and exist within
269
  * protocol_binary.h for use in other projects. Range operations are
270
  * not expected to be implemented in the memcached server itself.
271
  */
272
#define CLIENT_OPCODE_RGET                    0x30
273
#define CLIENT_OPCODE_RSET                    0x31
274
#define CLIENT_OPCODE_RSETQ                   0x32
275
#define CLIENT_OPCODE_RAPPEND                 0x33
276
#define CLIENT_OPCODE_RAPPENDQ                0x34
277
#define CLIENT_OPCODE_RPREPEND                0x35
278
#define CLIENT_OPCODE_RPREPENDQ               0x36
279
#define CLIENT_OPCODE_RDELETE                 0x37
280
#define CLIENT_OPCODE_RDELETEQ                0x38
281
#define CLIENT_OPCODE_RINCR                   0x39
282
#define CLIENT_OPCODE_RINCRQ                  0x3a
283
#define CLIENT_OPCODE_RDECR                   0x3b
284
#define CLIENT_OPCODE_RDECRQ                  0x3c
285
286
287
 /* VBucket commands */
288
#define CLIENT_OPCODE_SET_VBUCKET             0x3d
289
#define CLIENT_OPCODE_GET_VBUCKET             0x3e
290
#define CLIENT_OPCODE_DEL_VBUCKET             0x3f
291
292
 /* TAP commands */
293
4
#define CLIENT_OPCODE_TAP_CONNECT             0x40
294
0
#define CLIENT_OPCODE_TAP_MUTATION            0x41
295
1
#define CLIENT_OPCODE_TAP_DELETE              0x42
296
1
#define CLIENT_OPCODE_TAP_FLUSH               0x43
297
1
#define CLIENT_OPCODE_TAP_OPAQUE              0x44
298
1
#define CLIENT_OPCODE_TAP_VBUCKET_SET         0x45
299
1
#define CLIENT_OPCODE_TAP_CHECKPOINT_START    0x46
300
1
#define CLIENT_OPCODE_TAP_CHECKPOINT_END      0x47
301
302
6
#define CLIENT_OPCODE_GET_ALL_VB_SEQNOS       0x48
303
304
#define CLIENT_OPCODE_GET_EX                  0x49
305
#define CLIENT_OPCODE_GET_EX_REPLICA          0x4a
306
307
/* DCP commands */
308
100
#define CLIENT_OPCODE_DCP_OPEN_CONNECTION         0x50
309
1
#define CLIENT_OPCODE_DCP_ADD_STREAM              0x51
310
1
#define CLIENT_OPCODE_DCP_CLOSE_STREAM            0x52
311
12
#define CLIENT_OPCODE_DCP_STREAM_REQUEST          0x53
312
7
#define CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST    0x54
313
1
#define CLIENT_OPCODE_DCP_STREAM_END              0x55
314
19
#define CLIENT_OPCODE_DCP_SNAPSHOT_MARKER         0x56
315
128
#define CLIENT_OPCODE_DCP_MUTATION                0x57
316
149
#define CLIENT_OPCODE_DCP_DELETION                0x58
317
126
#define CLIENT_OPCODE_DCP_EXPIRATION              0x59
318
9
#define CLIENT_OPCODE_DCP_FLUSH                   0x5a
319
9
#define CLIENT_OPCODE_DCP_SET_VBUCKET_STATE       0x5b
320
#define CLIENT_OPCODE_DCP_NOOP                    0x5c
321
0
#define CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT  0x5d
322
4
#define CLIENT_OPCODE_DCP_CONTROL                 0x5e
323
103
#define CLIENT_OPCODE_DCP_SYSTEM_EVENT            0x5f
324
15
#define CLIENT_OPCODE_DCP_PREPARE                 0x60
325
0
#define CLIENT_OPCODE_DCP_SEQNO_ACK               0x61
326
0
#define CLIENT_OPCODE_DCP_COMMIT                  0x62
327
0
#define CLIENT_OPCODE_DCP_ABORT                   0x63
328
0
#define CLIENT_OPCODE_DCP_SEQNO_ADVANCED          0x64
329
0
#define CLIENT_OPCODE_DCP_OSO_SNAPSHOT            0x65
330
331
#define CLIENT_OPCODE_GET_FUSION_STORAGE_SNAPSHOT 0x70
332
#define CLIENT_OPCODE_RELEASE_FUSION_STORAGE_SNAPSHOT 0x71
333
#define CLIENT_OPCODE_MOUNT_FUSION_VB             0x72
334
#define CLIENT_OPCODE_UNMOUNT_FUSION_VB           0x73
335
#define CLIENT_OPCODE_SYNC_FUSION_LOGSTORE        0x74
336
#define CLIENT_OPCODE_START_FUSION_UPLOADER       0x75
337
#define CLIENT_OPCODE_STOP_FUSION_UPLOADER        0x76
338
#define CLIENT_OPCODE_DELETE_FUSION_NAMESPACE     0x77
339
#define CLIENT_OPCODE_GET_FUSION_NAMESPACES       0x78
340
341
 /* Commands from EP (eventually persistent) and bucket engines */
342
#define CLIENT_OPCODE_STOP_PERSISTENCE        0x80
343
#define CLIENT_OPCODE_START_PERSISTENCE       0x81
344
4
#define CLIENT_OPCODE_SET_PARAM               0x82
345
#define CLIENT_OPCODE_GET_REPLICA             0x83
346
48
#define CLIENT_OPCODE_CREATE_BUCKET           0x85
347
17
#define CLIENT_OPCODE_DELETE_BUCKET           0x86
348
13
#define CLIENT_OPCODE_LIST_BUCKETS            0x87
349
#define CLIENT_OPCODE_EXPAND_BUCKET           0x88
350
17
#define CLIENT_OPCODE_SELECT_BUCKET           0x89
351
#define CLIENT_OPCODE_START_REPLICATION       0x90
352
54
#define CLIENT_OPCODE_OBSERVE_SEQNO           0x91
353
339
#define CLIENT_OPCODE_OBSERVE                 0x92
354
#define CLIENT_OPCODE_EVICT_KEY               0x93
355
#define CLIENT_OPCODE_GET_LOCKED              0x94
356
#define CLIENT_OPCODE_UNLOCK_KEY              0x95
357
#define CLIENT_OPCODE_SYNC                    0x96
358
#define CLIENT_OPCODE_LAST_CLOSED_CHECKPOINT  0x97
359
#define CLIENT_OPCODE_RESTORE_FILE            0x98
360
#define CLIENT_OPCODE_RESTORE_ABORT           0x99
361
#define CLIENT_OPCODE_RESTORE_COMPLETE        0x9a
362
#define CLIENT_OPCODE_ONLINE_UPDATE_START     0x9b
363
#define CLIENT_OPCODE_ONLINE_UPDATE_COMPLETE  0x9c
364
#define CLIENT_OPCODE_ONLINE_UPDATE_REVERT    0x9d
365
#define CLIENT_OPCODE_DEREGISTER_TAP_CLIENT   0x9e
366
#define CLIENT_OPCODE_RESET_REPLICATION_CHAIN 0x9f
367
2
#define CLIENT_OPCODE_GET_META                0xa0
368
#define CLIENT_OPCODE_GETQ_META               0xa1
369
26
#define CLIENT_OPCODE_SET_WITH_META           0xa2
370
14
#define CLIENT_OPCODE_SETQ_WITH_META          0xa3
371
14
#define CLIENT_OPCODE_ADD_WITH_META           0xa4
372
1
#define CLIENT_OPCODE_ADDQ_WITH_META          0xa5
373
#define CLIENT_OPCODE_SNAPSHOT_VB_STATES      0xa6
374
#define CLIENT_OPCODE_VBUCKET_BATCH_COUNT     0xa7
375
14
#define CLIENT_OPCODE_DEL_WITH_META           0xa8
376
14
#define CLIENT_OPCODE_DELQ_WITH_META          0xa9
377
#define CLIENT_OPCODE_CREATE_CHECKPOINT       0xaa
378
#define CLIENT_OPCODE_NOTIFY_VBUCKET_UPDATE   0xac
379
#define CLIENT_OPCODE_ENABLE_TRAFFIC          0xad
380
#define CLIENT_OPCODE_DISABLE_TRAFFIC         0xae
381
5
#define CLIENT_OPCODE_IFCONFIG                0xaf
382
#define CLIENT_OPCODE_CHANGE_VB_FILTER        0xb0
383
#define CLIENT_OPCODE_CHECKPOINT_PERSISTENCE  0xb1
384
#define CLIENT_OPCODE_RETURN_META             0xb2
385
#define CLIENT_OPCODE_COMPACT_DB              0xb3
386
387
388
#define CLIENT_OPCODE_SET_CLUSTER_CONFIG      0xb4
389
0
#define CLIENT_OPCODE_GET_CLUSTER_CONFIG      0xb5
390
#define CLIENT_OPCODE_GET_RANDOM_KEY          0xb6
391
#define CLIENT_OPCODE_SEQNO_PERSISTENCE       0xb7
392
#define CLIENT_OPCODE_GET_KEYS                0xb8
393
0
#define CLIENT_OPCODE_COLLECTIONS_SET_MANIFEST 0xb9
394
0
#define CLIENT_OPCODE_COLLECTIONS_GET_MANIFEST 0xba
395
0
#define CLIENT_OPCODE_COLLECTIONS_GET_ID       0xbb
396
#define CLIENT_OPCODE_COLLECTIONS_GET_SCOPE_ID 0xbc
397
398
#define CLIENT_OPCODE_SET_DRIFT_COUNTER_STATE 0xc1
399
#define CLIENT_OPCODE_GET_ADJUSTED_TIME       0xc2
400
401
/* Sub-document API commands */
402
0
#define CLIENT_OPCODE_SUBDOC_GET              0xc5
403
0
#define CLIENT_OPCODE_SUBDOC_EXISTS           0xc6
404
0
#define CLIENT_OPCODE_SUBDOC_DICT_ADD         0xc7
405
0
#define CLIENT_OPCODE_SUBDOC_DICT_UPSERT      0xc8
406
0
#define CLIENT_OPCODE_SUBDOC_DELETE           0xc9
407
0
#define CLIENT_OPCODE_SUBDOC_REPLACE          0xca
408
0
#define CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST  0xcb
409
0
#define CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST 0xcc
410
0
#define CLIENT_OPCODE_SUBDOC_ARRAY_INSERT     0xcd
411
1
#define CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE 0xce
412
1
#define CLIENT_OPCODE_SUBDOC_COUNTER          0xcf
413
137
#define CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP     0xd0
414
63
#define CLIENT_OPCODE_SUBDOC_MULTI_MUTATION   0xd1
415
#define CLIENT_OPCODE_SUBDOC_GET_COUNT        0xd2
416
#define CLIENT_OPCODE_SUBDOC_REPLACE_BODY_WITH_XATTR 0xd3
417
418
1
#define CLIENT_OPCODE_RANGE_SCAN_CREATE       0xda
419
0
#define CLIENT_OPCODE_RANGE_SCAN_CONTINUE     0xdb
420
0
#define CLIENT_OPCODE_RANGE_SCAN_CANCEL       0xdc
421
422
#define CLIENT_OPCODE_PREPARE_SNAPSHOT        0xe0
423
#define CLIENT_OPCODE_RELEASE_SNAPSHOT        0xe1
424
#define CLIENT_OPCODE_DOWNLOAD_SNAPSHOT       0xe2
425
#define CLIENT_OPCODE_GET_FILE_FRAGMENT       0xe3
426
427
#define CLIENT_OPCODE_SCRUB                   0xf0
428
#define CLIENT_OPCODE_ISASL_REFRESH           0xf1
429
#define CLIENT_OPCODE_SSL_CERTS_REFRESH       0xf2
430
#define CLIENT_OPCODE_GET_CMD_TIMER           0xf3
431
#define CLIENT_OPCODE_SET_CTRL_TOKEN          0xf4
432
#define CLIENT_OPCODE_GET_CTRL_TOKEN          0xf5
433
#define CLIENT_OPCODE_UPDATE_EXTERNAL_USER_PERMISSIONS 0xf6
434
#define CLIENT_OPCODE_RBAC_REFRESH            0xf7
435
#define CLIENT_OPCODE_AUTH_PROVIDER           0xf8
436
#define CLIENT_OPCODE_DROP_PRIVILEGE          0xfb
437
#define CLIENT_OPCODE_ADJUST_TIMEOFDAY        0xfc
438
#define CLIENT_OPCODE_EWOULDBLOCK_CTL         0xfd
439
19
#define CLIENT_OPCODE_GET_ERROR_MAP           0xfe
440
441
 /* vBucket states */
442
#define VBUCKET_ACTIVE                              0x01
443
#define VBUCKET_PENDING                             0x02
444
#define VBUCKET_REPLICA                             0x03
445
#define VBUCKET_DEAD                                0x04
446
447
 /* Data Types */
448
#define DT_RAW_BYTES          0x00
449
15
#define DT_JSON               0x01
450
15
#define DT_SNAPPY             0x02
451
47
#define DT_XATTR              0x04
452
453
void proto_register_couchbase(void);
454
void proto_reg_handoff_couchbase(void);
455
456
static int proto_couchbase;
457
458
static int hf_magic;
459
static int hf_opcode;
460
static int hf_server_opcode;
461
static int hf_extlength;
462
static int hf_keylength;
463
static int hf_value_length;
464
static int hf_datatype;
465
static int hf_datatype_json;
466
static int hf_datatype_snappy;
467
static int hf_datatype_xattr;
468
static int hf_vbucket;
469
static int hf_status;
470
static int hf_total_bodylength;
471
static int hf_opaque;
472
static int hf_cas;
473
static int hf_ttp;
474
static int hf_ttr;
475
static int hf_collection_key_id;
476
static int hf_collection_key_logical;
477
static int hf_collection_manifest_id;
478
479
static int hf_flex_extras_length;
480
static int hf_flex_keylength;
481
static int hf_extras;
482
static int hf_extras_flags;
483
static int hf_extras_flags_backfill;
484
static int hf_extras_flags_dump;
485
static int hf_extras_flags_list_vbuckets;
486
static int hf_extras_flags_takeover_vbuckets;
487
static int hf_extras_flags_support_ack;
488
static int hf_extras_flags_request_keys_only;
489
static int hf_extras_flags_checkpoint;
490
static int hf_extras_flags_dcp_connection_type;
491
static int hf_extras_flags_dcp_add_stream_takeover;
492
static int hf_extras_flags_dcp_add_stream_diskonly;
493
static int hf_extras_flags_dcp_add_stream_latest;
494
static int hf_extras_flags_dcp_snapshot_marker_memory;
495
static int hf_extras_flags_dcp_snapshot_marker_disk;
496
static int hf_extras_flags_dcp_snapshot_marker_chk;
497
static int hf_extras_flags_dcp_snapshot_marker_ack;
498
static int hf_extras_flags_dcp_snapshot_marker_history;
499
static int hf_extras_flags_dcp_snapshot_marker_may_contain_dups;
500
static int hf_extras_flags_dcp_include_xattrs;
501
static int hf_extras_flags_dcp_no_value;
502
static int hf_extras_flags_dcp_include_delete_times;
503
static int hf_extras_flags_dcp_collections;
504
static int hf_extras_flags_dcp_oso_snapshot_begin;
505
static int hf_extras_flags_dcp_oso_snapshot_end;
506
static int hf_subdoc_doc_flags;
507
static int hf_subdoc_doc_flags_mkdoc;
508
static int hf_subdoc_doc_flags_add;
509
static int hf_subdoc_doc_flags_accessdeleted;
510
static int hf_subdoc_doc_flags_createasdeleted;
511
static int hf_subdoc_doc_flags_revivedocument;
512
static int hf_subdoc_doc_flags_replicaread;
513
static int hf_subdoc_doc_flags_reserved;
514
static int hf_subdoc_flags;
515
static int hf_subdoc_flags_mkdirp;
516
static int hf_subdoc_flags_xattrpath;
517
static int hf_subdoc_flags_expandmacros;
518
static int hf_subdoc_flags_reserved;
519
static int hf_extras_seqno;
520
static int hf_extras_mutation_seqno;
521
static int hf_extras_opaque;
522
static int hf_extras_reserved;
523
static int hf_extras_start_seqno;
524
static int hf_extras_end_seqno;
525
static int hf_extras_high_completed_seqno;
526
static int hf_extras_max_visible_seqno;
527
static int hf_extras_timestamp;
528
static int hf_extras_marker_version;
529
static int hf_extras_vbucket_uuid;
530
static int hf_extras_snap_start_seqno;
531
static int hf_extras_snap_end_seqno;
532
static int hf_extras_expiration;
533
static int hf_extras_delta;
534
static int hf_extras_initial;
535
static int hf_extras_unknown;
536
static int hf_extras_by_seqno;
537
static int hf_extras_rev_seqno;
538
static int hf_extras_prepared_seqno;
539
static int hf_extras_commit_seqno;
540
static int hf_extras_abort_seqno;
541
static int hf_extras_deleted;
542
static int hf_extras_lock_time;
543
static int hf_extras_nmeta;
544
static int hf_extras_nru;
545
static int hf_extras_bytes_to_ack;
546
static int hf_extras_delete_time;
547
static int hf_extras_delete_unused;
548
static int hf_extras_system_event_id;
549
static int hf_extras_system_event_version;
550
static int hf_extras_pathlen;
551
static int hf_extras_dcp_oso_snapshot_flags;
552
static int hf_server_extras_cccp_epoch;
553
static int hf_server_extras_cccp_revno;
554
static int hf_server_clustermap_value;
555
static int hf_server_authentication;
556
static int hf_server_external_users;
557
static int hf_server_get_authorization;
558
559
static int hf_key;
560
static int hf_path;
561
static int hf_value;
562
static int hf_uint64_response;
563
static int hf_observe;
564
static int hf_observe_vbucket;
565
static int hf_observe_keylength;
566
static int hf_observe_key;
567
static int hf_observe_status;
568
static int hf_observe_cas;
569
static int hf_observe_vbucket_uuid;
570
static int hf_observe_failed_over;
571
static int hf_observe_last_persisted_seqno;
572
static int hf_observe_current_seqno;
573
static int hf_observe_old_vbucket_uuid;
574
static int hf_observe_last_received_seqno;
575
576
static int hf_get_errmap_version;
577
578
static int hf_failover_log;
579
static int hf_failover_log_size;
580
static int hf_failover_log_vbucket_uuid;
581
static int hf_failover_log_vbucket_seqno;
582
583
static int hf_vbucket_states;
584
static int hf_vbucket_states_state;
585
static int hf_vbucket_states_size;
586
static int hf_vbucket_states_id;
587
static int hf_vbucket_states_seqno;
588
589
static int hf_bucket_type;
590
static int hf_bucket_config;
591
static int hf_config_key;
592
static int hf_config_value;
593
594
static int hf_multipath_opcode;
595
static int hf_multipath_index;
596
static int hf_multipath_pathlen;
597
static int hf_multipath_path;
598
static int hf_multipath_valuelen;
599
static int hf_multipath_value;
600
601
static int hf_meta_flags;
602
static int hf_meta_expiration;
603
static int hf_meta_revseqno;
604
static int hf_meta_cas;
605
static int hf_skip_conflict;
606
static int hf_force_accept;
607
static int hf_regenerate_cas;
608
static int hf_force_meta;
609
static int hf_is_expiration;
610
static int hf_meta_options;
611
static int hf_metalen;
612
static int hf_meta_reqextmeta;
613
static int hf_meta_deleted;
614
static int hf_exptime;
615
static int hf_extras_meta_seqno;
616
static int hf_confres;
617
static int hf_hello_features;
618
static int hf_hello_features_feature;
619
620
static int hf_xattr_length;
621
static int hf_xattr_pair_length;
622
static int hf_xattr_key;
623
static int hf_xattr_value;
624
static int hf_xattrs;
625
626
static int hf_flex_extras;
627
static int hf_flex_extras_n;
628
static int hf_flex_frame_id_byte0;
629
static int hf_flex_frame_id_req;
630
static int hf_flex_frame_id_res;
631
static int hf_flex_frame_id_req_esc;
632
static int hf_flex_frame_id_res_esc;
633
static int hf_flex_frame_len;
634
static int hf_flex_frame_len_esc;
635
static int hf_flex_frame_tracing_duration;
636
static int hf_flex_frame_ru_count;
637
static int hf_flex_frame_wu_count;
638
static int hf_flex_frame_durability_req;
639
static int hf_flex_frame_dcp_stream_id;
640
static int hf_flex_frame_impersonated_user;
641
642
static int hf_range_scan_uuid;
643
static int hf_range_scan_item_limit;
644
static int hf_range_scan_time_limit;
645
static int hf_range_scan_byte_limit;
646
647
static expert_field ei_warn_shall_not_have_value;
648
static expert_field ei_warn_shall_not_have_extras;
649
static expert_field ei_warn_shall_not_have_key;
650
static expert_field ei_compression_error;
651
static expert_field ei_warn_unknown_flex_unsupported;
652
static expert_field ei_warn_unknown_flex_id;
653
static expert_field ei_warn_unknown_flex_len;
654
655
static expert_field ei_value_missing;
656
static expert_field ei_warn_must_have_extras;
657
static expert_field ei_warn_must_have_key;
658
static expert_field ei_warn_illegal_extras_length;
659
static expert_field ei_warn_illegal_value_length;
660
static expert_field ei_warn_unknown_magic_byte;
661
static expert_field ei_warn_unknown_opcode;
662
static expert_field ei_warn_unknown_extras;
663
static expert_field ei_note_status_code;
664
static expert_field ei_separator_not_found;
665
static expert_field ei_illegal_value;
666
667
static int ett_couchbase;
668
static int ett_extras;
669
static int ett_extras_flags;
670
static int ett_observe;
671
static int ett_failover_log;
672
static int ett_vbucket_states;
673
static int ett_multipath;
674
static int ett_config;
675
static int ett_config_key;
676
static int ett_hello_features;
677
static int ett_datatype;
678
static int ett_xattrs;
679
static int ett_xattr_pair;
680
static int ett_flex_frame_extras;
681
static int ett_collection_key;
682
683
static const value_string magic_vals[] = {
684
  { MAGIC_CLIENT_REQUEST, "Request" },
685
  { MAGIC_CLIENT_RESPONSE, "Response" },
686
  { MAGIC_CLIENT_RESPONSE_FLEX, "Response with flexible framing extras" },
687
  { MAGIC_CLIENT_REQUEST_FLEX, "Request with flexible framing extras" },
688
  { MAGIC_SERVER_REQUEST, "Server Request"},
689
  { MAGIC_SERVER_RESPONSE, "Server Response"},
690
  { 0, NULL }
691
};
692
693
12.8k
#define FLEX_ESCAPE 0x0F
694
695
/*
696
  The flex extension identifiers are different for request/response
697
  i.e. 0 in a response is not 0 in a request
698
  Response IDs
699
 */
700
#define FLEX_RESPONSE_ID_RX_TX_DURATION 0
701
#define FLEX_RESPONSE_ID_RU_USAGE 1
702
#define FLEX_RESPONSE_ID_WU_USAGE 2
703
704
/* Request IDs */
705
#define FLEX_REQUEST_ID_REORDER 0
706
#define FLEX_REQUEST_ID_DURABILITY 1
707
#define FLEX_REQUEST_ID_DCP_STREAM_ID 2
708
#define FLEX_REQUEST_ID_OPEN_TRACING 3
709
#define FLEX_REQUEST_ID_IMPERSONATE 4
710
#define FLEX_REQUEST_ID_PRESERVE_TTL 5
711
712
static const value_string flex_frame_response_ids[] = {
713
  { FLEX_RESPONSE_ID_RX_TX_DURATION, "Server Recv->Send duration"},
714
  { FLEX_RESPONSE_ID_RU_USAGE, "Read units"},
715
  { FLEX_RESPONSE_ID_WU_USAGE, "Write units"},
716
  { 0, NULL }
717
};
718
719
static const value_string flex_frame_request_ids[] = {
720
  { FLEX_REQUEST_ID_REORDER, "Out of order Execution"},
721
  { FLEX_REQUEST_ID_DURABILITY, "Durability Requirements"},
722
  { FLEX_REQUEST_ID_DCP_STREAM_ID, "DCP Stream Identifier"},
723
  { FLEX_REQUEST_ID_OPEN_TRACING, "Open Tracing"},
724
  { FLEX_REQUEST_ID_IMPERSONATE, "Impersonate User"},
725
  { FLEX_REQUEST_ID_PRESERVE_TTL, "Preserve TTL"},
726
  { 0, NULL }
727
};
728
729
static const value_string flex_frame_durability_req[] = {
730
  { 1, "Majority"},
731
  { 2, "Majority and persist on active"},
732
  { 3, "Persist to majority"},
733
  { 0, NULL }
734
};
735
736
static const value_string status_vals[] = {
737
  { STATUS_SUCCESS,           "Success"                 },
738
  { STATUS_KEY_ENOENT,        "Key not found"           },
739
  { STATUS_KEY_EEXISTS,       "Key exists"              },
740
  { STATUS_E2BIG,             "Value too big"           },
741
  { STATUS_EINVAL,            "Invalid arguments"       },
742
  { STATUS_NOT_STORED,        "Key not stored"          },
743
  { STATUS_DELTA_BADVAL,      "Bad value to incr/decr"  },
744
  { STATUS_NOT_MY_VBUCKET,    "Not my vBucket"          },
745
  { STATUS_NO_VBUCKET,        "Not connected to a bucket" },
746
  { STATUS_LOCKED,            "The requested resource is locked" },
747
  { STATUS_DCP_STREAM_NOT_FOUND, "No DCP Stream for this request" },
748
  { STATUS_OPAQUE_NO_MATCH,   "Opaque does not match" },
749
  { STATUS_EWOULDTHROTTLE,    "Command would have been throttled" },
750
  { STATUS_ECONFIGONLY,       "Command can't be executed in config-only bucket" },
751
  { STATUS_NOT_LOCKED,        "Unlock request for an unlocked document" },
752
  { STATUS_AUTH_STALE,        "Authentication context is stale. Should reauthenticate." },
753
  { STATUS_AUTH_ERROR,        "Authentication error"    },
754
  { STATUS_AUTH_CONTINUE,     "Authentication continue" },
755
  { STATUS_ERANGE,            "Range error"             },
756
  { STATUS_ROLLBACK,          "Rollback"                },
757
  { STATUS_EACCESS,           "Access error"            },
758
  { STATUS_NOT_INITIALIZED,
759
    "The Couchbase cluster is currently initializing this node, and "
760
    "the Cluster manager has not yet granted all users access to the cluster."},
761
  { STATUS_RATELIMITED_NETWORK_INGRESS, "Rate limit: Network ingress"},
762
  { STATUS_RATELIMITED_NETWORK_EGRESS, "Rate limit: Network Egress"},
763
  { STATUS_RATELIMITED_MAX_CONNECTIONS, "Rate limit: Max Connections"},
764
  { STATUS_RATELIMITED_MAX_COMMANDS, "Rate limit: Max Commands"},
765
  {STATUS_SCOPE_SIZE_LIMIT_EXCEEDED, "To much data in Scope"},
766
  { STATUS_UNKNOWN_COMMAND,   "Unknown command"         },
767
  { STATUS_ENOMEM,            "Out of memory"           },
768
  { STATUS_NOT_SUPPORTED,     "Command isn't supported" },
769
  { STATUS_EINTERNAL,         "Internal error"          },
770
  { STATUS_EBUSY,             "Server is busy"          },
771
  { STATUS_ETMPFAIL,          "Temporary failure"       },
772
  { STATUS_XATTR_EINVAL,
773
    "There is something wrong with the syntax of the provided XATTR."},
774
  { STATUS_UNKNOWN_COLLECTION,
775
    "Operation attempted with an unknown collection."},
776
  { STATUS_NO_COLLECTIONS_MANIFEST,
777
    "No collections manifest has been set"},
778
  { STATUS_CANNOT_APPLY_MANIFEST,
779
    "Cannot apply the given manifest"},
780
  { STATUS_MANIFEST_IS_AHEAD,
781
    "Operation attempted with a manifest ahead of the server"},
782
  { STATUS_UNKNOWN_SCOPE,
783
    "Operation attempted with an unknown scope."},
784
  { STATUS_DCP_STREAMID_INVALID,
785
    "DCP Stream ID is invalid"},
786
  { STATUS_DURABILITY_INVALID_LEVEL,
787
    "The specified durability level is invalid" },
788
  { STATUS_DURABILITY_IMPOSSIBLE,
789
    "The specified durability requirements are not currently possible" },
790
  { STATUS_SYNC_WRITE_IN_PROGRESS,
791
    "A SyncWrite is already in progress on the specified key"},
792
  { STATUS_SYNC_WRITE_AMBIGUOUS,
793
    "The SyncWrite request has not completed in the specified time and has ambiguous result"},
794
  { STATUS_SYNC_WRITE_RECOMMIT_IN_PROGRESS,
795
    "The SyncWrite is being re-committed after a change in active node"},
796
  { STATUS_RANGE_SCAN_CANCELLED, "RangeScan was cancelled"},
797
  { STATUS_RANGE_SCAN_MORE, "RangeScan has more data available"},
798
  { STATUS_RANGE_SCAN_COMPLETE, "RangeScan has completed"},
799
  { STATUS_VBUUID_NOT_EQUAL, "VB UUID does not equal server value"},
800
  { STATUS_SUBDOC_PATH_ENOENT,
801
    "Subdoc: Path not does not exist"},
802
  { STATUS_SUBDOC_PATH_MISMATCH,
803
    "Subdoc: Path mismatch"},
804
  { STATUS_SUBDOC_PATH_EINVAL,
805
    "Subdoc: Invalid path"},
806
  { STATUS_SUBDOC_PATH_E2BIG,
807
    "Subdoc: Path too large"},
808
  { STATUS_SUBDOC_DOC_E2DEEP,
809
    "Subdoc: Document too deep"},
810
  { STATUS_SUBDOC_VALUE_CANTINSERT,
811
    "Subdoc: Cannot insert specified value"},
812
  { STATUS_SUBDOC_DOC_NOTJSON,
813
    "Subdoc: Existing document not JSON"},
814
  { STATUS_SUBDOC_NUM_ERANGE,
815
    "Subdoc: Existing number outside valid arithmetic range"},
816
  { STATUS_SUBDOC_DELTA_ERANGE,
817
    "Subdoc: Delta outside valid arithmetic range"},
818
  { STATUS_SUBDOC_PATH_EEXISTS,
819
    "Subdoc: Document path already exists"},
820
  { STATUS_SUBDOC_VALUE_ETOODEEP,
821
    "Subdoc: Inserting value would make document too deep"},
822
  { STATUS_SUBDOC_INVALID_COMBO,
823
    "Subdoc: Invalid combination for multi-path command"},
824
  { STATUS_SUBDOC_MULTI_PATH_FAILURE,
825
    "Subdoc: One or more paths in a multi-path command failed"},
826
  { STATUS_SUBDOC_SUCCESS_DELETED,
827
    "Subdoc: The operation completed successfully, but operated on a deleted document."},
828
  { STATUS_SUBDOC_XATTR_INVALID_FLAG_COMBO,
829
    "Subdoc: The combination of the subdoc flags for the xattrs doesn't make any sense."},
830
  { STATUS_SUBDOC_XATTR_INVALID_KEY_COMBO,
831
    "Subdoc: Only a single xattr key may be accessed at the same time."},
832
  { STATUS_SUBDOC_XATTR_UNKNOWN_MACRO,
833
    "Subdoc: The server has no knowledge of the requested macro."},
834
  { STATUS_SUBDOC_XATTR_UNKNOWN_VATTR,
835
    "Subdoc: The server has no knowledge of the requested virtual xattr."},
836
  { STATUS_SUBDOC_XATTR_CANT_MODIFY_VATTR,
837
    "Subdoc: Virtual xattrs can't be modified."},
838
  { STATUS_SUBDOC_MULTI_PATH_FAILURE_DELETED,
839
    "Subdoc: Specified key was found as a deleted document, but one or more path operations failed."},
840
  { STATUS_SUBDOC_INVALID_XATTR_ORDER,
841
    "Subdoc: According to the spec all xattr commands should come first, followed by the commands for the document body."},
842
  { STATUS_SUBDOC_XATTR_UNKNOWN_VATTR_MACRO,
843
    "Subdoc: The server does not know about this virtual macro."},
844
  { STATUS_SUBDOC_CAN_ONLY_REVIVE_DELETED_DOCUMENTS,
845
    "Subdoc: The document isn't dead (and we wanted to revive the document)."},
846
  { STATUS_SUBDOC_DELETED_DOCUMENT_CANT_HAVE_VALUE,
847
    "Subdoc: A deleted document can't have a user value."},
848
  { 0, NULL }
849
};
850
851
static value_string_ext status_vals_ext = VALUE_STRING_EXT_INIT(status_vals);
852
853
static const value_string client_opcode_vals[] = {
854
  { CLIENT_OPCODE_GET,                        "Get"                      },
855
  { CLIENT_OPCODE_SET,                        "Set"                      },
856
  { CLIENT_OPCODE_ADD,                        "Add"                      },
857
  { CLIENT_OPCODE_REPLACE,                    "Replace"                  },
858
  { CLIENT_OPCODE_DELETE,                     "Delete"                   },
859
  { CLIENT_OPCODE_INCREMENT,                  "Increment"                },
860
  { CLIENT_OPCODE_DECREMENT,                  "Decrement"                },
861
  { CLIENT_OPCODE_QUIT,                       "Quit"                     },
862
  { CLIENT_OPCODE_FLUSH,                      "Flush"                    },
863
  { CLIENT_OPCODE_GETQ,                       "Get Quietly"              },
864
  { CLIENT_OPCODE_NOOP,                       "NOOP"                     },
865
  { CLIENT_OPCODE_VERSION,                    "Version"                  },
866
  { CLIENT_OPCODE_GETK,                       "Get Key"                  },
867
  { CLIENT_OPCODE_GETKQ,                      "Get Key Quietly"          },
868
  { CLIENT_OPCODE_APPEND,                     "Append"                   },
869
  { CLIENT_OPCODE_PREPEND,                    "Prepend"                  },
870
  { CLIENT_OPCODE_STAT,                       "Statistics"               },
871
  { CLIENT_OPCODE_SETQ,                       "Set Quietly"              },
872
  { CLIENT_OPCODE_ADDQ,                       "Add Quietly"              },
873
  { CLIENT_OPCODE_REPLACEQ,                   "Replace Quietly"          },
874
  { CLIENT_OPCODE_DELETEQ,                    "Delete Quietly"           },
875
  { CLIENT_OPCODE_INCREMENTQ,                 "Increment Quietly"        },
876
  { CLIENT_OPCODE_DECREMENTQ,                 "Decrement Quietly"        },
877
  { CLIENT_OPCODE_QUITQ,                      "Quit Quietly"             },
878
  { CLIENT_OPCODE_FLUSHQ,                     "Flush Quietly"            },
879
  { CLIENT_OPCODE_APPENDQ,                    "Append Quietly"           },
880
  { CLIENT_OPCODE_PREPENDQ,                   "Prepend Quietly"          },
881
  { CLIENT_OPCODE_VERBOSITY,                  "Verbosity"                },
882
  { CLIENT_OPCODE_TOUCH,                      "Touch"                    },
883
  { CLIENT_OPCODE_GAT,                        "Get and Touch"            },
884
  { CLIENT_OPCODE_GATQ,                       "Gat and Touch Quietly"    },
885
  { CLIENT_OPCODE_HELLO,                      "Hello"                    },
886
  { CLIENT_OPCODE_SASL_LIST_MECHS,            "List SASL Mechanisms"     },
887
  { CLIENT_OPCODE_SASL_AUTH,                  "SASL Authenticate"        },
888
  { CLIENT_OPCODE_SASL_STEP,                  "SASL Step"                },
889
  { CLIENT_OPCODE_IOCTL_GET,                  "IOCTL Get"                },
890
  { CLIENT_OPCODE_IOCTL_SET,                  "IOCTL Set"                },
891
  { CLIENT_OPCODE_CONFIG_VALIDATE,            "Config Validate"          },
892
  { CLIENT_OPCODE_CONFIG_RELOAD,              "Config Reload"            },
893
  { CLIENT_OPCODE_AUDIT_PUT,                  "Audit Put"                },
894
  { CLIENT_OPCODE_AUDIT_CONFIG_RELOAD,        "Audit Config Reload"      },
895
  { CLIENT_OPCODE_SHUTDOWN,                   "Shutdown"                 },
896
  { CLIENT_OPCODE_SET_ACTIVE_ENCRYPTION_KEYS, "Set Active Encryption Keys"},
897
  { CLIENT_OPCODE_PRUNE_ENCRYPTION_KEYS,      "Prune Encryption Keys"    },
898
  { CLIENT_OPCODE_RGET,                       "Range Get"                },
899
  { CLIENT_OPCODE_RSET,                       "Range Set"                },
900
  { CLIENT_OPCODE_RSETQ,                      "Range Set Quietly"        },
901
  { CLIENT_OPCODE_RAPPEND,                    "Range Append"             },
902
  { CLIENT_OPCODE_RAPPENDQ,                   "Range Append Quietly"     },
903
  { CLIENT_OPCODE_RPREPEND,                   "Range Prepend"            },
904
  { CLIENT_OPCODE_RPREPENDQ,                  "Range Prepend Quietly"    },
905
  { CLIENT_OPCODE_RDELETE,                    "Range Delete"             },
906
  { CLIENT_OPCODE_RDELETEQ,                   "Range Delete Quietly"     },
907
  { CLIENT_OPCODE_RINCR,                      "Range Increment"          },
908
  { CLIENT_OPCODE_RINCRQ,                     "Range Increment Quietly"  },
909
  { CLIENT_OPCODE_RDECR,                      "Range Decrement"          },
910
  { CLIENT_OPCODE_RDECRQ,                     "Range Decrement Quietly"  },
911
  { CLIENT_OPCODE_SET_VBUCKET,                "Set VBucket"              },
912
  { CLIENT_OPCODE_GET_VBUCKET,                "Get VBucket"              },
913
  { CLIENT_OPCODE_DEL_VBUCKET,                "Delete VBucket"           },
914
  { CLIENT_OPCODE_TAP_CONNECT,                "TAP Connect"              },
915
  { CLIENT_OPCODE_TAP_MUTATION,               "TAP Mutation"             },
916
  { CLIENT_OPCODE_TAP_DELETE,                 "TAP Delete"               },
917
  { CLIENT_OPCODE_TAP_FLUSH,                  "TAP Flush"                },
918
  { CLIENT_OPCODE_TAP_OPAQUE,                 "TAP Opaque"               },
919
  { CLIENT_OPCODE_TAP_VBUCKET_SET,            "TAP VBucket Set"          },
920
  { CLIENT_OPCODE_TAP_CHECKPOINT_START,       "TAP Checkpoint Start"     },
921
  { CLIENT_OPCODE_TAP_CHECKPOINT_END,         "TAP Checkpoint End"       },
922
  { CLIENT_OPCODE_GET_ALL_VB_SEQNOS,          "Get All VBucket Seqnos"   },
923
  { CLIENT_OPCODE_GET_EX,                     "GetEx"                    },
924
  { CLIENT_OPCODE_GET_EX_REPLICA,             "GetEx Replica"            },
925
  { CLIENT_OPCODE_DCP_OPEN_CONNECTION,        "DCP Open Connection"      },
926
  { CLIENT_OPCODE_DCP_ADD_STREAM,             "DCP Add Stream"           },
927
  { CLIENT_OPCODE_DCP_CLOSE_STREAM,           "DCP Close Stream"         },
928
  { CLIENT_OPCODE_DCP_STREAM_REQUEST,         "DCP Stream Request"       },
929
  { CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST,   "DCP Get Failover Log"     },
930
  { CLIENT_OPCODE_DCP_STREAM_END,             "DCP Stream End"           },
931
  { CLIENT_OPCODE_DCP_SNAPSHOT_MARKER,        "DCP Snapshot Marker"      },
932
  { CLIENT_OPCODE_DCP_MUTATION,               "DCP (Key) Mutation"       },
933
  { CLIENT_OPCODE_DCP_DELETION,               "DCP (Key) Deletion"       },
934
  { CLIENT_OPCODE_DCP_EXPIRATION,             "DCP (Key) Expiration"     },
935
  { CLIENT_OPCODE_DCP_FLUSH,                  "DCP Flush"                },
936
  { CLIENT_OPCODE_DCP_SET_VBUCKET_STATE,      "DCP Set VBucket State"    },
937
  { CLIENT_OPCODE_DCP_NOOP,                   "DCP NOOP"                 },
938
  { CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT, "DCP Buffer Acknowledgement"},
939
  { CLIENT_OPCODE_DCP_CONTROL,                "DCP Control"              },
940
  { CLIENT_OPCODE_DCP_SYSTEM_EVENT,           "DCP System Event"         },
941
  { CLIENT_OPCODE_DCP_PREPARE,                "DCP Prepare"              },
942
  { CLIENT_OPCODE_DCP_SEQNO_ACK,              "DCP Seqno Acknowledgement"},
943
  { CLIENT_OPCODE_DCP_COMMIT,                 "DCP Commit"               },
944
  { CLIENT_OPCODE_DCP_ABORT,                  "DCP Abort"                },
945
  { CLIENT_OPCODE_DCP_SEQNO_ADVANCED,         "DCP Seqno Advanced"       },
946
  { CLIENT_OPCODE_DCP_OSO_SNAPSHOT,           "DCP Out of Sequence Order Snapshot"},
947
  { CLIENT_OPCODE_GET_FUSION_STORAGE_SNAPSHOT, "Get Fusion Storage Snapshot"},
948
  { CLIENT_OPCODE_RELEASE_FUSION_STORAGE_SNAPSHOT, "Release Fusion Storage Snapshot"},
949
  { CLIENT_OPCODE_MOUNT_FUSION_VB,            "Mount Fusion VBucket"     },
950
  { CLIENT_OPCODE_UNMOUNT_FUSION_VB,          "Unmount Fusion VBucket"   },
951
  { CLIENT_OPCODE_SYNC_FUSION_LOGSTORE,       "Sync Fusion Logstore"     },
952
  { CLIENT_OPCODE_START_FUSION_UPLOADER,      "Start Fusion Uploader"    },
953
  { CLIENT_OPCODE_STOP_FUSION_UPLOADER,       "Stop Fusion Uploader"     },
954
  { CLIENT_OPCODE_DELETE_FUSION_NAMESPACE,    "Delete Fusion Namespace"  },
955
  { CLIENT_OPCODE_GET_FUSION_NAMESPACES,      "Get Fusion Namespaces"    },
956
  { CLIENT_OPCODE_STOP_PERSISTENCE,           "Stop Persistence"         },
957
  { CLIENT_OPCODE_START_PERSISTENCE,          "Start Persistence"        },
958
  { CLIENT_OPCODE_SET_PARAM,                  "Set Parameter"            },
959
  { CLIENT_OPCODE_GET_REPLICA,                "Get Replica"              },
960
  { CLIENT_OPCODE_CREATE_BUCKET,              "Create Bucket"            },
961
  { CLIENT_OPCODE_DELETE_BUCKET,              "Delete Bucket"            },
962
  { CLIENT_OPCODE_LIST_BUCKETS,               "List Buckets"             },
963
  { CLIENT_OPCODE_EXPAND_BUCKET,              "Expand Bucket"            },
964
  { CLIENT_OPCODE_SELECT_BUCKET,              "Select Bucket"            },
965
  { CLIENT_OPCODE_START_REPLICATION,          "Start Replication"        },
966
  { CLIENT_OPCODE_OBSERVE_SEQNO,              "Observe Sequence Number"  },
967
  { CLIENT_OPCODE_OBSERVE,                    "Observe"                  },
968
  { CLIENT_OPCODE_EVICT_KEY,                  "Evict Key"                },
969
  { CLIENT_OPCODE_GET_LOCKED,                 "Get Locked"               },
970
  { CLIENT_OPCODE_UNLOCK_KEY,                 "Unlock Key"               },
971
  { CLIENT_OPCODE_SYNC,                       "Sync"                     },
972
  { CLIENT_OPCODE_LAST_CLOSED_CHECKPOINT,     "Last Closed Checkpoint"   },
973
  { CLIENT_OPCODE_RESTORE_FILE,               "Restore File"             },
974
  { CLIENT_OPCODE_RESTORE_ABORT,              "Restore Abort"            },
975
  { CLIENT_OPCODE_RESTORE_COMPLETE,           "Restore Complete"         },
976
  { CLIENT_OPCODE_ONLINE_UPDATE_START,        "Online Update Start"      },
977
  { CLIENT_OPCODE_ONLINE_UPDATE_COMPLETE,     "Online Update Complete"   },
978
  { CLIENT_OPCODE_ONLINE_UPDATE_REVERT,       "Online Update Revert"     },
979
  { CLIENT_OPCODE_DEREGISTER_TAP_CLIENT,      "Deregister TAP Client"    },
980
  { CLIENT_OPCODE_RESET_REPLICATION_CHAIN,    "Reset Replication Chain"  },
981
  { CLIENT_OPCODE_GET_META,                   "Get Meta"                 },
982
  { CLIENT_OPCODE_GETQ_META,                  "Get Meta Quietly"         },
983
  { CLIENT_OPCODE_SET_WITH_META,              "Set with Meta"            },
984
  { CLIENT_OPCODE_SETQ_WITH_META,             "Set with Meta Quietly"    },
985
  { CLIENT_OPCODE_ADD_WITH_META,              "Add with Meta"            },
986
  { CLIENT_OPCODE_ADDQ_WITH_META,             "Add with Meta Quietly"    },
987
  { CLIENT_OPCODE_SNAPSHOT_VB_STATES,         "Snapshot VBuckets States" },
988
  { CLIENT_OPCODE_VBUCKET_BATCH_COUNT,        "VBucket Batch Count"      },
989
  { CLIENT_OPCODE_DEL_WITH_META,              "Delete with Meta"         },
990
  { CLIENT_OPCODE_DELQ_WITH_META,             "Delete with Meta Quietly" },
991
  { CLIENT_OPCODE_CREATE_CHECKPOINT,          "Create Checkpoint"        },
992
  { CLIENT_OPCODE_NOTIFY_VBUCKET_UPDATE,      "Notify VBucket Update"    },
993
  { CLIENT_OPCODE_ENABLE_TRAFFIC,             "Enable Traffic"           },
994
  { CLIENT_OPCODE_DISABLE_TRAFFIC,            "Disable Traffic"          },
995
  { CLIENT_OPCODE_IFCONFIG,                   "Ifconfig"                 },
996
  { CLIENT_OPCODE_CHANGE_VB_FILTER,           "Change VBucket Filter"    },
997
  { CLIENT_OPCODE_CHECKPOINT_PERSISTENCE,     "Checkpoint Persistence"   },
998
  { CLIENT_OPCODE_RETURN_META,                "Return Meta"              },
999
  { CLIENT_OPCODE_COMPACT_DB,                 "Compact Database"         },
1000
  { CLIENT_OPCODE_SET_CLUSTER_CONFIG,         "Set Cluster Config"       },
1001
  { CLIENT_OPCODE_GET_CLUSTER_CONFIG,         "Get Cluster Config"       },
1002
  { CLIENT_OPCODE_GET_RANDOM_KEY,             "Get Random Key"           },
1003
  { CLIENT_OPCODE_SEQNO_PERSISTENCE,          "Seqno Persistence"        },
1004
  { CLIENT_OPCODE_GET_KEYS,                   "Get Keys"                 },
1005
  { CLIENT_OPCODE_COLLECTIONS_SET_MANIFEST,   "Set Collection's Manifest" },
1006
  { CLIENT_OPCODE_COLLECTIONS_GET_MANIFEST,   "Get Collection's Manifest" },
1007
  { CLIENT_OPCODE_COLLECTIONS_GET_ID,         "Get Collection ID"        },
1008
  { CLIENT_OPCODE_COLLECTIONS_GET_SCOPE_ID,   "Get Scope ID"             },
1009
  { CLIENT_OPCODE_SET_DRIFT_COUNTER_STATE,    "Set Drift Counter State"  },
1010
  { CLIENT_OPCODE_GET_ADJUSTED_TIME,          "Get Adjusted Time"        },
1011
  { CLIENT_OPCODE_SUBDOC_GET,                 "Subdoc Get"               },
1012
  { CLIENT_OPCODE_SUBDOC_EXISTS,              "Subdoc Exists"            },
1013
  { CLIENT_OPCODE_SUBDOC_DICT_ADD,            "Subdoc Dictionary Add"    },
1014
  { CLIENT_OPCODE_SUBDOC_DICT_UPSERT,         "Subdoc Dictionary Upsert" },
1015
  { CLIENT_OPCODE_SUBDOC_DELETE,              "Subdoc Delete"            },
1016
  { CLIENT_OPCODE_SUBDOC_REPLACE,             "Subdoc Replace"           },
1017
  { CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST,     "Subdoc Array Push Last"   },
1018
  { CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST,    "Subdoc Array Push First"  },
1019
  { CLIENT_OPCODE_SUBDOC_ARRAY_INSERT,        "Subdoc Array Insert"      },
1020
  { CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE,    "Subdoc Array Add Unique"  },
1021
  { CLIENT_OPCODE_SUBDOC_COUNTER,             "Subdoc Counter"           },
1022
  { CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP,        "Subdoc Multipath Lookup"  },
1023
  { CLIENT_OPCODE_SUBDOC_MULTI_MUTATION,      "Subdoc Multipath Mutation"},
1024
  { CLIENT_OPCODE_SUBDOC_GET_COUNT,           "Subdoc Get Count"         },
1025
  { CLIENT_OPCODE_SUBDOC_REPLACE_BODY_WITH_XATTR, "Subdoc Replace Body With Xattr"},
1026
  { CLIENT_OPCODE_RANGE_SCAN_CREATE,          "RangeScan Create"         },
1027
  { CLIENT_OPCODE_RANGE_SCAN_CONTINUE,        "RangeScan Continue"       },
1028
  { CLIENT_OPCODE_RANGE_SCAN_CANCEL,          "RangeScan Cancel"         },
1029
  { CLIENT_OPCODE_PREPARE_SNAPSHOT,           "Prepare Snapshot"         },
1030
  { CLIENT_OPCODE_RELEASE_SNAPSHOT,           "Release Snapshot"         },
1031
  { CLIENT_OPCODE_DOWNLOAD_SNAPSHOT,          "Download Snapshot"        },
1032
  { CLIENT_OPCODE_GET_FILE_FRAGMENT,          "Get File Fragment"        },
1033
  { CLIENT_OPCODE_SCRUB,                      "Scrub"                    },
1034
  { CLIENT_OPCODE_ISASL_REFRESH,              "isasl Refresh"            },
1035
  { CLIENT_OPCODE_SSL_CERTS_REFRESH,          "SSL Certificates Refresh" },
1036
  { CLIENT_OPCODE_GET_CMD_TIMER,              "Internal Timer Control"   },
1037
  { CLIENT_OPCODE_SET_CTRL_TOKEN,             "Set Control Token"        },
1038
  { CLIENT_OPCODE_GET_CTRL_TOKEN,             "Get Control Token"        },
1039
  { CLIENT_OPCODE_UPDATE_EXTERNAL_USER_PERMISSIONS, "Update External User Permissions"},
1040
  { CLIENT_OPCODE_RBAC_REFRESH,               "RBAC Refresh"             },
1041
  { CLIENT_OPCODE_AUTH_PROVIDER,              "Auth Provider"            },
1042
  { CLIENT_OPCODE_DROP_PRIVILEGE,             "Drop Privilege"           },
1043
  { CLIENT_OPCODE_ADJUST_TIMEOFDAY,           "Adjust Timeofday"         },
1044
  { CLIENT_OPCODE_EWOULDBLOCK_CTL,            "EWOULDBLOCK Control"      },
1045
  { CLIENT_OPCODE_GET_ERROR_MAP,              "Get Error Map"            },
1046
  /* Internally defined values not valid here */
1047
  { 0, NULL }
1048
};
1049
1050
static value_string_ext client_opcode_vals_ext = VALUE_STRING_EXT_INIT(client_opcode_vals);
1051
1052
typedef enum {
1053
    SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION = 0x01,
1054
    SERVER_OPCODE_AUTHENTICATE = 0x02,
1055
    SERVER_OPCODE_ACTIVE_EXTERNAL_USERS = 0x03,
1056
    SERVER_OPCODE_GET_AUTHORIZATION = 0x04
1057
} server_opcode_t;
1058
1059
static const value_string server_opcode_vals[] = {
1060
        { SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION, "ClustermapChangeNotification"},
1061
        { SERVER_OPCODE_AUTHENTICATE, "Authenticate"},
1062
        { SERVER_OPCODE_ACTIVE_EXTERNAL_USERS, "ActiveExternalUsers"},
1063
        { SERVER_OPCODE_GET_AUTHORIZATION, "GetAuthorization"},
1064
        {0, NULL}
1065
};
1066
static value_string_ext server_opcode_vals_ext = VALUE_STRING_EXT_INIT(server_opcode_vals);
1067
1068
static const value_string dcp_connection_type_vals[] = {
1069
  {0, "Consumer"},
1070
  {1, "Producer"},
1071
  {2, "Notifier"},
1072
  {0, NULL}
1073
};
1074
1075
static const value_string vbucket_states_vals[] = {
1076
  {1, "Active"},
1077
  {2, "Replica"},
1078
  {3, "Pending"},
1079
  {4, "Dead"},
1080
  {0, NULL}
1081
};
1082
1083
static int * const datatype_vals[] = {
1084
  &hf_datatype_json,
1085
  &hf_datatype_snappy,
1086
  &hf_datatype_xattr,
1087
  NULL
1088
};
1089
1090
static int * const subdoc_flags[] = {
1091
  &hf_subdoc_flags_mkdirp,
1092
  &hf_subdoc_flags_xattrpath,
1093
  &hf_subdoc_flags_expandmacros,
1094
  &hf_subdoc_flags_reserved,
1095
  NULL
1096
};
1097
1098
static int * const subdoc_doc_flags[] = {
1099
  &hf_subdoc_doc_flags_mkdoc,
1100
  &hf_subdoc_doc_flags_add,
1101
  &hf_subdoc_doc_flags_accessdeleted,
1102
  &hf_subdoc_doc_flags_createasdeleted,
1103
  &hf_subdoc_doc_flags_revivedocument,
1104
  &hf_subdoc_doc_flags_replicaread,
1105
  &hf_subdoc_doc_flags_reserved,
1106
  NULL
1107
};
1108
1109
static int * const set_with_meta_extra_flags[] = {
1110
        &hf_force_meta,
1111
        &hf_force_accept,
1112
        &hf_regenerate_cas,
1113
        &hf_skip_conflict,
1114
        NULL
1115
};
1116
1117
static int * const del_with_meta_extra_flags[] = {
1118
        &hf_force_meta,
1119
        &hf_force_accept,
1120
        &hf_regenerate_cas,
1121
        &hf_skip_conflict,
1122
        &hf_is_expiration,
1123
        NULL
1124
};
1125
1126
static const value_string feature_vals[] = {
1127
  {0x01, "Datatype (deprecated)"},
1128
  {0x02, "TLS"},
1129
  {0x03, "TCP Nodelay"},
1130
  {0x04, "Mutation Seqno"},
1131
  {0x05, "TCP Delay"},
1132
  {0x06, "XATTR"},
1133
  {0x07, "Error Map"},
1134
  {0x08, "Select Bucket"},
1135
  {0x09, "Collections (deprecated)"},
1136
  {0x0a, "Snappy"},
1137
  {0x0b, "JSON"},
1138
  {0x0c, "Duplex"},
1139
  {0x0d, "Clustermap Change Notification"},
1140
  {0x0e, "Unordered Execution"},
1141
  {0x0f, "Tracing"},
1142
  {0x10, "AltRequestSupport"},
1143
  {0x11, "SyncReplication"},
1144
  {0x12, "Collections"},
1145
  {0x13, "OpenTracing"},
1146
  {0x14, "PreserveTtl"},
1147
  {0x15, "VAttr"},
1148
  {0x16, "Point in Time Recovery"},
1149
  {0x17, "SubdocCreateAsDeleted"},
1150
  {0x18, "SubdocDocumentMacroSupport"},
1151
  {0x19, "SubdocReplaceBodyWithXattr"},
1152
  {0x1a, "ReportUnitUsage"},
1153
  {0x1b, "NonBlockingThrottlingMode"},
1154
  {0x1c, "SubdocReplicaRead"},
1155
  {0x1d, "GetClusterConfigWithKnownVersion"},
1156
  {0x1e, "DedupeNotMyVbucketClustermap"},
1157
  {0x1f, "ClustermapChangeNotificationBrief"},
1158
  {0x20, "SubdocAllowsAccessOnMultipleXattrKeys"},
1159
  {0, NULL}
1160
};
1161
1162
static const value_string dcp_system_event_id_vals [] = {
1163
    {0, "CreateCollection"},
1164
    {1, "DropCollection"},
1165
    {2, "Unused"},
1166
    {3, "CreateScope"},
1167
    {4, "DropScope"},
1168
    {5, "ModifyCollection"},
1169
    {0, NULL}
1170
};
1171
1172
static int * const snapshot_marker_flags [] = {
1173
    &hf_extras_flags_dcp_snapshot_marker_memory,
1174
    &hf_extras_flags_dcp_snapshot_marker_disk,
1175
    &hf_extras_flags_dcp_snapshot_marker_chk,
1176
    &hf_extras_flags_dcp_snapshot_marker_ack,
1177
    &hf_extras_flags_dcp_snapshot_marker_history,
1178
    &hf_extras_flags_dcp_snapshot_marker_may_contain_dups,
1179
    NULL
1180
};
1181
1182
static dissector_handle_t couchbase_handle;
1183
static dissector_handle_t json_handle;
1184
1185
/* desegmentation of COUCHBASE payload */
1186
static bool couchbase_desegment_body = true;
1187
static unsigned couchbase_ssl_port = 11207;
1188
static unsigned couchbase_ssl_port_pref = 11207;
1189
1190
/** Read out the magic byte (located at offset 0 in the header) */
1191
1.68k
static uint8_t get_magic(tvbuff_t *tvb) {
1192
1.68k
  return tvb_get_uint8(tvb, 0);
1193
1.68k
}
1194
1195
/** Read out the opcode (located at offset 1 in the header) */
1196
562
static uint8_t get_opcode(tvbuff_t *tvb) {
1197
562
  return tvb_get_uint8(tvb, 1);
1198
562
}
1199
1200
/** Read out the status code from the header (only "valid" for response packets) */
1201
203
static uint16_t get_status(tvbuff_t *tvb) {
1202
203
  return tvb_get_ntohs(tvb, 6);
1203
203
}
1204
1205
/** Read out flex size (using the upper bits of the key length when using flex encoding) */
1206
562
static uint8_t get_flex_framing_extras_length(tvbuff_t *tvb) {
1207
562
  if (is_flex_encoded(get_magic(tvb))) {
1208
303
    return tvb_get_uint8(tvb, 2);
1209
303
  }
1210
259
  return 0;
1211
562
}
1212
1213
/** Read out the size of the extras section (located at offset 4) */
1214
562
static uint8_t get_extras_length(tvbuff_t *tvb) {
1215
562
  return tvb_get_uint8(tvb, 4);
1216
562
}
1217
1218
/** Read out the datatype section (located at offset 5) */
1219
65
static uint8_t get_datatype(tvbuff_t *tvb) {
1220
65
  return tvb_get_uint8(tvb, 5);
1221
65
}
1222
1223
/** Read out the length of the key (1 or 2 bytes depending on the encoding) */
1224
562
static uint16_t get_key_length(tvbuff_t *tvb) {
1225
562
  if (is_flex_encoded(get_magic(tvb))) {
1226
303
    return tvb_get_uint8(tvb, 3);
1227
303
  }
1228
259
  return tvb_get_ntohs(tvb, 2);
1229
562
}
1230
1231
/** Read out the size for the rest of the frame data */
1232
562
static uint32_t get_body_length(tvbuff_t *tvb) {
1233
562
  return tvb_get_ntohl(tvb, 8);
1234
562
}
1235
1236
/* Returns true if the specified opcode's response value is JSON. */
1237
static bool
1238
has_json_value(bool is_request, uint8_t opcode)
1239
54
{
1240
54
  if (is_request) {
1241
48
    switch (opcode) {
1242
0
    case CLIENT_OPCODE_AUDIT_PUT:
1243
0
    case CLIENT_OPCODE_RANGE_SCAN_CREATE:
1244
0
      return true;
1245
1246
48
    default:
1247
48
      return false;
1248
48
    }
1249
48
  } else {
1250
6
    switch (opcode) {
1251
0
    case CLIENT_OPCODE_GET_CLUSTER_CONFIG:
1252
0
    case CLIENT_OPCODE_SUBDOC_GET:
1253
0
    case CLIENT_OPCODE_COLLECTIONS_GET_MANIFEST:
1254
0
    case CLIENT_OPCODE_COLLECTIONS_SET_MANIFEST:
1255
0
      return true;
1256
1257
6
    default:
1258
6
      return false;
1259
6
    }
1260
6
  }
1261
54
}
1262
1263
static void dissect_dcp_xattrs(tvbuff_t *tvb, proto_tree *tree,
1264
                               uint32_t value_len, unsigned offset,
1265
12
                               packet_info *pinfo) {
1266
12
  uint32_t xattr_size, pair_len;
1267
12
  unsigned mark;
1268
12
  proto_tree *xattr_tree, *pair_tree;
1269
12
  proto_item *ti;
1270
1271
12
  proto_tree_add_item_ret_uint(tree, hf_xattr_length, tvb, offset, 4, ENC_BIG_ENDIAN, &xattr_size);
1272
12
  value_len = value_len - (xattr_size + 4);
1273
12
  offset += 4;
1274
1275
12
  ti = proto_tree_add_item(tree, hf_xattrs, tvb, offset, xattr_size, ENC_NA);
1276
12
  xattr_tree = proto_item_add_subtree(ti, ett_xattrs);
1277
1278
115
  while (xattr_size > 0) {
1279
1280
112
    ti = proto_tree_add_item_ret_uint(xattr_tree, hf_xattr_pair_length, tvb, offset, 4, ENC_BIG_ENDIAN, &pair_len);
1281
112
    pair_tree = proto_item_add_subtree(ti, ett_xattr_pair);
1282
112
    offset += 4;
1283
112
    xattr_size -= 4;
1284
1285
112
    if (!tvb_find_uint8_length(tvb, offset, pair_len, 0x00, &mark)) {
1286
8
      expert_add_info_format(pinfo, ti, &ei_separator_not_found, "Null byte not found");
1287
8
      return;
1288
8
    }
1289
1290
104
    ti = proto_tree_add_item(pair_tree, hf_xattr_key, tvb, offset, mark - offset, ENC_ASCII);
1291
104
    xattr_size -= (mark - offset) + 1;
1292
104
    pair_len -= (mark - offset) + 1;
1293
104
    offset = mark + 1;
1294
1295
104
    if (!tvb_find_uint8_length(tvb, offset, pair_len, 0x00, &mark)) {
1296
1
      expert_add_info_format(pinfo, ti, &ei_separator_not_found, "Null byte not found");
1297
1
      return;
1298
1
    }
1299
1300
103
    proto_tree_add_item(pair_tree, hf_xattr_value, tvb, offset, mark - offset, ENC_ASCII);
1301
103
    xattr_size -= (mark - offset) + 1;
1302
103
    offset = mark + 1;
1303
103
  }
1304
1305
  //The regular value
1306
3
  proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
1307
3
}
1308
1309
/* Dissects the required extras for subdoc single-path packets */
1310
static void
1311
dissect_subdoc_spath_required_extras(tvbuff_t *tvb, proto_tree *extras_tree,
1312
                                     uint8_t extlen, bool request, unsigned* offset,
1313
                                     uint16_t *path_len, bool *illegal)
1314
1
{
1315
1
  if (request) {
1316
0
    if (extlen >= 3) {
1317
0
      *path_len = tvb_get_ntohs(tvb, *offset);
1318
0
      proto_tree_add_item(extras_tree, hf_extras_pathlen, tvb, *offset, 2,
1319
0
                          ENC_BIG_ENDIAN);
1320
0
      *offset += 2;
1321
1322
0
      proto_tree_add_bitmask(extras_tree, tvb, *offset, hf_subdoc_flags,
1323
0
                             ett_extras_flags, subdoc_flags, ENC_BIG_ENDIAN);
1324
0
      *offset += 1;
1325
0
    } else {
1326
      /* Must always have at least 3 bytes of extras */
1327
0
      *illegal = true;
1328
0
    }
1329
0
  }
1330
1
}
1331
1332
1
static void dissect_server_request_extras(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree, unsigned offset, uint8_t extlen, uint8_t opcode) {
1333
1
  if (extlen == 0) {
1334
1
    switch (opcode) {
1335
0
      case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION:
1336
0
        proto_tree_add_expert_format(tree, pinfo, &ei_warn_must_have_extras, tvb, offset, 0,
1337
0
                                     "ClustermapChangeNotification request must have extras");
1338
0
        return;
1339
1340
0
      case SERVER_OPCODE_GET_AUTHORIZATION:
1341
0
      case SERVER_OPCODE_AUTHENTICATE:
1342
1
      case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS:
1343
        // Success! none of these commands use extras
1344
1345
1
      default:
1346
        // Probably ok as we don't know about the opcode
1347
1
        return;
1348
1
    }
1349
1
  }
1350
1351
1352
0
  proto_item *extras_item = proto_tree_add_item(tree, hf_extras, tvb, offset, extlen, ENC_NA);
1353
0
  proto_tree *extras_tree = proto_item_add_subtree(extras_item, ett_extras);
1354
1355
0
  if (opcode == SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION) {
1356
    // Expected 16 bytes of extras!
1357
0
    if (extlen < 16) {
1358
0
      proto_tree_add_expert_format(extras_tree, pinfo,
1359
0
                                   &ei_warn_illegal_extras_length, tvb,
1360
0
                                   offset, extlen,
1361
0
                                   "ClustermapChangeNotification should have 16 bytes of extras");
1362
0
      return;
1363
0
    }
1364
1365
0
    proto_tree_add_item(extras_tree, hf_server_extras_cccp_epoch, tvb, offset, 8, ENC_BIG_ENDIAN);
1366
0
    offset += 8;
1367
0
    proto_tree_add_item(extras_tree, hf_server_extras_cccp_revno, tvb, offset, 8, ENC_BIG_ENDIAN);
1368
1369
0
    if (extlen > 16) {
1370
0
      proto_tree_add_expert_format(extras_tree, pinfo,
1371
0
                                   &ei_warn_illegal_extras_length, tvb,
1372
0
                                   offset + 16, extlen - 16,
1373
0
                                   "Unexpected amount of extras");
1374
0
    }
1375
0
    return;
1376
0
  }
1377
1378
  // we don't know how to decode this!
1379
0
  proto_tree_add_item(extras_tree, hf_extras_unknown, tvb, offset, extlen, ENC_NA);
1380
0
}
1381
1382
static void
1383
dissect_server_response_extras(tvbuff_t *tvb, packet_info *pinfo,
1384
                               proto_tree *tree, unsigned offset, uint8_t extlen,
1385
0
                               uint8_t opcode _U_) {
1386
0
  if (extlen == 0) {
1387
    // Success! none of the known commands use extras
1388
0
    return;
1389
0
  }
1390
1391
0
  proto_item *extras_item = proto_tree_add_item(tree, hf_extras, tvb, offset,
1392
0
                                                extlen, ENC_NA);
1393
0
  proto_tree *extras_tree = proto_item_add_subtree(extras_item, ett_extras);
1394
0
  proto_tree_add_expert_format(extras_tree, pinfo,
1395
0
                               &ei_warn_illegal_extras_length, tvb,
1396
0
                               offset, extlen,
1397
0
                               "Unexpected amount of extras");
1398
0
}
1399
1400
static void
1401
dissect_client_extras(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1402
                      unsigned offset, uint8_t extlen, uint8_t opcode, bool request,
1403
                      uint16_t *path_len)
1404
80
{
1405
80
  proto_tree *extras_tree = NULL;
1406
80
  proto_item *extras_item = NULL;
1407
80
  unsigned    save_offset = offset;
1408
80
  unsigned    ii;
1409
80
  unsigned    bpos;
1410
80
  bool        illegal = false;  /* Set when extras shall not be present */
1411
80
  bool        missing = false;  /* Set when extras is missing */
1412
80
  bool        first_flag;
1413
80
  uint32_t    flags;
1414
80
  proto_item *tf;
1415
80
  static const char * const tap_connect_flags[] = {
1416
80
    "BACKFILL", "DUMP", "LIST_VBUCKETS", "TAKEOVER_VBUCKETS",
1417
80
    "SUPPORT_ACK", "REQUEST_KEYS_ONLY", "CHECKPOINT", "REGISTERED_CLIENT"
1418
80
  };
1419
1420
80
  *path_len = 0;
1421
1422
80
  if (extlen) {
1423
28
    extras_item = proto_tree_add_item(tree, hf_extras, tvb, offset, extlen, ENC_NA);
1424
28
    extras_tree = proto_item_add_subtree(extras_item, ett_extras);
1425
28
  }
1426
1427
80
  switch (opcode) {
1428
1429
7
  case CLIENT_OPCODE_GET:
1430
7
  case CLIENT_OPCODE_GETQ:
1431
7
  case CLIENT_OPCODE_GETK:
1432
7
  case CLIENT_OPCODE_GETKQ:
1433
7
    if (extlen) {
1434
2
      if (request) {
1435
        /* Request shall not have extras */
1436
1
        illegal = true;
1437
1
      } else {
1438
1
        proto_tree_add_item(extras_tree, hf_extras_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
1439
1
        offset += 4;
1440
1
      }
1441
5
    } else if (!request) {
1442
      /* Response must have extras */
1443
2
      missing = true;
1444
2
    }
1445
7
    break;
1446
1447
1
  case CLIENT_OPCODE_SET:
1448
1
  case CLIENT_OPCODE_SETQ:
1449
3
  case CLIENT_OPCODE_ADD:
1450
3
  case CLIENT_OPCODE_ADDQ:
1451
4
  case CLIENT_OPCODE_REPLACE:
1452
4
  case CLIENT_OPCODE_REPLACEQ:
1453
4
    if (extlen) {
1454
3
      if (request) {
1455
2
        proto_tree_add_item(extras_tree, hf_extras_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
1456
2
        offset += 4;
1457
1458
2
        proto_tree_add_item(extras_tree, hf_extras_expiration, tvb, offset, 4, ENC_BIG_ENDIAN);
1459
2
        offset += 4;
1460
2
      } else {
1461
1
        proto_tree_add_item(extras_tree, hf_extras_vbucket_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
1462
1
        offset += 8;
1463
1464
1
        proto_tree_add_item(extras_tree, hf_extras_mutation_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1465
1
        offset += 8;
1466
1
      }
1467
3
    } else if (request) {
1468
      /* Request must have extras */
1469
1
      missing = true;
1470
1
    }
1471
4
    break;
1472
1473
2
  case CLIENT_OPCODE_INCREMENT:
1474
2
  case CLIENT_OPCODE_INCREMENTQ:
1475
3
  case CLIENT_OPCODE_DECREMENT:
1476
3
  case CLIENT_OPCODE_DECREMENTQ:
1477
3
    if (extlen) {
1478
1
      if (request) {
1479
0
        proto_tree_add_item(extras_tree, hf_extras_delta, tvb, offset, 8, ENC_BIG_ENDIAN);
1480
0
        offset += 8;
1481
1482
0
        proto_tree_add_item(extras_tree, hf_extras_initial, tvb, offset, 8, ENC_BIG_ENDIAN);
1483
0
        offset += 8;
1484
1485
0
        proto_tree_add_item(extras_tree, hf_extras_expiration, tvb, offset, 4, ENC_BIG_ENDIAN);
1486
0
        offset += 4;
1487
1
      } else {
1488
1
        proto_tree_add_item(extras_tree, hf_extras_vbucket_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
1489
1
        offset += 8;
1490
1491
1
        proto_tree_add_item(extras_tree, hf_extras_mutation_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1492
1
        offset += 8;
1493
1
      }
1494
2
    } else if (request) {
1495
      /* Request must have extras */
1496
2
      missing = true;
1497
2
    }
1498
3
    break;
1499
1500
8
  case CLIENT_OPCODE_FLUSH:
1501
10
  case CLIENT_OPCODE_FLUSHQ:
1502
10
    if (extlen) {
1503
4
      proto_tree_add_item(extras_tree, hf_extras_expiration, tvb, offset, 4, ENC_BIG_ENDIAN);
1504
4
      offset += 4;
1505
4
    }
1506
10
    break;
1507
1508
0
  case CLIENT_OPCODE_DELETE:
1509
0
  case CLIENT_OPCODE_DELETEQ:
1510
0
  case CLIENT_OPCODE_APPEND:
1511
0
  case CLIENT_OPCODE_APPENDQ:
1512
0
  case CLIENT_OPCODE_PREPEND:
1513
0
  case CLIENT_OPCODE_PREPENDQ:
1514
0
    if (extlen) {
1515
0
      if (request) {
1516
        /* Must not have extras */
1517
0
        illegal = true;
1518
0
      } else {
1519
0
        proto_tree_add_item(extras_tree, hf_extras_vbucket_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
1520
0
        offset += 8;
1521
1522
0
        proto_tree_add_item(extras_tree, hf_extras_mutation_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1523
0
        offset += 8;
1524
0
      }
1525
0
    }
1526
0
    break;
1527
1528
0
  case CLIENT_OPCODE_QUIT:
1529
0
  case CLIENT_OPCODE_QUITQ:
1530
0
  case CLIENT_OPCODE_VERSION:
1531
0
  case CLIENT_OPCODE_STAT:
1532
0
  case CLIENT_OPCODE_OBSERVE:
1533
0
  case CLIENT_OPCODE_OBSERVE_SEQNO:
1534
    /* Must not have extras */
1535
0
    if (extlen) {
1536
0
      illegal = true;
1537
0
    }
1538
0
    break;
1539
1540
0
  case CLIENT_OPCODE_GET_ALL_VB_SEQNOS:
1541
0
    if (extlen) {
1542
0
      if (request) {
1543
        /* May have extras */
1544
0
        proto_tree_add_item(extras_tree, hf_vbucket_states_state, tvb, offset, 4, ENC_BIG_ENDIAN);
1545
0
        offset += 4;
1546
0
      } else {
1547
        /* Must not have extras */
1548
0
        illegal = true;
1549
0
      }
1550
0
    }
1551
0
    break;
1552
1553
4
  case CLIENT_OPCODE_TAP_CONNECT:
1554
4
    {
1555
4
    static int * const extra_flags[] = {
1556
4
        &hf_extras_flags_backfill,
1557
4
        &hf_extras_flags_dump,
1558
4
        &hf_extras_flags_list_vbuckets,
1559
4
        &hf_extras_flags_takeover_vbuckets,
1560
4
        &hf_extras_flags_support_ack,
1561
4
        &hf_extras_flags_request_keys_only,
1562
4
        &hf_extras_flags_checkpoint,
1563
4
        NULL
1564
4
    };
1565
1566
    /* TODO: extra_flags fields are 16-bits wide, whereas flags is 4 bytes? */
1567
4
    tf = proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1568
1569
4
    flags = tvb_get_ntohl(tvb, offset);
1570
4
    first_flag = true;
1571
36
    for (ii = 0; ii < array_length(tap_connect_flags); ii++) {
1572
32
      bpos = 1 << ii;
1573
32
      if (flags & bpos) {
1574
12
        if (first_flag) {
1575
3
          proto_item_append_text(tf, " (");
1576
3
        }
1577
12
        proto_item_append_text(tf, "%s%s",
1578
12
                                  first_flag ? "" : ", ",
1579
12
                                  tap_connect_flags[ii]);
1580
12
        first_flag = false;
1581
12
      }
1582
32
    }
1583
4
    if (first_flag == true) {
1584
1
      proto_item_append_text(tf, " <None>");
1585
3
    } else {
1586
3
      proto_item_append_text(tf, ")");
1587
3
    }
1588
1589
4
    offset += 4;
1590
4
    }
1591
4
    break;
1592
1593
0
  case CLIENT_OPCODE_TAP_MUTATION:
1594
1
  case CLIENT_OPCODE_TAP_DELETE:
1595
1
  case CLIENT_OPCODE_TAP_FLUSH:
1596
1
  case CLIENT_OPCODE_TAP_OPAQUE:
1597
1
  case CLIENT_OPCODE_TAP_VBUCKET_SET:
1598
1
  case CLIENT_OPCODE_TAP_CHECKPOINT_START:
1599
1
  case CLIENT_OPCODE_TAP_CHECKPOINT_END:
1600
1
    break;
1601
1602
1
  case CLIENT_OPCODE_DCP_OPEN_CONNECTION:
1603
1
    if (extlen) {
1604
1
      if (request) {
1605
1
        static int * const extra_flags[] = {
1606
1
          &hf_extras_flags_dcp_connection_type,
1607
1
          &hf_extras_flags_dcp_include_xattrs,
1608
1
          &hf_extras_flags_dcp_no_value,
1609
1
          &hf_extras_flags_dcp_collections,
1610
1
          &hf_extras_flags_dcp_include_delete_times,
1611
1
          NULL
1612
1
        };
1613
1614
1
        proto_tree_add_item(extras_tree, hf_extras_seqno, tvb, offset, 4, ENC_BIG_ENDIAN);
1615
1
        offset += 4;
1616
1
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1617
1
        offset += 4;
1618
1
      } else {
1619
        /* Response must not have extras (response is in Value) */
1620
0
        illegal = true;
1621
0
      }
1622
1
    } else if (request) {
1623
      /* Request must have extras */
1624
0
      missing = true;
1625
0
    }
1626
1
    break;
1627
1628
0
  case CLIENT_OPCODE_DCP_ADD_STREAM:
1629
0
    if (extlen) {
1630
0
      if (request) {
1631
0
        static int * const extra_flags[] = {
1632
0
          &hf_extras_flags_dcp_add_stream_takeover,
1633
0
          &hf_extras_flags_dcp_add_stream_diskonly,
1634
0
          &hf_extras_flags_dcp_add_stream_latest,
1635
0
          NULL
1636
0
        };
1637
1638
0
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1639
0
        offset += 4;
1640
0
      } else {
1641
0
        proto_tree_add_item(extras_tree, hf_extras_opaque, tvb, offset, 4, ENC_BIG_ENDIAN);
1642
0
        offset += 4;
1643
0
      }
1644
0
    } else {
1645
0
      missing = true;
1646
0
    }
1647
0
    break;
1648
1649
0
  case CLIENT_OPCODE_DCP_STREAM_REQUEST:
1650
0
    if (extlen) {
1651
0
      if (request) {
1652
        /* No extra_flags and proto_tree_add_bitmask don't work with empty flags See Bug:17890
1653
        static int * const extra_flags[] = {
1654
          NULL
1655
        };
1656
1657
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1658
        */
1659
0
        proto_tree_add_item(extras_tree, hf_extras_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
1660
0
        offset += 4;
1661
0
        proto_tree_add_item(extras_tree, hf_extras_reserved, tvb, offset, 4, ENC_BIG_ENDIAN);
1662
0
        offset += 4;
1663
0
        proto_tree_add_item(extras_tree, hf_extras_start_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1664
0
        offset += 8;
1665
0
        proto_tree_add_item(extras_tree, hf_extras_end_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1666
0
        offset += 8;
1667
0
        proto_tree_add_item(extras_tree, hf_extras_vbucket_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
1668
0
        offset += 8;
1669
0
        proto_tree_add_item(extras_tree, hf_extras_snap_start_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1670
0
        offset += 8;
1671
0
        proto_tree_add_item(extras_tree, hf_extras_snap_end_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1672
0
        offset += 8;
1673
0
      }
1674
0
    } else if (request) {
1675
      /* Request must have extras */
1676
0
      missing = true;
1677
0
    }
1678
0
    break;
1679
1680
0
  case CLIENT_OPCODE_DCP_SNAPSHOT_MARKER:
1681
0
    if (extlen) {
1682
0
      if (request) {
1683
        // Two formats exist and the extlen allows us to know which is which
1684
0
        if (extlen == 1) {
1685
0
          proto_tree_add_item(extras_tree, hf_extras_marker_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1686
0
          offset += 1;
1687
0
        } else if (extlen == 20){
1688
0
          proto_tree_add_item(extras_tree, hf_extras_start_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1689
0
          offset += 8;
1690
0
          proto_tree_add_item(extras_tree, hf_extras_end_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1691
0
          offset += 8;
1692
0
          proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, snapshot_marker_flags, ENC_BIG_ENDIAN);
1693
0
          offset += 4;
1694
0
        } else {
1695
0
          illegal = true;
1696
0
        }
1697
0
      } else {
1698
0
        illegal = true;
1699
0
      }
1700
0
    } else if (request) {
1701
      /* Request must have extras */
1702
0
      missing = true;
1703
0
    }
1704
0
    break;
1705
1706
3
  case CLIENT_OPCODE_DCP_MUTATION:
1707
3
    if (extlen) {
1708
3
      if (request) {
1709
        /* No extra_flags and proto_tree_add_bitmask don't work with empty flags See Bug:17890
1710
        static int * const extra_flags[] = {
1711
          NULL
1712
        };
1713
        */
1714
1715
3
        proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1716
3
        offset += 8;
1717
3
        proto_tree_add_item(extras_tree, hf_extras_rev_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1718
3
        offset += 8;
1719
        /*
1720
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1721
        */
1722
3
        proto_tree_add_item(extras_tree, hf_extras_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
1723
3
        offset += 4;
1724
3
        proto_tree_add_item(extras_tree, hf_extras_expiration, tvb, offset, 4, ENC_BIG_ENDIAN);
1725
3
        offset += 4;
1726
3
        proto_tree_add_item(extras_tree, hf_extras_lock_time, tvb, offset, 4, ENC_BIG_ENDIAN);
1727
3
        offset += 4;
1728
3
        proto_tree_add_item(extras_tree, hf_extras_nmeta, tvb, offset, 2, ENC_BIG_ENDIAN);
1729
3
        offset += 2;
1730
3
        proto_tree_add_item(extras_tree, hf_extras_nru, tvb, offset, 1, ENC_BIG_ENDIAN);
1731
3
        offset += 1;
1732
3
      } else {
1733
0
        illegal = true;
1734
0
      }
1735
3
    } else if (request) {
1736
      /* Request must have extras */
1737
0
      missing = true;
1738
0
    }
1739
3
    break;
1740
1741
12
  case CLIENT_OPCODE_DCP_DELETION:
1742
12
    if (request) {
1743
12
      if (extlen == 18 || extlen == 21) {
1744
0
        proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1745
0
        offset += 8;
1746
0
        proto_tree_add_item(extras_tree, hf_extras_rev_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1747
0
        offset += 8;
1748
1749
        // Is this a delete with delete_time (21 bytes) or not (18 bytes)?
1750
0
        if (extlen == 18) {
1751
0
          proto_tree_add_item(extras_tree, hf_extras_nmeta, tvb, offset, 2, ENC_BIG_ENDIAN);
1752
0
          offset += 2;
1753
0
        } else if (extlen == 21) {
1754
0
          proto_tree_add_item(extras_tree, hf_extras_delete_time, tvb, offset, 4, ENC_BIG_ENDIAN);
1755
0
          offset += 4;
1756
0
          proto_tree_add_item(extras_tree, hf_extras_delete_unused, tvb, offset, 1, ENC_BIG_ENDIAN);
1757
0
          offset += 1;
1758
0
        }
1759
12
      } else if (extlen == 0) {
1760
7
        missing = true; // request with no extras
1761
7
      }
1762
12
    } else if (extlen) {
1763
0
        illegal = true; // response with extras
1764
0
    }
1765
12
    break;
1766
0
  case CLIENT_OPCODE_DCP_EXPIRATION:
1767
0
    if (extlen) {
1768
0
        if (request) {
1769
0
            proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1770
0
            offset += 8;
1771
0
            proto_tree_add_item(extras_tree, hf_extras_rev_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1772
0
            offset += 8;
1773
0
            if (extlen == 20) {
1774
0
                proto_tree_add_item(extras_tree, hf_extras_delete_time, tvb, offset, 4, ENC_BIG_ENDIAN);
1775
0
                offset += 4;
1776
0
            } else {
1777
                // Handle legacy expiration packet (despite its lack of use)
1778
0
                proto_tree_add_item(extras_tree, hf_extras_nmeta, tvb, offset, 2, ENC_BIG_ENDIAN);
1779
0
                offset += 2;
1780
0
            }
1781
0
        } else {
1782
0
            illegal = true;
1783
0
        }
1784
0
    } else if (request) {
1785
        /* Request must have extras */
1786
0
        missing = true;
1787
0
    }
1788
0
    break;
1789
0
  case CLIENT_OPCODE_DCP_FLUSH:
1790
0
    if (extlen) {
1791
0
      if (request) {
1792
0
        proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1793
0
        offset += 8;
1794
0
        proto_tree_add_item(extras_tree, hf_extras_rev_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1795
0
        offset += 8;
1796
0
        proto_tree_add_item(extras_tree, hf_extras_nmeta, tvb, offset, 2, ENC_BIG_ENDIAN);
1797
0
        offset += 2;
1798
0
      } else {
1799
0
        illegal = true;
1800
0
      }
1801
0
    } else if (request) {
1802
      /* Request must have extras */
1803
0
      missing = true;
1804
0
    }
1805
0
    break;
1806
1807
0
  case CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT:
1808
0
    if (extlen) {
1809
0
      if (request) {
1810
0
        proto_tree_add_item(extras_tree, hf_extras_bytes_to_ack, tvb, offset, 4, ENC_BIG_ENDIAN);
1811
0
        offset += 4;
1812
0
      } else {
1813
0
        illegal = true;
1814
0
      }
1815
0
    } else if (request) {
1816
      /* Request must have extras */
1817
0
      missing = true;
1818
0
    }
1819
0
    break;
1820
0
  case CLIENT_OPCODE_DCP_SYSTEM_EVENT: {
1821
0
    if (request && extlen == 13) {
1822
0
      proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1823
0
      offset += 8;
1824
0
      proto_tree_add_item(extras_tree, hf_extras_system_event_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1825
0
      offset += 4;
1826
0
      proto_tree_add_item(extras_tree, hf_extras_system_event_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1827
0
      offset += 1;
1828
0
    }
1829
0
    break;
1830
1
  }
1831
1
  case CLIENT_OPCODE_DCP_PREPARE: {
1832
1
    if (extlen) {
1833
0
      if (request) {
1834
        /* No extra_flags and proto_tree_add_bitmask don't work with empty flags See Bug:17890
1835
        static int * const extra_flags[] = {
1836
          NULL
1837
        };
1838
        */
1839
1840
0
        proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1841
0
        offset += 8;
1842
0
        proto_tree_add_item(extras_tree, hf_extras_rev_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1843
0
        offset += 8;
1844
        /*
1845
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1846
        */
1847
0
        proto_tree_add_item(extras_tree, hf_extras_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
1848
0
        offset += 4;
1849
0
        proto_tree_add_item(extras_tree, hf_extras_expiration, tvb, offset, 4, ENC_BIG_ENDIAN);
1850
0
        offset += 4;
1851
0
        proto_tree_add_item(extras_tree, hf_extras_lock_time, tvb, offset, 4, ENC_BIG_ENDIAN);
1852
0
        offset += 4;
1853
0
        proto_tree_add_item(extras_tree, hf_extras_nru, tvb, offset, 1, ENC_BIG_ENDIAN);
1854
0
        offset += 1;
1855
0
        proto_tree_add_item(extras_tree, hf_extras_deleted, tvb, offset, 1, ENC_BIG_ENDIAN);
1856
0
        offset += 1;
1857
0
        proto_tree_add_item(extras_tree, hf_flex_frame_durability_req, tvb, offset, 1, ENC_BIG_ENDIAN);
1858
0
        offset += 1;
1859
0
      } else {
1860
0
        illegal = true;
1861
0
      }
1862
1
    } else if (request) {
1863
      /* Request must have extras */
1864
0
      missing = true;
1865
0
    }
1866
1
    break;
1867
1
  }
1868
0
  case CLIENT_OPCODE_DCP_SEQNO_ACK: {
1869
0
    if (extlen) {
1870
0
      if (request) {
1871
0
        proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1872
0
        offset += 8;
1873
0
      } else {
1874
0
        illegal = true;
1875
0
      }
1876
0
    } else if (request) {
1877
      /* Request must have extras */
1878
0
      missing = true;
1879
0
    }
1880
0
    break;
1881
1
  }
1882
0
  case CLIENT_OPCODE_DCP_COMMIT: {
1883
0
    if (extlen) {
1884
0
      if (request) {
1885
0
        proto_tree_add_item(extras_tree, hf_extras_prepared_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1886
0
        offset += 8;
1887
0
        proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1888
0
        offset += 8;
1889
0
      } else {
1890
0
        illegal = true;
1891
0
      }
1892
0
    } else if (request) {
1893
      /* Request must have extras */
1894
0
      missing = true;
1895
0
    }
1896
0
    break;
1897
1
  }
1898
0
  case CLIENT_OPCODE_DCP_ABORT: {
1899
0
    if (extlen) {
1900
0
      if (request) {
1901
0
        proto_tree_add_item(extras_tree, hf_extras_prepared_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1902
0
        offset += 8;
1903
0
        proto_tree_add_item(extras_tree, hf_extras_abort_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1904
0
        offset += 8;
1905
0
      } else {
1906
0
        illegal = true;
1907
0
      }
1908
0
    } else if (request) {
1909
      /* Request must have extras */
1910
0
      missing = true;
1911
0
    }
1912
0
    break;
1913
1
  }
1914
0
  case CLIENT_OPCODE_DCP_SEQNO_ADVANCED: {
1915
0
    if (extlen) {
1916
0
      if (request) {
1917
0
        proto_tree_add_item(extras_tree, hf_extras_by_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
1918
0
        offset += 8;
1919
0
      } else {
1920
0
        illegal = true;
1921
0
      }
1922
0
    } else if (request) {
1923
      /* Request must have extras */
1924
0
      missing = true;
1925
0
    }
1926
0
    break;
1927
1
  }
1928
0
  case CLIENT_OPCODE_DCP_OSO_SNAPSHOT: {
1929
0
    if (extlen) {
1930
0
      if (request) {
1931
0
        static int * const extra_flags[] = {
1932
0
          &hf_extras_flags_dcp_oso_snapshot_begin,
1933
0
          &hf_extras_flags_dcp_oso_snapshot_end,
1934
0
          NULL
1935
0
        };
1936
0
        proto_tree_add_bitmask(extras_tree,
1937
0
                               tvb,
1938
0
                               offset,
1939
0
                               hf_extras_dcp_oso_snapshot_flags,
1940
0
                               ett_extras_flags,
1941
0
                               extra_flags,
1942
0
                               ENC_BIG_ENDIAN);
1943
0
        offset += 4;
1944
0
      } else {
1945
0
        illegal = true;
1946
0
      }
1947
0
    } else if (request) {
1948
      /* Request must have extras */
1949
0
      missing = true;
1950
0
    }
1951
0
    break;
1952
1
  }
1953
0
  case CLIENT_OPCODE_SUBDOC_GET:
1954
0
  case CLIENT_OPCODE_SUBDOC_EXISTS:
1955
0
    dissect_subdoc_spath_required_extras(tvb, extras_tree, extlen, request,
1956
0
                                         &offset, path_len, &illegal);
1957
0
    if (extlen == 4) {
1958
0
      proto_tree_add_bitmask(extras_tree, tvb, offset, hf_subdoc_doc_flags,
1959
0
                             ett_extras_flags, subdoc_doc_flags, ENC_BIG_ENDIAN);
1960
0
      offset += 1;
1961
0
    }
1962
0
    break;
1963
1964
0
  case CLIENT_OPCODE_SUBDOC_DICT_ADD:
1965
0
  case CLIENT_OPCODE_SUBDOC_DICT_UPSERT:
1966
0
  case CLIENT_OPCODE_SUBDOC_DELETE:
1967
0
  case CLIENT_OPCODE_SUBDOC_REPLACE:
1968
0
  case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST:
1969
0
  case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST:
1970
0
  case CLIENT_OPCODE_SUBDOC_ARRAY_INSERT:
1971
1
  case CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE:
1972
1
  case CLIENT_OPCODE_SUBDOC_COUNTER:
1973
1
    dissect_subdoc_spath_required_extras(tvb, extras_tree, extlen, request,
1974
1
                                         &offset, path_len, &illegal);
1975
1
    if (request) {
1976
      /* optional expiry only permitted for mutation requests,
1977
         if and only if (extlen == 7 || extlen == 8) */
1978
0
      if (extlen == 7 || extlen == 8) {
1979
0
        proto_tree_add_item(extras_tree, hf_extras_expiration, tvb, offset,
1980
0
                            4, ENC_BIG_ENDIAN);
1981
0
        offset += 4;
1982
0
      }
1983
      /* optional doc flags only permitted if and only if
1984
         (extlen == 4 || extlen == 8) */
1985
0
      if (extlen == 4 || extlen == 8) {
1986
0
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_subdoc_doc_flags,
1987
0
                               ett_extras_flags, subdoc_doc_flags,
1988
0
                               ENC_BIG_ENDIAN);
1989
0
        offset += 1;
1990
0
      }
1991
0
      if (extlen != 3 && extlen != 7 && extlen != 4 && extlen != 8) {
1992
0
        illegal = true;
1993
0
      }
1994
0
    }
1995
1
    break;
1996
1997
21
  case CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP:
1998
21
    if (request) {
1999
13
      if (extlen == 1) {
2000
0
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_subdoc_doc_flags,
2001
0
                               ett_extras_flags, subdoc_doc_flags,
2002
0
                               ENC_BIG_ENDIAN);
2003
0
        offset += 1;
2004
13
      } else {
2005
13
        illegal = true;
2006
13
      }
2007
13
    }
2008
21
    break;
2009
2010
1
  case CLIENT_OPCODE_SUBDOC_MULTI_MUTATION:
2011
1
    if (request) {
2012
0
      if (extlen == 4 || extlen == 5) {
2013
0
        proto_tree_add_item(extras_tree, hf_extras_expiration, tvb, offset, 4,
2014
0
                            ENC_BIG_ENDIAN);
2015
0
        offset += 4;
2016
0
      }
2017
0
      if (extlen == 1 || extlen == 5) {
2018
0
        proto_tree_add_bitmask(extras_tree, tvb, offset, hf_subdoc_doc_flags,
2019
0
                               ett_extras_flags, subdoc_doc_flags, ENC_BIG_ENDIAN);
2020
0
        offset += 1;
2021
0
      }
2022
0
      if (extlen != 1 && extlen != 4 && extlen != 5) {
2023
0
        illegal = true;
2024
0
      }
2025
0
    }
2026
1
    break;
2027
2028
0
  case CLIENT_OPCODE_DEL_WITH_META:
2029
0
  case CLIENT_OPCODE_SET_WITH_META:
2030
0
    if (request) {
2031
0
      proto_tree_add_item(extras_tree, hf_meta_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
2032
0
      offset += 4;
2033
0
      proto_tree_add_item(extras_tree, hf_meta_expiration, tvb, offset, 4, ENC_BIG_ENDIAN);
2034
0
      offset += 4;
2035
0
      proto_tree_add_item(extras_tree, hf_meta_revseqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2036
0
      offset += 8;
2037
0
      proto_tree_add_item(extras_tree, hf_meta_cas, tvb, offset, 8, ENC_BIG_ENDIAN);
2038
0
      offset += 8;
2039
2040
      /*The previous 24 bytes are required. The next two fields are optional,
2041
       * hence we are checking the extlen to see what fields we have. As they
2042
       * are different lengths we can do this by just checking the length.*/
2043
2044
      // Options field (4 bytes)
2045
0
      if (extlen == 28 || extlen == 30) {
2046
          /* TODO: these fields are all 16 bits wide, but field is 32 bits? */
2047
0
          proto_tree_add_bitmask(
2048
0
                  extras_tree,
2049
0
                  tvb,
2050
0
                  offset,
2051
0
                  hf_meta_options,
2052
0
                  ett_extras_flags,
2053
0
                  (opcode == CLIENT_OPCODE_DEL_WITH_META) ?
2054
0
                      del_with_meta_extra_flags : set_with_meta_extra_flags,
2055
0
                  ENC_BIG_ENDIAN);
2056
0
          offset += 4;
2057
0
      }
2058
      // Meta Length field (2 bytes)
2059
0
      if (extlen == 26 || extlen == 30) {
2060
0
        proto_tree_add_item(extras_tree, hf_metalen, tvb, offset, 2, ENC_BIG_ENDIAN);
2061
0
        offset += 2;
2062
0
      }
2063
0
    }
2064
0
    break;
2065
2066
2
  case CLIENT_OPCODE_GET_META:
2067
2
    if (request) {
2068
1
      if(extlen) {
2069
0
        proto_tree_add_item(extras_tree, hf_meta_reqextmeta, tvb, offset, 1, ENC_BIG_ENDIAN);
2070
0
        offset += 1;
2071
0
      }
2072
1
    } else {
2073
1
      proto_tree_add_item(extras_tree, hf_meta_deleted, tvb, offset, 4, ENC_BIG_ENDIAN);
2074
1
      offset += 4;
2075
1
      proto_tree_add_item(extras_tree, hf_meta_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
2076
1
      offset += 4;
2077
1
      proto_tree_add_item(extras_tree, hf_exptime, tvb, offset, 4, ENC_BIG_ENDIAN);
2078
1
      offset += 4;
2079
1
      proto_tree_add_item(extras_tree, hf_extras_meta_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2080
1
      offset += 8;
2081
1
      if (extlen == 21) {
2082
0
        proto_tree_add_item(extras_tree, hf_confres, tvb, offset, 1, ENC_BIG_ENDIAN);
2083
0
        offset += 1;
2084
0
      }
2085
1
    }
2086
2
    break;
2087
0
  case CLIENT_OPCODE_COLLECTIONS_GET_ID:
2088
0
    if (!request) {
2089
0
      proto_tree_add_item(extras_tree, hf_collection_manifest_id, tvb, offset, 8, ENC_BIG_ENDIAN);
2090
0
      offset += 8;
2091
0
      proto_tree_add_item(extras_tree, hf_collection_key_id, tvb, offset, 4, ENC_BIG_ENDIAN);
2092
0
      offset += 4;
2093
0
    }
2094
0
    break;
2095
0
  case CLIENT_OPCODE_RANGE_SCAN_CONTINUE:
2096
    // https://github.com/couchbase/kv_engine/blob/master/docs/range_scans/range_scan_continue.md
2097
0
    if (request) {
2098
0
      proto_tree_add_item(extras_tree, hf_range_scan_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
2099
0
      offset += 16;
2100
0
      proto_tree_add_item(extras_tree, hf_range_scan_item_limit, tvb, offset, 4, ENC_BIG_ENDIAN);
2101
0
      offset += 4;
2102
0
      proto_tree_add_item(extras_tree, hf_range_scan_time_limit, tvb, offset, 4, ENC_BIG_ENDIAN);
2103
0
      offset += 4;
2104
0
      proto_tree_add_item(extras_tree, hf_range_scan_byte_limit, tvb, offset, 4, ENC_BIG_ENDIAN);
2105
0
      offset += 4;
2106
0
    }
2107
0
    break;
2108
0
  case CLIENT_OPCODE_RANGE_SCAN_CANCEL:
2109
    // https://github.com/couchbase/kv_engine/blob/master/docs/range_scans/range_scan_cancel.md
2110
0
    if (request) {
2111
0
      proto_tree_add_item(extras_tree, hf_range_scan_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
2112
0
      offset += 16;
2113
0
    }
2114
0
    break;
2115
6
  default:
2116
6
    if (extlen) {
2117
      /* Decode as unknown extras */
2118
2
      proto_tree_add_item(extras_tree, hf_extras_unknown, tvb, offset, extlen, ENC_NA);
2119
2
      offset += extlen;
2120
2
    }
2121
6
    break;
2122
80
  }
2123
73
  if (illegal) {
2124
14
    proto_tree_add_expert_format(extras_tree, pinfo, &ei_warn_shall_not_have_extras, tvb, offset, 0,
2125
14
                           "%s %s should not have extras",
2126
14
                           val_to_str_ext(pinfo->pool, opcode, &client_opcode_vals_ext, "Opcode 0x%x"),
2127
14
                           request ? "Request" : "Response");
2128
14
    offset += extlen;
2129
59
  } else if (missing) {
2130
2131
12
    proto_tree_add_expert_format(tree, pinfo, &ei_warn_must_have_extras, tvb, offset, 0,
2132
12
                           "%s %s must have Extras",
2133
12
                           val_to_str_ext(pinfo->pool, opcode, &client_opcode_vals_ext, "Opcode Ox%x"),
2134
12
                           request ? "Request" : "Response");
2135
12
}
2136
2137
73
  if ((offset - save_offset) != extlen) {
2138
22
    expert_add_info_format(pinfo, extras_item, &ei_warn_illegal_extras_length,
2139
22
                           "Illegal Extras length, should be %d", offset - save_offset);
2140
22
  }
2141
73
}
2142
2143
/*
2144
  Decode an unsigned leb128 int from a slice within a tvbuff_t
2145
  @param tvb buffer to read from
2146
  @param start index of the first byte of 'slice'
2147
  @param end index of the last byte of the buffer 'slice'
2148
  @param [out] value the decoded value
2149
  @returns next byte after the leb128 bytes or -1 if we failed to decode
2150
*/
2151
static int
2152
39
dissect_unsigned_leb128(tvbuff_t *tvb, int start, int end, uint32_t* value) {
2153
39
    uint8_t byte = tvb_get_uint8(tvb, start);
2154
39
    *value = byte & 0x7f;
2155
2156
2157
39
    if ((byte & 0x80) == 0x80) {
2158
21
        uint32_t shift = 7;
2159
21
        int byte_idx;
2160
65
        for (byte_idx = start+1; byte_idx < end; byte_idx++) {
2161
62
            byte = tvb_get_uint8(tvb, byte_idx);
2162
            /* Ensure we are using a valid shift */
2163
62
            if (shift > 32)
2164
5
                return -1;
2165
57
            *value |= (byte & 0x7f) << shift;
2166
57
            if ((byte & 0x80) == 0) {
2167
13
                break;
2168
13
            }
2169
44
            shift += 7;
2170
44
        }
2171
16
        return (byte_idx == end) ? -1 : byte_idx + 1;
2172
21
    }
2173
18
    return start + 1;
2174
39
}
2175
2176
1
static void dissect_server_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, int keylen, uint8_t opcode, bool request) {
2177
1
  if (keylen == 0) {
2178
0
    switch (opcode) {
2179
0
      case SERVER_OPCODE_GET_AUTHORIZATION:
2180
0
        if (request) {
2181
0
          proto_tree_add_expert_format(tree, pinfo, &ei_warn_must_have_key,
2182
0
                                       tvb, offset, 0,
2183
0
                                       "GetAuthorization request must have key");
2184
0
        }
2185
0
        return;
2186
0
      case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION:
2187
0
        if (request) {
2188
0
          proto_tree_add_expert_format(tree, pinfo, &ei_warn_must_have_key,
2189
0
                                       tvb, offset, 0,
2190
0
                                       "ClustermapChangeNotification request must have key");
2191
0
        }
2192
0
      case SERVER_OPCODE_AUTHENTICATE:
2193
0
      case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS:
2194
        // Success! none of these commands want a key
2195
0
      default:
2196
        // Probably ok as we don't know about the opcode
2197
0
        return;
2198
0
    }
2199
0
  }
2200
2201
1
  proto_item *ti = proto_tree_add_item(tree, hf_key, tvb, offset, keylen, ENC_UTF_8);
2202
2203
1
  switch (opcode) {
2204
0
    case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION:
2205
0
      if (!request) {
2206
0
        expert_add_info_format(pinfo, ti, &ei_warn_shall_not_have_key,
2207
0
                               "ClustermapChangeNotification response shall not have key");
2208
0
      }
2209
0
      break;
2210
2211
0
    case SERVER_OPCODE_AUTHENTICATE:
2212
0
    case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS:
2213
0
        expert_add_info_format(pinfo, ti, &ei_warn_shall_not_have_key,
2214
0
                               "%s %s shall not have Key",
2215
0
                               val_to_str_ext(pinfo->pool, opcode,
2216
0
                                              &server_opcode_vals_ext,
2217
0
                                              "Opcode 0x%x"),
2218
0
                               request ? "Request" : "Response");
2219
0
      break;
2220
2221
0
    case SERVER_OPCODE_GET_AUTHORIZATION:
2222
0
      if (!request) {
2223
0
          expert_add_info_format(pinfo, ti, &ei_warn_shall_not_have_key,
2224
0
                                 "GetAuthorization response shall not have key");
2225
0
      }
2226
0
      break;
2227
0
    default:
2228
0
      break;
2229
1
  }
2230
1
}
2231
2232
static void
2233
dissect_client_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2234
                   unsigned offset, int keylen, uint8_t opcode, bool request)
2235
184
{
2236
184
  proto_item *ti = NULL;
2237
184
  bool        illegal = false;  /* Set when key shall not be present */
2238
184
  bool        missing = false;  /* Set when key is missing */
2239
2240
184
  if (keylen) {
2241
65
    bool collection_encoded_key = true;
2242
65
    switch (opcode) {
2243
1
      case CLIENT_OPCODE_STAT:
2244
2
      case CLIENT_OPCODE_HELLO:
2245
2
      case CLIENT_OPCODE_SASL_AUTH:
2246
3
      case CLIENT_OPCODE_SASL_STEP:
2247
3
      case CLIENT_OPCODE_IOCTL_GET:
2248
3
      case CLIENT_OPCODE_IOCTL_SET:
2249
4
      case CLIENT_OPCODE_DCP_CONTROL:
2250
4
      case CLIENT_OPCODE_SET_PARAM:
2251
4
      case CLIENT_OPCODE_CREATE_BUCKET:
2252
4
      case CLIENT_OPCODE_DELETE_BUCKET:
2253
4
      case CLIENT_OPCODE_SELECT_BUCKET:
2254
5
      case CLIENT_OPCODE_IFCONFIG:
2255
5
        collection_encoded_key = false;
2256
5
        break;
2257
60
      default:
2258
60
        break;
2259
65
    }
2260
2261
65
    ti = proto_tree_add_item(tree, hf_key, tvb, offset, keylen, ENC_UTF_8);
2262
2263
65
    if (collection_encoded_key) {
2264
      /* assume collections are enabled and add a field for the CID */
2265
39
      uint32_t cid = 0;
2266
39
      int ok = dissect_unsigned_leb128(tvb, offset, offset + keylen, &cid);
2267
2268
      /* Add collection info to a subtree */
2269
39
      proto_tree *cid_tree = proto_item_add_subtree(ti, ett_collection_key);
2270
2271
39
      if (ok == -1) {
2272
        /* cid decode issue, could just be a non-collection stream, don't warn
2273
           just add some info */
2274
8
        proto_tree_add_string_format(cid_tree,
2275
8
                                     hf_collection_key_logical,
2276
8
                                     tvb,
2277
8
                                     offset,
2278
8
                                     keylen,
2279
8
                                     NULL,
2280
8
                                     "Collection ID didn't decode, maybe no CID.");
2281
31
      } else {
2282
31
        proto_tree_add_uint(cid_tree, hf_collection_key_id, tvb, offset,
2283
31
                            (ok - offset), cid);
2284
31
        proto_tree_add_item(cid_tree, hf_collection_key_logical, tvb,
2285
31
                            ok, keylen - (ok - offset), ENC_UTF_8);
2286
31
      }
2287
39
    }
2288
65
    offset += keylen;
2289
65
  }
2290
2291
  /* inSanity check */
2292
184
  if (keylen) {
2293
41
    switch (opcode) {
2294
0
    case CLIENT_OPCODE_QUIT:
2295
0
    case CLIENT_OPCODE_QUITQ:
2296
0
    case CLIENT_OPCODE_NOOP:
2297
0
    case CLIENT_OPCODE_VERSION:
2298
0
    case CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST:
2299
0
    case CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT:
2300
0
    case CLIENT_OPCODE_GET_ALL_VB_SEQNOS:
2301
      /* Request and Response must not have key */
2302
0
      illegal = true;
2303
0
      break;
2304
2305
0
    case CLIENT_OPCODE_SET:
2306
1
    case CLIENT_OPCODE_ADD:
2307
2
    case CLIENT_OPCODE_REPLACE:
2308
2
    case CLIENT_OPCODE_DELETE:
2309
2
    case CLIENT_OPCODE_SETQ:
2310
2
    case CLIENT_OPCODE_ADDQ:
2311
2
    case CLIENT_OPCODE_REPLACEQ:
2312
2
    case CLIENT_OPCODE_DELETEQ:
2313
9
    case CLIENT_OPCODE_FLUSH:
2314
9
    case CLIENT_OPCODE_APPEND:
2315
9
    case CLIENT_OPCODE_PREPEND:
2316
11
    case CLIENT_OPCODE_FLUSHQ:
2317
11
    case CLIENT_OPCODE_APPENDQ:
2318
11
    case CLIENT_OPCODE_PREPENDQ:
2319
      /* Response must not have a key */
2320
11
      if (!request) {
2321
3
        illegal = true;
2322
3
      }
2323
11
      break;
2324
2325
0
    case CLIENT_OPCODE_DCP_ADD_STREAM:
2326
0
    case CLIENT_OPCODE_DCP_CLOSE_STREAM:
2327
0
    case CLIENT_OPCODE_DCP_STREAM_END:
2328
0
    case CLIENT_OPCODE_DCP_SNAPSHOT_MARKER:
2329
0
    case CLIENT_OPCODE_DCP_FLUSH:
2330
0
    case CLIENT_OPCODE_DCP_SET_VBUCKET_STATE:
2331
      /* Request must not have a key */
2332
0
      if (request) {
2333
0
        illegal = true;
2334
0
      }
2335
0
      break;
2336
41
    }
2337
143
  } else {
2338
143
    switch (opcode) {
2339
92
    case CLIENT_OPCODE_GET:
2340
93
    case CLIENT_OPCODE_GETQ:
2341
93
    case CLIENT_OPCODE_GETK:
2342
93
    case CLIENT_OPCODE_GETKQ:
2343
94
    case CLIENT_OPCODE_SET:
2344
95
    case CLIENT_OPCODE_ADD:
2345
95
    case CLIENT_OPCODE_REPLACE:
2346
95
    case CLIENT_OPCODE_DELETE:
2347
95
    case CLIENT_OPCODE_SETQ:
2348
95
    case CLIENT_OPCODE_ADDQ:
2349
95
    case CLIENT_OPCODE_REPLACEQ:
2350
95
    case CLIENT_OPCODE_DELETEQ:
2351
97
    case CLIENT_OPCODE_INCREMENT:
2352
98
    case CLIENT_OPCODE_DECREMENT:
2353
98
    case CLIENT_OPCODE_INCREMENTQ:
2354
98
    case CLIENT_OPCODE_DECREMENTQ:
2355
98
    case CLIENT_OPCODE_DCP_OPEN_CONNECTION:
2356
99
    case CLIENT_OPCODE_DCP_MUTATION:
2357
103
    case CLIENT_OPCODE_DCP_DELETION:
2358
103
    case CLIENT_OPCODE_DCP_EXPIRATION:
2359
103
    case CLIENT_OPCODE_DCP_SYSTEM_EVENT:
2360
      /* Request must have key */
2361
103
      if (request) {
2362
11
        missing = true;
2363
11
      }
2364
103
      break;
2365
143
    }
2366
143
  }
2367
2368
160
  if (illegal) {
2369
3
    expert_add_info_format(pinfo, ti, &ei_warn_shall_not_have_key, "%s %s shall not have Key",
2370
3
                           val_to_str_ext(pinfo->pool, opcode, &client_opcode_vals_ext, "Opcode 0x%x"),
2371
3
                           request ? "Request" : "Response");
2372
157
  } else if (missing) {
2373
11
    proto_tree_add_expert_format(tree, pinfo, &ei_warn_must_have_key, tvb, offset, 0,
2374
11
                           "%s %s must have Key",
2375
11
                           val_to_str_ext(pinfo->pool, opcode, &client_opcode_vals_ext, "Opcode Ox%x"),
2376
11
                           request ? "Request" : "Response");
2377
11
  }
2378
160
}
2379
2380
static void
2381
dissect_multipath_lookup_response(tvbuff_t *tvb, packet_info *pinfo,
2382
                                  proto_tree *tree, unsigned offset, uint32_t value_len)
2383
5
{
2384
5
  unsigned end = offset + value_len;
2385
5
  int spec_idx = 0;
2386
2387
21
  while (offset < end) {
2388
16
    proto_item *ti;
2389
16
    proto_tree *multipath_tree;
2390
16
    tvbuff_t *json_tvb;
2391
16
    uint32_t result_len;
2392
16
    unsigned start_offset = offset;
2393
2394
16
    ti = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_multipath,
2395
16
                                       &multipath_tree, "Lookup Result [ %u ]",
2396
16
                                       spec_idx);
2397
2398
16
    proto_tree_add_item(multipath_tree, hf_status, tvb, offset, 2,
2399
16
                        ENC_BIG_ENDIAN);
2400
16
    offset += 2;
2401
16
    proto_tree_add_item_ret_uint(multipath_tree, hf_value_length, tvb, offset,
2402
16
                                 4, ENC_BIG_ENDIAN, &result_len);
2403
16
    offset += 4;
2404
2405
16
    proto_tree_add_item(multipath_tree, hf_value, tvb, offset, result_len,
2406
16
                        ENC_ASCII);
2407
16
    if (result_len > 0) {
2408
10
        json_tvb = tvb_new_subset_length(tvb, offset, result_len);
2409
10
        call_dissector(json_handle, json_tvb, pinfo, multipath_tree);
2410
10
    }
2411
16
    offset += result_len;
2412
2413
16
    proto_item_set_len(ti, offset - start_offset);
2414
2415
16
    spec_idx++;
2416
16
  }
2417
5
}
2418
2419
static void
2420
dissect_multipath_mutation_response(tvbuff_t *tvb, packet_info *pinfo,
2421
                                    proto_tree *tree, unsigned offset, uint32_t value_len)
2422
0
{
2423
0
  unsigned end = offset + value_len;
2424
0
  int spec_idx = 0;
2425
2426
  /* Expect a variable number of mutation responses:
2427
   * - If response.status == SUCCESS, zero to N responses, one for each mutation
2428
   *   spec which returns a value.
2429
   * - If response.status != SUCCESS, exactly 1 response, for first failing
2430
   *   spec.
2431
   */
2432
0
  while (offset < end) {
2433
0
    proto_item *ti;
2434
0
    proto_tree *multipath_tree;
2435
0
    tvbuff_t *json_tvb;
2436
0
    uint32_t status;
2437
0
    unsigned start_offset = offset;
2438
2439
0
    ti = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_multipath,
2440
0
                                       &multipath_tree, "Mutation Result [ %u ]",
2441
0
                                       spec_idx);
2442
2443
0
    proto_tree_add_item(multipath_tree, hf_multipath_index, tvb, offset, 1,
2444
0
                        ENC_BIG_ENDIAN);
2445
0
    offset += 1;
2446
0
    proto_tree_add_item_ret_uint(multipath_tree, hf_status, tvb, offset, 2,
2447
0
                                 ENC_BIG_ENDIAN, &status);
2448
0
    offset += 2;
2449
0
    if (status == STATUS_SUCCESS) {
2450
0
      uint32_t result_len;
2451
0
      proto_tree_add_item_ret_uint(multipath_tree, hf_value_length, tvb,
2452
0
                                   offset, 4, ENC_BIG_ENDIAN, &result_len);
2453
0
      offset += 4;
2454
2455
0
      proto_tree_add_item(multipath_tree, hf_value, tvb, offset, result_len,
2456
0
                          ENC_ASCII);
2457
0
      if (result_len > 0) {
2458
0
        json_tvb = tvb_new_subset_length(tvb, offset, result_len);
2459
0
        call_dissector(json_handle, json_tvb, pinfo, multipath_tree);
2460
0
      }
2461
0
      offset += result_len;
2462
0
    }
2463
0
    proto_item_set_len(ti, offset - start_offset);
2464
2465
0
    spec_idx++;
2466
0
  }
2467
0
}
2468
2469
static void
2470
dissect_multipath_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2471
                        unsigned offset, uint32_t value_len, bool is_mutation,
2472
                        bool request)
2473
18
{
2474
18
  unsigned end = offset + value_len;
2475
18
  int spec_idx = 0;
2476
18
  proto_item *ti;
2477
18
  proto_tree *multipath_tree;
2478
2479
18
  if (request) {
2480
13
    int min_spec_size;
2481
2482
    /* Minimum size is the fixed header. */
2483
13
    min_spec_size = (is_mutation ? 8 : 4);
2484
2485
113
    while (offset + min_spec_size <= end) {
2486
100
      uint32_t path_len;
2487
100
      uint32_t spec_value_len = 0;
2488
100
      unsigned start_offset = offset;
2489
2490
100
      ti = proto_tree_add_subtree_format(tree, tvb, offset, -1, ett_multipath,
2491
100
                                         &multipath_tree,
2492
100
                                         (is_mutation ? "Mutation spec [ %u ]"
2493
100
                                                      : "Lookup spec [ %u ]"),
2494
100
                                         spec_idx);
2495
2496
100
      proto_tree_add_item(multipath_tree, hf_multipath_opcode, tvb, offset, 1,
2497
100
                          ENC_BIG_ENDIAN);
2498
100
      offset += 1;
2499
100
      proto_tree_add_bitmask(multipath_tree, tvb, offset, hf_subdoc_flags,
2500
100
                             ett_extras_flags, subdoc_flags, ENC_BIG_ENDIAN);
2501
100
      offset += 1;
2502
2503
100
      proto_tree_add_item_ret_uint(multipath_tree, hf_multipath_pathlen, tvb,
2504
100
                                   offset, 2, ENC_BIG_ENDIAN, &path_len);
2505
100
      offset += 2;
2506
2507
100
      if (is_mutation) {
2508
0
        proto_tree_add_item_ret_uint(multipath_tree, hf_multipath_valuelen,
2509
0
                                     tvb, offset, 4, ENC_BIG_ENDIAN,
2510
0
                                     &spec_value_len);
2511
0
        offset += 4;
2512
0
      }
2513
2514
100
      if (path_len) {
2515
18
        proto_tree_add_item(multipath_tree, hf_multipath_path, tvb, offset, path_len,
2516
18
                            ENC_ASCII);
2517
18
        offset += path_len;
2518
18
      }
2519
2520
100
      if (spec_value_len > 0) {
2521
0
        proto_tree_add_item(multipath_tree, hf_multipath_value, tvb, offset,
2522
0
                            spec_value_len, ENC_ASCII);
2523
0
        offset += spec_value_len;
2524
0
      }
2525
2526
100
      proto_item_set_len(ti, offset - start_offset);
2527
2528
100
      spec_idx++;
2529
100
    }
2530
13
  } else {
2531
5
    if (is_mutation) {
2532
0
      dissect_multipath_mutation_response(tvb, pinfo, tree, offset, value_len);
2533
5
    } else {
2534
5
      dissect_multipath_lookup_response(tvb, pinfo, tree, offset, value_len);
2535
5
    }
2536
5
  }
2537
18
}
2538
2539
static void
2540
dissect_value(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
2541
              unsigned offset, uint32_t value_len, uint16_t path_len, uint8_t opcode,
2542
              bool request, uint8_t datatype)
2543
56
{
2544
56
  proto_item *ti = NULL;
2545
56
  bool        illegal = false;  /* Set when value shall not be present */
2546
56
  bool        missing = false;  /* Set when value is missing */
2547
2548
56
  if (value_len > 0) {
2549
54
    if (opcode == CLIENT_OPCODE_OBSERVE) {
2550
0
      proto_tree *observe_tree;
2551
0
      unsigned oo = offset, end = offset + value_len;
2552
0
      ti = proto_tree_add_item(tree, hf_observe, tvb, offset, value_len, ENC_ASCII);
2553
0
      observe_tree = proto_item_add_subtree(ti, ett_observe);
2554
0
      while (oo < end) {
2555
0
        uint16_t kl; /* keylength */
2556
0
        proto_tree_add_item(observe_tree, hf_observe_vbucket, tvb, oo, 2, ENC_BIG_ENDIAN);
2557
0
        oo += 2;
2558
0
        kl = tvb_get_ntohs(tvb, oo);
2559
0
        proto_tree_add_item(observe_tree, hf_observe_keylength, tvb, oo, 2, ENC_BIG_ENDIAN);
2560
0
        oo += 2;
2561
0
        proto_tree_add_item(observe_tree, hf_observe_key, tvb, oo, kl, ENC_ASCII);
2562
0
        oo += kl;
2563
0
        if (!request) {
2564
0
          proto_tree_add_item(observe_tree, hf_observe_status, tvb, oo, 1, ENC_BIG_ENDIAN);
2565
0
          oo++;
2566
0
          proto_tree_add_item(observe_tree, hf_observe_cas, tvb, oo, 8, ENC_BIG_ENDIAN);
2567
0
          oo += 8;
2568
0
        }
2569
0
      }
2570
54
    } else if (opcode == CLIENT_OPCODE_OBSERVE_SEQNO) {
2571
0
      if (request) {
2572
0
        ti = proto_tree_add_item(tree, hf_observe_vbucket_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
2573
0
        if (value_len != 8) {
2574
0
          expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Illegal Value length, should be 8");
2575
0
        }
2576
0
      } else {
2577
        /*
2578
         * <format_type, vbucket id, vbucket uuid, last_persisted_seqno, current_seqno>
2579
         *
2580
         * - format_type is of type uint8_t and it describes whether
2581
         *   the vbucket has failed over or not. 1 indicates a hard
2582
         *   failover, 0 indicates otherwise.
2583
         * - vbucket id is of type uint16_t and it is the identifier for
2584
         *   the vbucket.
2585
         * - vbucket uuid is of type uint64_t and it represents a UUID for
2586
         *    the vbucket.
2587
         * - last_persisted_seqno is of type uint64_t and it is the
2588
         *   last sequence number that was persisted for this
2589
         *   vbucket.
2590
         * - current_seqno is of the type uint64_t and it is the
2591
         *   sequence number of the latest mutation in the vbucket.
2592
         *
2593
         * In the case of a hard failover, the tuple is of the form
2594
         * <format_type, vbucket id, vbucket uuid, last_persisted_seqno, current_seqno,
2595
         * old vbucket uuid, last_received_seqno>
2596
         *
2597
         * - old vbucket uuid is of type uint64_t and it is the
2598
         *   vbucket UUID of the vbucket prior to the hard failover.
2599
         *
2600
         * - last_received_seqno is of type uint64_t and it is the
2601
         *   last received sequence number in the old vbucket uuid.
2602
         *
2603
         * The other fields are the same as that mentioned in the normal case.
2604
         */
2605
0
        uint8_t failed_over;
2606
2607
0
        proto_tree_add_item_ret_uint8(tree, hf_observe_failed_over, tvb, offset, 1, ENC_BIG_ENDIAN, &failed_over);
2608
0
        offset++;
2609
0
        proto_tree_add_item(tree, hf_observe_vbucket, tvb, offset, 2, ENC_BIG_ENDIAN);
2610
0
        offset += 2;
2611
0
        proto_tree_add_item(tree, hf_observe_vbucket_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
2612
0
        offset += 8;
2613
0
        proto_tree_add_item(tree, hf_observe_last_persisted_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2614
0
        offset += 8;
2615
0
        proto_tree_add_item(tree, hf_observe_current_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2616
0
        offset += 8;
2617
0
        if (failed_over) {
2618
0
          proto_tree_add_item(tree, hf_observe_old_vbucket_uuid, tvb, offset, 8, ENC_BIG_ENDIAN);
2619
0
          offset += 8;
2620
0
          proto_tree_add_item(tree, hf_observe_last_received_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2621
0
        }
2622
0
      }
2623
54
    } else if (!request && (opcode == CLIENT_OPCODE_DCP_STREAM_REQUEST || opcode == CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST)) {
2624
0
      if (value_len % 16 != 0) {
2625
0
        expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Response with bad failover log length");
2626
0
      } else {
2627
0
        proto_tree *failover_log_tree;
2628
0
        int cur = offset, end = offset + value_len;
2629
0
        ti = proto_tree_add_item(tree, hf_failover_log, tvb, offset, value_len, ENC_ASCII);
2630
0
        failover_log_tree = proto_item_add_subtree(ti, ett_failover_log);
2631
0
        ti = proto_tree_add_uint(failover_log_tree, hf_failover_log_size, tvb, offset, 0, (end - cur) / 16);
2632
0
        proto_item_set_generated(ti);
2633
0
        while (cur < end) {
2634
0
          proto_tree_add_item(failover_log_tree, hf_failover_log_vbucket_uuid, tvb, cur, 8, ENC_BIG_ENDIAN);
2635
0
          cur += 8;
2636
0
          proto_tree_add_item(failover_log_tree, hf_failover_log_vbucket_seqno, tvb, cur, 8, ENC_BIG_ENDIAN);
2637
0
          cur += 8;
2638
0
        }
2639
0
      }
2640
54
    } else if (!request && opcode == CLIENT_OPCODE_GET_ALL_VB_SEQNOS) {
2641
0
      if (value_len % 10 != 0) {
2642
0
        expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Response with bad body length");
2643
0
      } else {
2644
0
        proto_tree *vbucket_states_tree;
2645
0
        unsigned cur = offset, end = offset + value_len;
2646
0
        ti = proto_tree_add_item(tree, hf_vbucket_states, tvb, offset, value_len, ENC_ASCII);
2647
0
        vbucket_states_tree = proto_item_add_subtree(ti, ett_vbucket_states);
2648
0
        ti = proto_tree_add_uint(vbucket_states_tree, hf_vbucket_states_size, tvb, offset, 0, (end - cur) / 10);
2649
0
        proto_item_set_generated(ti);
2650
0
        while (cur < end) {
2651
0
          proto_tree_add_item(vbucket_states_tree, hf_vbucket_states_id, tvb, cur, 2, ENC_BIG_ENDIAN);
2652
0
          cur += 2;
2653
0
          proto_tree_add_item(vbucket_states_tree, hf_vbucket_states_seqno, tvb, cur, 8, ENC_BIG_ENDIAN);
2654
0
          cur += 8;
2655
0
        }
2656
0
      }
2657
54
    } else if (!request && (opcode == CLIENT_OPCODE_INCREMENT || opcode == CLIENT_OPCODE_DECREMENT)) {
2658
0
      ti = proto_tree_add_item(tree, hf_uint64_response, tvb, offset, 8, ENC_BIG_ENDIAN);
2659
0
      if (value_len != 8) {
2660
0
        expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Illegal Value length, should be 8");
2661
0
      }
2662
54
    } else if (has_json_value(request, opcode)) {
2663
0
      tvbuff_t *json_tvb;
2664
0
      ti = proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
2665
0
      json_tvb = tvb_new_subset_length(tvb, offset, value_len);
2666
0
      call_dissector(json_handle, json_tvb, pinfo, tree);
2667
2668
54
    } else if (opcode == CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP ||
2669
36
               opcode == CLIENT_OPCODE_SUBDOC_MULTI_MUTATION) {
2670
18
      dissect_multipath_value(tvb, pinfo, tree, offset, value_len,
2671
18
                              (opcode == CLIENT_OPCODE_SUBDOC_MULTI_MUTATION),
2672
18
                              request);
2673
2674
36
    } else if (opcode == CLIENT_OPCODE_HELLO) {
2675
4
      unsigned curr = offset, end = offset + value_len;
2676
4
      proto_tree *hello_features_tree;
2677
4
      ti = proto_tree_add_item(tree, hf_hello_features, tvb, offset, value_len, ENC_NA);
2678
4
      hello_features_tree = proto_item_add_subtree(ti, ett_hello_features);
2679
35
      while (curr < end) {
2680
31
        proto_tree_add_item(hello_features_tree, hf_hello_features_feature, tvb, curr, 2, ENC_BIG_ENDIAN);
2681
31
        curr += 2;
2682
31
      }
2683
32
    } else if (!request && opcode == CLIENT_OPCODE_RANGE_SCAN_CREATE) {
2684
0
      proto_tree_add_item(tree, hf_range_scan_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
2685
32
    } else if (path_len != 0) {
2686
0
        ti = proto_tree_add_item(tree, hf_path, tvb, offset, path_len, ENC_ASCII);
2687
0
        value_len -= path_len;
2688
0
        if (value_len > 0) {
2689
0
            ti = proto_tree_add_item(tree, hf_value, tvb, offset + path_len,
2690
0
                                     value_len, ENC_ASCII);
2691
0
        }
2692
32
    } else if (request && opcode == CLIENT_OPCODE_CREATE_BUCKET) {
2693
0
      unsigned sep, equals_pos, sep_pos, config_len;
2694
0
      proto_tree *key_tree, *config_tree = NULL;
2695
2696
      /* There are 2 main items stored in the value. The bucket type (represented by a path to the engine) and the
2697
       * bucket config. These are separated by a NULL byte with the bucket type coming first.*/
2698
2699
0
      if (!tvb_find_uint8_length(tvb, offset, value_len, 0x00, &sep)) {
2700
0
        ti = proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
2701
0
        expert_add_info_format(pinfo, ti, &ei_separator_not_found, "Null byte not found");
2702
0
      } else {
2703
0
        proto_tree_add_item(tree, hf_bucket_type, tvb, offset, sep - offset, ENC_ASCII);
2704
0
        config_len = value_len - (sep - offset) - 1; //Don't include NULL byte in length
2705
0
        if(config_len <= 0) {
2706
0
          expert_add_info_format(pinfo, ti, &ei_separator_not_found, "Separator not found in expected location");
2707
0
        } else {
2708
0
          offset = sep + 1;// Ignore NULL byte
2709
2710
0
          ti = proto_tree_add_item(tree, hf_bucket_config, tvb, offset, config_len, ENC_ASCII);
2711
0
          config_tree = proto_item_add_subtree(ti, ett_config);
2712
0
        }
2713
2714
        /* The config is arranged as "key=value;key=value..."*/
2715
0
        while (config_len > 0) {
2716
          // Get the key
2717
0
          if (!tvb_find_uint8_length(tvb, offset, config_len, 0x3d, &equals_pos)) {
2718
0
            expert_add_info_format(pinfo, ti, &ei_illegal_value, "Each key needs a value");
2719
0
            break; // Break out the while loop
2720
0
          }
2721
0
          ti = proto_tree_add_item(config_tree, hf_config_key, tvb, offset, equals_pos - offset, ENC_ASCII);
2722
0
          key_tree = proto_item_add_subtree(ti, ett_config_key);
2723
0
          config_len -= (equals_pos - offset + 1);
2724
0
          offset = equals_pos + 1;
2725
0
          if (config_len <= 0) {
2726
0
            expert_add_info_format(pinfo, ti, &ei_illegal_value, "Corresponding value missing");
2727
0
            break;//Break out of while loop
2728
0
          }
2729
2730
          // Get the value
2731
0
          if (!tvb_find_uint8_length(tvb, offset, config_len, 0x3b, &sep_pos)) {
2732
0
            expert_add_info_format(pinfo, ti, &ei_separator_not_found, "Each key-value pair must be terminated by semi-colon");
2733
0
            break; // Break out the while loop
2734
0
          }
2735
0
          proto_tree_add_item(key_tree, hf_config_value, tvb, offset, sep_pos - offset, ENC_ASCII);
2736
0
          config_len -= (sep_pos - offset + 1);
2737
0
          offset = sep_pos + 1;
2738
0
        }
2739
0
      }
2740
32
    } else if ((datatype & DT_XATTR) && (opcode == CLIENT_OPCODE_SET_WITH_META ||
2741
13
      opcode == CLIENT_OPCODE_DCP_MUTATION || opcode == CLIENT_OPCODE_DCP_DELETION ||
2742
1
      opcode == CLIENT_OPCODE_DCP_EXPIRATION || opcode == CLIENT_OPCODE_DCP_PREPARE ||
2743
1
      opcode == CLIENT_OPCODE_DEL_WITH_META || opcode == CLIENT_OPCODE_ADD_WITH_META ||
2744
1
      opcode == CLIENT_OPCODE_SETQ_WITH_META || opcode == CLIENT_OPCODE_DELQ_WITH_META ||
2745
12
      opcode == CLIENT_OPCODE_ADDQ_WITH_META )) {
2746
2747
12
      dissect_dcp_xattrs(tvb, tree, value_len, offset, pinfo);
2748
20
    } else if (request && opcode == CLIENT_OPCODE_GET_ERROR_MAP) {
2749
0
      if (value_len != 2) {
2750
0
        expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Illegal Value length, should be 2");
2751
0
        ti = proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
2752
0
      } else {
2753
0
        ti = proto_tree_add_item(tree, hf_get_errmap_version, tvb, offset, value_len, ENC_BIG_ENDIAN);
2754
0
      }
2755
20
    } else if (request && opcode == CLIENT_OPCODE_DCP_SNAPSHOT_MARKER) {
2756
0
        if (value_len < 20) {
2757
0
            expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Illegal Value length, should be at least 20");
2758
0
            ti = proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
2759
0
        }
2760
2761
0
        proto_tree_add_item(tree, hf_extras_start_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2762
0
        offset += 8;
2763
0
        proto_tree_add_item(tree, hf_extras_end_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2764
0
        offset += 8;
2765
0
        proto_tree_add_bitmask(tree, tvb, offset, hf_extras_flags, ett_extras_flags, snapshot_marker_flags, ENC_BIG_ENDIAN);
2766
0
        offset += 4;
2767
2768
0
        if (value_len > 20) {
2769
0
            if (value_len < 36) {
2770
0
                expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Illegal Value length, should be at least 36");
2771
0
                ti = proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
2772
0
            }
2773
2774
0
            proto_tree_add_item(tree, hf_extras_max_visible_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2775
0
            offset += 8;
2776
0
            proto_tree_add_item(tree, hf_extras_high_completed_seqno, tvb, offset, 8, ENC_BIG_ENDIAN);
2777
0
            offset += 8;
2778
2779
0
            if (value_len > 36) {
2780
0
                if (value_len != 44) {
2781
0
                    expert_add_info_format(pinfo, ti, &ei_warn_illegal_value_length, "Illegal Value length, should be 44");
2782
0
                    ti = proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
2783
0
                }
2784
2785
0
                proto_tree_add_item(tree, hf_extras_timestamp, tvb, offset, 8, ENC_BIG_ENDIAN);
2786
0
            }
2787
0
        }
2788
20
    } else {
2789
20
      ti = proto_tree_add_item(tree, hf_value, tvb, offset, value_len, ENC_ASCII);
2790
#ifdef HAVE_SNAPPY
2791
      if (datatype & DT_SNAPPY) {
2792
        tvbuff_t* decompressed_tvb = tvb_child_uncompress_snappy(tvb, tvb, offset, tvb_captured_length_remaining(tvb, offset));
2793
        if (decompressed_tvb != NULL) {
2794
            add_new_data_source(pinfo, decompressed_tvb, "Decompressed Data");
2795
            if (datatype & DT_JSON) {
2796
              call_dissector(json_handle, decompressed_tvb, pinfo, tree);
2797
            }
2798
        } else {
2799
            expert_add_info_format(pinfo, ti, &ei_compression_error, "Error uncompressing snappy data");
2800
        }
2801
      }
2802
#endif
2803
20
    }
2804
54
  }
2805
2806
  /* Sanity check */
2807
56
  if (value_len) {
2808
18
    switch (opcode) {
2809
1
    case CLIENT_OPCODE_GET:
2810
1
    case CLIENT_OPCODE_GETQ:
2811
1
    case CLIENT_OPCODE_GETK:
2812
1
    case CLIENT_OPCODE_GETKQ:
2813
1
    case CLIENT_OPCODE_INCREMENT:
2814
1
    case CLIENT_OPCODE_DECREMENT:
2815
1
    case CLIENT_OPCODE_VERSION:
2816
1
    case CLIENT_OPCODE_INCREMENTQ:
2817
1
    case CLIENT_OPCODE_DECREMENTQ:
2818
1
    case CLIENT_OPCODE_DCP_OPEN_CONNECTION:
2819
1
    case CLIENT_OPCODE_DCP_ADD_STREAM:
2820
1
    case CLIENT_OPCODE_DCP_CLOSE_STREAM:
2821
1
    case CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST:
2822
1
    case CLIENT_OPCODE_DCP_STREAM_END:
2823
9
    case CLIENT_OPCODE_DCP_DELETION:
2824
9
    case CLIENT_OPCODE_DCP_EXPIRATION:
2825
9
    case CLIENT_OPCODE_DCP_FLUSH:
2826
9
    case CLIENT_OPCODE_DCP_SET_VBUCKET_STATE:
2827
      /* Request must not have value */
2828
9
      if (request) {
2829
9
        illegal = true;
2830
9
      }
2831
9
      break;
2832
0
    case CLIENT_OPCODE_DELETE:
2833
0
    case CLIENT_OPCODE_QUIT:
2834
5
    case CLIENT_OPCODE_FLUSH:
2835
5
    case CLIENT_OPCODE_NOOP:
2836
5
    case CLIENT_OPCODE_DELETEQ:
2837
5
    case CLIENT_OPCODE_QUITQ:
2838
5
    case CLIENT_OPCODE_FLUSHQ:
2839
      /* Request and Response must not have value */
2840
5
      illegal = true;
2841
5
      break;
2842
0
    case CLIENT_OPCODE_SET:
2843
0
    case CLIENT_OPCODE_ADD:
2844
0
    case CLIENT_OPCODE_REPLACE:
2845
0
    case CLIENT_OPCODE_SETQ:
2846
0
    case CLIENT_OPCODE_ADDQ:
2847
0
    case CLIENT_OPCODE_REPLACEQ:
2848
0
    case CLIENT_OPCODE_APPEND:
2849
0
    case CLIENT_OPCODE_PREPEND:
2850
0
    case CLIENT_OPCODE_APPENDQ:
2851
0
    case CLIENT_OPCODE_PREPENDQ:
2852
      /* Response must not have value */
2853
0
      if (!request) {
2854
0
        illegal = true;
2855
0
      }
2856
0
      break;
2857
18
    }
2858
38
  } else {
2859
38
    switch (opcode) {
2860
0
    case CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST:
2861
      /* Successful response must have value */
2862
0
      if (!request) {
2863
0
        missing = true;
2864
0
      }
2865
0
      break;
2866
38
    }
2867
38
  }
2868
2869
20
  if (illegal) {
2870
14
    expert_add_info_format(pinfo, ti, &ei_warn_shall_not_have_value, "%s %s shall not have Value",
2871
14
                           val_to_str_ext(pinfo->pool, opcode, &client_opcode_vals_ext, "Opcode 0x%x"),
2872
14
                           request ? "Request" : "Response");
2873
14
  } else if (missing) {
2874
0
    expert_add_info_format(pinfo, ti, &ei_value_missing, "%s %s must have Value",
2875
0
                           val_to_str_ext(pinfo->pool, opcode, &client_opcode_vals_ext, "Opcode 0x%x"),
2876
0
                           request ? "Request" : "Response");
2877
0
  }
2878
20
}
2879
2880
static void flex_frame_duration_dissect(tvbuff_t* tvb,
2881
                                        proto_tree* frame_tree,
2882
                                        unsigned offset,
2883
792
                                        unsigned length) {
2884
2885
792
  if (length != 2) {
2886
754
    proto_tree_add_expert_format(frame_tree,
2887
754
                                 NULL,
2888
754
                                 &ei_warn_unknown_flex_len,
2889
754
                                 tvb,
2890
754
                                 offset,
2891
754
                                 length,
2892
754
                                 "FlexFrame: RX/TX Duration with illegal length %d", length);
2893
754
  } else {
2894
38
    uint16_t encoded_micros = tvb_get_ntohs(tvb, offset);
2895
38
    proto_tree_add_double(frame_tree,
2896
38
                          hf_flex_frame_tracing_duration,
2897
38
                          tvb,
2898
38
                          offset,
2899
38
                          2,
2900
38
                          pow(encoded_micros, 1.74) / 2);
2901
38
  }
2902
792
}
2903
2904
static void flex_frame_ru_usage_dissect(tvbuff_t* tvb,
2905
                                        proto_tree* frame_tree,
2906
                                        unsigned offset,
2907
129
                                        unsigned length) {
2908
2909
129
  if (length != 2) {
2910
73
    proto_tree_add_expert_format(frame_tree,
2911
73
                                 NULL,
2912
73
                                 &ei_warn_unknown_flex_len,
2913
73
                                 tvb,
2914
73
                                 offset,
2915
73
                                 length,
2916
73
                                 "Read unit illegal length %d", length);
2917
73
  } else {
2918
56
    uint16_t units = tvb_get_ntohs(tvb, offset);
2919
56
    proto_tree_add_uint(frame_tree, hf_flex_frame_ru_count, tvb, offset, 2, units);
2920
56
  }
2921
129
}
2922
2923
static void flex_frame_wu_usage_dissect(tvbuff_t* tvb,
2924
                                        proto_tree* frame_tree,
2925
                                        unsigned offset,
2926
277
                                        unsigned length) {
2927
2928
277
  if (length != 2) {
2929
236
    proto_tree_add_expert_format(frame_tree,
2930
236
                                 NULL,
2931
236
                                 &ei_warn_unknown_flex_len,
2932
236
                                 tvb,
2933
236
                                 offset,
2934
236
                                 length,
2935
236
                                 "Write unit illegal length %d", length);
2936
236
  } else {
2937
41
    uint16_t units = tvb_get_ntohs(tvb, offset);
2938
41
    proto_tree_add_uint(frame_tree, hf_flex_frame_wu_count, tvb, offset, 2, units);
2939
41
  }
2940
277
}
2941
2942
static void flex_frame_reorder_dissect(tvbuff_t* tvb,
2943
                                       proto_tree* frame_tree,
2944
                                       unsigned offset,
2945
2.94k
                                       unsigned length) {
2946
  /* Expects no data, so just check len */
2947
2.94k
  if (length != 0) {
2948
215
    proto_tree_add_expert_format(frame_tree,
2949
215
                                 NULL,
2950
215
                                 &ei_warn_unknown_flex_len,
2951
215
                                 tvb,
2952
215
                                 offset,
2953
215
                                 length,
2954
215
                                 "FlexFrame: Out Of Order with illegal length %d", length);
2955
215
  }
2956
2.94k
}
2957
2958
static void flex_frame_durability_dissect(tvbuff_t* tvb,
2959
                                          proto_tree* frame_tree,
2960
                                          unsigned offset,
2961
296
                                          unsigned length) {
2962
296
  if (!(length == 1 || length == 3)) {
2963
156
    proto_tree_add_expert_format(frame_tree,
2964
156
                                 NULL,
2965
156
                                 &ei_warn_unknown_flex_len,
2966
156
                                 tvb,
2967
156
                                 offset,
2968
156
                                 length,
2969
156
                                 "FlexFrame: Durability with illegal length %d", length);
2970
156
    return;
2971
156
  }
2972
140
  proto_tree_add_item(frame_tree, hf_flex_frame_durability_req, tvb, offset, 1, ENC_BIG_ENDIAN);
2973
140
}
2974
2975
static void flex_frame_dcp_stream_id_dissect(tvbuff_t* tvb,
2976
                                             proto_tree* frame_tree,
2977
                                             unsigned offset,
2978
264
                                             unsigned length) {
2979
264
  if (length != 2) {
2980
151
    proto_tree_add_expert_format(frame_tree,
2981
151
                                 NULL,
2982
151
                                 &ei_warn_unknown_flex_len,
2983
151
                                 tvb,
2984
151
                                 offset,
2985
151
                                 length,
2986
151
                                 "FlexFrame: DCP Stream ID with illegal length %d", length);
2987
151
  } else {
2988
113
    uint16_t sid = tvb_get_ntohs(tvb, offset);
2989
113
    proto_tree_add_uint(frame_tree, hf_flex_frame_dcp_stream_id, tvb, offset, 2, sid);
2990
113
  }
2991
264
}
2992
2993
static void flex_frame_impersonate_dissect(tvbuff_t* tvb,
2994
                                           proto_tree* frame_tree,
2995
                                           unsigned offset,
2996
79
                                           unsigned length) {
2997
79
  proto_tree_add_item(frame_tree,
2998
79
                      hf_flex_frame_impersonated_user,
2999
79
                      tvb,
3000
79
                      offset,
3001
79
                      length,
3002
79
                      ENC_UTF_8|ENC_STR_HEX);
3003
79
}
3004
3005
static void flex_frame_preserve_ttl(tvbuff_t* tvb,
3006
                                    proto_tree* frame_tree,
3007
                                    unsigned offset,
3008
271
                                    unsigned length) {
3009
  /* Expects no data, so just check len */
3010
271
  if (length != 0) {
3011
217
    proto_tree_add_expert_format(frame_tree,
3012
217
                                 NULL,
3013
217
                                 &ei_warn_unknown_flex_len,
3014
217
                                 tvb,
3015
217
                                 offset,
3016
217
                                 length,
3017
217
                                 "FlexFrame: Preserve TTL with illegal length %d", length);
3018
217
  }
3019
271
}
3020
3021
typedef void (*flex_frame_by_id_dissect_fn)(tvbuff_t*,
3022
                                            proto_tree*,
3023
                                            unsigned,
3024
                                            unsigned);
3025
3026
struct flex_frame_by_id_dissect {
3027
  uint32_t id;
3028
  flex_frame_by_id_dissect_fn handler;
3029
};
3030
3031
static const struct flex_frame_by_id_dissect flex_frame_response_dissect[] = {
3032
  {FLEX_RESPONSE_ID_RX_TX_DURATION, &flex_frame_duration_dissect},
3033
  {FLEX_RESPONSE_ID_RU_USAGE, &flex_frame_ru_usage_dissect},
3034
  {FLEX_RESPONSE_ID_WU_USAGE, &flex_frame_wu_usage_dissect},
3035
  {0, NULL }
3036
};
3037
3038
static const struct flex_frame_by_id_dissect flex_frame_request_dissect[] = {
3039
  { FLEX_REQUEST_ID_REORDER, &flex_frame_reorder_dissect},
3040
  { FLEX_REQUEST_ID_DURABILITY, &flex_frame_durability_dissect},
3041
  { FLEX_REQUEST_ID_DCP_STREAM_ID, &flex_frame_dcp_stream_id_dissect},
3042
  { FLEX_REQUEST_ID_IMPERSONATE, &flex_frame_impersonate_dissect},
3043
  { FLEX_REQUEST_ID_PRESERVE_TTL, &flex_frame_preserve_ttl},
3044
  { 0, NULL }
3045
};
3046
3047
/*
3048
  Flexible Framing Extras:
3049
  https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md
3050
*/
3051
static void dissect_flexible_framing_extras(tvbuff_t* tvb,
3052
                                            packet_info* pinfo,
3053
                                            proto_tree* tree,
3054
                                            unsigned offset,
3055
                                            uint8_t flex_frame_extra_len,
3056
135
                                            bool request) {
3057
3058
    /* select some request/response ID decoders */
3059
135
  const struct flex_frame_by_id_dissect* id_dissectors = flex_frame_response_dissect;
3060
135
  int info_id = hf_flex_frame_id_res;
3061
135
  int info_id_esc = hf_flex_frame_id_res_esc;
3062
135
  int info_len_id = hf_flex_frame_len;
3063
135
  if (request) {
3064
84
    id_dissectors = flex_frame_request_dissect;
3065
84
    info_id = hf_flex_frame_id_req;
3066
84
    info_id_esc = hf_flex_frame_id_req_esc;
3067
84
  }
3068
3069
  /* This first item shows the entire extent of all frame extras.
3070
     If we have multiple frames, we will add them in the iteration */
3071
135
  proto_tree_add_uint(tree,
3072
135
                      hf_flex_extras,
3073
135
                      tvb,
3074
135
                      offset,
3075
135
                      flex_frame_extra_len,
3076
135
                      flex_frame_extra_len);
3077
3078
  /* iterate until we've consumed the flex_frame_extra_len */
3079
135
  unsigned bytes_remaining = flex_frame_extra_len;
3080
135
  int frame_index = 0;
3081
3082
6.54k
  while (bytes_remaining > 0) {
3083
3084
    /* FrameInfo starts with a 'tag' byte which is formed from 2 nibbles */
3085
6.45k
    uint8_t tag_byte = tvb_get_uint8(tvb, offset);
3086
3087
    /* 0xff isn't defined yet in the spec as to what it should do */
3088
6.45k
    if (tag_byte == 0xFF) {
3089
52
      proto_tree_add_expert_format(tree,
3090
52
                                   pinfo,
3091
52
                                   &ei_warn_unknown_flex_unsupported,
3092
52
                                   tvb,
3093
52
                                   offset,
3094
52
                                   1,
3095
52
                                   "Cannot decode 0xFF id/len byte");
3096
52
      return;
3097
52
    }
3098
3099
    /* extract the nibbles into u16, if the id/len nibbles are escapes, their
3100
       true values come from following bytes and can be larger than u8 */
3101
6.40k
    uint16_t id = tag_byte >> 4;
3102
6.40k
    uint16_t len = tag_byte & 0x0F;
3103
3104
6.40k
    int id_size = 1;
3105
    /* Calculate the id/len and add to the tree */
3106
6.40k
    if (id == FLEX_ESCAPE) {
3107
253
      id = id + tvb_get_uint8(tvb, offset + 1);
3108
253
      id_size++;
3109
253
      info_id = info_id_esc;
3110
253
    }
3111
3112
6.40k
    int len_size = 1;
3113
6.40k
    if (len == FLEX_ESCAPE) {
3114
46
      len = len + tvb_get_uint8(tvb, offset + 1);
3115
46
      len_size++;
3116
46
      info_len_id = hf_flex_frame_len_esc;
3117
46
    }
3118
3119
    /* add a new sub-tree for this FrameInfo */
3120
6.40k
    proto_item* flex_item = proto_tree_add_string_format(tree,
3121
6.40k
                                                         hf_flex_extras_n,
3122
6.40k
                                                         tvb,
3123
6.40k
                                                         offset,
3124
6.40k
                                                         1 + len,
3125
6.40k
                                                         NULL,
3126
6.40k
                                                         "Flexible Frame %d",
3127
6.40k
                                                         frame_index);
3128
3129
6.40k
    proto_tree* frame_tree = proto_item_add_subtree(flex_item,
3130
6.40k
                                                    ett_flex_frame_extras);
3131
3132
    /* Now add the info under the sub-tree */
3133
6.40k
    proto_tree_add_uint(frame_tree, info_id, tvb, offset, id_size, id);
3134
6.40k
    proto_tree_add_uint(frame_tree, info_len_id, tvb, offset, len_size, len);
3135
3136
    /* this is broken if both len and id are escaped, but we've returned earlier
3137
       for that case (with a warning) */
3138
6.40k
    offset = offset + 1 + (len_size - 1) + (id_size - 1);
3139
6.40k
    bytes_remaining = bytes_remaining - 1 - (len_size - 1) - (id_size - 1);
3140
3141
    /* lookup a dissector function by id */
3142
6.40k
    int id_index = 0, found = 0;
3143
14.4k
    while (id_dissectors[id_index].handler) {
3144
13.0k
      if (id_dissectors[id_index].id == id) {
3145
5.05k
        id_dissectors[id_index].handler(tvb, frame_tree, offset, len);
3146
5.05k
        found = 1;
3147
5.05k
        break;
3148
5.05k
      }
3149
8.01k
      id_index++;
3150
8.01k
    }
3151
3152
6.40k
    if (!found)  {
3153
1.27k
      proto_tree_add_expert_format(frame_tree,
3154
1.27k
                                   pinfo,
3155
1.27k
                                   &ei_warn_unknown_flex_id,
3156
1.27k
                                   tvb,
3157
1.27k
                                   offset,
3158
1.27k
                                   len,
3159
1.27k
                                   "FlexFrame: no dissector function for %d", id);
3160
1.27k
    }
3161
3162
6.40k
    offset += len;
3163
6.40k
    bytes_remaining -= len;
3164
6.40k
    frame_index++;
3165
6.40k
  }
3166
135
}
3167
3168
static bool
3169
is_xerror(uint8_t datatype, uint16_t status)
3170
0
{
3171
0
  if ((datatype & DT_JSON) && status != STATUS_SUBDOC_MULTI_PATH_FAILURE) {
3172
0
    return true;
3173
0
  }
3174
0
  return false;
3175
0
}
3176
3177
/// The following section contains dissector functions for the various
3178
/// server initiated push messages (and responses for them).
3179
/// It's easier to understand the logic with a single function per opcode
3180
/// than a long function with a ton of if/else statements
3181
3182
static void d_s_o_clustermap_change_notification_req(tvbuff_t *tvb,
3183
                                                     packet_info *pinfo,
3184
                                                     proto_tree *tree,
3185
                                                     unsigned offset,
3186
0
                                                     unsigned size) {
3187
0
  if (size == 0) {
3188
    // this is an error!
3189
0
    expert_add_info_format(pinfo, tree, &ei_warn_illegal_value_length,
3190
0
                           "Clustermap not present");
3191
0
    return;
3192
0
  }
3193
  // The payload is the clustermap in JSON
3194
0
  proto_tree_add_item(tree, hf_server_clustermap_value, tvb, offset, size,
3195
0
                      ENC_ASCII);
3196
0
  tvbuff_t *json_tvb = tvb_new_subset_length(tvb, offset, size);
3197
0
  call_dissector(json_handle, json_tvb, pinfo, tree);
3198
0
}
3199
3200
static void d_s_o_authenticate_req(tvbuff_t *tvb,
3201
                                   packet_info *pinfo,
3202
                                   proto_tree *tree,
3203
                                   unsigned offset,
3204
0
                                   unsigned size) {
3205
0
  if (size == 0) {
3206
    // this is an error!
3207
0
    expert_add_info_format(pinfo, tree, &ei_warn_illegal_value_length,
3208
0
                           "Authentication payload not present");
3209
0
    return;
3210
0
  }
3211
  // The payload is an JSON object with the authentication request
3212
0
  proto_tree_add_item(tree, hf_server_authentication, tvb, offset, size,
3213
0
                      ENC_ASCII);
3214
0
  tvbuff_t *json_tvb = tvb_new_subset_length(tvb, offset, size);
3215
0
  call_dissector(json_handle, json_tvb, pinfo, tree);
3216
0
}
3217
3218
static void d_s_o_active_external_users_req(tvbuff_t *tvb,
3219
                                            packet_info *pinfo,
3220
                                            proto_tree *tree,
3221
                                            unsigned offset,
3222
0
                                            unsigned size) {
3223
0
  if (size == 0) {
3224
    // this is an error!
3225
0
    expert_add_info_format(pinfo, tree, &ei_warn_illegal_value_length,
3226
0
                           "ActiveExternalUsers payload not present");
3227
0
    return;
3228
0
  }
3229
  // The payload is an JSON array with the list of the users
3230
0
  proto_tree_add_item(tree, hf_server_external_users, tvb, offset, size,
3231
0
                      ENC_ASCII);
3232
0
  tvbuff_t *json_tvb = tvb_new_subset_length(tvb, offset, size);
3233
0
  call_dissector(json_handle, json_tvb, pinfo, tree);
3234
0
}
3235
3236
static void d_s_o_get_authorization_req(tvbuff_t *tvb,
3237
                                        packet_info *pinfo,
3238
                                        proto_tree *tree,
3239
                                        unsigned offset,
3240
0
                                        unsigned size) {
3241
0
  if (size > 0) {
3242
    // this is an error!
3243
0
    proto_item *ti = proto_tree_add_item(tree, hf_value, tvb, offset, size,
3244
0
                                         ENC_ASCII);
3245
0
    expert_add_info_format(pinfo, ti, &ei_warn_shall_not_have_value,
3246
0
                           "GetAuthorization shall not have a value");
3247
0
  }
3248
0
}
3249
3250
/// Dissect the response to a server initiated push message which
3251
/// don't require a response (the client may send it, but the server
3252
/// will silently just ignore the response).
3253
/// If sent the body should not contain value unless the status code
3254
/// is an error and if so it shall be a JSON payload following the
3255
/// standard error format.
3256
static void d_s_o_server_ignored_response(tvbuff_t *tvb,
3257
                                          packet_info *pinfo,
3258
                                          proto_tree *tree,
3259
                                          unsigned offset,
3260
0
                                          unsigned size) {
3261
0
  if (size == 0) {
3262
0
    return;
3263
0
  }
3264
0
  proto_item *ti = proto_tree_add_item(tree, hf_value, tvb, offset, size,
3265
0
                                       ENC_ASCII);
3266
0
  if (get_status(tvb) == STATUS_SUCCESS) {
3267
0
    expert_add_info_format(pinfo, ti, &ei_warn_shall_not_have_value,
3268
0
                           "Success should not carry value");
3269
0
  } else {
3270
0
    tvbuff_t *json_tvb = tvb_new_subset_length(tvb, offset, size);
3271
0
    call_dissector(json_handle, json_tvb, pinfo, tree);
3272
0
  }
3273
0
}
3274
3275
static void d_s_o_authenticate_res(tvbuff_t *tvb ,
3276
                                   packet_info *pinfo ,
3277
                                   proto_tree *tree ,
3278
                                   unsigned offset ,
3279
0
                                   unsigned size ) {
3280
0
  if (size == 0) {
3281
0
    return;
3282
0
  }
3283
3284
  // Payload is JSON (for success and if there is an error)
3285
0
  proto_tree_add_item(tree, hf_server_authentication, tvb, offset, size,
3286
0
                      ENC_ASCII);
3287
0
  tvbuff_t *json_tvb = tvb_new_subset_length(tvb, offset, size);
3288
0
  call_dissector(json_handle, json_tvb, pinfo, tree);
3289
0
}
3290
3291
static void d_s_o_get_authorization_res(tvbuff_t *tvb,
3292
                                        packet_info *pinfo,
3293
                                        proto_tree *tree,
3294
                                        unsigned offset,
3295
0
                                        unsigned size) {
3296
0
  if (size == 0) {
3297
0
    return;
3298
0
  }
3299
3300
  // Payload is JSON (for success and if there is an error)
3301
0
  proto_tree_add_item(tree, hf_server_get_authorization, tvb, offset, size,
3302
0
                      ENC_ASCII);
3303
0
  tvbuff_t *json_tvb = tvb_new_subset_length(tvb, offset, size);
3304
0
  call_dissector(json_handle, json_tvb, pinfo, tree);
3305
3306
0
}
3307
3308
/**
3309
 * Does the opcode use the vbucket or not? (does it make any sense to
3310
 * add the vbucket to the info)
3311
 */
3312
97
static bool opcode_use_vbucket(uint8_t magic _U_, uint8_t opcode) {
3313
97
  switch (opcode) {
3314
0
    case CLIENT_OPCODE_OBSERVE:
3315
0
    case CLIENT_OPCODE_COLLECTIONS_GET_ID:
3316
0
    case CLIENT_OPCODE_IFCONFIG:
3317
0
    case CLIENT_OPCODE_SASL_LIST_MECHS:
3318
1
    case CLIENT_OPCODE_SASL_AUTH:
3319
1
    case CLIENT_OPCODE_SASL_STEP:
3320
1
    case CLIENT_OPCODE_SHUTDOWN:
3321
1
    case CLIENT_OPCODE_AUDIT_CONFIG_RELOAD:
3322
1
    case CLIENT_OPCODE_AUDIT_PUT:
3323
1
    case CLIENT_OPCODE_CONFIG_RELOAD:
3324
1
    case CLIENT_OPCODE_CONFIG_VALIDATE:
3325
1
    case CLIENT_OPCODE_IOCTL_SET:
3326
1
    case CLIENT_OPCODE_IOCTL_GET:
3327
12
    case CLIENT_OPCODE_HELLO:
3328
12
    case CLIENT_OPCODE_VERBOSITY:
3329
12
    case CLIENT_OPCODE_VERSION:
3330
13
    case CLIENT_OPCODE_NOOP:
3331
13
    case CLIENT_OPCODE_QUIT:
3332
13
    case CLIENT_OPCODE_LIST_BUCKETS:
3333
13
    case CLIENT_OPCODE_CREATE_BUCKET:
3334
13
    case CLIENT_OPCODE_DELETE_BUCKET:
3335
13
    case CLIENT_OPCODE_SELECT_BUCKET:
3336
13
      return false;
3337
3338
84
    default:
3339
84
      return true;
3340
97
  }
3341
97
}
3342
3343
/**
3344
 * Each frame header consist of 24 bytes in two slightly different formats
3345
 * (byte 6 and 7 is vbucket id in a request and status in a response).
3346
 *
3347
 * This method dissect the frame header. Please refer to
3348
 * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#request-header
3349
 * for the layout of the frame header.
3350
 */
3351
285
static void dissect_frame_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *couchbase_tree, proto_item *couchbase_item) {
3352
285
  uint8_t magic = get_magic(tvb);
3353
285
  char* str_magic;
3354
285
  proto_item *ti = proto_tree_add_item(couchbase_tree, hf_magic, tvb, 0, 1, ENC_BIG_ENDIAN);
3355
285
  if (try_val_to_str(magic, magic_vals) == NULL) {
3356
129
    expert_add_info_format(pinfo, ti, &ei_warn_unknown_magic_byte, "Unknown magic byte: 0x%x", magic);
3357
129
  }
3358
3359
285
  uint8_t opcode = get_opcode(tvb);
3360
3361
285
  const char *opcode_name;
3362
285
  if (is_server_magic(magic)) {
3363
2
    ti = proto_tree_add_item(couchbase_tree, hf_server_opcode, tvb, 1, 1, ENC_BIG_ENDIAN);
3364
2
    opcode_name = try_val_to_str_ext(opcode, &server_opcode_vals_ext);
3365
283
  } else {
3366
283
    ti = proto_tree_add_item(couchbase_tree, hf_opcode, tvb, 1, 1, ENC_BIG_ENDIAN);
3367
283
    opcode_name = try_val_to_str_ext(opcode, &client_opcode_vals_ext);
3368
283
  }
3369
3370
285
  if (opcode_name == NULL) {
3371
28
    expert_add_info_format(pinfo, ti, &ei_warn_unknown_opcode, "Unknown opcode: 0x%x", opcode);
3372
28
    opcode_name = "Unknown opcode";
3373
28
  }
3374
285
  str_magic = val_to_str(pinfo->pool, magic, magic_vals, "Unknown magic (0x%x)");
3375
285
  proto_item_append_text(couchbase_item, ", %s %s, Opcode: 0x%x",
3376
285
                         opcode_name,
3377
285
                         str_magic,
3378
285
                         opcode);
3379
285
  col_append_fstr(pinfo->cinfo, COL_INFO, "%s %s, Opcode: 0x%x",
3380
285
                  opcode_name,
3381
285
                  str_magic,
3382
285
                  opcode);
3383
3384
  /* Check for flex magic, which changes the header format */
3385
285
  uint16_t keylen;
3386
285
  uint8_t flex_frame_extras = get_flex_framing_extras_length(tvb);
3387
285
  if (is_flex_encoded(magic)) {
3388
    /* 2 separate bytes for the flex_extras and keylen */
3389
152
    proto_tree_add_item(couchbase_tree, hf_flex_extras_length, tvb, 2, 1, ENC_BIG_ENDIAN);
3390
152
    proto_tree_add_item(couchbase_tree, hf_flex_keylength, tvb, 3, 1, ENC_BIG_ENDIAN);
3391
152
  } else {
3392
    /* 2 bytes for the key */
3393
133
    proto_tree_add_item(couchbase_tree, hf_keylength, tvb, 2, 2, ENC_BIG_ENDIAN);
3394
133
  }
3395
285
  keylen = get_key_length(tvb);
3396
3397
285
  uint8_t extlen = get_extras_length(tvb);
3398
285
  proto_tree_add_item(couchbase_tree, hf_extlength, tvb, 4, 1, ENC_BIG_ENDIAN);
3399
3400
285
  proto_tree_add_bitmask(couchbase_tree, tvb, 5, hf_datatype, ett_datatype, datatype_vals, ENC_BIG_ENDIAN);
3401
3402
285
  if (is_request_magic(magic)) {
3403
97
    uint16_t vbucket = tvb_get_ntohs(tvb, 6);
3404
97
    proto_tree_add_item(couchbase_tree, hf_vbucket, tvb, 6, 2, ENC_BIG_ENDIAN);
3405
97
    if (opcode_use_vbucket(magic, opcode)) {
3406
84
      proto_item_append_text(couchbase_item, ", vb:%d", vbucket);
3407
84
      col_append_fstr(pinfo->cinfo, COL_INFO, ", vb:%d", vbucket);
3408
84
    }
3409
188
  } else {
3410
    /* This is a response or invalid magic... */
3411
188
    uint16_t status = get_status(tvb);
3412
188
    ti = proto_tree_add_item(couchbase_tree, hf_status, tvb, 6, 2, ENC_BIG_ENDIAN);
3413
188
    if (status != 0) {
3414
64
      expert_add_info_format(pinfo, ti, &ei_warn_unknown_opcode, "%s: %s",
3415
64
                             val_to_str_ext(pinfo->pool, opcode, &client_opcode_vals_ext, "Unknown opcode (0x%x)"),
3416
64
                             val_to_str_ext(pinfo->pool, status, &status_vals_ext, "Status: 0x%x"));
3417
64
    }
3418
188
  }
3419
3420
285
  uint32_t bodylen = get_body_length(tvb);
3421
285
  uint32_t value_len = bodylen - extlen - keylen - flex_frame_extras;
3422
285
  ti = proto_tree_add_uint(couchbase_tree, hf_value_length, tvb, 8, 0, value_len);
3423
285
  proto_item_set_generated(ti);
3424
3425
285
  proto_tree_add_item(couchbase_tree, hf_total_bodylength, tvb, 8, 4, ENC_BIG_ENDIAN);
3426
3427
  /*
3428
   * The opaque field uses network byte order (big-endian) like all other
3429
   * multi-byte fields in the protocol header. This allows clients to
3430
   * correlate requests with responses.
3431
   */
3432
285
  proto_tree_add_item(couchbase_tree, hf_opaque, tvb, 12, 4, ENC_BIG_ENDIAN);
3433
3434
  // Finally we've got the CAS (which observe has a special use for)
3435
285
  if (opcode == CLIENT_OPCODE_OBSERVE) {
3436
1
    proto_tree_add_item(couchbase_tree, hf_ttp, tvb, 16, 4, ENC_BIG_ENDIAN);
3437
1
    proto_tree_add_item(couchbase_tree, hf_ttr, tvb, 20, 4, ENC_BIG_ENDIAN);
3438
284
  } else {
3439
284
    proto_tree_add_item(couchbase_tree, hf_cas, tvb, 16, 8, ENC_BIG_ENDIAN);
3440
284
  }
3441
285
}
3442
3443
/**
3444
 * Dissect the flexible frame info's encoded in the packet
3445
 */
3446
static void dissect_frame_flex_info_section(tvbuff_t *tvb,
3447
                                            packet_info *pinfo,
3448
                                            proto_tree *tree,
3449
                                            unsigned offset,
3450
                                            uint8_t size,
3451
277
                                            uint8_t magic) {
3452
277
  if (size == 0) {
3453
141
    return;
3454
141
  }
3455
3456
136
  switch (magic) {
3457
0
    case MAGIC_SERVER_RESPONSE:
3458
1
    case MAGIC_SERVER_REQUEST:
3459
      // None of the server initiated messages use flex frame encoding!
3460
1
      proto_tree_add_item(tree, hf_flex_extras, tvb, offset, size, ENC_NA);
3461
1
      proto_tree_add_expert_format(tree,
3462
1
                                   pinfo,
3463
1
                                   &ei_warn_unknown_flex_unsupported,
3464
1
                                   tvb,
3465
1
                                   offset,
3466
1
                                   size,
3467
1
                                   "Server initiated messages don't use flex framing");
3468
1
      break;
3469
3470
84
    case MAGIC_CLIENT_REQUEST_FLEX:
3471
135
    case MAGIC_CLIENT_RESPONSE_FLEX:
3472
135
      dissect_flexible_framing_extras(tvb,
3473
135
                                      pinfo,
3474
135
                                      tree,
3475
135
                                      offset,
3476
135
                                      size,
3477
135
                                      is_request_magic(magic));
3478
135
      break;
3479
0
    default:
3480
0
      proto_tree_add_item(tree, hf_flex_extras, tvb, offset, size, ENC_NA);
3481
0
      proto_tree_add_expert_format(tree,
3482
0
                                   pinfo,
3483
0
                                   &ei_warn_unknown_flex_unsupported,
3484
0
                                   tvb,
3485
0
                                   offset,
3486
0
                                   size,
3487
0
                                   "According to the magic we should not have flex encoding");
3488
136
  }
3489
136
}
3490
3491
/**
3492
 * Dissect the extras section in the frame
3493
 */
3494
static void dissect_frame_extras(tvbuff_t *tvb,
3495
                                 packet_info *pinfo,
3496
                                 proto_tree *tree,
3497
                                 unsigned offset,
3498
                                 uint8_t size,
3499
                                 uint8_t magic,
3500
                                 uint8_t opcode,
3501
203
                                 uint16_t *subdoc_path_len) {
3502
203
  switch (magic) {
3503
0
    case MAGIC_SERVER_RESPONSE:
3504
0
      dissect_server_response_extras(tvb, pinfo, tree, offset, size, opcode);
3505
0
      break;
3506
1
    case MAGIC_SERVER_REQUEST:
3507
1
      dissect_server_request_extras(tvb, pinfo, tree, offset, size, opcode);
3508
1
      break;
3509
58
    case MAGIC_CLIENT_REQUEST_FLEX:
3510
76
    case MAGIC_CLIENT_RESPONSE_FLEX:
3511
77
    case MAGIC_CLIENT_REQUEST:
3512
80
    case MAGIC_CLIENT_RESPONSE:
3513
80
      dissect_client_extras(tvb, pinfo, tree, offset, size,
3514
80
                            opcode, is_request_magic(magic), subdoc_path_len);
3515
80
      break;
3516
122
    default:
3517
122
      proto_tree_add_item(tree, hf_extras, tvb, offset, size, ENC_NA);
3518
122
      proto_tree_add_expert_format(tree,
3519
122
                                   pinfo,
3520
122
                                   &ei_warn_unknown_extras,
3521
122
                                   tvb,
3522
122
                                   offset,
3523
122
                                   size,
3524
122
                                   "Invalid magic so we can't interpret extras");
3525
203
  }
3526
203
}
3527
3528
/**
3529
 * Dissect the key section in the frame
3530
 */
3531
static void dissect_frame_key(tvbuff_t *tvb,
3532
                              packet_info *pinfo,
3533
                              proto_tree *tree,
3534
                              unsigned offset,
3535
                              uint16_t size,
3536
                              uint8_t magic,
3537
185
                              uint8_t opcode) {
3538
185
  if (is_server_magic(magic)) {
3539
1
    dissect_server_key(tvb, pinfo, tree, offset, size, opcode,
3540
1
                       is_request_magic(magic));
3541
184
  } else {
3542
184
    dissect_client_key(tvb, pinfo, tree, offset, size, opcode,
3543
184
                       is_request_magic(magic));
3544
184
  }
3545
185
}
3546
3547
static void dissect_client_value(tvbuff_t *tvb,
3548
                                 packet_info *pinfo,
3549
                                 proto_tree *tree,
3550
                                 unsigned offset,
3551
                                 uint32_t size,
3552
                                 uint8_t magic,
3553
                                 uint8_t opcode,
3554
65
                                 uint16_t subdoc_path_len) {
3555
65
  uint8_t datatype = get_datatype(tvb);
3556
65
  if (is_request_magic(magic)) {
3557
50
    dissect_value(tvb, pinfo, tree, offset, size, subdoc_path_len, opcode, true, datatype);
3558
50
  } else {
3559
15
    uint16_t status = get_status(tvb);
3560
15
    if (status == 0) {
3561
6
      dissect_value(tvb, pinfo, tree, offset, size, subdoc_path_len, opcode, false, datatype);
3562
9
    } else if (size) {
3563
8
      proto_tree_add_item(tree, hf_value, tvb, offset, size, ENC_ASCII);
3564
8
      if (status == STATUS_NOT_MY_VBUCKET || is_xerror(datatype, status)) {
3565
0
        tvbuff_t *json_tvb;
3566
0
        json_tvb = tvb_new_subset_length(tvb, offset, size);
3567
0
        call_dissector(json_handle, json_tvb, pinfo, tree);
3568
8
      } else if (opcode == CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP) {
3569
0
        dissect_multipath_lookup_response(tvb, pinfo, tree, offset, size);
3570
8
      } else if (opcode == CLIENT_OPCODE_SUBDOC_MULTI_MUTATION) {
3571
0
        dissect_multipath_mutation_response(tvb, pinfo, tree, offset, size);
3572
0
      }
3573
8
      col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
3574
8
                      val_to_str_ext(pinfo->pool, status, &status_vals_ext,
3575
8
                                     "Unknown status: 0x%x"));
3576
8
    } else {
3577
      /* Newer opcodes do not include a value in non-SUCCESS responses. */
3578
1
      proto_tree *ti;
3579
1
      switch (opcode) {
3580
0
        case CLIENT_OPCODE_SUBDOC_GET:
3581
0
        case CLIENT_OPCODE_SUBDOC_EXISTS:
3582
0
        case CLIENT_OPCODE_SUBDOC_DICT_ADD:
3583
0
        case CLIENT_OPCODE_SUBDOC_DICT_UPSERT:
3584
0
        case CLIENT_OPCODE_SUBDOC_DELETE:
3585
0
        case CLIENT_OPCODE_SUBDOC_REPLACE:
3586
0
        case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST:
3587
0
        case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST:
3588
0
        case CLIENT_OPCODE_SUBDOC_ARRAY_INSERT:
3589
0
        case CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE:
3590
0
        case CLIENT_OPCODE_SUBDOC_COUNTER:
3591
0
        case CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP:
3592
0
        case CLIENT_OPCODE_SUBDOC_MULTI_MUTATION:
3593
0
          break;
3594
3595
1
        default:
3596
1
          ti = proto_tree_add_item(tree, hf_value, tvb, offset, 0,
3597
1
                                   ENC_ASCII);
3598
1
          expert_add_info_format(pinfo, ti, &ei_value_missing,
3599
1
                                 "%s with status %s (0x%x) must have Value",
3600
1
                                 val_to_str_ext(pinfo->pool, opcode,
3601
1
                                                &client_opcode_vals_ext,
3602
1
                                                "Opcode 0x%x"),
3603
1
                                 val_to_str_ext(pinfo->pool, status,
3604
1
                                                &status_vals_ext,
3605
1
                                                "Unknown"),
3606
1
                                 status);
3607
1
      }
3608
1
    }
3609
15
  }
3610
65
}
3611
3612
static void dissect_server_request_value(tvbuff_t *tvb,
3613
                                         packet_info *pinfo,
3614
                                         proto_tree *tree,
3615
                                         unsigned offset,
3616
0
                                         unsigned size) {
3617
0
  switch (get_opcode(tvb)) {
3618
0
    case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION:
3619
0
      d_s_o_clustermap_change_notification_req(tvb, pinfo, tree, offset, size);
3620
0
      return;
3621
0
    case SERVER_OPCODE_AUTHENTICATE:
3622
0
      d_s_o_authenticate_req(tvb, pinfo, tree, offset, size);
3623
0
      return;
3624
0
    case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS:
3625
0
      d_s_o_active_external_users_req(tvb, pinfo, tree, offset, size);
3626
0
      return;
3627
0
    case SERVER_OPCODE_GET_AUTHORIZATION:
3628
0
      d_s_o_get_authorization_req(tvb, pinfo, tree, offset, size);
3629
0
      return;
3630
0
    default:
3631
      // Unknown packet type.. just dump the data
3632
0
      if (size > 0) {
3633
0
        proto_tree_add_item(tree, hf_value, tvb, offset, size,
3634
0
                            ENC_ASCII);
3635
0
      }
3636
0
      return;
3637
0
  }
3638
0
}
3639
3640
static void dissect_server_response_value(tvbuff_t *tvb,
3641
                                         packet_info *pinfo,
3642
                                         proto_tree *tree,
3643
                                         unsigned offset,
3644
0
                                         unsigned size) {
3645
0
  col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
3646
0
                  val_to_str_ext(pinfo->pool, get_status(tvb), &status_vals_ext,
3647
0
                                 "Unknown status: 0x%x"));
3648
3649
0
  switch (get_opcode(tvb)) {
3650
0
    case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION:
3651
0
      d_s_o_server_ignored_response(tvb, pinfo, tree, offset, size);
3652
0
      return;
3653
0
    case SERVER_OPCODE_AUTHENTICATE:
3654
0
      d_s_o_authenticate_res(tvb, pinfo, tree, offset, size);
3655
0
      return;
3656
0
    case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS:
3657
0
      d_s_o_server_ignored_response(tvb, pinfo, tree, offset, size);
3658
0
      return;
3659
0
    case SERVER_OPCODE_GET_AUTHORIZATION:
3660
0
      d_s_o_get_authorization_res(tvb, pinfo, tree, offset, size);
3661
0
      return;
3662
0
    default:
3663
      // Unknown packet type.. just dump the data
3664
0
      if (size > 0) {
3665
0
        proto_tree_add_item(tree, hf_value, tvb, offset, size,
3666
0
                            ENC_ASCII);
3667
0
      }
3668
0
      return;
3669
0
  }
3670
0
}
3671
3672
/**
3673
 * Dissect the value section in the frame
3674
 */
3675
static void dissect_frame_value(tvbuff_t *tvb,
3676
                                packet_info *pinfo,
3677
                                proto_tree *tree,
3678
                                unsigned offset,
3679
                                uint32_t size,
3680
                                uint8_t magic,
3681
                                uint8_t opcode,
3682
160
                                uint16_t subdoc_path_len) {
3683
160
  if (size > INT32_MAX) {
3684
    // The packet size isn't supported
3685
7
  }
3686
3687
160
  switch (magic) {
3688
0
    case MAGIC_CLIENT_REQUEST:
3689
0
    case MAGIC_CLIENT_RESPONSE:
3690
50
    case MAGIC_CLIENT_REQUEST_FLEX:
3691
65
    case MAGIC_CLIENT_RESPONSE_FLEX:
3692
65
      dissect_client_value(tvb, pinfo, tree, offset, size, magic, opcode, subdoc_path_len);
3693
65
      return;
3694
0
    case MAGIC_SERVER_REQUEST:
3695
0
      dissect_server_request_value(tvb, pinfo, tree, offset, (int)size);
3696
0
      return;
3697
0
    case MAGIC_SERVER_RESPONSE:
3698
0
      dissect_server_response_value(tvb, pinfo, tree, offset, (int)size);
3699
0
      return;
3700
95
    default:
3701
      // Unknown magic... just dump the data
3702
95
      if (size > 0) {
3703
19
        proto_tree_add_item(tree, hf_value, tvb, offset, (int)size, ENC_ASCII);
3704
19
      }
3705
95
      return;
3706
160
  }
3707
160
}
3708
3709
/**
3710
 * Each frame in the protocol consists of a 24 byte header, followed by
3711
 * a variable number of sections (all of the sizes is located in the
3712
 * first 24 byte header):
3713
 *
3714
 * |---------------------------------------|
3715
 * |  Fixed 24 byte frame header           |
3716
 * |---------------------------------------|
3717
 * |  n bytes flex frame info              |
3718
 * |---------------------------------------|
3719
 * |  n bytes extras                       |
3720
 * |---------------------------------------|
3721
 * |  n bytes key                          |
3722
 * |---------------------------------------|
3723
 * |  n bytes value                        |
3724
 * |---------------------------------------|
3725
 *
3726
 * Call each function responsible for printing the segment
3727
 */
3728
static int
3729
dissect_couchbase(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3730
285
{
3731
285
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "Couchbase");
3732
285
  col_clear(pinfo->cinfo, COL_INFO);
3733
3734
285
  proto_item *couchbase_item = proto_tree_add_item(tree, proto_couchbase, tvb, 0, -1, ENC_NA);
3735
285
  proto_tree *couchbase_tree = proto_item_add_subtree(couchbase_item, ett_couchbase);
3736
3737
285
  dissect_frame_header(tvb, pinfo, couchbase_tree, couchbase_item);
3738
285
  uint8_t magic = get_magic(tvb);
3739
285
  unsigned offset = 24;
3740
3741
285
  uint8_t flex_frame_extra_len = get_flex_framing_extras_length(tvb);
3742
285
  uint8_t opcode = get_opcode(tvb);
3743
285
  uint8_t extras_length = get_extras_length(tvb);
3744
285
  uint16_t key_length = get_key_length(tvb);
3745
285
  uint32_t body_length = get_body_length(tvb);
3746
285
  uint32_t value_len = body_length - key_length - extras_length - flex_frame_extra_len;
3747
3748
285
  dissect_frame_flex_info_section(tvb, pinfo, couchbase_tree, offset, flex_frame_extra_len, magic);
3749
285
  offset += flex_frame_extra_len;
3750
3751
285
  uint16_t subdoc_path_len = 0;
3752
  // Dissect the extras section
3753
285
  dissect_frame_extras(tvb, pinfo, couchbase_tree, offset, extras_length, magic, opcode, &subdoc_path_len);
3754
285
  offset += extras_length;
3755
3756
  // dissect the key
3757
285
  dissect_frame_key(tvb, pinfo, couchbase_tree, offset, key_length, magic, opcode);
3758
285
  offset += key_length;
3759
3760
285
  dissect_frame_value(tvb, pinfo, couchbase_tree, offset, value_len, magic, opcode, subdoc_path_len);
3761
285
  return tvb_reported_length(tvb);
3762
285
}
3763
3764
static unsigned
3765
get_couchbase_pdu_length(packet_info *pinfo _U_, tvbuff_t *tvb, int offset,
3766
287
                         void *data _U_) {
3767
  // See https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#packet-structure
3768
  // for a description of each packet.
3769
  // The "length" field is located at offset 8 within the frame and does
3770
  // not include the fixed header.
3771
287
  return tvb_get_ntohl(tvb, offset + 8) + COUCHBASE_HEADER_LEN;
3772
287
}
3773
3774
/* Dissect the couchbase packet */
3775
static int
3776
dissect_couchbase_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
3777
149
                      void *data) {
3778
149
  if (try_val_to_str(tvb_get_uint8(tvb, 0), magic_vals) == NULL) {
3779
    // Magic isn't one of the know magics used by the Couchbase dissector
3780
5
    return 0;
3781
5
  }
3782
3783
144
  tcp_dissect_pdus(tvb, pinfo, tree, couchbase_desegment_body,
3784
144
                   COUCHBASE_HEADER_LEN,
3785
144
                   get_couchbase_pdu_length, dissect_couchbase, data);
3786
144
  return tvb_captured_length(tvb);
3787
149
}
3788
3789
3790
/* Registration functions; register couchbase protocol,
3791
 * its configuration options and also register the tcp dissectors.
3792
 */
3793
void
3794
proto_register_couchbase(void)
3795
15
{
3796
15
  static hf_register_info hf[] = {
3797
15
    { &hf_magic, { "Magic", "couchbase.magic", FT_UINT8, BASE_HEX, VALS(magic_vals), 0x0, "Magic number", HFILL } },
3798
15
    { &hf_opcode, { "Opcode", "couchbase.opcode", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &client_opcode_vals_ext, 0x0, "Command code", HFILL } },
3799
15
    { &hf_server_opcode, { "Server Opcode", "couchbase.server.opcode", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &server_opcode_vals_ext, 0x0, "Command code", HFILL } },
3800
15
    { &hf_extlength, { "Extras Length", "couchbase.extras.length", FT_UINT8, BASE_DEC, NULL, 0x0, "Length in bytes of the command extras", HFILL } },
3801
15
    { &hf_keylength, { "Key Length", "couchbase.key.length", FT_UINT16, BASE_DEC, NULL, 0x0, "Length in bytes of the text key that follows the command extras", HFILL } },
3802
15
    { &hf_value_length, { "Value Length", "couchbase.value.length", FT_UINT32, BASE_DEC, NULL, 0x0, "Length in bytes of the value that follows the key", HFILL } },
3803
15
    { &hf_datatype, { "Data Type", "couchbase.datatype", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3804
15
    { &hf_datatype_json, { "JSON", "couchbase.datatype.json", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DT_JSON, "JSON datatype", HFILL} },
3805
15
    { &hf_datatype_snappy, { "Snappy", "couchbase.datatype.snappy", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DT_SNAPPY, "Snappy Compressed", HFILL} },
3806
15
    { &hf_datatype_xattr, { "XATTR", "couchbase.datatype.xattr", FT_BOOLEAN, 8, TFS(&tfs_set_notset), DT_XATTR, "Xattrs included", HFILL} },
3807
15
    { &hf_vbucket, { "VBucket", "couchbase.vbucket", FT_UINT16, BASE_DEC_HEX, NULL, 0x0, "VBucket ID", HFILL } },
3808
15
    { &hf_status, { "Status", "couchbase.status", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &status_vals_ext, 0x0, "Status of the response", HFILL } },
3809
15
    { &hf_total_bodylength, { "Total Body Length", "couchbase.total_bodylength", FT_UINT32, BASE_DEC, NULL, 0x0, "Length in bytes of extra + key + value", HFILL } },
3810
15
    { &hf_opaque, { "Opaque", "couchbase.opaque", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
3811
15
    { &hf_cas, { "CAS", "couchbase.cas", FT_UINT64, BASE_HEX, NULL, 0x0, "Data version check", HFILL } },
3812
15
    { &hf_ttp, { "Time to Persist", "couchbase.ttp", FT_UINT32, BASE_DEC, NULL, 0x0, "Approximate time needed to persist the key (milliseconds)", HFILL } },
3813
15
    { &hf_ttr, { "Time to Replicate", "couchbase.ttr", FT_UINT32, BASE_DEC, NULL, 0x0, "Approximate time needed to replicate the key (milliseconds)", HFILL } },
3814
3815
15
    { &hf_collection_key_id, { "Collection ID", "couchbase.key.collection_id", FT_UINT32, BASE_HEX, NULL, 0x0, "If this a collection stream, this is the collection-ID", HFILL } },
3816
15
    { &hf_collection_key_logical, { "Collection Logical Key", "couchbase.key.logical_key", FT_STRING, BASE_NONE, NULL, 0x0, "If this a collection stream, this is the key in the collection", HFILL } },
3817
15
    { &hf_collection_manifest_id, { "Collections Manifest ID", "couchbase.key.collection_manifest_id", FT_UINT64, BASE_HEX, NULL, 0x0, "The collections manifest id", HFILL } },
3818
3819
15
    { &hf_flex_keylength, { "Key Length", "couchbase.key.length", FT_UINT8, BASE_DEC, NULL, 0x0, "Length in bytes of the text key that follows the command extras", HFILL } },
3820
15
    { &hf_flex_extras_length, { "Flexible Framing Extras Length", "couchbase.flex_extras", FT_UINT8, BASE_DEC, NULL, 0x0, "Length in bytes of the flexible framing extras that follows the response header", HFILL } },
3821
15
    { &hf_flex_extras, {"Flexible Framing Extras", "couchbase.flex_frame_extras", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3822
15
    { &hf_flex_extras_n, {"Flexible Framing Extras", "couchbase.flex_frame_extras.string", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3823
3824
15
    { &hf_flex_frame_id_byte0, {"Flexible Frame Byte0", "couchbase.flex_frame.byte0", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3825
3826
15
    { &hf_flex_frame_id_req, {"Flexible Frame ID (request)", "couchbase.flex_frame.frame.id", FT_UINT8, BASE_DEC, VALS(flex_frame_request_ids), 0x0, NULL, HFILL } },
3827
15
    { &hf_flex_frame_id_res, {"Flexible Frame ID (response)", "couchbase.flex_frame.frame.id", FT_UINT8, BASE_DEC, VALS(flex_frame_response_ids), 0x0, NULL, HFILL } },
3828
15
    { &hf_flex_frame_id_req_esc, {"Flexible Frame ID esc (request)", "couchbase.flex_frame.frame.id", FT_UINT16, BASE_DEC, VALS(flex_frame_request_ids), 0x0, NULL, HFILL } },
3829
15
    { &hf_flex_frame_id_res_esc, {"Flexible Frame ID esc (response)", "couchbase.flex_frame.frame.id", FT_UINT16, BASE_DEC, VALS(flex_frame_response_ids), 0x0, NULL, HFILL } },
3830
3831
3832
15
    { &hf_flex_frame_len, {"Flexible Frame Len", "couchbase.flex_frame.frame.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3833
15
    { &hf_flex_frame_len_esc, {"Flexible Frame Len (esc)", "couchbase.flex_frame.frame.len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3834
3835
15
    { &hf_flex_frame_tracing_duration, {"Server Recv->Send duration", "couchbase.flex_frame.frame.duration", FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, UNS(&units_microseconds), 0, NULL, HFILL } },
3836
15
    { &hf_flex_frame_ru_count, {"Read unit count", "couchbase.flex_frame.frame.ru_count", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
3837
15
    { &hf_flex_frame_wu_count, {"Write unit count", "couchbase.flex_frame.frame.wu_count", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
3838
15
    { &hf_flex_frame_durability_req, {"Durability Requirement", "couchbase.flex_frame.frame.durability_req", FT_UINT8, BASE_DEC, VALS(flex_frame_durability_req), 0, NULL, HFILL } },
3839
15
    { &hf_flex_frame_dcp_stream_id, {"DCP Stream Identifier", "couchbase.flex_frame.frame.dcp_stream_id", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
3840
15
    { &hf_flex_frame_impersonated_user, {"Impersonated User", "couchbase.flex_frame.frame.impersonated_user", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
3841
3842
15
    { &hf_extras, { "Extras", "couchbase.extras", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3843
15
    { &hf_extras_flags, { "Flags", "couchbase.extras.flags", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
3844
15
    { &hf_extras_flags_backfill, { "Backfill Age", "couchbase.extras.flags.backfill", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0001, NULL, HFILL } },
3845
15
    { &hf_extras_flags_dump, { "Dump", "couchbase.extras.flags.dump", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0002, NULL, HFILL } },
3846
15
    { &hf_extras_flags_list_vbuckets, { "List VBuckets", "couchbase.extras.flags.list_vbuckets", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0004, NULL, HFILL } },
3847
15
    { &hf_extras_flags_takeover_vbuckets, { "Takeover VBuckets", "couchbase.extras.flags.takeover_vbuckets", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0008, NULL, HFILL } },
3848
15
    { &hf_extras_flags_support_ack, { "Support ACK", "couchbase.extras.flags.support_ack", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0010, NULL, HFILL } },
3849
15
    { &hf_extras_flags_request_keys_only, { "Request Keys Only", "couchbase.extras.flags.request_keys_only", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0020, NULL, HFILL } },
3850
15
    { &hf_extras_flags_checkpoint, { "Checkpoint", "couchbase.extras.flags.checkpoint", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0040, NULL, HFILL } },
3851
3852
    /* Sub-document */
3853
15
    { &hf_subdoc_flags, { "Subdoc flags", "couchbase.extras.subdoc.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3854
15
    { &hf_subdoc_flags_mkdirp, { "MKDIR_P", "couchbase.extras.subdoc.flags.mkdir_p", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, "Create non-existent intermediate paths", HFILL} },
3855
15
    { &hf_subdoc_flags_xattrpath, { "XATTR_PATH", "couchbase.extras.subdoc.flags.xattr_path", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x04, "If set path refers to extended attribute (XATTR)", HFILL} },
3856
15
    { &hf_subdoc_flags_expandmacros, { "EXPAND_MACROS", "couchbase.extras.subdoc.flags.expand_macros", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x10, "Expand macro values inside XATTRs", HFILL} },
3857
15
    { &hf_subdoc_flags_reserved, {"Reserved fields", "couchbase.extras.subdoc.flags.reserved", FT_UINT8, BASE_HEX, NULL, 0xEA, "A reserved field", HFILL} },
3858
15
    { &hf_subdoc_doc_flags, { "Subdoc Doc flags", "couchbase.extras.subdoc.doc_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3859
15
    { &hf_subdoc_doc_flags_mkdoc, { "MKDOC", "couchbase.extras.subdoc.doc_flags.mkdoc", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, "Create document if it does not exist, implies mkdir_p", HFILL} },
3860
15
    { &hf_subdoc_doc_flags_add, { "ADD", "couchbase.extras.subdoc.doc_flags.add", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, "Fail if doc already exists", HFILL} },
3861
15
    { &hf_subdoc_doc_flags_accessdeleted, { "ACCESS_DELETED", "couchbase.extras.subdoc.doc_flags.access_deleted", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x04, "Allow access to XATTRs for deleted documents", HFILL} },
3862
15
    { &hf_subdoc_doc_flags_createasdeleted, { "CREATE_AS_DELETED", "couchbase.extras.subdoc.doc_flags.create_as_deleted", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x08, "If the document does not exist then create it in the Deleted state, instead of the normal Alive state", HFILL} },
3863
15
    { &hf_subdoc_doc_flags_revivedocument, { "REVIVE_DOCUMENT", "couchbase.extras.subdoc.doc_flags.revive_document", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x10, "If the document exists in the Deleted state, revive it to the normal Alive state", HFILL} },
3864
15
    { &hf_subdoc_doc_flags_replicaread, { "REPLICA_READ", "couchbase.extras.subdoc.doc_flags.replica_read", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x20, "Operate on a replica vbucket instead of an active one", HFILL} },
3865
15
    { &hf_subdoc_doc_flags_reserved, {"Reserved fields", "couchbase.extras.subdoc.doc_flags.reserved", FT_UINT8, BASE_HEX, NULL, 0xC0, "A reserved field", HFILL} },
3866
15
    { &hf_extras_pathlen, { "Path Length", "couchbase.extras.pathlen", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3867
3868
    /* DCP flags */
3869
15
    { &hf_extras_flags_dcp_connection_type, {"Connection Type", "couchbase.extras.flags.dcp_connection_type", FT_UINT32, BASE_HEX, VALS(dcp_connection_type_vals), 0x00000003, NULL, HFILL } },
3870
15
    { &hf_extras_flags_dcp_add_stream_takeover, {"Take Over", "couchbase.extras.flags.dcp_add_stream_takeover", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0001, NULL, HFILL } },
3871
15
    { &hf_extras_flags_dcp_add_stream_diskonly, {"Disk Only", "couchbase.extras.flags.dcp_add_stream_diskonly", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0002, NULL, HFILL } },
3872
15
    { &hf_extras_flags_dcp_add_stream_latest, {"Latest", "couchbase.extras.flags.dcp_add_stream_latest", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0004, NULL, HFILL } },
3873
15
    { &hf_extras_flags_dcp_snapshot_marker_memory, {"Memory", "couchbase.extras.flags.dcp_snapshot_marker_memory", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0001, NULL, HFILL } },
3874
15
    { &hf_extras_flags_dcp_snapshot_marker_disk, {"Disk", "couchbase.extras.flags.dcp_snapshot_marker_disk", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0002, NULL, HFILL } },
3875
15
    { &hf_extras_flags_dcp_snapshot_marker_chk, {"Chk", "couchbase.extras.flags.dcp_snapshot_marker_chk", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0004, NULL, HFILL } },
3876
15
    { &hf_extras_flags_dcp_snapshot_marker_ack, {"Ack", "couchbase.extras.flags.dcp_snapshot_marker_ack", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0008, NULL, HFILL } },
3877
15
    { &hf_extras_flags_dcp_snapshot_marker_history, {"History", "couchbase.extras.flags.dcp_snapshot_marker_history", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0010, NULL, HFILL } },
3878
15
    { &hf_extras_flags_dcp_snapshot_marker_may_contain_dups, {"May Contain Duplicates", "couchbase.extras.flags.dcp_snapshot_marker_may_contain_duplicates", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0020, NULL, HFILL } },
3879
15
    { &hf_extras_flags_dcp_include_xattrs, {"Include XATTRs", "couchbase.extras.flags.dcp_include_xattrs", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0004, "Indicates the server should include documents XATTRs", HFILL} },
3880
15
    { &hf_extras_flags_dcp_no_value, {"No Value", "couchbase.extras.flags.dcp_no_value", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0008, "Indicates the server should strip off values", HFILL} },
3881
15
    { &hf_extras_flags_dcp_collections, {"Enable Collections", "couchbase.extras.flags.dcp_collections", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0010, "Indicates the server should stream collections", HFILL} },
3882
15
    { &hf_extras_flags_dcp_include_delete_times, {"Include Delete Times", "couchbase.extras.flags.dcp_include_delete_times", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0020, "Indicates the server should include delete timestamps", HFILL} },
3883
15
    { &hf_extras_flags_dcp_oso_snapshot_begin, {"OSO Begin", "couchbase.extras.flags.dcp_oso_snapshot_begin", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0001, "The start of an OSO snapshot", HFILL} },
3884
15
    { &hf_extras_flags_dcp_oso_snapshot_end, {"OSO End", "couchbase.extras.flags.dcp_oso_snapshot_end", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0002, "The end of an OSO snapshot", HFILL} },
3885
3886
15
    { &hf_extras_seqno, { "Sequence number", "couchbase.extras.seqno", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3887
15
    { &hf_extras_mutation_seqno, { "Mutation Sequence Number", "couchbase.extras.mutation_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3888
15
    { &hf_extras_opaque, { "Opaque (vBucket identifier)", "couchbase.extras.opaque", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
3889
15
    { &hf_extras_reserved, { "Reserved", "couchbase.extras.reserved", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } },
3890
15
    { &hf_extras_start_seqno, { "Start Sequence Number", "couchbase.extras.start_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3891
15
    { &hf_extras_end_seqno, { "End Sequence Number", "couchbase.extras.end_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3892
15
    { &hf_extras_high_completed_seqno, { "High Completed Sequence Number", "couchbase.extras.high_completed_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3893
15
    { &hf_extras_max_visible_seqno, { "Max Visible Seqno", "couchbase.extras.max_visible_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3894
15
    { &hf_extras_timestamp, { "PiTR timestamp", "couchbase.extras.timestamp", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3895
15
    { &hf_extras_marker_version, { "Snapshot Marker Version", "couchbase.extras.marker_version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3896
15
    { &hf_extras_vbucket_uuid, { "VBucket UUID", "couchbase.extras.vbucket_uuid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } },
3897
15
    { &hf_extras_snap_start_seqno, { "Snapshot Start Sequence Number", "couchbase.extras.snap_start_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3898
15
    { &hf_extras_snap_end_seqno, { "Snapshot End Sequence Number", "couchbase.extras.snap_end_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3899
15
    { &hf_extras_by_seqno, { "by_seqno", "couchbase.extras.by_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3900
15
    { &hf_extras_prepared_seqno, { "by_seqno (prepared)", "couchbase.extras.by_seqno_prepared", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3901
15
    { &hf_extras_commit_seqno, { "by_seqno (commit)", "couchbase.extras.by_seqno_commit", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3902
15
    { &hf_extras_abort_seqno, { "by_seqno (abort)", "couchbase.extras.by_seqno_abort", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3903
15
    { &hf_extras_rev_seqno, { "rev_seqno", "couchbase.extras.rev_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3904
15
    { &hf_extras_lock_time, { "lock_time", "couchbase.extras.lock_time", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3905
15
    { &hf_extras_nmeta, { "nmeta", "couchbase.extras.nmeta", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3906
15
    { &hf_extras_nru, { "nru", "couchbase.extras.nru", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } },
3907
15
    { &hf_extras_deleted, { "deleted", "couchbase.extras.deleted", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3908
15
    { &hf_extras_bytes_to_ack, { "bytes_to_ack", "couchbase.extras.bytes_to_ack", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3909
15
    { &hf_extras_delete_time, { "delete_time", "couchbase.extras.delete_time", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3910
15
    { &hf_extras_delete_unused, { "unused", "couchbase.extras.delete_unused", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3911
15
    { &hf_extras_system_event_id, { "system_event_id", "couchbase.extras.system_event_id", FT_UINT32, BASE_DEC, VALS(dcp_system_event_id_vals), 0x0, NULL, HFILL } },
3912
15
    { &hf_extras_system_event_version, { "system_event_version", "couchbase.extras.system_event_version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3913
15
    { &hf_extras_dcp_oso_snapshot_flags, { "OSO snapshot flags", "couchbase.extras.dcp_oso_snapshot_flags", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3914
3915
15
    { &hf_failover_log, { "Failover Log", "couchbase.dcp.failover_log", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3916
15
    { &hf_failover_log_size, { "Size", "couchbase.dcp.failover_log.size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3917
15
    { &hf_failover_log_vbucket_uuid, { "VBucket UUID", "couchbase.dcp.failover_log.vbucket_uuid", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } },
3918
15
    { &hf_failover_log_vbucket_seqno, { "Sequence Number", "couchbase.dcp.failover_log.seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3919
3920
15
    { &hf_vbucket_states, { "VBucket States", "couchbase.vbucket_states", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3921
15
    { &hf_vbucket_states_state, { "State", "couchbase.vbucket_states.state", FT_UINT32, BASE_HEX, VALS(vbucket_states_vals), 0x0, NULL, HFILL } },
3922
15
    { &hf_vbucket_states_size, { "Size", "couchbase.vbucket_states.size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3923
15
    { &hf_vbucket_states_id, { "VBucket", "couchbase.vbucket_states.id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3924
15
    { &hf_vbucket_states_seqno, { "Sequence Number", "couchbase.vbucket_states.seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3925
3926
15
    { &hf_extras_expiration, { "Expiration", "couchbase.extras.expiration", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3927
15
    { &hf_extras_delta, { "Amount to Add", "couchbase.extras.delta", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3928
15
    { &hf_extras_initial, { "Initial Value", "couchbase.extras.initial", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3929
15
    { &hf_extras_unknown, { "Unknown", "couchbase.extras.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, "Unknown Extras", HFILL } },
3930
15
    { &hf_key, { "Key", "couchbase.key", FT_STRING, BASE_NONE, NULL, 0x0, "If this is a collection stream, the key is formed of a leb128 prefix and then the key", HFILL } },
3931
15
    { &hf_path, { "Path", "couchbase.path", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3932
15
    { &hf_value, { "Value", "couchbase.value", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3933
15
    { &hf_uint64_response, { "Response", "couchbase.extras.response", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3934
15
    { &hf_observe, { "Observe", "couchbase.observe", FT_STRING, BASE_NONE, NULL, 0x0, "The observe properties", HFILL } },
3935
15
    { &hf_observe_key, { "Key", "couchbase.observe.key", FT_STRING, BASE_NONE, NULL, 0x0, "The observable key", HFILL } },
3936
15
    { &hf_observe_keylength, { "Key Length", "couchbase.observe.keylength", FT_UINT16, BASE_DEC, NULL, 0x0, "The length of the observable key", HFILL } },
3937
15
    { &hf_observe_vbucket, { "VBucket", "couchbase.observe.vbucket", FT_UINT16, BASE_HEX, NULL, 0x0, "VBucket of the observable key", HFILL } },
3938
15
    { &hf_observe_status, { "Status", "couchbase.observe.status", FT_UINT8, BASE_HEX, NULL, 0x0, "Status of the observable key", HFILL } },
3939
15
    { &hf_observe_cas, { "CAS", "couchbase.observe.cas", FT_UINT64, BASE_HEX, NULL,                                                              0x0, "CAS value of the observable key",                                 HFILL } },
3940
15
    { &hf_observe_vbucket_uuid, { "VBucket UUID", "couchbase.observe.vbucket_uuid", FT_UINT64, BASE_HEX, NULL,                                   0x0, NULL,                                                              HFILL } },
3941
15
    { &hf_observe_last_persisted_seqno, { "Last persisted sequence number", "couchbase.observe.last_persisted_seqno", FT_UINT64, BASE_DEC, NULL, 0x0, NULL,                                                              HFILL } },
3942
15
    { &hf_observe_current_seqno, { "Current sequence number", "couchbase.observe.current_seqno", FT_UINT64, BASE_DEC, NULL,                      0x0, NULL,                                                              HFILL } },
3943
15
    { &hf_observe_old_vbucket_uuid, { "Old VBucket UUID", "couchbase.observe.old_vbucket_uuid", FT_UINT64, BASE_HEX, NULL,                       0x0, NULL,                                                              HFILL } },
3944
15
    { &hf_observe_last_received_seqno, { "Last received sequence number", "couchbase.observe.last_received_seqno", FT_UINT64, BASE_DEC, NULL,    0x0, NULL,                                                              HFILL } },
3945
15
    { &hf_observe_failed_over, { "Failed over", "couchbase.observe.failed_over", FT_UINT8, BASE_DEC, NULL,                                       0x0, NULL,                                                              HFILL } },
3946
3947
15
    { &hf_get_errmap_version, {"Version", "couchbase.geterrmap.version", FT_UINT16, BASE_DEC, NULL,                                              0x0, NULL,                                                              HFILL} },
3948
3949
15
    { &hf_multipath_opcode, { "Opcode", "couchbase.multipath.opcode", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &client_opcode_vals_ext,               0x0, "Command code",                                                    HFILL } },
3950
15
    { &hf_multipath_index, { "Index", "couchbase.multipath.index", FT_UINT8, BASE_DEC, NULL,                                                     0x0, NULL,                                                              HFILL } },
3951
15
    { &hf_multipath_pathlen, { "Path Length", "couchbase.multipath.path.length", FT_UINT16, BASE_DEC, NULL,                                      0x0, NULL,                                                              HFILL } },
3952
15
    { &hf_multipath_path, { "Path", "couchbase.multipath.path", FT_STRING, BASE_NONE, NULL,                                                      0x0, NULL,                                                              HFILL } },
3953
15
    { &hf_multipath_valuelen, { "Value Length", "couchbase.multipath.value.length", FT_UINT32, BASE_DEC, NULL,                                   0x0, NULL,                                                              HFILL } },
3954
15
    { &hf_multipath_value, { "Value", "couchbase.multipath.value", FT_STRING, BASE_NONE, NULL,                                                   0x0, NULL,                                                              HFILL } },
3955
3956
15
    { &hf_meta_flags, {"Flags", "couchbase.extras.flags", FT_UINT32, BASE_HEX, NULL,                                                             0x0, NULL,                                                              HFILL} },
3957
15
    { &hf_meta_expiration, {"Expiration", "couchbase.extras.expiration", FT_UINT32, BASE_HEX, NULL,                                              0x0, NULL,                                                              HFILL} },
3958
15
    { &hf_meta_revseqno, {"RevSeqno", "couchbase.extras.revseqno", FT_UINT64, BASE_HEX, NULL,                                                    0x0, NULL,                                                              HFILL} },
3959
15
    { &hf_meta_cas, {"CAS", "couchbase.extras.cas", FT_UINT64, BASE_HEX, NULL,                                                                   0x0, NULL,                                                              HFILL} },
3960
15
    { &hf_meta_options, {"Options", "couchbase.extras.options", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3961
15
    { &hf_force_meta, {"FORCE_WITH_META_OP", "couchbase.extras.options.force_with_meta_op", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0001, NULL, HFILL} },
3962
15
    { &hf_force_accept, {"FORCE_ACCEPT_WITH_META_OPS", "couchbase.extras.options.force_accept_with_meta_ops", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0002, NULL, HFILL} },
3963
15
    { &hf_regenerate_cas, {"REGENERATE_CAS", "couchbase.extras.option.regenerate_cas", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0004, NULL, HFILL} },
3964
15
    { &hf_skip_conflict, {"SKIP_CONFLICT_RESOLUTION", "couchbase.extras.options.skip_conflict_resolution", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0008, NULL, HFILL} },
3965
15
    { &hf_is_expiration, {"IS_EXPIRATION", "couchbase.extras.options.is_expiration", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0010, NULL, HFILL} },
3966
15
    { &hf_metalen, {"Meta Length", "couchbase.extras.meta_length", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3967
15
    { &hf_meta_reqextmeta, {"ReqExtMeta", "couchbase.extras.reqextmeta", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3968
15
    { &hf_meta_deleted, {"Deleted", "couchbase.extras.deleted", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3969
15
    { &hf_exptime, {"Expiry", "couchbase.extras.expiry", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3970
15
    { &hf_extras_meta_seqno, {"Seqno", "couchbase.extras.meta.seqno", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL} },
3971
15
    { &hf_confres, {"ConfRes", "couchbase.extras.confres", FT_UINT8, BASE_HEX, NULL, 0x0, "Conflict Resolution Mode", HFILL} },
3972
3973
15
    { &hf_bucket_type, {"Bucket Type", "couchbase.bucket.type", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3974
15
    { &hf_bucket_config, {"Bucket Config", "couchbase.bucket.config", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3975
15
    { &hf_config_key, {"Key", "couchbase.bucket.config.key", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3976
15
    { &hf_config_value, {"Value", "couchbase.bucket.config.value", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3977
15
    { &hf_hello_features, {"Hello Features", "couchbase.hello.features", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3978
15
    { &hf_hello_features_feature, {"Feature", "couchbase.hello.features.feature", FT_UINT16, BASE_HEX, VALS(feature_vals), 0x0, NULL, HFILL} },
3979
3980
15
    { &hf_xattrs, { "XATTRs", "couchbase.xattrs", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3981
15
    { &hf_xattr_length, {  "XATTR Length", "couchbase.xattrs.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} },
3982
15
    { &hf_xattr_pair_length, { "XATTR Pair Length", "couchbase.xattrs.pair.length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} },
3983
15
    { &hf_xattr_key, { "Key", "couchbase.xattrs.pair.key", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3984
15
    { &hf_xattr_value, { "Value", "couchbase.xattrs.pair.value", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL} },
3985
3986
3987
15
    { &hf_server_extras_cccp_epoch, { "Epoch", "couchbase.server.extras.cccp.epoch", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3988
15
    { &hf_server_extras_cccp_revno, { "Revision", "couchbase.server.extras.cccp.revision", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3989
15
    { &hf_server_clustermap_value, { "Clustermap", "couchbase.server.clustermap.value", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3990
15
    { &hf_server_authentication, { "Authentication", "couchbase.server.authentication", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3991
15
    { &hf_server_external_users, { "External users", "couchbase.server.external_users", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3992
15
    { &hf_server_get_authorization, { "Authorization", "couchbase.server.authorization", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3993
3994
15
    { &hf_range_scan_uuid, { "Range Scan UUID", "couchbase.range_scan.uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL } },
3995
15
    { &hf_range_scan_item_limit, { "Range Scan item limit", "couchbase.range_scan.item_limit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3996
15
    { &hf_range_scan_time_limit, { "Range Scan time limit", "couchbase.range_scan.time_limit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
3997
15
    { &hf_range_scan_byte_limit, { "Range Scan byte limit", "couchbase.range_scan.byte_limit", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }
3998
15
  };
3999
4000
15
  static ei_register_info ei[] = {
4001
15
    { &ei_value_missing, { "couchbase.value_missing", PI_PROTOCOL, PI_WARN, "Value is mandatory for this command", EXPFILL }},
4002
15
    { &ei_warn_shall_not_have_value, { "couchbase.warn.shall_not_have_value", PI_UNDECODED, PI_WARN, "Packet shall not have value", EXPFILL }},
4003
15
    { &ei_warn_shall_not_have_extras, { "couchbase.warn.shall_not_have_extras", PI_UNDECODED, PI_WARN, "Packet shall not have extras", EXPFILL }},
4004
15
    { &ei_warn_shall_not_have_key, { "couchbase.warn.shall_not_have_key", PI_UNDECODED, PI_WARN, "Packet shall not have key", EXPFILL }},
4005
15
    { &ei_warn_must_have_extras, { "couchbase.warn.must_have_extras", PI_UNDECODED, PI_WARN, "Packet must have extras", EXPFILL }},
4006
15
    { &ei_warn_must_have_key, { "couchbase.warn.must_have_key", PI_UNDECODED, PI_WARN, "Message must have Key", EXPFILL }},
4007
15
    { &ei_warn_illegal_extras_length, { "couchbase.warn.illegal_extras_length", PI_UNDECODED, PI_WARN, "Illegal Extras length", EXPFILL }},
4008
15
    { &ei_warn_illegal_value_length, { "couchbase.warn.illegal_value_length", PI_UNDECODED, PI_WARN, "Illegal Value length", EXPFILL }},
4009
15
    { &ei_warn_unknown_magic_byte, { "couchbase.warn.unknown_magic_byte", PI_UNDECODED, PI_WARN, "Unknown magic byte", EXPFILL }},
4010
15
    { &ei_warn_unknown_opcode, { "couchbase.warn.unknown_opcode", PI_UNDECODED, PI_WARN, "Unknown opcode", EXPFILL }},
4011
15
    { &ei_warn_unknown_extras, { "couchbase.warn.unknown_extras", PI_UNDECODED, PI_WARN, "Unknown extras", EXPFILL }},
4012
15
    { &ei_note_status_code, { "couchbase.note.status_code", PI_RESPONSE_CODE, PI_NOTE, "Status", EXPFILL }},
4013
15
    { &ei_separator_not_found, { "couchbase.warn.separator_not_found", PI_UNDECODED, PI_WARN, "Separator not found", EXPFILL }},
4014
15
    { &ei_illegal_value, { "couchbase.warn.illegal_value", PI_UNDECODED, PI_WARN, "Illegal value for command", EXPFILL }},
4015
15
    { &ei_compression_error, { "couchbase.error.compression", PI_UNDECODED, PI_WARN, "Compression error", EXPFILL }},
4016
15
    { &ei_warn_unknown_flex_unsupported, { "couchbase.warn.unsupported_flexible_frame", PI_UNDECODED, PI_WARN, "Unsupported Flexible encoding", EXPFILL }},
4017
15
    { &ei_warn_unknown_flex_id, { "couchbase.warn.unknown_flexible_frame_id", PI_UNDECODED, PI_WARN, "Flexible Response ID warning", EXPFILL }},
4018
15
    { &ei_warn_unknown_flex_len, { "couchbase.warn.unknown_flexible_frame_len", PI_UNDECODED, PI_WARN, "Flexible Response Length warning", EXPFILL }}
4019
15
  };
4020
4021
15
  static int *ett[] = {
4022
15
    &ett_couchbase,
4023
15
    &ett_extras,
4024
15
    &ett_flex_frame_extras,
4025
15
    &ett_extras_flags,
4026
15
    &ett_observe,
4027
15
    &ett_failover_log,
4028
15
    &ett_vbucket_states,
4029
15
    &ett_multipath,
4030
15
    &ett_config,
4031
15
    &ett_config_key,
4032
15
    &ett_hello_features,
4033
15
    &ett_datatype,
4034
15
    &ett_xattrs,
4035
15
    &ett_xattr_pair,
4036
15
    &ett_collection_key
4037
15
  };
4038
4039
15
  module_t *couchbase_module;
4040
15
  expert_module_t* expert_couchbase;
4041
4042
15
  proto_couchbase = proto_register_protocol("Couchbase Protocol", "Couchbase", "couchbase");
4043
4044
15
  proto_register_field_array(proto_couchbase, hf, array_length(hf));
4045
15
  proto_register_subtree_array(ett, array_length(ett));
4046
4047
15
  expert_couchbase = expert_register_protocol(proto_couchbase);
4048
15
  expert_register_field_array(expert_couchbase, ei, array_length(ei));
4049
4050
  /* Register our configuration options */
4051
15
  couchbase_module = prefs_register_protocol(proto_couchbase, &proto_reg_handoff_couchbase);
4052
4053
15
  couchbase_handle = register_dissector("couchbase", dissect_couchbase_pdu, proto_couchbase);
4054
4055
15
  prefs_register_bool_preference(couchbase_module, "desegment_pdus",
4056
15
                                 "Reassemble PDUs spanning multiple TCP segments",
4057
15
                                 "Whether the Couchbase dissector should reassemble PDUs"
4058
15
                                 " spanning multiple TCP segments."
4059
15
                                 " To use this option, you must also enable \"Allow subdissectors"
4060
15
                                 " to reassemble TCP streams\" in the TCP protocol settings.",
4061
15
                                 &couchbase_desegment_body);
4062
4063
15
  prefs_register_uint_preference(couchbase_module, "tls.port", "SSL/TLS Data Port",
4064
15
                                 "The port used for communicating with the data service via SSL/TLS",
4065
15
                                 10, &couchbase_ssl_port_pref);
4066
15
  prefs_register_obsolete_preference(couchbase_module, "ssl_port");
4067
15
}
4068
4069
/* Register the tcp couchbase dissector. */
4070
void
4071
proto_reg_handoff_couchbase(void)
4072
15
{
4073
15
  static bool initialized = false;
4074
4075
15
  if (!initialized){
4076
15
    json_handle = find_dissector_add_dependency("json", proto_couchbase);
4077
15
    dissector_add_uint_range_with_preference("tcp.port", COUCHBASE_DEFAULT_PORT, couchbase_handle);
4078
15
    initialized = true;
4079
15
  } else {
4080
0
    ssl_dissector_delete(couchbase_ssl_port, couchbase_handle);
4081
0
  }
4082
15
  couchbase_ssl_port = couchbase_ssl_port_pref;
4083
15
  ssl_dissector_add(couchbase_ssl_port, couchbase_handle);
4084
15
}
4085
4086
/*
4087
 * Editor modelines
4088
 *
4089
 * Local Variables:
4090
 * c-basic-offset: 2
4091
 * tab-width: 8
4092
 * indent-tabs-mode: nil
4093
 * End:
4094
 *
4095
 * ex: set shiftwidth=2 tabstop=8 expandtab:
4096
 * :indentSize=2:tabSize=8:noTabs=true:
4097
 */