f919bb334d8de72ea76b71726652516b59bc56cc
[obnox/wireshark/wip.git] / packet-ipsec.c
1 /* packet-ipsec.c
2  * Routines for IPsec/IPComp packet disassembly 
3  *
4  * $Id: packet-ipsec.c,v 1.41 2002/08/02 23:35:51 jmayer Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  * 
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30
31 #include <string.h>
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include "packet-ipsec.h"
35 #include "packet-ip.h"
36 #include <epan/resolv.h>
37 #include "ipproto.h"
38 #include "prefs.h"
39
40 /* Place AH payload in sub tree */
41 static gboolean g_ah_payload_in_subtree = FALSE;
42
43 static int proto_ah = -1;
44 static int hf_ah_spi = -1;
45 static int hf_ah_sequence = -1;
46 static int proto_esp = -1;
47 static int hf_esp_spi = -1;
48 static int hf_esp_sequence = -1;
49 static int proto_ipcomp = -1;
50 static int hf_ipcomp_flags = -1;
51 static int hf_ipcomp_cpi = -1;
52
53 static gint ett_ah = -1;
54 static gint ett_esp = -1;
55 static gint ett_ipcomp = -1;
56
57 static dissector_handle_t data_handle;
58
59 struct newah {
60         guint8  ah_nxt;         /* Next Header */
61         guint8  ah_len;         /* Length of data + 1, in 32bit */
62         guint16 ah_reserve;     /* Reserved for future use */
63         guint32 ah_spi;         /* Security parameter index */
64         guint32 ah_seq;         /* Sequence number field */
65         /* variable size, 32bit bound*/ /* Authentication data */
66 };
67
68 struct newesp {
69         guint32 esp_spi;        /* ESP */
70         guint32 esp_seq;        /* Sequence number */
71         /*variable size*/               /* (IV and) Payload data */
72         /*variable size*/               /* padding */
73         /*8bit*/                        /* pad size */
74         /*8bit*/                        /* next header */
75         /*8bit*/                        /* next header */
76         /*variable size, 32bit bound*/  /* Authentication data */
77 };
78
79 struct ipcomp {
80         guint8 comp_nxt;        /* Next Header */
81         guint8 comp_flags;      /* Must be zero */
82         guint16 comp_cpi;       /* Compression parameter index */
83 };
84
85 /* well-known algorithm number (in CPI), from RFC2409 */
86 #define IPCOMP_OUI      1       /* vendor specific */
87 #define IPCOMP_DEFLATE  2       /* RFC2394 */
88 #define IPCOMP_LZS      3       /* RFC2395 */
89 #define IPCOMP_MAX      4
90
91 static const value_string cpi2val[] = {
92     { IPCOMP_OUI, "OUI" },
93     { IPCOMP_DEFLATE, "DEFLATE" },
94     { IPCOMP_LZS, "LZS" },
95     { 0, NULL },
96 };
97
98 #ifndef offsetof
99 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
100 #endif
101
102 static void
103 dissect_ah(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
104 {
105     proto_tree *next_tree;
106     guint8 nxt;
107     tvbuff_t *next_tvb;
108     int advance;
109
110     advance = dissect_ah_header(tvb, pinfo, tree, &nxt, &next_tree);
111     next_tvb = tvb_new_subset(tvb, advance, -1, -1);
112
113     if (g_ah_payload_in_subtree) {
114         col_set_writable(pinfo->cinfo, FALSE);
115     }
116
117     /* do lookup with the subdissector table */
118     if (!dissector_try_port(ip_dissector_table, nxt, next_tvb, pinfo, next_tree)) {
119       call_dissector(data_handle,next_tvb, pinfo, next_tree);
120     }
121 }
122
123 int
124 dissect_ah_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
125                   guint8 *nxt_p, proto_tree **next_tree_p)
126 {
127     proto_tree *ah_tree;
128     proto_item *ti;
129     struct newah ah;
130     int advance;
131
132     if (check_col(pinfo->cinfo, COL_PROTOCOL))
133         col_set_str(pinfo->cinfo, COL_PROTOCOL, "AH");
134     if (check_col(pinfo->cinfo, COL_INFO))
135         col_clear(pinfo->cinfo, COL_INFO);
136
137     tvb_memcpy(tvb, (guint8 *)&ah, 0, sizeof(ah)); 
138     advance = sizeof(ah) + ((ah.ah_len - 1) << 2);
139
140     if (check_col(pinfo->cinfo, COL_INFO)) {
141         col_add_fstr(pinfo->cinfo, COL_INFO, "AH (SPI=0x%08x)",
142             (guint32)g_ntohl(ah.ah_spi));
143     }
144
145     if (tree) {
146         /* !!! specify length */
147         ti = proto_tree_add_item(tree, proto_ah, tvb, 0, advance, FALSE);
148         ah_tree = proto_item_add_subtree(ti, ett_ah);
149
150         proto_tree_add_text(ah_tree, tvb,
151                             offsetof(struct newah, ah_nxt), 1,
152                             "Next Header: %s (0x%02x)",
153                             ipprotostr(ah.ah_nxt), ah.ah_nxt);
154         proto_tree_add_text(ah_tree, tvb,
155                             offsetof(struct newah, ah_len), 1,
156                             "Length: %u", (ah.ah_len + 2) << 2);
157         proto_tree_add_uint(ah_tree, hf_ah_spi, tvb,
158                             offsetof(struct newah, ah_spi), 4,
159                             (guint32)g_ntohl(ah.ah_spi));
160         proto_tree_add_uint(ah_tree, hf_ah_sequence, tvb,
161                             offsetof(struct newah, ah_seq), 4,
162                             (guint32)g_ntohl(ah.ah_seq));
163         proto_tree_add_text(ah_tree, tvb,
164                             sizeof(ah), (ah.ah_len - 1) << 2,
165                             "ICV");
166
167         if (next_tree_p != NULL) {
168             /* Decide where to place next protocol decode */
169             if (g_ah_payload_in_subtree) {
170                 *next_tree_p = ah_tree;
171             }
172             else {
173                 *next_tree_p = tree;
174             }
175         }
176     } else {
177         if (next_tree_p != NULL)
178             *next_tree_p = NULL;
179     }
180
181     if (nxt_p != NULL)
182         *nxt_p = ah.ah_nxt;
183
184     /* start of the new header (could be a extension header) */
185     return advance;
186 }
187
188 static void
189 dissect_esp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
190 {
191     proto_tree *esp_tree;
192     proto_item *ti;
193     struct newesp esp;
194
195     /*
196      * load the top pane info. This should be overwritten by
197      * the next protocol in the stack
198      */
199     if (check_col(pinfo->cinfo, COL_PROTOCOL))
200         col_set_str(pinfo->cinfo, COL_PROTOCOL, "ESP");
201     if (check_col(pinfo->cinfo, COL_INFO))
202         col_clear(pinfo->cinfo, COL_INFO);
203
204     tvb_memcpy(tvb, (guint8 *)&esp, 0, sizeof(esp)); 
205
206     if (check_col(pinfo->cinfo, COL_INFO)) {
207         col_add_fstr(pinfo->cinfo, COL_INFO, "ESP (SPI=0x%08x)",
208             (guint32)g_ntohl(esp.esp_spi));
209     }
210
211     /*
212      * populate a tree in the second pane with the status of the link layer
213      * (ie none)
214      */
215     if(tree) {
216         ti = proto_tree_add_item(tree, proto_esp, tvb, 0, -1, FALSE);
217         esp_tree = proto_item_add_subtree(ti, ett_esp);
218         proto_tree_add_uint(esp_tree, hf_esp_spi, tvb, 
219                             offsetof(struct newesp, esp_spi), 4,
220                             (guint32)g_ntohl(esp.esp_spi));
221         proto_tree_add_uint(esp_tree, hf_esp_sequence, tvb,
222                             offsetof(struct newesp, esp_seq), 4,
223                             (guint32)g_ntohl(esp.esp_seq));
224         call_dissector(data_handle,
225             tvb_new_subset(tvb, sizeof(struct newesp), -1, -1),
226             pinfo, esp_tree);
227     }
228 }
229
230 static void
231 dissect_ipcomp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
232 {
233     proto_tree *ipcomp_tree;
234     proto_item *ti;
235     struct ipcomp ipcomp;
236     char *p;
237
238     /*
239      * load the top pane info. This should be overwritten by
240      * the next protocol in the stack
241      */
242     if (check_col(pinfo->cinfo, COL_PROTOCOL))
243         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPComp");
244     if (check_col(pinfo->cinfo, COL_INFO))
245         col_clear(pinfo->cinfo, COL_INFO);
246
247     tvb_memcpy(tvb, (guint8 *)&ipcomp, 0, sizeof(ipcomp)); 
248
249     if (check_col(pinfo->cinfo, COL_INFO)) {
250         p = match_strval(g_ntohs(ipcomp.comp_cpi), cpi2val);
251         if (p == NULL) {
252             col_add_fstr(pinfo->cinfo, COL_INFO, "IPComp (CPI=0x%04x)",
253                 g_ntohs(ipcomp.comp_cpi));
254         } else
255             col_add_fstr(pinfo->cinfo, COL_INFO, "IPComp (CPI=%s)", p);
256     }
257
258     /*
259      * populate a tree in the second pane with the status of the link layer
260      * (ie none)
261      */
262     if (tree) {
263         ti = proto_tree_add_item(tree, proto_ipcomp, tvb, 0, -1, FALSE);
264         ipcomp_tree = proto_item_add_subtree(ti, ett_ipcomp);
265
266         proto_tree_add_text(ipcomp_tree, tvb,
267             offsetof(struct ipcomp, comp_nxt), 1,
268             "Next Header: %s (0x%02x)",
269             ipprotostr(ipcomp.comp_nxt), ipcomp.comp_nxt);
270         proto_tree_add_uint(ipcomp_tree, hf_ipcomp_flags, tvb,
271             offsetof(struct ipcomp, comp_flags), 1,
272             ipcomp.comp_flags);
273         proto_tree_add_uint(ipcomp_tree, hf_ipcomp_cpi, tvb, 
274             offsetof(struct ipcomp, comp_cpi), 2,
275             g_ntohs(ipcomp.comp_cpi));
276         call_dissector(data_handle,
277             tvb_new_subset(tvb, sizeof(struct ipcomp), -1, -1), pinfo,
278             ipcomp_tree);
279     }
280 }
281
282 void
283 proto_register_ipsec(void)
284 {
285
286   static hf_register_info hf_ah[] = {
287     { &hf_ah_spi,
288       { "SPI",          "ah.spi",       FT_UINT32,      BASE_HEX, NULL, 0x0,
289         "", HFILL }},
290     { &hf_ah_sequence,
291       { "Sequence",     "ah.sequence",  FT_UINT32,      BASE_HEX, NULL, 0x0,
292         "", HFILL }}
293   };
294
295   static hf_register_info hf_esp[] = {
296     { &hf_esp_spi,
297       { "SPI",          "esp.spi",      FT_UINT32,      BASE_HEX, NULL, 0x0,
298         "", HFILL }},
299     { &hf_esp_sequence,
300       { "Sequence",     "esp.sequence", FT_UINT32,      BASE_HEX, NULL, 0x0,
301         "", HFILL }}
302   };
303
304   static hf_register_info hf_ipcomp[] = {
305     { &hf_ipcomp_flags,
306       { "Flags",        "ipcomp.flags", FT_UINT8,       BASE_HEX, NULL, 0x0,
307         "", HFILL }},
308     { &hf_ipcomp_cpi,
309       { "CPI",          "ipcomp.cpi",   FT_UINT16,      BASE_HEX, 
310         VALS(cpi2val),  0x0,            "", HFILL }},
311   };
312   static gint *ett[] = {
313     &ett_ah,
314     &ett_esp,
315     &ett_ipcomp,
316   };
317
318   module_t *ah_module;
319
320   proto_ah = proto_register_protocol("Authentication Header", "AH", "ah");
321   proto_register_field_array(proto_ah, hf_ah, array_length(hf_ah));
322
323   proto_esp = proto_register_protocol("Encapsulating Security Payload",
324                                       "ESP", "esp");
325   proto_register_field_array(proto_esp, hf_esp, array_length(hf_esp));
326
327   proto_ipcomp = proto_register_protocol("IP Payload Compression",
328                                          "IPComp", "ipcomp");
329   proto_register_field_array(proto_ipcomp, hf_ipcomp, array_length(hf_ipcomp));
330
331   proto_register_subtree_array(ett, array_length(ett));
332
333   /* Register a configuration option for placement of AH payload dissection */
334   ah_module = prefs_register_protocol(proto_ah, NULL);
335   prefs_register_bool_preference(ah_module, "place_ah_payload_in_subtree",
336             "Place AH payload in subtree",
337 "Whether the AH payload decode should be placed in a subtree",
338             &g_ah_payload_in_subtree);
339
340   register_dissector("esp", dissect_esp, proto_esp);
341   register_dissector("ah", dissect_ah, proto_ah);
342 }
343
344 void
345 proto_reg_handoff_ipsec(void)
346 {
347   dissector_handle_t esp_handle, ah_handle, ipcomp_handle;
348
349   data_handle = find_dissector("data");
350   ah_handle = find_dissector("ah");
351   dissector_add("ip.proto", IP_PROTO_AH, ah_handle);
352   esp_handle = find_dissector("esp");
353   dissector_add("ip.proto", IP_PROTO_ESP, esp_handle);
354   ipcomp_handle = create_dissector_handle(dissect_ipcomp, proto_ipcomp);
355   dissector_add("ip.proto", IP_PROTO_IPCOMP, ipcomp_handle);
356 }