print-babel.c revision 235427
191100Sdes/*
2115619Sdes * Copyright (c) 2007-2011 Gr��goire Henry, Juliusz Chroboczek
391100Sdes *
491100Sdes * Redistribution and use in source and binary forms, with or without
591100Sdes * modification, are permitted provided that the following conditions
699158Sdes * are met:
799158Sdes * 1. Redistributions of source code must retain the above copyright
899158Sdes *    notice, this list of conditions and the following disclaimer.
991100Sdes * 2. Redistributions in binary form must reproduce the above copyright
1091100Sdes *    notice, this list of conditions and the following disclaimer in the
1191100Sdes *    documentation and/or other materials provided with the distribution.
1291100Sdes * 3. Neither the name of the project nor the names of its contributors
1391100Sdes *    may be used to endorse or promote products derived from this software
1491100Sdes *    without specific prior written permission.
1591100Sdes *
1691100Sdes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1791100Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1891100Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1991100Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2091100Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2191100Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2291100Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2391100Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2491100Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2591100Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2691100Sdes * SUCH DAMAGE.
2791100Sdes */
2891100Sdes
2991100Sdes#ifdef HAVE_CONFIG_H
3091100Sdes#include "config.h"
3191100Sdes#endif
3291100Sdes
3391100Sdes#include <tcpdump-stdinc.h>
34115619Sdes
3591100Sdes#include <stdio.h>
3691100Sdes#include <string.h>
3791100Sdes
3891100Sdes#include "addrtoname.h"
3991100Sdes#include "interface.h"
4091100Sdes#include "extract.h"
4191100Sdes
4291100Sdesstatic void babel_print_v2(const u_char *cp, u_int length);
4391100Sdes
4491100Sdesvoid
4591100Sdesbabel_print(const u_char *cp, u_int length) {
4691100Sdes    printf("babel");
4791100Sdes
4891100Sdes    TCHECK2(*cp, 4);
4991100Sdes
5091100Sdes    if(cp[0] != 42) {
5191100Sdes        printf(" malformed header");
5291100Sdes        return;
5391100Sdes    } else {
5491100Sdes        printf(" %d", cp[1]);
5591100Sdes    }
5691100Sdes
5791100Sdes    switch(cp[1]) {
5891100Sdes    case 2:
5991100Sdes        babel_print_v2(cp,length);
6091100Sdes        break;
61107937Sdes    default:
62107937Sdes        printf(" unknown version");
6391100Sdes        break;
6491100Sdes    }
6591100Sdes
6691100Sdes    return;
6791100Sdes
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
85static const char *
86format_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
95static const unsigned char v4prefix[16] =
96    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
97
98static const char *
99format_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
110static const char *
111format_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
119static int
120network_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
174static int
175network_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
184static void
185babel_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}
415