aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2023-03-10 21:53:30 +0100
committerHimbeerserverDE <himbeerserverde@gmail.com>2023-03-10 21:53:30 +0100
commit44f58fa52e67bd79a36909358af62a57ba03a05b (patch)
treed7efa1b91168d9f95bbd784788c4a0e1db99398a
parentb549773d26da4ed2b707253ae3091442a8564835 (diff)
add lcp option parsing
-rw-r--r--src/auth.rs34
-rw-r--r--src/error.rs7
-rw-r--r--src/lcp.rs88
-rw-r--r--src/lib.rs1
4 files changed, 130 insertions, 0 deletions
diff --git a/src/auth.rs b/src/auth.rs
new file mode 100644
index 0000000..7c3be5a
--- /dev/null
+++ b/src/auth.rs
@@ -0,0 +1,34 @@
+use byteorder::{ByteOrder, NetworkEndian as NE};
+
+use std::convert::TryFrom;
+
+use crate::error::ParseError;
+use crate::ppp::{CHAP, PAP};
+
+fn ensure_minimal_buffer_length(buffer: &[u8]) -> Result<(), ParseError> {
+ if buffer.len() < 2 {
+ return Err(ParseError::BufferTooSmall(buffer.len()));
+ }
+ Ok(())
+}
+
+#[repr(u16)]
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum Protocol {
+ Pap = PAP,
+ Chap = CHAP,
+}
+
+impl TryFrom<&[u8]> for Protocol {
+ type Error = ParseError;
+ fn try_from(protocol: &[u8]) -> Result<Self, ParseError> {
+ ensure_minimal_buffer_length(protocol)?;
+
+ let auth_protocol = NE::read_u16(&protocol[..2]);
+ match auth_protocol {
+ PAP => Ok(Protocol::Pap),
+ CHAP => Ok(Protocol::Chap),
+ _ => Err(ParseError::InvalidAuthProtocol(auth_protocol)),
+ }
+ }
+}
diff --git a/src/error.rs b/src/error.rs
index b8322f8..28c28c6 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -66,6 +66,13 @@ pub enum ParseError {
InvalidPppProtocol(u16),
InvalidLcpCode(u8),
+
+ InvalidOptionType(u8),
+ InvalidOptionLength(u8),
+
+ InvalidQualityProtocol(u16),
+
+ InvalidAuthProtocol(u16),
}
#[derive(Debug)]
diff --git a/src/lcp.rs b/src/lcp.rs
index 59a7134..4fddd1a 100644
--- a/src/lcp.rs
+++ b/src/lcp.rs
@@ -2,6 +2,7 @@ use byteorder::{ByteOrder, NetworkEndian as NE};
use std::convert::TryFrom;
+use crate::auth;
use crate::error::ParseError;
pub const CONFIGURE_REQUEST: u8 = 1;
@@ -277,3 +278,90 @@ impl<'a> HeaderBuilder<'a> {
Header::with_buffer(self.0)
}
}
+
+fn ensure_minimal_option_length(buffer: &[u8]) -> Result<(), ParseError> {
+ if buffer.len() < 2 {
+ return Err(ParseError::BufferTooSmall(buffer.len()));
+ }
+ Ok(())
+}
+
+pub const MRU: u8 = 1;
+pub const AUTH_PROTOCOL: u8 = 3;
+pub const QUALITY_PROTOCOL: u8 = 4;
+pub const MAGIC_NUMBER: u8 = 5;
+pub const PFC: u8 = 7;
+pub const ACFC: u8 = 8;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum ConfigOption<'a> {
+ Mru(u16),
+ AuthProtocol(auth::Protocol),
+ QualityProtocol(&'a [u8]),
+ MagicNumber(u32),
+ Pfc,
+ Acfc,
+}
+
+impl<'a> TryFrom<&'a [u8]> for ConfigOption<'a> {
+ type Error = ParseError;
+ fn try_from(option: &'a [u8]) -> Result<ConfigOption<'a>, ParseError> {
+ ensure_minimal_option_length(option)?;
+
+ match option[0] {
+ MRU => {
+ // constant length
+ if option[1] != 4 {
+ return Err(ParseError::InvalidOptionLength(option[1]));
+ }
+
+ Ok(ConfigOption::Mru(NE::read_u16(&option[2..4])))
+ }
+ AUTH_PROTOCOL => {
+ if option[1] < 4 {
+ return Err(ParseError::InvalidOptionLength(option[1]));
+ }
+
+ let auth_protocol = auth::Protocol::try_from(&option[2..])?;
+ Ok(ConfigOption::AuthProtocol(auth_protocol))
+ }
+ QUALITY_PROTOCOL => {
+ if option[1] < 4 {
+ return Err(ParseError::InvalidOptionLength(option[1]));
+ }
+
+ let quality_protocol = NE::read_u16(&option[2..4]);
+ if quality_protocol != 0xc025 {
+ return Err(ParseError::InvalidQualityProtocol(quality_protocol));
+ }
+
+ Ok(ConfigOption::QualityProtocol(&option[4..]))
+ }
+ MAGIC_NUMBER => {
+ // constant length
+ if option[1] != 6 {
+ return Err(ParseError::InvalidOptionLength(option[1]));
+ }
+
+ Ok(ConfigOption::MagicNumber(NE::read_u32(&option[2..6])))
+ }
+ PFC => {
+ // constant length
+ if option[1] != 2 {
+ return Err(ParseError::InvalidOptionLength(option[1]));
+ }
+
+ Ok(ConfigOption::Pfc)
+ }
+ ACFC => {
+ // constant length
+ if option[1] != 2 {
+ return Err(ParseError::InvalidOptionLength(option[1]));
+ }
+
+ Ok(ConfigOption::Acfc)
+ }
+ _ => Err(ParseError::InvalidOptionType(option[0])),
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 7a1cb4e..357dd8b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,6 +9,7 @@ pub use header::{Code, Header, HeaderBuilder};
pub mod packet;
pub use packet::{Packet, PacketBuilder};
+pub mod auth;
pub mod error;
pub mod eth;
pub mod lcp;