Hello BIRD maintainers, I would like to report a possible RFC 7607 compliance issue in BIRD's BGP UPDATE validation: routes whose AS_PATH contains AS number 0 appear to be accepted into the BGP table instead of being treated as malformed. Summary BIRD appears not to reject AS 0 when it appears inside the AS_PATH path attribute. I tested this with an eBGP session where the peer sent a valid UPDATE whose AS_PATH was: 65002 0 BIRD accepted the route and displayed the AS_PATH with the reserved AS 0 still present. RFC 7607 Section 2 states that a BGP speaker must not originate or propagate a route with AS number 0 in AS_PATH, and that an UPDATE containing AS number 0 in AS_PATH must be considered malformed and handled according to RFC 7606. For a malformed AS_PATH attribute with parseable NLRI, RFC 7606 handling should be treat-as-withdraw: the route should not be installed, while the BGP session should remain established. Affected Version I reproduced this on: BIRD version 2.19.0+branch.master.880200b1f94c commit 880200b1 Observed Behavior After establishing an eBGP session, the peer sent an UPDATE for 192.0.2.0/24 with: ORIGIN: IGP AS_PATH: 65002 0 NEXT_HOP: 10.0.0.2 NLRI: 192.0.2.0/24 BIRD accepted the UPDATE. birdc show route 192.0.2.0/24 all showed: Table master4:192.0.2.0/24 unreachable [as0_test ... from 10.100.0.2] * (100) [AS0i] Type: BGP univ BGP.origin: IGP BGP.as_path: 65002 0 BGP.next_hop: 10.0.0.2 BGP.local_pref: 100 The route was marked unreachable because of next-hop resolution in the local test setup, but the important point is that the route was accepted into the BGP table with: BGP.as_path: 65002 0 I did not observe an error, warning, or treat-as-withdraw behavior for the reserved AS 0. The BIRD log showed the UPDATE being accepted: as0_test: BGP session established as0_test: Got UPDATE as0_test.ipv4 > added [best] 192.0.2.0/24 ... Expected Behavior BIRD should detect AS 0 in AS_PATH and treat the UPDATE as malformed. Since the UPDATE contains reachable NLRI and the NLRI is parseable, the expected behavior is: - do not install the route, - keep the BGP session established, - handle the route using treat-as-withdraw, consistent with RFC 7606 error handling for malformed AS_PATH attributes. Source-Level Analysis The AS_PATH decoder validates AS_PATH structure but does not appear to validate individual AS numbers against the reserved AS 0 value. In proto/bgp/attrs.c, bgp_decode_as_path() calls as_path_valid() and then stores the attribute: if (!as_path_valid(data, len, as_length, as_sets, as_confed, err, sizeof(err))) WITHDRAW("Malformed AS_PATH attribute - %s", err); ... bgp_set_attr_data(to, s->pool, BA_AS_PATH, flags, data, len); The later post-decode checks in bgp_decode_attrs() cover mandatory attribute presence, local-AS loop detection, confederation loop detection, ORIGINATOR_ID loop detection, and CLUSTER_LIST loop detection, but I could not find a check for AS 0: if (bgp_as_path_loopy(p, attrs, p->local_as)) goto loop; if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as)) goto loop; In nest/a-path.c, as_path_valid() checks segment framing, segment type, whether AS_SET / AS_CONFED_* are allowed, and zero-length segments: switch (type) { case AS_PATH_SET: if (!sets) BAD("AS_SET segment", type); break; case AS_PATH_SEQUENCE: break; case AS_PATH_CONFED_SEQUENCE: if (!confed) BAD("AS_CONFED_SEQUENCE segment", type); break; case AS_PATH_CONFED_SET: if (!sets || !confed) BAD("AS_CONFED_SET segment", type); break; default: BAD("unknown segment", type); } if (pos[1] == 0) BAD("zero-length segment", type); I did not find an equivalent validation pass that iterates through the AS numbers in the path and rejects asn == 0. Suggested Fix Add AS 0 validation during AS_PATH parsing or immediately after AS_PATH decoding. Conceptually: /* RFC 7607: AS 0 is reserved and must not appear in AS_PATH */ if (as_path_contains_as_zero(...)) WITHDRAW("Malformed AS_PATH attribute - AS 0 is reserved"); A similar validation may also be relevant for AS4_PATH, AGGREGATOR, and AS4_AGGREGATOR, since RFC 7607 also covers those attributes. However, this report only describes the AS_PATH case that I reproduced dynamically. Impact Accepting AS 0 in AS_PATH can cause interoperability and policy issues: - routes accepted by BIRD may later be rejected by stricter BGP speakers, - AS_PATH-based filters may behave unexpectedly, - reserved-AS input is allowed into routing policy and best-path processing, - this appears inconsistent with RFC 7607's reserved-AS handling. This does not require tearing down the BGP session. Treat-as-withdraw should be sufficient and would match the usual RFC 7606 approach for malformed AS_PATH attributes. Please let me know if you would like a minimal reproducer or packet capture. Best regards, Xinzhe Liu