Skip to content

Commit d23efee

Browse files
committed
isis: implement protection against replay attacks (RFC 7602)
RFC 5304 and RFC 5310 define cryptographic authentication for IS-IS PDUs but do not protect against replay attacks of IIHs and SNPs. RFC 7602 introduces the Extended Sequence Number TLV to address this gap. Signed-off-by: Renato Westphal <[email protected]>
1 parent fe7e196 commit d23efee

25 files changed

+1800
-98
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ Holo supports the following Internet Standards:
173173
* RFC 5310 - IS-IS Generic Cryptographic Authentication
174174
* RFC 6232 - Purge Originator Identification TLV for IS-IS
175175
* RFC 6233 - IS-IS Registry Extension for Purges
176+
* RFC 7602 - IS-IS Extended Sequence Number TLV
176177
* RFC 7794 - IS-IS Prefix Attributes for Extended IPv4 and IPv6 Reachability
177178
* RFC 7917 - Advertising Node Administrative Tags in IS-IS
178179
* RFC 7981 - IS-IS Extensions for Advertising Router Information

holo-isis/src/adjacency.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// See: https://nlnet.nl/NGI0
88
//
99

10-
use std::collections::BTreeSet;
10+
use std::collections::{BTreeSet, HashMap};
1111
use std::net::{Ipv4Addr, Ipv6Addr};
1212
use std::time::Instant;
1313

@@ -25,7 +25,9 @@ use crate::debug::Debug;
2525
use crate::instance::InstanceUpView;
2626
use crate::interface::{Interface, InterfaceType};
2727
use crate::northbound::notification;
28+
use crate::packet::consts::PduType;
2829
use crate::packet::subtlvs::neighbor::{AdjSidFlags, AdjSidStlv};
30+
use crate::packet::tlv::ExtendedSeqNum;
2931
use crate::packet::{AreaAddr, LanId, LevelType, SystemId};
3032
use crate::{sr, tasks};
3133

@@ -39,6 +41,7 @@ pub struct Adjacency {
3941
pub state: AdjacencyState,
4042
pub priority: Option<u8>,
4143
pub lan_id: Option<LanId>,
44+
pub ext_seqnum: HashMap<PduType, ExtendedSeqNum>,
4245
pub protocols_supported: Vec<u8>,
4346
pub area_addrs: BTreeSet<AreaAddr>,
4447
pub topologies: BTreeSet<u16>,
@@ -102,6 +105,7 @@ impl Adjacency {
102105
state: AdjacencyState::Down,
103106
priority: None,
104107
lan_id: None,
108+
ext_seqnum: Default::default(),
105109
protocols_supported: Default::default(),
106110
area_addrs: Default::default(),
107111
topologies: Default::default(),

holo-isis/src/error.rs

Lines changed: 91 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
// See: https://nlnet.nl/NGI0
88
//
99

10+
use holo_utils::DatabaseError;
1011
use holo_utils::ip::AddressFamily;
1112
use holo_yang::ToYang;
1213
use tracing::{error, warn, warn_span};
1314

1415
use crate::collections::{AdjacencyId, InterfaceId, LspEntryId};
1516
use crate::network::MulticastAddr;
17+
use crate::packet::consts::PduType;
1618
use crate::packet::error::DecodeError;
19+
use crate::packet::tlv::ExtendedSeqNum;
1720
use crate::packet::{LevelNumber, SystemId};
1821
use crate::spf;
1922

@@ -26,9 +29,8 @@ pub enum Error {
2629
InterfaceIdNotFound(InterfaceId),
2730
AdjacencyIdNotFound(AdjacencyId),
2831
LspEntryIdNotFound(LspEntryId),
29-
// Packet input
30-
PduDecodeError(String, [u8; 6], DecodeError),
31-
AdjacencyReject(String, [u8; 6], AdjacencyRejectError),
32+
// PDU input
33+
PduInputError(String, [u8; 6], PduInputError),
3234
// Segment Routing
3335
SrCapNotFound(LevelNumber, SystemId),
3436
SrCapUnsupportedAf(LevelNumber, SystemId, AddressFamily),
@@ -38,6 +40,7 @@ pub enum Error {
3840
SpfDelayUnexpectedEvent(LevelNumber, spf::fsm::State, spf::fsm::Event),
3941
InterfaceStartError(String, Box<Error>),
4042
InstanceStartError(Box<Error>),
43+
BootCountNvmUpdate(DatabaseError),
4144
}
4245

4346
// IS-IS I/O errors.
@@ -51,6 +54,13 @@ pub enum IoError {
5154
SendError(std::io::Error),
5255
}
5356

57+
#[derive(Debug)]
58+
pub enum PduInputError {
59+
DecodeError(DecodeError),
60+
AdjacencyReject(AdjacencyRejectError),
61+
ExtendedSeqNumError(ExtendedSeqNumError),
62+
}
63+
5464
#[derive(Debug)]
5565
pub enum AdjacencyRejectError {
5666
InvalidHelloType,
@@ -62,6 +72,12 @@ pub enum AdjacencyRejectError {
6272
NoCommonMt,
6373
}
6474

75+
#[derive(Debug)]
76+
pub enum ExtendedSeqNumError {
77+
MissingSeqNum(PduType),
78+
InvalidSeqNum(PduType, ExtendedSeqNum),
79+
}
80+
6581
// ===== impl Error =====
6682

6783
impl Error {
@@ -79,14 +95,7 @@ impl Error {
7995
Error::LspEntryIdNotFound(lse_id) => {
8096
warn!(?lse_id, "{}", self);
8197
}
82-
Error::PduDecodeError(ifname, source, error) => {
83-
warn_span!("interface", name = %ifname, ?source).in_scope(
84-
|| {
85-
warn!(%error, "{}", self);
86-
},
87-
)
88-
}
89-
Error::AdjacencyReject(ifname, source, error) => {
98+
Error::PduInputError(ifname, source, error) => {
9099
warn_span!("interface", name = %ifname, ?source).in_scope(
91100
|| {
92101
error.log();
@@ -114,6 +123,9 @@ impl Error {
114123
Error::InstanceStartError(error) => {
115124
error!(error = %with_source(error), "{}", self);
116125
}
126+
Error::BootCountNvmUpdate(error) => {
127+
error!(%error, "{}", self);
128+
}
117129
}
118130
}
119131
}
@@ -131,10 +143,9 @@ impl std::fmt::Display for Error {
131143
Error::LspEntryIdNotFound(..) => {
132144
write!(f, "LSP entry ID not found")
133145
}
134-
Error::PduDecodeError(..) => {
146+
Error::PduInputError(..) => {
135147
write!(f, "failed to decode packet")
136148
}
137-
Error::AdjacencyReject(_, _, error) => error.fmt(f),
138149
Error::CircuitIdAllocationFailed => {
139150
write!(f, "failed to allocate Circuit ID")
140151
}
@@ -159,6 +170,12 @@ impl std::fmt::Display for Error {
159170
Error::InstanceStartError(..) => {
160171
write!(f, "failed to start instance")
161172
}
173+
Error::BootCountNvmUpdate(..) => {
174+
write!(
175+
f,
176+
"failed to record updated boot count in non-volatile storage"
177+
)
178+
}
162179
}
163180
}
164181
}
@@ -243,10 +260,40 @@ impl std::error::Error for IoError {
243260
}
244261
}
245262

263+
// ===== impl PduInputError =====
264+
265+
impl PduInputError {
266+
fn log(&self) {
267+
match self {
268+
PduInputError::DecodeError(error) => {
269+
warn!("{}", error);
270+
}
271+
PduInputError::AdjacencyReject(error) => {
272+
error.log();
273+
}
274+
PduInputError::ExtendedSeqNumError(error) => {
275+
error.log();
276+
}
277+
}
278+
}
279+
}
280+
281+
impl From<AdjacencyRejectError> for PduInputError {
282+
fn from(error: AdjacencyRejectError) -> PduInputError {
283+
PduInputError::AdjacencyReject(error)
284+
}
285+
}
286+
287+
impl From<ExtendedSeqNumError> for PduInputError {
288+
fn from(error: ExtendedSeqNumError) -> PduInputError {
289+
PduInputError::ExtendedSeqNumError(error)
290+
}
291+
}
292+
246293
// ===== impl AdjacencyRejectError =====
247294

248295
impl AdjacencyRejectError {
249-
pub(crate) fn log(&self) {
296+
fn log(&self) {
250297
match self {
251298
AdjacencyRejectError::MaxAreaAddrsMismatch(max_area_addrs) => {
252299
warn!(%max_area_addrs, "{}", self);
@@ -288,6 +335,36 @@ impl std::fmt::Display for AdjacencyRejectError {
288335

289336
impl std::error::Error for AdjacencyRejectError {}
290337

338+
// ===== impl ExtendedSeqNumError =====
339+
340+
impl ExtendedSeqNumError {
341+
fn log(&self) {
342+
match self {
343+
ExtendedSeqNumError::MissingSeqNum(pdu_type) => {
344+
warn!(?pdu_type, "{}", self);
345+
}
346+
ExtendedSeqNumError::InvalidSeqNum(pdu_type, ext_seqnum) => {
347+
warn!(?pdu_type, ?ext_seqnum, "{}", self);
348+
}
349+
}
350+
}
351+
}
352+
353+
impl std::fmt::Display for ExtendedSeqNumError {
354+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355+
match self {
356+
ExtendedSeqNumError::MissingSeqNum(..) => {
357+
write!(f, "missing extended sequence number")
358+
}
359+
ExtendedSeqNumError::InvalidSeqNum(..) => {
360+
write!(f, "invalid extended sequence number")
361+
}
362+
}
363+
}
364+
}
365+
366+
impl std::error::Error for ExtendedSeqNumError {}
367+
291368
// ===== helper functions =====
292369

293370
fn with_source<E: std::error::Error>(error: E) -> String {

0 commit comments

Comments
 (0)