From Juliusz Chroboczek via bug #5812: Dissector for the Babel Routing
[obnox/wireshark/wip.git] / epan / dissectors / packet-babel.c
1 /* packet-babel.c
2  * Routines for Babel dissection (RFC 6126)
3  * Copyright 2011 by Juliusz Chroboczek <jch@pps.jussieu.fr>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (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 along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
34
35 #include <stdio.h>
36
37 void proto_reg_handoff_babel(void);
38
39 static int proto_babel = -1;
40
41 static gint ett_babel = -1;
42 static int hf_babel_magic = -1;
43 static int hf_babel_version = -1;
44 static int hf_babel_bodylen = -1;
45
46 static int hf_babel_message = -1;
47 static gint ett_message = -1;
48 static int hf_babel_message_type = -1;
49 static int hf_babel_message_length = -1;
50 static int hf_babel_message_nonce = -1;
51 static int hf_babel_message_interval = -1;
52 static int hf_babel_message_seqno = -1;
53 static int hf_babel_message_ae = -1;
54 static int hf_babel_message_prefix = -1;
55 static int hf_babel_message_rxcost = -1;
56 static int hf_babel_message_routerid = -1;
57 static int hf_babel_message_flags = -1;
58 static int hf_babel_message_plen = -1;
59 static int hf_babel_message_omitted = -1;
60 static int hf_babel_message_metric = -1;
61 static int hf_babel_message_hopcount = -1;
62
63 static gint ett_subtree = -1;
64
65 #define UDP_PORT_BABEL 6697
66
67 #define MESSAGE_PAD1 0
68 #define MESSAGE_PADN 1
69 #define MESSAGE_ACK_REQ 2
70 #define MESSAGE_ACK 3
71 #define MESSAGE_HELLO 4
72 #define MESSAGE_IHU 5
73 #define MESSAGE_ROUTER_ID 6
74 #define MESSAGE_NH 7
75 #define MESSAGE_UPDATE 8
76 #define MESSAGE_REQUEST 9
77 #define MESSAGE_MH_REQUEST 10
78
79 static const value_string messages[] = {
80     { MESSAGE_PAD1, "pad1"},
81     { MESSAGE_PADN, "padn"},
82     { MESSAGE_ACK_REQ, "ack-req"},
83     { MESSAGE_ACK, "ack"},
84     { MESSAGE_HELLO, "hello"},
85     { MESSAGE_IHU, "ihu"},
86     { MESSAGE_ROUTER_ID, "router-id"},
87     { MESSAGE_NH, "nh"},
88     { MESSAGE_UPDATE, "update"},
89     { MESSAGE_REQUEST, "request"},
90     { MESSAGE_MH_REQUEST, "mh-request"},
91     { 0, NULL}
92 };
93
94 static const value_string aes[] = {
95     { 0, "Wildcard" },
96     { 1, "IPv4" },
97     { 2, "IPv6" },
98     { 3, "Link-Local IPv6"},
99     { 0, NULL }
100 };
101
102 /* The prefix for v6-mapped IPv4 addresses.  Format_address below 
103    returns IPv4 addresses in that format. */
104
105 static const unsigned char v4prefix[16] =
106     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
107
108 /* The following two functions return ephemeral or constant strings, no
109    need to call free. */
110
111 static const char *
112 format_address(const unsigned char *prefix)
113 {
114     if(prefix == NULL)
115         return "corrupt";
116     else if(memcmp(prefix, v4prefix, 12) == 0)
117         return ip_to_str(prefix + 12);
118     else
119         return ip6_to_str((const struct e_in6_addr*)prefix);
120 }
121
122 const char *
123 format_prefix(const unsigned char *prefix, unsigned char plen)
124 {
125     return ep_strdup_printf("%s/%u", format_address(prefix), plen);
126 }
127
128 static int
129 network_prefix(int ae, int plen, unsigned int omitted,
130                const unsigned char *p, const unsigned char *dp,
131                unsigned int len, unsigned char *p_r)
132 {
133     unsigned pb;
134     unsigned char prefix[16];
135
136     if(plen >= 0)
137         pb = (plen + 7) / 8;
138     else if(ae == 1)
139         pb = 4;
140     else
141         pb = 16;
142
143     if(pb > 16)
144         return -1;
145
146     memset(prefix, 0, 16);
147
148     switch(ae) {
149     case 0: break;
150     case 1:
151         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
152             return -1;
153         memcpy(prefix, v4prefix, 12);
154         if(omitted) {
155             if (dp == NULL) return -1;
156             memcpy(prefix, dp, 12 + omitted);
157         }
158         if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb);
159         break;
160     case 2:
161         if(omitted > 16 || (pb > omitted && len < pb - omitted))
162             return -1;
163         if(omitted) {
164             if (dp == NULL) return -1;
165             memcpy(prefix, dp, omitted);
166         }
167         if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted);
168         break;
169     case 3:
170         if(pb > 8 && len < pb - 8) return -1;
171         prefix[0] = 0xfe;
172         prefix[1] = 0x80;
173         if(pb > 8) memcpy(prefix + 8, p, pb - 8);
174         break;
175     default:
176         return -1;
177     }
178
179     memcpy(p_r, prefix, 16);
180     return 1;
181 }
182
183 static int
184 network_address(int ae, const unsigned char *a, unsigned int len,
185                 unsigned char *a_r)
186 {
187     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
188 }
189
190 static int
191 dissect_babel(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
192 {
193     proto_item *ti;
194     unsigned char v4_prefix[16] = {0}, v6_prefix[16] = {0};
195     int i = 0;
196     proto_tree *babel_tree = NULL;
197     guint8 version;
198     guint16 bodylen;
199
200     if(tvb_length(tvb) < 4)
201         return 0;
202
203     if(tvb_get_guint8(tvb, 0) != 42)
204         return 0;
205     version = tvb_get_guint8(tvb, 1);
206
207     col_set_str(pinfo->cinfo, COL_PROTOCOL, "Babel");
208     col_set_str(pinfo->cinfo, COL_INFO, "Babel");
209
210     if(version != 2) {
211         col_add_fstr(pinfo->cinfo, COL_INFO, "Version %u", version);
212         return 2;
213     }
214         
215     if(tree) {
216         ti = proto_tree_add_item(tree, proto_babel, tvb, 0, -1, ENC_NA);
217         babel_tree = proto_item_add_subtree(ti, ett_babel);
218
219         proto_tree_add_item(babel_tree, hf_babel_magic, tvb, 0, 1, ENC_NA);
220         proto_tree_add_item(babel_tree, hf_babel_version, tvb, 1, 1, ENC_NA);
221         proto_tree_add_item(babel_tree, hf_babel_bodylen,
222                             tvb, 2, 2, ENC_BIG_ENDIAN);
223     }
224
225     bodylen = tvb_get_ntohs(tvb, 2);
226
227     i = 0;
228     while(i < bodylen) {
229         guint8 type, len = 0, total_length;
230         proto_tree *message_tree = NULL;
231         int message = 4 + i;
232
233         type = tvb_get_guint8(tvb, message);
234         if(type == MESSAGE_PAD1)
235             total_length = 1;
236         else {
237             len = tvb_get_guint8(tvb, message + 1);
238             total_length = len + 2;
239         }
240
241         col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
242                         val_to_str(type, messages, "unknown"));
243
244         ti = proto_tree_add_uint_format(babel_tree, hf_babel_message,
245                                         tvb, message, total_length, type,
246                                         "Message %s (%u)",
247                                         val_to_str(type, messages,
248                                                    "unknown"),
249                                         type);
250
251         if(tree) {
252             message_tree = proto_item_add_subtree(ti, ett_message);
253             proto_tree_add_item(message_tree, hf_babel_message_type,
254                                 tvb, message, 1, ENC_NA);
255         }
256
257         if(type == MESSAGE_PAD1) {
258             i++;
259             continue;
260         }
261
262         if(tree) {
263             proto_tree_add_item(message_tree, hf_babel_message_length,
264                                 tvb, message + 1, 1, ENC_BIG_ENDIAN);
265
266             if(type == MESSAGE_PADN) {
267             } else if(type == MESSAGE_ACK_REQ) {
268                 proto_tree_add_item(message_tree, hf_babel_message_nonce,
269                                     tvb, message + 4, 2, ENC_BIG_ENDIAN);
270                 proto_tree_add_item(message_tree, hf_babel_message_interval,
271                                     tvb, message + 6, 2, ENC_BIG_ENDIAN);
272             } else if(type == MESSAGE_ACK) {
273                 proto_tree_add_item(message_tree, hf_babel_message_nonce,
274                                     tvb, message + 2, 2, ENC_BIG_ENDIAN);
275             } else if(type == MESSAGE_HELLO) {
276                 proto_tree_add_item(message_tree, hf_babel_message_seqno,
277                                     tvb, message + 4, 2, ENC_BIG_ENDIAN);
278                 proto_tree_add_item(message_tree, hf_babel_message_interval,
279                                     tvb, message + 6, 2, ENC_BIG_ENDIAN);
280             } else if(type == MESSAGE_IHU) {
281                 proto_tree *subtree;
282                 unsigned char address[16];
283                 int rc =
284                     network_address(tvb_get_guint8(tvb, message + 2),
285                                     tvb_get_ptr(tvb, message + 8, len - 6),
286                                     len - 6,
287                                     address);
288                 proto_tree_add_item(message_tree, hf_babel_message_rxcost,
289                                     tvb, message + 4, 2, ENC_BIG_ENDIAN);
290                 proto_tree_add_item(message_tree, hf_babel_message_interval,
291                                     tvb, message + 6, 2, ENC_BIG_ENDIAN);
292                 ti = proto_tree_add_text(message_tree,
293                                          tvb, message + 4, len - 2,
294                                          "Address: %s",
295                                          format_address(rc < 0 ?
296                                                         NULL : address));
297                 subtree = proto_item_add_subtree(ti, ett_subtree);
298                 proto_tree_add_item(subtree, hf_babel_message_ae,
299                                     tvb, message + 2, 1, ENC_NA);
300                 proto_tree_add_item(subtree, hf_babel_message_prefix,
301                                     tvb, message + 4, len - 2, ENC_NA);
302             } else if(type == MESSAGE_ROUTER_ID) {
303                 proto_tree_add_item(message_tree, hf_babel_message_routerid,
304                                     tvb, message + 4, 8, ENC_NA);
305             } else if(type == MESSAGE_NH) {
306                 proto_tree *subtree;
307                 unsigned char nh[16];
308                 int rc =
309                     network_address(tvb_get_guint8(tvb, message + 2),
310                                     tvb_get_ptr(tvb, message + 4, len - 2),
311                                     len - 2,
312                                     nh);
313                 ti = proto_tree_add_text(message_tree,
314                                          tvb, message + 4, len - 2,
315                                          "NH: %s",
316                                          format_address(rc < 0 ? NULL : nh));
317                 subtree = proto_item_add_subtree(ti, ett_subtree);
318                 proto_tree_add_item(subtree, hf_babel_message_ae,
319                                     tvb, message + 2, 1, ENC_NA);
320                 proto_tree_add_item(subtree, hf_babel_message_prefix,
321                                     tvb, message + 4, len - 2, ENC_NA);
322             } else if(type == MESSAGE_UPDATE) {
323                 proto_tree *subtree;
324                 unsigned char p[16];
325                 guint8 ae = tvb_get_guint8(tvb, message + 2);
326                 guint8 flags = tvb_get_guint8(tvb, message + 3);
327                 guint8 plen = tvb_get_guint8(tvb, message + 4);
328                 int rc =
329                     network_prefix(ae, plen,
330                                    tvb_get_guint8(tvb, message + 5),
331                                    tvb_get_ptr(tvb, message + 12, len - 10),
332                                    ae == 1 ? v4_prefix : v6_prefix,
333                                    len - 10, p);
334                 if(rc >= 0 && (flags & 0x80)) {
335                     if(ae == 1)
336                         memcpy(v4_prefix, p, 16);
337                     else
338                         memcpy(v6_prefix, p, 16);
339                 }
340
341                 proto_tree_add_item(message_tree, hf_babel_message_flags,
342                                     tvb, message + 3, 1, ENC_NA);
343                 proto_tree_add_item(message_tree, hf_babel_message_interval,
344                                     tvb, message + 6, 2, ENC_BIG_ENDIAN);
345                 proto_tree_add_item(message_tree, hf_babel_message_seqno,
346                                     tvb, message + 8, 2, ENC_BIG_ENDIAN);
347                 proto_tree_add_item(message_tree, hf_babel_message_metric,
348                                     tvb, message + 10, 2, ENC_BIG_ENDIAN);
349                 ti = proto_tree_add_text(message_tree,
350                                          tvb, message + 12, len - 10,
351                                          "Prefix: %s",
352                                          format_prefix(rc < 0 ? NULL : p,
353                                                        plen));
354                 subtree = proto_item_add_subtree(ti, ett_subtree);
355                 proto_tree_add_item(subtree, hf_babel_message_ae,
356                                     tvb, message + 2, 1, ENC_NA);
357                 proto_tree_add_item(subtree, hf_babel_message_plen,
358                                     tvb, message + 4, 1, ENC_NA);
359                 proto_tree_add_item(subtree, hf_babel_message_omitted,
360                                     tvb, message + 5, 1, ENC_NA);
361                 proto_tree_add_item(subtree, hf_babel_message_prefix,
362                                     tvb, message + 12, len - 10, ENC_NA);
363             } else if(type == MESSAGE_REQUEST) {
364                 proto_tree *subtree;
365                 unsigned char p[16];
366                 guint8 plen = tvb_get_guint8(tvb, message + 3);
367                 int rc =
368                     network_prefix(tvb_get_guint8(tvb, message + 2), plen,
369                                    0,
370                                    tvb_get_ptr(tvb, message + 4, len - 2),
371                                    NULL,
372                                    len - 2, p);
373                 ti = proto_tree_add_text(message_tree,
374                                          tvb, message + 4, len - 2,
375                                          "Prefix: %s",
376                                          format_prefix(rc < 0 ? NULL : p,
377                                                        plen));
378                 subtree = proto_item_add_subtree(ti, ett_subtree);
379                 proto_tree_add_item(subtree, hf_babel_message_ae,
380                                     tvb, message + 2, 1, ENC_NA);
381                 proto_tree_add_item(subtree, hf_babel_message_plen,
382                                     tvb, message + 3, 1, ENC_NA);
383                 proto_tree_add_item(subtree, hf_babel_message_prefix,
384                                     tvb, message + 4, len - 2, ENC_NA);
385             } else if(type == MESSAGE_MH_REQUEST) {
386                 proto_tree *subtree;
387                 unsigned char p[16];
388                 guint8 plen = tvb_get_guint8(tvb, message + 3);
389                 int rc =
390                     network_prefix(tvb_get_guint8(tvb, message + 2), plen,
391                                    0,
392                                    tvb_get_ptr(tvb, message + 16, len - 14),
393                                    NULL,
394                                    len - 14, p);
395                 proto_tree_add_item(message_tree, hf_babel_message_seqno,
396                                     tvb, message + 4, 2, ENC_BIG_ENDIAN);
397                 proto_tree_add_item(message_tree, hf_babel_message_hopcount,
398                                     tvb, message + 6, 1, ENC_NA);
399                 proto_tree_add_item(message_tree, hf_babel_message_routerid,
400                                     tvb, message + 8, 8, ENC_NA);
401                 ti = proto_tree_add_text(message_tree,
402                                          tvb, message + 16, len - 14,
403                                          "Prefix: %s",
404                                          format_prefix(rc < 0 ? NULL : p,
405                                                        plen));
406                 subtree = proto_item_add_subtree(ti, ett_subtree);
407                 proto_tree_add_item(subtree, hf_babel_message_ae,
408                                     tvb, message + 2, 1, ENC_NA);
409                 proto_tree_add_item(subtree, hf_babel_message_plen,
410                                     tvb, message + 3, 1, ENC_NA);
411                 proto_tree_add_item(subtree, hf_babel_message_prefix,
412                                     tvb, message + 16, len - 14, ENC_NA);
413             }
414         }
415         i += len + 2;
416     }
417     return i;
418 }
419
420 void
421 proto_register_babel(void)
422 {
423     static hf_register_info hf[] = {
424         { &hf_babel_magic,
425           { "Magic", "babel.magic", FT_UINT8, BASE_DEC,
426             NULL, 0, "Magic value 42", HFILL }
427         },
428         { &hf_babel_version,
429           { "Version", "babel.version", FT_UINT8, BASE_DEC,
430             NULL, 0, "Version of the Babel protocol", HFILL }
431         },
432         { &hf_babel_bodylen,
433           { "Body Length", "babel.bodylen", FT_UINT16, BASE_DEC,
434             NULL, 0, NULL, HFILL }
435         },
436         { &hf_babel_message,
437           { "Message", "babel.message", FT_UINT8, BASE_DEC,
438             NULL, 0, "Babel Message", HFILL }
439         },
440         { &hf_babel_message_type,
441           { "Message Type", "babel.message.type", FT_UINT8, BASE_DEC,
442             VALS(messages), 0, NULL, HFILL }
443         },
444         { &hf_babel_message_length,
445           { "Message Length", "babel.message.length", FT_UINT8, BASE_DEC,
446             NULL, 0, NULL, HFILL }
447         },
448         { &hf_babel_message_nonce,
449           { "Nonce", "babel.message.nonce", FT_UINT16, BASE_HEX,
450            NULL, 0, NULL, HFILL }
451         },
452         { &hf_babel_message_interval,
453           { "Interval", "babel.message.interval", FT_UINT16, BASE_DEC,
454            NULL, 0, "Interval (in centiseconds)", HFILL }
455         },
456         { &hf_babel_message_seqno,
457           { "Seqno", "babel.message.seqno", FT_UINT16, BASE_HEX,
458            NULL, 0, NULL, HFILL }
459         },
460         { &hf_babel_message_ae,
461           { "Address Encoding", "babel.message.ae", FT_UINT8, BASE_DEC,
462             VALS(aes), 0, NULL, HFILL }
463         },
464         { &hf_babel_message_prefix,
465           { "Raw Prefix", "babel.message.prefix", FT_BYTES, BASE_NONE,
466             NULL, 0, NULL, HFILL }
467         },
468         { &hf_babel_message_rxcost,
469           { "Rxcost", "babel.message.rxcost", FT_UINT16, BASE_HEX,
470            NULL, 0, "Rxcost (from the point of vue of the sender)", HFILL }
471         },
472         { &hf_babel_message_routerid,
473           { "Router ID", "babel.message.routerid", FT_BYTES, BASE_NONE,
474            NULL, 0, NULL, HFILL }
475         },
476         { &hf_babel_message_flags,
477           { "Flags", "babel.message.flags", FT_UINT8, BASE_HEX,
478             NULL, 0, NULL, HFILL }
479         },
480         { &hf_babel_message_plen,
481           { "Prefix Length", "babel.message.plen", FT_UINT8, BASE_DEC,
482             NULL, 0, NULL, HFILL }
483         },
484         { &hf_babel_message_omitted,
485           { "Omitted Bytes", "babel.message.omitted", FT_UINT8, BASE_DEC,
486             NULL, 0, "Number of bytes omitted from the prefix", HFILL }
487         },
488         { &hf_babel_message_metric,
489           { "Metric", "babel.message.metric", FT_UINT16, BASE_DEC,
490            NULL, 0, NULL, HFILL }
491         },
492         { &hf_babel_message_hopcount,
493           { "Hop Count", "babel.message.omitted", FT_UINT8, BASE_DEC,
494             NULL, 0, NULL, HFILL }
495         },
496     };
497
498     static gint *ett[] = {
499         &ett_babel,
500         &ett_message,
501         &ett_subtree,
502     };
503
504     module_t *babel_module;
505
506     proto_babel =
507         proto_register_protocol("Babel Routing Protocol", "Babel", "babel");
508
509     proto_register_field_array(proto_babel, hf, array_length(hf));
510     proto_register_subtree_array(ett, array_length(ett));
511
512     babel_module = prefs_register_protocol(proto_babel,
513                                            proto_reg_handoff_babel);
514 }
515
516 void
517 proto_reg_handoff_babel(void)
518 {
519     dissector_handle_t babel_handle;
520
521     babel_handle = new_create_dissector_handle(dissect_babel, proto_babel);
522     dissector_add_uint("udp.port", UDP_PORT_BABEL, babel_handle);
523 }