mirror of
https://github.com/cubixle/radius-rs.git
synced 2026-04-30 13:58:41 +01:00
Support RFC2868
This commit is contained in:
@@ -13,6 +13,7 @@ This supports the following RFC dictionaries at the moment:
|
|||||||
- [RFC2865](https://tools.ietf.org/html/rfc2865)
|
- [RFC2865](https://tools.ietf.org/html/rfc2865)
|
||||||
- [RFC2866](https://tools.ietf.org/html/rfc2866)
|
- [RFC2866](https://tools.ietf.org/html/rfc2866)
|
||||||
- [RFC2867](https://tools.ietf.org/html/rfc2867)
|
- [RFC2867](https://tools.ietf.org/html/rfc2867)
|
||||||
|
- [RFC2868](https://tools.ietf.org/html/rfc2868)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -26,7 +27,6 @@ Simple example implementations are here:
|
|||||||
- timeout feature on the client
|
- timeout feature on the client
|
||||||
- retransmission feature on the client
|
- retransmission feature on the client
|
||||||
- Support the following RFC dictionaries:
|
- Support the following RFC dictionaries:
|
||||||
- rfc2868
|
|
||||||
- rfc2869
|
- rfc2869
|
||||||
- rfc3162
|
- rfc3162
|
||||||
- rfc3576
|
- rfc3576
|
||||||
|
|||||||
+127
-4
@@ -117,6 +117,7 @@ use std::net::Ipv4Addr;
|
|||||||
|
|
||||||
use crate::avp::{AVP, AVPType, AVPError};
|
use crate::avp::{AVP, AVPType, AVPError};
|
||||||
use crate::packet::Packet;
|
use crate::packet::Packet;
|
||||||
|
use crate::tag::Tag;
|
||||||
|
|
||||||
";
|
";
|
||||||
|
|
||||||
@@ -182,7 +183,7 @@ fn generate_attribute_code(
|
|||||||
generate_common_attribute_code(w, &attr_name, &type_identifier, type_value);
|
generate_common_attribute_code(w, &attr_name, &type_identifier, type_value);
|
||||||
match attr.value_type {
|
match attr.value_type {
|
||||||
RadiusAttributeValueType::String => match attr.has_tag {
|
RadiusAttributeValueType::String => match attr.has_tag {
|
||||||
true => unimplemented!(),
|
true => generate_tagged_string_attribute_code(w, &method_identifier, &type_identifier),
|
||||||
false => generate_string_attribute_code(w, &method_identifier, &type_identifier),
|
false => generate_string_attribute_code(w, &method_identifier, &type_identifier),
|
||||||
},
|
},
|
||||||
RadiusAttributeValueType::UserPassword => match attr.has_tag {
|
RadiusAttributeValueType::UserPassword => match attr.has_tag {
|
||||||
@@ -190,7 +191,9 @@ fn generate_attribute_code(
|
|||||||
false => generate_user_password_attribute_code(w, &method_identifier, &type_identifier),
|
false => generate_user_password_attribute_code(w, &method_identifier, &type_identifier),
|
||||||
},
|
},
|
||||||
RadiusAttributeValueType::TunnelPassword => match attr.has_tag {
|
RadiusAttributeValueType::TunnelPassword => match attr.has_tag {
|
||||||
true => unimplemented!(),
|
true => {
|
||||||
|
generate_tunnel_password_attribute_code(w, &method_identifier, &type_identifier)
|
||||||
|
}
|
||||||
false => unimplemented!(),
|
false => unimplemented!(),
|
||||||
},
|
},
|
||||||
RadiusAttributeValueType::Octets => match attr.has_tag {
|
RadiusAttributeValueType::Octets => match attr.has_tag {
|
||||||
@@ -204,7 +207,12 @@ fn generate_attribute_code(
|
|||||||
RadiusAttributeValueType::Integer => {
|
RadiusAttributeValueType::Integer => {
|
||||||
match value_defined_attributes_set.contains(&attr_name) {
|
match value_defined_attributes_set.contains(&attr_name) {
|
||||||
true => match attr.has_tag {
|
true => match attr.has_tag {
|
||||||
true => unimplemented!(),
|
true => generate_value_tagged_defined_integer_attribute_code(
|
||||||
|
w,
|
||||||
|
&method_identifier,
|
||||||
|
&type_identifier,
|
||||||
|
&attr_name.to_pascal_case(),
|
||||||
|
),
|
||||||
false => generate_value_defined_integer_attribute_code(
|
false => generate_value_defined_integer_attribute_code(
|
||||||
w,
|
w,
|
||||||
&method_identifier,
|
&method_identifier,
|
||||||
@@ -213,7 +221,11 @@ fn generate_attribute_code(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
false => match attr.has_tag {
|
false => match attr.has_tag {
|
||||||
true => unimplemented!(),
|
true => generate_tagged_integer_attribute_code(
|
||||||
|
w,
|
||||||
|
&method_identifier,
|
||||||
|
&type_identifier,
|
||||||
|
),
|
||||||
false => {
|
false => {
|
||||||
generate_integer_attribute_code(w, &method_identifier, &type_identifier)
|
generate_integer_attribute_code(w, &method_identifier, &type_identifier)
|
||||||
}
|
}
|
||||||
@@ -270,6 +282,32 @@ pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<String>, AV
|
|||||||
w.write_all(code.as_bytes()).unwrap();
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_tagged_string_attribute_code(
|
||||||
|
w: &mut BufWriter<File>,
|
||||||
|
method_identifier: &str,
|
||||||
|
type_identifier: &str,
|
||||||
|
) {
|
||||||
|
let code = format!(
|
||||||
|
"pub fn add_{method_identifier}(packet: &mut Packet, tag: Option<&Tag>, value: &str) {{
|
||||||
|
packet.add(AVP::encode_tagged_string({type_identifier}, tag, value));
|
||||||
|
}}
|
||||||
|
pub fn lookup_{method_identifier}(packet: &Packet) -> Option<Result<(String, Option<Tag>), AVPError>> {{
|
||||||
|
packet.lookup({type_identifier}).map(|v| v.decode_tagged_string())
|
||||||
|
}}
|
||||||
|
pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<(String, Option<Tag>)>, AVPError> {{
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all({type_identifier}) {{
|
||||||
|
vec.push(avp.decode_tagged_string()?)
|
||||||
|
}}
|
||||||
|
Ok(vec)
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
method_identifier = method_identifier,
|
||||||
|
type_identifier = type_identifier,
|
||||||
|
);
|
||||||
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_user_password_attribute_code(
|
fn generate_user_password_attribute_code(
|
||||||
w: &mut BufWriter<File>,
|
w: &mut BufWriter<File>,
|
||||||
method_identifier: &str,
|
method_identifier: &str,
|
||||||
@@ -297,6 +335,33 @@ pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<Vec<u8>>, A
|
|||||||
w.write_all(code.as_bytes()).unwrap();
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_tunnel_password_attribute_code(
|
||||||
|
w: &mut BufWriter<File>,
|
||||||
|
method_identifier: &str,
|
||||||
|
type_identifier: &str,
|
||||||
|
) {
|
||||||
|
let code = format!(
|
||||||
|
"pub fn add_{method_identifier}(packet: &mut Packet, tag: Option<&Tag>, value: &[u8]) -> Result<(), AVPError> {{
|
||||||
|
packet.add(AVP::encode_tunnel_password({type_identifier}, tag, value, packet.get_secret(), packet.get_authenticator())?);
|
||||||
|
Ok(())
|
||||||
|
}}
|
||||||
|
pub fn lookup_{method_identifier}(packet: &Packet) -> Option<Result<(Vec<u8>, Tag), AVPError>> {{
|
||||||
|
packet.lookup({type_identifier}).map(|v| v.decode_tunnel_password(packet.get_secret(), packet.get_authenticator()))
|
||||||
|
}}
|
||||||
|
pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<(Vec<u8>, Tag)>, AVPError> {{
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all({type_identifier}) {{
|
||||||
|
vec.push(avp.decode_tunnel_password(packet.get_secret(), packet.get_authenticator())?)
|
||||||
|
}}
|
||||||
|
Ok(vec)
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
method_identifier = method_identifier,
|
||||||
|
type_identifier = type_identifier,
|
||||||
|
);
|
||||||
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_octets_attribute_code(
|
fn generate_octets_attribute_code(
|
||||||
w: &mut BufWriter<File>,
|
w: &mut BufWriter<File>,
|
||||||
method_identifier: &str,
|
method_identifier: &str,
|
||||||
@@ -375,6 +440,32 @@ pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<u32>, AVPEr
|
|||||||
w.write_all(code.as_bytes()).unwrap();
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_tagged_integer_attribute_code(
|
||||||
|
w: &mut BufWriter<File>,
|
||||||
|
method_identifier: &str,
|
||||||
|
type_identifier: &str,
|
||||||
|
) {
|
||||||
|
let code = format!(
|
||||||
|
"pub fn add_{method_identifier}(packet: &mut Packet, tag: Option<&Tag>, value: u32) {{
|
||||||
|
packet.add(AVP::encode_tagged_u32({type_identifier}, tag, value));
|
||||||
|
}}
|
||||||
|
pub fn lookup_{method_identifier}(packet: &Packet) -> Option<Result<(u32, Tag), AVPError>> {{
|
||||||
|
packet.lookup({type_identifier}).map(|v| v.decode_tagged_u32())
|
||||||
|
}}
|
||||||
|
pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<(u32, Tag)>, AVPError> {{
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all({type_identifier}) {{
|
||||||
|
vec.push(avp.decode_tagged_u32()?)
|
||||||
|
}}
|
||||||
|
Ok(vec)
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
method_identifier = method_identifier,
|
||||||
|
type_identifier = type_identifier,
|
||||||
|
);
|
||||||
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_value_defined_integer_attribute_code(
|
fn generate_value_defined_integer_attribute_code(
|
||||||
w: &mut BufWriter<File>,
|
w: &mut BufWriter<File>,
|
||||||
method_identifier: &str,
|
method_identifier: &str,
|
||||||
@@ -403,6 +494,38 @@ pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<{value_type
|
|||||||
w.write_all(code.as_bytes()).unwrap();
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_value_tagged_defined_integer_attribute_code(
|
||||||
|
w: &mut BufWriter<File>,
|
||||||
|
method_identifier: &str,
|
||||||
|
type_identifier: &str,
|
||||||
|
value_type: &str,
|
||||||
|
) {
|
||||||
|
let code = format!(
|
||||||
|
"pub fn add_{method_identifier}(packet: &mut Packet, tag: Option<&Tag>, value: {value_type}) {{
|
||||||
|
packet.add(AVP::encode_tagged_u32({type_identifier}, tag, value as u32));
|
||||||
|
}}
|
||||||
|
pub fn lookup_{method_identifier}(packet: &Packet) -> Option<Result<({value_type}, Tag), AVPError>> {{
|
||||||
|
packet.lookup({type_identifier}).map(|v| {{
|
||||||
|
let (v, t) = v.decode_tagged_u32()?;
|
||||||
|
Ok((v as {value_type}, t))
|
||||||
|
}})
|
||||||
|
}}
|
||||||
|
pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result<Vec<({value_type}, Tag)>, AVPError> {{
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all({type_identifier}) {{
|
||||||
|
let (v, t) = avp.decode_tagged_u32()?;
|
||||||
|
vec.push((v as {value_type}, t))
|
||||||
|
}}
|
||||||
|
Ok(vec)
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
method_identifier = method_identifier,
|
||||||
|
type_identifier = type_identifier,
|
||||||
|
value_type = value_type,
|
||||||
|
);
|
||||||
|
w.write_all(code.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_vsa_attribute_code() {
|
fn generate_vsa_attribute_code() {
|
||||||
// NOP
|
// NOP
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# -*- text -*-
|
||||||
|
# Copyright (C) 2020 The FreeRADIUS Server project and contributors
|
||||||
|
# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0
|
||||||
|
# Version $Id$
|
||||||
|
#
|
||||||
|
# Attributes and values defined in RFC 2868.
|
||||||
|
# http://www.ietf.org/rfc/rfc2868.txt
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
ATTRIBUTE Tunnel-Type 64 integer has_tag
|
||||||
|
ATTRIBUTE Tunnel-Medium-Type 65 integer has_tag
|
||||||
|
ATTRIBUTE Tunnel-Client-Endpoint 66 string has_tag
|
||||||
|
ATTRIBUTE Tunnel-Server-Endpoint 67 string has_tag
|
||||||
|
|
||||||
|
ATTRIBUTE Tunnel-Password 69 string has_tag,encrypt=2
|
||||||
|
|
||||||
|
ATTRIBUTE Tunnel-Private-Group-Id 81 string has_tag
|
||||||
|
ATTRIBUTE Tunnel-Assignment-Id 82 string has_tag
|
||||||
|
ATTRIBUTE Tunnel-Preference 83 integer has_tag
|
||||||
|
|
||||||
|
ATTRIBUTE Tunnel-Client-Auth-Id 90 string has_tag
|
||||||
|
ATTRIBUTE Tunnel-Server-Auth-Id 91 string has_tag
|
||||||
|
|
||||||
|
# Tunnel Type
|
||||||
|
|
||||||
|
VALUE Tunnel-Type PPTP 1
|
||||||
|
VALUE Tunnel-Type L2F 2
|
||||||
|
VALUE Tunnel-Type L2TP 3
|
||||||
|
VALUE Tunnel-Type ATMP 4
|
||||||
|
VALUE Tunnel-Type VTP 5
|
||||||
|
VALUE Tunnel-Type AH 6
|
||||||
|
VALUE Tunnel-Type IP 7
|
||||||
|
VALUE Tunnel-Type MIN-IP 8
|
||||||
|
VALUE Tunnel-Type ESP 9
|
||||||
|
VALUE Tunnel-Type GRE 10
|
||||||
|
VALUE Tunnel-Type DVS 11
|
||||||
|
VALUE Tunnel-Type IP-in-IP 12
|
||||||
|
|
||||||
|
# Tunnel Medium Type
|
||||||
|
|
||||||
|
VALUE Tunnel-Medium-Type IP 1
|
||||||
|
VALUE Tunnel-Medium-Type IPv4 1
|
||||||
|
VALUE Tunnel-Medium-Type IPv6 2
|
||||||
|
VALUE Tunnel-Medium-Type NSAP 3
|
||||||
|
VALUE Tunnel-Medium-Type HDLC 4
|
||||||
|
VALUE Tunnel-Medium-Type BBN-1822 5
|
||||||
|
VALUE Tunnel-Medium-Type IEEE-802 6
|
||||||
|
VALUE Tunnel-Medium-Type E.163 7
|
||||||
|
VALUE Tunnel-Medium-Type E.164 8
|
||||||
|
VALUE Tunnel-Medium-Type F.69 9
|
||||||
|
VALUE Tunnel-Medium-Type X.121 10
|
||||||
|
VALUE Tunnel-Medium-Type IPX 11
|
||||||
|
VALUE Tunnel-Medium-Type Appletalk 12
|
||||||
|
VALUE Tunnel-Medium-Type DecNet-IV 13
|
||||||
|
VALUE Tunnel-Medium-Type Banyan-Vines 14
|
||||||
|
VALUE Tunnel-Medium-Type E.164-NSAP 15
|
||||||
+106
-15
@@ -1,10 +1,12 @@
|
|||||||
|
use rand::Rng;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
use crate::tag::Tag;
|
|
||||||
use chrono::{DateTime, TimeZone, Utc};
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::tag::{Tag, UNUSED_TAG_VALUE};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AVPError {
|
pub enum AVPError {
|
||||||
#[error(
|
#[error(
|
||||||
@@ -22,6 +24,10 @@ pub enum AVPError {
|
|||||||
UnexpectedDecodingError(String),
|
UnexpectedDecodingError(String),
|
||||||
#[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),
|
||||||
|
#[error("invalid tag for string value. this must not be zero")]
|
||||||
|
InvalidTagForStringValueError(),
|
||||||
|
#[error("invalid tag for integer value. this must be less than or equal 0x1f")]
|
||||||
|
InvalidTagForIntegerValueError(),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type AVPType = u8;
|
pub type AVPType = u8;
|
||||||
@@ -42,6 +48,20 @@ impl AVP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encode_tagged_u32(typ: AVPType, tag: Option<&Tag>, value: u32) -> Self {
|
||||||
|
let tag = match tag {
|
||||||
|
None => &Tag {
|
||||||
|
value: UNUSED_TAG_VALUE,
|
||||||
|
},
|
||||||
|
Some(tag) => tag,
|
||||||
|
};
|
||||||
|
|
||||||
|
AVP {
|
||||||
|
typ,
|
||||||
|
value: [vec![tag.value], u32::to_be_bytes(value).to_vec()].concat(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn encode_string(typ: AVPType, value: &str) -> Self {
|
pub fn encode_string(typ: AVPType, value: &str) -> Self {
|
||||||
AVP {
|
AVP {
|
||||||
typ,
|
typ,
|
||||||
@@ -49,6 +69,19 @@ impl AVP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encode_tagged_string(typ: AVPType, tag: Option<&Tag>, value: &str) -> Self {
|
||||||
|
match tag {
|
||||||
|
None => AVP {
|
||||||
|
typ,
|
||||||
|
value: value.as_bytes().to_vec(),
|
||||||
|
},
|
||||||
|
Some(tag) => AVP {
|
||||||
|
typ,
|
||||||
|
value: [vec![tag.value], value.as_bytes().to_vec()].concat(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn encode_bytes(typ: AVPType, value: &[u8]) -> Self {
|
pub fn encode_bytes(typ: AVPType, value: &[u8]) -> Self {
|
||||||
AVP {
|
AVP {
|
||||||
typ,
|
typ,
|
||||||
@@ -142,9 +175,8 @@ impl AVP {
|
|||||||
|
|
||||||
pub fn encode_tunnel_password(
|
pub fn encode_tunnel_password(
|
||||||
typ: AVPType,
|
typ: AVPType,
|
||||||
|
tag: Option<&Tag>,
|
||||||
plain_text: &[u8],
|
plain_text: &[u8],
|
||||||
tag: u8,
|
|
||||||
salt: &[u8],
|
|
||||||
secret: &[u8],
|
secret: &[u8],
|
||||||
request_authenticator: &[u8],
|
request_authenticator: &[u8],
|
||||||
) -> Result<Self, AVPError> {
|
) -> Result<Self, AVPError> {
|
||||||
@@ -176,13 +208,8 @@ impl AVP {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if salt.len() != 2 {
|
let mut rng = rand::thread_rng();
|
||||||
return Err(AVPError::InvalidAttributeLengthError(2));
|
let salt: [u8; 2] = [rng.gen::<u8>() | 0x80, rng.gen::<u8>()];
|
||||||
}
|
|
||||||
|
|
||||||
if salt[0] & 0x80 != 0x80 {
|
|
||||||
return Err(AVPError::InvalidSaltMSBError(salt[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if secret.is_empty() {
|
if secret.is_empty() {
|
||||||
return Err(AVPError::SecretMissingError());
|
return Err(AVPError::SecretMissingError());
|
||||||
@@ -194,9 +221,13 @@ impl AVP {
|
|||||||
|
|
||||||
// NOTE: prepend one byte as a tag and two bytes as a salt
|
// NOTE: prepend one byte as a tag and two bytes as a salt
|
||||||
// TODO: should it separate them to private struct fields?
|
// TODO: should it separate them to private struct fields?
|
||||||
let mut enc: Vec<u8> = [vec![tag], salt.to_vec()].concat();
|
let mut enc: Vec<u8> = [
|
||||||
|
vec![tag.map_or(UNUSED_TAG_VALUE, |v| v.value)],
|
||||||
|
salt.to_vec(),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
let mut buff = [request_authenticator, salt].concat();
|
let mut buff = [request_authenticator, &salt].concat();
|
||||||
if plain_text.is_empty() {
|
if plain_text.is_empty() {
|
||||||
return Ok(AVP {
|
return Ok(AVP {
|
||||||
typ,
|
typ,
|
||||||
@@ -244,6 +275,33 @@ impl AVP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decode_tagged_u32(&self) -> Result<(u32, Tag), AVPError> {
|
||||||
|
if self.value.is_empty() {
|
||||||
|
return Err(AVPError::InvalidAttributeLengthError(self.value.len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let tag = Tag {
|
||||||
|
value: self.value[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref RFC2868:
|
||||||
|
// Valid values for this field are 0x01 through 0x1F,
|
||||||
|
// inclusive. If the Tag field is unused, it MUST be zero (0x00)
|
||||||
|
if !tag.is_valid_value() && !tag.is_zero() {
|
||||||
|
return Err(AVPError::InvalidTagForIntegerValueError());
|
||||||
|
}
|
||||||
|
|
||||||
|
const U32_SIZE: usize = std::mem::size_of::<u32>();
|
||||||
|
if self.value[1..].len() != U32_SIZE {
|
||||||
|
return Err(AVPError::InvalidAttributeLengthError(self.value.len()));
|
||||||
|
}
|
||||||
|
let (int_bytes, _) = self.value[1..].split_at(U32_SIZE);
|
||||||
|
match int_bytes.try_into() {
|
||||||
|
Ok(boxed_array) => Ok((u32::from_be_bytes(boxed_array), tag)),
|
||||||
|
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decode_string(&self) -> Result<String, AVPError> {
|
pub fn decode_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),
|
||||||
@@ -251,6 +309,41 @@ impl AVP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decode_tagged_string(&self) -> Result<(String, Option<Tag>), AVPError> {
|
||||||
|
let string_vec = self.value.to_vec();
|
||||||
|
if string_vec.is_empty() {
|
||||||
|
return Err(AVPError::InvalidAttributeLengthError(string_vec.len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let tag = Tag {
|
||||||
|
value: string_vec[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref RFC2868:
|
||||||
|
// If the value of the Tag field is greater than 0x00
|
||||||
|
// and less than or equal to 0x1F, it SHOULD be interpreted as
|
||||||
|
// indicating which tunnel (of several alternatives) this attribute
|
||||||
|
// pertains.
|
||||||
|
if tag.is_valid_value() {
|
||||||
|
return match String::from_utf8(string_vec[1..].to_vec()) {
|
||||||
|
Ok(str) => Ok((str, Some(tag))),
|
||||||
|
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag.is_zero() {
|
||||||
|
return Err(AVPError::InvalidTagForStringValueError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ref RFC2868:
|
||||||
|
// If the Tag field is greater than 0x1F, it SHOULD be
|
||||||
|
// interpreted as the first byte of the following String field.
|
||||||
|
match String::from_utf8(self.value.to_vec()) {
|
||||||
|
Ok(str) => Ok((str, None)),
|
||||||
|
Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn decode_bytes(&self) -> Vec<u8> {
|
pub fn decode_bytes(&self) -> Vec<u8> {
|
||||||
self.value.to_vec()
|
self.value.to_vec()
|
||||||
}
|
}
|
||||||
@@ -510,7 +603,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_should_convert_tunnel_password() -> Result<(), AVPError> {
|
fn it_should_convert_tunnel_password() -> Result<(), AVPError> {
|
||||||
let salt: Vec<u8> = vec![0x80, 0xef];
|
|
||||||
let tag = Tag { value: 0x1e };
|
let tag = Tag { value: 0x1e };
|
||||||
let secret = b"12345".to_vec();
|
let secret = b"12345".to_vec();
|
||||||
let request_authenticator = b"0123456789abcdef".to_vec();
|
let request_authenticator = b"0123456789abcdef".to_vec();
|
||||||
@@ -550,9 +642,8 @@ mod tests {
|
|||||||
for test_case in test_cases {
|
for test_case in test_cases {
|
||||||
let user_password_avp_result = AVP::encode_tunnel_password(
|
let user_password_avp_result = AVP::encode_tunnel_password(
|
||||||
1,
|
1,
|
||||||
|
Some(&tag),
|
||||||
test_case.plain_text.as_bytes(),
|
test_case.plain_text.as_bytes(),
|
||||||
tag.value,
|
|
||||||
&salt,
|
|
||||||
&secret,
|
&secret,
|
||||||
&request_authenticator,
|
&request_authenticator,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ pub mod request;
|
|||||||
pub mod rfc2865;
|
pub mod rfc2865;
|
||||||
pub mod rfc2866;
|
pub mod rfc2866;
|
||||||
pub mod rfc2867;
|
pub mod rfc2867;
|
||||||
|
pub mod rfc2868;
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
|
|||||||
@@ -0,0 +1,308 @@
|
|||||||
|
// Code generated by machine generator; DO NOT EDIT.
|
||||||
|
|
||||||
|
use crate::avp::{AVPError, AVPType, AVP};
|
||||||
|
use crate::packet::Packet;
|
||||||
|
use crate::tag::Tag;
|
||||||
|
|
||||||
|
pub type TunnelMediumType = u32;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_IP: TunnelMediumType = 1;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_I_PV_4: TunnelMediumType = 1;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_I_PV_6: TunnelMediumType = 2;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_NSAP: TunnelMediumType = 3;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_HDLC: TunnelMediumType = 4;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_BBN_1822: TunnelMediumType = 5;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_IEEE_802: TunnelMediumType = 6;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_E_163: TunnelMediumType = 7;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_E_164: TunnelMediumType = 8;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_F_69: TunnelMediumType = 9;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_X_121: TunnelMediumType = 10;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_IPX: TunnelMediumType = 11;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_APPLETALK: TunnelMediumType = 12;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_DEC_NET_IV: TunnelMediumType = 13;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_BANYAN_VINES: TunnelMediumType = 14;
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_E_164_NSAP: TunnelMediumType = 15;
|
||||||
|
|
||||||
|
pub type TunnelType = u32;
|
||||||
|
pub const TUNNEL_TYPE_PPTP: TunnelType = 1;
|
||||||
|
pub const TUNNEL_TYPE_L2F: TunnelType = 2;
|
||||||
|
pub const TUNNEL_TYPE_L2TP: TunnelType = 3;
|
||||||
|
pub const TUNNEL_TYPE_ATMP: TunnelType = 4;
|
||||||
|
pub const TUNNEL_TYPE_VTP: TunnelType = 5;
|
||||||
|
pub const TUNNEL_TYPE_AH: TunnelType = 6;
|
||||||
|
pub const TUNNEL_TYPE_IP: TunnelType = 7;
|
||||||
|
pub const TUNNEL_TYPE_MIN_IP: TunnelType = 8;
|
||||||
|
pub const TUNNEL_TYPE_ESP: TunnelType = 9;
|
||||||
|
pub const TUNNEL_TYPE_GRE: TunnelType = 10;
|
||||||
|
pub const TUNNEL_TYPE_DVS: TunnelType = 11;
|
||||||
|
pub const TUNNEL_TYPE_IP_IN_IP: TunnelType = 12;
|
||||||
|
|
||||||
|
pub const TUNNEL_TYPE_TYPE: AVPType = 64;
|
||||||
|
pub fn delete_tunnel_type(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_TYPE_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_type(packet: &mut Packet, tag: Option<&Tag>, value: TunnelType) {
|
||||||
|
packet.add(AVP::encode_tagged_u32(TUNNEL_TYPE_TYPE, tag, value as u32));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_type(packet: &Packet) -> Option<Result<(TunnelType, Tag), AVPError>> {
|
||||||
|
packet.lookup(TUNNEL_TYPE_TYPE).map(|v| {
|
||||||
|
let (v, t) = v.decode_tagged_u32()?;
|
||||||
|
Ok((v as TunnelType, t))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_type(packet: &Packet) -> Result<Vec<(TunnelType, Tag)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_TYPE_TYPE) {
|
||||||
|
let (v, t) = avp.decode_tagged_u32()?;
|
||||||
|
vec.push((v as TunnelType, t))
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_MEDIUM_TYPE_TYPE: AVPType = 65;
|
||||||
|
pub fn delete_tunnel_medium_type(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_MEDIUM_TYPE_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_medium_type(packet: &mut Packet, tag: Option<&Tag>, value: TunnelMediumType) {
|
||||||
|
packet.add(AVP::encode_tagged_u32(
|
||||||
|
TUNNEL_MEDIUM_TYPE_TYPE,
|
||||||
|
tag,
|
||||||
|
value as u32,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_medium_type(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Option<Result<(TunnelMediumType, Tag), AVPError>> {
|
||||||
|
packet.lookup(TUNNEL_MEDIUM_TYPE_TYPE).map(|v| {
|
||||||
|
let (v, t) = v.decode_tagged_u32()?;
|
||||||
|
Ok((v as TunnelMediumType, t))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_medium_type(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Result<Vec<(TunnelMediumType, Tag)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_MEDIUM_TYPE_TYPE) {
|
||||||
|
let (v, t) = avp.decode_tagged_u32()?;
|
||||||
|
vec.push((v as TunnelMediumType, t))
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_CLIENT_ENDPOINT_TYPE: AVPType = 66;
|
||||||
|
pub fn delete_tunnel_client_endpoint(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_CLIENT_ENDPOINT_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_client_endpoint(packet: &mut Packet, tag: Option<&Tag>, value: &str) {
|
||||||
|
packet.add(AVP::encode_tagged_string(
|
||||||
|
TUNNEL_CLIENT_ENDPOINT_TYPE,
|
||||||
|
tag,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_client_endpoint(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Option<Result<(String, Option<Tag>), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_CLIENT_ENDPOINT_TYPE)
|
||||||
|
.map(|v| v.decode_tagged_string())
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_client_endpoint(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Result<Vec<(String, Option<Tag>)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_CLIENT_ENDPOINT_TYPE) {
|
||||||
|
vec.push(avp.decode_tagged_string()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_SERVER_ENDPOINT_TYPE: AVPType = 67;
|
||||||
|
pub fn delete_tunnel_server_endpoint(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_SERVER_ENDPOINT_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_server_endpoint(packet: &mut Packet, tag: Option<&Tag>, value: &str) {
|
||||||
|
packet.add(AVP::encode_tagged_string(
|
||||||
|
TUNNEL_SERVER_ENDPOINT_TYPE,
|
||||||
|
tag,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_server_endpoint(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Option<Result<(String, Option<Tag>), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_SERVER_ENDPOINT_TYPE)
|
||||||
|
.map(|v| v.decode_tagged_string())
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_server_endpoint(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Result<Vec<(String, Option<Tag>)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_SERVER_ENDPOINT_TYPE) {
|
||||||
|
vec.push(avp.decode_tagged_string()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_PASSWORD_TYPE: AVPType = 69;
|
||||||
|
pub fn delete_tunnel_password(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_PASSWORD_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_password(
|
||||||
|
packet: &mut Packet,
|
||||||
|
tag: Option<&Tag>,
|
||||||
|
value: &[u8],
|
||||||
|
) -> Result<(), AVPError> {
|
||||||
|
packet.add(AVP::encode_tunnel_password(
|
||||||
|
TUNNEL_PASSWORD_TYPE,
|
||||||
|
tag,
|
||||||
|
value,
|
||||||
|
packet.get_secret(),
|
||||||
|
packet.get_authenticator(),
|
||||||
|
)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_password(packet: &Packet) -> Option<Result<(Vec<u8>, Tag), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_PASSWORD_TYPE)
|
||||||
|
.map(|v| v.decode_tunnel_password(packet.get_secret(), packet.get_authenticator()))
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_password(packet: &Packet) -> Result<Vec<(Vec<u8>, Tag)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_PASSWORD_TYPE) {
|
||||||
|
vec.push(avp.decode_tunnel_password(packet.get_secret(), packet.get_authenticator())?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_PRIVATE_GROUP_ID_TYPE: AVPType = 81;
|
||||||
|
pub fn delete_tunnel_private_group_id(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_PRIVATE_GROUP_ID_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_private_group_id(packet: &mut Packet, tag: Option<&Tag>, value: &str) {
|
||||||
|
packet.add(AVP::encode_tagged_string(
|
||||||
|
TUNNEL_PRIVATE_GROUP_ID_TYPE,
|
||||||
|
tag,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_private_group_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Option<Result<(String, Option<Tag>), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_PRIVATE_GROUP_ID_TYPE)
|
||||||
|
.map(|v| v.decode_tagged_string())
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_private_group_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Result<Vec<(String, Option<Tag>)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_PRIVATE_GROUP_ID_TYPE) {
|
||||||
|
vec.push(avp.decode_tagged_string()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_ASSIGNMENT_ID_TYPE: AVPType = 82;
|
||||||
|
pub fn delete_tunnel_assignment_id(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_ASSIGNMENT_ID_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_assignment_id(packet: &mut Packet, tag: Option<&Tag>, value: &str) {
|
||||||
|
packet.add(AVP::encode_tagged_string(
|
||||||
|
TUNNEL_ASSIGNMENT_ID_TYPE,
|
||||||
|
tag,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_assignment_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Option<Result<(String, Option<Tag>), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_ASSIGNMENT_ID_TYPE)
|
||||||
|
.map(|v| v.decode_tagged_string())
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_assignment_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Result<Vec<(String, Option<Tag>)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_ASSIGNMENT_ID_TYPE) {
|
||||||
|
vec.push(avp.decode_tagged_string()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_PREFERENCE_TYPE: AVPType = 83;
|
||||||
|
pub fn delete_tunnel_preference(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_PREFERENCE_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_preference(packet: &mut Packet, tag: Option<&Tag>, value: u32) {
|
||||||
|
packet.add(AVP::encode_tagged_u32(TUNNEL_PREFERENCE_TYPE, tag, value));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_preference(packet: &Packet) -> Option<Result<(u32, Tag), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_PREFERENCE_TYPE)
|
||||||
|
.map(|v| v.decode_tagged_u32())
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_preference(packet: &Packet) -> Result<Vec<(u32, Tag)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_PREFERENCE_TYPE) {
|
||||||
|
vec.push(avp.decode_tagged_u32()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_CLIENT_AUTH_ID_TYPE: AVPType = 90;
|
||||||
|
pub fn delete_tunnel_client_auth_id(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_CLIENT_AUTH_ID_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_client_auth_id(packet: &mut Packet, tag: Option<&Tag>, value: &str) {
|
||||||
|
packet.add(AVP::encode_tagged_string(
|
||||||
|
TUNNEL_CLIENT_AUTH_ID_TYPE,
|
||||||
|
tag,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_client_auth_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Option<Result<(String, Option<Tag>), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_CLIENT_AUTH_ID_TYPE)
|
||||||
|
.map(|v| v.decode_tagged_string())
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_client_auth_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Result<Vec<(String, Option<Tag>)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_CLIENT_AUTH_ID_TYPE) {
|
||||||
|
vec.push(avp.decode_tagged_string()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TUNNEL_SERVER_AUTH_ID_TYPE: AVPType = 91;
|
||||||
|
pub fn delete_tunnel_server_auth_id(packet: &mut Packet) {
|
||||||
|
packet.delete(TUNNEL_SERVER_AUTH_ID_TYPE);
|
||||||
|
}
|
||||||
|
pub fn add_tunnel_server_auth_id(packet: &mut Packet, tag: Option<&Tag>, value: &str) {
|
||||||
|
packet.add(AVP::encode_tagged_string(
|
||||||
|
TUNNEL_SERVER_AUTH_ID_TYPE,
|
||||||
|
tag,
|
||||||
|
value,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
pub fn lookup_tunnel_server_auth_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Option<Result<(String, Option<Tag>), AVPError>> {
|
||||||
|
packet
|
||||||
|
.lookup(TUNNEL_SERVER_AUTH_ID_TYPE)
|
||||||
|
.map(|v| v.decode_tagged_string())
|
||||||
|
}
|
||||||
|
pub fn lookup_all_tunnel_server_auth_id(
|
||||||
|
packet: &Packet,
|
||||||
|
) -> Result<Vec<(String, Option<Tag>)>, AVPError> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for avp in packet.lookup_all(TUNNEL_SERVER_AUTH_ID_TYPE) {
|
||||||
|
vec.push(avp.decode_tagged_string()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|||||||
+7
-1
@@ -1,15 +1,21 @@
|
|||||||
|
pub(crate) const UNUSED_TAG_VALUE: u8 = 0x00;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
pub(crate) value: u8,
|
pub(crate) value: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tag {
|
impl Tag {
|
||||||
|
pub fn new(value: u8) -> Self {
|
||||||
|
Tag { value }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_value(&self) -> u8 {
|
pub fn get_value(&self) -> u8 {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_zero(&self) -> bool {
|
pub fn is_zero(&self) -> bool {
|
||||||
self.value == 0
|
self.value == UNUSED_TAG_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_valid_value(&self) -> bool {
|
pub fn is_valid_value(&self) -> bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user