Download raw body.
bgpd: rtr protocol fixes
The current handling of RTR min-version is not complete.
In rtr_parse_header() there is an implicit downgrade path that I missed
when introducing min_version.
So check min_version in the implict downgrade case and error out if the
suggested version is too low. Also trigger the RTR_EVNT_NEGOTIATION_DONE
event only after parsing all of the header. If the PDU was bad don't
trigger this event.
In the rtr_fsm() when closing a connection check the state of the
active_lock and if the lock is held, reset the cache, release the lock and
recalculate the sets. The internal state is corrupt if a connection error
triggerd during an exchange so it makes no sense to carry a bad cache
around.
--
:wq Claudio
Index: rtr_proto.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rtr_proto.c,v
diff -u -p -r1.53 rtr_proto.c
--- rtr_proto.c 30 Apr 2026 18:22:59 -0000 1.53
+++ rtr_proto.c 18 May 2026 13:08:41 -0000
@@ -471,6 +471,7 @@ rtr_parse_header(struct rtr_session *rs,
struct ibuf hdr;
size_t len;
uint16_t errcode;
+ int neg_done = 0;
len = ibuf_size(msg);
@@ -482,12 +483,14 @@ rtr_parse_header(struct rtr_session *rs,
switch (rh.type) {
case CACHE_RESPONSE:
case CACHE_RESET:
- /* implicit downgrade */
+ /* implicit downgrade if allowed */
if (rh.version < rs->version) {
+ if (rh.version < rs->min_version)
+ goto badversion;
rs->prev_version = rs->version;
rs->version = rh.version;
}
- rtr_fsm(rs, RTR_EVNT_NEGOTIATION_DONE);
+ neg_done = 1;
break;
case ERROR_REPORT:
errcode = ntohs(rh.session_id);
@@ -563,8 +566,10 @@ rtr_parse_header(struct rtr_session *rs,
return -1;
}
- *msgtype = rh.type;
+ if (neg_done)
+ rtr_fsm(rs, RTR_EVNT_NEGOTIATION_DONE);
+ *msgtype = rh.type;
return 0;
badlen:
@@ -573,8 +578,8 @@ rtr_parse_header(struct rtr_session *rs,
return -1;
badversion:
- rtr_send_error(rs, msg, UNEXP_PROTOCOL_VERS, "%s: version %d",
- log_rtr_type(rh.type), rh.version);
+ rtr_send_error(rs, msg, UNEXP_PROTOCOL_VERS, "%s: version %d want %d",
+ log_rtr_type(rh.type), rh.version, rs->version);
return -1;
}
@@ -1133,10 +1138,20 @@ rtr_fsm(struct rtr_session *rs, enum rtr
rtr_send_serial_query(rs);
break;
case RTR_EVNT_RESET_AND_CLOSE:
- rtr_reset_cache(rs);
- rtr_recalc();
- /* FALLTHROUGH */
case RTR_EVNT_CON_CLOSE:
+ /*
+ * Reset cache after an error or if the connection is reset
+ * during a delta exchange. The internal state in that moment
+ * is possibly corrupt and should not be used.
+ */
+ if (event == RTR_EVNT_RESET_AND_CLOSE ||
+ rs->active_lock) {
+ rtr_reset_cache(rs);
+ rtr_sem_release(rs->active_lock);
+ rs->active_lock = 0;
+ rtr_recalc();
+ }
+
if (rs->fd != -1) {
/* flush buffers */
msgbuf_clear(rs->w);
bgpd: rtr protocol fixes