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