diff options
author | Juliusz Chroboczek <jch@pps.jussieu.fr> | 2011-04-24 02:53:08 +0200 |
---|---|---|
committer | Michael Richardson <mcr@sandelman.ca> | 2011-04-27 15:27:20 -0400 |
commit | 12b169509d018d3cfc0dfd1db44d03bf71a68be6 (patch) | |
tree | 232b6a9151aab0b45ac063cfc3d2e87d274974e4 /print-babel.c | |
parent | 76bbd5f9eaae7248214ab54c3ffdeee5ffaec4cb (diff) | |
download | tcpdump-12b169509d018d3cfc0dfd1db44d03bf71a68be6.tar.gz |
Add printer for the Babel routing protocol (RFC 6126).
This version includes a couple of fixes from Wireshark.
Diffstat (limited to 'print-babel.c')
-rw-r--r-- | print-babel.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/print-babel.c b/print-babel.c new file mode 100644 index 00000000..a8108fc5 --- /dev/null +++ b/print-babel.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2007-2011 Grégoire Henry, Juliusz Chroboczek + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <tcpdump-stdinc.h> + +#include <stdio.h> +#include <string.h> + +#include "addrtoname.h" +#include "interface.h" + +static void babel_print_v2(const u_char *cp, u_int length); + +void +babel_print(const u_char *cp, u_int length) { + printf("babel"); + + TCHECK2(*cp, 4); + + if(cp[0] != 42) { + printf(" malformed header"); + return; + } else { + printf(" %d", cp[1]); + } + + switch(cp[1]) { + case 2: + babel_print_v2(cp,length); + break; + default: + printf(" unknown version"); + break; + } + + return; + + trunc: + printf(" [|babel]"); + return; +} + +#if defined __GNUC__ +struct __us { unsigned short x __attribute__((packed)); }; +#define DO_NTOHS(_d, _s) \ + do { _d = ntohs(((const struct __us*)(_s))->x); } while(0) +#define DO_HTONS(_d, _s) \ + do { ((struct __us*)(_d))->x = htons(_s); } while(0) +#else +#define DO_NTOHS(_d, _s) \ + do { short _dd; \ + memcpy(&(_dd), (_s), 2); \ + _d = ntohs(_dd); } while(0) +#define DO_HTONS(_d, _s) \ + do { unsigned short _dd; \ + _dd = htons(_s); \ + memcpy((_d), &(_dd), 2); } while(0) +#endif + +#define MESSAGE_PAD1 0 +#define MESSAGE_PADN 1 +#define MESSAGE_ACK_REQ 2 +#define MESSAGE_ACK 3 +#define MESSAGE_HELLO 4 +#define MESSAGE_IHU 5 +#define MESSAGE_ROUTER_ID 6 +#define MESSAGE_NH 7 +#define MESSAGE_UPDATE 8 +#define MESSAGE_REQUEST 9 +#define MESSAGE_MH_REQUEST 10 + +static const char * +format_id(const u_char *id) +{ + static char buf[25]; + snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]); + buf[24] = '\0'; + return buf; +} + +static const unsigned char v4prefix[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; + +static const char * +format_prefix(const u_char *prefix, unsigned char plen) +{ + static char buf[50]; + if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0) + snprintf(buf, 50, "%s/%u", ipaddr_string(prefix + 12), plen - 96); + else + snprintf(buf, 50, "%s/%u", ip6addr_string(prefix), plen); + buf[49] = '\0'; + return buf; +} + +static const char * +format_address(const u_char *prefix) +{ + if(memcmp(prefix, v4prefix, 12) == 0) + return ipaddr_string(prefix + 12); + else + return ip6addr_string(prefix); +} + +static int +network_prefix(int ae, int plen, unsigned int omitted, + const unsigned char *p, const unsigned char *dp, + unsigned int len, unsigned char *p_r) +{ + unsigned pb; + unsigned char prefix[16]; + + if(plen >= 0) + pb = (plen + 7) / 8; + else if(ae == 1) + pb = 4; + else + pb = 16; + + if(pb > 16) + return -1; + + memset(prefix, 0, 16); + + switch(ae) { + case 0: break; + case 1: + if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) + return -1; + memcpy(prefix, v4prefix, 12); + if(omitted) { + if (dp == NULL) return -1; + memcpy(prefix, dp, 12 + omitted); + } + if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); + break; + case 2: + if(omitted > 16 || (pb > omitted && len < pb - omitted)) + return -1; + if(omitted) { + if (dp == NULL) return -1; + memcpy(prefix, dp, omitted); + } + if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); + break; + case 3: + if(pb > 8 && len < pb - 8) return -1; + prefix[0] = 0xfe; + prefix[1] = 0x80; + if(pb > 8) memcpy(prefix + 8, p, pb - 8); + break; + default: + return -1; + } + + memcpy(p_r, prefix, 16); + return 1; +} + +static int +network_address(int ae, const unsigned char *a, unsigned int len, + unsigned char *a_r) +{ + return network_prefix(ae, -1, 0, a, NULL, len, a_r); +} + +static void +babel_print_v2(const u_char *cp, u_int length) { + int i; + u_short bodylen; + u_char v4_prefix[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; + u_char v6_prefix[16] = {0}; + + DO_NTOHS(bodylen, cp + 2); + printf(" (%d)", bodylen); + + i = 0; + while(i < bodylen) { + const u_char *message; + u_char type, len; + + TCHECK2(*cp, 4 + i); + + message = cp + 4 + i; + type = message[0]; + len = message[1]; + + TCHECK2(*cp, 4 + i + 2 + len); + + switch(type) { + case MESSAGE_PAD1: { + if(!vflag) + printf(" pad1"); + else + printf("\n\tPad 1"); + } + break; + + case MESSAGE_PADN: { + if(!vflag) + printf(" padN"); + else + printf("\n\tPad %d", len + 2); + } + break; + + case MESSAGE_ACK_REQ: { + u_short nonce, interval; + if(!vflag) + printf(" ack-req"); + else { + printf("\n\tAcknowledgment Request "); + if(len < 6) goto corrupt; + DO_NTOHS(nonce, message + 4); + DO_NTOHS(interval, message + 6); + printf("%04x %d", nonce, interval); + } + } + break; + + case MESSAGE_ACK: { + u_short nonce; + if(!vflag) + printf(" ack"); + else { + printf("\n\tAcknowledgment "); + if(len < 2) goto corrupt; + DO_NTOHS(nonce, message + 2); + printf("%04x", nonce); + } + } + break; + + case MESSAGE_HELLO: { + u_short seqno, interval; + if(!vflag) + printf(" hello"); + else { + printf("\n\tHello "); + if(len < 6) goto corrupt; + DO_NTOHS(seqno, message + 4); + DO_NTOHS(interval, message + 6); + printf("seqno %u interval %u", seqno, interval); + } + } + break; + + case MESSAGE_IHU: { + unsigned short txcost, interval; + if(!vflag) + printf(" ihu"); + else { + u_char address[16]; + int rc; + printf("\n\tIHU "); + if(len < 6) goto corrupt; + DO_NTOHS(txcost, message + 4); + DO_NTOHS(interval, message + 6); + rc = network_address(message[2], message + 8, len - 6, address); + if(rc < 0) { printf("[|babel]"); break; } + printf("%s txcost %u interval %d", + format_address(address), txcost, interval); + } + } + break; + + case MESSAGE_ROUTER_ID: { + if(!vflag) + printf(" router-id"); + else { + printf("\n\tRouter Id"); + if(len < 10) goto corrupt; + printf(" %s", format_id(message + 4)); + } + } + break; + + case MESSAGE_NH: { + if(!vflag) + printf(" nh"); + else { + int rc; + u_char nh[16]; + printf("\n\tNext Hop"); + if(len < 2) goto corrupt; + rc = network_address(message[2], message + 4, len - 2, nh); + if(rc < 0) goto corrupt; + printf(" %s", format_address(nh)); + } + } + break; + + case MESSAGE_UPDATE: { + if(!vflag) { + printf(" update"); + if(len < 1) + printf("/truncated"); + else + printf("%s%s%s", + (message[3] & 0x80) ? "/prefix": "", + (message[3] & 0x40) ? "/id" : "", + (message[3] & 0x3f) ? "/unknown" : ""); + } else { + u_short interval, seqno, metric; + u_char plen; + int rc; + u_char prefix[16]; + printf("\n\tUpdate"); + if(len < 10) goto corrupt; + plen = message[4] + (message[2] == 1 ? 96 : 0); + rc = network_prefix(message[2], message[4], message[5], + message + 12, + message[2] == 1 ? v4_prefix : v6_prefix, + len - 10, prefix); + if(rc < 0) goto corrupt; + DO_NTOHS(interval, message + 6); + DO_NTOHS(seqno, message + 8); + DO_NTOHS(metric, message + 10); + printf("%s%s%s %s metric %u seqno %u interval %u", + (message[3] & 0x80) ? "/prefix": "", + (message[3] & 0x40) ? "/id" : "", + (message[3] & 0x3f) ? "/unknown" : "", + format_prefix(prefix, plen), + metric, seqno, interval); + if(message[3] & 0x80) { + if(message[2] == 1) + memcpy(v4_prefix, prefix, 16); + else + memcpy(v6_prefix, prefix, 16); + } + } + } + break; + + case MESSAGE_REQUEST: { + if(!vflag) + printf(" request"); + else { + int rc; + u_char prefix[16], plen; + printf("\n\tRequest "); + if(len < 2) goto corrupt; + plen = message[3] + (message[2] == 1 ? 96 : 0); + rc = network_prefix(message[2], message[3], 0, + message + 4, NULL, len - 2, prefix); + if(rc < 0) goto corrupt; + plen = message[3] + (message[2] == 1 ? 96 : 0); + printf("for %s", + message[2] == 0 ? "any" : format_prefix(prefix, plen)); + } + } + break; + + case MESSAGE_MH_REQUEST : { + if(!vflag) + printf(" mh-request"); + else { + int rc; + u_short seqno; + u_char prefix[16], plen; + printf("\n\tMH-Request "); + if(len < 14) goto corrupt; + DO_NTOHS(seqno, message + 4); + rc = network_prefix(message[2], message[3], 0, + message + 16, NULL, len - 14, prefix); + if(rc < 0) goto corrupt; + plen = message[3] + (message[2] == 1 ? 96 : 0); + printf("(%u hops) for %s seqno %u id %s", + message[6], format_prefix(prefix, plen), + seqno, format_id(message + 8)); + } + } + break; + default: + if(!vflag) + printf(" unknown"); + else + printf("\n\tUnknown message type %d", type); + } + i += len + 2; + } + return; + + trunc: + printf(" [|babel]"); + return; + + corrupt: + printf(" (corrupt)"); + return; +} |