bgp improvements.

- a few more tree types
- RFC1771 NLRI printed on advertisements
- AS_PATH parsing
- lots of small cleanup on printing "byte" vs "bytes"

From: Greg Hankins <gregh@cc.gatech.edu>

svn path=/trunk/; revision=1015
This commit is contained in:
Jun-ichiro itojun Hagino 1999-11-11 21:08:52 +00:00
parent 4020918fa4
commit 1d554ab6c9
3 changed files with 207 additions and 131 deletions

View File

@ -2,7 +2,7 @@
* Routines for BGP packet dissection.
* Copyright 1999, Jun-ichiro itojun Hagino <itojun@itojun.org>
*
* $Id: packet-bgp.c,v 1.8 1999/11/06 01:28:49 itojun Exp $
* $Id: packet-bgp.c,v 1.9 1999/11/11 21:08:51 itojun Exp $
*
* Supports:
* RFC1771 A Border Gateway Protocol 4 (BGP-4)
@ -63,6 +63,7 @@
#include "packet.h"
#include "packet-bgp.h"
#include "packet-ipv6.h"
#include <arpa/inet.h>
static const value_string bgptypevals[] = {
{ BGP_OPEN, "OPEN Message" },
@ -178,6 +179,9 @@ static const value_string afnumber[] = {
static int proto_bgp = -1;
/*
* Decode an IPv4 prefix.
*/
static int
decode_prefix4(const u_char *pd, char *buf, int buflen)
{
@ -196,6 +200,9 @@ decode_prefix4(const u_char *pd, char *buf, int buflen)
return 1 + (plen + 7) / 8;
}
/*
* Decode an IPv6 prefix.
*/
static int
decode_prefix6(const u_char *pd, char *buf, int buflen)
{
@ -220,8 +227,8 @@ decode_prefix6(const u_char *pd, char *buf, int buflen)
static void
dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
{
struct bgp_open bgpo; /* BGP OPEN message */
int hlen; /* message length */
struct bgp_open bgpo; /* BGP OPEN message */
int hlen; /* message length */
/* snarf OPEN message */
memcpy(&bgpo, &pd[offset], sizeof(bgpo));
@ -251,64 +258,58 @@ dissect_bgp_open(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
}
}
/* NOTE: caller needs to free() the returned value. */
static char *
dissect_bgp_aspath(const u_char *pd, int len)
{
char *msg;
int j, n;
char *q;
if (len % 2)
return NULL;
msg = malloc(len / 2 * 6 + 10);
if (!msg)
return NULL;
q = msg;
for (j = 0; j < len; j += 2) {
n = sprintf(q, "%u ", ntohs(*(guint16 *)&pd[j]));
q += n;
}
/* remove the last blank */
q--;
*q = '\0';
return msg;
}
/*
* Dissect a BGP UPDATE message.
*/
static void
dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
proto_tree *tree)
{
struct bgp bgp;
struct bgp bgp;
struct bgp_attr bgpa;
int hlen;
const u_char *p;
int len;
proto_item *ti;
proto_tree *subtree, *subtree2, *subtree3;
int i;
int hlen;
const u_char *p;
const u_char *q;
const u_char *end;
int len;
proto_item *ti;
proto_tree *subtree;
proto_tree *subtree2;
proto_tree *subtree3;
int i;
int j;
guint8 length;
guint8 type;
struct in_addr prefix;
char *as_path_str = NULL;
char junk_buf[10];
/* snarf UPDATE message */
memcpy(&bgp, &pd[offset], sizeof(bgp));
hlen = ntohs(bgp.bgp_len);
p = &pd[offset + BGP_HEADER_SIZE]; /*XXX*/
/* check for withdrawals */
len = ntohs(*(guint16 *)p);
proto_tree_add_text(tree, p - pd, 2,
"Unfeasible routes length: %d", len = ntohs(*(guint16 *)p));
ti = proto_tree_add_text(tree, p - pd, len,
"Withdrawn routes (%u bytes)", len);
if (len) {
subtree = proto_item_add_subtree(ti, ETT_BGP);
"Unfeasible routes length: %u %s", len, (len == 1) ? "byte" : "bytes");
if (len > 0) {
ti = proto_tree_add_text(tree, p - pd, len, "Withdrawn routes:");
/* TODO: unfeasible */
subtree = proto_item_add_subtree(ti, ETT_BGP_UNFEAS);
}
p += 2 + len;
proto_tree_add_text(tree, p - pd, 2,
"Total path attribute length: %d", len = ntohs(*(guint16 *)p));
ti = proto_tree_add_text(tree, p - pd + 2, len,
"Path attributes (%u bytes)", len);
if (len) {
subtree = proto_item_add_subtree(ti, ETT_BGP);
/* check for advertisements */
len = ntohs(*(guint16 *)p);
proto_tree_add_text(tree, p - pd, 2, "Total path attribute length: %u %s",
len, (len == 1) ? "byte" : "bytes");
/* path attributes */
/* --- move --- */
if (len > 0) {
ti = proto_tree_add_text(tree, p - pd + 2, len, "Path attributes");
subtree = proto_item_add_subtree(ti, ETT_BGP_ATTRS);
i = 2;
while (i < len) {
int alen, aoff;
@ -317,7 +318,7 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
int off, snpa;
memcpy(&bgpa, &p[i], sizeof(bgpa));
if (bgpa.bgpa_flags & 0x10) {
if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
alen = ntohs(*(guint16 *)&p[i + sizeof(bgpa)]);
aoff = sizeof(bgpa) + 2;
} else {
@ -335,135 +336,167 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
goto default_attribute_top;
msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"Attribute: %s: %s (%u bytes)",
"%s: %s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
msg, alen + aoff);
msg, alen + aoff, (alen + aoff == 1) ? "byte" :
"bytes");
break;
case BGPTYPE_AS_PATH:
if (alen % 2)
goto default_attribute_top;
msg = dissect_bgp_aspath(p + i + aoff, alen);
if (msg == NULL)
/* (p + i + 3) =
(p + current attribute + 3 bytes to first tuple) */
end = p + alen + i + 3;
q = p + i + 3;
/* must be freed by second case */
/* "alen * 6" (5 digits + space) should be a good estimate
of how long the AS path string could be */
as_path_str = malloc(alen * 6);
memset(as_path_str, '\0', alen * 6);
if (as_path_str == NULL) break;
/* snarf each AS path */
while (q < end) {
type = *q++;
if (type == AS_SET) {
sprintf(as_path_str, "{");
}
length = *q++;
/* snarf each value in path */
for (j = 0; j < length; j++) {
sprintf(junk_buf, "%u%c", pntohs(q),
(type == AS_SET) ? ',' : ' ');
strcat(as_path_str, junk_buf);
q += 2;
}
/* cleanup end of string */
if (type == AS_SET) {
as_path_str[strlen(as_path_str) - 1] = '}';
as_path_str[strlen(as_path_str) + 1] = '\0';
}
else {
as_path_str[strlen(as_path_str) - 1] = '\0';
}
}
if (as_path_str[0] == '\0')
goto default_attribute_top;
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"Attribute: %s: %s (%u bytes)",
"%s: %s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
msg, alen + aoff);
free(msg);
as_path_str, alen + aoff, (alen + aoff == 1) ? "byte" :
"bytes");
break;
case BGPTYPE_NEXT_HOP:
if (alen != 4)
goto default_attribute_top;
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"Attribute: %s: %s (%u bytes)",
"%s: %s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
ip_to_str(&p[i + aoff]), alen + aoff);
ip_to_str(&p[i + aoff]), alen + aoff, (alen + aoff == 1)
? "byte" : "bytes");
break;
case BGPTYPE_MULTI_EXIT_DISC:
if (alen != 4)
goto default_attribute_top;
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"Attribute: %s: %u (%u bytes)",
"%s: %u (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
ntohl(*(guint32 *)&p[i + aoff]),
alen + aoff);
ntohl(*(guint32 *)&p[i + aoff]), alen + aoff,
(alen + aoff == 1) ? "byte" : "bytes");
break;
case BGPTYPE_LOCAL_PREF:
if (alen != 4)
goto default_attribute_top;
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"Attribute: %s: %u (%u bytes)",
"%s: %u (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
ntohl(*(guint32 *)&p[i + aoff]),
alen + aoff);
ntohl(*(guint32 *)&p[i + aoff]), alen + aoff,
(alen + aoff == 1) ? "byte" : "bytes");
break;
case BGPTYPE_AGGREGATOR:
if (alen != 6)
case BGPTYPE_ATOMIC_AGGREGATE:
if (alen != 0)
goto default_attribute_top;
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"Attribute: %s: AS %u, origin %s (%u bytes)",
"%s: (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
ntohs(*(guint16 *)&p[i + aoff]),
ip_to_str(&p[i + aoff + 2]), alen + aoff);
alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
break;
default:
default_attribute_top:
ti = proto_tree_add_text(subtree, p - pd + i, alen + aoff,
"Attribute: %s (%u bytes)",
"%s (%u %s)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
alen + aoff);
alen + aoff, (alen + aoff == 1) ? "byte" : "bytes");
}
subtree2 = proto_item_add_subtree(ti, ETT_BGP);
subtree2 = proto_item_add_subtree(ti, ETT_BGP_ATTR);
/* figure out flags */
ti = proto_tree_add_text(subtree2,
p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
"Flags: 0x%02x", bgpa.bgpa_flags);
subtree3 = proto_item_add_subtree(ti, ETT_BGP);
subtree3 = proto_item_add_subtree(ti, ETT_BGP_ATTR_FLAGS);
proto_tree_add_text(subtree3,
p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
"%s", decode_boolean_bitfield(bgpa.bgpa_flags,
0x80, 8, "Optional", "not Optional"));
BGP_ATTR_FLAG_OPTIONAL, 8, "Optional", "Well-known"));
proto_tree_add_text(subtree3,
p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
"%s", decode_boolean_bitfield(bgpa.bgpa_flags,
0x40, 8, "Transitive", "not Transitive"));
BGP_ATTR_FLAG_TRANSITIVE, 8, "Transitive",
"Non-transitive"));
proto_tree_add_text(subtree3,
p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
"%s", decode_boolean_bitfield(bgpa.bgpa_flags,
0x20, 8, "Partial", "not Partial"));
BGP_ATTR_FLAG_PARTIAL, 8, "Partial", "Complete"));
proto_tree_add_text(subtree3,
p - pd + i + offsetof(struct bgp_attr, bgpa_flags), 1,
"%s", decode_boolean_bitfield(bgpa.bgpa_flags,
0x10, 8, "Extended length", "not Extended length"));
BGP_ATTR_FLAG_EXTENDED_LENGTH, 8, "Extended length",
"Regular length"));
proto_tree_add_text(subtree2,
p - pd + i + offsetof(struct bgp_attr, bgpa_type), 1,
"Type code: %s (0x%02x)",
"Type code: %s (%u)",
val_to_str(bgpa.bgpa_type, bgpattr_type, "Unknown"),
bgpa.bgpa_type);
if (bgpa.bgpa_flags & 0x10) {
/* check for the Extended Length bit */
if (bgpa.bgpa_flags & BGP_ATTR_FLAG_EXTENDED_LENGTH) {
proto_tree_add_text(subtree2,
p - pd + i + sizeof(bgpa), aoff - sizeof(bgpa),
"Attribute length: %d", alen);
"Length: %d %s", alen,
(alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2,
p - pd + i + sizeof(bgpa), aoff - sizeof(bgpa),
"Attribute length: %d", alen);
"Length: %d %s", alen,
(alen == 1) ? "byte" : "bytes");
}
switch (bgpa.bgpa_type) {
case BGPTYPE_ORIGIN:
if (alen != 1) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Origin: Invalid (%d bytes)", alen);
"Origin (invalid): %u %s", alen,
(alen == 1) ? "byte" : "bytes");
} else {
msg = val_to_str(p[i + aoff], bgpattr_origin, "Unknown");
proto_tree_add_text(subtree2, p - pd + i + aoff, 1,
"Origin: %s (0x%02x)", msg, p[i + aoff]);
"Origin: %s (%u)", msg, p[i + aoff]);
}
break;
case BGPTYPE_AS_PATH:
if (alen % 2) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"AS path: Invalid (%d bytes)", alen);
} else {
msg = dissect_bgp_aspath(p + i + aoff, alen);
if (msg == NULL) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"AS path (%d bytes)", alen);
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"AS path: %s (%d ASes, %d bytes)",
msg, alen / 2, alen);
free(msg);
}
}
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"AS path: %s (%u %s)", as_path_str, alen,
(alen == 1) ? "byte" : "bytes");
free(as_path_str);
break;
case BGPTYPE_NEXT_HOP:
if (alen != 4) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Next hop: Invalid (%d bytes)", alen);
"Next hop (invalid): %u %s", alen,
(alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Next hop: %s", ip_to_str(&p[i + aoff]));
@ -472,8 +505,8 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
case BGPTYPE_MULTI_EXIT_DISC:
if (alen != 4) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Multi exit discriminator: Invalid (%d bytes)",
alen);
"Multi exit discriminator (invalid): %u %s",
alen, (alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Multi exit discriminator: %u",
@ -483,7 +516,8 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
case BGPTYPE_LOCAL_PREF:
if (alen != 4) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Local preference: Invalid (%d bytes)", alen);
"Local preference (invalid): %u %s", alen,
(alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Local preference: %u",
@ -493,7 +527,8 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
case BGPTYPE_ATOMIC_AGGREGATE:
if (alen != 0) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Atomic aggregate: Invalid (%d bytes)", alen);
"Atomic aggregate (invalid): %u %s", alen,
(alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, 0,
"Atomic aggregate");
@ -502,7 +537,8 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
case BGPTYPE_AGGREGATOR:
if (alen != 6) {
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Aggregator: Invalid (%d bytes)", alen);
"Aggregator (invalid): %u %s", alen,
(alen == 1) ? "byte" : "bytes");
} else {
proto_tree_add_text(subtree2, p - pd + i + aoff, 2,
"Aggregator AS: %u",
@ -523,13 +559,14 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
p[i + aoff + 2]);
ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3, 1,
"Next hop network address (%d bytes)",
p[i + aoff + 3]);
"Next hop network address (%d %s)",
p[i + aoff + 3], (p[i + aoff + 3] == 1) ? "byte" :
"bytes");
if (af == AFNUM_INET || af == AFNUM_INET6) {
int j, advance;
const char *s;
subtree3 = proto_item_add_subtree(ti, ETT_BGP);
subtree3 = proto_item_add_subtree(ti, ETT_BGP_MP_REACH_NLRI);
j = 0;
while (j < p[i + aoff + 3]) {
@ -563,24 +600,25 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
"Subnetwork points of attachment: %u", snpa);
off++;
if (snpa)
subtree3 = proto_item_add_subtree(ti, ETT_BGP);
subtree3 = proto_item_add_subtree(ti, ETT_BGP_MP_REACH_NLRI);
for (/*nothing*/; snpa > 0; snpa--) {
proto_tree_add_text(subtree3, p - pd + i + aoff + off, 1,
"SNPA length: ", p[i + aoff + off]);
off++;
proto_tree_add_text(subtree3, p - pd + i + aoff + off,
p[i + aoff + off - 1],
"SNPA (%u bytes)", p[i + aoff + off - 1]);
"SNPA (%u %s)", p[i + aoff + off - 1],
(p[i + aoff + off - 1] == 1) ? "byte" : "bytes");
off += p[i + aoff + off - 1];
}
alen -= off;
aoff += off;
ti = proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Network Layer Reachability Information (%u bytes)",
alen);
"Network Layer Reachability Information (%u %s)",
alen, (alen == 1) ? "byte" : "bytes");
if (alen)
subtree3 = proto_item_add_subtree(ti, ETT_BGP);
subtree3 = proto_item_add_subtree(ti, ETT_BGP_MP_UNREACH_NLRI);
while (alen > 0) {
int advance;
char buf[256];
@ -616,12 +654,13 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
p[i + aoff + 2] >= 128 ? "Vendor specific" : "Unknown"),
p[i + aoff + 2]);
ti = proto_tree_add_text(subtree2, p - pd + i + aoff + 3,
alen - 3, "Withdrawn Routes (%u bytes)", alen - 3);
alen - 3, "Withdrawn Routes (%u %s)", alen - 3,
(alen - 3 == 1) ? "byte" : "bytes");
alen -= 3;
aoff += 3;
if (alen > 0)
subtree3 = proto_item_add_subtree(ti, ETT_BGP);
subtree3 = proto_item_add_subtree(ti, ETT_BGP_MP_UNREACH_NLRI);
while (alen > 0) {
int advance;
char buf[256];
@ -648,19 +687,40 @@ dissect_bgp_update(const u_char *pd, int offset, frame_data *fd,
break;
default:
proto_tree_add_text(subtree2, p - pd + i + aoff, alen,
"Unknown (%d bytes)", alen);
"Unknown (%d %s)", alen, (alen == 1) ? "byte" :
"bytes");
break;
}
i += alen + aoff;
}
}
p += 2 + len;
len = hlen - (p - &pd[offset]);
ti = proto_tree_add_text(tree, p - pd, len,
"Network layer reachability information (%d bytes)", len);
if (len) {
subtree = proto_item_add_subtree(ti, ETT_BGP);
/* --- move --- */
p += 2 + len;
/* NLRI */
len = hlen - (p - &pd[offset]);
ti = proto_tree_add_text(tree, p - pd, len,
"Network layer reachability information: %u %s", len,
(len == 1) ? "byte" : "bytes");
if (len > 0) {
subtree = proto_item_add_subtree(ti, ETT_BGP_NLRI);
/* parse prefixes */
end = p + len;
while (p < end) {
memset(&prefix, 0, sizeof(prefix));
/* snarf length */
length = *p;
i = convert_prefix(length);
p++;
/* snarf prefix */
memcpy(&prefix, p, i);
proto_tree_add_text(subtree, p - pd - 1, i + 1, "%s/%d",
inet_ntoa(prefix), length);
p += i;
}
}
}
}

View File

@ -1,7 +1,7 @@
/* packet-bgp.c
* Definitions for BGP packet disassembly structures and routine
*
* $Id: packet-bgp.h,v 1.3 1999/11/06 01:28:50 itojun Exp $
* $Id: packet-bgp.h,v 1.4 1999/11/11 21:08:52 itojun Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@unicom.net>
@ -25,9 +25,6 @@
#ifndef __PACKET_BGP_H__
#define __PACKET_BGP_H__
#include "packet.h"
#include "packet-ipv6.h"
/* some handy things to know */
#define BGP_MAX_PACKET_SIZE 4096
#define BGP_MARKER_SIZE 16
@ -75,6 +72,16 @@ struct bgp_attr {
guint8 bgpa_type;
};
/* attribute flags, from RFC 1771 */
#define BGP_ATTR_FLAG_OPTIONAL 0x80
#define BGP_ATTR_FLAG_TRANSITIVE 0x40
#define BGP_ATTR_FLAG_PARTIAL 0x20
#define BGP_ATTR_FLAG_EXTENDED_LENGTH 0x10
/* AS_PATH segment types, from RFC 1771 */
#define AS_SET 1
#define AS_SEQUENCE 2
#define BGPTYPE_ORIGIN 1 /* RFC1771 */
#define BGPTYPE_AS_PATH 2 /* RFC1771 */
#define BGPTYPE_NEXT_HOP 3 /* RFC1771 */
@ -118,4 +125,9 @@ do { \
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
#endif
/*
* Convert prefix length into number of guint8s needed for prefix.
*/
#define convert_prefix(p) (((p) + 7) / (8))
#endif

View File

@ -1,7 +1,7 @@
/* packet.h
* Definitions for packet disassembly structures and routines
*
* $Id: packet.h,v 1.134 1999/11/11 08:35:10 guy Exp $
* $Id: packet.h,v 1.135 1999/11/11 21:08:52 itojun Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -285,7 +285,11 @@ enum {
ETT_BGP_NOTIFICATION,
ETT_BGP_ATTRS,
ETT_BGP_ATTR,
ETT_BGP_ATTR_FLAGS,
ETT_BGP_UNFEAS,
ETT_BGP_NLRI,
ETT_BGP_MP_REACH_NLRI,
ETT_BGP_MP_UNREACH_NLRI,
ETT_CLNP,
ETT_COTP,
ETT_VINES_FRP,