/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 | | */ |