10f74e101Schristos /* 20f74e101Schristos * Copyright (C) 1999 WIDE Project. 30f74e101Schristos * All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that the following conditions 70f74e101Schristos * are met: 80f74e101Schristos * 1. Redistributions of source code must retain the above copyright 90f74e101Schristos * notice, this list of conditions and the following disclaimer. 100f74e101Schristos * 2. Redistributions in binary form must reproduce the above copyright 110f74e101Schristos * notice, this list of conditions and the following disclaimer in the 120f74e101Schristos * documentation and/or other materials provided with the distribution. 130f74e101Schristos * 3. Neither the name of the project nor the names of its contributors 140f74e101Schristos * may be used to endorse or promote products derived from this software 150f74e101Schristos * without specific prior written permission. 160f74e101Schristos * 170f74e101Schristos * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 180f74e101Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 190f74e101Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 200f74e101Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 210f74e101Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 220f74e101Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 230f74e101Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 240f74e101Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 250f74e101Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 260f74e101Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 270f74e101Schristos * SUCH DAMAGE. 280f74e101Schristos * 2972c96ff3Schristos * Extensively modified by Hannes Gredler (hannes@gredler.at) for more 300f74e101Schristos * complete BGP support. 310f74e101Schristos */ 320f74e101Schristos 3311b3aaa1Schristos #include <sys/cdefs.h> 340f74e101Schristos #ifndef lint 35*26ba0b50Schristos __RCSID("$NetBSD: print-bgp.c,v 1.13 2024/09/02 16:15:30 christos Exp $"); 3611b3aaa1Schristos #endif 37b3a00663Schristos 38dc860a36Sspz /* \summary: Border Gateway Protocol (BGP) printer */ 39dc860a36Sspz 40c74ad251Schristos /* specification: RFC 4271 */ 41c74ad251Schristos 42c74ad251Schristos #include <config.h> 430f74e101Schristos 44c74ad251Schristos #include "netdissect-stdinc.h" 450f74e101Schristos 460f74e101Schristos #include <stdio.h> 470f74e101Schristos #include <string.h> 480f74e101Schristos 49fdccd7e4Schristos #include "netdissect.h" 500f74e101Schristos #include "addrtoname.h" 510f74e101Schristos #include "extract.h" 520f74e101Schristos #include "af.h" 530f74e101Schristos #include "l2vpn.h" 540f74e101Schristos 550f74e101Schristos struct bgp { 56c74ad251Schristos nd_byte bgp_marker[16]; 57c74ad251Schristos nd_uint16_t bgp_len; 58c74ad251Schristos nd_uint8_t bgp_type; 590f74e101Schristos }; 600f74e101Schristos #define BGP_SIZE 19 /* unaligned */ 610f74e101Schristos 620f74e101Schristos #define BGP_OPEN 1 630f74e101Schristos #define BGP_UPDATE 2 640f74e101Schristos #define BGP_NOTIFICATION 3 650f74e101Schristos #define BGP_KEEPALIVE 4 660f74e101Schristos #define BGP_ROUTE_REFRESH 5 670f74e101Schristos 68870189d2Schristos static const struct tok bgp_msg_values[] = { 690f74e101Schristos { BGP_OPEN, "Open"}, 700f74e101Schristos { BGP_UPDATE, "Update"}, 710f74e101Schristos { BGP_NOTIFICATION, "Notification"}, 720f74e101Schristos { BGP_KEEPALIVE, "Keepalive"}, 730f74e101Schristos { BGP_ROUTE_REFRESH, "Route Refresh"}, 740f74e101Schristos { 0, NULL} 750f74e101Schristos }; 760f74e101Schristos 770f74e101Schristos struct bgp_open { 78c74ad251Schristos nd_byte bgpo_marker[16]; 79c74ad251Schristos nd_uint16_t bgpo_len; 80c74ad251Schristos nd_uint8_t bgpo_type; 81c74ad251Schristos nd_uint8_t bgpo_version; 82c74ad251Schristos nd_uint16_t bgpo_myas; 83c74ad251Schristos nd_uint16_t bgpo_holdtime; 84c74ad251Schristos nd_uint32_t bgpo_id; 85c74ad251Schristos nd_uint8_t bgpo_optlen; 860f74e101Schristos /* options should follow */ 870f74e101Schristos }; 880f74e101Schristos #define BGP_OPEN_SIZE 29 /* unaligned */ 890f74e101Schristos 900f74e101Schristos struct bgp_opt { 91c74ad251Schristos nd_uint8_t bgpopt_type; 92c74ad251Schristos nd_uint8_t bgpopt_len; 930f74e101Schristos /* variable length */ 940f74e101Schristos }; 950f74e101Schristos #define BGP_OPT_SIZE 2 /* some compilers may pad to 4 bytes */ 960e9868baSchristos #define BGP_CAP_HEADER_SIZE 2 /* some compilers may pad to 4 bytes */ 970f74e101Schristos 980f74e101Schristos struct bgp_notification { 99c74ad251Schristos nd_byte bgpn_marker[16]; 100c74ad251Schristos nd_uint16_t bgpn_len; 101c74ad251Schristos nd_uint8_t bgpn_type; 102c74ad251Schristos nd_uint8_t bgpn_major; 103c74ad251Schristos nd_uint8_t bgpn_minor; 1040f74e101Schristos }; 1050f74e101Schristos #define BGP_NOTIFICATION_SIZE 21 /* unaligned */ 1060f74e101Schristos 1070f74e101Schristos struct bgp_route_refresh { 108c74ad251Schristos nd_byte bgp_marker[16]; 109c74ad251Schristos nd_uint16_t len; 110c74ad251Schristos nd_uint8_t type; /* No padding after this; afi is, in fact, not aligned */ 111c74ad251Schristos nd_uint16_t afi; 112c74ad251Schristos nd_uint8_t res; 113c74ad251Schristos nd_uint8_t safi; 114c74ad251Schristos }; 1150f74e101Schristos #define BGP_ROUTE_REFRESH_SIZE 23 1160f74e101Schristos 1170e9868baSchristos #define bgp_attr_lenlen(flags, p) \ 118c74ad251Schristos (((flags) & 0x10) ? 2U : 1U) 1190e9868baSchristos #define bgp_attr_len(flags, p) \ 120c74ad251Schristos (((flags) & 0x10) ? GET_BE_U_2(p) : GET_U_1(p)) 1210f74e101Schristos 1220f74e101Schristos #define BGPTYPE_ORIGIN 1 1230f74e101Schristos #define BGPTYPE_AS_PATH 2 1240f74e101Schristos #define BGPTYPE_NEXT_HOP 3 1250f74e101Schristos #define BGPTYPE_MULTI_EXIT_DISC 4 1260f74e101Schristos #define BGPTYPE_LOCAL_PREF 5 1270f74e101Schristos #define BGPTYPE_ATOMIC_AGGREGATE 6 1280f74e101Schristos #define BGPTYPE_AGGREGATOR 7 1290f74e101Schristos #define BGPTYPE_COMMUNITIES 8 /* RFC1997 */ 130dc860a36Sspz #define BGPTYPE_ORIGINATOR_ID 9 /* RFC4456 */ 131dc860a36Sspz #define BGPTYPE_CLUSTER_LIST 10 /* RFC4456 */ 132dc860a36Sspz #define BGPTYPE_DPA 11 /* deprecated, draft-ietf-idr-bgp-dpa */ 133dc860a36Sspz #define BGPTYPE_ADVERTISERS 12 /* deprecated RFC1863 */ 134dc860a36Sspz #define BGPTYPE_RCID_PATH 13 /* deprecated RFC1863 */ 135dc860a36Sspz #define BGPTYPE_MP_REACH_NLRI 14 /* RFC4760 */ 136dc860a36Sspz #define BGPTYPE_MP_UNREACH_NLRI 15 /* RFC4760 */ 137dc860a36Sspz #define BGPTYPE_EXTD_COMMUNITIES 16 /* RFC4360 */ 138dc860a36Sspz #define BGPTYPE_AS4_PATH 17 /* RFC6793 */ 139dc860a36Sspz #define BGPTYPE_AGGREGATOR4 18 /* RFC6793 */ 140dc860a36Sspz #define BGPTYPE_PMSI_TUNNEL 22 /* RFC6514 */ 141dc860a36Sspz #define BGPTYPE_TUNNEL_ENCAP 23 /* RFC5512 */ 142dc860a36Sspz #define BGPTYPE_TRAFFIC_ENG 24 /* RFC5543 */ 143dc860a36Sspz #define BGPTYPE_IPV6_EXTD_COMMUNITIES 25 /* RFC5701 */ 144fdccd7e4Schristos #define BGPTYPE_AIGP 26 /* RFC7311 */ 145dc860a36Sspz #define BGPTYPE_PE_DISTINGUISHER_LABEL 27 /* RFC6514 */ 146dc860a36Sspz #define BGPTYPE_ENTROPY_LABEL 28 /* RFC6790 */ 147dc860a36Sspz #define BGPTYPE_LARGE_COMMUNITY 32 /* draft-ietf-idr-large-community-05 */ 148dc860a36Sspz #define BGPTYPE_ATTR_SET 128 /* RFC6368 */ 1490f74e101Schristos 1500f74e101Schristos #define BGP_MP_NLRI_MINSIZE 3 /* End of RIB Marker detection */ 1510f74e101Schristos 152870189d2Schristos static const struct tok bgp_attr_values[] = { 1530f74e101Schristos { BGPTYPE_ORIGIN, "Origin"}, 1540f74e101Schristos { BGPTYPE_AS_PATH, "AS Path"}, 1550f74e101Schristos { BGPTYPE_AS4_PATH, "AS4 Path"}, 1560f74e101Schristos { BGPTYPE_NEXT_HOP, "Next Hop"}, 1570f74e101Schristos { BGPTYPE_MULTI_EXIT_DISC, "Multi Exit Discriminator"}, 1580f74e101Schristos { BGPTYPE_LOCAL_PREF, "Local Preference"}, 1590f74e101Schristos { BGPTYPE_ATOMIC_AGGREGATE, "Atomic Aggregate"}, 1600f74e101Schristos { BGPTYPE_AGGREGATOR, "Aggregator"}, 1610f74e101Schristos { BGPTYPE_AGGREGATOR4, "Aggregator4"}, 1620f74e101Schristos { BGPTYPE_COMMUNITIES, "Community"}, 1630f74e101Schristos { BGPTYPE_ORIGINATOR_ID, "Originator ID"}, 1640f74e101Schristos { BGPTYPE_CLUSTER_LIST, "Cluster List"}, 1650f74e101Schristos { BGPTYPE_DPA, "DPA"}, 1660f74e101Schristos { BGPTYPE_ADVERTISERS, "Advertisers"}, 1670f74e101Schristos { BGPTYPE_RCID_PATH, "RCID Path / Cluster ID"}, 1680f74e101Schristos { BGPTYPE_MP_REACH_NLRI, "Multi-Protocol Reach NLRI"}, 1690f74e101Schristos { BGPTYPE_MP_UNREACH_NLRI, "Multi-Protocol Unreach NLRI"}, 1700f74e101Schristos { BGPTYPE_EXTD_COMMUNITIES, "Extended Community"}, 1710f74e101Schristos { BGPTYPE_PMSI_TUNNEL, "PMSI Tunnel"}, 172dc860a36Sspz { BGPTYPE_TUNNEL_ENCAP, "Tunnel Encapsulation"}, 173dc860a36Sspz { BGPTYPE_TRAFFIC_ENG, "Traffic Engineering"}, 174dc860a36Sspz { BGPTYPE_IPV6_EXTD_COMMUNITIES, "IPv6 Extended Community"}, 175fdccd7e4Schristos { BGPTYPE_AIGP, "Accumulated IGP Metric"}, 176dc860a36Sspz { BGPTYPE_PE_DISTINGUISHER_LABEL, "PE Distinguisher Label"}, 177dc860a36Sspz { BGPTYPE_ENTROPY_LABEL, "Entropy Label"}, 178dc860a36Sspz { BGPTYPE_LARGE_COMMUNITY, "Large Community"}, 1790f74e101Schristos { BGPTYPE_ATTR_SET, "Attribute Set"}, 1800f74e101Schristos { 255, "Reserved for development"}, 1810f74e101Schristos { 0, NULL} 1820f74e101Schristos }; 1830f74e101Schristos 1840f74e101Schristos #define BGP_AS_SET 1 1850f74e101Schristos #define BGP_AS_SEQUENCE 2 1860f74e101Schristos #define BGP_CONFED_AS_SEQUENCE 3 /* draft-ietf-idr-rfc3065bis-01 */ 1870f74e101Schristos #define BGP_CONFED_AS_SET 4 /* draft-ietf-idr-rfc3065bis-01 */ 1880f74e101Schristos 1890f74e101Schristos #define BGP_AS_SEG_TYPE_MIN BGP_AS_SET 1900f74e101Schristos #define BGP_AS_SEG_TYPE_MAX BGP_CONFED_AS_SET 1910f74e101Schristos 192870189d2Schristos static const struct tok bgp_as_path_segment_open_values[] = { 1930f74e101Schristos { BGP_AS_SEQUENCE, ""}, 1940f74e101Schristos { BGP_AS_SET, "{ "}, 1950f74e101Schristos { BGP_CONFED_AS_SEQUENCE, "( "}, 1960f74e101Schristos { BGP_CONFED_AS_SET, "({ "}, 1970f74e101Schristos { 0, NULL} 1980f74e101Schristos }; 1990f74e101Schristos 200870189d2Schristos static const struct tok bgp_as_path_segment_close_values[] = { 2010f74e101Schristos { BGP_AS_SEQUENCE, ""}, 2020f74e101Schristos { BGP_AS_SET, "}"}, 2030f74e101Schristos { BGP_CONFED_AS_SEQUENCE, ")"}, 2040f74e101Schristos { BGP_CONFED_AS_SET, "})"}, 2050f74e101Schristos { 0, NULL} 2060f74e101Schristos }; 2070f74e101Schristos 2080f74e101Schristos #define BGP_OPT_AUTH 1 2090f74e101Schristos #define BGP_OPT_CAP 2 2100f74e101Schristos 211870189d2Schristos static const struct tok bgp_opt_values[] = { 2120f74e101Schristos { BGP_OPT_AUTH, "Authentication Information"}, 2130f74e101Schristos { BGP_OPT_CAP, "Capabilities Advertisement"}, 2140f74e101Schristos { 0, NULL} 2150f74e101Schristos }; 2160f74e101Schristos 217dc860a36Sspz #define BGP_CAPCODE_MP 1 /* RFC2858 */ 218dc860a36Sspz #define BGP_CAPCODE_RR 2 /* RFC2918 */ 219dc860a36Sspz #define BGP_CAPCODE_ORF 3 /* RFC5291 */ 220dc860a36Sspz #define BGP_CAPCODE_MR 4 /* RFC3107 */ 221dc860a36Sspz #define BGP_CAPCODE_EXT_NH 5 /* RFC5549 */ 222c74ad251Schristos #define BGP_CAPCODE_ML 8 /* RFC8277 */ 223dc860a36Sspz #define BGP_CAPCODE_RESTART 64 /* RFC4724 */ 224dc860a36Sspz #define BGP_CAPCODE_AS_NEW 65 /* RFC6793 */ 225dc860a36Sspz #define BGP_CAPCODE_DYN_CAP 67 /* draft-ietf-idr-dynamic-cap */ 226dc860a36Sspz #define BGP_CAPCODE_MULTISESS 68 /* draft-ietf-idr-bgp-multisession */ 227dc860a36Sspz #define BGP_CAPCODE_ADD_PATH 69 /* RFC7911 */ 228dc860a36Sspz #define BGP_CAPCODE_ENH_RR 70 /* draft-keyur-bgp-enhanced-route-refresh */ 229c74ad251Schristos #define BGP_CAPCODE_LLGR 71 /* draft-uttaro-idr-bgp-persistence-05 */ 2300f74e101Schristos #define BGP_CAPCODE_RR_CISCO 128 2310f74e101Schristos 232870189d2Schristos static const struct tok bgp_capcode_values[] = { 2330f74e101Schristos { BGP_CAPCODE_MP, "Multiprotocol Extensions"}, 2340f74e101Schristos { BGP_CAPCODE_RR, "Route Refresh"}, 2350f74e101Schristos { BGP_CAPCODE_ORF, "Cooperative Route Filtering"}, 236dc860a36Sspz { BGP_CAPCODE_MR, "Multiple Routes to a Destination"}, 237dc860a36Sspz { BGP_CAPCODE_EXT_NH, "Extended Next Hop Encoding"}, 238c74ad251Schristos { BGP_CAPCODE_ML, "Multiple Labels"}, 2390f74e101Schristos { BGP_CAPCODE_RESTART, "Graceful Restart"}, 2400f74e101Schristos { BGP_CAPCODE_AS_NEW, "32-Bit AS Number"}, 2410f74e101Schristos { BGP_CAPCODE_DYN_CAP, "Dynamic Capability"}, 242dc860a36Sspz { BGP_CAPCODE_MULTISESS, "Multisession BGP"}, 243fdccd7e4Schristos { BGP_CAPCODE_ADD_PATH, "Multiple Paths"}, 244dc860a36Sspz { BGP_CAPCODE_ENH_RR, "Enhanced Route Refresh"}, 245c74ad251Schristos { BGP_CAPCODE_LLGR, "Long-lived Graceful Restart"}, 2460f74e101Schristos { BGP_CAPCODE_RR_CISCO, "Route Refresh (Cisco)"}, 2470f74e101Schristos { 0, NULL} 2480f74e101Schristos }; 2490f74e101Schristos 2500f74e101Schristos #define BGP_NOTIFY_MAJOR_MSG 1 2510f74e101Schristos #define BGP_NOTIFY_MAJOR_OPEN 2 2520f74e101Schristos #define BGP_NOTIFY_MAJOR_UPDATE 3 2530f74e101Schristos #define BGP_NOTIFY_MAJOR_HOLDTIME 4 2540f74e101Schristos #define BGP_NOTIFY_MAJOR_FSM 5 2550f74e101Schristos #define BGP_NOTIFY_MAJOR_CEASE 6 2560f74e101Schristos #define BGP_NOTIFY_MAJOR_CAP 7 2570f74e101Schristos 258870189d2Schristos static const struct tok bgp_notify_major_values[] = { 2590f74e101Schristos { BGP_NOTIFY_MAJOR_MSG, "Message Header Error"}, 2600f74e101Schristos { BGP_NOTIFY_MAJOR_OPEN, "OPEN Message Error"}, 2610f74e101Schristos { BGP_NOTIFY_MAJOR_UPDATE, "UPDATE Message Error"}, 2620f74e101Schristos { BGP_NOTIFY_MAJOR_HOLDTIME,"Hold Timer Expired"}, 2630f74e101Schristos { BGP_NOTIFY_MAJOR_FSM, "Finite State Machine Error"}, 2640f74e101Schristos { BGP_NOTIFY_MAJOR_CEASE, "Cease"}, 2650f74e101Schristos { BGP_NOTIFY_MAJOR_CAP, "Capability Message Error"}, 2660f74e101Schristos { 0, NULL} 2670f74e101Schristos }; 2680f74e101Schristos 269c74ad251Schristos /* RFC 4486 */ 2700f74e101Schristos #define BGP_NOTIFY_MINOR_CEASE_MAXPRFX 1 271c74ad251Schristos #define BGP_NOTIFY_MINOR_CEASE_SHUT 2 272c74ad251Schristos #define BGP_NOTIFY_MINOR_CEASE_RESET 4 273870189d2Schristos static const struct tok bgp_notify_minor_cease_values[] = { 2740f74e101Schristos { BGP_NOTIFY_MINOR_CEASE_MAXPRFX, "Maximum Number of Prefixes Reached"}, 275c74ad251Schristos { BGP_NOTIFY_MINOR_CEASE_SHUT, "Administrative Shutdown"}, 2760f74e101Schristos { 3, "Peer Unconfigured"}, 277c74ad251Schristos { BGP_NOTIFY_MINOR_CEASE_RESET, "Administrative Reset"}, 2780f74e101Schristos { 5, "Connection Rejected"}, 2790f74e101Schristos { 6, "Other Configuration Change"}, 2800f74e101Schristos { 7, "Connection Collision Resolution"}, 2810f74e101Schristos { 0, NULL} 2820f74e101Schristos }; 2830f74e101Schristos 284870189d2Schristos static const struct tok bgp_notify_minor_msg_values[] = { 2850f74e101Schristos { 1, "Connection Not Synchronized"}, 2860f74e101Schristos { 2, "Bad Message Length"}, 2870f74e101Schristos { 3, "Bad Message Type"}, 2880f74e101Schristos { 0, NULL} 2890f74e101Schristos }; 2900f74e101Schristos 291870189d2Schristos static const struct tok bgp_notify_minor_open_values[] = { 2920f74e101Schristos { 1, "Unsupported Version Number"}, 2930f74e101Schristos { 2, "Bad Peer AS"}, 2940f74e101Schristos { 3, "Bad BGP Identifier"}, 2950f74e101Schristos { 4, "Unsupported Optional Parameter"}, 2960f74e101Schristos { 5, "Authentication Failure"}, 2970f74e101Schristos { 6, "Unacceptable Hold Time"}, 2980f74e101Schristos { 7, "Capability Message Error"}, 2990f74e101Schristos { 0, NULL} 3000f74e101Schristos }; 3010f74e101Schristos 302870189d2Schristos static const struct tok bgp_notify_minor_update_values[] = { 3030f74e101Schristos { 1, "Malformed Attribute List"}, 3040f74e101Schristos { 2, "Unrecognized Well-known Attribute"}, 3050f74e101Schristos { 3, "Missing Well-known Attribute"}, 3060f74e101Schristos { 4, "Attribute Flags Error"}, 3070f74e101Schristos { 5, "Attribute Length Error"}, 3080f74e101Schristos { 6, "Invalid ORIGIN Attribute"}, 3090f74e101Schristos { 7, "AS Routing Loop"}, 3100f74e101Schristos { 8, "Invalid NEXT_HOP Attribute"}, 3110f74e101Schristos { 9, "Optional Attribute Error"}, 3120f74e101Schristos { 10, "Invalid Network Field"}, 3130f74e101Schristos { 11, "Malformed AS_PATH"}, 3140f74e101Schristos { 0, NULL} 3150f74e101Schristos }; 3160f74e101Schristos 317dc860a36Sspz static const struct tok bgp_notify_minor_fsm_values[] = { 318c74ad251Schristos { 0, "Unspecified Error"}, 319dc860a36Sspz { 1, "In OpenSent State"}, 320dc860a36Sspz { 2, "In OpenConfirm State"}, 321dc860a36Sspz { 3, "In Established State"}, 322dc860a36Sspz { 0, NULL } 323dc860a36Sspz }; 324dc860a36Sspz 325870189d2Schristos static const struct tok bgp_notify_minor_cap_values[] = { 3260f74e101Schristos { 1, "Invalid Action Value" }, 3270f74e101Schristos { 2, "Invalid Capability Length" }, 3280f74e101Schristos { 3, "Malformed Capability Value" }, 3290f74e101Schristos { 4, "Unsupported Capability Code" }, 3300f74e101Schristos { 0, NULL } 3310f74e101Schristos }; 3320f74e101Schristos 333870189d2Schristos static const struct tok bgp_origin_values[] = { 3340f74e101Schristos { 0, "IGP"}, 3350f74e101Schristos { 1, "EGP"}, 3360f74e101Schristos { 2, "Incomplete"}, 3370f74e101Schristos { 0, NULL} 3380f74e101Schristos }; 3390f74e101Schristos 3400f74e101Schristos #define BGP_PMSI_TUNNEL_RSVP_P2MP 1 3410f74e101Schristos #define BGP_PMSI_TUNNEL_LDP_P2MP 2 3420f74e101Schristos #define BGP_PMSI_TUNNEL_PIM_SSM 3 3430f74e101Schristos #define BGP_PMSI_TUNNEL_PIM_SM 4 3440f74e101Schristos #define BGP_PMSI_TUNNEL_PIM_BIDIR 5 3450f74e101Schristos #define BGP_PMSI_TUNNEL_INGRESS 6 3460f74e101Schristos #define BGP_PMSI_TUNNEL_LDP_MP2MP 7 3470f74e101Schristos 348870189d2Schristos static const struct tok bgp_pmsi_tunnel_values[] = { 3490f74e101Schristos { BGP_PMSI_TUNNEL_RSVP_P2MP, "RSVP-TE P2MP LSP"}, 3500f74e101Schristos { BGP_PMSI_TUNNEL_LDP_P2MP, "LDP P2MP LSP"}, 3510f74e101Schristos { BGP_PMSI_TUNNEL_PIM_SSM, "PIM-SSM Tree"}, 3520f74e101Schristos { BGP_PMSI_TUNNEL_PIM_SM, "PIM-SM Tree"}, 3530f74e101Schristos { BGP_PMSI_TUNNEL_PIM_BIDIR, "PIM-Bidir Tree"}, 3540f74e101Schristos { BGP_PMSI_TUNNEL_INGRESS, "Ingress Replication"}, 3550f74e101Schristos { BGP_PMSI_TUNNEL_LDP_MP2MP, "LDP MP2MP LSP"}, 3560f74e101Schristos { 0, NULL} 3570f74e101Schristos }; 3580f74e101Schristos 359870189d2Schristos static const struct tok bgp_pmsi_flag_values[] = { 3600f74e101Schristos { 0x01, "Leaf Information required"}, 3610f74e101Schristos { 0, NULL} 3620f74e101Schristos }; 3630f74e101Schristos 364fdccd7e4Schristos #define BGP_AIGP_TLV 1 365fdccd7e4Schristos 366fdccd7e4Schristos static const struct tok bgp_aigp_values[] = { 367fdccd7e4Schristos { BGP_AIGP_TLV, "AIGP"}, 368fdccd7e4Schristos { 0, NULL} 369fdccd7e4Schristos }; 370fdccd7e4Schristos 3710f74e101Schristos /* Subsequent address family identifier, RFC2283 section 7 */ 3720f74e101Schristos #define SAFNUM_RES 0 3730f74e101Schristos #define SAFNUM_UNICAST 1 3740f74e101Schristos #define SAFNUM_MULTICAST 2 375dc860a36Sspz #define SAFNUM_UNIMULTICAST 3 /* deprecated now */ 3760f74e101Schristos /* labeled BGP RFC3107 */ 3770f74e101Schristos #define SAFNUM_LABUNICAST 4 378dc860a36Sspz /* RFC6514 */ 3790f74e101Schristos #define SAFNUM_MULTICAST_VPN 5 380dc860a36Sspz /* draft-nalawade-kapoor-tunnel-safi */ 381dc860a36Sspz #define SAFNUM_TUNNEL 64 382dc860a36Sspz /* RFC4761 */ 383dc860a36Sspz #define SAFNUM_VPLS 65 384dc860a36Sspz /* RFC6037 */ 3850f74e101Schristos #define SAFNUM_MDT 66 386c74ad251Schristos /* RFC7432 */ 387c74ad251Schristos #define SAFNUM_EVPN 70 388dc860a36Sspz /* RFC4364 */ 3890f74e101Schristos #define SAFNUM_VPNUNICAST 128 390dc860a36Sspz /* RFC6513 */ 3910f74e101Schristos #define SAFNUM_VPNMULTICAST 129 392dc860a36Sspz #define SAFNUM_VPNUNIMULTICAST 130 /* deprecated now */ 393dc860a36Sspz /* RFC4684 */ 3940f74e101Schristos #define SAFNUM_RT_ROUTING_INFO 132 3950f74e101Schristos 3960f74e101Schristos #define BGP_VPN_RD_LEN 8 3970f74e101Schristos 398870189d2Schristos static const struct tok bgp_safi_values[] = { 3990f74e101Schristos { SAFNUM_RES, "Reserved"}, 4000f74e101Schristos { SAFNUM_UNICAST, "Unicast"}, 4010f74e101Schristos { SAFNUM_MULTICAST, "Multicast"}, 4020f74e101Schristos { SAFNUM_UNIMULTICAST, "Unicast+Multicast"}, 4030f74e101Schristos { SAFNUM_LABUNICAST, "labeled Unicast"}, 4040f74e101Schristos { SAFNUM_TUNNEL, "Tunnel"}, 4050f74e101Schristos { SAFNUM_VPLS, "VPLS"}, 4060f74e101Schristos { SAFNUM_MDT, "MDT"}, 407c74ad251Schristos { SAFNUM_EVPN, "EVPN"}, 4080f74e101Schristos { SAFNUM_VPNUNICAST, "labeled VPN Unicast"}, 4090f74e101Schristos { SAFNUM_VPNMULTICAST, "labeled VPN Multicast"}, 4100f74e101Schristos { SAFNUM_VPNUNIMULTICAST, "labeled VPN Unicast+Multicast"}, 4110f74e101Schristos { SAFNUM_RT_ROUTING_INFO, "Route Target Routing Information"}, 4120f74e101Schristos { SAFNUM_MULTICAST_VPN, "Multicast VPN"}, 4130f74e101Schristos { 0, NULL } 4140f74e101Schristos }; 4150f74e101Schristos 4160f74e101Schristos /* well-known community */ 4170f74e101Schristos #define BGP_COMMUNITY_NO_EXPORT 0xffffff01 4180f74e101Schristos #define BGP_COMMUNITY_NO_ADVERT 0xffffff02 4190f74e101Schristos #define BGP_COMMUNITY_NO_EXPORT_SUBCONFED 0xffffff03 4200f74e101Schristos 421c74ad251Schristos /* Extended community type - RFC 4360 */ 4220f74e101Schristos #define BGP_EXT_COM_RT_0 0x0002 /* Route Target,Format AS(2bytes):AN(4bytes) */ 4230f74e101Schristos #define BGP_EXT_COM_RT_1 0x0102 /* Route Target,Format IP address:AN(2bytes) */ 4240f74e101Schristos #define BGP_EXT_COM_RT_2 0x0202 /* Route Target,Format AN(4bytes):local(2bytes) */ 4250f74e101Schristos #define BGP_EXT_COM_RO_0 0x0003 /* Route Origin,Format AS(2bytes):AN(4bytes) */ 4260f74e101Schristos #define BGP_EXT_COM_RO_1 0x0103 /* Route Origin,Format IP address:AN(2bytes) */ 4270f74e101Schristos #define BGP_EXT_COM_RO_2 0x0203 /* Route Origin,Format AN(4bytes):local(2bytes) */ 4280f74e101Schristos #define BGP_EXT_COM_LINKBAND 0x4004 /* Link Bandwidth,Format AS(2B):Bandwidth(4B) */ 4290f74e101Schristos /* rfc2547 bgp-mpls-vpns */ 4300f74e101Schristos #define BGP_EXT_COM_VPN_ORIGIN 0x0005 /* OSPF Domain ID / VPN of Origin - draft-rosen-vpns-ospf-bgp-mpls */ 431c74ad251Schristos #define BGP_EXT_COM_VPN_ORIGIN2 0x0105 /* duplicate - keep for backwards compatibility */ 432c74ad251Schristos #define BGP_EXT_COM_VPN_ORIGIN3 0x0205 /* duplicate - keep for backwards compatibility */ 433c74ad251Schristos #define BGP_EXT_COM_VPN_ORIGIN4 0x8005 /* duplicate - keep for backwards compatibility */ 4340f74e101Schristos 4350f74e101Schristos #define BGP_EXT_COM_OSPF_RTYPE 0x0306 /* OSPF Route Type,Format Area(4B):RouteType(1B):Options(1B) */ 436c74ad251Schristos #define BGP_EXT_COM_OSPF_RTYPE2 0x8000 /* duplicate - keep for backwards compatibility */ 437c74ad251Schristos #define BGP_EXT_COM_ENCAP 0x030c /* rfc5512 */ 4380f74e101Schristos 4390f74e101Schristos #define BGP_EXT_COM_OSPF_RID 0x0107 /* OSPF Router ID,Format RouterID(4B):Unused(2B) */ 440c74ad251Schristos #define BGP_EXT_COM_OSPF_RID2 0x8001 /* duplicate - keep for backwards compatibility */ 4410f74e101Schristos 4420f74e101Schristos #define BGP_EXT_COM_L2INFO 0x800a /* draft-kompella-ppvpn-l2vpn */ 4430f74e101Schristos 4440e9868baSchristos #define BGP_EXT_COM_SOURCE_AS 0x0009 /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */ 4450e9868baSchristos #define BGP_EXT_COM_VRF_RT_IMP 0x010b /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */ 4460e9868baSchristos #define BGP_EXT_COM_L2VPN_RT_0 0x000a /* L2VPN Identifier,Format AS(2bytes):AN(4bytes) */ 4470e9868baSchristos #define BGP_EXT_COM_L2VPN_RT_1 0xF10a /* L2VPN Identifier,Format IP address:AN(2bytes) */ 4480e9868baSchristos 449c74ad251Schristos /* https://www.cisco.com/en/US/tech/tk436/tk428/technologies_tech_note09186a00801eb09a.shtml */ 4500f74e101Schristos #define BGP_EXT_COM_EIGRP_GEN 0x8800 4510f74e101Schristos #define BGP_EXT_COM_EIGRP_METRIC_AS_DELAY 0x8801 4520f74e101Schristos #define BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW 0x8802 4530f74e101Schristos #define BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU 0x8803 4540f74e101Schristos #define BGP_EXT_COM_EIGRP_EXT_REMAS_REMID 0x8804 4550f74e101Schristos #define BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC 0x8805 4560f74e101Schristos 457870189d2Schristos static const struct tok bgp_extd_comm_flag_values[] = { 4580f74e101Schristos { 0x8000, "vendor-specific"}, 4590f74e101Schristos { 0x4000, "non-transitive"}, 4600f74e101Schristos { 0, NULL}, 4610f74e101Schristos }; 4620f74e101Schristos 463870189d2Schristos static const struct tok bgp_extd_comm_subtype_values[] = { 4640f74e101Schristos { BGP_EXT_COM_RT_0, "target"}, 4650f74e101Schristos { BGP_EXT_COM_RT_1, "target"}, 4660f74e101Schristos { BGP_EXT_COM_RT_2, "target"}, 4670f74e101Schristos { BGP_EXT_COM_RO_0, "origin"}, 4680f74e101Schristos { BGP_EXT_COM_RO_1, "origin"}, 4690f74e101Schristos { BGP_EXT_COM_RO_2, "origin"}, 4700f74e101Schristos { BGP_EXT_COM_LINKBAND, "link-BW"}, 4710f74e101Schristos { BGP_EXT_COM_VPN_ORIGIN, "ospf-domain"}, 4720f74e101Schristos { BGP_EXT_COM_VPN_ORIGIN2, "ospf-domain"}, 4730f74e101Schristos { BGP_EXT_COM_VPN_ORIGIN3, "ospf-domain"}, 4740f74e101Schristos { BGP_EXT_COM_VPN_ORIGIN4, "ospf-domain"}, 4750f74e101Schristos { BGP_EXT_COM_OSPF_RTYPE, "ospf-route-type"}, 4760f74e101Schristos { BGP_EXT_COM_OSPF_RTYPE2, "ospf-route-type"}, 477c74ad251Schristos { BGP_EXT_COM_ENCAP, "encapsulation"}, 4780f74e101Schristos { BGP_EXT_COM_OSPF_RID, "ospf-router-id"}, 4790f74e101Schristos { BGP_EXT_COM_OSPF_RID2, "ospf-router-id"}, 4800f74e101Schristos { BGP_EXT_COM_L2INFO, "layer2-info"}, 4810f74e101Schristos { BGP_EXT_COM_EIGRP_GEN, "eigrp-general-route (flag, tag)" }, 4820f74e101Schristos { BGP_EXT_COM_EIGRP_METRIC_AS_DELAY, "eigrp-route-metric (AS, delay)" }, 4830f74e101Schristos { BGP_EXT_COM_EIGRP_METRIC_REL_NH_BW, "eigrp-route-metric (reliability, nexthop, bandwidth)" }, 4840f74e101Schristos { BGP_EXT_COM_EIGRP_METRIC_LOAD_MTU, "eigrp-route-metric (load, MTU)" }, 4850f74e101Schristos { BGP_EXT_COM_EIGRP_EXT_REMAS_REMID, "eigrp-external-route (remote-AS, remote-ID)" }, 4860f74e101Schristos { BGP_EXT_COM_EIGRP_EXT_REMPROTO_REMMETRIC, "eigrp-external-route (remote-proto, remote-metric)" }, 4870f74e101Schristos { BGP_EXT_COM_SOURCE_AS, "source-AS" }, 4880f74e101Schristos { BGP_EXT_COM_VRF_RT_IMP, "vrf-route-import"}, 4890e9868baSchristos { BGP_EXT_COM_L2VPN_RT_0, "l2vpn-id"}, 4900e9868baSchristos { BGP_EXT_COM_L2VPN_RT_1, "l2vpn-id"}, 4910f74e101Schristos { 0, NULL}, 4920f74e101Schristos }; 4930f74e101Schristos 494c74ad251Schristos /* RFC RFC5512 BGP Tunnel Encapsulation Attribute Tunnel Types */ 495c74ad251Schristos #define BGP_ENCAP_TUNNEL_L2TPV3_IP 1 496c74ad251Schristos #define BGP_ENCAP_TUNNEL_GRE 2 497c74ad251Schristos #define BGP_ENCAP_TUNNEL_TRANSMIT 3 498c74ad251Schristos #define BGP_ENCAP_TUNNEL_IPSEC 4 499c74ad251Schristos #define BGP_ENCAP_TUNNEL_IP_IPSEC 5 500c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS_IP 6 501c74ad251Schristos #define BGP_ENCAP_TUNNEL_IP_IP 7 502c74ad251Schristos #define BGP_ENCAP_TUNNEL_VXLAN 8 503c74ad251Schristos #define BGP_ENCAP_TUNNEL_NVGRE 9 504c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS 10 505c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS_GRE 11 506c74ad251Schristos #define BGP_ENCAP_TUNNEL_VXLAN_GPE 12 507c74ad251Schristos #define BGP_ENCAP_TUNNEL_MPLS_UDP 13 508c74ad251Schristos #define BGP_ENCAP_TUNNEL_IPV6 14 509c74ad251Schristos #define BGP_ENCAP_TUNNEL_SR_TE 15 510c74ad251Schristos #define BGP_ENCAP_TUNNEL_BARE 16 511c74ad251Schristos #define BGP_ENCAP_TUNNEL_SR 17 512c74ad251Schristos 513c74ad251Schristos static const struct tok bgp_extd_comm_encap_tunnel_values[] = { 514c74ad251Schristos { BGP_ENCAP_TUNNEL_L2TPV3_IP, "L2TPv3 over IP"}, 515c74ad251Schristos { BGP_ENCAP_TUNNEL_GRE, "GRE"}, 516c74ad251Schristos { BGP_ENCAP_TUNNEL_TRANSMIT, "Transmit Tunnel"}, 517c74ad251Schristos { BGP_ENCAP_TUNNEL_IPSEC, "IPsec"}, 518c74ad251Schristos { BGP_ENCAP_TUNNEL_IP_IPSEC, "IP in IP with IPsec"}, 519c74ad251Schristos { BGP_ENCAP_TUNNEL_MPLS_IP, "MPLS in IP with IPsec"}, 520c74ad251Schristos { BGP_ENCAP_TUNNEL_IP_IP, "IP in IP"}, 521c74ad251Schristos { BGP_ENCAP_TUNNEL_VXLAN, "VXLAN"}, 522c74ad251Schristos { BGP_ENCAP_TUNNEL_NVGRE, "NVGRE"}, 523c74ad251Schristos { BGP_ENCAP_TUNNEL_MPLS, "MPLS"}, 524c74ad251Schristos { BGP_ENCAP_TUNNEL_MPLS_GRE, "MPLS in GRE"}, 525c74ad251Schristos { BGP_ENCAP_TUNNEL_VXLAN_GPE, "VXLAN GPE"}, 526c74ad251Schristos { BGP_ENCAP_TUNNEL_MPLS_UDP, "MPLS in UDP"}, 527c74ad251Schristos { BGP_ENCAP_TUNNEL_IPV6, "IPv6"}, 528c74ad251Schristos { BGP_ENCAP_TUNNEL_SR_TE, "SR TE"}, 529c74ad251Schristos { BGP_ENCAP_TUNNEL_BARE, "Bare"}, 530c74ad251Schristos { BGP_ENCAP_TUNNEL_SR, "SR"}, 531c74ad251Schristos { 0, NULL}, 532c74ad251Schristos }; 533c74ad251Schristos 5340f74e101Schristos /* OSPF codes for BGP_EXT_COM_OSPF_RTYPE draft-rosen-vpns-ospf-bgp-mpls */ 5350f74e101Schristos #define BGP_OSPF_RTYPE_RTR 1 /* OSPF Router LSA */ 5360f74e101Schristos #define BGP_OSPF_RTYPE_NET 2 /* OSPF Network LSA */ 5370f74e101Schristos #define BGP_OSPF_RTYPE_SUM 3 /* OSPF Summary LSA */ 5380f74e101Schristos #define BGP_OSPF_RTYPE_EXT 5 /* OSPF External LSA, note that ASBR doesn't apply to MPLS-VPN */ 5390f74e101Schristos #define BGP_OSPF_RTYPE_NSSA 7 /* OSPF NSSA External*/ 5400f74e101Schristos #define BGP_OSPF_RTYPE_SHAM 129 /* OSPF-MPLS-VPN Sham link */ 5410f74e101Schristos #define BGP_OSPF_RTYPE_METRIC_TYPE 0x1 /* LSB of RTYPE Options Field */ 5420f74e101Schristos 543870189d2Schristos static const struct tok bgp_extd_comm_ospf_rtype_values[] = { 5440f74e101Schristos { BGP_OSPF_RTYPE_RTR, "Router" }, 5450f74e101Schristos { BGP_OSPF_RTYPE_NET, "Network" }, 5460f74e101Schristos { BGP_OSPF_RTYPE_SUM, "Summary" }, 5470f74e101Schristos { BGP_OSPF_RTYPE_EXT, "External" }, 5480f74e101Schristos { BGP_OSPF_RTYPE_NSSA,"NSSA External" }, 5490f74e101Schristos { BGP_OSPF_RTYPE_SHAM,"MPLS-VPN Sham" }, 5500f74e101Schristos { 0, NULL }, 5510f74e101Schristos }; 5520f74e101Schristos 553fdccd7e4Schristos /* ADD-PATH Send/Receive field values */ 554fdccd7e4Schristos static const struct tok bgp_add_path_recvsend[] = { 555fdccd7e4Schristos { 1, "Receive" }, 556fdccd7e4Schristos { 2, "Send" }, 557fdccd7e4Schristos { 3, "Both" }, 558fdccd7e4Schristos { 0, NULL }, 559fdccd7e4Schristos }; 560fdccd7e4Schristos 561c74ad251Schristos #define AS_STR_SIZE sizeof("xxxxx.xxxxx") 5620f74e101Schristos 5630f74e101Schristos /* 5640f74e101Schristos * as_printf 5650f74e101Schristos * 5660f74e101Schristos * Convert an AS number into a string and return string pointer. 5670f74e101Schristos * 568b3a00663Schristos * Depending on bflag is set or not, AS number is converted into ASDOT notation 5690f74e101Schristos * or plain number notation. 5700f74e101Schristos * 5710f74e101Schristos */ 5720f74e101Schristos static char * 573b3a00663Schristos as_printf(netdissect_options *ndo, 574c74ad251Schristos char *str, size_t size, u_int asnum) 5750f74e101Schristos { 576b3a00663Schristos if (!ndo->ndo_bflag || asnum <= 0xFFFF) { 5770f74e101Schristos snprintf(str, size, "%u", asnum); 5780f74e101Schristos } else { 5790f74e101Schristos snprintf(str, size, "%u.%u", asnum >> 16, asnum & 0xFFFF); 5800f74e101Schristos } 5810f74e101Schristos return str; 5820f74e101Schristos } 5830f74e101Schristos 5840e9868baSchristos #define ITEMCHECK(minlen) if (itemlen < minlen) goto badtlv; 5850e9868baSchristos 5860f74e101Schristos int 587b3a00663Schristos decode_prefix4(netdissect_options *ndo, 588c74ad251Schristos const u_char *pptr, u_int itemlen, char *buf, size_t buflen) 5890f74e101Schristos { 590c74ad251Schristos nd_ipv4 addr; 5910e9868baSchristos u_int plen, plenbytes; 5920f74e101Schristos 5930e9868baSchristos ITEMCHECK(1); 594c74ad251Schristos plen = GET_U_1(pptr); 5950f74e101Schristos if (32 < plen) 5960f74e101Schristos return -1; 5970e9868baSchristos itemlen -= 1; 5980f74e101Schristos 5990f74e101Schristos memset(&addr, 0, sizeof(addr)); 6000e9868baSchristos plenbytes = (plen + 7) / 8; 6010e9868baSchristos ITEMCHECK(plenbytes); 602c74ad251Schristos GET_CPY_BYTES(&addr, pptr + 1, plenbytes); 6030f74e101Schristos if (plen % 8) { 604c74ad251Schristos ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); 6050f74e101Schristos } 606c74ad251Schristos snprintf(buf, buflen, "%s/%u", ipaddr_string(ndo, (const u_char *)&addr), plen); 6070e9868baSchristos return 1 + plenbytes; 6080f74e101Schristos 6090e9868baSchristos badtlv: 610c74ad251Schristos return -2; 6110f74e101Schristos } 6120f74e101Schristos 6130f74e101Schristos static int 614b3a00663Schristos decode_labeled_prefix4(netdissect_options *ndo, 615c74ad251Schristos const u_char *pptr, u_int itemlen, char *buf, 616c74ad251Schristos size_t buflen) 6170f74e101Schristos { 618c74ad251Schristos nd_ipv4 addr; 6190e9868baSchristos u_int plen, plenbytes; 6200f74e101Schristos 6210e9868baSchristos /* prefix length and label = 4 bytes */ 622c74ad251Schristos ND_TCHECK_4(pptr); 6230e9868baSchristos ITEMCHECK(4); 624c74ad251Schristos plen = GET_U_1(pptr); /* get prefix length */ 6250f74e101Schristos 6260f74e101Schristos /* this is one of the weirdnesses of rfc3107 6270f74e101Schristos the label length (actually the label + COS bits) 6280f74e101Schristos is added to the prefix length; 6290f74e101Schristos we also do only read out just one label - 6300f74e101Schristos there is no real application for advertisement of 631ba2ff121Schristos stacked labels in a single BGP message 6320f74e101Schristos */ 6330f74e101Schristos 6340f74e101Schristos if (24 > plen) 6350f74e101Schristos return -1; 6360f74e101Schristos 6370f74e101Schristos plen-=24; /* adjust prefixlen - labellength */ 6380f74e101Schristos 6390f74e101Schristos if (32 < plen) 6400f74e101Schristos return -1; 6410e9868baSchristos itemlen -= 4; 6420f74e101Schristos 6430f74e101Schristos memset(&addr, 0, sizeof(addr)); 6440e9868baSchristos plenbytes = (plen + 7) / 8; 6450e9868baSchristos ITEMCHECK(plenbytes); 646c74ad251Schristos GET_CPY_BYTES(&addr, pptr + 4, plenbytes); 6470f74e101Schristos if (plen % 8) { 648c74ad251Schristos ((u_char *)&addr)[plenbytes - 1] &= ((0xff00 >> (plen % 8)) & 0xff); 6490f74e101Schristos } 6500f74e101Schristos /* the label may get offsetted by 4 bits so lets shift it right */ 651c74ad251Schristos snprintf(buf, buflen, "%s/%u, label:%u %s", 652c74ad251Schristos ipaddr_string(ndo, (const u_char *)&addr), 6530f74e101Schristos plen, 654c74ad251Schristos GET_BE_U_3(pptr + 1)>>4, 655c74ad251Schristos ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); 6560f74e101Schristos 6570e9868baSchristos return 4 + plenbytes; 6580f74e101Schristos 6590f74e101Schristos trunc: 6600f74e101Schristos return -2; 6610e9868baSchristos 6620e9868baSchristos badtlv: 6630e9868baSchristos return -3; 6640f74e101Schristos } 6650f74e101Schristos 6660f74e101Schristos /* 6670f74e101Schristos * bgp_vpn_ip_print 6680f74e101Schristos * 669c74ad251Schristos * print an ipv4 or ipv6 address into a buffer dependent on address length. 6700f74e101Schristos */ 6710f74e101Schristos static char * 672b3a00663Schristos bgp_vpn_ip_print(netdissect_options *ndo, 673ba2ff121Schristos const u_char *pptr, u_int addr_length) 674ba2ff121Schristos { 6750f74e101Schristos 6760f74e101Schristos /* worst case string is s fully formatted v6 address */ 6770f74e101Schristos static char addr[sizeof("1234:5678:89ab:cdef:1234:5678:89ab:cdef")]; 6780f74e101Schristos char *pos = addr; 6790f74e101Schristos 6800f74e101Schristos switch(addr_length) { 681c74ad251Schristos case (sizeof(nd_ipv4) << 3): /* 32 */ 682c74ad251Schristos snprintf(pos, sizeof(addr), "%s", GET_IPADDR_STRING(pptr)); 6830f74e101Schristos break; 684c74ad251Schristos case (sizeof(nd_ipv6) << 3): /* 128 */ 685c74ad251Schristos snprintf(pos, sizeof(addr), "%s", GET_IP6ADDR_STRING(pptr)); 6860f74e101Schristos break; 6870f74e101Schristos default: 6880f74e101Schristos snprintf(pos, sizeof(addr), "bogus address length %u", addr_length); 6890f74e101Schristos break; 6900f74e101Schristos } 6910f74e101Schristos pos += strlen(pos); 6920f74e101Schristos 6930f74e101Schristos *(pos) = '\0'; 6940f74e101Schristos return (addr); 6950f74e101Schristos } 6960f74e101Schristos 6970f74e101Schristos /* 6980f74e101Schristos * bgp_vpn_sg_print 6990f74e101Schristos * 7000f74e101Schristos * print an multicast s,g entry into a buffer. 7010f74e101Schristos * the s,g entry is encoded like this. 7020f74e101Schristos * 7030f74e101Schristos * +-----------------------------------+ 7040f74e101Schristos * | Multicast Source Length (1 octet) | 7050f74e101Schristos * +-----------------------------------+ 7060f74e101Schristos * | Multicast Source (Variable) | 7070f74e101Schristos * +-----------------------------------+ 7080f74e101Schristos * | Multicast Group Length (1 octet) | 7090f74e101Schristos * +-----------------------------------+ 7100f74e101Schristos * | Multicast Group (Variable) | 7110f74e101Schristos * +-----------------------------------+ 7120f74e101Schristos * 7130f74e101Schristos * return the number of bytes read from the wire. 7140f74e101Schristos */ 715c74ad251Schristos static u_int 716b3a00663Schristos bgp_vpn_sg_print(netdissect_options *ndo, 717c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 718ba2ff121Schristos { 719b3a00663Schristos uint8_t addr_length; 7200f74e101Schristos u_int total_length, offset; 7210f74e101Schristos 7220f74e101Schristos total_length = 0; 7230f74e101Schristos 7240f74e101Schristos /* Source address length, encoded in bits */ 725c74ad251Schristos addr_length = GET_U_1(pptr); 726c74ad251Schristos pptr++; 7270f74e101Schristos 7280f74e101Schristos /* Source address */ 729c74ad251Schristos ND_TCHECK_LEN(pptr, (addr_length >> 3)); 7300f74e101Schristos total_length += (addr_length >> 3) + 1; 731c74ad251Schristos offset = (u_int)strlen(buf); 7320f74e101Schristos if (addr_length) { 7330f74e101Schristos snprintf(buf + offset, buflen - offset, ", Source %s", 734b3a00663Schristos bgp_vpn_ip_print(ndo, pptr, addr_length)); 7350f74e101Schristos pptr += (addr_length >> 3); 7360f74e101Schristos } 7370f74e101Schristos 7380f74e101Schristos /* Group address length, encoded in bits */ 739c74ad251Schristos addr_length = GET_U_1(pptr); 740c74ad251Schristos pptr++; 7410f74e101Schristos 7420f74e101Schristos /* Group address */ 743c74ad251Schristos ND_TCHECK_LEN(pptr, (addr_length >> 3)); 7440f74e101Schristos total_length += (addr_length >> 3) + 1; 745c74ad251Schristos offset = (u_int)strlen(buf); 7460f74e101Schristos if (addr_length) { 7470f74e101Schristos snprintf(buf + offset, buflen - offset, ", Group %s", 748b3a00663Schristos bgp_vpn_ip_print(ndo, pptr, addr_length)); 7490f74e101Schristos pptr += (addr_length >> 3); 7500f74e101Schristos } 7510f74e101Schristos 7520f74e101Schristos trunc: 7530f74e101Schristos return (total_length); 7540f74e101Schristos } 7550f74e101Schristos 756c74ad251Schristos /* Print an RFC 4364 Route Distinguisher */ 757c74ad251Schristos const char * 758b3a00663Schristos bgp_vpn_rd_print(netdissect_options *ndo, 759ba2ff121Schristos const u_char *pptr) 760ba2ff121Schristos { 7610f74e101Schristos /* allocate space for the largest possible string */ 762c74ad251Schristos static char rd[sizeof("xxxxx.xxxxx:xxxxx (xxx.xxx.xxx.xxx:xxxxx)")]; 7630f74e101Schristos char *pos = rd; 764c74ad251Schristos /* allocate space for the largest possible string */ 765c74ad251Schristos char astostr[AS_STR_SIZE]; 7660f74e101Schristos 7670f74e101Schristos /* ok lets load the RD format */ 768c74ad251Schristos switch (GET_BE_U_2(pptr)) { 7690f74e101Schristos 7700f74e101Schristos case 0: 771c74ad251Schristos /* 2-byte-AS:number fmt */ 7720f74e101Schristos snprintf(pos, sizeof(rd) - (pos - rd), "%u:%u (= %u.%u.%u.%u)", 773c74ad251Schristos GET_BE_U_2(pptr + 2), 774c74ad251Schristos GET_BE_U_4(pptr + 4), 775c74ad251Schristos GET_U_1(pptr + 4), GET_U_1(pptr + 5), 776c74ad251Schristos GET_U_1(pptr + 6), GET_U_1(pptr + 7)); 7770f74e101Schristos break; 7780f74e101Schristos 7790f74e101Schristos case 1: 780c74ad251Schristos /* IP-address:AS fmt */ 7810f74e101Schristos snprintf(pos, sizeof(rd) - (pos - rd), "%u.%u.%u.%u:%u", 782c74ad251Schristos GET_U_1(pptr + 2), GET_U_1(pptr + 3), 783c74ad251Schristos GET_U_1(pptr + 4), GET_U_1(pptr + 5), 784c74ad251Schristos GET_BE_U_2(pptr + 6)); 7850f74e101Schristos break; 7860f74e101Schristos 7870f74e101Schristos case 2: 788c74ad251Schristos /* 4-byte-AS:number fmt */ 7890f74e101Schristos snprintf(pos, sizeof(rd) - (pos - rd), "%s:%u (%u.%u.%u.%u:%u)", 790c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 2)), 791c74ad251Schristos GET_BE_U_2(pptr + 6), GET_U_1(pptr + 2), 792c74ad251Schristos GET_U_1(pptr + 3), GET_U_1(pptr + 4), 793c74ad251Schristos GET_U_1(pptr + 5), GET_BE_U_2(pptr + 6)); 7940f74e101Schristos break; 7950f74e101Schristos default: 7960f74e101Schristos snprintf(pos, sizeof(rd) - (pos - rd), "unknown RD format"); 7970f74e101Schristos break; 7980f74e101Schristos } 7990f74e101Schristos pos += strlen(pos); 8000f74e101Schristos *(pos) = '\0'; 8010f74e101Schristos return (rd); 8020f74e101Schristos } 8030f74e101Schristos 804c74ad251Schristos /* 805c74ad251Schristos * Print an RFC 4360 Extended Community. 806c74ad251Schristos */ 807c74ad251Schristos static void 808c74ad251Schristos bgp_extended_community_print(netdissect_options *ndo, 809c74ad251Schristos const u_char *pptr) 810c74ad251Schristos { 811c74ad251Schristos union { /* copy buffer for bandwidth values */ 812c74ad251Schristos float f; 813c74ad251Schristos uint32_t i; 814c74ad251Schristos } bw; 815c74ad251Schristos /* allocate space for the largest possible string */ 816c74ad251Schristos char astostr[AS_STR_SIZE]; 817c74ad251Schristos 818c74ad251Schristos switch (GET_BE_U_2(pptr)) { 819c74ad251Schristos 820c74ad251Schristos case BGP_EXT_COM_RT_0: 821c74ad251Schristos case BGP_EXT_COM_RO_0: 822c74ad251Schristos case BGP_EXT_COM_L2VPN_RT_0: 823c74ad251Schristos ND_PRINT("%u:%u (= %s)", 824c74ad251Schristos GET_BE_U_2(pptr + 2), 825c74ad251Schristos GET_BE_U_4(pptr + 4), 826c74ad251Schristos GET_IPADDR_STRING(pptr+4)); 827c74ad251Schristos break; 828c74ad251Schristos 829c74ad251Schristos case BGP_EXT_COM_RT_1: 830c74ad251Schristos case BGP_EXT_COM_RO_1: 831c74ad251Schristos case BGP_EXT_COM_L2VPN_RT_1: 832c74ad251Schristos case BGP_EXT_COM_VRF_RT_IMP: 833c74ad251Schristos ND_PRINT("%s:%u", 834c74ad251Schristos GET_IPADDR_STRING(pptr+2), 835c74ad251Schristos GET_BE_U_2(pptr + 6)); 836c74ad251Schristos break; 837c74ad251Schristos 838c74ad251Schristos case BGP_EXT_COM_RT_2: 839c74ad251Schristos case BGP_EXT_COM_RO_2: 840c74ad251Schristos ND_PRINT("%s:%u", 841c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), 842c74ad251Schristos GET_BE_U_4(pptr + 2)), GET_BE_U_2(pptr + 6)); 843c74ad251Schristos break; 844c74ad251Schristos 845c74ad251Schristos case BGP_EXT_COM_LINKBAND: 846c74ad251Schristos bw.i = GET_BE_U_4(pptr + 4); 847c74ad251Schristos ND_PRINT("bandwidth: %.3f Mbps", 848c74ad251Schristos bw.f*8/1000000); 849c74ad251Schristos break; 850c74ad251Schristos 851c74ad251Schristos case BGP_EXT_COM_VPN_ORIGIN: 852c74ad251Schristos case BGP_EXT_COM_VPN_ORIGIN2: 853c74ad251Schristos case BGP_EXT_COM_VPN_ORIGIN3: 854c74ad251Schristos case BGP_EXT_COM_VPN_ORIGIN4: 855c74ad251Schristos case BGP_EXT_COM_OSPF_RID: 856c74ad251Schristos case BGP_EXT_COM_OSPF_RID2: 857c74ad251Schristos ND_PRINT("%s", GET_IPADDR_STRING(pptr+2)); 858c74ad251Schristos break; 859c74ad251Schristos 860c74ad251Schristos case BGP_EXT_COM_OSPF_RTYPE: 861c74ad251Schristos case BGP_EXT_COM_OSPF_RTYPE2: 862c74ad251Schristos ND_PRINT("area:%s, router-type:%s, metric-type:%s%s", 863c74ad251Schristos GET_IPADDR_STRING(pptr+2), 864c74ad251Schristos tok2str(bgp_extd_comm_ospf_rtype_values, 865c74ad251Schristos "unknown (0x%02x)", 866c74ad251Schristos GET_U_1((pptr + 6))), 867c74ad251Schristos (GET_U_1(pptr + 7) & BGP_OSPF_RTYPE_METRIC_TYPE) ? "E2" : "", 868c74ad251Schristos ((GET_U_1(pptr + 6) == BGP_OSPF_RTYPE_EXT) || (GET_U_1(pptr + 6) == BGP_OSPF_RTYPE_NSSA)) ? "E1" : ""); 869c74ad251Schristos break; 870c74ad251Schristos 871c74ad251Schristos case BGP_EXT_COM_L2INFO: 872c74ad251Schristos ND_PRINT("%s Control Flags [0x%02x]:MTU %u", 873c74ad251Schristos tok2str(l2vpn_encaps_values, 874c74ad251Schristos "unknown encaps", 875c74ad251Schristos GET_U_1((pptr + 2))), 876c74ad251Schristos GET_U_1((pptr + 3)), 877c74ad251Schristos GET_BE_U_2(pptr + 4)); 878c74ad251Schristos break; 879c74ad251Schristos 880c74ad251Schristos case BGP_EXT_COM_SOURCE_AS: 881c74ad251Schristos ND_PRINT("AS %u", GET_BE_U_2(pptr + 2)); 882c74ad251Schristos break; 883c74ad251Schristos 884c74ad251Schristos case BGP_EXT_COM_ENCAP: 885c74ad251Schristos ND_PRINT("Tunnel type: %s", tok2str(bgp_extd_comm_encap_tunnel_values, 886c74ad251Schristos "unknown encaps", 887c74ad251Schristos GET_BE_U_2(pptr + 6))); 888c74ad251Schristos break; 889c74ad251Schristos 890c74ad251Schristos default: 891c74ad251Schristos ND_PRINT("%02x%02x%02x%02x%02x%02x", 892c74ad251Schristos GET_U_1(pptr + 2), 893c74ad251Schristos GET_U_1(pptr + 3), 894c74ad251Schristos GET_U_1(pptr + 4), 895c74ad251Schristos GET_U_1(pptr + 5), 896c74ad251Schristos GET_U_1(pptr + 6), 897c74ad251Schristos GET_U_1(pptr + 7)); 898c74ad251Schristos break; 899c74ad251Schristos } 900c74ad251Schristos } 901c74ad251Schristos 902c74ad251Schristos /* 903c74ad251Schristos * RFC4684 (Section 4)/RFC2858 (Section 4). 904c74ad251Schristos * RTC membership prefix is structured as follows 905c74ad251Schristos * [prefix-len] [origin-as] [route-target] 906c74ad251Schristos * The route-target is encoded as RT ext-comms. 907c74ad251Schristos * Prefix-len may be 0, 32..96 908c74ad251Schristos * 909c74ad251Schristos * Note that pptr is not packet data - it is 910c74ad251Schristos * a buffer owned by our caller - therefore GET_* 911c74ad251Schristos * macros can not be used. 912c74ad251Schristos */ 913c74ad251Schristos static char * 914c74ad251Schristos bgp_rt_prefix_print(netdissect_options *ndo, 915c74ad251Schristos const u_char *pptr, 916c74ad251Schristos u_int plen) 917c74ad251Schristos { 918c74ad251Schristos /* allocate space for the largest possible string */ 919c74ad251Schristos char rtc_prefix_in_hex[sizeof("0000 0000 0000 0000")] = ""; 920c74ad251Schristos u_int rtc_prefix_in_hex_len = 0; 921c74ad251Schristos static char output[61]; /* max response string */ 922c74ad251Schristos /* allocate space for the largest possible string */ 923c74ad251Schristos char astostr[AS_STR_SIZE]; 924c74ad251Schristos uint16_t ec_type = 0; 925c74ad251Schristos u_int octet_count; 926c74ad251Schristos u_int i; 927c74ad251Schristos 928c74ad251Schristos if (plen == 0) { 929c74ad251Schristos snprintf(output, sizeof(output), "route-target: 0:0/0"); 930c74ad251Schristos return (output); 931c74ad251Schristos } 932c74ad251Schristos 933c74ad251Schristos /* hex representation of the prefix */ 934c74ad251Schristos octet_count = (plen+7)/8; 935c74ad251Schristos for (i=0; i<octet_count; i++) { 936c74ad251Schristos rtc_prefix_in_hex_len += snprintf(rtc_prefix_in_hex+rtc_prefix_in_hex_len, 937c74ad251Schristos sizeof(rtc_prefix_in_hex)-rtc_prefix_in_hex_len, 938c74ad251Schristos "%02x%s", *(pptr+i), 939c74ad251Schristos ((i%2 == 1) && (i<octet_count-1)) ? " " : ""); 940c74ad251Schristos } 941c74ad251Schristos 942c74ad251Schristos if (plen < 16) { 943c74ad251Schristos /* 944c74ad251Schristos * The prefix is too short to include the full ext-comm type, 945c74ad251Schristos * so we have no way to parse it further. 946c74ad251Schristos */ 947c74ad251Schristos snprintf(output, sizeof(output), "route-target: partial-type: (%s/%d)", 948c74ad251Schristos rtc_prefix_in_hex, plen); 949c74ad251Schristos return (output); 950c74ad251Schristos } 951c74ad251Schristos 952c74ad251Schristos /* 953c74ad251Schristos * get the ext-comm type 954c74ad251Schristos * Note: pptr references a static 8 octet buffer with unused bits set to 0, 955c74ad251Schristos * hence EXTRACT_*() macros are safe. 956c74ad251Schristos */ 957c74ad251Schristos ec_type = EXTRACT_BE_U_2(pptr); 958c74ad251Schristos switch (ec_type) { 959c74ad251Schristos case BGP_EXT_COM_RT_0: 960c74ad251Schristos /* 2-byte-AS:number fmt */ 961c74ad251Schristos snprintf(output, sizeof(output), "route-target: %u:%u/%d (%s)", 962c74ad251Schristos EXTRACT_BE_U_2(pptr+2), 963c74ad251Schristos EXTRACT_BE_U_4(pptr+4), 964c74ad251Schristos plen, rtc_prefix_in_hex); 965c74ad251Schristos break; 966c74ad251Schristos 967c74ad251Schristos case BGP_EXT_COM_RT_1: 968c74ad251Schristos /* IP-address:AS fmt */ 969c74ad251Schristos snprintf(output, sizeof(output), "route-target: %u.%u.%u.%u:%u/%d (%s)", 970c74ad251Schristos *(pptr+2), *(pptr+3), *(pptr+4), *(pptr+5), 971c74ad251Schristos EXTRACT_BE_U_2(pptr+6), plen, rtc_prefix_in_hex); 972c74ad251Schristos break; 973c74ad251Schristos 974c74ad251Schristos case BGP_EXT_COM_RT_2: 975c74ad251Schristos /* 4-byte-AS:number fmt */ 976c74ad251Schristos snprintf(output, sizeof(output), "route-target: %s:%u/%d (%s)", 977c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), EXTRACT_BE_U_4(pptr+2)), 978c74ad251Schristos EXTRACT_BE_U_2(pptr+6), plen, rtc_prefix_in_hex); 979c74ad251Schristos break; 980c74ad251Schristos 981c74ad251Schristos default: 982c74ad251Schristos snprintf(output, sizeof(output), "route target: unknown-type(%04x) (%s/%d)", 983c74ad251Schristos ec_type, 984c74ad251Schristos rtc_prefix_in_hex, plen); 985c74ad251Schristos break; 986c74ad251Schristos } 987c74ad251Schristos return (output); 988c74ad251Schristos } 989c74ad251Schristos 990c74ad251Schristos /* RFC 4684 */ 9910f74e101Schristos static int 992b3a00663Schristos decode_rt_routing_info(netdissect_options *ndo, 993c74ad251Schristos const u_char *pptr) 9940f74e101Schristos { 995b3a00663Schristos uint8_t route_target[8]; 9960f74e101Schristos u_int plen; 997c74ad251Schristos /* allocate space for the largest possible string */ 998c74ad251Schristos char astostr[AS_STR_SIZE]; 999c74ad251Schristos u_int num_octets; 10000f74e101Schristos 100172c96ff3Schristos /* NLRI "prefix length" from RFC 2858 Section 4. */ 1002c74ad251Schristos plen = GET_U_1(pptr); /* get prefix length */ 10030f74e101Schristos 100472c96ff3Schristos /* NLRI "prefix" (ibid), valid lengths are { 0, 32, 33, ..., 96 } bits. 100572c96ff3Schristos * RFC 4684 Section 4 defines the layout of "origin AS" and "route 100672c96ff3Schristos * target" fields inside the "prefix" depending on its length. 100772c96ff3Schristos */ 1008ba2ff121Schristos if (0 == plen) { 100972c96ff3Schristos /* Without "origin AS", without "route target". */ 1010c74ad251Schristos ND_PRINT("\n\t default route target"); 1011ba2ff121Schristos return 1; 1012ba2ff121Schristos } 10130f74e101Schristos 1014c74ad251Schristos if (32 > plen) { 1015c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 10160f74e101Schristos return -1; 1017c74ad251Schristos } 10180f74e101Schristos 101972c96ff3Schristos /* With at least "origin AS", possibly with "route target". */ 1020c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(pptr + 1)); 102172c96ff3Schristos 10220f74e101Schristos plen -= 32; /* adjust prefix length */ 10230f74e101Schristos 1024c74ad251Schristos if (64 < plen) { 1025c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 10260f74e101Schristos return -1; 1027c74ad251Schristos } 10280f74e101Schristos 102972c96ff3Schristos /* From now on (plen + 7) / 8 evaluates to { 0, 1, 2, ..., 8 } 103072c96ff3Schristos * and gives the number of octets in the variable-length "route 103172c96ff3Schristos * target" field inside this NLRI "prefix". Look for it. 103272c96ff3Schristos */ 10330f74e101Schristos memset(&route_target, 0, sizeof(route_target)); 1034c74ad251Schristos num_octets = (plen + 7) / 8; 1035c74ad251Schristos GET_CPY_BYTES(&route_target, pptr + 5, num_octets); 1036c74ad251Schristos /* If mask-len is not on octet boundary, ensure all extra bits are 0 */ 10370f74e101Schristos if (plen % 8) { 1038c74ad251Schristos ((u_char *)&route_target)[num_octets - 1] &= 10390f74e101Schristos ((0xff00 >> (plen % 8)) & 0xff); 10400f74e101Schristos } 1041c74ad251Schristos ND_PRINT("\n\t origin AS: %s, %s", 1042c74ad251Schristos astostr, 1043c74ad251Schristos bgp_rt_prefix_print(ndo, (u_char *)&route_target, plen)); 10440f74e101Schristos 1045c74ad251Schristos return 5 + num_octets; 10460f74e101Schristos } 10470f74e101Schristos 10480f74e101Schristos static int 1049b3a00663Schristos decode_labeled_vpn_prefix4(netdissect_options *ndo, 1050c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 10510f74e101Schristos { 1052c74ad251Schristos nd_ipv4 addr; 10530f74e101Schristos u_int plen; 10540f74e101Schristos 1055c74ad251Schristos plen = GET_U_1(pptr); /* get prefix length */ 10560f74e101Schristos 10570f74e101Schristos if ((24+64) > plen) 10580f74e101Schristos return -1; 10590f74e101Schristos 10600f74e101Schristos plen -= (24+64); /* adjust prefixlen - labellength - RD len*/ 10610f74e101Schristos 10620f74e101Schristos if (32 < plen) 10630f74e101Schristos return -1; 10640f74e101Schristos 10650f74e101Schristos memset(&addr, 0, sizeof(addr)); 1066c74ad251Schristos GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8); 10670f74e101Schristos if (plen % 8) { 10680f74e101Schristos ((u_char *)&addr)[(plen + 7) / 8 - 1] &= 10690f74e101Schristos ((0xff00 >> (plen % 8)) & 0xff); 10700f74e101Schristos } 10710f74e101Schristos /* the label may get offsetted by 4 bits so lets shift it right */ 1072c74ad251Schristos snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", 1073b3a00663Schristos bgp_vpn_rd_print(ndo, pptr+4), 1074c74ad251Schristos ipaddr_string(ndo, (const u_char *)&addr), 10750f74e101Schristos plen, 1076c74ad251Schristos GET_BE_U_3(pptr + 1)>>4, 1077c74ad251Schristos ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); 10780f74e101Schristos 10790f74e101Schristos return 12 + (plen + 7) / 8; 10800f74e101Schristos } 10810f74e101Schristos 10820f74e101Schristos /* 10830f74e101Schristos * +-------------------------------+ 10840f74e101Schristos * | | 10850f74e101Schristos * | RD:IPv4-address (12 octets) | 10860f74e101Schristos * | | 10870f74e101Schristos * +-------------------------------+ 10880f74e101Schristos * | MDT Group-address (4 octets) | 10890f74e101Schristos * +-------------------------------+ 10900f74e101Schristos */ 10910f74e101Schristos 10920f74e101Schristos #define MDT_VPN_NLRI_LEN 16 10930f74e101Schristos 10940f74e101Schristos static int 1095b3a00663Schristos decode_mdt_vpn_nlri(netdissect_options *ndo, 1096c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 10970f74e101Schristos { 10980f74e101Schristos const u_char *rd; 10990f74e101Schristos const u_char *vpn_ip; 11000f74e101Schristos 11010f74e101Schristos /* if the NLRI is not predefined length, quit.*/ 1102c74ad251Schristos if (GET_U_1(pptr) != MDT_VPN_NLRI_LEN * 8) 11030f74e101Schristos return -1; 11040f74e101Schristos pptr++; 11050f74e101Schristos 11060f74e101Schristos /* RD */ 1107c74ad251Schristos ND_TCHECK_8(pptr); 11080f74e101Schristos rd = pptr; 11090f74e101Schristos pptr += 8; 11100f74e101Schristos 11110f74e101Schristos /* IPv4 address */ 11120f74e101Schristos vpn_ip = pptr; 1113c74ad251Schristos pptr += sizeof(nd_ipv4); 11140f74e101Schristos 11150f74e101Schristos /* MDT Group Address */ 11160f74e101Schristos snprintf(buf, buflen, "RD: %s, VPN IP Address: %s, MC Group Address: %s", 1117c74ad251Schristos bgp_vpn_rd_print(ndo, rd), GET_IPADDR_STRING(vpn_ip), GET_IPADDR_STRING(pptr)); 11180f74e101Schristos 11190f74e101Schristos return MDT_VPN_NLRI_LEN + 1; 11200f74e101Schristos 11210f74e101Schristos trunc: 11220f74e101Schristos return -2; 11230f74e101Schristos } 11240f74e101Schristos 11250f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI 1 11260f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI 2 11270f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI 3 11280f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF 4 11290f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE 5 11300f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN 6 11310f74e101Schristos #define BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN 7 11320f74e101Schristos 1133870189d2Schristos static const struct tok bgp_multicast_vpn_route_type_values[] = { 11340f74e101Schristos { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI, "Intra-AS I-PMSI"}, 11350f74e101Schristos { BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI, "Inter-AS I-PMSI"}, 11360f74e101Schristos { BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI, "S-PMSI"}, 11370f74e101Schristos { BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF, "Intra-AS Segment-Leaf"}, 11380f74e101Schristos { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE, "Source-Active"}, 11390f74e101Schristos { BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN, "Shared Tree Join"}, 11400f74e101Schristos { BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN, "Source Tree Join"}, 114172c96ff3Schristos { 0, NULL} 11420f74e101Schristos }; 11430f74e101Schristos 1144a8e08e94Skamil UNALIGNED_OK 11450f74e101Schristos static int 1146b3a00663Schristos decode_multicast_vpn(netdissect_options *ndo, 1147c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 11480f74e101Schristos { 1149c74ad251Schristos /* allocate space for the largest possible string */ 1150c74ad251Schristos char astostr[AS_STR_SIZE]; 1151c74ad251Schristos uint8_t route_type, route_length; 1152c74ad251Schristos u_int addr_length, sg_length; 11530f74e101Schristos u_int offset; 11540f74e101Schristos 1155c74ad251Schristos route_type = GET_U_1(pptr); 1156c74ad251Schristos pptr++; 1157c74ad251Schristos route_length = GET_U_1(pptr); 1158c74ad251Schristos pptr++; 11590f74e101Schristos 11600f74e101Schristos snprintf(buf, buflen, "Route-Type: %s (%u), length: %u", 11610f74e101Schristos tok2str(bgp_multicast_vpn_route_type_values, 11620f74e101Schristos "Unknown", route_type), 11630f74e101Schristos route_type, route_length); 11640f74e101Schristos 11650f74e101Schristos switch(route_type) { 11660f74e101Schristos case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_I_PMSI: 1167c74ad251Schristos ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN); 1168*26ba0b50Schristos if (route_length < BGP_VPN_RD_LEN) 1169*26ba0b50Schristos goto trunc; 1170c74ad251Schristos offset = (u_int)strlen(buf); 11710f74e101Schristos snprintf(buf + offset, buflen - offset, ", RD: %s, Originator %s", 1172b3a00663Schristos bgp_vpn_rd_print(ndo, pptr), 1173b3a00663Schristos bgp_vpn_ip_print(ndo, pptr + BGP_VPN_RD_LEN, 11740f74e101Schristos (route_length - BGP_VPN_RD_LEN) << 3)); 11750f74e101Schristos break; 11760f74e101Schristos case BGP_MULTICAST_VPN_ROUTE_TYPE_INTER_AS_I_PMSI: 1177c74ad251Schristos ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4); 1178c74ad251Schristos offset = (u_int)strlen(buf); 11790f74e101Schristos snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", 1180b3a00663Schristos bgp_vpn_rd_print(ndo, pptr), 1181b3a00663Schristos as_printf(ndo, astostr, sizeof(astostr), 1182c74ad251Schristos GET_BE_U_4(pptr + BGP_VPN_RD_LEN))); 11830f74e101Schristos break; 11840f74e101Schristos 11850f74e101Schristos case BGP_MULTICAST_VPN_ROUTE_TYPE_S_PMSI: 1186c74ad251Schristos ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN); 1187c74ad251Schristos offset = (u_int)strlen(buf); 11880f74e101Schristos snprintf(buf + offset, buflen - offset, ", RD: %s", 1189b3a00663Schristos bgp_vpn_rd_print(ndo, pptr)); 11900f74e101Schristos pptr += BGP_VPN_RD_LEN; 11910f74e101Schristos 1192b3a00663Schristos sg_length = bgp_vpn_sg_print(ndo, pptr, buf, buflen); 11930f74e101Schristos addr_length = route_length - sg_length; 11940f74e101Schristos 1195c74ad251Schristos ND_TCHECK_LEN(pptr, addr_length); 1196c74ad251Schristos offset = (u_int)strlen(buf); 11970f74e101Schristos snprintf(buf + offset, buflen - offset, ", Originator %s", 1198b3a00663Schristos bgp_vpn_ip_print(ndo, pptr, addr_length << 3)); 11990f74e101Schristos break; 12000f74e101Schristos 12010f74e101Schristos case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_ACTIVE: 1202c74ad251Schristos ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN); 1203c74ad251Schristos offset = (u_int)strlen(buf); 12040f74e101Schristos snprintf(buf + offset, buflen - offset, ", RD: %s", 1205b3a00663Schristos bgp_vpn_rd_print(ndo, pptr)); 12060f74e101Schristos pptr += BGP_VPN_RD_LEN; 12070f74e101Schristos 1208b3a00663Schristos bgp_vpn_sg_print(ndo, pptr, buf, buflen); 12090f74e101Schristos break; 12100f74e101Schristos 12110f74e101Schristos case BGP_MULTICAST_VPN_ROUTE_TYPE_SHARED_TREE_JOIN: /* fall through */ 12120f74e101Schristos case BGP_MULTICAST_VPN_ROUTE_TYPE_SOURCE_TREE_JOIN: 1213c74ad251Schristos ND_TCHECK_LEN(pptr, BGP_VPN_RD_LEN + 4); 1214c74ad251Schristos offset = (u_int)strlen(buf); 12150f74e101Schristos snprintf(buf + offset, buflen - offset, ", RD: %s, Source-AS %s", 1216b3a00663Schristos bgp_vpn_rd_print(ndo, pptr), 1217b3a00663Schristos as_printf(ndo, astostr, sizeof(astostr), 1218c74ad251Schristos GET_BE_U_4(pptr + BGP_VPN_RD_LEN))); 121972c96ff3Schristos pptr += BGP_VPN_RD_LEN + 4; 12200f74e101Schristos 1221b3a00663Schristos bgp_vpn_sg_print(ndo, pptr, buf, buflen); 12220f74e101Schristos break; 12230f74e101Schristos 12240f74e101Schristos /* 12250f74e101Schristos * no per route-type printing yet. 12260f74e101Schristos */ 12270f74e101Schristos case BGP_MULTICAST_VPN_ROUTE_TYPE_INTRA_AS_SEG_LEAF: 12280f74e101Schristos default: 12290f74e101Schristos break; 12300f74e101Schristos } 12310f74e101Schristos 12320f74e101Schristos return route_length + 2; 12330f74e101Schristos 12340f74e101Schristos trunc: 12350f74e101Schristos return -2; 12360f74e101Schristos } 12370f74e101Schristos 12380f74e101Schristos /* 12390f74e101Schristos * As I remember, some versions of systems have an snprintf() that 12400f74e101Schristos * returns -1 if the buffer would have overflowed. If the return 12410f74e101Schristos * value is negative, set buflen to 0, to indicate that we've filled 12420f74e101Schristos * the buffer up. 12430f74e101Schristos * 12440f74e101Schristos * If the return value is greater than buflen, that means that 12450f74e101Schristos * the buffer would have overflowed; again, set buflen to 0 in 12460f74e101Schristos * that case. 12470f74e101Schristos */ 1248fdccd7e4Schristos #define UPDATE_BUF_BUFLEN(buf, buflen, stringlen) \ 1249fdccd7e4Schristos if (stringlen<0) \ 12500f74e101Schristos buflen=0; \ 1251fdccd7e4Schristos else if ((u_int)stringlen>buflen) \ 12520f74e101Schristos buflen=0; \ 12530f74e101Schristos else { \ 1254fdccd7e4Schristos buflen-=stringlen; \ 1255fdccd7e4Schristos buf+=stringlen; \ 12560f74e101Schristos } 12570f74e101Schristos 12580f74e101Schristos static int 1259b3a00663Schristos decode_labeled_vpn_l2(netdissect_options *ndo, 1260c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 12610f74e101Schristos { 1262c74ad251Schristos u_int plen, tlen, tlv_type, tlv_len, ttlv_len; 1263c74ad251Schristos int stringlen; 12640f74e101Schristos 1265c74ad251Schristos plen = GET_BE_U_2(pptr); 12660f74e101Schristos tlen = plen; 12670f74e101Schristos pptr += 2; 12680e9868baSchristos /* Old and new L2VPN NLRI share AFI/SAFI 12690e9868baSchristos * -> Assume a 12 Byte-length NLRI is auto-discovery-only 12700e9868baSchristos * and > 17 as old format. Complain for the middle case 12710e9868baSchristos */ 12720e9868baSchristos if (plen == 12) { 12730e9868baSchristos /* assume AD-only with RD, BGPNH */ 1274c74ad251Schristos ND_TCHECK_LEN(pptr, 12); 12750e9868baSchristos buf[0] = '\0'; 1276fdccd7e4Schristos stringlen = snprintf(buf, buflen, "RD: %s, BGPNH: %s", 1277b3a00663Schristos bgp_vpn_rd_print(ndo, pptr), 1278c74ad251Schristos GET_IPADDR_STRING(pptr+8)); 1279fdccd7e4Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 12800e9868baSchristos pptr += 12; 12810e9868baSchristos tlen -= 12; 1282c74ad251Schristos return plen + 2; 12830e9868baSchristos } else if (plen > 17) { 12840e9868baSchristos /* assume old format */ 12850e9868baSchristos /* RD, ID, LBLKOFF, LBLBASE */ 12860e9868baSchristos 1287c74ad251Schristos ND_TCHECK_LEN(pptr, 15); 12880f74e101Schristos buf[0] = '\0'; 1289fdccd7e4Schristos stringlen = snprintf(buf, buflen, "RD: %s, CE-ID: %u, Label-Block Offset: %u, Label Base %u", 1290b3a00663Schristos bgp_vpn_rd_print(ndo, pptr), 1291c74ad251Schristos GET_BE_U_2(pptr + 8), 1292c74ad251Schristos GET_BE_U_2(pptr + 10), 1293c74ad251Schristos GET_BE_U_3(pptr + 12)>>4); /* the label is offsetted by 4 bits so lets shift it right */ 1294fdccd7e4Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 12950f74e101Schristos pptr += 15; 12960f74e101Schristos tlen -= 15; 12970f74e101Schristos 12980f74e101Schristos /* ok now the variable part - lets read out TLVs*/ 1299c74ad251Schristos while (tlen != 0) { 1300c74ad251Schristos if (tlen < 3) { 1301c74ad251Schristos if (buflen != 0) { 1302c74ad251Schristos stringlen=snprintf(buf,buflen, "\n\t\tran past the end"); 1303c74ad251Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 1304c74ad251Schristos } 1305c74ad251Schristos return plen + 2; 1306c74ad251Schristos } 1307c74ad251Schristos tlv_type = GET_U_1(pptr); 1308c74ad251Schristos pptr++; 1309c74ad251Schristos tlv_len = GET_BE_U_2(pptr); /* length, in *bits* */ 1310c74ad251Schristos ttlv_len = (tlv_len + 7)/8; /* length, in *bytes* */ 13110f74e101Schristos pptr += 2; 13120f74e101Schristos 13130f74e101Schristos switch(tlv_type) { 13140f74e101Schristos case 1: 13150f74e101Schristos if (buflen != 0) { 1316fdccd7e4Schristos stringlen=snprintf(buf,buflen, "\n\t\tcircuit status vector (%u) length: %u: 0x", 13170f74e101Schristos tlv_type, 13180f74e101Schristos tlv_len); 1319fdccd7e4Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 13200f74e101Schristos } 1321c74ad251Schristos while (ttlv_len != 0) { 1322c74ad251Schristos if (tlen < 1) { 13230f74e101Schristos if (buflen != 0) { 1324c74ad251Schristos stringlen=snprintf(buf,buflen, " (ran past the end)"); 1325c74ad251Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 1326c74ad251Schristos } 1327c74ad251Schristos return plen + 2; 1328c74ad251Schristos } 1329c74ad251Schristos ND_TCHECK_1(pptr); 1330c74ad251Schristos if (buflen != 0) { 1331c74ad251Schristos stringlen=snprintf(buf,buflen, "%02x", 1332c74ad251Schristos GET_U_1(pptr)); 1333c74ad251Schristos pptr++; 1334fdccd7e4Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 13350f74e101Schristos } 13360f74e101Schristos ttlv_len--; 1337c74ad251Schristos tlen--; 13380f74e101Schristos } 13390f74e101Schristos break; 13400f74e101Schristos default: 13410f74e101Schristos if (buflen != 0) { 1342fdccd7e4Schristos stringlen=snprintf(buf,buflen, "\n\t\tunknown TLV #%u, length: %u", 13430f74e101Schristos tlv_type, 13440f74e101Schristos tlv_len); 1345fdccd7e4Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 13460f74e101Schristos } 1347c74ad251Schristos if (tlen < ttlv_len) { 1348c74ad251Schristos if (buflen != 0) { 1349c74ad251Schristos stringlen=snprintf(buf,buflen, " (ran past the end)"); 1350c74ad251Schristos UPDATE_BUF_BUFLEN(buf, buflen, stringlen); 13510f74e101Schristos } 13520f74e101Schristos return plen + 2; 1353c74ad251Schristos } 1354c74ad251Schristos tlen -= ttlv_len; 1355c74ad251Schristos break; 1356c74ad251Schristos } 1357c74ad251Schristos } 1358c74ad251Schristos return plen + 2; 13590e9868baSchristos } else { 13600e9868baSchristos /* complain bitterly ? */ 13610e9868baSchristos /* fall through */ 13620e9868baSchristos goto trunc; 13630e9868baSchristos } 13640e9868baSchristos 13650f74e101Schristos trunc: 13660f74e101Schristos return -2; 13670f74e101Schristos } 13680f74e101Schristos 13690f74e101Schristos int 1370b3a00663Schristos decode_prefix6(netdissect_options *ndo, 1371c74ad251Schristos const u_char *pd, u_int itemlen, char *buf, size_t buflen) 13720f74e101Schristos { 1373c74ad251Schristos nd_ipv6 addr; 13740e9868baSchristos u_int plen, plenbytes; 13750f74e101Schristos 13760e9868baSchristos ITEMCHECK(1); 1377c74ad251Schristos plen = GET_U_1(pd); 13780f74e101Schristos if (128 < plen) 13790f74e101Schristos return -1; 13800e9868baSchristos itemlen -= 1; 13810f74e101Schristos 13820f74e101Schristos memset(&addr, 0, sizeof(addr)); 13830e9868baSchristos plenbytes = (plen + 7) / 8; 13840e9868baSchristos ITEMCHECK(plenbytes); 1385c74ad251Schristos GET_CPY_BYTES(&addr, pd + 1, plenbytes); 13860f74e101Schristos if (plen % 8) { 1387c74ad251Schristos addr[plenbytes - 1] &= 13880f74e101Schristos ((0xff00 >> (plen % 8)) & 0xff); 13890f74e101Schristos } 1390c74ad251Schristos snprintf(buf, buflen, "%s/%u", ip6addr_string(ndo, (const u_char *)&addr), plen); 13910e9868baSchristos return 1 + plenbytes; 13920f74e101Schristos 13930e9868baSchristos badtlv: 1394c74ad251Schristos return -2; 13950f74e101Schristos } 13960f74e101Schristos 13970f74e101Schristos static int 1398b3a00663Schristos decode_labeled_prefix6(netdissect_options *ndo, 1399c74ad251Schristos const u_char *pptr, u_int itemlen, char *buf, size_t buflen) 14000f74e101Schristos { 1401c74ad251Schristos nd_ipv6 addr; 14020e9868baSchristos u_int plen, plenbytes; 14030f74e101Schristos 14040e9868baSchristos /* prefix length and label = 4 bytes */ 1405c74ad251Schristos ND_TCHECK_4(pptr); 14060e9868baSchristos ITEMCHECK(4); 1407c74ad251Schristos plen = GET_U_1(pptr); /* get prefix length */ 14080f74e101Schristos 14090f74e101Schristos if (24 > plen) 14100f74e101Schristos return -1; 14110f74e101Schristos 14120f74e101Schristos plen -= 24; /* adjust prefixlen - labellength */ 14130f74e101Schristos 14140f74e101Schristos if (128 < plen) 14150f74e101Schristos return -1; 14160e9868baSchristos itemlen -= 4; 14170f74e101Schristos 14180f74e101Schristos memset(&addr, 0, sizeof(addr)); 14190e9868baSchristos plenbytes = (plen + 7) / 8; 1420c74ad251Schristos GET_CPY_BYTES(&addr, pptr + 4, plenbytes); 14210f74e101Schristos if (plen % 8) { 1422c74ad251Schristos addr[plenbytes - 1] &= 14230f74e101Schristos ((0xff00 >> (plen % 8)) & 0xff); 14240f74e101Schristos } 14250f74e101Schristos /* the label may get offsetted by 4 bits so lets shift it right */ 1426c74ad251Schristos snprintf(buf, buflen, "%s/%u, label:%u %s", 1427c74ad251Schristos ip6addr_string(ndo, (const u_char *)&addr), 14280f74e101Schristos plen, 1429c74ad251Schristos GET_BE_U_3(pptr + 1)>>4, 1430c74ad251Schristos ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); 14310f74e101Schristos 14320e9868baSchristos return 4 + plenbytes; 14330f74e101Schristos 14340f74e101Schristos trunc: 14350f74e101Schristos return -2; 14360e9868baSchristos 14370e9868baSchristos badtlv: 14380e9868baSchristos return -3; 14390f74e101Schristos } 14400f74e101Schristos 14410f74e101Schristos static int 1442b3a00663Schristos decode_labeled_vpn_prefix6(netdissect_options *ndo, 1443c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 14440f74e101Schristos { 1445c74ad251Schristos nd_ipv6 addr; 14460f74e101Schristos u_int plen; 14470f74e101Schristos 1448c74ad251Schristos plen = GET_U_1(pptr); /* get prefix length */ 14490f74e101Schristos 14500f74e101Schristos if ((24+64) > plen) 14510f74e101Schristos return -1; 14520f74e101Schristos 14530f74e101Schristos plen -= (24+64); /* adjust prefixlen - labellength - RD len*/ 14540f74e101Schristos 14550f74e101Schristos if (128 < plen) 14560f74e101Schristos return -1; 14570f74e101Schristos 14580f74e101Schristos memset(&addr, 0, sizeof(addr)); 1459c74ad251Schristos GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8); 14600f74e101Schristos if (plen % 8) { 1461c74ad251Schristos addr[(plen + 7) / 8 - 1] &= 14620f74e101Schristos ((0xff00 >> (plen % 8)) & 0xff); 14630f74e101Schristos } 14640f74e101Schristos /* the label may get offsetted by 4 bits so lets shift it right */ 1465c74ad251Schristos snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", 1466b3a00663Schristos bgp_vpn_rd_print(ndo, pptr+4), 1467c74ad251Schristos ip6addr_string(ndo, (const u_char *)&addr), 14680f74e101Schristos plen, 1469c74ad251Schristos GET_BE_U_3(pptr + 1)>>4, 1470c74ad251Schristos ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); 14710f74e101Schristos 14720f74e101Schristos return 12 + (plen + 7) / 8; 14730f74e101Schristos } 14740f74e101Schristos 14750f74e101Schristos static int 1476b3a00663Schristos decode_clnp_prefix(netdissect_options *ndo, 1477c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 14780f74e101Schristos { 1479b3a00663Schristos uint8_t addr[19]; 14800f74e101Schristos u_int plen; 14810f74e101Schristos 1482c74ad251Schristos plen = GET_U_1(pptr); /* get prefix length */ 14830f74e101Schristos 14840f74e101Schristos if (152 < plen) 14850f74e101Schristos return -1; 14860f74e101Schristos 14870f74e101Schristos memset(&addr, 0, sizeof(addr)); 1488c74ad251Schristos GET_CPY_BYTES(&addr, pptr + 4, (plen + 7) / 8); 14890f74e101Schristos if (plen % 8) { 14900f74e101Schristos addr[(plen + 7) / 8 - 1] &= 14910f74e101Schristos ((0xff00 >> (plen % 8)) & 0xff); 14920f74e101Schristos } 1493c74ad251Schristos /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */ 1494c74ad251Schristos snprintf(buf, buflen, "%s/%u", 1495fdccd7e4Schristos isonsap_string(ndo, addr,(plen + 7) / 8), 14960f74e101Schristos plen); 14970f74e101Schristos 14980f74e101Schristos return 1 + (plen + 7) / 8; 14990f74e101Schristos } 15000f74e101Schristos 15010f74e101Schristos static int 1502b3a00663Schristos decode_labeled_vpn_clnp_prefix(netdissect_options *ndo, 1503c74ad251Schristos const u_char *pptr, char *buf, size_t buflen) 15040f74e101Schristos { 1505b3a00663Schristos uint8_t addr[19]; 15060f74e101Schristos u_int plen; 15070f74e101Schristos 1508c74ad251Schristos plen = GET_U_1(pptr); /* get prefix length */ 15090f74e101Schristos 15100f74e101Schristos if ((24+64) > plen) 15110f74e101Schristos return -1; 15120f74e101Schristos 15130f74e101Schristos plen -= (24+64); /* adjust prefixlen - labellength - RD len*/ 15140f74e101Schristos 15150f74e101Schristos if (152 < plen) 15160f74e101Schristos return -1; 15170f74e101Schristos 15180f74e101Schristos memset(&addr, 0, sizeof(addr)); 1519c74ad251Schristos GET_CPY_BYTES(&addr, pptr + 12, (plen + 7) / 8); 15200f74e101Schristos if (plen % 8) { 1521c74ad251Schristos addr[(plen + 7) / 8 - 1] &= ((0xff00 >> (plen % 8)) & 0xff); 15220f74e101Schristos } 15230f74e101Schristos /* the label may get offsetted by 4 bits so lets shift it right */ 1524c74ad251Schristos /* Cannot use GET_ISONSAP_STRING (not packet buffer pointer) */ 1525c74ad251Schristos snprintf(buf, buflen, "RD: %s, %s/%u, label:%u %s", 1526b3a00663Schristos bgp_vpn_rd_print(ndo, pptr+4), 1527fdccd7e4Schristos isonsap_string(ndo, addr,(plen + 7) / 8), 15280f74e101Schristos plen, 1529c74ad251Schristos GET_BE_U_3(pptr + 1)>>4, 1530c74ad251Schristos ((GET_U_1(pptr + 3) & 1) == 0) ? "(BOGUS: Bottom of Stack NOT set!)" : "(bottom)" ); 15310f74e101Schristos 15320f74e101Schristos return 12 + (plen + 7) / 8; 15330f74e101Schristos } 15340f74e101Schristos 15350f74e101Schristos /* 15360f74e101Schristos * bgp_attr_get_as_size 15370f74e101Schristos * 15380f74e101Schristos * Try to find the size of the ASs encoded in an as-path. It is not obvious, as 15390f74e101Schristos * both Old speakers that do not support 4 byte AS, and the new speakers that do 15400f74e101Schristos * support, exchange AS-Path with the same path-attribute type value 0x02. 15410f74e101Schristos */ 1542c74ad251Schristos static u_int 1543b3a00663Schristos bgp_attr_get_as_size(netdissect_options *ndo, 1544c74ad251Schristos uint8_t bgpa_type, const u_char *pptr, u_int len) 15450f74e101Schristos { 15460f74e101Schristos const u_char *tptr = pptr; 15470f74e101Schristos 15480f74e101Schristos /* 15490f74e101Schristos * If the path attribute is the optional AS4 path type, then we already 15500f74e101Schristos * know, that ASs must be encoded in 4 byte format. 15510f74e101Schristos */ 15520f74e101Schristos if (bgpa_type == BGPTYPE_AS4_PATH) { 15530f74e101Schristos return 4; 15540f74e101Schristos } 15550f74e101Schristos 15560f74e101Schristos /* 15570f74e101Schristos * Let us assume that ASs are of 2 bytes in size, and check if the AS-Path 15580f74e101Schristos * TLV is good. If not, ask the caller to try with AS encoded as 4 bytes 15590f74e101Schristos * each. 15600f74e101Schristos */ 15610f74e101Schristos while (tptr < pptr + len) { 15620f74e101Schristos /* 15630f74e101Schristos * If we do not find a valid segment type, our guess might be wrong. 15640f74e101Schristos */ 1565c74ad251Schristos if (GET_U_1(tptr) < BGP_AS_SEG_TYPE_MIN || GET_U_1(tptr) > BGP_AS_SEG_TYPE_MAX) { 15660f74e101Schristos goto trunc; 15670f74e101Schristos } 1568c74ad251Schristos tptr += 2 + GET_U_1(tptr + 1) * 2; 15690f74e101Schristos } 15700f74e101Schristos 15710f74e101Schristos /* 15720f74e101Schristos * If we correctly reached end of the AS path attribute data content, 15730f74e101Schristos * then most likely ASs were indeed encoded as 2 bytes. 15740f74e101Schristos */ 15750f74e101Schristos if (tptr == pptr + len) { 15760f74e101Schristos return 2; 15770f74e101Schristos } 15780f74e101Schristos 15790f74e101Schristos trunc: 15800f74e101Schristos 15810f74e101Schristos /* 15820f74e101Schristos * We can come here, either we did not have enough data, or if we 15830f74e101Schristos * try to decode 4 byte ASs in 2 byte format. Either way, return 4, 1584*26ba0b50Schristos * so that caller can try to decode each AS as of 4 bytes. If indeed 15850f74e101Schristos * there was not enough data, it will crib and end the parse anyways. 15860f74e101Schristos */ 15870f74e101Schristos return 4; 15880f74e101Schristos } 15890f74e101Schristos 1590c74ad251Schristos /* 1591c74ad251Schristos * The only way to know that a BGP UPDATE message is using add path is 1592c74ad251Schristos * by checking if the capability is in the OPEN message which we may have missed. 1593c74ad251Schristos * So this function checks if it is possible that the update could contain add path 1594c74ad251Schristos * and if so it checks that standard BGP doesn't make sense. 1595c74ad251Schristos */ 1596c74ad251Schristos static int 1597c74ad251Schristos check_add_path(netdissect_options *ndo, const u_char *pptr, u_int length, 1598c74ad251Schristos u_int max_prefix_length) 1599c74ad251Schristos { 1600c74ad251Schristos u_int offset, prefix_length; 1601c74ad251Schristos 1602c74ad251Schristos if (length < 5) { 1603c74ad251Schristos return 0; 1604c74ad251Schristos } 1605c74ad251Schristos 1606c74ad251Schristos /* 1607*26ba0b50Schristos * Scan through the NLRI information under the assumption that 1608c74ad251Schristos * it doesn't have path IDs. 1609c74ad251Schristos */ 1610c74ad251Schristos for (offset = 0; offset < length;) { 1611c74ad251Schristos offset += 4; 1612c74ad251Schristos if (!ND_TTEST_1(pptr + offset)) { 1613c74ad251Schristos /* We ran out of captured data; quit scanning. */ 1614c74ad251Schristos break; 1615c74ad251Schristos } 1616c74ad251Schristos prefix_length = GET_U_1(pptr + offset); 1617c74ad251Schristos /* 1618c74ad251Schristos * Add 4 to cover the path id 1619c74ad251Schristos * and check the prefix length isn't greater than 32/128. 1620c74ad251Schristos */ 1621c74ad251Schristos if (prefix_length > max_prefix_length) { 1622c74ad251Schristos return 0; 1623c74ad251Schristos } 1624c74ad251Schristos /* Add 1 for the prefix_length byte and prefix_length to cover the address */ 1625c74ad251Schristos offset += 1 + ((prefix_length + 7) / 8); 1626c74ad251Schristos } 1627c74ad251Schristos /* check we haven't gone past the end of the section */ 1628c74ad251Schristos if (offset > length) { 1629c74ad251Schristos return 0; 1630c74ad251Schristos } 1631c74ad251Schristos 1632c74ad251Schristos /* check it's not standard BGP */ 1633c74ad251Schristos for (offset = 0; offset < length; ) { 1634c74ad251Schristos if (!ND_TTEST_1(pptr + offset)) { 1635c74ad251Schristos /* We ran out of captured data; quit scanning. */ 1636c74ad251Schristos break; 1637c74ad251Schristos } 1638c74ad251Schristos prefix_length = GET_U_1(pptr + offset); 1639c74ad251Schristos /* 1640c74ad251Schristos * If the prefix_length is zero (0.0.0.0/0) 1641c74ad251Schristos * and since it's not the only address (length >= 5) 1642c74ad251Schristos * then it is add-path 1643c74ad251Schristos */ 1644c74ad251Schristos if (prefix_length < 1 || prefix_length > max_prefix_length) { 1645c74ad251Schristos return 1; 1646c74ad251Schristos } 1647c74ad251Schristos offset += 1 + ((prefix_length + 7) / 8); 1648c74ad251Schristos } 1649c74ad251Schristos if (offset > length) { 1650c74ad251Schristos return 1; 1651c74ad251Schristos } 1652c74ad251Schristos 1653c74ad251Schristos /* assume not add-path by default */ 1654c74ad251Schristos return 0; 1655c74ad251Schristos } 1656c74ad251Schristos 1657c74ad251Schristos static int 1658c74ad251Schristos bgp_mp_af_print(netdissect_options *ndo, 1659c74ad251Schristos const u_char *tptr, u_int tlen, 1660c74ad251Schristos uint16_t *afp, uint8_t *safip) 1661c74ad251Schristos { 1662c74ad251Schristos uint16_t af; 1663c74ad251Schristos uint8_t safi; 1664c74ad251Schristos 1665c74ad251Schristos af = GET_BE_U_2(tptr); 1666c74ad251Schristos *afp = af; 1667c74ad251Schristos safi = GET_U_1(tptr + 2); 1668c74ad251Schristos *safip = safi; 1669c74ad251Schristos 1670c74ad251Schristos ND_PRINT("\n\t AFI: %s (%u), %sSAFI: %s (%u)", 1671c74ad251Schristos tok2str(af_values, "Unknown AFI", af), 1672c74ad251Schristos af, 1673c74ad251Schristos (safi>128) ? "vendor specific " : "", /* 128 is meanwhile wellknown */ 1674c74ad251Schristos tok2str(bgp_safi_values, "Unknown SAFI", safi), 1675c74ad251Schristos safi); 1676c74ad251Schristos 1677c74ad251Schristos switch(af<<8 | safi) { 1678c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_UNICAST): 1679c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_MULTICAST): 1680c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST): 1681c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_LABUNICAST): 1682c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO): 1683c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST): 1684c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST): 1685c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST): 1686c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): 1687c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_MDT): 1688c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_UNICAST): 1689c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_MULTICAST): 1690c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST): 1691c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST): 1692c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST): 1693c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST): 1694c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST): 1695c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_UNICAST): 1696c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST): 1697c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST): 1698c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST): 1699c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST): 1700c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST): 1701c74ad251Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST): 1702c74ad251Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST): 1703c74ad251Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST): 1704c74ad251Schristos case (AFNUM_VPLS<<8 | SAFNUM_VPLS): 1705c74ad251Schristos break; 1706c74ad251Schristos default: 1707c74ad251Schristos ND_TCHECK_LEN(tptr, tlen); 1708c74ad251Schristos ND_PRINT("\n\t no AFI %u / SAFI %u decoder", af, safi); 1709c74ad251Schristos if (ndo->ndo_vflag <= 1) 1710c74ad251Schristos print_unknown_data(ndo, tptr, "\n\t ", tlen); 1711c74ad251Schristos return -1; 1712c74ad251Schristos } 1713c74ad251Schristos return 0; 1714c74ad251Schristos trunc: 1715c74ad251Schristos return -2; 1716c74ad251Schristos } 1717c74ad251Schristos 1718c74ad251Schristos static int 1719c74ad251Schristos bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi, 1720c74ad251Schristos const u_char *tptr, u_int len, 1721c74ad251Schristos char *buf, size_t buflen, 1722c74ad251Schristos int add_path4, int add_path6) 1723c74ad251Schristos { 1724c74ad251Schristos int advance; 1725c74ad251Schristos u_int path_id = 0; 1726c74ad251Schristos 1727c74ad251Schristos switch (af<<8 | safi) { 1728c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_UNICAST): 1729c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_MULTICAST): 1730c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST): 1731c74ad251Schristos if (add_path4) { 1732c74ad251Schristos path_id = GET_BE_U_4(tptr); 1733c74ad251Schristos tptr += 4; 1734c74ad251Schristos } 1735c74ad251Schristos advance = decode_prefix4(ndo, tptr, len, buf, buflen); 1736c74ad251Schristos if (advance == -1) 1737c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1738c74ad251Schristos else if (advance == -2) 1739c74ad251Schristos break; /* bytes left, but not enough */ 1740c74ad251Schristos else 1741c74ad251Schristos ND_PRINT("\n\t %s", buf); 1742c74ad251Schristos if (add_path4) { 1743c74ad251Schristos ND_PRINT(" Path Id: %u", path_id); 1744c74ad251Schristos advance += 4; 1745c74ad251Schristos } 1746c74ad251Schristos break; 1747c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_LABUNICAST): 1748c74ad251Schristos advance = decode_labeled_prefix4(ndo, tptr, len, buf, buflen); 1749c74ad251Schristos if (advance == -1) 1750c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1751c74ad251Schristos else if (advance == -2) 1752c74ad251Schristos goto trunc; 1753c74ad251Schristos else if (advance == -3) 1754c74ad251Schristos break; /* bytes left, but not enough */ 1755c74ad251Schristos else 1756c74ad251Schristos ND_PRINT("\n\t %s", buf); 1757c74ad251Schristos break; 1758c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST): 1759c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST): 1760c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST): 1761c74ad251Schristos advance = decode_labeled_vpn_prefix4(ndo, tptr, buf, buflen); 1762c74ad251Schristos if (advance == -1) 1763c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1764c74ad251Schristos else 1765c74ad251Schristos ND_PRINT("\n\t %s", buf); 1766c74ad251Schristos break; 1767c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO): 1768c74ad251Schristos advance = decode_rt_routing_info(ndo, tptr); 1769c74ad251Schristos break; 1770c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): /* fall through */ 1771c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_MULTICAST_VPN): 1772c74ad251Schristos advance = decode_multicast_vpn(ndo, tptr, buf, buflen); 1773c74ad251Schristos if (advance == -1) 1774c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1775c74ad251Schristos else if (advance == -2) 1776c74ad251Schristos goto trunc; 1777c74ad251Schristos else 1778c74ad251Schristos ND_PRINT("\n\t %s", buf); 1779c74ad251Schristos break; 1780c74ad251Schristos 1781c74ad251Schristos case (AFNUM_INET<<8 | SAFNUM_MDT): 1782c74ad251Schristos advance = decode_mdt_vpn_nlri(ndo, tptr, buf, buflen); 1783c74ad251Schristos if (advance == -1) 1784c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1785c74ad251Schristos else if (advance == -2) 1786c74ad251Schristos goto trunc; 1787c74ad251Schristos else 1788c74ad251Schristos ND_PRINT("\n\t %s", buf); 1789c74ad251Schristos break; 1790c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_UNICAST): 1791c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_MULTICAST): 1792c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST): 1793c74ad251Schristos if (add_path6) { 1794c74ad251Schristos path_id = GET_BE_U_4(tptr); 1795c74ad251Schristos tptr += 4; 1796c74ad251Schristos } 1797c74ad251Schristos advance = decode_prefix6(ndo, tptr, len, buf, buflen); 1798c74ad251Schristos if (advance == -1) 1799c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1800c74ad251Schristos else if (advance == -2) 1801c74ad251Schristos break; /* bytes left, but not enough */ 1802c74ad251Schristos else 1803c74ad251Schristos ND_PRINT("\n\t %s", buf); 1804c74ad251Schristos if (add_path6) { 1805c74ad251Schristos ND_PRINT(" Path Id: %u", path_id); 1806c74ad251Schristos advance += 4; 1807c74ad251Schristos } 1808c74ad251Schristos break; 1809c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST): 1810c74ad251Schristos advance = decode_labeled_prefix6(ndo, tptr, len, buf, buflen); 1811c74ad251Schristos if (advance == -1) 1812c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1813c74ad251Schristos else if (advance == -2) 1814c74ad251Schristos goto trunc; 1815c74ad251Schristos else if (advance == -3) 1816c74ad251Schristos break; /* bytes left, but not enough */ 1817c74ad251Schristos else 1818c74ad251Schristos ND_PRINT("\n\t %s", buf); 1819c74ad251Schristos break; 1820c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST): 1821c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST): 1822c74ad251Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST): 1823c74ad251Schristos advance = decode_labeled_vpn_prefix6(ndo, tptr, buf, buflen); 1824c74ad251Schristos if (advance == -1) 1825c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1826c74ad251Schristos else 1827c74ad251Schristos ND_PRINT("\n\t %s", buf); 1828c74ad251Schristos break; 1829c74ad251Schristos case (AFNUM_VPLS<<8 | SAFNUM_VPLS): 1830c74ad251Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST): 1831c74ad251Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST): 1832c74ad251Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST): 1833c74ad251Schristos advance = decode_labeled_vpn_l2(ndo, tptr, buf, buflen); 1834c74ad251Schristos if (advance == -1) 1835c74ad251Schristos ND_PRINT("\n\t (illegal length)"); 1836c74ad251Schristos else if (advance == -2) 1837c74ad251Schristos goto trunc; 1838c74ad251Schristos else 1839c74ad251Schristos ND_PRINT("\n\t %s", buf); 1840c74ad251Schristos break; 1841c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_UNICAST): 1842c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST): 1843c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST): 1844c74ad251Schristos advance = decode_clnp_prefix(ndo, tptr, buf, buflen); 1845c74ad251Schristos if (advance == -1) 1846c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1847c74ad251Schristos else 1848c74ad251Schristos ND_PRINT("\n\t %s", buf); 1849c74ad251Schristos break; 1850c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST): 1851c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST): 1852c74ad251Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST): 1853c74ad251Schristos advance = decode_labeled_vpn_clnp_prefix(ndo, tptr, buf, buflen); 1854c74ad251Schristos if (advance == -1) 1855c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 1856c74ad251Schristos else 1857c74ad251Schristos ND_PRINT("\n\t %s", buf); 1858c74ad251Schristos break; 1859c74ad251Schristos default: 1860c74ad251Schristos /* 1861c74ad251Schristos * This should not happen, we should have been protected 1862c74ad251Schristos * by bgp_mp_af_print()'s return value. 1863c74ad251Schristos */ 1864c74ad251Schristos ND_PRINT("\n\t ERROR: no AFI %u / SAFI %u decoder", af, safi); 1865c74ad251Schristos advance = -4; 1866c74ad251Schristos break; 1867c74ad251Schristos } 1868c74ad251Schristos return advance; 1869c74ad251Schristos trunc: /* we rely on the caller to recognize -2 return value */ 1870c74ad251Schristos return -2; 1871c74ad251Schristos } 1872c74ad251Schristos 18730f74e101Schristos static int 1874b3a00663Schristos bgp_attr_print(netdissect_options *ndo, 1875c74ad251Schristos uint8_t atype, const u_char *pptr, u_int len, 1876c74ad251Schristos const unsigned attr_set_level) 18770f74e101Schristos { 1878c74ad251Schristos /* allocate space for the largest possible string */ 1879c74ad251Schristos char astostr[AS_STR_SIZE]; 1880c74ad251Schristos u_int i; 1881b3a00663Schristos uint16_t af; 1882b3a00663Schristos uint8_t safi, snpa, nhlen; 18830f74e101Schristos int advance; 18840e9868baSchristos u_int tlen; 18850f74e101Schristos const u_char *tptr; 18860f74e101Schristos char buf[MAXHOSTNAMELEN + 100]; 1887c74ad251Schristos u_int as_size; 1888c74ad251Schristos int add_path4, add_path6; 1889c74ad251Schristos int ret; 18900f74e101Schristos 18910f74e101Schristos tptr = pptr; 18920f74e101Schristos tlen = len; 18930f74e101Schristos 18940e9868baSchristos switch (atype) { 18950f74e101Schristos case BGPTYPE_ORIGIN: 18960f74e101Schristos if (len != 1) 1897c74ad251Schristos ND_PRINT("invalid len"); 18980f74e101Schristos else { 1899c74ad251Schristos ND_PRINT("%s", tok2str(bgp_origin_values, 19000f74e101Schristos "Unknown Origin Typecode", 1901c74ad251Schristos GET_U_1(tptr))); 19020f74e101Schristos } 19030f74e101Schristos break; 19040f74e101Schristos 19050f74e101Schristos /* 19060f74e101Schristos * Process AS4 byte path and AS2 byte path attributes here. 19070f74e101Schristos */ 19080f74e101Schristos case BGPTYPE_AS4_PATH: 19090f74e101Schristos case BGPTYPE_AS_PATH: 19100f74e101Schristos if (len % 2) { 1911c74ad251Schristos ND_PRINT("invalid len"); 19120f74e101Schristos break; 19130f74e101Schristos } 19140f74e101Schristos if (!len) { 1915c74ad251Schristos ND_PRINT("empty"); 19160f74e101Schristos break; 19170f74e101Schristos } 19180f74e101Schristos 19190f74e101Schristos /* 19200f74e101Schristos * BGP updates exchanged between New speakers that support 4 19210f74e101Schristos * byte AS, ASs are always encoded in 4 bytes. There is no 19220f74e101Schristos * definitive way to find this, just by the packet's 19230f74e101Schristos * contents. So, check for packet's TLV's sanity assuming 19240f74e101Schristos * 2 bytes first, and it does not pass, assume that ASs are 19250f74e101Schristos * encoded in 4 bytes format and move on. 19260f74e101Schristos */ 1927b3a00663Schristos as_size = bgp_attr_get_as_size(ndo, atype, pptr, len); 19280f74e101Schristos 19290f74e101Schristos while (tptr < pptr + len) { 1930c74ad251Schristos ND_PRINT("%s", tok2str(bgp_as_path_segment_open_values, 1931c74ad251Schristos "?", GET_U_1(tptr))); 1932c74ad251Schristos for (i = 0; i < GET_U_1(tptr + 1) * as_size; i += as_size) { 1933c74ad251Schristos ND_TCHECK_LEN(tptr + 2 + i, as_size); 1934c74ad251Schristos ND_PRINT("%s ", 1935b3a00663Schristos as_printf(ndo, astostr, sizeof(astostr), 19360f74e101Schristos as_size == 2 ? 1937c74ad251Schristos GET_BE_U_2(tptr + i + 2) : 1938c74ad251Schristos GET_BE_U_4(tptr + i + 2))); 19390f74e101Schristos } 1940c74ad251Schristos ND_PRINT("%s", tok2str(bgp_as_path_segment_close_values, 1941c74ad251Schristos "?", GET_U_1(tptr))); 1942c74ad251Schristos tptr += 2 + GET_U_1(tptr + 1) * as_size; 19430f74e101Schristos } 19440f74e101Schristos break; 19450f74e101Schristos case BGPTYPE_NEXT_HOP: 19460f74e101Schristos if (len != 4) 1947c74ad251Schristos ND_PRINT("invalid len"); 19480f74e101Schristos else { 1949c74ad251Schristos ND_PRINT("%s", GET_IPADDR_STRING(tptr)); 19500f74e101Schristos } 19510f74e101Schristos break; 19520f74e101Schristos case BGPTYPE_MULTI_EXIT_DISC: 19530f74e101Schristos case BGPTYPE_LOCAL_PREF: 19540f74e101Schristos if (len != 4) 1955c74ad251Schristos ND_PRINT("invalid len"); 19560f74e101Schristos else { 1957c74ad251Schristos ND_PRINT("%u", GET_BE_U_4(tptr)); 19580f74e101Schristos } 19590f74e101Schristos break; 19600f74e101Schristos case BGPTYPE_ATOMIC_AGGREGATE: 19610f74e101Schristos if (len != 0) 1962c74ad251Schristos ND_PRINT("invalid len"); 19630f74e101Schristos break; 19640f74e101Schristos case BGPTYPE_AGGREGATOR: 19650f74e101Schristos 19660f74e101Schristos /* 19670f74e101Schristos * Depending on the AS encoded is of 2 bytes or of 4 bytes, 19680f74e101Schristos * the length of this PA can be either 6 bytes or 8 bytes. 19690f74e101Schristos */ 19700f74e101Schristos if (len != 6 && len != 8) { 1971c74ad251Schristos ND_PRINT("invalid len"); 19720f74e101Schristos break; 19730f74e101Schristos } 1974c74ad251Schristos ND_TCHECK_LEN(tptr, len); 19750f74e101Schristos if (len == 6) { 1976c74ad251Schristos ND_PRINT(" AS #%s, origin %s", 1977c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(tptr)), 1978c74ad251Schristos GET_IPADDR_STRING(tptr + 2)); 19790f74e101Schristos } else { 1980c74ad251Schristos ND_PRINT(" AS #%s, origin %s", 1981b3a00663Schristos as_printf(ndo, astostr, sizeof(astostr), 1982c74ad251Schristos GET_BE_U_4(tptr)), GET_IPADDR_STRING(tptr + 4)); 19830f74e101Schristos } 19840f74e101Schristos break; 19850f74e101Schristos case BGPTYPE_AGGREGATOR4: 19860f74e101Schristos if (len != 8) { 1987c74ad251Schristos ND_PRINT("invalid len"); 19880f74e101Schristos break; 19890f74e101Schristos } 1990c74ad251Schristos ND_PRINT(" AS #%s, origin %s", 1991c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(tptr)), 1992c74ad251Schristos GET_IPADDR_STRING(tptr + 4)); 19930f74e101Schristos break; 19940f74e101Schristos case BGPTYPE_COMMUNITIES: 19950f74e101Schristos if (len % 4) { 1996c74ad251Schristos ND_PRINT("invalid len"); 19970f74e101Schristos break; 19980f74e101Schristos } 1999c74ad251Schristos while (tlen != 0) { 2000b3a00663Schristos uint32_t comm; 2001c74ad251Schristos ND_TCHECK_4(tptr); 2002c74ad251Schristos if (tlen < 4) 2003c74ad251Schristos goto trunc; 2004c74ad251Schristos comm = GET_BE_U_4(tptr); 20050f74e101Schristos switch (comm) { 20060f74e101Schristos case BGP_COMMUNITY_NO_EXPORT: 2007c74ad251Schristos ND_PRINT(" NO_EXPORT"); 20080f74e101Schristos break; 20090f74e101Schristos case BGP_COMMUNITY_NO_ADVERT: 2010c74ad251Schristos ND_PRINT(" NO_ADVERTISE"); 20110f74e101Schristos break; 20120f74e101Schristos case BGP_COMMUNITY_NO_EXPORT_SUBCONFED: 2013c74ad251Schristos ND_PRINT(" NO_EXPORT_SUBCONFED"); 20140f74e101Schristos break; 20150f74e101Schristos default: 2016c74ad251Schristos ND_PRINT("%u:%u%s", 20170f74e101Schristos (comm >> 16) & 0xffff, 20180f74e101Schristos comm & 0xffff, 2019c74ad251Schristos (tlen>4) ? ", " : ""); 20200f74e101Schristos break; 20210f74e101Schristos } 20220f74e101Schristos tlen -=4; 20230f74e101Schristos tptr +=4; 20240f74e101Schristos } 20250f74e101Schristos break; 20260f74e101Schristos case BGPTYPE_ORIGINATOR_ID: 20270f74e101Schristos if (len != 4) { 2028c74ad251Schristos ND_PRINT("invalid len"); 20290f74e101Schristos break; 20300f74e101Schristos } 2031c74ad251Schristos ND_PRINT("%s",GET_IPADDR_STRING(tptr)); 20320f74e101Schristos break; 20330f74e101Schristos case BGPTYPE_CLUSTER_LIST: 20340f74e101Schristos if (len % 4) { 2035c74ad251Schristos ND_PRINT("invalid len"); 20360f74e101Schristos break; 20370f74e101Schristos } 2038c74ad251Schristos while (tlen != 0) { 2039c74ad251Schristos if (tlen < 4) 2040c74ad251Schristos goto trunc; 2041c74ad251Schristos ND_PRINT("%s%s", 2042c74ad251Schristos GET_IPADDR_STRING(tptr), 2043c74ad251Schristos (tlen>4) ? ", " : ""); 20440f74e101Schristos tlen -=4; 20450f74e101Schristos tptr +=4; 20460f74e101Schristos } 20470f74e101Schristos break; 20480f74e101Schristos case BGPTYPE_MP_REACH_NLRI: 2049c74ad251Schristos ND_TCHECK_3(tptr); 2050c74ad251Schristos if (tlen < 3) 2051c74ad251Schristos goto trunc; 2052c74ad251Schristos ret = bgp_mp_af_print(ndo, tptr, tlen, &af, &safi); 2053c74ad251Schristos if (ret == -2) 2054c74ad251Schristos goto trunc; 2055c74ad251Schristos if (ret < 0) 20560f74e101Schristos break; 20570f74e101Schristos 20580f74e101Schristos tptr += 3; 2059c74ad251Schristos tlen -= 3; 20600f74e101Schristos 2061c74ad251Schristos ND_TCHECK_1(tptr); 2062c74ad251Schristos if (tlen < 1) 2063c74ad251Schristos goto trunc; 2064c74ad251Schristos nhlen = GET_U_1(tptr); 20650f74e101Schristos tptr++; 2066c74ad251Schristos tlen--; 20670f74e101Schristos 2068c74ad251Schristos if (nhlen) { 2069c74ad251Schristos u_int nnh = 0; 2070c74ad251Schristos uint8_t tnhlen = nhlen; 2071c74ad251Schristos if (tlen < tnhlen) 2072c74ad251Schristos goto trunc; 2073c74ad251Schristos ND_PRINT("\n\t nexthop: "); 2074c74ad251Schristos while (tnhlen != 0) { 2075870189d2Schristos if (nnh++ > 0) { 2076c74ad251Schristos ND_PRINT(", " ); 2077870189d2Schristos } 20780f74e101Schristos switch(af<<8 | safi) { 20790f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_UNICAST): 20800f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_MULTICAST): 20810f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_UNIMULTICAST): 20820f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_LABUNICAST): 20830f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_RT_ROUTING_INFO): 20840f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_MULTICAST_VPN): 20850f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_MDT): 2086c74ad251Schristos if (tnhlen < sizeof(nd_ipv4)) { 2087c74ad251Schristos ND_PRINT("invalid len"); 2088c74ad251Schristos tptr += tnhlen; 2089c74ad251Schristos tlen -= tnhlen; 2090c74ad251Schristos tnhlen = 0; 20910f74e101Schristos } else { 2092c74ad251Schristos ND_PRINT("%s",GET_IPADDR_STRING(tptr)); 2093c74ad251Schristos tptr += sizeof(nd_ipv4); 2094c74ad251Schristos tnhlen -= sizeof(nd_ipv4); 2095c74ad251Schristos tlen -= sizeof(nd_ipv4); 20960f74e101Schristos } 20970f74e101Schristos break; 20980f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_VPNUNICAST): 20990f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_VPNMULTICAST): 21000f74e101Schristos case (AFNUM_INET<<8 | SAFNUM_VPNUNIMULTICAST): 2101c74ad251Schristos if (tnhlen < sizeof(nd_ipv4)+BGP_VPN_RD_LEN) { 2102c74ad251Schristos ND_PRINT("invalid len"); 2103c74ad251Schristos tptr += tnhlen; 2104c74ad251Schristos tlen -= tnhlen; 2105c74ad251Schristos tnhlen = 0; 21060f74e101Schristos } else { 2107c74ad251Schristos ND_PRINT("RD: %s, %s", 2108b3a00663Schristos bgp_vpn_rd_print(ndo, tptr), 2109c74ad251Schristos GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN)); 2110c74ad251Schristos tptr += (sizeof(nd_ipv4)+BGP_VPN_RD_LEN); 2111c74ad251Schristos tlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN); 2112c74ad251Schristos tnhlen -= (sizeof(nd_ipv4)+BGP_VPN_RD_LEN); 21130f74e101Schristos } 21140f74e101Schristos break; 21150f74e101Schristos case (AFNUM_INET6<<8 | SAFNUM_UNICAST): 21160f74e101Schristos case (AFNUM_INET6<<8 | SAFNUM_MULTICAST): 21170f74e101Schristos case (AFNUM_INET6<<8 | SAFNUM_UNIMULTICAST): 21180f74e101Schristos case (AFNUM_INET6<<8 | SAFNUM_LABUNICAST): 2119c74ad251Schristos if (tnhlen < sizeof(nd_ipv6)) { 2120c74ad251Schristos ND_PRINT("invalid len"); 2121c74ad251Schristos tptr += tnhlen; 2122c74ad251Schristos tlen -= tnhlen; 2123c74ad251Schristos tnhlen = 0; 21240f74e101Schristos } else { 2125c74ad251Schristos ND_PRINT("%s", GET_IP6ADDR_STRING(tptr)); 2126c74ad251Schristos tptr += sizeof(nd_ipv6); 2127c74ad251Schristos tlen -= sizeof(nd_ipv6); 2128c74ad251Schristos tnhlen -= sizeof(nd_ipv6); 21290f74e101Schristos } 21300f74e101Schristos break; 21310f74e101Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNUNICAST): 21320f74e101Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNMULTICAST): 21330f74e101Schristos case (AFNUM_INET6<<8 | SAFNUM_VPNUNIMULTICAST): 2134c74ad251Schristos if (tnhlen < sizeof(nd_ipv6)+BGP_VPN_RD_LEN) { 2135c74ad251Schristos ND_PRINT("invalid len"); 2136c74ad251Schristos tptr += tnhlen; 2137c74ad251Schristos tlen -= tnhlen; 2138c74ad251Schristos tnhlen = 0; 21390f74e101Schristos } else { 2140c74ad251Schristos ND_PRINT("RD: %s, %s", 2141b3a00663Schristos bgp_vpn_rd_print(ndo, tptr), 2142c74ad251Schristos GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN)); 2143c74ad251Schristos tptr += (sizeof(nd_ipv6)+BGP_VPN_RD_LEN); 2144c74ad251Schristos tlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN); 2145c74ad251Schristos tnhlen -= (sizeof(nd_ipv6)+BGP_VPN_RD_LEN); 21460f74e101Schristos } 21470f74e101Schristos break; 21480f74e101Schristos case (AFNUM_VPLS<<8 | SAFNUM_VPLS): 21490f74e101Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNICAST): 21500f74e101Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST): 21510f74e101Schristos case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST): 2152c74ad251Schristos if (tnhlen < sizeof(nd_ipv4)) { 2153c74ad251Schristos ND_PRINT("invalid len"); 2154c74ad251Schristos tptr += tnhlen; 2155c74ad251Schristos tlen -= tnhlen; 2156c74ad251Schristos tnhlen = 0; 21570f74e101Schristos } else { 2158c74ad251Schristos ND_PRINT("%s", GET_IPADDR_STRING(tptr)); 2159c74ad251Schristos tptr += (sizeof(nd_ipv4)); 2160c74ad251Schristos tlen -= (sizeof(nd_ipv4)); 2161c74ad251Schristos tnhlen -= (sizeof(nd_ipv4)); 21620f74e101Schristos } 21630f74e101Schristos break; 21640f74e101Schristos case (AFNUM_NSAP<<8 | SAFNUM_UNICAST): 21650f74e101Schristos case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST): 21660f74e101Schristos case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST): 2167c74ad251Schristos ND_PRINT("%s", GET_ISONSAP_STRING(tptr, tnhlen)); 2168c74ad251Schristos tptr += tnhlen; 2169c74ad251Schristos tlen -= tnhlen; 2170c74ad251Schristos tnhlen = 0; 21710f74e101Schristos break; 21720f74e101Schristos 21730f74e101Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNUNICAST): 21740f74e101Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNMULTICAST): 21750f74e101Schristos case (AFNUM_NSAP<<8 | SAFNUM_VPNUNIMULTICAST): 2176c74ad251Schristos if (tnhlen < BGP_VPN_RD_LEN+1) { 2177c74ad251Schristos ND_PRINT("invalid len"); 2178c74ad251Schristos tptr += tnhlen; 2179c74ad251Schristos tlen -= tnhlen; 2180c74ad251Schristos tnhlen = 0; 21810f74e101Schristos } else { 2182c74ad251Schristos ND_TCHECK_LEN(tptr, tnhlen); 2183c74ad251Schristos ND_PRINT("RD: %s, %s", 2184b3a00663Schristos bgp_vpn_rd_print(ndo, tptr), 2185c74ad251Schristos GET_ISONSAP_STRING(tptr+BGP_VPN_RD_LEN,tnhlen-BGP_VPN_RD_LEN)); 21860f74e101Schristos /* rfc986 mapped IPv4 address ? */ 2187c74ad251Schristos if (GET_BE_U_4(tptr + BGP_VPN_RD_LEN) == 0x47000601) 2188c74ad251Schristos ND_PRINT(" = %s", GET_IPADDR_STRING(tptr+BGP_VPN_RD_LEN+4)); 21890f74e101Schristos /* rfc1888 mapped IPv6 address ? */ 2190c74ad251Schristos else if (GET_BE_U_3(tptr + BGP_VPN_RD_LEN) == 0x350000) 2191c74ad251Schristos ND_PRINT(" = %s", GET_IP6ADDR_STRING(tptr+BGP_VPN_RD_LEN+3)); 2192c74ad251Schristos tptr += tnhlen; 2193c74ad251Schristos tlen -= tnhlen; 2194c74ad251Schristos tnhlen = 0; 21950f74e101Schristos } 21960f74e101Schristos break; 21970f74e101Schristos default: 2198c74ad251Schristos /* 2199c74ad251Schristos * bgp_mp_af_print() should have saved us from 2200c74ad251Schristos * an unsupported AFI/SAFI. 2201c74ad251Schristos */ 2202c74ad251Schristos ND_PRINT("ERROR: no AFI %u/SAFI %u nexthop decoder", af, safi); 2203c74ad251Schristos tptr += tnhlen; 2204c74ad251Schristos tlen -= tnhlen; 2205c74ad251Schristos tnhlen = 0; 22060f74e101Schristos goto done; 22070f74e101Schristos break; 22080f74e101Schristos } 22090f74e101Schristos } 22100f74e101Schristos } 2211c74ad251Schristos ND_PRINT(", nh-length: %u", nhlen); 22120f74e101Schristos 2213c74ad251Schristos /* As per RFC 2858; this is reserved in RFC 4760 */ 2214c74ad251Schristos if (tlen < 1) 2215c74ad251Schristos goto trunc; 2216c74ad251Schristos snpa = GET_U_1(tptr); 22170f74e101Schristos tptr++; 2218c74ad251Schristos tlen--; 22190f74e101Schristos 22200f74e101Schristos if (snpa) { 2221c74ad251Schristos ND_PRINT("\n\t %u SNPA", snpa); 2222c74ad251Schristos for (/*nothing*/; snpa != 0; snpa--) { 2223c74ad251Schristos uint8_t snpalen; 2224c74ad251Schristos if (tlen < 1) 2225c74ad251Schristos goto trunc; 2226c74ad251Schristos snpalen = GET_U_1(tptr); 2227c74ad251Schristos ND_PRINT("\n\t %u bytes", snpalen); 2228c74ad251Schristos tptr++; 2229c74ad251Schristos tlen--; 2230c74ad251Schristos if (tlen < snpalen) 2231c74ad251Schristos goto trunc; 2232c74ad251Schristos ND_TCHECK_LEN(tptr, snpalen); 2233c74ad251Schristos tptr += snpalen; 2234c74ad251Schristos tlen -= snpalen; 22350f74e101Schristos } 22360f74e101Schristos } else { 2237c74ad251Schristos ND_PRINT(", no SNPA"); 22380f74e101Schristos } 22390f74e101Schristos 2240*26ba0b50Schristos add_path4 = check_add_path(ndo, tptr, 2241*26ba0b50Schristos (len-ND_BYTES_BETWEEN(pptr, tptr)), 32); 2242*26ba0b50Schristos add_path6 = check_add_path(ndo, tptr, 2243*26ba0b50Schristos (len-ND_BYTES_BETWEEN(pptr, tptr)), 128); 2244c74ad251Schristos 224572c96ff3Schristos while (tptr < pptr + len) { 2246c74ad251Schristos advance = bgp_nlri_print(ndo, af, safi, tptr, len, buf, sizeof(buf), 2247c74ad251Schristos add_path4, add_path6); 2248c74ad251Schristos if (advance == -2) 22490f74e101Schristos goto trunc; 22500f74e101Schristos if (advance < 0) 22510f74e101Schristos break; 22520f74e101Schristos tptr += advance; 22530f74e101Schristos } 22540f74e101Schristos break; 22550f74e101Schristos 22560f74e101Schristos case BGPTYPE_MP_UNREACH_NLRI: 2257c74ad251Schristos ND_TCHECK_LEN(tptr, BGP_MP_NLRI_MINSIZE); 2258c74ad251Schristos ret = bgp_mp_af_print(ndo, tptr, tlen, &af, &safi); 2259c74ad251Schristos if (ret == -2) 2260c74ad251Schristos goto trunc; 2261c74ad251Schristos if (ret < 0) 2262c74ad251Schristos break; 22630f74e101Schristos 22640f74e101Schristos if (len == BGP_MP_NLRI_MINSIZE) 2265c74ad251Schristos ND_PRINT("\n\t End-of-Rib Marker (empty NLRI)"); 22660f74e101Schristos 22670f74e101Schristos tptr += 3; 22680f74e101Schristos 2269*26ba0b50Schristos add_path4 = check_add_path(ndo, tptr, 2270*26ba0b50Schristos (len-ND_BYTES_BETWEEN(pptr, tptr)), 32); 2271*26ba0b50Schristos add_path6 = check_add_path(ndo, tptr, 2272*26ba0b50Schristos (len-ND_BYTES_BETWEEN(pptr, tptr)), 128); 2273c74ad251Schristos 227472c96ff3Schristos while (tptr < pptr + len) { 2275c74ad251Schristos advance = bgp_nlri_print(ndo, af, safi, tptr, len, buf, sizeof(buf), 2276c74ad251Schristos add_path4, add_path6); 2277c74ad251Schristos if (advance == -2) 22780f74e101Schristos goto trunc; 22790f74e101Schristos if (advance < 0) 22800f74e101Schristos break; 22810f74e101Schristos tptr += advance; 22820f74e101Schristos } 22830f74e101Schristos break; 22840f74e101Schristos case BGPTYPE_EXTD_COMMUNITIES: 22850f74e101Schristos if (len % 8) { 2286c74ad251Schristos ND_PRINT("invalid len"); 22870f74e101Schristos break; 22880f74e101Schristos } 2289c74ad251Schristos while (tlen != 0) { 2290b3a00663Schristos uint16_t extd_comm; 22910f74e101Schristos 2292c74ad251Schristos ND_TCHECK_2(tptr); 2293c74ad251Schristos if (tlen < 2) 2294c74ad251Schristos goto trunc; 2295c74ad251Schristos extd_comm=GET_BE_U_2(tptr); 22960f74e101Schristos 2297c74ad251Schristos ND_PRINT("\n\t %s (0x%04x), Flags [%s]", 2298fdccd7e4Schristos tok2str(bgp_extd_comm_subtype_values, 22990f74e101Schristos "unknown extd community typecode", 2300fdccd7e4Schristos extd_comm), 23010f74e101Schristos extd_comm, 2302c74ad251Schristos bittok2str(bgp_extd_comm_flag_values, "none", extd_comm)); 23030f74e101Schristos 2304c74ad251Schristos ND_TCHECK_8(tptr); 2305c74ad251Schristos if (tlen < 8) 2306c74ad251Schristos goto trunc; 2307c74ad251Schristos ND_PRINT(": "); 2308c74ad251Schristos bgp_extended_community_print(ndo, tptr); 23090f74e101Schristos tlen -= 8; 23100f74e101Schristos tptr += 8; 23110f74e101Schristos } 23120f74e101Schristos break; 23130f74e101Schristos 23140f74e101Schristos case BGPTYPE_PMSI_TUNNEL: 23150f74e101Schristos { 2316b3a00663Schristos uint8_t tunnel_type, flags; 23170f74e101Schristos 2318c74ad251Schristos ND_TCHECK_5(tptr); 2319c74ad251Schristos if (tlen < 5) 2320c74ad251Schristos goto trunc; 2321c74ad251Schristos flags = GET_U_1(tptr); 2322c74ad251Schristos tunnel_type = GET_U_1(tptr + 1); 23230f74e101Schristos 2324c74ad251Schristos ND_PRINT("\n\t Tunnel-type %s (%u), Flags [%s], MPLS Label %u", 23250f74e101Schristos tok2str(bgp_pmsi_tunnel_values, "Unknown", tunnel_type), 23260f74e101Schristos tunnel_type, 23270f74e101Schristos bittok2str(bgp_pmsi_flag_values, "none", flags), 2328c74ad251Schristos GET_BE_U_3(tptr + 2)>>4); 23290f74e101Schristos 23300f74e101Schristos tptr +=5; 23310f74e101Schristos tlen -= 5; 23320f74e101Schristos 23330f74e101Schristos switch (tunnel_type) { 23340f74e101Schristos case BGP_PMSI_TUNNEL_PIM_SM: /* fall through */ 23350f74e101Schristos case BGP_PMSI_TUNNEL_PIM_BIDIR: 2336c74ad251Schristos ND_PRINT("\n\t Sender %s, P-Group %s", 2337c74ad251Schristos GET_IPADDR_STRING(tptr), 2338c74ad251Schristos GET_IPADDR_STRING(tptr+4)); 23390f74e101Schristos break; 23400f74e101Schristos 23410f74e101Schristos case BGP_PMSI_TUNNEL_PIM_SSM: 2342c74ad251Schristos ND_PRINT("\n\t Root-Node %s, P-Group %s", 2343c74ad251Schristos GET_IPADDR_STRING(tptr), 2344c74ad251Schristos GET_IPADDR_STRING(tptr+4)); 23450f74e101Schristos break; 23460f74e101Schristos case BGP_PMSI_TUNNEL_INGRESS: 2347c74ad251Schristos ND_PRINT("\n\t Tunnel-Endpoint %s", 2348c74ad251Schristos GET_IPADDR_STRING(tptr)); 23490f74e101Schristos break; 23500f74e101Schristos case BGP_PMSI_TUNNEL_LDP_P2MP: /* fall through */ 23510f74e101Schristos case BGP_PMSI_TUNNEL_LDP_MP2MP: 2352c74ad251Schristos ND_PRINT("\n\t Root-Node %s, LSP-ID 0x%08x", 2353c74ad251Schristos GET_IPADDR_STRING(tptr), 2354c74ad251Schristos GET_BE_U_4(tptr + 4)); 23550f74e101Schristos break; 23560f74e101Schristos case BGP_PMSI_TUNNEL_RSVP_P2MP: 2357c74ad251Schristos ND_PRINT("\n\t Extended-Tunnel-ID %s, P2MP-ID 0x%08x", 2358c74ad251Schristos GET_IPADDR_STRING(tptr), 2359c74ad251Schristos GET_BE_U_4(tptr + 4)); 23600f74e101Schristos break; 23610f74e101Schristos default: 2362b3a00663Schristos if (ndo->ndo_vflag <= 1) { 2363b3a00663Schristos print_unknown_data(ndo, tptr, "\n\t ", tlen); 23640f74e101Schristos } 23650f74e101Schristos } 23660f74e101Schristos break; 23670f74e101Schristos } 2368fdccd7e4Schristos case BGPTYPE_AIGP: 2369fdccd7e4Schristos { 2370fdccd7e4Schristos uint8_t type; 2371fdccd7e4Schristos uint16_t length; 2372fdccd7e4Schristos 2373fdccd7e4Schristos while (tlen >= 3) { 2374c74ad251Schristos type = GET_U_1(tptr); 2375c74ad251Schristos length = GET_BE_U_2(tptr + 1); 237672c96ff3Schristos tptr += 3; 237772c96ff3Schristos tlen -= 3; 2378fdccd7e4Schristos 2379c74ad251Schristos ND_PRINT("\n\t %s TLV (%u), length %u", 2380fdccd7e4Schristos tok2str(bgp_aigp_values, "Unknown", type), 2381c74ad251Schristos type, length); 2382fdccd7e4Schristos 238372c96ff3Schristos if (length < 3) 238472c96ff3Schristos goto trunc; 238572c96ff3Schristos length -= 3; 238672c96ff3Schristos 2387fdccd7e4Schristos /* 2388fdccd7e4Schristos * Check if we can read the TLV data. 2389fdccd7e4Schristos */ 2390c74ad251Schristos if (tlen < length) 2391c74ad251Schristos goto trunc; 2392fdccd7e4Schristos 2393fdccd7e4Schristos switch (type) { 2394fdccd7e4Schristos 2395fdccd7e4Schristos case BGP_AIGP_TLV: 239672c96ff3Schristos if (length < 8) 239772c96ff3Schristos goto trunc; 2398c74ad251Schristos ND_PRINT(", metric %" PRIu64, 2399c74ad251Schristos GET_BE_U_8(tptr)); 2400fdccd7e4Schristos break; 2401fdccd7e4Schristos 2402fdccd7e4Schristos default: 2403fdccd7e4Schristos if (ndo->ndo_vflag <= 1) { 240472c96ff3Schristos print_unknown_data(ndo, tptr,"\n\t ", length); 2405fdccd7e4Schristos } 2406fdccd7e4Schristos } 2407fdccd7e4Schristos 2408fdccd7e4Schristos tptr += length; 2409fdccd7e4Schristos tlen -= length; 2410fdccd7e4Schristos } 2411fdccd7e4Schristos break; 2412fdccd7e4Schristos } 24130f74e101Schristos case BGPTYPE_ATTR_SET: 2414c74ad251Schristos ND_TCHECK_4(tptr); 24150e9868baSchristos if (len < 4) 24160e9868baSchristos goto trunc; 2417c74ad251Schristos ND_PRINT("\n\t Origin AS: %s", 2418c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_4(tptr))); 24190f74e101Schristos tptr += 4; 24200f74e101Schristos len -= 4; 24210f74e101Schristos 24220e9868baSchristos while (len) { 2423fdccd7e4Schristos u_int aflags, alenlen, alen; 24240f74e101Schristos 2425c74ad251Schristos ND_TCHECK_2(tptr); 2426c74ad251Schristos if (len < 2) { 2427c74ad251Schristos ND_PRINT(" [path attr too short]"); 2428c74ad251Schristos tptr += len; 2429c74ad251Schristos break; 2430c74ad251Schristos } 2431c74ad251Schristos aflags = GET_U_1(tptr); 2432c74ad251Schristos atype = GET_U_1(tptr + 1); 24330e9868baSchristos tptr += 2; 24340e9868baSchristos len -= 2; 24350e9868baSchristos alenlen = bgp_attr_lenlen(aflags, tptr); 2436c74ad251Schristos ND_TCHECK_LEN(tptr, alenlen); 2437c74ad251Schristos if (len < alenlen) { 2438c74ad251Schristos ND_PRINT(" [path attr too short]"); 2439c74ad251Schristos tptr += len; 2440c74ad251Schristos break; 2441c74ad251Schristos } 24420e9868baSchristos alen = bgp_attr_len(aflags, tptr); 24430e9868baSchristos tptr += alenlen; 24440e9868baSchristos len -= alenlen; 24450f74e101Schristos 2446c74ad251Schristos ND_PRINT("\n\t %s (%u), length: %u", 2447fdccd7e4Schristos tok2str(bgp_attr_values, 2448fdccd7e4Schristos "Unknown Attribute", atype), 24490e9868baSchristos atype, 2450c74ad251Schristos alen); 24510f74e101Schristos 24520e9868baSchristos if (aflags) { 2453c74ad251Schristos ND_PRINT(", Flags [%s%s%s%s", 24540e9868baSchristos aflags & 0x80 ? "O" : "", 24550e9868baSchristos aflags & 0x40 ? "T" : "", 24560e9868baSchristos aflags & 0x20 ? "P" : "", 2457c74ad251Schristos aflags & 0x10 ? "E" : ""); 24580e9868baSchristos if (aflags & 0xf) 2459c74ad251Schristos ND_PRINT("+%x", aflags & 0xf); 2460c74ad251Schristos ND_PRINT("]"); 24610f74e101Schristos } 2462c74ad251Schristos ND_PRINT(": "); 2463c74ad251Schristos if (len < alen) { 2464c74ad251Schristos ND_PRINT(" [path attr too short]"); 2465c74ad251Schristos tptr += len; 2466c74ad251Schristos break; 2467c74ad251Schristos } 2468c74ad251Schristos /* 2469c74ad251Schristos * The protocol encoding per se allows ATTR_SET to be nested 2470c74ad251Schristos * as many times as the message can accommodate. This printer 2471c74ad251Schristos * used to be able to recurse into ATTR_SET contents until the 2472c74ad251Schristos * stack exhaustion, but now there is a limit on that (if live 2473c74ad251Schristos * protocol exchange goes that many levels deep, something is 2474c74ad251Schristos * probably wrong anyway). Feel free to refine this value if 2475817e9a7eSchristos * you can find the spec with respective normative text. 2476817e9a7eSchristos */ 2477817e9a7eSchristos if (attr_set_level == 10) 2478c74ad251Schristos ND_PRINT("(too many nested levels, not recursing)"); 2479817e9a7eSchristos else if (!bgp_attr_print(ndo, atype, tptr, alen, attr_set_level + 1)) 24800f74e101Schristos return 0; 24810f74e101Schristos tptr += alen; 24820f74e101Schristos len -= alen; 24830f74e101Schristos } 24840f74e101Schristos break; 24850f74e101Schristos 2486dc860a36Sspz case BGPTYPE_LARGE_COMMUNITY: 2487dc860a36Sspz if (len == 0 || len % 12) { 2488c74ad251Schristos ND_PRINT("invalid len"); 2489dc860a36Sspz break; 2490dc860a36Sspz } 2491c74ad251Schristos ND_PRINT("\n\t "); 2492c74ad251Schristos while (len != 0) { 2493c74ad251Schristos ND_PRINT("%u:%u:%u%s", 2494c74ad251Schristos GET_BE_U_4(tptr), 2495c74ad251Schristos GET_BE_U_4(tptr + 4), 2496c74ad251Schristos GET_BE_U_4(tptr + 8), 2497c74ad251Schristos (len > 12) ? ", " : ""); 2498dc860a36Sspz tptr += 12; 2499c74ad251Schristos /* 2500c74ad251Schristos * len will always be a multiple of 12, as per the above, 2501c74ad251Schristos * so this will never underflow. 2502c74ad251Schristos */ 2503dc860a36Sspz len -= 12; 2504dc860a36Sspz } 2505dc860a36Sspz break; 25060f74e101Schristos default: 2507c74ad251Schristos ND_TCHECK_LEN(pptr, len); 2508c74ad251Schristos ND_PRINT("\n\t no Attribute %u decoder", atype); /* we have no decoder for the attribute */ 2509b3a00663Schristos if (ndo->ndo_vflag <= 1) 2510b3a00663Schristos print_unknown_data(ndo, pptr, "\n\t ", len); 25110f74e101Schristos break; 25120f74e101Schristos } 2513c74ad251Schristos done: 2514b3a00663Schristos if (ndo->ndo_vflag > 1 && len) { /* omit zero length attributes*/ 2515c74ad251Schristos ND_TCHECK_LEN(pptr, len); 2516b3a00663Schristos print_unknown_data(ndo, pptr, "\n\t ", len); 25170f74e101Schristos } 25180f74e101Schristos return 1; 25190f74e101Schristos 25200f74e101Schristos trunc: 25210f74e101Schristos return 0; 25220f74e101Schristos } 25230f74e101Schristos 25240f74e101Schristos static void 2525b3a00663Schristos bgp_capabilities_print(netdissect_options *ndo, 2526c74ad251Schristos const u_char *opt, u_int caps_len) 25270e9868baSchristos { 2528c74ad251Schristos /* allocate space for the largest possible string */ 2529c74ad251Schristos char astostr[AS_STR_SIZE]; 2530c74ad251Schristos u_int cap_type, cap_len, tcap_len, cap_offset; 2531c74ad251Schristos u_int i = 0; 25320e9868baSchristos 25330e9868baSchristos while (i < caps_len) { 2534c74ad251Schristos ND_TCHECK_LEN(opt + i, BGP_CAP_HEADER_SIZE); 2535c74ad251Schristos cap_type=GET_U_1(opt + i); 2536c74ad251Schristos cap_len=GET_U_1(opt + i + 1); 2537c74ad251Schristos ND_PRINT("\n\t %s (%u), length: %u", 2538c74ad251Schristos tok2str(bgp_capcode_values, "Unknown", cap_type), 25390e9868baSchristos cap_type, 2540c74ad251Schristos cap_len); 2541c74ad251Schristos ND_TCHECK_LEN(opt + 2 + i, cap_len); 25420e9868baSchristos switch (cap_type) { 25430e9868baSchristos case BGP_CAPCODE_MP: 2544817e9a7eSchristos /* AFI (16 bits), Reserved (8 bits), SAFI (8 bits) */ 2545c74ad251Schristos if (cap_len < 4) { 2546c74ad251Schristos ND_PRINT(" (too short, < 4)"); 2547c74ad251Schristos return; 2548c74ad251Schristos } 2549c74ad251Schristos ND_PRINT("\n\t\tAFI %s (%u), SAFI %s (%u)", 2550c74ad251Schristos tok2str(af_values, "Unknown", GET_BE_U_2(opt + i + 2)), 2551c74ad251Schristos GET_BE_U_2(opt + i + 2), 2552c74ad251Schristos tok2str(bgp_safi_values, "Unknown", GET_U_1(opt + i + 5)), 2553c74ad251Schristos GET_U_1(opt + i + 5)); 2554c74ad251Schristos break; 2555c74ad251Schristos case BGP_CAPCODE_ML: 2556c74ad251Schristos cap_offset = 2; 2557c74ad251Schristos tcap_len = cap_len; 2558c74ad251Schristos while (tcap_len >= 4) { 2559c74ad251Schristos ND_PRINT( "\n\t\tAFI %s (%u), SAFI %s (%u), Count: %u", 2560fdccd7e4Schristos tok2str(af_values, "Unknown", 2561c74ad251Schristos GET_BE_U_2(opt + i + cap_offset)), 2562c74ad251Schristos GET_BE_U_2(opt + i + cap_offset), 2563fdccd7e4Schristos tok2str(bgp_safi_values, "Unknown", 2564c74ad251Schristos GET_U_1(opt + i + cap_offset + 2)), 2565c74ad251Schristos GET_U_1(opt + i + cap_offset + 2), 2566c74ad251Schristos GET_U_1(opt + i + cap_offset + 3)); 2567c74ad251Schristos tcap_len -= 4; 2568c74ad251Schristos cap_offset += 4; 2569c74ad251Schristos } 25700e9868baSchristos break; 25710e9868baSchristos case BGP_CAPCODE_RESTART: 2572817e9a7eSchristos /* Restart Flags (4 bits), Restart Time in seconds (12 bits) */ 2573c74ad251Schristos if (cap_len < 2) { 2574c74ad251Schristos ND_PRINT(" (too short, < 2)"); 2575c74ad251Schristos return; 2576c74ad251Schristos } 2577c74ad251Schristos tcap_len=cap_len; 2578c74ad251Schristos ND_PRINT("\n\t\tRestart Flags: [%s], Restart Time %us", 2579c74ad251Schristos ((GET_U_1(opt + i + 2))&0x80) ? "R" : "none", 2580c74ad251Schristos GET_BE_U_2(opt + i + 2)&0xfff); 25810e9868baSchristos tcap_len-=2; 25820e9868baSchristos cap_offset=4; 25830e9868baSchristos while(tcap_len>=4) { 2584c74ad251Schristos ND_PRINT("\n\t\t AFI %s (%u), SAFI %s (%u), Forwarding state preserved: %s", 2585fdccd7e4Schristos tok2str(af_values,"Unknown", 2586c74ad251Schristos GET_BE_U_2(opt + i + cap_offset)), 2587c74ad251Schristos GET_BE_U_2(opt + i + cap_offset), 2588fdccd7e4Schristos tok2str(bgp_safi_values,"Unknown", 2589c74ad251Schristos GET_U_1(opt + i + cap_offset + 2)), 2590c74ad251Schristos GET_U_1(opt + (i + cap_offset + 2)), 2591c74ad251Schristos ((GET_U_1(opt + (i + cap_offset + 3)))&0x80) ? "yes" : "no" ); 25920e9868baSchristos tcap_len -= 4; 25930e9868baSchristos cap_offset += 4; 25940e9868baSchristos } 25950e9868baSchristos break; 25960e9868baSchristos case BGP_CAPCODE_RR: 2597c74ad251Schristos case BGP_CAPCODE_LLGR: 25980e9868baSchristos case BGP_CAPCODE_RR_CISCO: 25990e9868baSchristos break; 26000e9868baSchristos case BGP_CAPCODE_AS_NEW: 26010e9868baSchristos /* 26020e9868baSchristos * Extract the 4 byte AS number encoded. 26030e9868baSchristos */ 2604c74ad251Schristos if (cap_len < 4) { 2605c74ad251Schristos ND_PRINT(" (too short, < 4)"); 2606c74ad251Schristos return; 26070e9868baSchristos } 2608c74ad251Schristos ND_PRINT("\n\t\t 4 Byte AS %s", 2609c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), 2610c74ad251Schristos GET_BE_U_4(opt + i + 2))); 26110e9868baSchristos break; 2612fdccd7e4Schristos case BGP_CAPCODE_ADD_PATH: 2613c74ad251Schristos if (cap_len == 0) { 2614c74ad251Schristos ND_PRINT(" (bogus)"); /* length */ 2615c74ad251Schristos break; 2616c74ad251Schristos } 2617c74ad251Schristos tcap_len=cap_len; 2618fdccd7e4Schristos cap_offset=2; 2619c74ad251Schristos while (tcap_len != 0) { 2620fdccd7e4Schristos if (tcap_len < 4) { 2621c74ad251Schristos nd_print_invalid(ndo); 2622fdccd7e4Schristos break; 2623fdccd7e4Schristos } 2624c74ad251Schristos ND_PRINT("\n\t\tAFI %s (%u), SAFI %s (%u), Send/Receive: %s", 2625c74ad251Schristos tok2str(af_values,"Unknown",GET_BE_U_2(opt + i + cap_offset)), 2626c74ad251Schristos GET_BE_U_2(opt + i + cap_offset), 2627c74ad251Schristos tok2str(bgp_safi_values,"Unknown",GET_U_1(opt + i + cap_offset + 2)), 2628c74ad251Schristos GET_U_1(opt + (i + cap_offset + 2)), 2629c74ad251Schristos tok2str(bgp_add_path_recvsend,"Bogus (0x%02x)",GET_U_1(opt + i + cap_offset + 3)) 2630c74ad251Schristos ); 2631fdccd7e4Schristos tcap_len -= 4; 2632fdccd7e4Schristos cap_offset += 4; 2633fdccd7e4Schristos } 2634fdccd7e4Schristos break; 26350e9868baSchristos default: 2636c74ad251Schristos ND_PRINT("\n\t\tno decoder for Capability %u", 2637c74ad251Schristos cap_type); 2638b3a00663Schristos if (ndo->ndo_vflag <= 1) 2639c74ad251Schristos print_unknown_data(ndo, opt + i + 2, "\n\t\t", 2640c74ad251Schristos cap_len); 26410e9868baSchristos break; 26420e9868baSchristos } 2643c74ad251Schristos if (ndo->ndo_vflag > 1 && cap_len != 0) { 2644c74ad251Schristos print_unknown_data(ndo, opt + i + 2, "\n\t\t", cap_len); 26450e9868baSchristos } 26460e9868baSchristos i += BGP_CAP_HEADER_SIZE + cap_len; 26470e9868baSchristos } 26480e9868baSchristos return; 26490e9868baSchristos 26500e9868baSchristos trunc: 2651c74ad251Schristos nd_print_trunc(ndo); 26520e9868baSchristos } 26530e9868baSchristos 26540e9868baSchristos static void 2655b3a00663Schristos bgp_open_print(netdissect_options *ndo, 2656c74ad251Schristos const u_char *dat, u_int length) 26570f74e101Schristos { 2658c74ad251Schristos /* allocate space for the largest possible string */ 2659c74ad251Schristos char astostr[AS_STR_SIZE]; 2660c74ad251Schristos const struct bgp_open *bgp_open_header; 2661c74ad251Schristos u_int optslen; 2662c74ad251Schristos const struct bgp_opt *bgpopt; 26630f74e101Schristos const u_char *opt; 2664c74ad251Schristos u_int i; 26650f74e101Schristos 2666c74ad251Schristos ND_TCHECK_LEN(dat, BGP_OPEN_SIZE); 2667c74ad251Schristos if (length < BGP_OPEN_SIZE) 2668c74ad251Schristos goto trunc; 26690f74e101Schristos 2670c74ad251Schristos bgp_open_header = (const struct bgp_open *)dat; 26710f74e101Schristos 2672c74ad251Schristos ND_PRINT("\n\t Version %u, ", 2673c74ad251Schristos GET_U_1(bgp_open_header->bgpo_version)); 2674c74ad251Schristos ND_PRINT("my AS %s, ", 2675c74ad251Schristos as_printf(ndo, astostr, sizeof(astostr), GET_BE_U_2(bgp_open_header->bgpo_myas))); 2676c74ad251Schristos ND_PRINT("Holdtime %us, ", 2677c74ad251Schristos GET_BE_U_2(bgp_open_header->bgpo_holdtime)); 2678c74ad251Schristos ND_PRINT("ID %s", GET_IPADDR_STRING(bgp_open_header->bgpo_id)); 2679c74ad251Schristos optslen = GET_U_1(bgp_open_header->bgpo_optlen); 2680c74ad251Schristos ND_PRINT("\n\t Optional parameters, length: %u", optslen); 26810f74e101Schristos 2682c74ad251Schristos opt = dat + BGP_OPEN_SIZE; 2683c74ad251Schristos length -= BGP_OPEN_SIZE; 26840f74e101Schristos 26850f74e101Schristos i = 0; 2686c74ad251Schristos while (i < optslen) { 2687c74ad251Schristos uint8_t opt_type, opt_len; 2688c74ad251Schristos 2689c74ad251Schristos ND_TCHECK_LEN(opt + i, BGP_OPT_SIZE); 2690c74ad251Schristos if (length < BGP_OPT_SIZE + i) 2691c74ad251Schristos goto trunc; 2692c74ad251Schristos bgpopt = (const struct bgp_opt *)(opt + i); 2693c74ad251Schristos opt_type = GET_U_1(bgpopt->bgpopt_type); 2694c74ad251Schristos opt_len = GET_U_1(bgpopt->bgpopt_len); 2695c74ad251Schristos if (BGP_OPT_SIZE + i + opt_len > optslen) { 2696c74ad251Schristos ND_PRINT("\n\t Option %u, length: %u, goes past the end of the options", 2697c74ad251Schristos opt_type, opt_len); 26980f74e101Schristos break; 26990f74e101Schristos } 27000f74e101Schristos 2701c74ad251Schristos ND_PRINT("\n\t Option %s (%u), length: %u", 2702c74ad251Schristos tok2str(bgp_opt_values,"Unknown",opt_type), 2703c74ad251Schristos opt_type, 2704c74ad251Schristos opt_len); 27050f74e101Schristos 27060e9868baSchristos /* now let's decode the options we know*/ 2707c74ad251Schristos switch(opt_type) { 27080f74e101Schristos 27090e9868baSchristos case BGP_OPT_CAP: 2710c74ad251Schristos bgp_capabilities_print(ndo, opt + BGP_OPT_SIZE + i, 2711c74ad251Schristos opt_len); 27120f74e101Schristos break; 27130e9868baSchristos 27140f74e101Schristos case BGP_OPT_AUTH: 27150f74e101Schristos default: 2716c74ad251Schristos ND_PRINT("\n\t no decoder for option %u", 2717c74ad251Schristos opt_type); 27180f74e101Schristos break; 27190f74e101Schristos } 2720c74ad251Schristos i += BGP_OPT_SIZE + opt_len; 27210f74e101Schristos } 27220f74e101Schristos return; 27230f74e101Schristos trunc: 2724c74ad251Schristos nd_print_trunc(ndo); 27250f74e101Schristos } 27260f74e101Schristos 27270f74e101Schristos static void 2728b3a00663Schristos bgp_update_print(netdissect_options *ndo, 2729c74ad251Schristos const u_char *dat, u_int length) 27300f74e101Schristos { 27310f74e101Schristos const u_char *p; 2732c74ad251Schristos u_int withdrawn_routes_len; 2733c74ad251Schristos char buf[MAXHOSTNAMELEN + 100]; 2734c74ad251Schristos int wpfx; 2735c74ad251Schristos u_int len; 27360f74e101Schristos int i; 2737c74ad251Schristos int add_path; 2738c74ad251Schristos u_int path_id = 0; 27390f74e101Schristos 2740c74ad251Schristos ND_TCHECK_LEN(dat, BGP_SIZE); 27410e9868baSchristos if (length < BGP_SIZE) 27420e9868baSchristos goto trunc; 2743c74ad251Schristos p = dat + BGP_SIZE; 27440e9868baSchristos length -= BGP_SIZE; 27450f74e101Schristos 27460f74e101Schristos /* Unfeasible routes */ 2747c74ad251Schristos ND_TCHECK_2(p); 27480e9868baSchristos if (length < 2) 27490e9868baSchristos goto trunc; 2750c74ad251Schristos withdrawn_routes_len = GET_BE_U_2(p); 27510e9868baSchristos p += 2; 27520e9868baSchristos length -= 2; 2753c74ad251Schristos if (withdrawn_routes_len > 1) { 27540f74e101Schristos /* 27550f74e101Schristos * Without keeping state from the original NLRI message, 27560f74e101Schristos * it's not possible to tell if this a v4 or v6 route, 27570f74e101Schristos * so only try to decode it if we're not v6 enabled. 27580f74e101Schristos */ 2759c74ad251Schristos ND_TCHECK_LEN(p, withdrawn_routes_len); 27600e9868baSchristos if (length < withdrawn_routes_len) 27610e9868baSchristos goto trunc; 2762c74ad251Schristos ND_PRINT("\n\t Withdrawn routes:"); 2763c74ad251Schristos add_path = check_add_path(ndo, p, withdrawn_routes_len, 32); 2764c74ad251Schristos while (withdrawn_routes_len != 0) { 2765c74ad251Schristos if (add_path) { 2766c74ad251Schristos if (withdrawn_routes_len < 4) { 2767c74ad251Schristos p += withdrawn_routes_len; 2768c74ad251Schristos length -= withdrawn_routes_len; 2769c74ad251Schristos break; 2770c74ad251Schristos } 2771c74ad251Schristos path_id = GET_BE_U_4(p); 2772c74ad251Schristos p += 4; 2773c74ad251Schristos length -= 4; 2774c74ad251Schristos withdrawn_routes_len -= 4; 2775c74ad251Schristos } 2776c74ad251Schristos wpfx = decode_prefix4(ndo, p, withdrawn_routes_len, buf, sizeof(buf)); 2777c74ad251Schristos if (wpfx == -1) { 2778c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 2779c74ad251Schristos break; 2780c74ad251Schristos } else if (wpfx == -2) 2781c74ad251Schristos goto trunc; /* bytes left, but not enough */ 2782c74ad251Schristos else { 2783c74ad251Schristos ND_PRINT("\n\t %s", buf); 2784c74ad251Schristos if (add_path) { 2785c74ad251Schristos ND_PRINT(" Path Id: %u", path_id); 2786c74ad251Schristos } 2787c74ad251Schristos p += wpfx; 2788c74ad251Schristos length -= wpfx; 2789c74ad251Schristos withdrawn_routes_len -= wpfx; 2790c74ad251Schristos } 2791c74ad251Schristos } 2792c74ad251Schristos } else { 2793c74ad251Schristos ND_TCHECK_LEN(p, withdrawn_routes_len); 2794c74ad251Schristos if (length < withdrawn_routes_len) 2795c74ad251Schristos goto trunc; 27960e9868baSchristos p += withdrawn_routes_len; 27970e9868baSchristos length -= withdrawn_routes_len; 27980f74e101Schristos } 27990f74e101Schristos 2800c74ad251Schristos ND_TCHECK_2(p); 28010e9868baSchristos if (length < 2) 28020e9868baSchristos goto trunc; 2803c74ad251Schristos len = GET_BE_U_2(p); 28040e9868baSchristos p += 2; 28050e9868baSchristos length -= 2; 28060f74e101Schristos 28070e9868baSchristos if (withdrawn_routes_len == 0 && len == 0 && length == 0) { 28080e9868baSchristos /* No withdrawn routes, no path attributes, no NLRI */ 2809c74ad251Schristos ND_PRINT("\n\t End-of-Rib Marker (empty NLRI)"); 28100f74e101Schristos return; 28110f74e101Schristos } 28120f74e101Schristos 28130f74e101Schristos if (len) { 2814c74ad251Schristos /* Make sure the path attributes don't go past the end of the packet */ 2815c74ad251Schristos if (length < len) 2816c74ad251Schristos goto trunc; 28170f74e101Schristos /* do something more useful!*/ 28180e9868baSchristos while (len) { 2819c74ad251Schristos uint8_t aflags, atype, alenlen; 2820c74ad251Schristos uint16_t alen; 28210f74e101Schristos 2822c74ad251Schristos ND_TCHECK_2(p); 28230e9868baSchristos if (length < 2) 28240e9868baSchristos goto trunc; 2825c74ad251Schristos if (len < 2) { 2826c74ad251Schristos ND_PRINT("\n\t [path attrs too short]"); 2827c74ad251Schristos p += len; 2828c74ad251Schristos length -= len; 2829c74ad251Schristos break; 2830c74ad251Schristos } 2831c74ad251Schristos aflags = GET_U_1(p); 2832c74ad251Schristos atype = GET_U_1(p + 1); 28330e9868baSchristos p += 2; 28340e9868baSchristos len -= 2; 28350e9868baSchristos length -= 2; 28360e9868baSchristos alenlen = bgp_attr_lenlen(aflags, p); 2837c74ad251Schristos ND_TCHECK_LEN(p, alenlen); 28380e9868baSchristos if (length < alenlen) 28390e9868baSchristos goto trunc; 2840c74ad251Schristos if (len < alenlen) { 2841c74ad251Schristos ND_PRINT("\n\t [path attrs too short]"); 2842c74ad251Schristos p += len; 2843c74ad251Schristos length -= len; 2844c74ad251Schristos break; 2845c74ad251Schristos } 28460e9868baSchristos alen = bgp_attr_len(aflags, p); 28470e9868baSchristos p += alenlen; 28480e9868baSchristos len -= alenlen; 28490e9868baSchristos length -= alenlen; 28500f74e101Schristos 2851c74ad251Schristos ND_PRINT("\n\t %s (%u), length: %u", 2852c74ad251Schristos tok2str(bgp_attr_values, "Unknown Attribute", atype), 28530e9868baSchristos atype, 2854c74ad251Schristos alen); 28550f74e101Schristos 28560e9868baSchristos if (aflags) { 2857c74ad251Schristos ND_PRINT(", Flags [%s%s%s%s", 28580e9868baSchristos aflags & 0x80 ? "O" : "", 28590e9868baSchristos aflags & 0x40 ? "T" : "", 28600e9868baSchristos aflags & 0x20 ? "P" : "", 2861c74ad251Schristos aflags & 0x10 ? "E" : ""); 28620e9868baSchristos if (aflags & 0xf) 2863c74ad251Schristos ND_PRINT("+%x", aflags & 0xf); 2864c74ad251Schristos ND_PRINT("]: "); 28650f74e101Schristos } 2866c74ad251Schristos if (len < alen) { 2867c74ad251Schristos ND_PRINT(" [path attrs too short]"); 2868c74ad251Schristos p += len; 2869c74ad251Schristos length -= len; 2870c74ad251Schristos break; 2871c74ad251Schristos } 28720e9868baSchristos if (length < alen) 28730e9868baSchristos goto trunc; 2874817e9a7eSchristos if (!bgp_attr_print(ndo, atype, p, alen, 0)) 28750e9868baSchristos goto trunc; 28760e9868baSchristos p += alen; 28770e9868baSchristos len -= alen; 28780e9868baSchristos length -= alen; 28790f74e101Schristos } 28800f74e101Schristos } 28810f74e101Schristos 28820e9868baSchristos if (length) { 2883c74ad251Schristos add_path = check_add_path(ndo, p, length, 32); 2884c74ad251Schristos ND_PRINT("\n\t Updated routes:"); 2885c74ad251Schristos while (length != 0) { 2886c74ad251Schristos if (add_path) { 2887c74ad251Schristos ND_TCHECK_4(p); 2888c74ad251Schristos if (length < 4) 2889c74ad251Schristos goto trunc; 2890c74ad251Schristos path_id = GET_BE_U_4(p); 2891c74ad251Schristos p += 4; 2892c74ad251Schristos length -= 4; 2893c74ad251Schristos } 2894b3a00663Schristos i = decode_prefix4(ndo, p, length, buf, sizeof(buf)); 28950f74e101Schristos if (i == -1) { 2896c74ad251Schristos ND_PRINT("\n\t (illegal prefix length)"); 28970f74e101Schristos break; 28980f74e101Schristos } else if (i == -2) 28990e9868baSchristos goto trunc; /* bytes left, but not enough */ 29000f74e101Schristos else { 2901c74ad251Schristos ND_PRINT("\n\t %s", buf); 2902c74ad251Schristos if (add_path) { 2903c74ad251Schristos ND_PRINT(" Path Id: %u", path_id); 2904c74ad251Schristos } 29050f74e101Schristos p += i; 29060e9868baSchristos length -= i; 29070f74e101Schristos } 29080f74e101Schristos } 29090f74e101Schristos } 29100f74e101Schristos return; 29110f74e101Schristos trunc: 2912c74ad251Schristos nd_print_trunc(ndo); 29130f74e101Schristos } 29140f74e101Schristos 29150f74e101Schristos static void 2916b3a00663Schristos bgp_notification_print(netdissect_options *ndo, 2917c74ad251Schristos const u_char *dat, u_int length) 29180f74e101Schristos { 2919c74ad251Schristos const struct bgp_notification *bgp_notification_header; 29200f74e101Schristos const u_char *tptr; 2921c74ad251Schristos uint8_t bgpn_major, bgpn_minor; 29220f74e101Schristos 2923c74ad251Schristos ND_TCHECK_LEN(dat, BGP_NOTIFICATION_SIZE); 29240f74e101Schristos if (length<BGP_NOTIFICATION_SIZE) 29250f74e101Schristos return; 29260f74e101Schristos 2927c74ad251Schristos bgp_notification_header = (const struct bgp_notification *)dat; 2928c74ad251Schristos bgpn_major = GET_U_1(bgp_notification_header->bgpn_major); 2929c74ad251Schristos bgpn_minor = GET_U_1(bgp_notification_header->bgpn_minor); 29300f74e101Schristos 2931c74ad251Schristos ND_PRINT(", %s (%u)", 2932c74ad251Schristos tok2str(bgp_notify_major_values, "Unknown Error", 2933c74ad251Schristos bgpn_major), 2934c74ad251Schristos bgpn_major); 2935c74ad251Schristos 2936c74ad251Schristos switch (bgpn_major) { 29370f74e101Schristos 29380f74e101Schristos case BGP_NOTIFY_MAJOR_MSG: 2939c74ad251Schristos ND_PRINT(", subcode %s (%u)", 2940fdccd7e4Schristos tok2str(bgp_notify_minor_msg_values, "Unknown", 2941c74ad251Schristos bgpn_minor), 2942c74ad251Schristos bgpn_minor); 29430f74e101Schristos break; 29440f74e101Schristos case BGP_NOTIFY_MAJOR_OPEN: 2945c74ad251Schristos ND_PRINT(", subcode %s (%u)", 2946fdccd7e4Schristos tok2str(bgp_notify_minor_open_values, "Unknown", 2947c74ad251Schristos bgpn_minor), 2948c74ad251Schristos bgpn_minor); 29490f74e101Schristos break; 29500f74e101Schristos case BGP_NOTIFY_MAJOR_UPDATE: 2951c74ad251Schristos ND_PRINT(", subcode %s (%u)", 2952fdccd7e4Schristos tok2str(bgp_notify_minor_update_values, "Unknown", 2953c74ad251Schristos bgpn_minor), 2954c74ad251Schristos bgpn_minor); 29550f74e101Schristos break; 2956dc860a36Sspz case BGP_NOTIFY_MAJOR_FSM: 2957c74ad251Schristos ND_PRINT(" subcode %s (%u)", 2958dc860a36Sspz tok2str(bgp_notify_minor_fsm_values, "Unknown", 2959c74ad251Schristos bgpn_minor), 2960c74ad251Schristos bgpn_minor); 2961dc860a36Sspz break; 29620f74e101Schristos case BGP_NOTIFY_MAJOR_CAP: 2963c74ad251Schristos ND_PRINT(" subcode %s (%u)", 2964fdccd7e4Schristos tok2str(bgp_notify_minor_cap_values, "Unknown", 2965c74ad251Schristos bgpn_minor), 2966c74ad251Schristos bgpn_minor); 2967dc860a36Sspz break; 29680f74e101Schristos case BGP_NOTIFY_MAJOR_CEASE: 2969c74ad251Schristos ND_PRINT(", subcode %s (%u)", 2970fdccd7e4Schristos tok2str(bgp_notify_minor_cease_values, "Unknown", 2971c74ad251Schristos bgpn_minor), 2972c74ad251Schristos bgpn_minor); 29730f74e101Schristos 2974c74ad251Schristos /* RFC 4486 mentions optionally 7 bytes 29750f74e101Schristos * for the maxprefix subtype, which may contain AFI, SAFI and MAXPREFIXES 29760f74e101Schristos */ 2977c74ad251Schristos if(bgpn_minor == BGP_NOTIFY_MINOR_CEASE_MAXPRFX && length >= BGP_NOTIFICATION_SIZE + 7) { 29780f74e101Schristos tptr = dat + BGP_NOTIFICATION_SIZE; 2979c74ad251Schristos ND_PRINT(", AFI %s (%u), SAFI %s (%u), Max Prefixes: %u", 2980c74ad251Schristos tok2str(af_values, "Unknown", GET_BE_U_2(tptr)), 2981c74ad251Schristos GET_BE_U_2(tptr), 2982c74ad251Schristos tok2str(bgp_safi_values, "Unknown", GET_U_1((tptr + 2))), 2983c74ad251Schristos GET_U_1((tptr + 2)), 2984c74ad251Schristos GET_BE_U_4(tptr + 3)); 2985c74ad251Schristos } 2986c74ad251Schristos /* 2987c74ad251Schristos * RFC 9003 describes a method to send a communication 2988c74ad251Schristos * intended for human consumption regarding the Administrative Shutdown 2989c74ad251Schristos */ 2990c74ad251Schristos if ((bgpn_minor == BGP_NOTIFY_MINOR_CEASE_SHUT || 2991c74ad251Schristos bgpn_minor == BGP_NOTIFY_MINOR_CEASE_RESET) && 2992c74ad251Schristos length >= BGP_NOTIFICATION_SIZE + 1) { 2993c74ad251Schristos tptr = dat + BGP_NOTIFICATION_SIZE; 2994c74ad251Schristos uint8_t shutdown_comm_length = GET_U_1(tptr); 2995c74ad251Schristos uint8_t remainder_offset = 0; 2996c74ad251Schristos /* garbage, hexdump it all */ 2997c74ad251Schristos if (shutdown_comm_length > length - (BGP_NOTIFICATION_SIZE + 1)) { 2998c74ad251Schristos ND_PRINT(", invalid Shutdown Communication length"); 2999*26ba0b50Schristos } else if (shutdown_comm_length == 0) { 3000c74ad251Schristos ND_PRINT(", empty Shutdown Communication"); 3001c74ad251Schristos remainder_offset += 1; 3002c74ad251Schristos } 3003c74ad251Schristos /* a proper shutdown communication */ 3004c74ad251Schristos else { 3005c74ad251Schristos ND_PRINT(", Shutdown Communication (length: %u): \"", shutdown_comm_length); 3006c74ad251Schristos (void)nd_printn(ndo, tptr+1, shutdown_comm_length, NULL); 3007c74ad251Schristos ND_PRINT("\""); 3008c74ad251Schristos remainder_offset += shutdown_comm_length + 1; 3009c74ad251Schristos } 3010c74ad251Schristos /* if there is trailing data, hexdump it */ 3011c74ad251Schristos if(length - (remainder_offset + BGP_NOTIFICATION_SIZE) > 0) { 3012c74ad251Schristos ND_PRINT(", Data: (length: %u)", length - (remainder_offset + BGP_NOTIFICATION_SIZE)); 3013c74ad251Schristos hex_print(ndo, "\n\t\t", tptr + remainder_offset, length - (remainder_offset + BGP_NOTIFICATION_SIZE)); 3014c74ad251Schristos } 30150f74e101Schristos } 30160f74e101Schristos break; 30170f74e101Schristos default: 30180f74e101Schristos break; 30190f74e101Schristos } 30200f74e101Schristos 30210f74e101Schristos return; 30220f74e101Schristos trunc: 3023c74ad251Schristos nd_print_trunc(ndo); 30240f74e101Schristos } 30250f74e101Schristos 30260f74e101Schristos static void 3027b3a00663Schristos bgp_route_refresh_print(netdissect_options *ndo, 3028c74ad251Schristos const u_char *pptr, u_int len) 3029ba2ff121Schristos { 30300f74e101Schristos const struct bgp_route_refresh *bgp_route_refresh_header; 30310f74e101Schristos 3032c74ad251Schristos ND_TCHECK_LEN(pptr, BGP_ROUTE_REFRESH_SIZE); 30330f74e101Schristos 30340f74e101Schristos /* some little sanity checking */ 30350f74e101Schristos if (len<BGP_ROUTE_REFRESH_SIZE) 30360f74e101Schristos return; 30370f74e101Schristos 30380f74e101Schristos bgp_route_refresh_header = (const struct bgp_route_refresh *)pptr; 30390f74e101Schristos 3040c74ad251Schristos ND_PRINT("\n\t AFI %s (%u), SAFI %s (%u)", 3041fdccd7e4Schristos tok2str(af_values,"Unknown", 3042c74ad251Schristos GET_BE_U_2(bgp_route_refresh_header->afi)), 3043c74ad251Schristos GET_BE_U_2(bgp_route_refresh_header->afi), 3044fdccd7e4Schristos tok2str(bgp_safi_values,"Unknown", 3045c74ad251Schristos GET_U_1(bgp_route_refresh_header->safi)), 3046c74ad251Schristos GET_U_1(bgp_route_refresh_header->safi)); 30470f74e101Schristos 3048b3a00663Schristos if (ndo->ndo_vflag > 1) { 3049c74ad251Schristos ND_TCHECK_LEN(pptr, len); 3050b3a00663Schristos print_unknown_data(ndo, pptr, "\n\t ", len); 30510f74e101Schristos } 30520f74e101Schristos 30530f74e101Schristos return; 30540f74e101Schristos trunc: 3055c74ad251Schristos nd_print_trunc(ndo); 30560f74e101Schristos } 30570f74e101Schristos 30580f74e101Schristos static int 3059c74ad251Schristos bgp_pdu_print(netdissect_options *ndo, 3060c74ad251Schristos const u_char *dat, u_int length) 30610f74e101Schristos { 3062c74ad251Schristos const struct bgp *bgp_header; 3063c74ad251Schristos uint8_t bgp_type; 30640f74e101Schristos 3065c74ad251Schristos ND_TCHECK_LEN(dat, BGP_SIZE); 3066c74ad251Schristos bgp_header = (const struct bgp *)dat; 3067c74ad251Schristos bgp_type = GET_U_1(bgp_header->bgp_type); 30680f74e101Schristos 3069c74ad251Schristos ND_PRINT("\n\t%s Message (%u), length: %u", 3070c74ad251Schristos tok2str(bgp_msg_values, "Unknown", bgp_type), 3071c74ad251Schristos bgp_type, 3072c74ad251Schristos length); 3073c74ad251Schristos 3074c74ad251Schristos switch (bgp_type) { 30750f74e101Schristos case BGP_OPEN: 3076b3a00663Schristos bgp_open_print(ndo, dat, length); 30770f74e101Schristos break; 30780f74e101Schristos case BGP_UPDATE: 3079b3a00663Schristos bgp_update_print(ndo, dat, length); 30800f74e101Schristos break; 30810f74e101Schristos case BGP_NOTIFICATION: 3082b3a00663Schristos bgp_notification_print(ndo, dat, length); 30830f74e101Schristos break; 30840f74e101Schristos case BGP_KEEPALIVE: 30850f74e101Schristos break; 30860f74e101Schristos case BGP_ROUTE_REFRESH: 3087b3a00663Schristos bgp_route_refresh_print(ndo, dat, length); 30880f74e101Schristos break; 30890f74e101Schristos default: 30900f74e101Schristos /* we have no decoder for the BGP message */ 3091c74ad251Schristos ND_TCHECK_LEN(dat, length); 3092c74ad251Schristos ND_PRINT("\n\t no Message %u decoder", bgp_type); 3093b3a00663Schristos print_unknown_data(ndo, dat, "\n\t ", length); 30940f74e101Schristos break; 30950f74e101Schristos } 30960f74e101Schristos return 1; 30970f74e101Schristos trunc: 3098c74ad251Schristos nd_print_trunc(ndo); 30990f74e101Schristos return 0; 31000f74e101Schristos } 31010f74e101Schristos 31020f74e101Schristos void 3103b3a00663Schristos bgp_print(netdissect_options *ndo, 3104c74ad251Schristos const u_char *dat, u_int length _U_) 31050f74e101Schristos { 31060f74e101Schristos const u_char *p; 3107c74ad251Schristos const u_char *ep = ndo->ndo_snapend; 31080f74e101Schristos const u_char *start; 31090f74e101Schristos const u_char marker[] = { 31100f74e101Schristos 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 31110f74e101Schristos 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 31120f74e101Schristos }; 3113c74ad251Schristos const struct bgp *bgp_header; 3114b3a00663Schristos uint16_t hlen; 31150f74e101Schristos 3116c74ad251Schristos ndo->ndo_protocol = "bgp"; 3117c74ad251Schristos ND_PRINT(": BGP"); 31180f74e101Schristos 3119b3a00663Schristos if (ndo->ndo_vflag < 1) /* lets be less chatty */ 31200f74e101Schristos return; 31210f74e101Schristos 31220f74e101Schristos p = dat; 31230f74e101Schristos start = p; 31240f74e101Schristos while (p < ep) { 3125c74ad251Schristos if (!ND_TTEST_1(p)) 31260f74e101Schristos break; 3127c74ad251Schristos if (GET_U_1(p) != 0xff) { 31280f74e101Schristos p++; 31290f74e101Schristos continue; 31300f74e101Schristos } 31310f74e101Schristos 3132c74ad251Schristos if (!ND_TTEST_LEN(p, sizeof(marker))) 31330f74e101Schristos break; 31340f74e101Schristos if (memcmp(p, marker, sizeof(marker)) != 0) { 31350f74e101Schristos p++; 31360f74e101Schristos continue; 31370f74e101Schristos } 31380f74e101Schristos 31390f74e101Schristos /* found BGP header */ 3140c74ad251Schristos ND_TCHECK_LEN(p, BGP_SIZE); 3141c74ad251Schristos bgp_header = (const struct bgp *)p; 31420f74e101Schristos 31430f74e101Schristos if (start != p) 3144c74ad251Schristos nd_print_trunc(ndo); 31450f74e101Schristos 3146c74ad251Schristos hlen = GET_BE_U_2(bgp_header->bgp_len); 31470f74e101Schristos if (hlen < BGP_SIZE) { 3148c74ad251Schristos ND_PRINT("\nmessage length %u < %u", hlen, BGP_SIZE); 3149c74ad251Schristos nd_print_invalid(ndo); 31500f74e101Schristos break; 31510f74e101Schristos } 31520f74e101Schristos 3153c74ad251Schristos if (ND_TTEST_LEN(p, hlen)) { 3154c74ad251Schristos if (!bgp_pdu_print(ndo, p, hlen)) 31550f74e101Schristos return; 31560f74e101Schristos p += hlen; 31570f74e101Schristos start = p; 31580f74e101Schristos } else { 3159c74ad251Schristos ND_PRINT("\n[|BGP %s]", 3160fdccd7e4Schristos tok2str(bgp_msg_values, 31610f74e101Schristos "Unknown Message Type", 3162c74ad251Schristos GET_U_1(bgp_header->bgp_type))); 31630f74e101Schristos break; 31640f74e101Schristos } 31650f74e101Schristos } 31660f74e101Schristos 31670f74e101Schristos return; 31680f74e101Schristos 31690f74e101Schristos trunc: 3170c74ad251Schristos nd_print_trunc(ndo); 31710f74e101Schristos } 3172