Support RFC2868

This commit is contained in:
moznion
2020-12-02 02:26:55 +09:00
parent a86e88cd20
commit f27b0d85fb
7 changed files with 607 additions and 21 deletions
+106 -15
View File
@@ -1,10 +1,12 @@
use rand::Rng;
use std::convert::TryInto;
use std::net::{Ipv4Addr, Ipv6Addr};
use crate::tag::Tag;
use chrono::{DateTime, TimeZone, Utc};
use thiserror::Error;
use crate::tag::{Tag, UNUSED_TAG_VALUE};
#[derive(Error, Debug)]
pub enum AVPError {
#[error(
@@ -22,6 +24,10 @@ pub enum AVPError {
UnexpectedDecodingError(String),
#[error("invalid salt. the MSB has to be 1, but given value isn't: {0}")]
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;
@@ -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 {
AVP {
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 {
AVP {
typ,
@@ -142,9 +175,8 @@ impl AVP {
pub fn encode_tunnel_password(
typ: AVPType,
tag: Option<&Tag>,
plain_text: &[u8],
tag: u8,
salt: &[u8],
secret: &[u8],
request_authenticator: &[u8],
) -> Result<Self, AVPError> {
@@ -176,13 +208,8 @@ impl AVP {
));
}
if salt.len() != 2 {
return Err(AVPError::InvalidAttributeLengthError(2));
}
if salt[0] & 0x80 != 0x80 {
return Err(AVPError::InvalidSaltMSBError(salt[0]));
}
let mut rng = rand::thread_rng();
let salt: [u8; 2] = [rng.gen::<u8>() | 0x80, rng.gen::<u8>()];
if secret.is_empty() {
return Err(AVPError::SecretMissingError());
@@ -194,9 +221,13 @@ impl AVP {
// NOTE: prepend one byte as a tag and two bytes as a salt
// 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() {
return Ok(AVP {
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> {
match String::from_utf8(self.value.to_vec()) {
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> {
self.value.to_vec()
}
@@ -510,7 +603,6 @@ mod tests {
#[test]
fn it_should_convert_tunnel_password() -> Result<(), AVPError> {
let salt: Vec<u8> = vec![0x80, 0xef];
let tag = Tag { value: 0x1e };
let secret = b"12345".to_vec();
let request_authenticator = b"0123456789abcdef".to_vec();
@@ -550,9 +642,8 @@ mod tests {
for test_case in test_cases {
let user_password_avp_result = AVP::encode_tunnel_password(
1,
Some(&tag),
test_case.plain_text.as_bytes(),
tag.value,
&salt,
&secret,
&request_authenticator,
);
+1
View File
@@ -6,4 +6,5 @@ pub mod request;
pub mod rfc2865;
pub mod rfc2866;
pub mod rfc2867;
pub mod rfc2868;
pub mod tag;
+308
View File
@@ -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
View File
@@ -1,15 +1,21 @@
pub(crate) const UNUSED_TAG_VALUE: u8 = 0x00;
#[derive(Debug, PartialEq)]
pub struct Tag {
pub(crate) value: u8,
}
impl Tag {
pub fn new(value: u8) -> Self {
Tag { value }
}
pub fn get_value(&self) -> u8 {
self.value
}
pub fn is_zero(&self) -> bool {
self.value == 0
self.value == UNUSED_TAG_VALUE
}
pub fn is_valid_value(&self) -> bool {