From 8581e12a124f91c3b45f2ff0e772b34cf491dbd9 Mon Sep 17 00:00:00 2001 From: sthen Date: Mon, 7 Sep 2009 12:25:36 +0000 Subject: Teach the printer about capabilities, new cease codes, end-of-rib marker, and handle 32-bit ASN. ok claudio@ --- usr.sbin/tcpdump/print-bgp.c | 378 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 324 insertions(+), 54 deletions(-) (limited to 'usr.sbin/tcpdump/print-bgp.c') diff --git a/usr.sbin/tcpdump/print-bgp.c b/usr.sbin/tcpdump/print-bgp.c index 55fdf30cc09..9bfb1789839 100644 --- a/usr.sbin/tcpdump/print-bgp.c +++ b/usr.sbin/tcpdump/print-bgp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: print-bgp.c,v 1.11 2009/01/29 09:46:32 bluhm Exp $ */ +/* $OpenBSD: print-bgp.c,v 1.12 2009/09/07 12:25:36 sthen Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -31,7 +31,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Id: print-bgp.c,v 1.11 2009/01/29 09:46:32 bluhm Exp $"; + "@(#) $Id: print-bgp.c,v 1.12 2009/09/07 12:25:36 sthen Exp $"; #endif #include @@ -62,6 +62,7 @@ struct bgp { #define BGP_UPDATE 2 #define BGP_NOTIFICATION 3 #define BGP_KEEPALIVE 4 +#define BGP_ROUTE_REFRESH 5 struct bgp_open { u_int8_t bgpo_marker[16]; @@ -81,8 +82,11 @@ struct bgp_opt { u_int8_t bgpopt_len; /* variable length */ }; +#define BGP_OPT_CAP 2 #define BGP_OPT_SIZE 2 /* some compilers may pad to 4 bytes */ +#define BGP_UPDATE_MINSIZE 23 + struct bgp_notification { u_int8_t bgpn_marker[16]; u_int16_t bgpn_len; @@ -93,6 +97,16 @@ struct bgp_notification { }; #define BGP_NOTIFICATION_SIZE 21 /* unaligned */ +struct bgp_route_refresh { + u_int8_t bgp_marker[16]; + u_int16_t len; + u_int8_t type; + u_int8_t afi[2]; /* unaligned; should be u_int16_t */ + u_int8_t res; + u_int8_t safi; +}; +#define BGP_ROUTE_REFRESH_SIZE 23 + struct bgp_attr { u_int8_t bgpa_flags; u_int8_t bgpa_type; @@ -122,11 +136,35 @@ struct bgp_attr { #define BGPTYPE_RCID_PATH 13 /* RFC1863 */ #define BGPTYPE_MP_REACH_NLRI 14 /* RFC2283 */ #define BGPTYPE_MP_UNREACH_NLRI 15 /* RFC2283 */ +#define BGPTYPE_EXTD_COMMUNITIES 16 /* RFC4360 */ +#define BGPTYPE_AS4_PATH 17 /* RFC4893 */ +#define BGPTYPE_AGGREGATOR4 18 /* RFC4893 */ + +#define BGP_AS_SET 1 +#define BGP_AS_SEQUENCE 2 +#define BGP_CONFED_AS_SEQUENCE 3 /* draft-ietf-idr-rfc3065bis-01 */ +#define BGP_CONFED_AS_SET 4 /* draft-ietf-idr-rfc3065bis-01 */ + +static struct tok bgp_as_path_segment_open_values[] = { + { BGP_AS_SET, " {" }, + { BGP_AS_SEQUENCE, " " }, + { BGP_CONFED_AS_SEQUENCE, " (" }, + { BGP_CONFED_AS_SET, " ({" }, + { 0, NULL}, +}; + +static struct tok bgp_as_path_segment_close_values[] = { + { BGP_AS_SET, "}" }, + { BGP_AS_SEQUENCE, "" }, + { BGP_CONFED_AS_SEQUENCE, ")" }, + { BGP_CONFED_AS_SET, "})" }, + { 0, NULL}, +}; #define BGP_MP_NLRI_MINSIZE 3 static const char *bgptype[] = { - NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE", + NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE", "ROUTE-REFRESH", }; #define bgp_type(x) num_or_str(bgptype, sizeof(bgptype)/sizeof(bgptype[0]), (x)) @@ -136,29 +174,53 @@ static const char *bgpopt_type[] = { #define bgp_opttype(x) \ num_or_str(bgpopt_type, sizeof(bgpopt_type)/sizeof(bgpopt_type[0]), (x)) +#define BGP_CAPCODE_MP 1 +#define BGP_CAPCODE_RESTART 64 /* draft-ietf-idr-restart-05 */ +#define BGP_CAPCODE_AS4 65 /* RFC4893 */ + +static const char *bgp_capcode[] = { + NULL, "MULTI_PROTOCOL", "ROUTE_REFRESH", + /* 3: RFC5291 */ "OUTBOUND_ROUTE_FILTERING", + /* 4: RFC3107 */ "MULTIPLE_ROUTES", + /* 5: RFC5549 */ "EXTENDED_NEXTHOP_ENCODING", + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 64: RFC4724 */ "GRACEFUL_RESTART", + /* 65: RFC4893 */ "AS4", 0, + /* 67: [Chen] */ "DYNAMIC_CAPABILITY", + /* 68: [Appanna] */ "MULTISESSION", + /* 69: [draft-ietf-idr-add-paths] */ "ADD-PATH", +}; + +#define bgp_capcode(x) \ + num_or_str(bgp_capcode, sizeof(bgp_capcode)/sizeof(bgp_capcode[0]), (x)) + +#define BGP_NOTIFY_MAJOR_CEASE 6 static const char *bgpnotify_major[] = { NULL, "Message Header Error", "OPEN Message Error", "UPDATE Message Error", "Hold Timer Expired", "Finite State Machine Error", - "Cease", + "Cease", "Capability Message Error", }; #define bgp_notify_major(x) \ num_or_str(bgpnotify_major, \ sizeof(bgpnotify_major)/sizeof(bgpnotify_major[0]), (x)) -static const char *bgpnotify_minor_1[] = { +static const char *bgpnotify_minor_msg[] = { NULL, "Connection Not Synchronized", "Bad Message Length", "Bad Message Type", }; -static const char *bgpnotify_minor_2[] = { +static const char *bgpnotify_minor_open[] = { NULL, "Unsupported Version Number", "Bad Peer AS", "Bad BGP Identifier", "Unsupported Optional Parameter", "Authentication Failure", - "Unacceptable Hold Time", + "Unacceptable Hold Time", "Unsupported Capability", }; -static const char *bgpnotify_minor_3[] = { +static const char *bgpnotify_minor_update[] = { NULL, "Malformed Attribute List", "Unrecognized Well-known Attribute", "Missing Well-known Attribute", "Attribute Flags Error", "Attribute Length Error", @@ -167,13 +229,32 @@ static const char *bgpnotify_minor_3[] = { "Invalid Network Field", "Malformed AS_PATH", }; +/* RFC 4486 */ +#define BGP_NOTIFY_MINOR_CEASE_MAXPRFX 1 +static const char *bgpnotify_minor_cease[] = { + NULL, "Maximum Number of Prefixes Reached", "Administratively Shutdown", + "Peer De-configured", "Administratively Reset", "Connection Rejected", + "Other Configuration Change", "Connection Collision Resolution", + "Out of Resources", +}; + +static const char *bgpnotify_minor_cap[] = { + NULL, "Invalid Action Value", "Invalid Capability Length", + "Malformed Capability Value", "Unsupported Capability Code", +}; + static const char **bgpnotify_minor[] = { - NULL, bgpnotify_minor_1, bgpnotify_minor_2, bgpnotify_minor_3, + NULL, bgpnotify_minor_msg, bgpnotify_minor_open, bgpnotify_minor_update, }; static const int bgpnotify_minor_siz[] = { - 0, sizeof(bgpnotify_minor_1)/sizeof(bgpnotify_minor_1[0]), - sizeof(bgpnotify_minor_2)/sizeof(bgpnotify_minor_2[0]), - sizeof(bgpnotify_minor_3)/sizeof(bgpnotify_minor_3[0]), + 0, + sizeof(bgpnotify_minor_msg)/sizeof(bgpnotify_minor_msg[0]), + sizeof(bgpnotify_minor_open)/sizeof(bgpnotify_minor_open[0]), + sizeof(bgpnotify_minor_update)/sizeof(bgpnotify_minor_update[0]), + 0, + 0, + sizeof(bgpnotify_minor_cease)/sizeof(bgpnotify_minor_cease[0]), + sizeof(bgpnotify_minor_cap)/sizeof(bgpnotify_minor_cap[0]), }; static const char *bgpattr_origin[] = { @@ -188,6 +269,7 @@ static const char *bgpattr_type[] = { "MULTI_EXIT_DISC", "LOCAL_PREF", "ATOMIC_AGGREGATE", "AGGREGATOR", "COMMUNITIES", "ORIGINATOR_ID", "CLUSTER_LIST", "DPA", "ADVERTISERS", "RCID_PATH", "MP_REACH_NLRI", "MP_UNREACH_NLRI", + "EXTD_COMMUNITIES", "AS4_PATH", "AGGREGATOR4", }; #define bgp_attr_type(x) \ num_or_str(bgpattr_type, \ @@ -196,6 +278,13 @@ static const char *bgpattr_type[] = { /* Subsequent address family identifier, RFC2283 section 7 */ static const char *bgpattr_nlri_safi[] = { "Reserved", "Unicast", "Multicast", "Unicast+Multicast", + "labeled Unicast", /* MPLS BGP RFC3107 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 64-66: MPLS BGP RFC3107 */ + "Tunnel", "VPLS", "MDT", }; #define bgp_attr_nlri_safi(x) \ num_or_str(bgpattr_nlri_safi, \ @@ -263,6 +352,7 @@ decode_prefix4(const u_char *pd, char *buf, u_int buflen) * prefix length is in bits; packet only contains * enough bytes of address to contain this many bits */ + plen = pd[0]; if (plen < 0 || 32 < plen) return -1; memset(&addr, 0, sizeof(addr)); @@ -321,11 +411,13 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len) u_int16_t af; u_int8_t safi, snpa; int advance; - int tlen; + int tlen, asn_bytes; const u_char *p; char buf[MAXHOSTNAMELEN + 100]; p = dat; + tlen = len; + asn_bytes = 0; switch (attr->bgpa_type) { case BGPTYPE_ORIGIN: @@ -336,7 +428,18 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len) printf(" %s", bgp_attr_origin(p[0])); } break; + case BGPTYPE_AS4_PATH: + asn_bytes = 4; + /* FALLTHROUGH */ case BGPTYPE_AS_PATH: + /* + * 2-byte speakers will receive AS4_PATH as well AS_PATH (2-byte). + * 4-byte speakers will only receive AS_PATH but it will be 4-byte. + * To identify which is the case, compare the length of the path + * segment value in bytes, with the path segment length from the + * message (counted in # of AS) + */ + if (len % 2) { printf(" invalid len"); break; @@ -346,28 +449,31 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len) break; } while (p < dat + len) { - /* - * under RFC1965, p[0] means: - * 1: AS_SET 2: AS_SEQUENCE - * 3: AS_CONFED_SET 4: AS_CONFED_SEQUENCE - */ - printf(" "); - TCHECK(p[1]); - if (p[0] == 3 || p[0] == 4) - printf("confed"); - printf("%s", (p[0] & 1) ? "{" : ""); - for (i = 0; i < p[1] * 2; i += 2) { - TCHECK2(p[2 + i], 2); /* ASN is 2-bytes */ - printf("%s%u", i == 0 ? "" : " ", - EXTRACT_16BITS(&p[2 + i])); + TCHECK(p[0]); + if (asn_bytes == 0) { + asn_bytes = (len-2)/p[1]; } - printf("%s", (p[0] & 1) ? "}" : ""); - /* - * 1 byte for attr type, 1 byte for path length, - * plus size of ASN (2-bytes for now) * no of ASN - * - */ - p += 2 + p[1] * 2; + printf("%s", + tok2str(bgp_as_path_segment_open_values, + "?", p[0])); + + for (i = 0; i < p[1] * asn_bytes; i += asn_bytes) { + TCHECK2(p[2 + i], asn_bytes); + printf("%s", i == 0 ? "" : " "); + if (asn_bytes == 2 || EXTRACT_16BITS(&p[2 + i])) + printf("%u%s", + EXTRACT_16BITS(&p[2 + i]), + asn_bytes == 4 ? "." : ""); + if (asn_bytes == 4) + printf("%u", + EXTRACT_16BITS(&p[2 + i + 2])); + } + TCHECK(p[0]); + printf("%s", + tok2str(bgp_as_path_segment_close_values, + "?", p[0])); + TCHECK(p[1]); + p += 2 + p[1] * asn_bytes; } break; case BGPTYPE_NEXT_HOP: @@ -391,24 +497,34 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len) if (len != 0) printf(" invalid len"); break; + case BGPTYPE_AGGREGATOR4: case BGPTYPE_AGGREGATOR: - if (len != 6) { + /* + * like AS_PATH/AS4_PATH, AGGREGATOR can contain + * either 2-byte or 4-byte ASN, and AGGREGATOR4 + * always contains 4-byte ASN. + */ + if (len != 6 && len != 8) { printf(" invalid len"); break; } - TCHECK2(p[0], 6); - printf(" AS #%u, origin %s", EXTRACT_16BITS(p), - getname(p + 2)); + TCHECK2(p[0], len); + printf(" AS #"); + if (len == 6 || EXTRACT_16BITS(p)) + printf("%u%s", EXTRACT_16BITS(p), len == 8 ? "." : ""); + if (len == 8) + printf("%u", EXTRACT_16BITS(p+2)); + printf(", origin %s", getname(p+len-4)); break; case BGPTYPE_COMMUNITIES: if (len % 4) { printf(" invalid len"); break; } - for (i = 0; i < len; i += 4) { + while (tlen>0) { u_int32_t comm; - TCHECK2(p[i], 4); - comm = EXTRACT_32BITS(&p[i]); + TCHECK2(p[0], 4); + comm = EXTRACT_32BITS(p); switch (comm) { case BGP_COMMUNITY_NO_EXPORT: printf(" NO_EXPORT"); @@ -427,6 +543,30 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len) (comm >> 16) & 0xffff, comm & 0xffff); break; } + tlen -= 4; + p += 4; + } + break; + case BGPTYPE_ORIGINATOR_ID: + if (len != 4) { + printf(" invalid len"); + break; + } + TCHECK2(p[0], 4); + printf("%s",getname(p)); + break; + case BGPTYPE_CLUSTER_LIST: + if (len % 4) { + printf(" invalid len"); + break; + } + while (tlen>0) { + TCHECK2(p[0], 4); + printf(" %s%s", + getname(p), + (tlen>4) ? ", " : ""); + tlen -=4; + p +=4; } break; case BGPTYPE_MP_REACH_NLRI: @@ -434,7 +574,7 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len) af = EXTRACT_16BITS(p); safi = p[2]; if (safi >= 128) - printf(" %s vendor specific,", af_name(af)); + printf(" %s vendor specific %u,", af_name(af), safi); else { printf(" %s %s,", af_name(af), bgp_attr_nlri_safi(safi)); @@ -524,7 +664,7 @@ bgp_attr_print(const struct bgp_attr *attr, const u_char *dat, int len) af = EXTRACT_16BITS(p); safi = p[2]; if (safi >= 128) - printf(" %s vendor specific,", af_name(af)); + printf(" %s vendor specific %u,", af_name(af), safi); else { printf(" %s %s,", af_name(af), bgp_attr_nlri_safi(safi)); @@ -571,7 +711,7 @@ bgp_open_print(const u_char *dat, int length) struct bgp_open bgpo; struct bgp_opt bgpopt; const u_char *opt; - int i; + int i,cap_type,cap_len,tcap_len,cap_offset; TCHECK2(dat[0], BGP_OPEN_SIZE); memcpy(&bgpo, dat, BGP_OPEN_SIZE); @@ -582,6 +722,10 @@ bgp_open_print(const u_char *dat, int length) printf(" ID %s,", getname((u_char *)&bgpo.bgpo_id)); printf(" Option length %u", bgpo.bgpo_optlen); + /* sanity checking */ + if ((length < bgpo.bgpo_optlen+BGP_OPEN_SIZE) || (!bgpo.bgpo_optlen)) + return; + /* ugly! */ opt = &((const struct bgp_open *)dat)->bgpo_optlen; opt++; @@ -595,10 +739,71 @@ bgp_open_print(const u_char *dat, int length) break; } - printf(" (option %s, len=%d)", bgp_opttype(bgpopt.bgpopt_type), - bgpopt.bgpopt_len); + if (i == 0) + printf(" ("); /* ) */ + else + printf(" "); + + switch(bgpopt.bgpopt_type) { + case BGP_OPT_CAP: + cap_type=opt[i+BGP_OPT_SIZE]; + cap_len=opt[i+BGP_OPT_SIZE+1]; + tcap_len=cap_len; + printf("(CAP %s", /* ) */ + bgp_capcode(cap_type)); + + switch(cap_type) { + case BGP_CAPCODE_MP: + printf(" [%s %s]", + af_name(EXTRACT_16BITS(opt+i+BGP_OPT_SIZE+2)), + bgp_attr_nlri_safi(opt[i+BGP_OPT_SIZE+5])); + break; + case BGP_CAPCODE_RESTART: + printf(" [%s], Time %us", + ((opt[i+BGP_OPT_SIZE+2])&0x80) ? "R" : "none", + EXTRACT_16BITS(opt+i+BGP_OPT_SIZE+2)&0xfff); + tcap_len-=2; + cap_offset=4; + while(tcap_len>=4) { + printf(" (%s %s)%s", + af_name(EXTRACT_16BITS( + opt+i+BGP_OPT_SIZE+cap_offset)), + bgp_attr_nlri_safi( + opt[i+BGP_OPT_SIZE+cap_offset+2]), + ((opt[i+BGP_OPT_SIZE+cap_offset+3])&0x80) ? + " forwarding state preserved" : "" ); + tcap_len-=4; + cap_offset+=4; + } + break; + case BGP_CAPCODE_AS4: + printf(" #"); + if (EXTRACT_16BITS(opt+i+BGP_OPT_SIZE+2)) + printf("%u.", + EXTRACT_16BITS(opt+i+BGP_OPT_SIZE+2)); + printf("%u", + EXTRACT_16BITS(opt+i+BGP_OPT_SIZE+4)); + break; + default: + break; + } + if (vflag > 1) { + TCHECK2(opt[i+BGP_OPT_SIZE+2],cap_len); + } + /* ( */ + printf(")"); + break; + default: + printf(" (option %s, len=%u)", + bgp_opttype(bgpopt.bgpopt_type), + bgpopt.bgpopt_len); + break; + } + i += BGP_OPT_SIZE + bgpopt.bgpopt_len; } + /* ( */ + printf(")"); return; trunc: printf("[|BGP]"); @@ -640,12 +845,11 @@ bgp_update_print(const u_char *dat, int length) while(i < 2 + len) { wpfx = decode_prefix4(&p[i], buf, sizeof(buf)); - if (wpfx == -2) - goto trunc; - else if (wpfx < 0) { + if (wpfx = -1) { printf(" (illegal prefix length)"); break; - } + } else if (wpfx == -2) + goto trunc; i += wpfx; printf(" %s", buf); } @@ -657,6 +861,11 @@ bgp_update_print(const u_char *dat, int length) TCHECK2(p[0], 2); len = EXTRACT_16BITS(p); + if (len == 0 && length == BGP_UPDATE_MINSIZE) { + printf(" End-of-Rib Marker (empty NLRI)"); + return; + } + if (len) { /* do something more useful!*/ i = 2; @@ -709,12 +918,11 @@ bgp_update_print(const u_char *dat, int length) while (dat + length > p) { char buf[MAXHOSTNAMELEN + 100]; i = decode_prefix4(p, buf, sizeof(buf)); - if (i == -2) - goto trunc; - else if (i < 0) { + if (i == -1) { printf(" (illegal prefix length)"); break; - } + } else if (i == -2) + goto trunc; printf(" %s", buf); p += i; } @@ -731,13 +939,63 @@ static void bgp_notification_print(const u_char *dat, int length) { struct bgp_notification bgpn; + u_int16_t af; + u_int8_t safi; + const u_char *p; TCHECK2(dat[0], BGP_NOTIFICATION_SIZE); memcpy(&bgpn, dat, BGP_NOTIFICATION_SIZE); + /* sanity checking */ + if (length= BGP_NOTIFICATION_SIZE + 7) { + + p = dat + BGP_NOTIFICATION_SIZE; + TCHECK2(*p, 7); + + af = EXTRACT_16BITS(p); + safi = p[2]; + printf(" %s %s,", af_name(af), + bgp_attr_nlri_safi(safi)); + + printf(" Max Prefixes: %u", EXTRACT_32BITS(p+3)); + } + } + + return; +trunc: + printf("[|BGP]"); +} + +static void +bgp_route_refresh_print(const u_char *dat, int length) +{ + const struct bgp_route_refresh *bgp_route_refresh_header; + + TCHECK2(dat[0], BGP_ROUTE_REFRESH_SIZE); + + /* sanity checking */ + if (lengthafi)), + bgp_attr_nlri_safi(bgp_route_refresh_header->safi)); + return; trunc: printf("[|BGP]"); @@ -762,6 +1020,13 @@ bgp_header_print(const u_char *dat, int length) case BGP_NOTIFICATION: bgp_notification_print(dat, length); break; + case BGP_KEEPALIVE: + break; + case BGP_ROUTE_REFRESH: + bgp_route_refresh_print(dat, length); + default: + TCHECK2(*dat, length); + break; } /* ( */ @@ -822,6 +1087,11 @@ bgp_print(const u_char *dat, int length) printf("\n\t"); else printf(" "); + if (hlen < BGP_SIZE) { + printf("\n[|BGP Bogus header length %u < %u]", + hlen, BGP_SIZE); + break; + } if (TTEST2(p[0], hlen)) { if (!bgp_header_print(p, hlen)) return; -- cgit v1.2.3-59-g8ed1b