Improve error enums

This commit is contained in:
moznion
2020-12-12 02:50:39 +09:00
parent ced6b62e5e
commit 7910542618
9 changed files with 240 additions and 97 deletions
+1 -1
View File
@@ -556,7 +556,7 @@ fn generate_fixed_length_octets_attribute_code(
let code = format!( let code = format!(
"pub fn add_{method_identifier}(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {{ "pub fn add_{method_identifier}(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {{
if value.len() != {fixed_octets_length} {{ if value.len() != {fixed_octets_length} {{
return Err(AVPError::InvalidAttributeLengthError({fixed_octets_length})); return Err(AVPError::InvalidAttributeLengthError(\"{fixed_octets_length} bytes\".to_owned(), value.len()));
}} }}
packet.add(AVP::from_bytes({type_identifier}, value)); packet.add(AVP::from_bytes({type_identifier}, value));
Ok(()) Ok(())
+51 -23
View File
@@ -7,27 +7,39 @@ use tokio::time::timeout;
use radius::packet::Packet; use radius::packet::Packet;
use crate::client::ClientError::{
FailedConnection, FailedParsingUDPResponse, FailedRadiusPacketEncoding,
FailedReceivingResponse, FailedSendingPacket, FailedUdpSocketBinding,
};
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ClientError { pub enum ClientError {
#[error("failed to bind a UDP socket => `{0}`")] /// This error is occurred when UDP socket binding has been failed.
FailedUdpSocketBinding(String), #[error("failed to bind a UDP socket; {0}")]
#[error("failed to connect to `{0}` => `{1}`")] FailedUdpSocketBindingError(String),
FailedConnection(String, String),
#[error("failed to encode a RADIUS request => `{0}`")] /// This error is raised when it failed to establish the connection.
FailedRadiusPacketEncoding(String), #[error("failed to establish a UDP connection to {0}; {1}")]
#[error("failed to send a UDP datagram to `{0}` => `{1}`")] FailedEstablishingUdpConnectionError(String, String),
FailedSendingPacket(String, String),
#[error("failed to receive the UDP response from `{0}` => `{1}`")] /// This error is raised when encoding RADIUS packet has been failed.
FailedReceivingResponse(String, String), #[error("failed to encode a RADIUS request; {0}")]
#[error("failed to parse a UDP response into a RADIUS packet => `{0}`")] FailedRadiusPacketEncodingError(String),
FailedParsingUDPResponse(String),
/// This error is raised when it fails to send a RADIUS packet.
#[error("failed to send a UDP datagram to {0}; {1}")]
FailedSendingRadiusPacketError(String, String),
/// This error is raised when it fails to receive a RADIUS response.
#[error("failed to receive the UDP response from {0}; {1}")]
FailedReceivingResponseError(String, String),
/// This error is raised when it fails to decode a RADIUS response packet.
#[error("failed to decode a RADIUS response packet; {0}")]
FailedDecodingRadiusResponseError(String),
/// This error is raised when it exceeds the connection timeout duration.
/// Connection timeout means it fails to establish a connection in time.
#[error("connection timeout")] #[error("connection timeout")]
ConnectionTimeoutError(), ConnectionTimeoutError(),
/// This error is raised when it exceeds the socket timeout duration.
/// Socket timeout means it fails to receive a response from the request target in time.
#[error("socket timeout")] #[error("socket timeout")]
SocketTimeoutError(), SocketTimeoutError(),
} }
@@ -74,7 +86,7 @@ impl Client {
let conn = match UdpSocket::bind(local_addr).await { let conn = match UdpSocket::bind(local_addr).await {
Ok(conn) => conn, Ok(conn) => conn,
Err(e) => return Err(FailedUdpSocketBinding(e.to_string())), Err(e) => return Err(ClientError::FailedUdpSocketBindingError(e.to_string())),
}; };
match self.connection_timeout { match self.connection_timeout {
@@ -89,7 +101,12 @@ impl Client {
let request_data = match request_packet.encode() { let request_data = match request_packet.encode() {
Ok(encoded) => encoded, Ok(encoded) => encoded,
Err(e) => return Err(FailedRadiusPacketEncoding(format!("{:?}", e))), Err(e) => {
return Err(ClientError::FailedRadiusPacketEncodingError(format!(
"{:?}",
e
)))
}
}; };
let response = match self.socket_timeout { let response = match self.socket_timeout {
@@ -109,14 +126,20 @@ impl Client {
match Packet::decode(&response.to_vec(), request_packet.get_secret()) { match Packet::decode(&response.to_vec(), request_packet.get_secret()) {
Ok(response_packet) => Ok(response_packet), Ok(response_packet) => Ok(response_packet),
Err(e) => Err(FailedParsingUDPResponse(format!("{:?}", e))), Err(e) => Err(ClientError::FailedDecodingRadiusResponseError(format!(
"{:?}",
e
))),
} }
} }
async fn connect(&self, conn: &UdpSocket, remote_addr: &SocketAddr) -> Result<(), ClientError> { async fn connect(&self, conn: &UdpSocket, remote_addr: &SocketAddr) -> Result<(), ClientError> {
match conn.connect(remote_addr).await { match conn.connect(remote_addr).await {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(FailedConnection(remote_addr.to_string(), e.to_string())), Err(e) => Err(ClientError::FailedEstablishingUdpConnectionError(
remote_addr.to_string(),
e.to_string(),
)),
} }
} }
@@ -128,13 +151,18 @@ impl Client {
) -> Result<Vec<u8>, ClientError> { ) -> Result<Vec<u8>, ClientError> {
match conn.send(request_data).await { match conn.send(request_data).await {
Ok(_) => {} Ok(_) => {}
Err(e) => return Err(FailedSendingPacket(remote_addr.to_string(), e.to_string())), Err(e) => {
return Err(ClientError::FailedSendingRadiusPacketError(
remote_addr.to_string(),
e.to_string(),
))
}
}; };
let mut buf = vec![0; Self::MAX_DATAGRAM_SIZE]; let mut buf = vec![0; Self::MAX_DATAGRAM_SIZE];
match conn.recv(&mut buf).await { match conn.recv(&mut buf).await {
Ok(len) => Ok(buf[..len].to_vec()), Ok(len) => Ok(buf[..len].to_vec()),
Err(e) => Err(FailedReceivingResponse( Err(e) => Err(ClientError::FailedReceivingResponseError(
remote_addr.to_string(), remote_addr.to_string(),
e.to_string(), e.to_string(),
)), )),
+6 -2
View File
@@ -4,8 +4,12 @@ use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum SecretProviderError { pub enum SecretProviderError {
#[error("failed to fetch a secret value => `{0}`")] /// An error that represents a failure to fetch a secret value from the provider.
FailedFetching(String), #[error("failed to fetch a secret value: {0}")]
FailedFetchingError(String),
/// An error that represents a generic (i.e. unclassified) error that occurs on the secret value provider.
#[error("unexpected error: {0}")]
GenericError(String),
} }
/// SecretProvider is a provider for secret value. /// SecretProvider is a provider for secret value.
+109 -48
View File
@@ -9,23 +9,39 @@ use crate::tag::{Tag, UNUSED_TAG_VALUE};
#[derive(Error, PartialEq, Debug)] #[derive(Error, PartialEq, Debug)]
pub enum AVPError { pub enum AVPError {
#[error( /// This error is raised on the length of given plain text for user-password exceeds the maximum limit.
"the maximum length of the plain text is 128, but the given value is longer than that" #[error("the maximum length of the plain text for user-password is 128, but the given value has {0} bytes")]
)] UserPasswordPlainTextMaximumLengthExceededError(usize),
PlainTextMaximumLengthExceededError(),
#[error("secret hasn't be empty, but the given value is empty")] /// This error is raised when the given secret value for a password is empty.
SecretMissingError(), #[error("secret for password mustn't be empty, but the given value is empty")]
#[error("request authenticator has to have 16-bytes payload, but the given value doesn't")] PasswordSecretMissingError(),
/// This error is raised when the given request-authenticator for the password doesn't have 16 bytes length exactly.
#[error("request authenticator for password has to have 16-bytes payload, but the given value doesn't")]
InvalidRequestAuthenticatorLength(), InvalidRequestAuthenticatorLength(),
#[error("invalid attribute length: {0}")]
InvalidAttributeLengthError(usize), /// This error is raised when attribute length is conflicted with the expected.
// ^ TODO: more meaningful error message #[error("invalid attribute length: expected={0}, actual={1} bytes")]
#[error("unexpected decoding error: {0}")] InvalidAttributeLengthError(String, usize),
UnexpectedDecodingError(String),
/// This error is raised when the tagged-value doesn't have a tag byte.
#[error("tag value is missing")]
TagMissingError(),
/// This error represents AVP decoding error.
#[error("decoding error: {0}")]
DecodingError(String),
/// This error is raised when the MSB of salt is invalid.
#[error("invalid salt. the MSB has to be 1, but given value isn't: {0}")] #[error("invalid salt. the MSB has to be 1, but given value isn't: {0}")]
InvalidSaltMSBError(u8), InvalidSaltMSBError(u8),
/// This error is raised when a tag is invalid for the tagged-staring value.
#[error("invalid tag for string value. this must not be zero")] #[error("invalid tag for string value. this must not be zero")]
InvalidTagForStringValueError(), InvalidTagForStringValueError(),
/// This error is raised when a tag is invalid for the tagged-integer value.
#[error("invalid tag for integer value. this must be less than or equal 0x1f")] #[error("invalid tag for integer value. this must be less than or equal 0x1f")]
InvalidTagForIntegerValueError(), InvalidTagForIntegerValueError(),
} }
@@ -115,7 +131,10 @@ impl AVP {
pub fn from_ipv4_prefix(typ: AVPType, prefix: &[u8]) -> Result<Self, AVPError> { pub fn from_ipv4_prefix(typ: AVPType, prefix: &[u8]) -> Result<Self, AVPError> {
let prefix_len = prefix.len(); let prefix_len = prefix.len();
if prefix_len != 4 { if prefix_len != 4 {
return Err(AVPError::InvalidAttributeLengthError(prefix_len)); return Err(AVPError::InvalidAttributeLengthError(
"4 bytes".to_owned(),
prefix_len,
));
} }
Ok(AVP { Ok(AVP {
@@ -136,7 +155,10 @@ impl AVP {
pub fn from_ipv6_prefix(typ: AVPType, prefix: &[u8]) -> Result<Self, AVPError> { pub fn from_ipv6_prefix(typ: AVPType, prefix: &[u8]) -> Result<Self, AVPError> {
let prefix_len = prefix.len(); let prefix_len = prefix.len();
if prefix_len > 16 { if prefix_len > 16 {
return Err(AVPError::InvalidAttributeLengthError(prefix_len)); return Err(AVPError::InvalidAttributeLengthError(
"16 bytes".to_owned(),
prefix_len,
));
} }
Ok(AVP { Ok(AVP {
@@ -169,11 +191,13 @@ impl AVP {
// ref: https://tools.ietf.org/html/rfc2865#section-5.2 // ref: https://tools.ietf.org/html/rfc2865#section-5.2
if plain_text.len() > 128 { if plain_text.len() > 128 {
return Err(AVPError::PlainTextMaximumLengthExceededError()); return Err(AVPError::UserPasswordPlainTextMaximumLengthExceededError(
plain_text.len(),
));
} }
if secret.is_empty() { if secret.is_empty() {
return Err(AVPError::SecretMissingError()); return Err(AVPError::PasswordSecretMissingError());
} }
if request_authenticator.len() != 16 { if request_authenticator.len() != 16 {
@@ -251,6 +275,7 @@ impl AVP {
if request_authenticator.len() > 240 { if request_authenticator.len() > 240 {
return Err(AVPError::InvalidAttributeLengthError( return Err(AVPError::InvalidAttributeLengthError(
"240 bytes".to_owned(),
request_authenticator.len(), request_authenticator.len(),
)); ));
} }
@@ -259,7 +284,7 @@ impl AVP {
let salt: [u8; 2] = [rng.gen::<u8>() | 0x80, rng.gen::<u8>()]; let salt: [u8; 2] = [rng.gen::<u8>() | 0x80, rng.gen::<u8>()];
if secret.is_empty() { if secret.is_empty() {
return Err(AVPError::SecretMissingError()); return Err(AVPError::PasswordSecretMissingError());
} }
if request_authenticator.len() != 16 { if request_authenticator.len() != 16 {
@@ -313,13 +338,16 @@ impl AVP {
pub fn encode_u32(&self) -> Result<u32, AVPError> { pub fn encode_u32(&self) -> Result<u32, AVPError> {
const U32_SIZE: usize = std::mem::size_of::<u32>(); const U32_SIZE: usize = std::mem::size_of::<u32>();
if self.value.len() != U32_SIZE { if self.value.len() != U32_SIZE {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::InvalidAttributeLengthError(
format!("{} bytes", U32_SIZE),
self.value.len(),
));
} }
let (int_bytes, _) = self.value.split_at(U32_SIZE); let (int_bytes, _) = self.value.split_at(U32_SIZE);
match int_bytes.try_into() { match int_bytes.try_into() {
Ok(boxed_array) => Ok(u32::from_be_bytes(boxed_array)), Ok(boxed_array) => Ok(u32::from_be_bytes(boxed_array)),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
@@ -327,20 +355,23 @@ impl AVP {
pub fn encode_u16(&self) -> Result<u16, AVPError> { pub fn encode_u16(&self) -> Result<u16, AVPError> {
const U16_SIZE: usize = std::mem::size_of::<u16>(); const U16_SIZE: usize = std::mem::size_of::<u16>();
if self.value.len() != U16_SIZE { if self.value.len() != U16_SIZE {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::InvalidAttributeLengthError(
format!("{} bytes", U16_SIZE),
self.value.len(),
));
} }
let (int_bytes, _) = self.value.split_at(U16_SIZE); let (int_bytes, _) = self.value.split_at(U16_SIZE);
match int_bytes.try_into() { match int_bytes.try_into() {
Ok(boxed_array) => Ok(u16::from_be_bytes(boxed_array)), Ok(boxed_array) => Ok(u16::from_be_bytes(boxed_array)),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
/// (This method is for dictionary developers) encode an AVP into a tag and u32 value. /// (This method is for dictionary developers) encode an AVP into a tag and u32 value.
pub fn encode_tagged_u32(&self) -> Result<(u32, Tag), AVPError> { pub fn encode_tagged_u32(&self) -> Result<(u32, Tag), AVPError> {
if self.value.is_empty() { if self.value.is_empty() {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::TagMissingError());
} }
let tag = Tag { let tag = Tag {
@@ -356,12 +387,15 @@ impl AVP {
const U32_SIZE: usize = std::mem::size_of::<u32>(); const U32_SIZE: usize = std::mem::size_of::<u32>();
if self.value[1..].len() != U32_SIZE { if self.value[1..].len() != U32_SIZE {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::InvalidAttributeLengthError(
format!("{} bytes", U32_SIZE + 1),
self.value.len(),
));
} }
let (int_bytes, _) = self.value[1..].split_at(U32_SIZE); let (int_bytes, _) = self.value[1..].split_at(U32_SIZE);
match int_bytes.try_into() { match int_bytes.try_into() {
Ok(boxed_array) => Ok((u32::from_be_bytes(boxed_array), tag)), Ok(boxed_array) => Ok((u32::from_be_bytes(boxed_array), tag)),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
@@ -369,7 +403,7 @@ impl AVP {
pub fn encode_string(&self) -> Result<String, AVPError> { pub fn encode_string(&self) -> Result<String, AVPError> {
match String::from_utf8(self.value.to_vec()) { match String::from_utf8(self.value.to_vec()) {
Ok(str) => Ok(str), Ok(str) => Ok(str),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
@@ -377,7 +411,7 @@ impl AVP {
pub fn encode_tagged_string(&self) -> Result<(String, Option<Tag>), AVPError> { pub fn encode_tagged_string(&self) -> Result<(String, Option<Tag>), AVPError> {
let string_vec = self.value.to_vec(); let string_vec = self.value.to_vec();
if string_vec.is_empty() { if string_vec.is_empty() {
return Err(AVPError::InvalidAttributeLengthError(string_vec.len())); return Err(AVPError::TagMissingError());
} }
let tag = Tag { let tag = Tag {
@@ -392,7 +426,7 @@ impl AVP {
if tag.is_valid_value() { if tag.is_valid_value() {
return match String::from_utf8(string_vec[1..].to_vec()) { return match String::from_utf8(string_vec[1..].to_vec()) {
Ok(str) => Ok((str, Some(tag))), Ok(str) => Ok((str, Some(tag))),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
}; };
} }
@@ -405,7 +439,7 @@ impl AVP {
// interpreted as the first byte of the following String field. // interpreted as the first byte of the following String field.
match String::from_utf8(self.value.to_vec()) { match String::from_utf8(self.value.to_vec()) {
Ok(str) => Ok((str, None)), Ok(str) => Ok((str, None)),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
@@ -418,13 +452,16 @@ impl AVP {
pub fn encode_ipv4(&self) -> Result<Ipv4Addr, AVPError> { pub fn encode_ipv4(&self) -> Result<Ipv4Addr, AVPError> {
const IPV4_SIZE: usize = std::mem::size_of::<Ipv4Addr>(); const IPV4_SIZE: usize = std::mem::size_of::<Ipv4Addr>();
if self.value.len() != IPV4_SIZE { if self.value.len() != IPV4_SIZE {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::InvalidAttributeLengthError(
format!("{} bytes", IPV4_SIZE),
self.value.len(),
));
} }
let (int_bytes, _) = self.value.split_at(IPV4_SIZE); let (int_bytes, _) = self.value.split_at(IPV4_SIZE);
match int_bytes.try_into() { match int_bytes.try_into() {
Ok::<[u8; IPV4_SIZE], _>(boxed_array) => Ok(Ipv4Addr::from(boxed_array)), Ok::<[u8; IPV4_SIZE], _>(boxed_array) => Ok(Ipv4Addr::from(boxed_array)),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
@@ -432,7 +469,10 @@ impl AVP {
pub fn encode_ipv4_prefix(&self) -> Result<Vec<u8>, AVPError> { pub fn encode_ipv4_prefix(&self) -> Result<Vec<u8>, AVPError> {
match self.value.len() == 6 { match self.value.len() == 6 {
true => Ok(self.value[2..].to_owned()), true => Ok(self.value[2..].to_owned()),
false => Err(AVPError::InvalidAttributeLengthError(self.value.len())), false => Err(AVPError::InvalidAttributeLengthError(
"6 bytes".to_owned(),
self.value.len(),
)),
} }
} }
@@ -440,13 +480,16 @@ impl AVP {
pub fn encode_ipv6(&self) -> Result<Ipv6Addr, AVPError> { pub fn encode_ipv6(&self) -> Result<Ipv6Addr, AVPError> {
const IPV6_SIZE: usize = std::mem::size_of::<Ipv6Addr>(); const IPV6_SIZE: usize = std::mem::size_of::<Ipv6Addr>();
if self.value.len() != IPV6_SIZE { if self.value.len() != IPV6_SIZE {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::InvalidAttributeLengthError(
format!("{} bytes", IPV6_SIZE),
self.value.len(),
));
} }
let (int_bytes, _) = self.value.split_at(IPV6_SIZE); let (int_bytes, _) = self.value.split_at(IPV6_SIZE);
match int_bytes.try_into() { match int_bytes.try_into() {
Ok::<[u8; IPV6_SIZE], _>(boxed_array) => Ok(Ipv6Addr::from(boxed_array)), Ok::<[u8; IPV6_SIZE], _>(boxed_array) => Ok(Ipv6Addr::from(boxed_array)),
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
@@ -454,7 +497,10 @@ impl AVP {
pub fn encode_ipv6_prefix(&self) -> Result<Vec<u8>, AVPError> { pub fn encode_ipv6_prefix(&self) -> Result<Vec<u8>, AVPError> {
match self.value.len() >= 2 { match self.value.len() >= 2 {
true => Ok(self.value[2..].to_owned()), true => Ok(self.value[2..].to_owned()),
false => Err(AVPError::InvalidAttributeLengthError(self.value.len())), false => Err(AVPError::InvalidAttributeLengthError(
"2+ bytes".to_owned(),
self.value.len(),
)),
} }
} }
@@ -465,11 +511,14 @@ impl AVP {
request_authenticator: &[u8], request_authenticator: &[u8],
) -> Result<Vec<u8>, AVPError> { ) -> Result<Vec<u8>, AVPError> {
if self.value.len() < 16 || self.value.len() > 128 { if self.value.len() < 16 || self.value.len() > 128 {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::InvalidAttributeLengthError(
"16 >= bytes && 128 <= bytes".to_owned(),
self.value.len(),
));
} }
if secret.is_empty() { if secret.is_empty() {
return Err(AVPError::SecretMissingError()); return Err(AVPError::PasswordSecretMissingError());
} }
if request_authenticator.len() != 16 { if request_authenticator.len() != 16 {
@@ -506,7 +555,10 @@ impl AVP {
pub fn encode_date(&self) -> Result<DateTime<Utc>, AVPError> { pub fn encode_date(&self) -> Result<DateTime<Utc>, AVPError> {
const U32_SIZE: usize = std::mem::size_of::<u32>(); const U32_SIZE: usize = std::mem::size_of::<u32>();
if self.value.len() != U32_SIZE { if self.value.len() != U32_SIZE {
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); return Err(AVPError::InvalidAttributeLengthError(
format!("{}", U32_SIZE),
self.value.len(),
));
} }
let (int_bytes, _) = self.value.split_at(U32_SIZE); let (int_bytes, _) = self.value.split_at(U32_SIZE);
@@ -515,7 +567,7 @@ impl AVP {
let timestamp = u32::from_be_bytes(boxed_array); let timestamp = u32::from_be_bytes(boxed_array);
Ok(Utc.timestamp(timestamp as i64, 0)) Ok(Utc.timestamp(timestamp as i64, 0))
} }
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), Err(e) => Err(AVPError::DecodingError(e.to_string())),
} }
} }
@@ -525,11 +577,11 @@ impl AVP {
secret: &[u8], secret: &[u8],
request_authenticator: &[u8], request_authenticator: &[u8],
) -> Result<(Vec<u8>, Tag), AVPError> { ) -> Result<(Vec<u8>, Tag), AVPError> {
if self.value.len() - 3 < 16 if self.value.len() < 19 || self.value.len() > 243 || (self.value.len() - 3) % 16 != 0 {
|| self.value.len() - 3 > 240 return Err(AVPError::InvalidAttributeLengthError(
|| (self.value.len() - 3) % 16 != 0 "19 <= bytes && bytes <= 242 && (bytes - 3) % 16 == 0".to_owned(),
{ self.value.len(),
return Err(AVPError::InvalidAttributeLengthError(self.value.len())); ));
} }
if self.value[1] & 0x80 != 0x80 { if self.value[1] & 0x80 != 0x80 {
@@ -538,7 +590,7 @@ impl AVP {
} }
if secret.is_empty() { if secret.is_empty() {
return Err(AVPError::SecretMissingError()); return Err(AVPError::PasswordSecretMissingError());
} }
if request_authenticator.len() != 16 { if request_authenticator.len() != 16 {
@@ -804,10 +856,16 @@ mod tests {
#[test] #[test]
fn should_convert_ipv4_prefix_fail_because_of_invalid_prefix_length() { fn should_convert_ipv4_prefix_fail_because_of_invalid_prefix_length() {
let avp = AVP::from_ipv4_prefix(1, &[0x01, 0x02, 0x03]); let avp = AVP::from_ipv4_prefix(1, &[0x01, 0x02, 0x03]);
assert_eq!(avp.unwrap_err(), AVPError::InvalidAttributeLengthError(3)); assert_eq!(
avp.unwrap_err(),
AVPError::InvalidAttributeLengthError("4 bytes".to_owned(), 3)
);
let avp = AVP::from_ipv4_prefix(1, &[0x01, 0x02, 0x03, 0x04, 0x05]); let avp = AVP::from_ipv4_prefix(1, &[0x01, 0x02, 0x03, 0x04, 0x05]);
assert_eq!(avp.unwrap_err(), AVPError::InvalidAttributeLengthError(5)); assert_eq!(
avp.unwrap_err(),
AVPError::InvalidAttributeLengthError("4 bytes".to_owned(), 5)
);
assert_eq!( assert_eq!(
AVP { AVP {
@@ -816,7 +874,7 @@ mod tests {
} }
.encode_ipv4_prefix() .encode_ipv4_prefix()
.unwrap_err(), .unwrap_err(),
AVPError::InvalidAttributeLengthError(0) AVPError::InvalidAttributeLengthError("6 bytes".to_owned(), 0)
); );
} }
@@ -849,6 +907,9 @@ mod tests {
0x0e, 0x0f, 0x10, 0x0e, 0x0f, 0x10,
], ],
); );
assert_eq!(avp.unwrap_err(), AVPError::InvalidAttributeLengthError(17)); assert_eq!(
avp.unwrap_err(),
AVPError::InvalidAttributeLengthError("16 bytes".to_owned(), 17)
);
} }
} }
+45 -16
View File
@@ -12,17 +12,28 @@ const RADIUS_PACKET_HEADER_LENGTH: usize = 20; // i.e. minimum packet length
#[derive(Error, Debug, PartialEq)] #[derive(Error, Debug, PartialEq)]
pub enum PacketError { pub enum PacketError {
#[error("radius packet doesn't have enough length of bytes; it has to be at least {0} bytes")] /// An error indicates the entire length of the given packet has insufficient length.
InsufficientPacketLengthError(usize), #[error("RADIUS packet doesn't have enough length of bytes; it has to be at least {0} bytes, but actual length was {1}")]
#[error("invalid radius packet length: {0}")] InsufficientPacketPayloadLengthError(usize, usize),
InvalidPacketLengthError(usize),
#[error("unexpected decoding error: {0}")] /// An error indicates the length that is instructed by a header is insufficient.
UnexpectedDecodingError(String), #[error("RADIUS packet header indicates the length as {0} bytes, but this is insufficient; this must have {1} bytes at least")]
InsufficientHeaderDefinedPacketLengthError(usize, usize),
/// An error indicates the length that is instructed by a header exceeds the maximum length of the RADIUS packet.
#[error("RADIUS packet header indicates the length as {0} bytes, but this exceeds the maximum length {1} bytes")]
HeaderDefinedPacketLengthExceedsMaximumLimitError(usize, usize),
/// An error that is raised when an error has been occurred on decoding bytes for a packet.
#[error("failed to decode the packet: {0}")] #[error("failed to decode the packet: {0}")]
DecodingError(String), DecodingError(String),
/// An error that is raised when an error has been occurred on encoding a packet into bytes.
#[error("failed to encode the packet: {0}")] #[error("failed to encode the packet: {0}")]
EncodingError(String), EncodingError(String),
#[error("Unknown radius packet code: {0}")]
/// An error that is raised when it received unknown packet type code of RADIUS.
#[error("Unknown RADIUS packet type code: {0}")]
UnknownCodeError(String), UnknownCodeError(String),
} }
@@ -69,17 +80,35 @@ impl Packet {
/// This decodes bytes into a Packet. /// This decodes bytes into a Packet.
pub fn decode(bs: &[u8], secret: &[u8]) -> Result<Self, PacketError> { pub fn decode(bs: &[u8], secret: &[u8]) -> Result<Self, PacketError> {
if bs.len() < RADIUS_PACKET_HEADER_LENGTH { if bs.len() < RADIUS_PACKET_HEADER_LENGTH {
return Err(PacketError::InsufficientPacketLengthError( return Err(PacketError::InsufficientPacketPayloadLengthError(
RADIUS_PACKET_HEADER_LENGTH, RADIUS_PACKET_HEADER_LENGTH,
bs.len(),
)); ));
} }
let len = match bs[2..4].try_into() { let len = match bs[2..4].try_into() {
Ok(v) => u16::from_be_bytes(v), Ok(v) => u16::from_be_bytes(v),
Err(e) => return Err(PacketError::UnexpectedDecodingError(e.to_string())), Err(e) => return Err(PacketError::DecodingError(e.to_string())),
} as usize; } as usize;
if len < RADIUS_PACKET_HEADER_LENGTH || len > MAX_PACKET_LENGTH || bs.len() < len { if len < RADIUS_PACKET_HEADER_LENGTH {
return Err(PacketError::InvalidPacketLengthError(len)); return Err(PacketError::InsufficientHeaderDefinedPacketLengthError(
len,
RADIUS_PACKET_HEADER_LENGTH,
));
}
if len > MAX_PACKET_LENGTH {
return Err(
PacketError::HeaderDefinedPacketLengthExceedsMaximumLimitError(
len,
MAX_PACKET_LENGTH,
),
);
}
if bs.len() < len {
return Err(PacketError::InsufficientPacketPayloadLengthError(
len,
bs.len(),
));
} }
let attributes = match Attributes::decode(&bs[RADIUS_PACKET_HEADER_LENGTH..len].to_vec()) { let attributes = match Attributes::decode(&bs[RADIUS_PACKET_HEADER_LENGTH..len].to_vec()) {
@@ -266,7 +295,7 @@ mod tests {
use crate::avp::AVP; use crate::avp::AVP;
use crate::code::Code; use crate::code::Code;
use crate::packet::{Packet, PacketError}; use crate::packet::{Packet, PacketError, MAX_PACKET_LENGTH, RADIUS_PACKET_HEADER_LENGTH};
use crate::rfc2865; use crate::rfc2865;
#[test] #[test]
@@ -468,19 +497,19 @@ mod tests {
let test_cases = &[ let test_cases = &[
TestCase { TestCase {
plain_text: "\x01", plain_text: "\x01",
expected_error: PacketError::InsufficientPacketLengthError(20), expected_error: PacketError::InsufficientPacketPayloadLengthError(RADIUS_PACKET_HEADER_LENGTH, 1),
}, },
TestCase { TestCase {
plain_text: "\x01\x7f\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01", plain_text: "\x01\x7f\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01",
expected_error: PacketError::InvalidPacketLengthError(0), expected_error: PacketError::InsufficientHeaderDefinedPacketLengthError(0, RADIUS_PACKET_HEADER_LENGTH),
}, },
TestCase { TestCase {
plain_text: "\x01\x7f\x7f\x7f\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01", plain_text: "\x01\x7f\x7f\x7f\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01",
expected_error: PacketError::InvalidPacketLengthError(32639), expected_error: PacketError::HeaderDefinedPacketLengthExceedsMaximumLimitError(32639, MAX_PACKET_LENGTH),
}, },
TestCase { TestCase {
plain_text: "\x00\x7f\x00\x16\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00", plain_text: "\x00\x7f\x00\x16\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00",
expected_error: PacketError::InvalidPacketLengthError(22), expected_error: PacketError::InsufficientPacketPayloadLengthError(22, 21),
}, },
TestCase { TestCase {
plain_text: "\x01\x01\x00\x16\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00", plain_text: "\x01\x01\x00\x16\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00",
+12 -3
View File
@@ -69,7 +69,10 @@ pub fn delete_arap_password(packet: &mut Packet) {
} }
pub fn add_arap_password(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { pub fn add_arap_password(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {
if value.len() != 16 { if value.len() != 16 {
return Err(AVPError::InvalidAttributeLengthError(16)); return Err(AVPError::InvalidAttributeLengthError(
"16 bytes".to_owned(),
value.len(),
));
} }
packet.add(AVP::from_bytes(ARAP_PASSWORD_TYPE, value)); packet.add(AVP::from_bytes(ARAP_PASSWORD_TYPE, value));
Ok(()) Ok(())
@@ -91,7 +94,10 @@ pub fn delete_arap_features(packet: &mut Packet) {
} }
pub fn add_arap_features(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { pub fn add_arap_features(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {
if value.len() != 14 { if value.len() != 14 {
return Err(AVPError::InvalidAttributeLengthError(14)); return Err(AVPError::InvalidAttributeLengthError(
"14 bytes".to_owned(),
value.len(),
));
} }
packet.add(AVP::from_bytes(ARAP_FEATURES_TYPE, value)); packet.add(AVP::from_bytes(ARAP_FEATURES_TYPE, value));
Ok(()) Ok(())
@@ -290,7 +296,10 @@ pub fn delete_arap_challenge_response(packet: &mut Packet) {
} }
pub fn add_arap_challenge_response(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { pub fn add_arap_challenge_response(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {
if value.len() != 8 { if value.len() != 8 {
return Err(AVPError::InvalidAttributeLengthError(8)); return Err(AVPError::InvalidAttributeLengthError(
"8 bytes".to_owned(),
value.len(),
));
} }
packet.add(AVP::from_bytes(ARAP_CHALLENGE_RESPONSE_TYPE, value)); packet.add(AVP::from_bytes(ARAP_CHALLENGE_RESPONSE_TYPE, value));
Ok(()) Ok(())
+4 -1
View File
@@ -31,7 +31,10 @@ pub fn delete_framed_interface_id(packet: &mut Packet) {
} }
pub fn add_framed_interface_id(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { pub fn add_framed_interface_id(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {
if value.len() != 8 { if value.len() != 8 {
return Err(AVPError::InvalidAttributeLengthError(8)); return Err(AVPError::InvalidAttributeLengthError(
"8 bytes".to_owned(),
value.len(),
));
} }
packet.add(AVP::from_bytes(FRAMED_INTERFACE_ID_TYPE, value)); packet.add(AVP::from_bytes(FRAMED_INTERFACE_ID_TYPE, value));
Ok(()) Ok(())
+8 -2
View File
@@ -181,7 +181,10 @@ pub fn delete_pmip6_home_interface_id(packet: &mut Packet) {
} }
pub fn add_pmip6_home_interface_id(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { pub fn add_pmip6_home_interface_id(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {
if value.len() != 8 { if value.len() != 8 {
return Err(AVPError::InvalidAttributeLengthError(8)); return Err(AVPError::InvalidAttributeLengthError(
"8 bytes".to_owned(),
value.len(),
));
} }
packet.add(AVP::from_bytes(PMIP6_HOME_INTERFACE_ID_TYPE, value)); packet.add(AVP::from_bytes(PMIP6_HOME_INTERFACE_ID_TYPE, value));
Ok(()) Ok(())
@@ -205,7 +208,10 @@ pub fn delete_pmip6_visited_interface_id(packet: &mut Packet) {
} }
pub fn add_pmip6_visited_interface_id(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { pub fn add_pmip6_visited_interface_id(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {
if value.len() != 8 { if value.len() != 8 {
return Err(AVPError::InvalidAttributeLengthError(8)); return Err(AVPError::InvalidAttributeLengthError(
"8 bytes".to_owned(),
value.len(),
));
} }
packet.add(AVP::from_bytes(PMIP6_VISITED_INTERFACE_ID_TYPE, value)); packet.add(AVP::from_bytes(PMIP6_VISITED_INTERFACE_ID_TYPE, value));
Ok(()) Ok(())
+4 -1
View File
@@ -9,7 +9,10 @@ pub fn delete_originating_line_info(packet: &mut Packet) {
} }
pub fn add_originating_line_info(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { pub fn add_originating_line_info(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {
if value.len() != 2 { if value.len() != 2 {
return Err(AVPError::InvalidAttributeLengthError(2)); return Err(AVPError::InvalidAttributeLengthError(
"2 bytes".to_owned(),
value.len(),
));
} }
packet.add(AVP::from_bytes(ORIGINATING_LINE_INFO_TYPE, value)); packet.add(AVP::from_bytes(ORIGINATING_LINE_INFO_TYPE, value));
Ok(()) Ok(())