/src/wireshark/epan/dissectors/packet-nano.c
Line | Count | Source |
1 | | /* packet-nano.c |
2 | | * Routines for Nano / RaiBlocks dissection |
3 | | * Copyright 2018, Roland Haenel <roland@haenel.me> |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | /* |
13 | | * For information about Nano / RaiBlocks, go to http://www.nano.org |
14 | | */ |
15 | | |
16 | | #include <config.h> |
17 | | |
18 | | #include <conversation.h> |
19 | | #include "packet-tcp.h" |
20 | | #include <proto_data.h> |
21 | | |
22 | | #include <epan/packet.h> |
23 | | #include <epan/to_str.h> |
24 | | #include <wsutil/str_util.h> |
25 | | |
26 | | void proto_reg_handoff_nano(void); |
27 | | void proto_register_nano(void); |
28 | | |
29 | | static dissector_handle_t nano_handle, nano_tcp_handle; |
30 | | |
31 | | static int proto_nano; |
32 | | |
33 | | static int hf_nano_magic_number; |
34 | | static int hf_nano_version_max; |
35 | | static int hf_nano_version_using; |
36 | | static int hf_nano_version_min; |
37 | | static int hf_nano_packet_type; |
38 | | static int hf_nano_extensions; |
39 | | static int hf_nano_extensions_block_type; |
40 | | static int hf_nano_keepalive_peer_ip; |
41 | | static int hf_nano_keepalive_peer_port; |
42 | | |
43 | | static int hf_nano_block_hash_previous; |
44 | | static int hf_nano_block_hash_source; |
45 | | static int hf_nano_block_signature; |
46 | | static int hf_nano_block_work; |
47 | | static int hf_nano_block_destination_account; |
48 | | static int hf_nano_block_balance; |
49 | | static int hf_nano_block_account; |
50 | | static int hf_nano_block_representative_account; |
51 | | static int hf_nano_block_link; |
52 | | |
53 | | static int hf_nano_vote_account; |
54 | | static int hf_nano_vote_signature; |
55 | | static int hf_nano_vote_sequence; |
56 | | |
57 | | static int hf_nano_bulk_pull_account; |
58 | | static int hf_nano_bulk_pull_block_hash_end; |
59 | | |
60 | | static int hf_nano_frontier_req_account; |
61 | | static int hf_nano_frontier_req_age; |
62 | | static int hf_nano_frontier_req_count; |
63 | | |
64 | | static int hf_nano_bulk_pull_blocks_min_hash; |
65 | | static int hf_nano_bulk_pull_blocks_max_hash; |
66 | | static int hf_nano_bulk_pull_blocks_mode; |
67 | | static int hf_nano_bulk_pull_blocks_max_count; |
68 | | |
69 | | static int hf_nano_bulk_push_block_type; |
70 | | |
71 | | static int hf_nano_bulk_pull_block_type; |
72 | | |
73 | | static int hf_nano_frontier_account; |
74 | | static int hf_nano_frontier_head_hash; |
75 | | |
76 | | static int ett_nano; |
77 | | static int ett_nano_header; |
78 | | static int ett_nano_extensions; |
79 | | static int ett_nano_peers; |
80 | | static int ett_nano_peer_details[8]; |
81 | | static int ett_nano_block; |
82 | | static int ett_nano_vote; |
83 | | static int ett_nano_bulk_pull; |
84 | | static int ett_nano_frontier_req; |
85 | | static int ett_nano_bulk_pull_blocks; |
86 | | static int ett_nano_frontier; |
87 | | |
88 | 2 | #define NANO_PACKET_TYPE_INVALID 0 |
89 | | #define NANO_PACKET_TYPE_NOT_A_TYPE 1 |
90 | 7 | #define NANO_PACKET_TYPE_KEEPALIVE 2 |
91 | 2 | #define NANO_PACKET_TYPE_PUBLISH 3 |
92 | 2 | #define NANO_PACKET_TYPE_CONFIRM_REQ 4 |
93 | 6 | #define NANO_PACKET_TYPE_CONFIRM_ACK 5 |
94 | 10 | #define NANO_PACKET_TYPE_BULK_PULL 6 |
95 | 9 | #define NANO_PACKET_TYPE_BULK_PUSH 7 |
96 | 2 | #define NANO_PACKET_TYPE_FRONTIER_REQ 8 |
97 | 2 | #define NANO_PACKET_TYPE_BULK_PULL_BLOCKS 9 |
98 | | |
99 | | static const value_string nano_packet_type_strings[] = { |
100 | | { NANO_PACKET_TYPE_INVALID, "Invalid" }, |
101 | | { NANO_PACKET_TYPE_NOT_A_TYPE, "Not A Type" }, |
102 | | { NANO_PACKET_TYPE_KEEPALIVE, "Keepalive" }, |
103 | | { NANO_PACKET_TYPE_PUBLISH, "Publish" }, |
104 | | { NANO_PACKET_TYPE_CONFIRM_REQ, "Confirm Req" }, |
105 | | { NANO_PACKET_TYPE_CONFIRM_ACK, "Confirm Ack" }, |
106 | | { NANO_PACKET_TYPE_BULK_PULL, "Bulk Pull" }, |
107 | | { NANO_PACKET_TYPE_BULK_PUSH, "Bulk Push" }, |
108 | | { NANO_PACKET_TYPE_FRONTIER_REQ, "Frontier Req" }, |
109 | | { NANO_PACKET_TYPE_BULK_PULL_BLOCKS, "Bulk Pull Blocks" }, |
110 | | { 0, NULL }, |
111 | | }; |
112 | | |
113 | | #define NANO_BLOCK_TYPE_INVALID 0 |
114 | 0 | #define NANO_BLOCK_TYPE_NOT_A_BLOCK 1 |
115 | 0 | #define NANO_BLOCK_TYPE_SEND 2 |
116 | 1 | #define NANO_BLOCK_TYPE_RECEIVE 3 |
117 | 0 | #define NANO_BLOCK_TYPE_OPEN 4 |
118 | 0 | #define NANO_BLOCK_TYPE_CHANGE 5 |
119 | 0 | #define NANO_BLOCK_TYPE_STATE 6 |
120 | | |
121 | | static const value_string nano_block_type_strings[] = { |
122 | | { NANO_BLOCK_TYPE_INVALID, "Invalid" }, |
123 | | { NANO_BLOCK_TYPE_NOT_A_BLOCK, "Not A Block" }, |
124 | | { NANO_BLOCK_TYPE_SEND, "Send" }, |
125 | | { NANO_BLOCK_TYPE_RECEIVE, "Receive" }, |
126 | | { NANO_BLOCK_TYPE_OPEN, "Open" }, |
127 | | { NANO_BLOCK_TYPE_CHANGE, "Change" }, |
128 | | { NANO_BLOCK_TYPE_STATE, "State" }, |
129 | | { 0, NULL }, |
130 | | }; |
131 | | |
132 | | static const string_string nano_magic_numbers[] = { |
133 | | { "RA", "Nano Test Network" }, |
134 | | { "RB", "Nano Beta Network" }, |
135 | | { "RC", "Nano Production Network" }, |
136 | | { NULL, NULL } |
137 | | }; |
138 | | |
139 | | #define NANO_BULK_PULL_BLOCKS_MODE_LIST_BLOCKS 0 |
140 | | #define NANO_BULK_PULL_BLOCKS_MODE_CHECKSUM_BLOCKS 1 |
141 | | |
142 | | static const value_string nano_bulk_pull_blocks_mode_strings[] = { |
143 | | { NANO_BULK_PULL_BLOCKS_MODE_LIST_BLOCKS, "List Blocks" }, |
144 | | { NANO_BULK_PULL_BLOCKS_MODE_CHECKSUM_BLOCKS, "Checksum Blocks" }, |
145 | | { 0, NULL }, |
146 | | }; |
147 | | |
148 | 14 | #define NANO_UDP_PORT 7075 /* Not IANA registered */ |
149 | 14 | #define NANO_TCP_PORT 7075 /* Not IANA registered */ |
150 | | |
151 | 0 | #define NANO_BLOCK_SIZE_SEND (32+32+16+64+8) |
152 | 1 | #define NANO_BLOCK_SIZE_RECEIVE (32+32+64+8) |
153 | 0 | #define NANO_BLOCK_SIZE_OPEN (32+32+32+64+8) |
154 | 0 | #define NANO_BLOCK_SIZE_CHANGE (32+32+64+8) |
155 | 0 | #define NANO_BLOCK_SIZE_STATE (32+32+32+16+32+64+8) |
156 | | |
157 | | // Nano header length, and thus minimum length of any Nano UDP packet (or bootstrap request) |
158 | 35 | #define NANO_HEADER_LENGTH 8 |
159 | | |
160 | | // Nano bootstrap session state |
161 | | struct nano_session_state { |
162 | | int client_packet_type; |
163 | | uint32_t server_port; |
164 | | }; |
165 | | |
166 | | |
167 | | // dissect the inside of a keepalive packet (that is, the neighbor nodes) |
168 | | static int dissect_nano_keepalive(tvbuff_t *tvb, packet_info *pinfo, proto_tree *nano_tree, int offset) |
169 | 7 | { |
170 | 7 | proto_item *ti; |
171 | 7 | proto_tree *peer_tree, *peer_entry_tree; |
172 | 7 | int i, peers; |
173 | 7 | ws_in6_addr ip_addr; |
174 | 7 | uint32_t port; |
175 | 7 | char buf[100]; |
176 | | |
177 | 7 | peer_tree = proto_tree_add_subtree(nano_tree, tvb, offset, 8*(16+2), ett_nano_peers, NULL, "Peer List"); |
178 | | |
179 | 7 | peers = 0; |
180 | 47 | for (i = 0; i < 8; i++) { |
181 | 40 | peer_entry_tree = proto_tree_add_subtree(peer_tree, tvb, offset, 18, ett_nano_peer_details[i], &ti, "Peer"); |
182 | | |
183 | 40 | tvb_get_ipv6(tvb, offset, &ip_addr); |
184 | 40 | proto_tree_add_item(peer_entry_tree, hf_nano_keepalive_peer_ip, tvb, offset, 16, ENC_NA); |
185 | 40 | offset += 16; |
186 | | |
187 | 40 | proto_tree_add_item_ret_uint(peer_entry_tree, hf_nano_keepalive_peer_port, tvb, offset, 2, ENC_LITTLE_ENDIAN, &port); |
188 | 40 | offset += 2; |
189 | | |
190 | 40 | if (!memcmp(&ip_addr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) { |
191 | 12 | proto_item_append_text(ti, ": (none)"); |
192 | 28 | } else if (!memcmp(&ip_addr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\xff\xff", 12)) { |
193 | 0 | ip_addr_to_str_buf((ws_in4_addr *)((uint8_t *)&ip_addr + 12), buf, sizeof(buf)); |
194 | 0 | proto_item_append_text(ti, ": %s:%d", buf, port); |
195 | 0 | peers++; |
196 | 28 | } else { |
197 | 28 | ip6_to_str_buf(&ip_addr, buf, sizeof(buf)); |
198 | 28 | proto_item_append_text(ti, ": [%s]:%d", buf, port); |
199 | 28 | peers++; |
200 | 28 | } |
201 | 40 | } |
202 | | |
203 | 7 | col_add_fstr(pinfo->cinfo, COL_INFO, "Keepalive (%d peer%s)", peers, plurality(peers, "", "s")); |
204 | | |
205 | 7 | return offset; |
206 | 7 | } |
207 | | |
208 | | // dissect a receive block |
209 | | static int dissect_nano_receive_block(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
210 | 1 | { |
211 | 1 | proto_tree *block_tree; |
212 | | |
213 | 1 | block_tree = proto_tree_add_subtree(nano_tree, tvb, offset, NANO_BLOCK_SIZE_RECEIVE, ett_nano_block, NULL, "Receive Block"); |
214 | | |
215 | 1 | proto_tree_add_item(block_tree, hf_nano_block_hash_previous, tvb, offset, 32, ENC_NA); |
216 | 1 | offset += 32; |
217 | | |
218 | 1 | proto_tree_add_item(block_tree, hf_nano_block_hash_source, tvb, offset, 32, ENC_NA); |
219 | 1 | offset += 32; |
220 | | |
221 | 1 | proto_tree_add_item(block_tree, hf_nano_block_signature, tvb, offset, 64, ENC_NA); |
222 | 1 | offset += 64; |
223 | | |
224 | 1 | proto_tree_add_item(block_tree, hf_nano_block_work, tvb, offset, 8, ENC_NA); |
225 | 1 | offset += 8; |
226 | | |
227 | 1 | return offset; |
228 | 1 | } |
229 | | |
230 | | // dissect a send block |
231 | | static int dissect_nano_send_block(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
232 | 0 | { |
233 | 0 | proto_tree *block_tree; |
234 | |
|
235 | 0 | block_tree = proto_tree_add_subtree(nano_tree, tvb, offset, NANO_BLOCK_SIZE_SEND, ett_nano_block, NULL, "Send Block"); |
236 | |
|
237 | 0 | proto_tree_add_item(block_tree, hf_nano_block_hash_previous, tvb, offset, 32, ENC_NA); |
238 | 0 | offset += 32; |
239 | |
|
240 | 0 | proto_tree_add_item(block_tree, hf_nano_block_destination_account, tvb, offset, 32, ENC_NA); |
241 | 0 | offset += 32; |
242 | |
|
243 | 0 | proto_tree_add_item(block_tree, hf_nano_block_balance, tvb, offset, 16, ENC_NA); |
244 | 0 | offset += 16; |
245 | |
|
246 | 0 | proto_tree_add_item(block_tree, hf_nano_block_signature, tvb, offset, 64, ENC_NA); |
247 | 0 | offset += 64; |
248 | |
|
249 | 0 | proto_tree_add_item(block_tree, hf_nano_block_work, tvb, offset, 8, ENC_NA); |
250 | 0 | offset += 8; |
251 | |
|
252 | 0 | return offset; |
253 | 0 | } |
254 | | |
255 | | // dissect an open block |
256 | | static int dissect_nano_open_block(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
257 | 0 | { |
258 | 0 | proto_tree *block_tree; |
259 | |
|
260 | 0 | block_tree = proto_tree_add_subtree(nano_tree, tvb, offset, NANO_BLOCK_SIZE_OPEN, ett_nano_block, NULL, "Open Block"); |
261 | |
|
262 | 0 | proto_tree_add_item(block_tree, hf_nano_block_hash_source, tvb, offset, 32, ENC_NA); |
263 | 0 | offset += 32; |
264 | |
|
265 | 0 | proto_tree_add_item(block_tree, hf_nano_block_representative_account, tvb, offset, 32, ENC_NA); |
266 | 0 | offset += 32; |
267 | |
|
268 | 0 | proto_tree_add_item(block_tree, hf_nano_block_account, tvb, offset, 32, ENC_NA); |
269 | 0 | offset += 32; |
270 | |
|
271 | 0 | proto_tree_add_item(block_tree, hf_nano_block_signature, tvb, offset, 64, ENC_NA); |
272 | 0 | offset += 64; |
273 | |
|
274 | 0 | proto_tree_add_item(block_tree, hf_nano_block_work, tvb, offset, 8, ENC_NA); |
275 | 0 | offset += 8; |
276 | |
|
277 | 0 | return offset; |
278 | 0 | } |
279 | | |
280 | | // dissect an change block |
281 | | static int dissect_nano_change_block(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
282 | 0 | { |
283 | 0 | proto_tree *block_tree; |
284 | |
|
285 | 0 | block_tree = proto_tree_add_subtree(nano_tree, tvb, offset, NANO_BLOCK_SIZE_CHANGE, ett_nano_block, NULL, "Change Block"); |
286 | |
|
287 | 0 | proto_tree_add_item(block_tree, hf_nano_block_hash_previous, tvb, offset, 32, ENC_NA); |
288 | 0 | offset += 32; |
289 | |
|
290 | 0 | proto_tree_add_item(block_tree, hf_nano_block_representative_account, tvb, offset, 32, ENC_NA); |
291 | 0 | offset += 32; |
292 | |
|
293 | 0 | proto_tree_add_item(block_tree, hf_nano_block_signature, tvb, offset, 64, ENC_NA); |
294 | 0 | offset += 64; |
295 | |
|
296 | 0 | proto_tree_add_item(block_tree, hf_nano_block_work, tvb, offset, 8, ENC_NA); |
297 | 0 | offset += 8; |
298 | |
|
299 | 0 | return offset; |
300 | 0 | } |
301 | | |
302 | | // dissect a state block |
303 | | static int dissect_nano_state(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
304 | 0 | { |
305 | 0 | proto_tree *block_tree; |
306 | |
|
307 | 0 | block_tree = proto_tree_add_subtree(nano_tree, tvb, offset, NANO_BLOCK_SIZE_STATE, ett_nano_block, NULL, "State Block"); |
308 | |
|
309 | 0 | proto_tree_add_item(block_tree, hf_nano_block_account, tvb, offset, 32, ENC_NA); |
310 | 0 | offset += 32; |
311 | |
|
312 | 0 | proto_tree_add_item(block_tree, hf_nano_block_hash_previous, tvb, offset, 32, ENC_NA); |
313 | 0 | offset += 32; |
314 | |
|
315 | 0 | proto_tree_add_item(block_tree, hf_nano_block_representative_account, tvb, offset, 32, ENC_NA); |
316 | 0 | offset += 32; |
317 | |
|
318 | 0 | proto_tree_add_item(block_tree, hf_nano_block_balance, tvb, offset, 16, ENC_NA); |
319 | 0 | offset += 16; |
320 | |
|
321 | 0 | proto_tree_add_item(block_tree, hf_nano_block_link, tvb, offset, 32, ENC_NA); |
322 | 0 | offset += 32; |
323 | |
|
324 | 0 | proto_tree_add_item(block_tree, hf_nano_block_signature, tvb, offset, 64, ENC_NA); |
325 | 0 | offset += 64; |
326 | |
|
327 | 0 | proto_tree_add_item(block_tree, hf_nano_block_work, tvb, offset, 8, ENC_NA); |
328 | 0 | offset += 8; |
329 | |
|
330 | 0 | return offset; |
331 | 0 | } |
332 | | |
333 | | // dissect a vote |
334 | | static int dissect_nano_vote(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
335 | 1 | { |
336 | 1 | proto_tree *vote_tree; |
337 | | |
338 | 1 | vote_tree = proto_tree_add_subtree(nano_tree, tvb, offset, 32+64+8, ett_nano_block, NULL, "Vote"); |
339 | | |
340 | 1 | proto_tree_add_item(vote_tree, hf_nano_vote_account, tvb, offset, 32, ENC_NA); |
341 | 1 | offset += 32; |
342 | | |
343 | 1 | proto_tree_add_item(vote_tree, hf_nano_vote_signature, tvb, offset, 64, ENC_NA); |
344 | 1 | offset += 64; |
345 | | |
346 | 1 | proto_tree_add_item(vote_tree, hf_nano_vote_sequence, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
347 | 1 | offset += 8; |
348 | | |
349 | 1 | return offset; |
350 | 1 | } |
351 | | |
352 | | // dissect a Nano protocol header, fills in the values |
353 | | // for nano_packet_type, nano_block_type |
354 | | static int dissect_nano_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *nano_tree, int offset, unsigned *nano_packet_type, uint64_t *extensions) |
355 | 15 | { |
356 | 15 | proto_tree *header_tree; |
357 | 15 | char *nano_magic_number; |
358 | 15 | static int * const nano_extensions[] = { |
359 | 15 | &hf_nano_extensions_block_type, |
360 | 15 | NULL |
361 | 15 | }; |
362 | | |
363 | 15 | header_tree = proto_tree_add_subtree(nano_tree, tvb, offset, NANO_HEADER_LENGTH, ett_nano_header, NULL, "Nano Protocol Header"); |
364 | | |
365 | 15 | nano_magic_number = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, 2, ENC_ASCII); |
366 | 15 | proto_tree_add_string_format_value(header_tree, hf_nano_magic_number, tvb, 0, |
367 | 15 | 2, nano_magic_number, "%s (%s)", str_to_str_wmem(pinfo->pool, nano_magic_number, nano_magic_numbers, "Unknown"), nano_magic_number); |
368 | 15 | offset += 2; |
369 | | |
370 | 15 | proto_tree_add_item(header_tree, hf_nano_version_max, tvb, offset, 1, ENC_NA); |
371 | 15 | offset += 1; |
372 | | |
373 | 15 | proto_tree_add_item(header_tree, hf_nano_version_using, tvb, offset, 1, ENC_NA); |
374 | 15 | offset += 1; |
375 | | |
376 | 15 | proto_tree_add_item(header_tree, hf_nano_version_min, tvb, offset, 1, ENC_NA); |
377 | 15 | offset += 1; |
378 | | |
379 | 15 | proto_tree_add_item_ret_uint(header_tree, hf_nano_packet_type, tvb, offset, 1, ENC_NA, nano_packet_type); |
380 | 15 | offset += 1; |
381 | | |
382 | 15 | proto_tree_add_bitmask_ret_uint64(header_tree, tvb, offset, hf_nano_extensions, ett_nano_extensions, nano_extensions, ENC_LITTLE_ENDIAN, extensions); |
383 | 15 | offset += 2; |
384 | | |
385 | 15 | return offset; |
386 | 15 | } |
387 | | |
388 | | // dissect a Nano packet (UDP) |
389 | | static int dissect_nano(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
390 | 12 | { |
391 | 12 | proto_item *ti; |
392 | 12 | proto_tree *nano_tree; |
393 | 12 | unsigned nano_packet_type, nano_block_type, offset; |
394 | 12 | uint64_t extensions; |
395 | | |
396 | | /* Check that the packet is long enough for it to belong to us. */ |
397 | 12 | if (tvb_reported_length(tvb) < NANO_HEADER_LENGTH) |
398 | 1 | return 0; |
399 | | |
400 | 11 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Nano"); |
401 | 11 | col_clear(pinfo->cinfo, COL_INFO); |
402 | | |
403 | 11 | ti = proto_tree_add_item(tree, proto_nano, tvb, 0, -1, ENC_NA); |
404 | 11 | nano_tree = proto_item_add_subtree(ti, ett_nano); |
405 | | |
406 | 11 | offset = dissect_nano_header(tvb, pinfo, nano_tree, 0, &nano_packet_type, &extensions); |
407 | | |
408 | | // call specific dissectors for specific packet types |
409 | 11 | switch (nano_packet_type) { |
410 | 7 | case NANO_PACKET_TYPE_KEEPALIVE: |
411 | 7 | return dissect_nano_keepalive(tvb, pinfo, nano_tree, offset); |
412 | | |
413 | 2 | case NANO_PACKET_TYPE_PUBLISH: |
414 | 2 | case NANO_PACKET_TYPE_CONFIRM_REQ: |
415 | 3 | case NANO_PACKET_TYPE_CONFIRM_ACK: |
416 | | |
417 | | // set the INFO header with more information |
418 | 3 | nano_block_type = (unsigned)((extensions >> 8) & 0xF); |
419 | 3 | col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%s)", |
420 | 3 | val_to_str_const(nano_packet_type, VALS(nano_packet_type_strings), " "), |
421 | 3 | val_to_str(pinfo->pool, nano_block_type, VALS(nano_block_type_strings), "Unknown (%d)")); |
422 | | |
423 | | // if it's a Confirm Ack packet, we first have a vote |
424 | 3 | if (nano_packet_type == NANO_PACKET_TYPE_CONFIRM_ACK) { |
425 | 1 | offset = dissect_nano_vote(tvb, nano_tree, offset); |
426 | 1 | } |
427 | | |
428 | | // dissect the actual block |
429 | 3 | switch (nano_block_type) { |
430 | 1 | case NANO_BLOCK_TYPE_RECEIVE: |
431 | 1 | dissect_nano_receive_block(tvb, nano_tree, offset); |
432 | 1 | break; |
433 | 0 | case NANO_BLOCK_TYPE_SEND: |
434 | 0 | dissect_nano_send_block(tvb, nano_tree, offset); |
435 | 0 | break; |
436 | 0 | case NANO_BLOCK_TYPE_OPEN: |
437 | 0 | dissect_nano_open_block(tvb, nano_tree, offset); |
438 | 0 | break; |
439 | 0 | case NANO_BLOCK_TYPE_CHANGE: |
440 | 0 | dissect_nano_change_block(tvb, nano_tree, offset); |
441 | 0 | break; |
442 | 0 | case NANO_BLOCK_TYPE_STATE: |
443 | 0 | dissect_nano_state(tvb, nano_tree, offset); |
444 | 0 | break; |
445 | 3 | } |
446 | 1 | break; |
447 | | |
448 | 1 | default: |
449 | 1 | col_add_str(pinfo->cinfo, COL_INFO, |
450 | 1 | val_to_str(pinfo->pool, nano_packet_type, VALS(nano_packet_type_strings), "Unknown (%d)")); |
451 | 11 | } |
452 | | |
453 | 2 | return tvb_captured_length(tvb); |
454 | 11 | } |
455 | | |
456 | | // determine the length of a nano bootstrap message (client) |
457 | | static unsigned get_nano_tcp_client_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) |
458 | 5 | { |
459 | 5 | int nano_packet_type, nano_block_type; |
460 | 5 | struct nano_session_state *session_state; |
461 | | |
462 | 5 | session_state = (struct nano_session_state *)data; |
463 | 5 | if (session_state->client_packet_type == NANO_PACKET_TYPE_BULK_PUSH) { |
464 | | // we're in the middle of a bulk push, so we expect a block type (uint8) and a block |
465 | |
|
466 | 0 | nano_block_type = tvb_get_uint8(tvb, offset); |
467 | 0 | switch (nano_block_type) { |
468 | 0 | case NANO_BLOCK_TYPE_NOT_A_BLOCK: |
469 | 0 | return 1; |
470 | 0 | case NANO_BLOCK_TYPE_SEND: |
471 | 0 | return 1 + NANO_BLOCK_SIZE_SEND; |
472 | 0 | case NANO_BLOCK_TYPE_RECEIVE: |
473 | 0 | return 1 + NANO_BLOCK_SIZE_RECEIVE; |
474 | 0 | case NANO_BLOCK_TYPE_OPEN: |
475 | 0 | return 1 + NANO_BLOCK_SIZE_OPEN; |
476 | 0 | case NANO_BLOCK_TYPE_CHANGE: |
477 | 0 | return 1 + NANO_BLOCK_SIZE_CHANGE; |
478 | 0 | case NANO_BLOCK_TYPE_STATE: |
479 | 0 | return 1 + NANO_BLOCK_SIZE_STATE; |
480 | 0 | default: |
481 | | // this is invalid |
482 | 0 | return tvb_captured_length(tvb) - offset; |
483 | 0 | } |
484 | 0 | } |
485 | | |
486 | | // we expect a client command, this starts with a full Nano header |
487 | 5 | if (tvb_captured_length(tvb) - offset < NANO_HEADER_LENGTH) { |
488 | 1 | return 0; |
489 | 1 | } |
490 | | |
491 | 4 | nano_packet_type = tvb_get_uint8(tvb, offset + 5); |
492 | | |
493 | 4 | switch (nano_packet_type) { |
494 | 3 | case NANO_PACKET_TYPE_BULK_PULL: |
495 | 3 | return NANO_HEADER_LENGTH + 32 + 32; |
496 | 0 | case NANO_PACKET_TYPE_BULK_PUSH: |
497 | 0 | return NANO_HEADER_LENGTH; |
498 | 0 | case NANO_PACKET_TYPE_FRONTIER_REQ: |
499 | 0 | return NANO_HEADER_LENGTH + 32 + 4 + 4; |
500 | 0 | case NANO_PACKET_TYPE_BULK_PULL_BLOCKS: |
501 | 0 | return NANO_HEADER_LENGTH + 32 + 32 + 1 + 4; |
502 | 4 | } |
503 | | |
504 | 1 | return tvb_captured_length(tvb) - offset; |
505 | 4 | } |
506 | | |
507 | | // dissect a bulk pull request |
508 | | static int dissect_nano_bulk_pull(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
509 | 3 | { |
510 | 3 | proto_tree *vote_tree; |
511 | | |
512 | 3 | vote_tree = proto_tree_add_subtree(nano_tree, tvb, offset, 32+32, ett_nano_bulk_pull, NULL, "Bulk Pull"); |
513 | | |
514 | 3 | proto_tree_add_item(vote_tree, hf_nano_bulk_pull_account, tvb, offset, 32, ENC_NA); |
515 | 3 | offset += 32; |
516 | | |
517 | 3 | proto_tree_add_item(vote_tree, hf_nano_bulk_pull_block_hash_end, tvb, offset, 32, ENC_NA); |
518 | 3 | offset += 32; |
519 | | |
520 | 3 | return offset; |
521 | 3 | } |
522 | | |
523 | | // dissect a frontier request |
524 | | static int dissect_nano_frontier_req(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
525 | 0 | { |
526 | 0 | proto_tree *vote_tree; |
527 | |
|
528 | 0 | vote_tree = proto_tree_add_subtree(nano_tree, tvb, offset, 32+4+4, ett_nano_frontier_req, NULL, "Frontier Request"); |
529 | |
|
530 | 0 | proto_tree_add_item(vote_tree, hf_nano_frontier_req_account, tvb, offset, 32, ENC_NA); |
531 | 0 | offset += 32; |
532 | |
|
533 | 0 | proto_tree_add_item(vote_tree, hf_nano_frontier_req_age, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
534 | 0 | offset += 4; |
535 | |
|
536 | 0 | proto_tree_add_item(vote_tree, hf_nano_frontier_req_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
537 | 0 | offset += 4; |
538 | |
|
539 | 0 | return offset; |
540 | 0 | } |
541 | | |
542 | | // dissect a bulk pull blocks request |
543 | | static int dissect_nano_bulk_pull_blocks(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
544 | 0 | { |
545 | 0 | proto_tree *vote_tree; |
546 | |
|
547 | 0 | vote_tree = proto_tree_add_subtree(nano_tree, tvb, offset, 32+4+4, ett_nano_frontier_req, NULL, "Bulk Pull Blocks"); |
548 | |
|
549 | 0 | proto_tree_add_item(vote_tree, hf_nano_bulk_pull_blocks_min_hash, tvb, offset, 32, ENC_NA); |
550 | 0 | offset += 32; |
551 | |
|
552 | 0 | proto_tree_add_item(vote_tree, hf_nano_bulk_pull_blocks_max_hash, tvb, offset, 32, ENC_NA); |
553 | 0 | offset += 32; |
554 | |
|
555 | 0 | proto_tree_add_item(nano_tree, hf_nano_bulk_pull_blocks_mode, tvb, offset, 1, ENC_NA); |
556 | 0 | offset += 1; |
557 | |
|
558 | 0 | proto_tree_add_item(vote_tree, hf_nano_bulk_pull_blocks_max_count, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
559 | 0 | offset += 4; |
560 | |
|
561 | 0 | return offset; |
562 | 0 | } |
563 | | |
564 | | // dissect a single nano bootstrap message (client) |
565 | | static int dissect_nano_tcp_client_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_) |
566 | 4 | { |
567 | 4 | int offset; |
568 | 4 | uint32_t nano_packet_type, nano_block_type; |
569 | 4 | uint64_t extensions; |
570 | 4 | struct nano_session_state *session_state; |
571 | | |
572 | 4 | session_state = (struct nano_session_state *)data; |
573 | | |
574 | 4 | if (session_state->client_packet_type == NANO_PACKET_TYPE_BULK_PUSH) { |
575 | | // we're within a bulk push |
576 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Bulk Push "); |
577 | 0 | proto_tree_add_item_ret_uint(tree, hf_nano_bulk_push_block_type, tvb, 0, 1, ENC_NA, &nano_block_type); |
578 | 0 | switch (nano_block_type) { |
579 | 0 | case NANO_BLOCK_TYPE_NOT_A_BLOCK: |
580 | 0 | session_state->client_packet_type = NANO_PACKET_TYPE_INVALID; |
581 | 0 | break; |
582 | 0 | case NANO_BLOCK_TYPE_SEND: |
583 | 0 | dissect_nano_send_block(tvb, tree, 1); |
584 | 0 | break; |
585 | 0 | case NANO_BLOCK_TYPE_RECEIVE: |
586 | 0 | dissect_nano_receive_block(tvb, tree, 1); |
587 | 0 | break; |
588 | 0 | case NANO_BLOCK_TYPE_OPEN: |
589 | 0 | dissect_nano_open_block(tvb, tree, 1); |
590 | 0 | break; |
591 | 0 | case NANO_BLOCK_TYPE_CHANGE: |
592 | 0 | dissect_nano_change_block(tvb, tree, 1); |
593 | 0 | break; |
594 | 0 | case NANO_BLOCK_TYPE_STATE: |
595 | 0 | dissect_nano_state(tvb, tree, 1); |
596 | 0 | break; |
597 | 0 | } |
598 | 0 | return tvb_captured_length(tvb); |
599 | 0 | } |
600 | | |
601 | | // a bootstrap client command starts with a Nano header |
602 | 4 | offset = dissect_nano_header(tvb, pinfo, tree, 0, &nano_packet_type, &extensions); |
603 | 4 | session_state->client_packet_type = nano_packet_type; |
604 | | |
605 | 4 | switch (nano_packet_type) { |
606 | 3 | case NANO_PACKET_TYPE_BULK_PULL: |
607 | 3 | col_set_str(pinfo->cinfo, COL_INFO, "Bulk Pull Request "); |
608 | 3 | dissect_nano_bulk_pull(tvb, tree, offset); |
609 | 3 | break; |
610 | 0 | case NANO_PACKET_TYPE_BULK_PUSH: |
611 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Bulk Push Request "); |
612 | 0 | break; |
613 | 0 | case NANO_PACKET_TYPE_FRONTIER_REQ: |
614 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Frontier Request "); |
615 | 0 | dissect_nano_frontier_req(tvb, tree, offset); |
616 | 0 | break; |
617 | 0 | case NANO_PACKET_TYPE_BULK_PULL_BLOCKS: |
618 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Bulk Pull Blocks Request "); |
619 | 0 | dissect_nano_bulk_pull_blocks(tvb, tree, offset); |
620 | 0 | break; |
621 | 4 | } |
622 | | |
623 | 4 | return tvb_captured_length(tvb); |
624 | 4 | } |
625 | | |
626 | | // determine the length of a nano bootstrap message (server) |
627 | | static unsigned get_nano_tcp_server_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) |
628 | 1 | { |
629 | 1 | int nano_block_type; |
630 | 1 | struct nano_session_state *session_state; |
631 | | |
632 | 1 | session_state = (struct nano_session_state *)data; |
633 | | |
634 | 1 | if (session_state->client_packet_type == NANO_PACKET_TYPE_BULK_PULL || |
635 | 1 | session_state->client_packet_type == NANO_PACKET_TYPE_BULK_PULL_BLOCKS) { |
636 | | // we're in response to a bulk pull (blocks), so we expect a block type (uint8) and a block |
637 | |
|
638 | 0 | nano_block_type = tvb_get_uint8(tvb, offset); |
639 | 0 | switch (nano_block_type) { |
640 | 0 | case NANO_BLOCK_TYPE_NOT_A_BLOCK: |
641 | 0 | return 1; |
642 | 0 | case NANO_BLOCK_TYPE_SEND: |
643 | 0 | return 1 + NANO_BLOCK_SIZE_SEND; |
644 | 0 | case NANO_BLOCK_TYPE_RECEIVE: |
645 | 0 | return 1 + NANO_BLOCK_SIZE_RECEIVE; |
646 | 0 | case NANO_BLOCK_TYPE_OPEN: |
647 | 0 | return 1 + NANO_BLOCK_SIZE_OPEN; |
648 | 0 | case NANO_BLOCK_TYPE_CHANGE: |
649 | 0 | return 1 + NANO_BLOCK_SIZE_CHANGE; |
650 | 0 | case NANO_BLOCK_TYPE_STATE: |
651 | 0 | return 1 + NANO_BLOCK_SIZE_STATE; |
652 | 0 | default: |
653 | | // this is invalid |
654 | 0 | return tvb_captured_length(tvb) - offset; |
655 | 0 | } |
656 | 0 | } |
657 | | |
658 | 1 | if (session_state->client_packet_type == NANO_PACKET_TYPE_FRONTIER_REQ) { |
659 | 0 | return 32 + 32; |
660 | 0 | } |
661 | | |
662 | 1 | return tvb_captured_length(tvb) - offset; |
663 | 1 | } |
664 | | |
665 | | // dissect a frontier response entry |
666 | | static int dissect_nano_frontier(tvbuff_t *tvb, proto_tree *nano_tree, int offset) |
667 | 0 | { |
668 | 0 | proto_tree *frontier_tree; |
669 | |
|
670 | 0 | frontier_tree = proto_tree_add_subtree(nano_tree, tvb, offset, 32+32, ett_nano_frontier, NULL, "Frontier"); |
671 | |
|
672 | 0 | proto_tree_add_item(frontier_tree, hf_nano_frontier_account, tvb, offset, 32, ENC_NA); |
673 | 0 | offset += 32; |
674 | |
|
675 | 0 | proto_tree_add_item(frontier_tree, hf_nano_frontier_head_hash, tvb, offset, 32, ENC_NA); |
676 | 0 | offset += 32; |
677 | |
|
678 | 0 | return offset; |
679 | 0 | } |
680 | | |
681 | | // dissect a single nano bootstrap message (server) |
682 | | static int dissect_nano_tcp_server_message(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree _U_, void *data _U_) |
683 | 1 | { |
684 | 1 | uint32_t nano_block_type; |
685 | 1 | struct nano_session_state *session_state; |
686 | | |
687 | 1 | session_state = (struct nano_session_state *)data; |
688 | | |
689 | 1 | if (session_state->client_packet_type == NANO_PACKET_TYPE_BULK_PULL || |
690 | 1 | session_state->client_packet_type == NANO_PACKET_TYPE_BULK_PULL_BLOCKS) { |
691 | | |
692 | | // we're within a bulk pull (blocks) |
693 | 0 | col_set_str(pinfo->cinfo, COL_INFO, session_state->client_packet_type == NANO_PACKET_TYPE_BULK_PULL ? "Bulk Pull Response " : "Bulk Pull Blocks Response "); |
694 | |
|
695 | 0 | proto_tree_add_item_ret_uint(tree, hf_nano_bulk_pull_block_type, tvb, 0, 1, ENC_NA, &nano_block_type); |
696 | 0 | switch (nano_block_type) { |
697 | 0 | case NANO_BLOCK_TYPE_NOT_A_BLOCK: |
698 | 0 | session_state->client_packet_type = NANO_PACKET_TYPE_INVALID; |
699 | 0 | break; |
700 | 0 | case NANO_BLOCK_TYPE_SEND: |
701 | 0 | dissect_nano_send_block(tvb, tree, 1); |
702 | 0 | break; |
703 | 0 | case NANO_BLOCK_TYPE_RECEIVE: |
704 | 0 | dissect_nano_receive_block(tvb, tree, 1); |
705 | 0 | break; |
706 | 0 | case NANO_BLOCK_TYPE_OPEN: |
707 | 0 | dissect_nano_open_block(tvb, tree, 1); |
708 | 0 | break; |
709 | 0 | case NANO_BLOCK_TYPE_CHANGE: |
710 | 0 | dissect_nano_change_block(tvb, tree, 1); |
711 | 0 | break; |
712 | 0 | case NANO_BLOCK_TYPE_STATE: |
713 | 0 | dissect_nano_state(tvb, tree, 1); |
714 | 0 | break; |
715 | 0 | } |
716 | 0 | return tvb_captured_length(tvb); |
717 | 0 | } |
718 | | |
719 | 1 | if (session_state->client_packet_type == NANO_PACKET_TYPE_FRONTIER_REQ) { |
720 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Frontier Response "); |
721 | 0 | dissect_nano_frontier(tvb, tree, 0); |
722 | 0 | } |
723 | | |
724 | 1 | return tvb_captured_length(tvb); |
725 | 1 | } |
726 | | |
727 | | // dissect a Nano bootstrap packet (TCP) |
728 | | static int dissect_nano_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
729 | 4 | { |
730 | 4 | int is_client; |
731 | 4 | proto_item *ti; |
732 | 4 | proto_tree *nano_tree; |
733 | 4 | conversation_t *conversation; |
734 | 4 | struct nano_session_state *session_state, *packet_session_state; |
735 | | |
736 | | // try to find this conversation |
737 | 4 | if ((conversation = find_conversation_pinfo(pinfo, 0)) == NULL) { |
738 | | // create new conversation |
739 | 0 | conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), |
740 | 0 | pinfo->srcport, pinfo->destport, 0); |
741 | 0 | } |
742 | | |
743 | | // try to find session state |
744 | 4 | session_state = (struct nano_session_state *)conversation_get_proto_data(conversation, proto_nano); |
745 | 4 | if (!session_state) { |
746 | | // create new session state |
747 | 2 | session_state = wmem_new0(wmem_file_scope(), struct nano_session_state); |
748 | 2 | session_state->client_packet_type = NANO_PACKET_TYPE_INVALID; |
749 | 2 | session_state->server_port = pinfo->match_uint; |
750 | 2 | conversation_add_proto_data(conversation, proto_nano, session_state); |
751 | 2 | } |
752 | | |
753 | | // check if we have a session state associated with the packet (start state for this packet) |
754 | 4 | packet_session_state = (struct nano_session_state *)p_get_proto_data(wmem_file_scope(), pinfo, proto_nano, 0); |
755 | 4 | if (!packet_session_state) { |
756 | | // this packet does not have a stored session state, get it from the conversation |
757 | 4 | packet_session_state = wmem_new0(wmem_file_scope(), struct nano_session_state); |
758 | 4 | memcpy(packet_session_state, session_state, sizeof(struct nano_session_state)); |
759 | 4 | p_add_proto_data(wmem_file_scope(), pinfo, proto_nano, 0, packet_session_state); |
760 | 4 | } else { |
761 | | // this packet has a stored session state, take this as a starting point |
762 | 0 | memcpy(session_state, packet_session_state, sizeof(struct nano_session_state)); |
763 | 0 | } |
764 | | |
765 | | // set some columns to meaningful defaults |
766 | 4 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Nano Bootstrap"); |
767 | 4 | col_clear(pinfo->cinfo, COL_INFO); |
768 | | |
769 | | // add Nano protocol tree |
770 | 4 | ti = proto_tree_add_item(tree, proto_nano, tvb, 0, -1, ENC_NA); |
771 | 4 | nano_tree = proto_item_add_subtree(ti, ett_nano); |
772 | | |
773 | | // is this a bootstrap client or server? |
774 | 4 | is_client = pinfo->destport == session_state->server_port; |
775 | | |
776 | 4 | if (is_client) { |
777 | | // Nano bootstrap client |
778 | 3 | tcp_dissect_pdus(tvb, pinfo, nano_tree, true, 1, get_nano_tcp_client_message_len, dissect_nano_tcp_client_message, session_state); |
779 | | |
780 | 3 | } else { |
781 | | // Nano bootstrap server |
782 | 1 | tcp_dissect_pdus(tvb, pinfo, nano_tree, true, 1, get_nano_tcp_server_message_len, dissect_nano_tcp_server_message, session_state); |
783 | 1 | } |
784 | | |
785 | 4 | return tvb_captured_length(tvb); |
786 | 4 | } |
787 | | |
788 | | /* Heuristics test */ |
789 | | static bool test_nano(packet_info *pinfo _U_, tvbuff_t *tvb, int offset _U_, void *data _U_) |
790 | 0 | { |
791 | | // if it's not a complete header length, it's not Nano. |
792 | 0 | if (tvb_captured_length(tvb) < NANO_HEADER_LENGTH) |
793 | 0 | return false; |
794 | | |
795 | | // first byte must be 'R', second byte 'A' or 'B' or 'C' |
796 | 0 | if (tvb_get_uint8(tvb, 0) != (uint8_t) 'R') |
797 | 0 | return false; |
798 | | |
799 | 0 | char network = (char) tvb_get_uint8(tvb, 1); |
800 | 0 | if (network != 'A' && network != 'B' && network != 'C') |
801 | 0 | return false; |
802 | | |
803 | 0 | uint8_t version_max = tvb_get_uint8(tvb, 2); |
804 | 0 | uint8_t version_using = tvb_get_uint8(tvb, 3); |
805 | 0 | uint8_t version_min = tvb_get_uint8(tvb, 4); |
806 | 0 | if (version_max > 30 || version_max < version_using || version_using < version_min) |
807 | 0 | return false; |
808 | | |
809 | 0 | uint8_t ptype = tvb_get_uint8(tvb, 5); |
810 | 0 | if (ptype > 15) |
811 | 0 | return false; |
812 | | |
813 | 0 | return true; |
814 | 0 | } |
815 | | |
816 | | static bool dissect_nano_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
817 | 0 | { |
818 | 0 | conversation_t *conversation; |
819 | 0 | struct nano_session_state *session_state; |
820 | |
|
821 | 0 | if (!test_nano(pinfo, tvb, 0, data)) |
822 | 0 | return false; |
823 | | |
824 | 0 | conversation = find_or_create_conversation(pinfo); |
825 | 0 | conversation_set_dissector(conversation, nano_tcp_handle); |
826 | | |
827 | | // try to find session state |
828 | 0 | session_state = (struct nano_session_state *)conversation_get_proto_data(conversation, proto_nano); |
829 | 0 | if (!session_state) { |
830 | | // create new session state |
831 | 0 | session_state = wmem_new0(wmem_file_scope(), struct nano_session_state); |
832 | 0 | session_state->client_packet_type = NANO_PACKET_TYPE_INVALID; |
833 | 0 | session_state->server_port = pinfo->destport; |
834 | 0 | conversation_add_proto_data(conversation, proto_nano, session_state); |
835 | 0 | } |
836 | |
|
837 | 0 | dissect_nano_tcp(tvb, pinfo, tree, data); |
838 | |
|
839 | 0 | return true; |
840 | 0 | } |
841 | | |
842 | | static bool dissect_nano_heur_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
843 | 0 | { |
844 | 0 | conversation_t *conversation; |
845 | |
|
846 | 0 | if (!test_nano(pinfo, tvb, 0, data)) |
847 | 0 | return false; |
848 | | |
849 | 0 | conversation = find_or_create_conversation(pinfo); |
850 | 0 | conversation_set_dissector(conversation, nano_handle); |
851 | |
|
852 | 0 | dissect_nano(tvb, pinfo, tree, data); |
853 | |
|
854 | 0 | return true; |
855 | 0 | } |
856 | | |
857 | | void proto_register_nano(void) |
858 | 14 | { |
859 | 14 | static hf_register_info hf[] = { |
860 | 14 | { &hf_nano_magic_number, |
861 | 14 | { "Magic Number", "nano.magic_number", |
862 | 14 | FT_STRING, BASE_NONE, NULL, 0x00, |
863 | 14 | "Nano Protocol Magic Number", HFILL } |
864 | 14 | }, |
865 | 14 | { &hf_nano_version_max, |
866 | 14 | { "Maximum Version", "nano.version_max", |
867 | 14 | FT_UINT8, BASE_DEC_HEX, NULL, 0x00, |
868 | 14 | "Maximum Supported Protocol Version", HFILL } |
869 | 14 | }, |
870 | 14 | { &hf_nano_version_using, |
871 | 14 | { "Using Version", "nano.version_using", |
872 | 14 | FT_UINT8, BASE_DEC_HEX, NULL, 0x00, |
873 | 14 | "Used Protocol Version", HFILL } |
874 | 14 | }, |
875 | 14 | { &hf_nano_version_min, |
876 | 14 | { "Minimum Version", "nano.version_min", |
877 | 14 | FT_UINT8, BASE_DEC_HEX, NULL, 0x00, |
878 | 14 | "Minimum Supported Protocol Version", HFILL } |
879 | 14 | }, |
880 | 14 | { &hf_nano_packet_type, |
881 | 14 | { "Packet Type", "nano.packet_type", |
882 | 14 | FT_UINT8, BASE_DEC_HEX, VALS(nano_packet_type_strings), 0x00, |
883 | 14 | NULL, HFILL } |
884 | 14 | }, |
885 | 14 | { &hf_nano_extensions, |
886 | 14 | { "Extensions Field", "nano.extensions", |
887 | 14 | FT_UINT16, BASE_HEX, NULL, 0x00, |
888 | 14 | NULL, HFILL } |
889 | 14 | }, |
890 | 14 | { &hf_nano_extensions_block_type, |
891 | 14 | { "Block Type", "nano.extensions.block_type", |
892 | 14 | FT_UINT16, BASE_HEX, VALS(nano_block_type_strings), 0x0f00, |
893 | 14 | NULL, HFILL } |
894 | 14 | }, |
895 | 14 | { &hf_nano_keepalive_peer_ip, |
896 | 14 | { "Peer IP Address", "nano.keepalive.peer_ip", |
897 | 14 | FT_IPv6, BASE_NONE, NULL, 0x00, |
898 | 14 | NULL, HFILL } |
899 | 14 | }, |
900 | 14 | { &hf_nano_keepalive_peer_port, |
901 | 14 | { "Peer Port", "nano.keepalive.peer_port", |
902 | 14 | FT_UINT16, BASE_DEC, NULL, 0x00, |
903 | 14 | NULL, HFILL } |
904 | 14 | }, |
905 | 14 | { &hf_nano_block_hash_previous, |
906 | 14 | { "Previous Block Hash", "nano.block.hash_previous", |
907 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
908 | 14 | NULL, HFILL } |
909 | 14 | }, |
910 | 14 | { &hf_nano_block_hash_source, |
911 | 14 | { "Source Block Hash", "nano.block.hash_source", |
912 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
913 | 14 | NULL, HFILL } |
914 | 14 | }, |
915 | 14 | { &hf_nano_block_signature, |
916 | 14 | { "Signature", "nano.block.signature", |
917 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
918 | 14 | NULL, HFILL } |
919 | 14 | }, |
920 | 14 | { &hf_nano_block_work, |
921 | 14 | { "Work", "nano.block.work", |
922 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
923 | 14 | NULL, HFILL } |
924 | 14 | }, |
925 | 14 | { &hf_nano_block_destination_account, |
926 | 14 | { "Destination Account", "nano.block.destination_account", |
927 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
928 | 14 | NULL, HFILL } |
929 | 14 | }, |
930 | 14 | { &hf_nano_block_balance, |
931 | 14 | { "Balance", "nano.block.balance", |
932 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
933 | 14 | NULL, HFILL } |
934 | 14 | }, |
935 | 14 | { &hf_nano_block_account, |
936 | 14 | { "Account", "nano.block.account", |
937 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
938 | 14 | NULL, HFILL } |
939 | 14 | }, |
940 | 14 | { &hf_nano_block_representative_account, |
941 | 14 | { "Representative Account", "nano.block.representative_account", |
942 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
943 | 14 | NULL, HFILL } |
944 | 14 | }, |
945 | 14 | { &hf_nano_block_link, |
946 | 14 | { "Link", "nano.block.link", |
947 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
948 | 14 | NULL, HFILL } |
949 | 14 | }, |
950 | 14 | { &hf_nano_vote_account, |
951 | 14 | { "Account", "nano.vote.account", |
952 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
953 | 14 | NULL, HFILL } |
954 | 14 | }, |
955 | 14 | { &hf_nano_vote_signature, |
956 | 14 | { "Signature", "nano.vote.signature", |
957 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
958 | 14 | NULL, HFILL } |
959 | 14 | }, |
960 | 14 | { &hf_nano_vote_sequence, |
961 | 14 | { "Sequence", "nano.vote.sequence", |
962 | 14 | FT_UINT64, BASE_DEC_HEX, NULL, 0x00, |
963 | 14 | NULL, HFILL } |
964 | 14 | }, |
965 | 14 | { &hf_nano_bulk_pull_account, |
966 | 14 | { "Account", "nano.bulk_pull.account", |
967 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
968 | 14 | NULL, HFILL } |
969 | 14 | }, |
970 | 14 | { &hf_nano_bulk_pull_block_hash_end, |
971 | 14 | { "End Block Hash", "nano.bulk_pull_block.hash_end", |
972 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
973 | 14 | NULL, HFILL } |
974 | 14 | }, |
975 | 14 | { &hf_nano_frontier_req_account, |
976 | 14 | { "Account", "nano.frontier_req.account", |
977 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
978 | 14 | NULL, HFILL } |
979 | 14 | }, |
980 | 14 | { &hf_nano_frontier_req_age, |
981 | 14 | { "Age", "nano.frontier_req.age", |
982 | 14 | FT_UINT32, BASE_HEX_DEC, NULL, 0x00, |
983 | 14 | NULL, HFILL } |
984 | 14 | }, |
985 | 14 | { &hf_nano_frontier_req_count, |
986 | 14 | { "Count", "nano.frontier_req.count", |
987 | 14 | FT_UINT32, BASE_HEX_DEC, NULL, 0x00, |
988 | 14 | NULL, HFILL } |
989 | 14 | }, |
990 | 14 | { &hf_nano_bulk_pull_blocks_min_hash, |
991 | 14 | { "Min Block Hash", "nano.bulk_pull_blocks.min_hash", |
992 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
993 | 14 | NULL, HFILL } |
994 | 14 | }, |
995 | 14 | { &hf_nano_bulk_pull_blocks_max_hash, |
996 | 14 | { "Max Block Hash", "nano.bulk_pull_blocks.max_hash", |
997 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
998 | 14 | NULL, HFILL } |
999 | 14 | }, |
1000 | 14 | { &hf_nano_bulk_pull_blocks_mode, |
1001 | 14 | { "Mode", "nano.bulk_pull_blocks.mode", |
1002 | 14 | FT_UINT8, BASE_DEC_HEX, VALS(nano_bulk_pull_blocks_mode_strings), 0x00, |
1003 | 14 | NULL, HFILL } |
1004 | 14 | }, |
1005 | 14 | { &hf_nano_bulk_pull_blocks_max_count, |
1006 | 14 | { "Max Count", "nano.bulk_pull_blocks.max_count", |
1007 | 14 | FT_UINT32, BASE_HEX_DEC, NULL, 0x00, |
1008 | 14 | NULL, HFILL } |
1009 | 14 | }, |
1010 | 14 | { &hf_nano_bulk_push_block_type, |
1011 | 14 | { "Block Type", "nano.bulk_push.block_type", |
1012 | 14 | FT_UINT8, BASE_HEX, VALS(nano_block_type_strings), 0x00, |
1013 | 14 | NULL, HFILL } |
1014 | 14 | }, |
1015 | 14 | { &hf_nano_bulk_pull_block_type, |
1016 | 14 | { "Block Type", "nano.bulk_pull.block_type", |
1017 | 14 | FT_UINT8, BASE_HEX, VALS(nano_block_type_strings), 0x00, |
1018 | 14 | NULL, HFILL } |
1019 | 14 | }, |
1020 | 14 | { &hf_nano_frontier_account, |
1021 | 14 | { "Account", "nano.frontier.account", |
1022 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
1023 | 14 | NULL, HFILL } |
1024 | 14 | }, |
1025 | 14 | { &hf_nano_frontier_head_hash, |
1026 | 14 | { "Head Hash", "nano.frontier.head_hash", |
1027 | 14 | FT_BYTES, BASE_NONE, NULL, 0x00, |
1028 | 14 | NULL, HFILL } |
1029 | 14 | } |
1030 | 14 | }; |
1031 | | |
1032 | 14 | static int *ett[] = { |
1033 | 14 | &ett_nano, |
1034 | 14 | &ett_nano_header, |
1035 | 14 | &ett_nano_extensions, |
1036 | 14 | &ett_nano_peers, |
1037 | 14 | &ett_nano_peer_details[0], |
1038 | 14 | &ett_nano_peer_details[1], |
1039 | 14 | &ett_nano_peer_details[2], |
1040 | 14 | &ett_nano_peer_details[3], |
1041 | 14 | &ett_nano_peer_details[4], |
1042 | 14 | &ett_nano_peer_details[5], |
1043 | 14 | &ett_nano_peer_details[6], |
1044 | 14 | &ett_nano_peer_details[7], |
1045 | 14 | &ett_nano_block, |
1046 | 14 | &ett_nano_vote, |
1047 | 14 | &ett_nano_bulk_pull, |
1048 | 14 | &ett_nano_frontier_req, |
1049 | 14 | &ett_nano_bulk_pull_blocks, |
1050 | 14 | &ett_nano_frontier |
1051 | 14 | }; |
1052 | | |
1053 | 14 | proto_nano = proto_register_protocol("Nano Cryptocurrency Protocol", "Nano", "nano"); |
1054 | | |
1055 | 14 | proto_register_field_array(proto_nano, hf, array_length(hf)); |
1056 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
1057 | 14 | } |
1058 | | |
1059 | | void proto_reg_handoff_nano(void) |
1060 | 14 | { |
1061 | 14 | nano_handle = register_dissector("nano", dissect_nano, proto_nano); |
1062 | 14 | dissector_add_uint_with_preference("udp.port", NANO_UDP_PORT, nano_handle); |
1063 | 14 | heur_dissector_add("udp", dissect_nano_heur_udp, "Nano UDP Heuristics", "nano-udp", proto_nano, HEURISTIC_DISABLE); |
1064 | | |
1065 | 14 | nano_tcp_handle = register_dissector("nano-over-tcp", dissect_nano_tcp, proto_nano); |
1066 | 14 | dissector_add_uint_with_preference("tcp.port", NANO_TCP_PORT, nano_tcp_handle); |
1067 | 14 | heur_dissector_add("tcp", dissect_nano_heur_tcp, "Nano TCP Heuristics", "nano-tcp", proto_nano, HEURISTIC_DISABLE); |
1068 | 14 | } |
1069 | | |
1070 | | /* |
1071 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1072 | | * |
1073 | | * Local variables: |
1074 | | * c-basic-offset: 4 |
1075 | | * tab-width: 8 |
1076 | | * indent-tabs-mode: nil |
1077 | | * End: |
1078 | | * |
1079 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
1080 | | * :indentSize=4:tabSize=8:noTabs=true: |
1081 | | */ |