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