From Markus Friedl:
[obnox/wireshark/wip.git] / packet-enc.c
1 /*
2  * Copyright (c) 2003 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <string.h>
29 #include <glib.h>
30 #include <epan/packet.h>
31 #include "etypes.h"
32 #include <epan/resolv.h>
33 #include "packet-ip.h"
34 #include "packet-ipv6.h"
35
36 #ifndef offsetof
37 /* Can't trust stddef.h to be there for us */
38 # define offsetof(type, member) ((size_t)(&((type *)0)->member))
39 #endif
40
41 /* The header in OpenBSD Encapsulating Interface files. */
42
43 struct enchdr {
44   guint32 af;
45   guint32 spi;
46   guint32 flags;
47 };
48 #define ENC_HDRLEN    sizeof(struct enchdr)
49
50 # define BSD_ENC_INET    2
51 # define BSD_ENC_INET6   24
52
53 # define BSD_ENC_M_CONF          0x0400  /* payload encrypted */
54 # define BSD_ENC_M_AUTH          0x0800  /* payload authenticated */
55 # define BSD_ENC_M_COMP          0x1000  /* payload compressed */
56 # define BSD_ENC_M_AUTH_AH       0x2000  /* header authenticated */
57
58
59 static dissector_handle_t  data_handle, ip_handle, ipv6_handle;
60
61 /* header fields */
62 static unsigned int proto_enc = -1;
63 static unsigned int hf_enc_af = -1;
64 static unsigned int hf_enc_spi = -1;
65 static unsigned int hf_enc_flags = -1;
66
67 static gint ett_enc = -1;
68
69 void
70 capture_enc(const guchar *pd, int offset, int len, packet_counts *ld)
71 {
72   struct enchdr ench;
73
74   if (!BYTES_ARE_IN_FRAME(offset, len, (int)ENC_HDRLEN)) {
75     ld->other++;
76     return;
77   }
78
79   offset += ENC_HDRLEN;
80
81   /* Copy out the enc header to insure alignment */
82   memcpy(&ench, pd, sizeof(ench));
83   ench.af = g_ntohl(ench.af);
84
85   switch (ench.af) {
86
87   case BSD_ENC_INET:
88     capture_ip(pd, offset, len, ld);
89     break;
90
91 #ifdef notyet
92   case BSD_ENC_INET6:
93     capture_ipv6(pd, offset, len, ld);
94     break;
95 #endif
96
97   default:
98     ld->other++;
99     break;
100   }
101 }
102
103 static const value_string af_vals[] = {
104   { BSD_ENC_INET,  "IPv4" },
105   { BSD_ENC_INET6, "IPv6" },
106   { 0,            NULL }
107 };
108
109 static void
110 dissect_enc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
111 {
112   struct enchdr ench;
113   tvbuff_t *next_tvb;
114   proto_tree *enc_tree;
115   proto_item *ti;
116
117   if (check_col(pinfo->cinfo, COL_PROTOCOL))
118     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENC");
119
120   /* Copy out the enc header to insure alignment */
121   tvb_memcpy(tvb, (guint8 *)&ench, 0, sizeof(ench));
122
123   /* Byteswap the header now */
124   ench.spi = g_ntohl(ench.spi);
125   /* ench.af = g_ntohl(ench.af); */
126   /* ench.flags = g_ntohl(ench.flags); */
127
128   if (tree) {
129     ti = proto_tree_add_protocol_format(tree, proto_enc, tvb, 0,
130              ENC_HDRLEN,
131              "Enc %s, SPI 0x%8.8x, %s%s%s%s",
132              val_to_str(ench.af, af_vals, "unknown (%u)"),
133              ench.spi,
134              ench.flags ? "" : "unprotected",
135              ench.flags & BSD_ENC_M_AUTH ? "authentic" : "",
136              (ench.flags & (BSD_ENC_M_AUTH|BSD_ENC_M_CONF)) ==
137                 (BSD_ENC_M_AUTH|BSD_ENC_M_CONF) ? ", " : "",
138              ench.flags & BSD_ENC_M_CONF ? "confidential" : ""
139              );
140     enc_tree = proto_item_add_subtree(ti, ett_enc);
141
142     proto_tree_add_uint(enc_tree, hf_enc_af, tvb,
143              offsetof(struct enchdr, af), sizeof(ench.af),
144              ench.af);
145     proto_tree_add_uint(enc_tree, hf_enc_spi, tvb,
146              offsetof(struct enchdr, spi), sizeof(ench.spi),
147              ench.spi);
148     proto_tree_add_uint(enc_tree, hf_enc_flags, tvb,
149              offsetof(struct enchdr, flags), sizeof(ench.flags),
150              ench.flags);
151   }
152
153   /* Set the tvbuff for the payload after the header */
154   next_tvb = tvb_new_subset(tvb, ENC_HDRLEN, -1, -1);
155
156   switch (ench.af) {
157
158   case BSD_ENC_INET:
159     call_dissector(ip_handle, next_tvb, pinfo, tree);
160     break;
161
162   case BSD_ENC_INET6:
163     call_dissector(ipv6_handle, next_tvb, pinfo, tree);
164     break;
165
166   default:
167     call_dissector(data_handle, next_tvb, pinfo, tree);
168     break;
169   }
170 }
171
172 void
173 proto_register_enc(void)
174 {
175   static hf_register_info hf[] = {
176     { &hf_enc_af,
177       { "Address Family", "enc.af", FT_UINT32, BASE_DEC, VALS(af_vals), 0x0,
178         "Protocol (IPv4 vs IPv6)", HFILL }},
179     { &hf_enc_spi,
180       { "SPI", "enc.spi", FT_UINT32, BASE_HEX, NULL, 0x0,
181         "Security Parameter Index", HFILL }},
182     { &hf_enc_flags,
183       { "Flags", "enc.flags", FT_UINT32, BASE_HEX, NULL, 0x0,
184         "ENC flags", HFILL }},
185   };
186   static gint *ett[] = { &ett_enc };
187
188   proto_enc = proto_register_protocol("OpenBSD Encapsulating device",
189                                       "ENC", "enc");
190   proto_register_field_array(proto_enc, hf, array_length(hf));
191   proto_register_subtree_array(ett, array_length(ett));
192 }
193
194 void
195 proto_reg_handoff_enc(void)
196 {
197   dissector_handle_t enc_handle;
198
199   ip_handle = find_dissector("ip");
200   ipv6_handle = find_dissector("ipv6");
201   data_handle = find_dissector("data");
202
203   enc_handle = create_dissector_handle(dissect_enc, proto_enc);
204   dissector_add("wtap_encap", WTAP_ENCAP_ENC0, enc_handle);
205 }