Merge branch 'vendor/TCPDUMP'
[dragonfly.git] / contrib / tcpdump / print-babel.c
1 /*
2  * Copyright (c) 2007-2011 GrĂ©goire Henry, Juliusz Chroboczek
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  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <tcpdump-stdinc.h>
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "addrtoname.h"
39 #include "interface.h"
40 #include "extract.h"
41
42 static void babel_print_v2(const u_char *cp, u_int length);
43
44 void
45 babel_print(const u_char *cp, u_int length) {
46     printf("babel");
47
48     TCHECK2(*cp, 4);
49
50     if(cp[0] != 42) {
51         printf(" malformed header");
52         return;
53     } else {
54         printf(" %d", cp[1]);
55     }
56
57     switch(cp[1]) {
58     case 2:
59         babel_print_v2(cp,length);
60         break;
61     default:
62         printf(" unknown version");
63         break;
64     }
65
66     return;
67
68  trunc:
69     printf(" [|babel]");
70     return;
71 }
72
73 #define MESSAGE_PAD1 0
74 #define MESSAGE_PADN 1
75 #define MESSAGE_ACK_REQ 2
76 #define MESSAGE_ACK 3
77 #define MESSAGE_HELLO 4
78 #define MESSAGE_IHU 5
79 #define MESSAGE_ROUTER_ID 6
80 #define MESSAGE_NH 7
81 #define MESSAGE_UPDATE 8
82 #define MESSAGE_REQUEST 9
83 #define MESSAGE_MH_REQUEST 10
84
85 static const char *
86 format_id(const u_char *id)
87 {
88     static char buf[25];
89     snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
90              id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
91     buf[24] = '\0';
92     return buf;
93 }
94
95 static const unsigned char v4prefix[16] =
96     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
97
98 static const char *
99 format_prefix(const u_char *prefix, unsigned char plen)
100 {
101     static char buf[50];
102     if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
103         snprintf(buf, 50, "%s/%u", ipaddr_string(prefix + 12), plen - 96);
104     else
105         snprintf(buf, 50, "%s/%u", ip6addr_string(prefix), plen);
106     buf[49] = '\0';
107     return buf;
108 }
109
110 static const char *
111 format_address(const u_char *prefix)
112 {
113     if(memcmp(prefix, v4prefix, 12) == 0)
114         return ipaddr_string(prefix + 12);
115     else
116         return ip6addr_string(prefix);
117 }
118
119 static int
120 network_prefix(int ae, int plen, unsigned int omitted,
121                const unsigned char *p, const unsigned char *dp,
122                unsigned int len, unsigned char *p_r)
123 {
124     unsigned pb;
125     unsigned char prefix[16];
126
127     if(plen >= 0)
128         pb = (plen + 7) / 8;
129     else if(ae == 1)
130         pb = 4;
131     else
132         pb = 16;
133
134     if(pb > 16)
135         return -1;
136
137     memset(prefix, 0, 16);
138
139     switch(ae) {
140     case 0: break;
141     case 1:
142         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
143             return -1;
144         memcpy(prefix, v4prefix, 12);
145         if(omitted) {
146             if (dp == NULL) return -1;
147             memcpy(prefix, dp, 12 + omitted);
148         }
149         if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted);
150         break;
151     case 2:
152         if(omitted > 16 || (pb > omitted && len < pb - omitted))
153             return -1;
154         if(omitted) {
155             if (dp == NULL) return -1;
156             memcpy(prefix, dp, omitted);
157         }
158         if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted);
159         break;
160     case 3:
161         if(pb > 8 && len < pb - 8) return -1;
162         prefix[0] = 0xfe;
163         prefix[1] = 0x80;
164         if(pb > 8) memcpy(prefix + 8, p, pb - 8);
165         break;
166     default:
167         return -1;
168     }
169
170     memcpy(p_r, prefix, 16);
171     return 1;
172 }
173
174 static int
175 network_address(int ae, const unsigned char *a, unsigned int len,
176                 unsigned char *a_r)
177 {
178     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
179 }
180
181 #define ICHECK(i, l) \
182         if ((i) + (l) > bodylen || (i) + (l) > length) goto corrupt;
183
184 static void
185 babel_print_v2(const u_char *cp, u_int length) {
186     u_int i;
187     u_short bodylen;
188     u_char v4_prefix[16] =
189         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
190     u_char v6_prefix[16] = {0};
191
192     TCHECK2(*cp, 4);
193     if (length < 4)
194         goto corrupt;
195     bodylen = EXTRACT_16BITS(cp + 2);
196     printf(" (%u)", bodylen);
197
198     /* Process the TLVs in the body */
199     i = 0;
200     while(i < bodylen) {
201         const u_char *message;
202         u_char type, len;
203
204         message = cp + 4 + i;
205         TCHECK2(*message, 2);
206         ICHECK(i, 2);
207         type = message[0];
208         len = message[1];
209
210         TCHECK2(*message, 2 + len);
211         ICHECK(i, 2 + len);
212
213         switch(type) {
214         case MESSAGE_PAD1: {
215             if(!vflag)
216                 printf(" pad1");
217             else
218                 printf("\n\tPad 1");
219         }
220             break;
221
222         case MESSAGE_PADN: {
223             if(!vflag)
224                 printf(" padN");
225             else
226                 printf("\n\tPad %d", len + 2);
227         }
228             break;
229
230         case MESSAGE_ACK_REQ: {
231             u_short nonce, interval;
232             if(!vflag)
233                 printf(" ack-req");
234             else {
235                 printf("\n\tAcknowledgment Request ");
236                 if(len < 6) goto corrupt;
237                 nonce = EXTRACT_16BITS(message + 4);
238                 interval = EXTRACT_16BITS(message + 6);
239                 printf("%04x %d", nonce, interval);
240             }
241         }
242             break;
243
244         case MESSAGE_ACK: {
245             u_short nonce;
246             if(!vflag)
247                 printf(" ack");
248             else {
249                 printf("\n\tAcknowledgment ");
250                 if(len < 2) goto corrupt;
251                 nonce = EXTRACT_16BITS(message + 2);
252                 printf("%04x", nonce);
253             }
254         }
255             break;
256
257         case MESSAGE_HELLO:  {
258             u_short seqno, interval;
259             if(!vflag)
260                 printf(" hello");
261             else {
262                 printf("\n\tHello ");
263                 if(len < 6) goto corrupt;
264                 seqno = EXTRACT_16BITS(message + 4);
265                 interval = EXTRACT_16BITS(message + 6);
266                 printf("seqno %u interval %u", seqno, interval);
267             }
268         }
269             break;
270
271         case MESSAGE_IHU: {
272             unsigned short txcost, interval;
273             if(!vflag)
274                 printf(" ihu");
275             else {
276                 u_char address[16];
277                 int rc;
278                 printf("\n\tIHU ");
279                 if(len < 6) goto corrupt;
280                 txcost = EXTRACT_16BITS(message + 4);
281                 interval = EXTRACT_16BITS(message + 6);
282                 rc = network_address(message[2], message + 8, len - 6, address);
283                 if(rc < 0) { printf("[|babel]"); break; }
284                 printf("%s txcost %u interval %d",
285                        format_address(address), txcost, interval);
286             }
287         }
288             break;
289
290         case MESSAGE_ROUTER_ID: {
291             if(!vflag)
292                 printf(" router-id");
293             else {
294                 printf("\n\tRouter Id");
295                 if(len < 10) goto corrupt;
296                 printf(" %s", format_id(message + 4));
297             }
298         }
299             break;
300
301         case MESSAGE_NH: {
302             if(!vflag)
303                 printf(" nh");
304             else {
305                 int rc;
306                 u_char nh[16];
307                 printf("\n\tNext Hop");
308                 if(len < 2) goto corrupt;
309                 rc = network_address(message[2], message + 4, len - 2, nh);
310                 if(rc < 0) goto corrupt;
311                 printf(" %s", format_address(nh));
312             }
313         }
314             break;
315
316         case MESSAGE_UPDATE: {
317             if(!vflag) {
318                 printf(" update");
319                 if(len < 1)
320                     printf("/truncated");
321                 else
322                     printf("%s%s%s",
323                            (message[3] & 0x80) ? "/prefix": "",
324                            (message[3] & 0x40) ? "/id" : "",
325                            (message[3] & 0x3f) ? "/unknown" : "");
326             } else {
327                 u_short interval, seqno, metric;
328                 u_char plen;
329                 int rc;
330                 u_char prefix[16];
331                 printf("\n\tUpdate");
332                 if(len < 10) goto corrupt;
333                 plen = message[4] + (message[2] == 1 ? 96 : 0);
334                 rc = network_prefix(message[2], message[4], message[5],
335                                     message + 12,
336                                     message[2] == 1 ? v4_prefix : v6_prefix,
337                                     len - 10, prefix);
338                 if(rc < 0) goto corrupt;
339                 interval = EXTRACT_16BITS(message + 6);
340                 seqno = EXTRACT_16BITS(message + 8);
341                 metric = EXTRACT_16BITS(message + 10);
342                 printf("%s%s%s %s metric %u seqno %u interval %u",
343                        (message[3] & 0x80) ? "/prefix": "",
344                        (message[3] & 0x40) ? "/id" : "",
345                        (message[3] & 0x3f) ? "/unknown" : "",
346                        format_prefix(prefix, plen),
347                        metric, seqno, interval);
348                 if(message[3] & 0x80) {
349                     if(message[2] == 1)
350                         memcpy(v4_prefix, prefix, 16);
351                     else
352                         memcpy(v6_prefix, prefix, 16);
353                 }
354             }
355         }
356             break;
357
358         case MESSAGE_REQUEST: {
359             if(!vflag)
360                 printf(" request");
361             else {
362                 int rc;
363                 u_char prefix[16], plen;
364                 printf("\n\tRequest ");
365                 if(len < 2) goto corrupt;
366                 plen = message[3] + (message[2] == 1 ? 96 : 0);
367                 rc = network_prefix(message[2], message[3], 0,
368                                     message + 4, NULL, len - 2, prefix);
369                 if(rc < 0) goto corrupt;
370                 plen = message[3] + (message[2] == 1 ? 96 : 0);
371                 printf("for %s",
372                        message[2] == 0 ? "any" : format_prefix(prefix, plen));
373             }
374         }
375             break;
376
377         case MESSAGE_MH_REQUEST : {
378             if(!vflag)
379                 printf(" mh-request");
380             else {
381                 int rc;
382                 u_short seqno;
383                 u_char prefix[16], plen;
384                 printf("\n\tMH-Request ");
385                 if(len < 14) goto corrupt;
386                 seqno = EXTRACT_16BITS(message + 4);
387                 rc = network_prefix(message[2], message[3], 0,
388                                     message + 16, NULL, len - 14, prefix);
389                 if(rc < 0) goto corrupt;
390                 plen = message[3] + (message[2] == 1 ? 96 : 0);
391                 printf("(%u hops) for %s seqno %u id %s",
392                        message[6], format_prefix(prefix, plen),
393                        seqno, format_id(message + 8));
394             }
395         }
396             break;
397         default:
398             if(!vflag)
399                 printf(" unknown");
400             else
401                 printf("\n\tUnknown message type %d", type);
402         }
403         i += len + 2;
404     }
405     return;
406
407  trunc:
408     printf(" [|babel]");
409     return;
410
411  corrupt:
412     printf(" (corrupt)");
413     return;
414 }