Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-nat-pmp.c
blobf52abfe3e792e4234f313747f357403bbf3bc505
1 /* packet-nat-pmp.c
2 * Routines for NAT Port Mapping Protocol packet disassembly.
3 * RFC 6886
5 * Copyright 2009, Stig Bjorlykke <stig@bjorlykke.org>
7 * Routines for Port Control Protocol packet disassembly
8 * (backwards compatible with NAT Port Mapping protocol)
9 * RFC6887: Port Control Protocol (PCP) https://tools.ietf.org/html/rfc6887
11 * Copyright 2012, Michael Mann
13 * Description Option for the Port Control Protocol
14 * RFC 7220
15 * Discovering NAT64 IPv6 Prefixes Using the Port Control Protocol (PCP)
16 * RFC 7225
18 * Alexis La Goutte
20 * Wireshark - Network traffic analyzer
21 * By Gerald Combs <gerald@wireshark.org>
22 * Copyright 1998 Gerald Combs
24 * SPDX-License-Identifier: GPL-2.0-or-later
27 #include "config.h"
29 #include <epan/packet.h>
30 #include <epan/expert.h>
31 #include <epan/tfs.h>
32 #include <wsutil/array.h>
34 void proto_register_nat_pmp(void);
35 void proto_reg_handoff_nat_pmp(void);
37 static dissector_handle_t nat_pmp_handle;
38 static dissector_handle_t pcp_handle;
40 #define PCP_PORT_RANGE "5350-5351"
42 /* NAT Port opcodes */
43 #define EXTERNAL_ADDRESS_REQUEST 0
44 #define MAP_UDP_REQUEST 1
45 #define MAP_TCP_REQUEST 2
46 #define EXTERNAL_ADDRESS_RESPONSE 128
47 #define MAP_UDP_RESPONSE 129
48 #define MAP_TCP_RESPONSE 130
50 /* Port Control opcodes */
51 #define ANNOUNCE_REQUEST 0
52 #define MAP_REQUEST 1
53 #define PEER_REQUEST 2
54 #define ANNOUNCE_RESPONSE 128
55 #define MAP_RESPONSE 129
56 #define PEER_RESPONSE 130
58 /* Port Control options */
59 #define OPT_THIRD_PARTY 1
60 #define OPT_PREFER_FAILURE 2
61 #define OPT_FILTER 3
62 #define OPT_DESCRIPTION 128
63 #define OPT_PREFIX64 129
64 #define OPT_PORT_SET 130
66 static int proto_nat_pmp;
67 static int proto_pcp;
69 static int hf_version;
70 static int hf_opcode;
71 static int hf_result_code;
72 static int hf_sssoe;
73 static int hf_external_ip;
74 static int hf_reserved;
75 static int hf_internal_port;
76 static int hf_external_port_requested;
77 static int hf_external_port_mapped;
78 static int hf_rpmlis;
79 static int hf_pmlis;
81 static int ett_nat_pmp;
83 /* Port Control Protocol */
84 static int hf_pcp_version;
85 static int hf_request;
86 static int hf_response;
87 static int hf_pcp_r;
88 static int hf_pcp_opcode;
89 static int hf_pcp_result_code;
90 static int hf_reserved1;
91 static int hf_reserved2;
92 static int hf_reserved12;
93 static int hf_req_lifetime;
94 static int hf_rsp_lifetime;
95 static int hf_client_ip;
96 static int hf_epoch_time;
97 static int hf_map_nonce;
98 static int hf_map_protocol;
99 static int hf_map_reserved1;
100 static int hf_map_internal_port;
101 static int hf_map_req_sug_external_port;
102 static int hf_map_req_sug_ext_ip;
103 static int hf_map_rsp_assigned_external_port;
104 static int hf_map_rsp_assigned_ext_ip;
105 static int hf_peer_nonce;
106 static int hf_peer_protocol;
107 static int hf_peer_reserved;
108 static int hf_peer_internal_port;
109 static int hf_peer_req_sug_external_port;
110 static int hf_peer_req_sug_ext_ip;
111 static int hf_peer_remote_peer_port;
112 static int hf_peer_remote_peer_ip;
113 static int hf_peer_rsp_assigned_external_port;
114 static int hf_peer_rsp_assigned_ext_ip;
115 static int hf_options;
116 static int hf_option;
117 static int hf_option_code;
118 static int hf_option_reserved;
119 static int hf_option_length;
120 static int hf_option_third_party_internal_ip;
121 static int hf_option_filter_reserved;
122 static int hf_option_filter_prefix_length;
123 static int hf_option_filter_remote_peer_port;
124 static int hf_option_filter_remote_peer_ip;
125 static int hf_option_description;
126 static int hf_option_p64_length;
127 static int hf_option_p64_prefix64;
128 static int hf_option_p64_suffix;
129 static int hf_option_p64_ipv4_prefix_count;
130 static int hf_option_p64_ipv4_prefix_length;
131 static int hf_option_p64_ipv4_address;
132 static int hf_option_portset_size;
133 static int hf_option_portset_first_suggested_port;
134 static int hf_option_portset_first_assigned_port;
135 static int hf_option_portset_reserved;
136 static int hf_option_portset_parity;
137 static int hf_option_padding;
139 static int ett_pcp;
140 static int ett_opcode;
141 static int ett_option;
142 static int ett_suboption;
144 static expert_field ei_natpmp_opcode_unknown;
145 static expert_field ei_pcp_opcode_unknown;
146 static expert_field ei_pcp_option_unknown;
148 static const value_string opcode_vals[] = {
149 { EXTERNAL_ADDRESS_REQUEST, "External Address Request" },
150 { EXTERNAL_ADDRESS_RESPONSE, "External Address Response" },
151 { MAP_UDP_REQUEST, "Map UDP Request" },
152 { MAP_UDP_RESPONSE, "Map UDP Response" },
153 { MAP_TCP_REQUEST, "Map TCP Request" },
154 { MAP_TCP_RESPONSE, "Map TCP Response" },
155 { 0, NULL }
158 static const value_string result_vals[] = {
159 { 0, "Success" },
160 { 1, "Unsupported Version" },
161 { 2, "Not Authorized/Refused" },
162 { 3, "Network Failure" },
163 { 4, "Out of resources" },
164 { 5, "Unsupported opcode" },
165 { 0, NULL }
168 static const value_string pcp_opcode_vals[] = {
169 { 0, "Announce" },
170 { 1, "Map" },
171 { 2, "Peer" },
172 { 0, NULL }
175 static const value_string pcp_ropcode_vals[] = {
176 { ANNOUNCE_REQUEST, "Announce Request" },
177 { MAP_REQUEST, "Map Request" },
178 { PEER_REQUEST, "Peer Request" },
179 { ANNOUNCE_RESPONSE, "Announce Response" },
180 { MAP_RESPONSE, "Map Response" },
181 { PEER_RESPONSE, "Peer Response" },
182 { 0, NULL }
185 static const value_string pcp_result_vals[] = {
186 { 0, "Success" },
187 { 1, "Unsupported Version" },
188 { 2, "Not Authorized/Refused" },
189 { 3, "Malformed Request" },
190 { 4, "Unsupported opcode" },
191 { 5, "Unsupported option" },
192 { 6, "Malformed option" },
193 { 7, "Network failure" },
194 { 8, "No resources" },
195 { 9, "Unsupported protocol" },
196 { 10, "User exceeds quota" },
197 { 11, "Cannot provide external port" },
198 { 12, "Address mismatch" },
199 { 13, "Excessive remote peers" },
200 { 0, NULL }
203 static const value_string pcp_option_vals[] = {
204 { 0, "Reserved" },
205 { OPT_THIRD_PARTY, "Third Party" },
206 { OPT_PREFER_FAILURE, "Prefer Failure" },
207 { OPT_FILTER, "Filter" },
208 { OPT_DESCRIPTION, "Description" },
209 { OPT_PREFIX64, "Prefix64" },
210 { OPT_PORT_SET, "Port Set" },
211 { 0, NULL }
214 static const value_string pcp_protocol_vals[] = {
215 {0, "All Protocols"},
216 {6, "TCP"},
217 {17, "UDP"},
218 { 0, NULL }
221 static int
222 dissect_nat_pmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
224 proto_tree *nat_pmp_tree;
225 proto_item *ti, *op_ti;
226 int start_offset, offset = 0;
227 uint8_t opcode;
229 col_set_str (pinfo->cinfo, COL_PROTOCOL, "NAT-PMP");
230 col_clear (pinfo->cinfo, COL_INFO);
232 start_offset = offset;
233 ti = proto_tree_add_item(tree, proto_nat_pmp, tvb, offset, -1, ENC_NA);
234 nat_pmp_tree = proto_item_add_subtree(ti, ett_nat_pmp);
236 proto_tree_add_item(nat_pmp_tree, hf_version, tvb, offset, 1, ENC_BIG_ENDIAN);
237 offset++;
239 opcode = tvb_get_uint8 (tvb, offset);
240 proto_item_append_text (ti, ", %s", val_to_str(opcode, opcode_vals, "Unknown opcode: %d"));
241 op_ti = proto_tree_add_item(nat_pmp_tree, hf_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
242 offset++;
244 col_add_str (pinfo->cinfo, COL_INFO, val_to_str(opcode, opcode_vals, "Unknown opcode: %d"));
246 switch(opcode) {
248 case EXTERNAL_ADDRESS_REQUEST:
249 /* No more data */
250 break;
252 case EXTERNAL_ADDRESS_RESPONSE:
253 proto_tree_add_item(nat_pmp_tree, hf_result_code, tvb, offset, 2, ENC_BIG_ENDIAN);
254 offset += 2;
256 proto_tree_add_item(nat_pmp_tree, hf_sssoe, tvb, offset, 4, ENC_BIG_ENDIAN);
257 offset += 4;
259 proto_tree_add_item(nat_pmp_tree, hf_external_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
260 offset += 4;
261 break;
263 case MAP_UDP_REQUEST:
264 case MAP_TCP_REQUEST:
265 proto_tree_add_item(nat_pmp_tree, hf_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
266 offset += 2;
268 proto_tree_add_item(nat_pmp_tree, hf_internal_port, tvb, offset, 2, ENC_BIG_ENDIAN);
269 offset += 2;
271 proto_tree_add_item(nat_pmp_tree, hf_external_port_requested, tvb, offset, 2, ENC_BIG_ENDIAN);
272 offset += 2;
274 proto_tree_add_item(nat_pmp_tree, hf_rpmlis, tvb, offset, 4, ENC_BIG_ENDIAN);
275 offset += 4;
276 break;
278 case MAP_UDP_RESPONSE:
279 case MAP_TCP_RESPONSE:
280 proto_tree_add_item(nat_pmp_tree, hf_result_code, tvb, offset, 2, ENC_BIG_ENDIAN);
281 offset += 2;
283 proto_tree_add_item(nat_pmp_tree, hf_sssoe, tvb, offset, 4, ENC_BIG_ENDIAN);
284 offset += 4;
286 proto_tree_add_item(nat_pmp_tree, hf_internal_port, tvb, offset, 2, ENC_BIG_ENDIAN);
287 offset += 2;
289 proto_tree_add_item(nat_pmp_tree, hf_external_port_mapped, tvb, offset, 2, ENC_BIG_ENDIAN);
290 offset += 2;
292 proto_tree_add_item(nat_pmp_tree, hf_pmlis, tvb, offset, 4, ENC_BIG_ENDIAN);
293 offset += 4;
294 break;
296 default:
297 /* Unknown OP */
298 expert_add_info_format(pinfo, op_ti, &ei_natpmp_opcode_unknown, "Unknown opcode: %d", opcode);
299 break;
302 return (offset-start_offset);
305 static int
306 dissect_portcontrol_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint8_t version)
308 proto_tree *pcp_tree, *opcode_tree = NULL, *option_tree, *option_sub_tree;
309 proto_item *ti, *opcode_ti, *option_ti, *suboption_ti;
310 int offset = 0, start_offset, start_opcode_offset, start_option_offset;
311 uint8_t ropcode, option;
312 uint16_t option_length;
313 int mod_option_length = 0;
314 int option_padding_length = 0;
315 bool is_response;
316 const char* op_str;
318 if(version == 1)
319 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PCP v1");
320 else
321 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PCP v2");
322 col_clear(pinfo->cinfo, COL_INFO);
324 start_offset = offset;
325 ti = proto_tree_add_item(tree, proto_pcp, tvb, offset, -1, ENC_NA);
326 pcp_tree = proto_item_add_subtree(ti, ett_pcp);
328 proto_tree_add_item(pcp_tree, hf_pcp_version, tvb, offset, 1, ENC_BIG_ENDIAN);
329 offset++;
331 ropcode = tvb_get_uint8(tvb, offset);
332 is_response = ropcode & 0x80;
333 op_str = val_to_str(ropcode, pcp_ropcode_vals, "Unknown opcode: %d");
334 proto_item_append_text(ti, ", %s", op_str);
335 proto_tree_add_item(pcp_tree, hf_pcp_r, tvb, offset, 1, ENC_BIG_ENDIAN);
336 opcode_ti = proto_tree_add_item(pcp_tree, hf_pcp_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
337 offset++;
338 col_add_str(pinfo->cinfo, COL_INFO, op_str);
340 if(!is_response)
342 ti = proto_tree_add_boolean(pcp_tree, hf_request, tvb, offset-1, 1, is_response == false);
343 proto_item_set_hidden(ti);
345 proto_tree_add_item(pcp_tree, hf_reserved2, tvb, offset, 2, ENC_BIG_ENDIAN);
346 offset+=2;
348 proto_tree_add_item(pcp_tree, hf_req_lifetime, tvb, offset, 4, ENC_BIG_ENDIAN);
349 offset+=4;
351 proto_tree_add_item(pcp_tree, hf_client_ip, tvb, offset, 16, ENC_NA);
352 offset+=16;
354 else
356 ti = proto_tree_add_boolean(pcp_tree, hf_response, tvb, offset-1, 1, is_response == true);
357 proto_item_set_hidden(ti);
359 proto_tree_add_item(pcp_tree, hf_reserved1, tvb, offset, 1, ENC_BIG_ENDIAN);
360 offset++;
362 proto_tree_add_item(pcp_tree, hf_pcp_result_code, tvb, offset, 1, ENC_BIG_ENDIAN);
363 offset++;
365 proto_tree_add_item(pcp_tree, hf_rsp_lifetime, tvb, offset, 4, ENC_BIG_ENDIAN);
366 offset+=4;
368 proto_tree_add_item(pcp_tree, hf_epoch_time, tvb, offset, 4, ENC_BIG_ENDIAN);
369 offset+=4;
371 proto_tree_add_item(pcp_tree, hf_reserved12, tvb, offset, 12, ENC_NA);
372 offset+=12;
375 start_opcode_offset = offset;
376 if(try_val_to_str(ropcode, pcp_ropcode_vals) != NULL)
378 opcode_tree = proto_tree_add_subtree(pcp_tree, tvb, offset, 0, ett_opcode, &opcode_ti, op_str);
381 uint32_t protocol = 0;
382 uint32_t internal_port = 0;
383 uint32_t external_port = 0;
384 uint32_t port_set_size = 0;
386 switch(ropcode) {
388 case ANNOUNCE_REQUEST:
389 case ANNOUNCE_RESPONSE:
390 /* No data */
391 break;
392 case MAP_REQUEST:
393 case MAP_RESPONSE:
395 if(version > 1) {
396 proto_tree_add_item(opcode_tree, hf_map_nonce, tvb, offset, 12, ENC_NA);
397 offset+=12;
400 proto_tree_add_item_ret_uint(opcode_tree, hf_map_protocol, tvb, offset, 1, ENC_BIG_ENDIAN, &protocol);
401 offset++;
402 proto_tree_add_item(opcode_tree, hf_map_reserved1, tvb, offset, 3, ENC_BIG_ENDIAN);
403 offset += 3;
404 proto_tree_add_item_ret_uint(opcode_tree, hf_map_internal_port, tvb, offset, 2, ENC_BIG_ENDIAN, &internal_port);
405 offset += 2;
407 if (ropcode == MAP_REQUEST) {
408 proto_tree_add_item_ret_uint(opcode_tree, hf_map_req_sug_external_port, tvb, offset, 2, ENC_BIG_ENDIAN, &external_port);
409 offset += 2;
410 proto_tree_add_item(opcode_tree, hf_map_req_sug_ext_ip, tvb, offset, 16, ENC_NA);
411 offset += 16;
412 } else {
413 proto_tree_add_item_ret_uint(opcode_tree, hf_map_rsp_assigned_external_port, tvb, offset, 2, ENC_BIG_ENDIAN, &external_port);
414 offset += 2;
415 proto_tree_add_item(opcode_tree, hf_map_rsp_assigned_ext_ip, tvb, offset, 16, ENC_NA);
416 offset += 16;
419 break;
421 case PEER_REQUEST:
422 case PEER_RESPONSE:
423 if(version > 1)
425 proto_tree_add_item(opcode_tree, hf_peer_nonce, tvb, offset, 12, ENC_NA);
426 offset+=12;
429 proto_tree_add_item(opcode_tree, hf_peer_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
430 offset++;
431 proto_tree_add_item(opcode_tree, hf_peer_reserved, tvb, offset, 3, ENC_NA);
432 offset+=3;
433 proto_tree_add_item(opcode_tree, hf_peer_internal_port, tvb, offset, 2, ENC_BIG_ENDIAN);
434 offset+=2;
435 if(ropcode == PEER_REQUEST)
437 proto_tree_add_item(opcode_tree, hf_peer_req_sug_external_port, tvb, offset, 2, ENC_BIG_ENDIAN);
438 offset+=2;
439 proto_tree_add_item(opcode_tree, hf_peer_req_sug_ext_ip, tvb, offset, 16, ENC_NA);
440 offset+=16;
442 else
444 proto_tree_add_item(opcode_tree, hf_peer_rsp_assigned_external_port, tvb, offset, 2, ENC_BIG_ENDIAN);
445 offset+=2;
446 proto_tree_add_item(opcode_tree, hf_peer_rsp_assigned_ext_ip, tvb, offset, 16, ENC_NA);
447 offset+=16;
450 proto_tree_add_item(opcode_tree, hf_peer_remote_peer_port, tvb, offset, 2, ENC_BIG_ENDIAN);
451 offset+=2;
452 proto_tree_add_item(opcode_tree, hf_peer_reserved, tvb, offset, 2, ENC_NA);
453 offset+=2;
454 proto_tree_add_item(opcode_tree, hf_peer_remote_peer_ip, tvb, offset, 16, ENC_NA);
455 offset+=16;
456 break;
457 default:
458 /* Unknown OP */
459 expert_add_info_format(pinfo, opcode_ti, &ei_pcp_opcode_unknown, "Unknown opcode: %d", ropcode);
460 break;
463 /* Now see if there are any options for the supported opcodes */
464 if((tvb_reported_length_remaining(tvb, offset) > 0) &&
465 (try_val_to_str(ropcode, pcp_ropcode_vals) != NULL))
467 start_option_offset = offset;
468 option_ti = proto_tree_add_item(opcode_tree, hf_options, tvb, offset, 0, ENC_NA);
469 option_tree = proto_item_add_subtree(option_ti, ett_option);
471 while(tvb_reported_length_remaining(tvb, offset) > 0)
473 suboption_ti = proto_tree_add_item(option_tree, hf_option, tvb, offset, 1, ENC_NA);
474 option_sub_tree = proto_item_add_subtree(suboption_ti, ett_suboption);
476 proto_tree_add_item(option_sub_tree, hf_option_code, tvb, offset, 1, ENC_BIG_ENDIAN);
477 option = tvb_get_uint8(tvb, offset);
478 proto_item_append_text(suboption_ti, ": %s", val_to_str(option, pcp_option_vals, "Unknown option: %d"));
479 offset++;
481 proto_tree_add_item(option_sub_tree, hf_option_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
482 offset++;
484 proto_tree_add_item(option_sub_tree, hf_option_length, tvb, offset, 2, ENC_BIG_ENDIAN);
485 option_length = tvb_get_ntohs(tvb, offset);
486 offset+=2;
488 mod_option_length = option_length % 4;
489 if( mod_option_length != 0 )
491 option_padding_length = 4 - mod_option_length;
494 proto_item_set_len(suboption_ti, option_length+4+option_padding_length);
496 if(option_length > 0)
498 switch(option) {
500 case OPT_THIRD_PARTY:
501 proto_tree_add_item(option_sub_tree, hf_option_third_party_internal_ip, tvb, offset, 16, ENC_NA);
502 break;
504 case OPT_PREFER_FAILURE:
505 /* No data */
506 break;
508 case OPT_FILTER:
509 proto_tree_add_item(option_sub_tree, hf_option_filter_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
510 proto_tree_add_item(option_sub_tree, hf_option_filter_prefix_length, tvb, offset+1, 1, ENC_BIG_ENDIAN);
511 proto_tree_add_item(option_sub_tree, hf_option_filter_remote_peer_port, tvb, offset+2, 2, ENC_BIG_ENDIAN);
512 proto_tree_add_item(option_sub_tree, hf_option_filter_remote_peer_ip, tvb, offset+4, 16, ENC_NA);
513 break;
515 case OPT_DESCRIPTION:
516 proto_tree_add_item(option_sub_tree, hf_option_description, tvb, offset, option_length, ENC_UTF_8);
517 break;
519 case OPT_PREFIX64:
521 uint32_t p64_length;
522 int optoffset = 0;
524 if(option_length-optoffset < 2)
526 /*TODO: report an error here*/
527 break;
529 proto_tree_add_item_ret_uint(option_sub_tree, hf_option_p64_length, tvb, offset+optoffset, 2, ENC_BIG_ENDIAN, &p64_length);
530 optoffset += 2;
531 if(option_length-optoffset < 12)
533 /*TODO: report an error here*/
534 break;
536 if(p64_length <= 12)
538 /*TODO: Fix display of Prefix64 and Suffix*/
539 proto_tree_add_item(option_sub_tree, hf_option_p64_prefix64, tvb, offset+optoffset, p64_length, ENC_NA);
540 optoffset += p64_length;
542 proto_tree_add_item(option_sub_tree, hf_option_p64_suffix, tvb, offset+optoffset, 12-p64_length, ENC_NA);
543 optoffset += (12-p64_length);
544 } else {
545 /*TODO: report an error here*/
546 optoffset += 12;
549 if(option_length-optoffset > 0)
551 uint32_t ipv4_prefix_count;
553 if(option_length-optoffset < 2)
555 /*TODO: report an error here*/
556 break;
558 proto_tree_add_item_ret_uint(option_sub_tree, hf_option_p64_ipv4_prefix_count, tvb, offset+optoffset, 2, ENC_BIG_ENDIAN, &ipv4_prefix_count);
559 optoffset += 2;
561 while(ipv4_prefix_count)
563 if(option_length-optoffset < 2)
565 /*TODO: report an error here*/
566 break;
568 proto_tree_add_item(option_sub_tree, hf_option_p64_ipv4_prefix_length, tvb, offset+optoffset, 2, ENC_BIG_ENDIAN);
569 optoffset += 2;
570 if(option_length-optoffset < 4)
572 /*TODO: report an error here*/
573 break;
575 proto_tree_add_item(option_sub_tree, hf_option_p64_ipv4_address, tvb, offset+optoffset, 4, ENC_BIG_ENDIAN);
576 optoffset += 4;
577 ipv4_prefix_count--;
581 break;
583 case OPT_PORT_SET:
584 proto_tree_add_item_ret_uint(option_sub_tree, hf_option_portset_size, tvb, offset, 2, ENC_BIG_ENDIAN, &port_set_size);
585 if (!is_response) {
586 proto_tree_add_item_ret_uint(option_sub_tree, hf_option_portset_first_suggested_port, tvb, offset + 2, 2, ENC_BIG_ENDIAN, &external_port);
587 } else {
588 proto_tree_add_item_ret_uint(option_sub_tree, hf_option_portset_first_assigned_port, tvb, offset + 2, 2, ENC_BIG_ENDIAN, &external_port);
590 proto_tree_add_item(option_sub_tree, hf_option_portset_reserved, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
591 proto_tree_add_item(option_sub_tree, hf_option_portset_parity, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
592 break;
594 default:
595 /* Unknown option */
596 expert_add_info_format(pinfo, option_ti, &ei_pcp_option_unknown, "Unknown option: %d", option);
597 break;
601 offset+=option_length;
603 if( option_padding_length > 0 )
605 proto_tree_add_item(option_sub_tree, hf_option_padding, tvb, offset, option_padding_length, ENC_NA);
606 offset+=option_padding_length;
610 proto_item_set_len(option_ti, offset-start_option_offset);
613 proto_item_set_len(opcode_ti, offset-start_opcode_offset);
615 bool is_map_opcode = (ropcode == MAP_REQUEST || ropcode == MAP_RESPONSE);
616 if (is_map_opcode && port_set_size != 0) {
617 col_add_fstr(
618 pinfo->cinfo,
619 COL_INFO,
620 "%s: %d-%d -> %d-%d [%s]",
621 op_str,
622 internal_port,
623 internal_port + port_set_size,
624 external_port,
625 external_port + port_set_size,
626 val_to_str(protocol, pcp_protocol_vals, "Unknown Protocol %d")
628 } else if (is_map_opcode) {
629 col_add_fstr(
630 pinfo->cinfo,
631 COL_INFO,
632 "%s: %d -> %d [%s]",
633 op_str,
634 internal_port,
635 external_port,
636 val_to_str(protocol, pcp_protocol_vals, "Unknown Protocol %d")
640 return (offset-start_offset);
643 static int
644 dissect_portcontrol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
646 uint8_t version = tvb_get_uint8(tvb, 0);
648 switch(version)
650 case 0:
651 /* NAT-PMP protocol */
652 return dissect_nat_pmp(tvb, pinfo, tree, data);
653 case 1:
654 case 2:
655 return dissect_portcontrol_pdu(tvb, pinfo, tree, version);
658 return 0;
661 void proto_register_nat_pmp(void)
663 static hf_register_info hf[] = {
664 { &hf_version,
665 { "Version", "nat-pmp.version", FT_UINT8, BASE_DEC,
666 NULL, 0x0, NULL, HFILL } },
667 { &hf_opcode,
668 { "Opcode", "nat-pmp.opcode", FT_UINT8, BASE_DEC,
669 VALS(opcode_vals), 0x0, NULL, HFILL } },
670 { &hf_result_code,
671 { "Result Code", "nat-pmp.result_code", FT_UINT16, BASE_DEC,
672 VALS(result_vals), 0x0, NULL, HFILL } },
673 { &hf_sssoe,
674 { "Seconds Since Start of Epoch", "nat-pmp.sssoe", FT_UINT32, BASE_DEC,
675 NULL, 0x0, NULL, HFILL } },
676 { &hf_external_ip,
677 { "External IP Address", "nat-pmp.external_ip", FT_IPv4, BASE_NONE,
678 NULL, 0x0, NULL, HFILL } },
679 { &hf_reserved,
680 { "Reserved", "nat-pmp.reserved", FT_UINT16, BASE_DEC,
681 NULL, 0x0, "Reserved (must be zero)", HFILL } },
682 { &hf_internal_port,
683 { "Internal Port", "nat-pmp.internal_port", FT_UINT16, BASE_DEC,
684 NULL, 0x0, NULL, HFILL } },
685 { &hf_external_port_requested,
686 { "Requested External Port", "nat-pmp.external_port", FT_UINT16, BASE_DEC,
687 NULL, 0x0, NULL, HFILL } },
688 { &hf_external_port_mapped,
689 { "Mapped External Port", "nat-pmp.external_port", FT_UINT16, BASE_DEC,
690 NULL, 0x0, NULL, HFILL } },
691 { &hf_rpmlis,
692 { "Requested Port Mapping Lifetime", "nat-pmp.pml", FT_UINT32, BASE_DEC,
693 NULL, 0x0, "Requested Port Mapping Lifetime in Seconds", HFILL } },
694 { &hf_pmlis,
695 { "Port Mapping Lifetime", "nat-pmp.pml", FT_UINT32, BASE_DEC,
696 NULL, 0x0, "Port Mapping Lifetime in Seconds", HFILL } },
699 static hf_register_info pcp_hf[] = {
700 { &hf_pcp_version,
701 { "Version", "portcontrol.version", FT_UINT8, BASE_DEC,
702 NULL, 0x0, NULL, HFILL } },
703 { &hf_request,
704 { "Request", "portcontrol.request", FT_BOOLEAN, 8,
705 NULL, 0x01, NULL, HFILL } },
706 { &hf_response,
707 { "Response", "portcontrol.response", FT_BOOLEAN, 8,
708 NULL, 0x01, NULL, HFILL } },
709 { &hf_pcp_r,
710 { "R", "portcontrol.r", FT_BOOLEAN, 8,
711 TFS(&tfs_response_request), 0x80, "Indicates Request (0) or Response (1)", HFILL } },
712 { &hf_pcp_opcode,
713 { "Opcode", "portcontrol.opcode", FT_UINT8, BASE_DEC,
714 VALS(pcp_opcode_vals), 0x7F, NULL, HFILL } },
715 { &hf_pcp_result_code,
716 { "Result Code", "portcontrol.result_code", FT_UINT16, BASE_DEC,
717 VALS(pcp_result_vals), 0x0, NULL, HFILL } },
718 { &hf_reserved1,
719 { "Reserved", "portcontrol.reserved", FT_UINT8, BASE_DEC,
720 NULL, 0x0, NULL, HFILL } },
721 { &hf_reserved2,
722 { "Reserved", "portcontrol.reserved", FT_UINT16, BASE_DEC,
723 NULL, 0x0, NULL, HFILL } },
724 { &hf_reserved12,
725 { "Reserved", "portcontrol.rsp_reserved", FT_BYTES, BASE_NONE,
726 NULL, 0x0, NULL, HFILL } },
727 { &hf_req_lifetime,
728 { "Requested Lifetime", "portcontrol.lifetime_req", FT_UINT32, BASE_DEC,
729 NULL, 0x0, NULL, HFILL } },
730 { &hf_rsp_lifetime,
731 { "Lifetime", "portcontrol.lifetime_rsp", FT_UINT32, BASE_DEC,
732 NULL, 0x0, NULL, HFILL } },
733 { &hf_client_ip,
734 { "Client IP Address", "portcontrol.client_ip", FT_IPv6, BASE_NONE,
735 NULL, 0x0, NULL, HFILL } },
736 { &hf_epoch_time,
737 { "Epoch Time", "portcontrol.epoch_time", FT_UINT32, BASE_DEC,
738 NULL, 0x0, NULL, HFILL } },
739 { &hf_map_nonce,
740 { "Mapping Nonce", "portcontrol.map.nonce", FT_BYTES, BASE_NONE,
741 NULL, 0x0, NULL, HFILL } },
742 { &hf_map_protocol,
743 { "Protocol", "portcontrol.map.protocol", FT_UINT8, BASE_DEC,
744 NULL, 0x0, NULL, HFILL } },
745 { &hf_map_reserved1,
746 { "Reserved", "portcontrol.map.reserved", FT_UINT24, BASE_DEC,
747 NULL, 0x0, NULL, HFILL } },
748 { &hf_map_internal_port,
749 { "Internal Port", "portcontrol.map.internal_port", FT_UINT16, BASE_DEC,
750 NULL, 0x0, NULL, HFILL } },
751 { &hf_map_req_sug_external_port,
752 { "Suggested External Port", "portcontrol.map.req_sug_external_port", FT_UINT16, BASE_DEC,
753 NULL, 0x0, NULL, HFILL } },
754 { &hf_map_req_sug_ext_ip,
755 { "Suggested External IP Address", "portcontrol.map.req_sug_external_ip", FT_IPv6, BASE_NONE,
756 NULL, 0x0, NULL, HFILL } },
757 { &hf_map_rsp_assigned_external_port,
758 { "Assigned External Port", "portcontrol.map.rsp_assigned_external_port", FT_UINT16, BASE_DEC,
759 NULL, 0x0, NULL, HFILL } },
760 { &hf_map_rsp_assigned_ext_ip,
761 { "Assigned External IP Address", "portcontrol.map.rsp_assigned_ext_ip", FT_IPv6, BASE_NONE,
762 NULL, 0x0, NULL, HFILL } },
763 { &hf_peer_nonce,
764 { "Mapping Nonce", "portcontrol.peer.nonce", FT_BYTES, BASE_NONE,
765 NULL, 0x0, NULL, HFILL } },
766 { &hf_peer_protocol,
767 { "Protocol", "portcontrol.peer.protocol", FT_UINT8, BASE_DEC,
768 NULL, 0x0, NULL, HFILL } },
769 { &hf_peer_reserved,
770 { "Reserved", "portcontrol.peer.reserved", FT_BYTES, BASE_NONE,
771 NULL, 0x0, NULL, HFILL } },
772 { &hf_peer_internal_port,
773 { "Internal Port", "portcontrol.peer.internal_port", FT_UINT16, BASE_DEC,
774 NULL, 0x0, NULL, HFILL } },
775 { &hf_peer_req_sug_external_port,
776 { "Suggested External Port", "portcontrol.peer.req_sug_external_port", FT_UINT16, BASE_DEC,
777 NULL, 0x0, NULL, HFILL } },
778 { &hf_peer_req_sug_ext_ip,
779 { "Suggested External IP Address", "portcontrol.peer.req_sug_external_ip", FT_IPv6, BASE_NONE,
780 NULL, 0x0, NULL, HFILL } },
781 { &hf_peer_remote_peer_port,
782 { "Remote Peer Port", "portcontrol.peer.remote_peer_port", FT_UINT16, BASE_DEC,
783 NULL, 0x0, NULL, HFILL } },
784 { &hf_peer_remote_peer_ip,
785 { "Remote Peer IP Address", "portcontrol.peer.remote_peer_ip", FT_IPv6, BASE_NONE,
786 NULL, 0x0, NULL, HFILL } },
787 { &hf_peer_rsp_assigned_external_port,
788 { "Assigned External Port", "portcontrol.peer.rsp_assigned_external_port", FT_UINT16, BASE_DEC,
789 NULL, 0x0, NULL, HFILL } },
790 { &hf_peer_rsp_assigned_ext_ip,
791 { "Assigned External IP Address", "portcontrol.peer.rsp_assigned_ext_ip", FT_IPv6, BASE_NONE,
792 NULL, 0x0, NULL, HFILL } },
793 { &hf_options,
794 { "Options", "portcontrol.options", FT_NONE, BASE_NONE,
795 NULL, 0x0, NULL, HFILL } },
796 { &hf_option,
797 { "Option", "portcontrol.option", FT_NONE, BASE_NONE,
798 NULL, 0x0, NULL, HFILL } },
799 { &hf_option_code,
800 { "Option", "portcontrol.option.code", FT_UINT8, BASE_DEC,
801 VALS(pcp_option_vals), 0x0, NULL, HFILL } },
802 { &hf_option_reserved,
803 { "Reserved", "portcontrol.option.reserved", FT_UINT8, BASE_DEC,
804 NULL, 0x0, NULL, HFILL } },
805 { &hf_option_length,
806 { "Option Length", "portcontrol.option.length", FT_UINT16, BASE_DEC,
807 NULL, 0x0, NULL, HFILL } },
808 { &hf_option_third_party_internal_ip,
809 { "Internal IP Address", "portcontrol.option.third_party.internal_ip", FT_IPv6, BASE_NONE,
810 NULL, 0x0, NULL, HFILL } },
811 { &hf_option_filter_reserved,
812 { "Reserved", "portcontrol.option.filter.reserved", FT_UINT8, BASE_DEC,
813 NULL, 0x0, NULL, HFILL } },
814 { &hf_option_filter_prefix_length,
815 { "Prefix Length", "portcontrol.option.filter.prefix_length", FT_UINT8, BASE_DEC,
816 NULL, 0x0, NULL, HFILL } },
817 { &hf_option_filter_remote_peer_port,
818 { "Remote Peer Port", "portcontrol.option.filter.remote_peer_port", FT_UINT16, BASE_DEC,
819 NULL, 0x0, NULL, HFILL } },
820 { &hf_option_filter_remote_peer_ip,
821 { "Remote Peer IP Address", "portcontrol.option.filter.remote_peer_ip", FT_IPv6, BASE_NONE,
822 NULL, 0x0, NULL, HFILL } },
823 { &hf_option_description,
824 { "Description", "portcontrol.option.description", FT_STRING, BASE_NONE,
825 NULL, 0x0, NULL, HFILL } },
826 { &hf_option_p64_length,
827 { "Length", "portcontrol.option.p64.length", FT_UINT16, BASE_DEC,
828 NULL, 0x0, NULL, HFILL } },
829 { &hf_option_p64_prefix64,
830 { "Prefix64", "portcontrol.option.p64.prefix64", FT_BYTES, BASE_NONE,
831 NULL, 0x0, NULL, HFILL } },
832 { &hf_option_p64_suffix,
833 { "Suffix", "portcontrol.option.p64.suffix", FT_BYTES, BASE_NONE,
834 NULL, 0x0, NULL, HFILL } },
835 { &hf_option_p64_ipv4_prefix_count,
836 { "IPv4 Prefix Count", "portcontrol.option.p64.ipv4_prefix_count", FT_UINT16, BASE_DEC,
837 NULL, 0x0, NULL, HFILL } },
838 { &hf_option_p64_ipv4_prefix_length,
839 { "IPv4 Prefix Length", "portcontrol.option.p64.ipv4_prefix_length", FT_UINT16, BASE_DEC,
840 NULL, 0x0, NULL, HFILL } },
841 { &hf_option_p64_ipv4_address,
842 { "IPv4 Address", "portcontrol.option.p64.ipv4_address", FT_IPv4, BASE_NONE,
843 NULL, 0x0, NULL, HFILL } },
844 { &hf_option_portset_size,
845 { "Port Set Size", "portcontrol.option.portset.size", FT_UINT16, BASE_DEC,
846 NULL, 0x0, NULL, HFILL } },
847 { &hf_option_portset_first_suggested_port,
848 { "Suggested First Port", "portcontrol.option.portset.req_sug_first_external_port", FT_UINT16, BASE_DEC,
849 NULL, 0x0, NULL, HFILL } },
850 { &hf_option_portset_first_assigned_port,
851 { "Assigned First Port", "portcontrol.option.portset.rsp_assigned_first_external_port", FT_UINT16, BASE_DEC,
852 NULL, 0x0, NULL, HFILL } },
853 { &hf_option_portset_reserved,
854 { "Reserved", "portcontrol.option.portset.reserved", FT_UINT8, BASE_HEX,
855 NULL, 0xFE, NULL, HFILL } },
856 { &hf_option_portset_parity,
857 { "Parity Requested", "portcontrol.option.portset.parity", FT_BOOLEAN, 8,
858 NULL, 0x01, NULL, HFILL } },
859 { &hf_option_padding,
860 { "Padding", "portcontrol.option.padding", FT_BYTES, BASE_NONE,
861 NULL, 0x0, NULL, HFILL } },
864 static int *pcp_ett[] = {
865 &ett_pcp,
866 &ett_opcode,
867 &ett_option,
868 &ett_suboption
871 static int *ett[] = {
872 &ett_nat_pmp,
875 static ei_register_info natpmp_ei[] = {
876 { &ei_natpmp_opcode_unknown, { "nat-pmp.opcode.unknown", PI_RESPONSE_CODE, PI_WARN, "Unknown opcode", EXPFILL }},
879 static ei_register_info pcp_ei[] = {
880 { &ei_pcp_opcode_unknown, { "portcontrol.opcode.unknown", PI_RESPONSE_CODE, PI_WARN, "Unknown opcode", EXPFILL }},
881 { &ei_pcp_option_unknown, { "portcontrol.option.unknown", PI_RESPONSE_CODE, PI_WARN, "Unknown option", EXPFILL }},
884 expert_module_t* expert_nat_pmp;
885 expert_module_t* expert_pcp;
887 proto_nat_pmp = proto_register_protocol("NAT Port Mapping Protocol", "NAT-PMP", "nat-pmp");
889 proto_register_field_array(proto_nat_pmp, hf, array_length(hf));
890 proto_register_subtree_array(ett, array_length(ett));
891 expert_nat_pmp = expert_register_protocol(proto_nat_pmp);
892 expert_register_field_array(expert_nat_pmp, natpmp_ei, array_length(natpmp_ei));
894 nat_pmp_handle = register_dissector("nat-pmp", dissect_nat_pmp, proto_nat_pmp);
896 proto_pcp = proto_register_protocol("Port Control Protocol", "Port Control", "portcontrol");
898 proto_register_field_array(proto_pcp, pcp_hf, array_length(pcp_hf));
899 proto_register_subtree_array(pcp_ett, array_length(pcp_ett));
900 expert_pcp = expert_register_protocol(proto_pcp);
901 expert_register_field_array(expert_pcp, pcp_ei, array_length(pcp_ei));
903 pcp_handle = register_dissector("portcontrol", dissect_portcontrol, proto_pcp);
906 void proto_reg_handoff_nat_pmp(void)
908 dissector_add_uint_range_with_preference("udp.port", PCP_PORT_RANGE, pcp_handle);
910 /* Port Control Protocol (packet-portcontrol.c) shares the same UDP ports as
911 NAT-PMP, but it backwards compatible. However, still let NAT-PMP
912 use Decode As
914 dissector_add_for_decode_as_with_preference("udp.port", nat_pmp_handle);
918 * Editor modelines
920 * Local Variables:
921 * c-basic-offset: 2
922 * tab-width: 8
923 * indent-tabs-mode: nil
924 * End:
926 * ex: set shiftwidth=2 tabstop=8 expandtab:
927 * :indentSize=2:tabSize=8:noTabs=true: