diff --git a/nest/a-path.c b/nest/a-path.c index b6a30f54..cffd46ab 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -25,7 +25,7 @@ #define BAD(DSC, VAL) ({ err_dsc = DSC; err_val = VAL; goto bad; }) int -as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen) +as_path_valid(byte *data, uint len, int bs, int sets, int confed, char *err, uint elen) { byte *pos = data; char *err_dsc = NULL; @@ -46,13 +46,21 @@ as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen) switch (type) { case AS_PATH_SET: + if (!sets) + BAD("AS_SET segment", type); + break; + case AS_PATH_SEQUENCE: break; case AS_PATH_CONFED_SEQUENCE: - case AS_PATH_CONFED_SET: if (!confed) - BAD("AS_CONFED* segment", type); + BAD("AS_CONFED_SEQUENCE segment", type); + break; + + case AS_PATH_CONFED_SET: + if (!sets || !confed) + BAD("AS_CONFED_SET segment", type); break; default: diff --git a/nest/attrs.h b/nest/attrs.h index 6fb0a8fa..3a4b0acd 100644 --- a/nest/attrs.h +++ b/nest/attrs.h @@ -30,7 +30,7 @@ struct f_tree; -int as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen); +int as_path_valid(byte *data, uint len, int bs, int sets, int confed, char *err, uint elen); int as_path_16to32(byte *dst, const byte *src, uint len); int as_path_32to16(byte *dst, const byte *src, uint len); int as_path_contains_as4(const struct adata *path); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 9a4e12d2..9b243763 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -426,10 +426,11 @@ bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte { struct bgp_proto *p = s->proto; int as_length = s->as4_session ? 4 : 2; + int as_sets = p->cf->allow_as_sets; int as_confed = p->cf->confederation && p->is_interior; char err[128]; - if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err))) + if (!as_path_valid(data, len, as_length, as_sets, as_confed, err, sizeof(err))) WITHDRAW("Malformed AS_PATH attribute - %s", err); /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */ @@ -763,6 +764,9 @@ bgp_decode_as4_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flag static void bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to) { + struct bgp_proto *p = s->proto; + int sets = p->cf->allow_as_sets; + char err[128]; if (s->as4_session) @@ -771,7 +775,7 @@ bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byt if (len < 6) DISCARD(BAD_LENGTH, "AS4_PATH", len); - if (!as_path_valid(data, len, 4, 1, err, sizeof(err))) + if (!as_path_valid(data, len, 4, sets, 1, err, sizeof(err))) DISCARD("Malformed AS4_PATH attribute - %s", err); struct adata *a = lp_alloc_adata(s->pool, len); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index d3e8f2ff..1270b8f3 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -107,6 +107,7 @@ struct bgp_config { int interpret_communities; /* Hardwired handling of well-known communities */ int allow_local_as; /* Allow that number of local ASNs in incoming AS_PATHs */ int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */ + int allow_as_sets; /* Allow AS_SETs in incoming AS_PATHs */ int gr_mode; /* Graceful restart mode (BGP_GR_*) */ int llgr_mode; /* Long-lived graceful restart mode (BGP_LLGR_*) */ int setkey; /* Set MD5 password to system SA/SP database */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 692854cf..090ba24e 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -29,7 +29,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG, - LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, + LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS, DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST) %type bgp_nh @@ -63,6 +63,7 @@ bgp_proto_start: proto_start BGP { BGP_CFG->enable_as4 = 1; BGP_CFG->capabilities = 2; BGP_CFG->interpret_communities = 1; + BGP_CFG->allow_as_sets = 1; BGP_CFG->default_local_pref = 100; BGP_CFG->gr_mode = BGP_GR_AWARE; BGP_CFG->gr_time = 120; @@ -179,6 +180,7 @@ bgp_proto: | bgp_proto ALLOW LOCAL AS ';' { BGP_CFG->allow_local_as = -1; } | bgp_proto ALLOW LOCAL AS expr ';' { BGP_CFG->allow_local_as = $5; } | bgp_proto ALLOW BGP_LOCAL_PREF bool ';' { BGP_CFG->allow_local_pref = $4; } + | bgp_proto ALLOW AS SETS bool ';' { BGP_CFG->allow_as_sets = $5; } | bgp_proto GRACEFUL RESTART bool ';' { BGP_CFG->gr_mode = $4; } | bgp_proto GRACEFUL RESTART AWARE ';' { BGP_CFG->gr_mode = BGP_GR_AWARE; } | bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; }