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