3475cf852f3fbf3c444fdfe206ecb5d2aa5afb6c
[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.13 2000/04/16 22:46:20 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 <glib.h>
41 #include "packet.h"
42 #include "packet-ipsec.h"
43 #include "packet-ip.h"
44 #include "resolv.h"
45
46 static int proto_ah = -1;
47 static int hf_ah_spi = -1;
48 static int hf_ah_sequence = -1;
49 static int proto_esp = -1;
50 static int hf_esp_spi = -1;
51 static int hf_esp_sequence = -1;
52 static int proto_ipcomp = -1;
53 static int hf_ipcomp_flags = -1;
54 static int hf_ipcomp_cpi = -1;
55
56 static gint ett_ah = -1;
57 static gint ett_esp = -1;
58 static gint ett_ipcomp = -1;
59
60 struct newah {
61         guint8  ah_nxt;         /* Next Header */
62         guint8  ah_len;         /* Length of data + 1, in 32bit */
63         guint16 ah_reserve;     /* Reserved for future use */
64         guint32 ah_spi;         /* Security parameter index */
65         guint32 ah_seq;         /* Sequence number field */
66         /* variable size, 32bit bound*/ /* Authentication data */
67 };
68
69 struct newesp {
70         guint32 esp_spi;        /* ESP */
71         guint32 esp_seq;        /* Sequence number */
72         /*variable size*/               /* (IV and) Payload data */
73         /*variable size*/               /* padding */
74         /*8bit*/                        /* pad size */
75         /*8bit*/                        /* next header */
76         /*8bit*/                        /* next header */
77         /*variable size, 32bit bound*/  /* Authentication data */
78 };
79
80 struct ipcomp {
81         guint8 comp_nxt;        /* Next Header */
82         guint8 comp_flags;      /* Must be zero */
83         guint16 comp_cpi;       /* Compression parameter index */
84 };
85
86 /* well-known algorithm number (in CPI), from RFC2409 */
87 #define IPCOMP_OUI      1       /* vendor specific */
88 #define IPCOMP_DEFLATE  2       /* RFC2394 */
89 #define IPCOMP_LZS      3       /* RFC2395 */
90 #define IPCOMP_MAX      4
91
92 static const value_string cpi2val[] = {
93     { IPCOMP_OUI, "OUI" },
94     { IPCOMP_DEFLATE, "DEFLATE" },
95     { IPCOMP_LZS, "LZS" },
96     { 0, NULL },
97 };
98
99 #ifndef offsetof
100 #define offsetof(type, member)  ((size_t)(&((type *)0)->member))
101 #endif
102
103 int
104 dissect_ah(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
105 {
106     proto_tree *ah_tree;
107     proto_item *ti;
108     struct newah ah;
109     int advance;
110
111     memcpy(&ah, (void *) &pd[offset], sizeof(ah)); 
112     advance = sizeof(ah) + ((ah.ah_len - 1) << 2);
113
114     if (check_col(fd, COL_PROTOCOL))
115         col_add_str(fd, COL_PROTOCOL, "AH");
116     if (check_col(fd, COL_INFO)) {
117         col_add_fstr(fd, COL_INFO, "AH (SPI=0x%08x)",
118             (guint32)ntohl(ah.ah_spi));
119     }
120
121     if (tree) {
122         /* !!! specify length */
123         ti = proto_tree_add_item(tree, proto_ah, offset, advance, NULL);
124         ah_tree = proto_item_add_subtree(ti, ett_ah);
125
126         proto_tree_add_text(ah_tree, offset + offsetof(struct newah, ah_nxt), 1,
127             "Next Header: %s (0x%02x)", ipprotostr(ah.ah_nxt), ah.ah_nxt);
128         proto_tree_add_text(ah_tree, offset + offsetof(struct newah, ah_len), 1,
129             "Length: %d", ah.ah_len << 2);
130         proto_tree_add_item(ah_tree, hf_ah_spi,
131                             offset + offsetof(struct newah, ah_spi), 4,
132                             (guint32)ntohl(ah.ah_spi));
133         proto_tree_add_item(ah_tree, hf_ah_sequence,
134                             offset + offsetof(struct newah, ah_seq), 4,
135                             (guint32)ntohl(ah.ah_seq));
136         proto_tree_add_text(ah_tree, offset + sizeof(ah), (ah.ah_len - 1) << 2,
137                             "ICV");
138     }
139
140     /* start of the new header (could be a extension header) */
141     return advance;
142 }
143
144 void
145 dissect_esp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
146 {
147     proto_tree *esp_tree;
148     proto_item *ti;
149     struct newesp esp;
150
151     memcpy(&esp, (void *) &pd[offset], sizeof(esp)); 
152
153     /*
154      * load the top pane info. This should be overwritten by
155      * the next protocol in the stack
156      */
157     if (check_col(fd, COL_PROTOCOL))
158         col_add_str(fd, COL_PROTOCOL, "ESP");
159     if (check_col(fd, COL_INFO)) {
160         col_add_fstr(fd, COL_INFO, "ESP (SPI=0x%08x)",
161             (guint32)ntohl(esp.esp_spi));
162     }
163
164     /*
165      * populate a tree in the second pane with the status of the link layer
166      * (ie none)
167      */
168     if(tree) {
169         ti = proto_tree_add_item(tree, proto_esp, offset, END_OF_FRAME, NULL);
170         esp_tree = proto_item_add_subtree(ti, ett_esp);
171         proto_tree_add_item(esp_tree, hf_esp_spi, 
172                             offset + offsetof(struct newesp, esp_spi), 4,
173                             (guint32)ntohl(esp.esp_spi));
174         proto_tree_add_item(esp_tree, hf_esp_sequence,
175                             offset + offsetof(struct newesp, esp_seq), 4,
176                             (guint32)ntohl(esp.esp_seq));
177         dissect_data(pd, offset + sizeof(struct newesp), fd, esp_tree);
178     }
179 }
180
181 void
182 dissect_ipcomp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
183 {
184     proto_tree *ipcomp_tree;
185     proto_item *ti;
186     struct ipcomp ipcomp;
187     char *p;
188
189     memcpy(&ipcomp, (void *) &pd[offset], sizeof(ipcomp)); 
190
191     /*
192      * load the top pane info. This should be overwritten by
193      * the next protocol in the stack
194      */
195     if (check_col(fd, COL_PROTOCOL))
196         col_add_str(fd, COL_PROTOCOL, "IPComp");
197     if (check_col(fd, COL_INFO)) {
198         p = val_to_str(ntohs(ipcomp.comp_cpi), cpi2val, "");
199         if (p[0] == '\0') {
200             col_add_fstr(fd, COL_INFO, "IPComp (CPI=0x%04x)",
201                 ntohs(ipcomp.comp_cpi));
202         } else
203             col_add_fstr(fd, COL_INFO, "IPComp (CPI=%s)", p);
204     }
205
206     /*
207      * populate a tree in the second pane with the status of the link layer
208      * (ie none)
209      */
210     if (tree) {
211         ti = proto_tree_add_item(tree, proto_ipcomp, offset, END_OF_FRAME,
212             NULL);
213         ipcomp_tree = proto_item_add_subtree(ti, ett_ipcomp);
214
215         proto_tree_add_text(ipcomp_tree,
216             offset + offsetof(struct ipcomp, comp_nxt), 1,
217             "Next Header: %s (0x%02x)",
218             ipprotostr(ipcomp.comp_nxt), ipcomp.comp_nxt);
219         proto_tree_add_item(ipcomp_tree, hf_ipcomp_flags,
220             offset + offsetof(struct ipcomp, comp_flags), 1,
221             ipcomp.comp_flags);
222         p = val_to_str(ntohs(ipcomp.comp_cpi), cpi2val, "");
223         if (p[0] == '\0') {
224             proto_tree_add_item(ipcomp_tree, hf_ipcomp_cpi, 
225                 offset + offsetof(struct ipcomp, comp_cpi), 2,
226                 ntohs(ipcomp.comp_cpi));
227         } else {
228             proto_tree_add_uint_format(ipcomp_tree, hf_ipcomp_cpi, 
229                 offset + offsetof(struct ipcomp, comp_cpi), 2,
230                 ntohs(ipcomp.comp_cpi),
231                 "CPI: %s (0x%04x)",
232                 p, ntohs(ipcomp.comp_cpi));
233         }
234         dissect_data(pd, offset + sizeof(struct ipcomp), fd, ipcomp_tree);
235     }
236 }
237
238 void
239 proto_register_ipsec(void)
240 {
241
242   static hf_register_info hf_ah[] = {
243     { &hf_ah_spi,
244       { "SPI",          "ah.spi",       FT_UINT32,      BASE_HEX, NULL, 0x0,
245         "" }},
246     { &hf_ah_sequence,
247       { "Sequence",     "ah.sequence",  FT_UINT32,      BASE_HEX, NULL, 0x0,
248         "" }}
249   };
250
251   static hf_register_info hf_esp[] = {
252     { &hf_esp_spi,
253       { "SPI",          "esp.spi",      FT_UINT32,      BASE_HEX, NULL, 0x0,
254         "" }},
255     { &hf_esp_sequence,
256       { "Sequence",     "esp.sequence", FT_UINT32,      BASE_HEX, NULL, 0x0,
257         "" }}
258   };
259
260   static hf_register_info hf_ipcomp[] = {
261     { &hf_ipcomp_flags,
262       { "Flags",        "ipcomp.flags", FT_UINT8,       BASE_HEX, NULL, 0x0,
263         "" }},
264     { &hf_ipcomp_cpi,
265       { "CPI",          "ipcomp.cpi",   FT_UINT16,      BASE_HEX, NULL, 0x0,
266         "" }},
267   };
268   static gint *ett[] = {
269     &ett_ah,
270     &ett_esp,
271     &ett_ipcomp,
272   };
273
274   proto_ah = proto_register_protocol("Authentication Header", "ah");
275   proto_register_field_array(proto_ah, hf_ah, array_length(hf_ah));
276
277   proto_esp = proto_register_protocol("Encapsulated Security Payload", "esp");
278   proto_register_field_array(proto_esp, hf_esp, array_length(hf_esp));
279
280   proto_ipcomp = proto_register_protocol("IP Payload Compression", "ipcomp");
281   proto_register_field_array(proto_ipcomp, hf_ipcomp, array_length(hf_ipcomp));
282
283   proto_register_subtree_array(ett, array_length(ett));
284 }
285
286 void
287 proto_reg_handoff_ipsec(void)
288 {
289   dissector_add("ip.proto", IP_PROTO_ESP, dissect_esp);
290   dissector_add("ip.proto", IP_PROTO_IPCOMP, dissect_ipcomp);
291 }