Don't guard col_set_str (COL_PROTOCOL) with col_check
[obnox/wireshark/wip.git] / epan / dissectors / packet-ipsec-tcp.c
1 /*
2  * Routines for the disassembly of the proprietary Cisco IPSEC in
3  * TCP encapsulation protocol
4  *
5  * $Id$
6  *
7  * Copyright 2007 Joerg Mayer (see AUTHORS file)
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 /* TODO:
29  * - Find out the meaning of the (unknown) trailer
30  * - UDP checksum is wrong
31  * - Currently doesn't handle AH (lack of sample trace)
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <glib.h>
39 #include <epan/packet.h>
40 #include <epan/prefs.h>
41 #include "packet-ndmp.h"
42
43 static int hf_tcpencap_unknown = -1;
44 static int hf_tcpencap_zero = -1;
45 static int hf_tcpencap_seq = -1;
46 static int hf_tcpencap_ike_direction = -1;
47 static int hf_tcpencap_esp_zero = -1;
48 static int hf_tcpencap_magic = -1;
49 static int hf_tcpencap_proto = -1;
50 static int hf_tcpencap_magic2 = -1;
51
52 static int proto_tcpencap = -1;
53 static gint ett_tcpencap = -1;
54 static gint ett_tcpencap_unknown = -1;
55
56 static const value_string tcpencap_ikedir_vals[] = {
57         { 0x0000,       "Server to client" },
58         { 0x4000,       "Client to server" },
59
60         { 0,    NULL }
61 };
62
63 static const value_string tcpencap_proto_vals[] = {
64         { 0x11, "ISAKMP" },
65         { 0x32, "ESP" },
66
67         { 0,    NULL }
68 };
69
70 #define TCP_CISCO_IPSEC 10000
71 static guint global_tcpencap_tcp_port = TCP_CISCO_IPSEC;
72
73 static dissector_handle_t esp_handle;
74 static dissector_handle_t udp_handle;
75
76 #define TCP_ENCAP_P_ESP 1
77 #define TCP_ENCAP_P_UDP 2
78
79
80 /* oh what a crap protocol.
81    there is nothing in the protocol that makes it easy to identify and then
82    worse is that by default it is using port 10000 which ndmp has been
83    using for ages.
84
85    assume it is tcpencap    if it does not look like ndmp
86 */
87 static int
88 packet_is_tcpencap(tvbuff_t *tvb, packet_info *pinfo)
89 {
90         if(check_if_ndmp(tvb, pinfo)){
91                 return FALSE;
92         }
93
94         return TRUE;
95 }
96
97 /*
98  * TCP Encapsulation of IPsec Packets   
99  * as supported by the cisco vpn3000 concentrator series
100  */
101 static int
102 dissect_tcpencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
103 {
104         proto_tree *tcpencap_tree = NULL;
105         proto_tree *tcpencap_unknown_tree = NULL;
106
107         proto_item *tree_item = NULL;
108         proto_item *unknown_item = NULL;
109         tvbuff_t *next_tvb;
110         guint32 reported_length = tvb_reported_length(tvb);
111         guint32 offset;
112         guint8  protocol;
113
114         /* verify that this looks like a tcpencap packet */
115         if(!packet_is_tcpencap(tvb, pinfo)){
116                 return 0;
117         }
118
119         col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCPENCAP");
120         if (check_col(pinfo->cinfo, COL_INFO))
121                 col_clear(pinfo->cinfo, COL_INFO);
122
123         /* If the first 4 bytes are 0x01f401f4 (udp src and dst port = 500)
124            we most likely have UDP (isakmp) traffic */
125         
126         if (tvb_get_ntohl(tvb, 0) == 0x01f401f4) { /* UDP means ISAKMP */
127                 protocol = TCP_ENCAP_P_UDP;
128         } else { /* Hopefully ESP */
129                 protocol = TCP_ENCAP_P_ESP;
130         }
131
132         if (tree) {
133                 tree_item = proto_tree_add_item(tree, proto_tcpencap, tvb, 0, -1, FALSE);
134                 tcpencap_tree = proto_item_add_subtree(tree_item, ett_tcpencap);
135
136                 /* Dissect the trailer following the encapsulated IPSEC/ISAKMP packet */
137                 offset = reported_length - 16;
138                 unknown_item = proto_tree_add_item(tcpencap_tree, hf_tcpencap_unknown, tvb,
139                         offset, 16, FALSE);
140                 /* Try to guess the contents of the trailer */
141                 tcpencap_unknown_tree = proto_item_add_subtree(unknown_item, ett_tcpencap_unknown);
142                 proto_tree_add_item(tcpencap_unknown_tree, hf_tcpencap_zero, tvb, offset + 0, 4, FALSE);
143                 proto_tree_add_item(tcpencap_unknown_tree, hf_tcpencap_seq, tvb, offset + 4, 2, FALSE);
144                 if (protocol == TCP_ENCAP_P_UDP) {
145                         proto_tree_add_item(tcpencap_unknown_tree, hf_tcpencap_ike_direction, tvb, offset + 6, 2, FALSE);
146                 } else {
147                         proto_tree_add_item(tcpencap_unknown_tree, hf_tcpencap_esp_zero, tvb, offset + 6, 2, FALSE);
148                 }
149                 proto_tree_add_item(tcpencap_unknown_tree, hf_tcpencap_magic, tvb, offset + 8, 5, FALSE);
150                 proto_tree_add_item(tcpencap_unknown_tree, hf_tcpencap_proto, tvb, offset + 13, 1, FALSE);
151                 proto_tree_add_item(tcpencap_unknown_tree, hf_tcpencap_magic2, tvb, offset + 14, 2, FALSE);
152         }
153
154         /* Create the tvbuffer for the next dissector */
155         next_tvb = tvb_new_subset(tvb, 0, reported_length - 16 , -1);
156         if (protocol == TCP_ENCAP_P_UDP) {
157                 call_dissector(udp_handle, next_tvb, pinfo, tree);
158         } else { /* Hopefully ESP */
159                 call_dissector(esp_handle, next_tvb, pinfo, tree);
160         }
161
162         return tvb_length(tvb);
163 }
164
165 void
166 proto_register_tcpencap(void)
167 {
168         static hf_register_info hf[] = {
169
170                 { &hf_tcpencap_unknown,
171                 { "Unknown trailer",      "tcpencap.unknown", FT_BYTES, BASE_NONE, NULL,
172                         0x0, NULL, HFILL }},
173
174                 { &hf_tcpencap_zero,
175                 { "All zero",      "tcpencap.zero", FT_BYTES, BASE_NONE, NULL,
176                         0x0, NULL, HFILL }},
177
178                 { &hf_tcpencap_seq,
179                 { "Sequence number",      "tcpencap.seq", FT_UINT16, BASE_HEX, NULL,
180                         0x0, NULL, HFILL }},
181
182                 { &hf_tcpencap_esp_zero,
183                 { "ESP zero",      "tcpencap.espzero", FT_UINT16, BASE_HEX, NULL,
184                         0x0, NULL, HFILL }},
185
186                 { &hf_tcpencap_ike_direction,
187                 { "ISAKMP traffic direction",      "tcpencap.ikedirection", FT_UINT16, BASE_HEX, VALS(tcpencap_ikedir_vals),
188                         0x0, NULL, HFILL }},
189
190                 { &hf_tcpencap_magic,
191                 { "Magic number",      "tcpencap.magic", FT_BYTES, BASE_NONE, NULL,
192                         0x0, NULL, HFILL }},
193
194                 { &hf_tcpencap_proto,
195                 { "Protocol",      "tcpencap.proto", FT_UINT8, BASE_HEX, VALS(tcpencap_proto_vals),
196                         0x0, NULL, HFILL }},
197
198                 { &hf_tcpencap_magic2,
199                 { "Magic 2",      "tcpencap.magic2", FT_BYTES, BASE_NONE, NULL,
200                         0x0, NULL, HFILL }},
201
202         };
203
204         static gint *ett[] = {
205                 &ett_tcpencap,
206                 &ett_tcpencap_unknown,
207         };
208
209         module_t *tcpencap_module;
210
211         void proto_reg_handoff_tcpencap(void);
212
213         proto_tcpencap = proto_register_protocol(
214                 "TCP Encapsulation of IPsec Packets", "TCPENCAP", "tcpencap");
215         proto_register_field_array(proto_tcpencap, hf, array_length(hf));
216         proto_register_subtree_array(ett, array_length(ett));
217         tcpencap_module = prefs_register_protocol(proto_tcpencap, proto_reg_handoff_tcpencap);
218         prefs_register_uint_preference(tcpencap_module, "tcp.port", "IPSEC TCP Port",
219                 "Set the port for IPSEC/ISAKMP messages"
220                 "If other than the default of 10000)",
221                 10, &global_tcpencap_tcp_port);
222 }
223
224 void
225 proto_reg_handoff_tcpencap(void)
226 {
227         static dissector_handle_t tcpencap_handle;
228         static gboolean initialized = FALSE;
229         static guint tcpencap_tcp_port;
230
231         if (!initialized) {
232                 tcpencap_handle = new_create_dissector_handle(dissect_tcpencap, proto_tcpencap);
233                 esp_handle = find_dissector("esp");
234                 udp_handle = find_dissector("udp");
235                 initialized = TRUE;
236         } else {
237                 dissector_delete("tcp.port", tcpencap_tcp_port, tcpencap_handle);
238         }
239
240         tcpencap_tcp_port = global_tcpencap_tcp_port;
241         dissector_add("tcp.port", global_tcpencap_tcp_port, tcpencap_handle);
242 }
243