mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 04:50:35 +00:00 
			
		
		
		
	When received malformed AS4 capability, it should return -1 (notification send), and the received flag SHOULD NOT be set. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
		
			
				
	
	
		
			986 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			986 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/*
 | 
						|
 * Copyright (C) 2007 Sun Microsystems, Inc.
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "qobj.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "stream.h"
 | 
						|
#include "privs.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "queue.h"
 | 
						|
#include "filter.h"
 | 
						|
#include "frr_pthread.h"
 | 
						|
 | 
						|
#include "bgpd/bgpd.c"
 | 
						|
#include "bgpd/bgp_open.h"
 | 
						|
#include "bgpd/bgp_debug.h"
 | 
						|
#include "bgpd/bgp_packet.h"
 | 
						|
 | 
						|
#define VT100_RESET "\x1b[0m"
 | 
						|
#define VT100_RED "\x1b[31m"
 | 
						|
#define VT100_GREEN "\x1b[32m"
 | 
						|
#define VT100_YELLOW "\x1b[33m"
 | 
						|
 | 
						|
#define CAPABILITY 0
 | 
						|
#define DYNCAP     1
 | 
						|
#define OPT_PARAM  2
 | 
						|
 | 
						|
/* need these to link in libbgp */
 | 
						|
struct zebra_privs_t bgpd_privs = {};
 | 
						|
struct event_loop *master = NULL;
 | 
						|
 | 
						|
static int failed = 0;
 | 
						|
static int tty = 0;
 | 
						|
 | 
						|
/* test segments to parse and validate, and use for other tests */
 | 
						|
static struct test_segment {
 | 
						|
	const char *name;
 | 
						|
	const char *desc;
 | 
						|
	const uint8_t data[1024];
 | 
						|
	int len;
 | 
						|
#define SHOULD_PARSE	0
 | 
						|
#define SHOULD_ERR	-1
 | 
						|
	int parses;    /* whether it should parse or not */
 | 
						|
	as_t peek_for; /* what peek_for_as4_capability should say */
 | 
						|
 | 
						|
	/* AFI/SAFI validation */
 | 
						|
	int validate_afi;
 | 
						|
	iana_afi_t afi;
 | 
						|
	iana_safi_t safi;
 | 
						|
#define VALID_AFI 1
 | 
						|
#define INVALID_AFI 0
 | 
						|
	int afi_valid;
 | 
						|
} test_segments[] = {
 | 
						|
	/* 0 */
 | 
						|
	{
 | 
						|
		"caphdr",
 | 
						|
		"capability header, and no more",
 | 
						|
		{CAPABILITY_CODE_REFRESH, 0x0},
 | 
						|
		2,
 | 
						|
		SHOULD_PARSE,
 | 
						|
	},
 | 
						|
	/* 1 */
 | 
						|
	{
 | 
						|
		"nodata",
 | 
						|
		"header, no data but length says there is",
 | 
						|
		{0x1, 0xa},
 | 
						|
		2,
 | 
						|
		SHOULD_ERR,
 | 
						|
	},
 | 
						|
	/* 2 */
 | 
						|
	{
 | 
						|
		"padded",
 | 
						|
		"valid, with padding",
 | 
						|
		{CAPABILITY_CODE_REFRESH, 0x2, 0x0, 0x0},
 | 
						|
		4,
 | 
						|
		SHOULD_PARSE,
 | 
						|
	},
 | 
						|
	/* 3 */
 | 
						|
	{
 | 
						|
		"minsize",
 | 
						|
		"violates minsize requirement",
 | 
						|
		{CAPABILITY_CODE_ORF, 0x2, 0x0, 0x0},
 | 
						|
		4,
 | 
						|
		SHOULD_ERR,
 | 
						|
	},
 | 
						|
	{NULL, NULL, {0}, 0, 0},
 | 
						|
};
 | 
						|
 | 
						|
static struct test_segment mp_segments[] = {
 | 
						|
	{
 | 
						|
		"MP4",
 | 
						|
		"MP IP/Uni",
 | 
						|
		{0x1, 0x4, 0x0, 0x1, 0x0, 0x1},
 | 
						|
		6,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		IANA_AFI_IPV4,
 | 
						|
		IANA_SAFI_UNICAST,
 | 
						|
		VALID_AFI,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"MPv6",
 | 
						|
		"MP IPv6/Uni",
 | 
						|
		{0x1, 0x4, 0x0, 0x2, 0x0, 0x1},
 | 
						|
		6,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		IANA_AFI_IPV6,
 | 
						|
		IANA_SAFI_UNICAST,
 | 
						|
		VALID_AFI,
 | 
						|
	},
 | 
						|
	/* 5 */
 | 
						|
	{
 | 
						|
		"MP2",
 | 
						|
		"MP IP/Multicast",
 | 
						|
		{CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x2},
 | 
						|
		6,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		IANA_AFI_IPV4,
 | 
						|
		IANA_SAFI_MULTICAST,
 | 
						|
		VALID_AFI,
 | 
						|
	},
 | 
						|
	/* 6 */
 | 
						|
	{
 | 
						|
		"MP3",
 | 
						|
		"MP IP6/MPLS-labeled VPN",
 | 
						|
		{CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x80},
 | 
						|
		6,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		IANA_AFI_IPV6,
 | 
						|
		IANA_SAFI_MPLS_VPN,
 | 
						|
		VALID_AFI,
 | 
						|
	},
 | 
						|
	/* 7 */
 | 
						|
	{
 | 
						|
		"MP5",
 | 
						|
		"MP IP6/MPLS-VPN",
 | 
						|
		{CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x4},
 | 
						|
		6,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		IANA_AFI_IPV6,
 | 
						|
		IANA_SAFI_MPLS_VPN,
 | 
						|
		VALID_AFI,
 | 
						|
	},
 | 
						|
	/* 8 */
 | 
						|
	{
 | 
						|
		"MP6",
 | 
						|
		"MP IP4/MPLS-labeled VPN",
 | 
						|
		{CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80},
 | 
						|
		6,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		IANA_AFI_IPV4,
 | 
						|
		IANA_SAFI_MPLS_VPN,
 | 
						|
		VALID_AFI,
 | 
						|
	},
 | 
						|
	/* 10 */
 | 
						|
	{
 | 
						|
		"MP8",
 | 
						|
		"MP unknown AFI/SAFI",
 | 
						|
		{CAPABILITY_CODE_MP, 0x4, 0x0, 0xa, 0x0, 0x81},
 | 
						|
		6,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		0xa,
 | 
						|
		0x81,
 | 
						|
		INVALID_AFI, /* parses, but unknown */
 | 
						|
	},
 | 
						|
	/* 11 */
 | 
						|
	{
 | 
						|
		"MP-short",
 | 
						|
		"MP IP4/Unicast, length too short (< minimum)",
 | 
						|
		{CAPABILITY_CODE_MP, 0x2, 0x0, 0x1, 0x0, 0x1},
 | 
						|
		6,
 | 
						|
		SHOULD_ERR,
 | 
						|
	},
 | 
						|
	/* 12 */
 | 
						|
	{
 | 
						|
		"MP-overflow",
 | 
						|
		"MP IP4/Unicast, length too long",
 | 
						|
		{CAPABILITY_CODE_MP, 0x6, 0x0, 0x1, 0x0, 0x1},
 | 
						|
		6,
 | 
						|
		SHOULD_ERR,
 | 
						|
		0,
 | 
						|
		1,
 | 
						|
		IANA_AFI_IPV4,
 | 
						|
		IANA_SAFI_UNICAST,
 | 
						|
		VALID_AFI,
 | 
						|
	},
 | 
						|
	{NULL, NULL, {0}, 0, 0}};
 | 
						|
 | 
						|
static struct test_segment misc_segments[] =
 | 
						|
	{
 | 
						|
		/* 13 */
 | 
						|
		{
 | 
						|
			"ORF",
 | 
						|
			"ORF, simple, single entry, single tuple",
 | 
						|
			{/* hdr */ CAPABILITY_CODE_ORF, 0x7,
 | 
						|
			 /* mpc */ 0x0, 0x1, 0x0, 0x1,
 | 
						|
			 /* num */ 0x1,
 | 
						|
			 /* tuples */ 0x40, 0x3},
 | 
						|
			9,
 | 
						|
			SHOULD_PARSE,
 | 
						|
		},
 | 
						|
		/* 14 */
 | 
						|
		{
 | 
						|
			"ORF-many",
 | 
						|
			"ORF, multi entry/tuple",
 | 
						|
			{
 | 
						|
				/* hdr */ CAPABILITY_CODE_ORF,
 | 
						|
				0x21,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x1,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				ORF_MODE_BOTH,
 | 
						|
				0x80,
 | 
						|
				ORF_MODE_RECEIVE,
 | 
						|
				0x80,
 | 
						|
				ORF_MODE_SEND,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				ORF_MODE_BOTH,
 | 
						|
				0x80,
 | 
						|
				ORF_MODE_RECEIVE,
 | 
						|
				0x80,
 | 
						|
				ORF_MODE_SEND,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x2,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				ORF_MODE_RECEIVE,
 | 
						|
				0x80,
 | 
						|
				ORF_MODE_SEND,
 | 
						|
				0x80,
 | 
						|
				ORF_MODE_BOTH,
 | 
						|
			},
 | 
						|
			35,
 | 
						|
			SHOULD_PARSE,
 | 
						|
		},
 | 
						|
		/* 15 */
 | 
						|
		{
 | 
						|
			"ORFlo",
 | 
						|
			"ORF, multi entry/tuple, hdr length too short",
 | 
						|
			{
 | 
						|
				/* hdr */ CAPABILITY_CODE_ORF,
 | 
						|
				0x15,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x1,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x1,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x2,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
			},
 | 
						|
			35,
 | 
						|
			SHOULD_ERR, /* It should error on invalid
 | 
						|
				       Route-Refresh.. */
 | 
						|
		},
 | 
						|
		/* 16 */
 | 
						|
		{"ORFlu",
 | 
						|
		 "ORF, multi entry/tuple, length too long",
 | 
						|
		 {
 | 
						|
			 /* hdr */ 0x3,
 | 
						|
			 0x22,
 | 
						|
			 /* mpc */ 0x0,
 | 
						|
			 0x1,
 | 
						|
			 0x0,
 | 
						|
			 0x1,
 | 
						|
			 /* num */ 0x3,
 | 
						|
			 /* tuples */ 0x40,
 | 
						|
			 0x3,
 | 
						|
			 0x80,
 | 
						|
			 0x1,
 | 
						|
			 0x80,
 | 
						|
			 0x2,
 | 
						|
			 /* mpc */ 0x0,
 | 
						|
			 0x2,
 | 
						|
			 0x0,
 | 
						|
			 0x1,
 | 
						|
			 /* num */ 0x3,
 | 
						|
			 /* tuples */ 0x40,
 | 
						|
			 0x3,
 | 
						|
			 0x80,
 | 
						|
			 0x1,
 | 
						|
			 0x80,
 | 
						|
			 0x2,
 | 
						|
			 /* mpc */ 0x0,
 | 
						|
			 0x2,
 | 
						|
			 0x0,
 | 
						|
			 0x2,
 | 
						|
			 /* num */ 0x3,
 | 
						|
			 /* tuples */ 0x40,
 | 
						|
			 0x3,
 | 
						|
			 0x80,
 | 
						|
			 0x1,
 | 
						|
			 0x80,
 | 
						|
			 0x2,
 | 
						|
		 },
 | 
						|
		 35,
 | 
						|
		 SHOULD_ERR},
 | 
						|
		/* 17 */
 | 
						|
		{
 | 
						|
			"ORFnu",
 | 
						|
			"ORF, multi entry/tuple, entry number too long",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x3,
 | 
						|
				0x21,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x1,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x4,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x2,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
			},
 | 
						|
			35,
 | 
						|
			SHOULD_PARSE, /* parses, but last few tuples should be
 | 
						|
					 gibberish */
 | 
						|
		},
 | 
						|
		/* 18 */
 | 
						|
		{
 | 
						|
			"ORFno",
 | 
						|
			"ORF, multi entry/tuple, entry number too short",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x3,
 | 
						|
				0x21,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x1,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x1,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x2,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
			},
 | 
						|
			35,
 | 
						|
			SHOULD_PARSE, /* Parses, but should get gibberish
 | 
						|
					 afi/safis */
 | 
						|
		},
 | 
						|
		/* 17 */
 | 
						|
		{
 | 
						|
			"ORFpad",
 | 
						|
			"ORF, multi entry/tuple, padded to align",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x3,
 | 
						|
				0x22,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x1,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x1,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				/* mpc */ 0x0,
 | 
						|
				0x2,
 | 
						|
				0x0,
 | 
						|
				0x2,
 | 
						|
				/* num */ 0x3,
 | 
						|
				/* tuples */ 0x40,
 | 
						|
				0x3,
 | 
						|
				0x80,
 | 
						|
				0x1,
 | 
						|
				0x80,
 | 
						|
				0x2,
 | 
						|
				0x00,
 | 
						|
			},
 | 
						|
			36,
 | 
						|
			SHOULD_PARSE,
 | 
						|
		},
 | 
						|
		/* 19 */
 | 
						|
		{
 | 
						|
			"AS4",
 | 
						|
			"AS4 capability",
 | 
						|
			{0x41, 0x4, 0xab, 0xcd, 0xef,
 | 
						|
			 0x12}, /* AS: 2882400018 */
 | 
						|
			6,
 | 
						|
			SHOULD_PARSE,
 | 
						|
			2882400018,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"AS4",
 | 
						|
			"AS4 capability: short",
 | 
						|
			{0x41, 0x4, 0xab, 0xcd, 0xef}, /* AS: 2882400018 */
 | 
						|
			5,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"AS4",
 | 
						|
			"AS4 capability: long",
 | 
						|
			{0x41, 0x4, 0xab, 0xcd, 0xef, 0x12, 0x12},
 | 
						|
			7,
 | 
						|
			SHOULD_ERR,
 | 
						|
			2882400018,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"GR",
 | 
						|
			"GR capability",
 | 
						|
			{
 | 
						|
				/* hdr */ CAPABILITY_CODE_RESTART, 0xe,
 | 
						|
				/* R-bit, time */ 0xf1, 0x12,
 | 
						|
				/* afi */ 0x0, 0x1,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0xf,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0x0,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x2,
 | 
						|
				/* flags */ 0x1,
 | 
						|
			},
 | 
						|
			16,
 | 
						|
			SHOULD_PARSE,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"GR-short",
 | 
						|
			"GR capability, but header length too short",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x40, 0xa,
 | 
						|
				/* R-bit, time */ 0xf1, 0x12,
 | 
						|
				/* afi */ 0x0, 0x1,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0xf,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0x0,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x2,
 | 
						|
				/* flags */ 0x1,
 | 
						|
			},
 | 
						|
			15 /* array is 16 though */,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"GR-long",
 | 
						|
			"GR capability, but header length too long",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x40, 0xf,
 | 
						|
				/* R-bit, time */ 0xf1, 0x12,
 | 
						|
				/* afi */ 0x0, 0x1,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0xf,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0x0,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x2,
 | 
						|
				/* flags */ 0x01,
 | 
						|
			},
 | 
						|
			16,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"GR-trunc",
 | 
						|
			"GR capability, but truncated",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x40, 0xf,
 | 
						|
				/* R-bit, time */ 0xf1, 0x12,
 | 
						|
				/* afi */ 0x0, 0x1,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0xf,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x1,
 | 
						|
				/* flags */ 0x0,
 | 
						|
				/* afi */ 0x0, 0x2,
 | 
						|
				/* safi */ 0x2,
 | 
						|
				/* flags */ 0x1,
 | 
						|
			},
 | 
						|
			15,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"GR-empty",
 | 
						|
			"GR capability, but empty.",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x40, 0x0,
 | 
						|
			},
 | 
						|
			2,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"MP-empty",
 | 
						|
			"MP capability, but empty.",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x1, 0x0,
 | 
						|
			},
 | 
						|
			2,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"ORF-empty",
 | 
						|
			"ORF capability, but empty.",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x3, 0x0,
 | 
						|
			},
 | 
						|
			2,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"AS4-empty",
 | 
						|
			"AS4 capability, but empty.",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x41, 0x0,
 | 
						|
			},
 | 
						|
			2,
 | 
						|
			SHOULD_ERR,
 | 
						|
			-1,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"dyn-empty",
 | 
						|
			"Dynamic capability, but empty.",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x42, 0x0,
 | 
						|
			},
 | 
						|
			2,
 | 
						|
			SHOULD_PARSE,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"dyn-old",
 | 
						|
			"Dynamic capability (deprecated version)",
 | 
						|
			{CAPABILITY_CODE_DYNAMIC, 0x0},
 | 
						|
			2,
 | 
						|
			SHOULD_PARSE,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"Role",
 | 
						|
			"Role capability",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x9, 0x1,
 | 
						|
				0x1,
 | 
						|
			},
 | 
						|
			3,
 | 
						|
			SHOULD_PARSE,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"Role-long",
 | 
						|
			"Role capability, but too long",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x9, 0x4,
 | 
						|
				0x0, 0x0, 0x0, 0x1,
 | 
						|
			},
 | 
						|
			6,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			"Role-empty",
 | 
						|
			"Role capability, but empty.",
 | 
						|
			{
 | 
						|
				/* hdr */ 0x9, 0x0,
 | 
						|
			},
 | 
						|
			2,
 | 
						|
			SHOULD_ERR,
 | 
						|
		},
 | 
						|
		{NULL, NULL, {0}, 0, 0}};
 | 
						|
 | 
						|
/* DYNAMIC message */
 | 
						|
struct test_segment dynamic_cap_msgs[] = {
 | 
						|
	{
 | 
						|
		"DynCap",
 | 
						|
		"Dynamic Capability Message, IP/Multicast",
 | 
						|
		{0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2},
 | 
						|
		7,
 | 
						|
		SHOULD_PARSE, /* horrible alignment, just as with ORF */
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"DynCapLong",
 | 
						|
		"Dynamic Capability Message, IP/Multicast, truncated",
 | 
						|
		{0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2},
 | 
						|
		5,
 | 
						|
		SHOULD_ERR,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"DynCapPadded",
 | 
						|
		"Dynamic Capability Message, IP/Multicast, padded",
 | 
						|
		{0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2, 0x0},
 | 
						|
		8,
 | 
						|
		SHOULD_ERR, /* No way to tell padding from data.. */
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"DynCapMPCpadded",
 | 
						|
		"Dynamic Capability Message, IP/Multicast, cap data padded",
 | 
						|
		{0x0, 0x1, 0x5, 0x0, 0x1, 0x0, 0x2, 0x0},
 | 
						|
		8,
 | 
						|
		SHOULD_PARSE, /* You can though add padding to the capability
 | 
						|
				 data */
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"DynCapMPCoverflow",
 | 
						|
		"Dynamic Capability Message, IP/Multicast, cap data != length",
 | 
						|
		{0x0, 0x1, 0x3, 0x0, 0x1, 0x0, 0x2, 0x0},
 | 
						|
		8,
 | 
						|
		SHOULD_ERR,
 | 
						|
	},
 | 
						|
	{NULL, NULL, {0}, 0, 0}};
 | 
						|
 | 
						|
/* Entire Optional-Parameters block */
 | 
						|
struct test_segment opt_params[] = {
 | 
						|
	{
 | 
						|
		"Cap-singlets",
 | 
						|
		"One capability per Optional-Param",
 | 
						|
		{
 | 
						|
			0x02, 0x06, 0x01, 0x04,
 | 
						|
			0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
 | 
						|
			0x02, 0x06, 0x01, 0x04,
 | 
						|
			0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
 | 
						|
			0x02, 0x02, 0x80, 0x00, /* RR (old) */
 | 
						|
			0x02, 0x02, 0x02, 0x00, /* RR */
 | 
						|
		},
 | 
						|
		24,
 | 
						|
		SHOULD_PARSE,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"Cap-series",
 | 
						|
		"Series of capability, one Optional-Param",
 | 
						|
		{
 | 
						|
			0x02, 0x10, 0x01, 0x04, 0x00, 0x01, 0x00,
 | 
						|
			0x01,				    /* MP IPv4/Uni */
 | 
						|
			0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
 | 
						|
			0x80, 0x00,			    /* RR (old) */
 | 
						|
			0x02, 0x00,			    /* RR */
 | 
						|
		},
 | 
						|
		18,
 | 
						|
		SHOULD_PARSE,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"AS4more",
 | 
						|
		"AS4 capability after other caps (singlets)",
 | 
						|
		{
 | 
						|
			0x02, 0x06, 0x01, 0x04,
 | 
						|
			0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */
 | 
						|
			0x02, 0x06, 0x01, 0x04,
 | 
						|
			0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
 | 
						|
			0x02, 0x02, 0x80, 0x00, /* RR (old) */
 | 
						|
			0x02, 0x02, 0x02, 0x00, /* RR */
 | 
						|
			0x02, 0x06, 0x41, 0x04,
 | 
						|
			0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */
 | 
						|
		},
 | 
						|
		32,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		196614,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"AS4series",
 | 
						|
		"AS4 capability, in series of capabilities",
 | 
						|
		{
 | 
						|
			0x02, 0x16, 0x01, 0x04, 0x00, 0x01,
 | 
						|
			0x00, 0x01,			    /* MP IPv4/Uni */
 | 
						|
			0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */
 | 
						|
			0x80, 0x00,			    /* RR (old) */
 | 
						|
			0x02, 0x00,			    /* RR */
 | 
						|
			0x41, 0x04, 0x00, 0x03, 0x00, 0x06  /* AS4: 1996614 */
 | 
						|
		},
 | 
						|
		24,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		196614,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"AS4real",
 | 
						|
		"AS4 capability, in series of capabilities",
 | 
						|
		{
 | 
						|
			0x02, 0x06, 0x01, 0x04,
 | 
						|
			0x00, 0x01, 0x00, 0x01, /* MP IPv4/uni */
 | 
						|
			0x02, 0x06, 0x01, 0x04,
 | 
						|
			0x00, 0x02, 0x00, 0x01, /* MP IPv6/uni */
 | 
						|
			0x02, 0x02, 0x80, 0x00, /* RR old */
 | 
						|
			0x02, 0x02, 0x02, 0x00, /* RR */
 | 
						|
			0x02, 0x06, 0x41, 0x04,
 | 
						|
			0x00, 0x03, 0x00, 0x06, /* AS4 */
 | 
						|
		},
 | 
						|
		32,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		196614,
 | 
						|
	},
 | 
						|
	{
 | 
						|
		"AS4real2",
 | 
						|
		"AS4 capability, in series of capabilities",
 | 
						|
		{
 | 
						|
			0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02,
 | 
						|
			0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02,
 | 
						|
			0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x06, 0x41,
 | 
						|
			0x04, 0x00, 0x00, 0xfc, 0x03, 0x02, 0x09, 0x82, 0x07,
 | 
						|
			0x00, 0x01, 0x00, 0x01, 0x01, 0x80, 0x03, 0x02, 0x09,
 | 
						|
			0x03, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x40, 0x03,
 | 
						|
			0x02, 0x02, 0x42, 0x00,
 | 
						|
		},
 | 
						|
		58,
 | 
						|
		SHOULD_PARSE,
 | 
						|
		64515,
 | 
						|
	},
 | 
						|
 | 
						|
	{NULL, NULL, {0}, 0, 0}};
 | 
						|
 | 
						|
/* basic parsing test */
 | 
						|
static void parse_test(struct peer *peer, struct test_segment *t, int type)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
	int capability = 0;
 | 
						|
	as_t as4 = 0;
 | 
						|
	int oldfailed = failed;
 | 
						|
	int len = t->len;
 | 
						|
#define RANDOM_FUZZ 35
 | 
						|
 | 
						|
	stream_reset(peer->curr);
 | 
						|
	stream_put(peer->curr, NULL, RANDOM_FUZZ);
 | 
						|
	stream_set_getp(peer->curr, RANDOM_FUZZ);
 | 
						|
 | 
						|
	switch (type) {
 | 
						|
	case CAPABILITY:
 | 
						|
		stream_putc(peer->curr, BGP_OPEN_OPT_CAP);
 | 
						|
		stream_putc(peer->curr, t->len);
 | 
						|
		break;
 | 
						|
	case DYNCAP:
 | 
						|
		/*        for (i = 0; i < BGP_MARKER_SIZE; i++)
 | 
						|
			  stream_putc (peer->, 0xff);
 | 
						|
			stream_putw (s, 0);
 | 
						|
			stream_putc (s, BGP_MSG_CAPABILITY);*/
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	stream_write(peer->curr, t->data, t->len);
 | 
						|
 | 
						|
	printf("%s: %s\n", t->name, t->desc);
 | 
						|
 | 
						|
	switch (type) {
 | 
						|
	case CAPABILITY:
 | 
						|
		len += 2; /* to cover the OPT-Param header */
 | 
						|
		fallthrough;
 | 
						|
	case OPT_PARAM:
 | 
						|
		printf("len: %u\n", len);
 | 
						|
		/* peek_for_as4 wants getp at capibility*/
 | 
						|
		as4 = peek_for_as4_capability(peer, len);
 | 
						|
		printf("peek_for_as4: as4 is %u\n", as4);
 | 
						|
		/* and it should leave getp as it found it */
 | 
						|
		assert(stream_get_getp(peer->curr) == RANDOM_FUZZ);
 | 
						|
 | 
						|
		ret = bgp_open_option_parse(peer, len, &capability);
 | 
						|
		break;
 | 
						|
	case DYNCAP:
 | 
						|
		ret = bgp_capability_receive(peer->connection, peer, t->len);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		printf("unknown type %u\n", type);
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
 | 
						|
	if (ret != BGP_Stop && t->validate_afi) {
 | 
						|
		afi_t afi;
 | 
						|
		safi_t safi;
 | 
						|
 | 
						|
		/* Convert AFI, SAFI to internal values, check. */
 | 
						|
		if (bgp_map_afi_safi_iana2int(t->afi, t->safi, &afi, &safi)) {
 | 
						|
			if (t->afi_valid == VALID_AFI)
 | 
						|
				failed++;
 | 
						|
		}
 | 
						|
		printf("MP: %u(%u)/%u(%u): recv %u, nego %u\n", t->afi, afi,
 | 
						|
		       t->safi, safi, peer->afc_recv[afi][safi],
 | 
						|
		       peer->afc_nego[afi][safi]);
 | 
						|
 | 
						|
		if (t->afi_valid == VALID_AFI) {
 | 
						|
 | 
						|
			if (!peer->afc_recv[afi][safi])
 | 
						|
				failed++;
 | 
						|
			if (!peer->afc_nego[afi][safi])
 | 
						|
				failed++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (as4 != t->peek_for) {
 | 
						|
		printf("as4 %u != %u\n", as4, t->peek_for);
 | 
						|
		failed++;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Some of the functions used return BGP_Stop on error and some return
 | 
						|
	 * -1. If we have -1, keep it; if we have BGP_Stop, transform it to the
 | 
						|
	 * correct pass/fail code
 | 
						|
	 */
 | 
						|
	if (ret != -1)
 | 
						|
		ret = (ret == BGP_Stop) ? -1 : 0;
 | 
						|
 | 
						|
	printf("parsed?: %s\n", ret ? "no" : "yes");
 | 
						|
 | 
						|
	if (ret != t->parses) {
 | 
						|
		printf("t->parses: %d\nret: %d\n", t->parses, ret);
 | 
						|
		failed++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (tty)
 | 
						|
		printf("%s",
 | 
						|
		       (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET
 | 
						|
					    : VT100_GREEN "OK" VT100_RESET);
 | 
						|
	else
 | 
						|
		printf("%s", (failed > oldfailed) ? "failed!" : "OK");
 | 
						|
 | 
						|
	if (failed)
 | 
						|
		printf(" (%u)", failed);
 | 
						|
 | 
						|
	printf("\n\n");
 | 
						|
}
 | 
						|
 | 
						|
static struct bgp *bgp;
 | 
						|
static as_t asn = 100;
 | 
						|
 | 
						|
int main(void)
 | 
						|
{
 | 
						|
	struct peer *peer;
 | 
						|
	int i, j;
 | 
						|
 | 
						|
	conf_bgp_debug_neighbor_events = -1UL;
 | 
						|
	conf_bgp_debug_packet = -1UL;
 | 
						|
	conf_bgp_debug_as4 = -1UL;
 | 
						|
	term_bgp_debug_neighbor_events = -1UL;
 | 
						|
	term_bgp_debug_packet = -1UL;
 | 
						|
	term_bgp_debug_as4 = -1UL;
 | 
						|
 | 
						|
	qobj_init();
 | 
						|
	master = event_master_create(NULL);
 | 
						|
	bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
 | 
						|
	vrf_init(NULL, NULL, NULL, NULL);
 | 
						|
	bgp_option_set(BGP_OPT_NO_LISTEN);
 | 
						|
 | 
						|
	frr_pthread_init();
 | 
						|
	bgp_pthreads_init();
 | 
						|
	bgp_pth_ka->running = true;
 | 
						|
 | 
						|
	if (fileno(stdout) >= 0)
 | 
						|
		tty = isatty(fileno(stdout));
 | 
						|
 | 
						|
	if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
 | 
						|
		    ASNOTATION_PLAIN) < 0)
 | 
						|
		return -1;
 | 
						|
 | 
						|
	peer = peer_create_accept(bgp);
 | 
						|
	peer->host = (char *)"foo";
 | 
						|
 | 
						|
	for (i = AFI_IP; i < AFI_MAX; i++)
 | 
						|
		for (j = SAFI_UNICAST; j < SAFI_MAX; j++) {
 | 
						|
			peer->afc[i][j] = 1;
 | 
						|
			peer->afc_adv[i][j] = 1;
 | 
						|
		}
 | 
						|
 | 
						|
	peer->curr = stream_new(BGP_MAX_PACKET_SIZE);
 | 
						|
 | 
						|
	i = 0;
 | 
						|
	while (mp_segments[i].name)
 | 
						|
		parse_test(peer, &mp_segments[i++], CAPABILITY);
 | 
						|
 | 
						|
	/* These tests assume mp_segments tests set at least
 | 
						|
	 * one of the afc_nego's
 | 
						|
	 */
 | 
						|
	i = 0;
 | 
						|
	while (test_segments[i].name)
 | 
						|
		parse_test(peer, &test_segments[i++], CAPABILITY);
 | 
						|
 | 
						|
	i = 0;
 | 
						|
	while (misc_segments[i].name)
 | 
						|
		parse_test(peer, &misc_segments[i++], CAPABILITY);
 | 
						|
 | 
						|
	i = 0;
 | 
						|
	while (opt_params[i].name)
 | 
						|
		parse_test(peer, &opt_params[i++], OPT_PARAM);
 | 
						|
 | 
						|
	SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV);
 | 
						|
	peer->connection = bgp_peer_connection_new(peer);
 | 
						|
	peer->connection->status = Established;
 | 
						|
 | 
						|
	i = 0;
 | 
						|
	while (dynamic_cap_msgs[i].name)
 | 
						|
		parse_test(peer, &dynamic_cap_msgs[i++], DYNCAP);
 | 
						|
 | 
						|
	printf("failures: %d\n", failed);
 | 
						|
	return failed;
 | 
						|
}
 |