diff --git a/README.md b/README.md index 2a899e9..265e3ff 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This supports the following RFC dictionaries at the moment: - [RFC2867](https://tools.ietf.org/html/rfc2867) - [RFC2868](https://tools.ietf.org/html/rfc2868) - [RFC2869](https://tools.ietf.org/html/rfc2869) +- [RFC3162](https://tools.ietf.org/html/rfc3162) - [RFC3576](https://tools.ietf.org/html/rfc3576) - [RFC4072](https://tools.ietf.org/html/rfc4072) - [RFC5090](https://tools.ietf.org/html/rfc5090) @@ -33,7 +34,6 @@ Simple example implementations are here: - retransmission feature on the client - Support the following RFC dictionaries: - - rfc3162 - rfc3580 - rfc4372 - rfc4603 diff --git a/code-generator/src/main.rs b/code-generator/src/main.rs index f8dbf69..56b0981 100644 --- a/code-generator/src/main.rs +++ b/code-generator/src/main.rs @@ -48,6 +48,9 @@ enum RadiusAttributeValueType { TunnelPassword, Octets, IpAddr, + Ipv6Addr, + Ipv6Prefix, + IfId, Date, Integer, VSA, @@ -60,6 +63,9 @@ impl FromStr for RadiusAttributeValueType { "string" => Ok(RadiusAttributeValueType::String), "octets" => Ok(RadiusAttributeValueType::Octets), "ipaddr" => Ok(RadiusAttributeValueType::IpAddr), + "ipv6addr" => Ok(RadiusAttributeValueType::Ipv6Addr), + "ipv6prefix" => Ok(RadiusAttributeValueType::Ipv6Prefix), + "ifid" => Ok(RadiusAttributeValueType::IfId), "date" => Ok(RadiusAttributeValueType::Date), "integer" => Ok(RadiusAttributeValueType::Integer), "vsa" => Ok(RadiusAttributeValueType::VSA), @@ -118,7 +124,7 @@ fn main() { fn generate_header(w: &mut BufWriter) { let code = b"// Code generated by machine generator; DO NOT EDIT. -use std::net::Ipv4Addr; +use std::net::{Ipv4Addr, Ipv6Addr}; use chrono::{DateTime, Utc}; @@ -228,6 +234,23 @@ fn generate_attribute_code( true => unimplemented!("tagged-ip-addr"), false => generate_ipaddr_attribute_code(w, &method_identifier, &type_identifier), }, + RadiusAttributeValueType::Ipv6Addr => match attr.has_tag { + true => unimplemented!("tagged-ip-v6-addr"), + false => generate_ipv6addr_attribute_code(w, &method_identifier, &type_identifier), + }, + RadiusAttributeValueType::Ipv6Prefix => match attr.has_tag { + true => unimplemented!("tagged-ipv6-prefix"), + false => generate_ipv6_prefix_attribute_code(w, &method_identifier, &type_identifier), + }, + RadiusAttributeValueType::IfId => match attr.has_tag { + true => unimplemented!("tagged-ifid"), + false => generate_fixed_length_octets_attribute_code( + w, + &method_identifier, + &type_identifier, + 8, + ), + }, RadiusAttributeValueType::Date => match attr.has_tag { true => unimplemented!("tagged-date"), false => generate_date_attribute_code(w, &method_identifier, &type_identifier), @@ -505,6 +528,59 @@ pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result, w.write_all(code.as_bytes()).unwrap(); } +fn generate_ipv6addr_attribute_code( + w: &mut BufWriter, + method_identifier: &str, + type_identifier: &str, +) { + let code = format!( + "pub fn add_{method_identifier}(packet: &mut Packet, value: &Ipv6Addr) {{ + packet.add(AVP::from_ipv6({type_identifier}, value)); +}} +pub fn lookup_{method_identifier}(packet: &Packet) -> Option> {{ + packet.lookup({type_identifier}).map(|v| v.encode_ipv6()) +}} +pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result, AVPError> {{ + let mut vec = Vec::new(); + for avp in packet.lookup_all({type_identifier}) {{ + vec.push(avp.encode_ipv6()?) + }} + Ok(vec) +}} +", + method_identifier = method_identifier, + type_identifier = type_identifier, + ); + w.write_all(code.as_bytes()).unwrap(); +} + +fn generate_ipv6_prefix_attribute_code( + w: &mut BufWriter, + method_identifier: &str, + type_identifier: &str, +) { + let code = format!( + "pub fn add_{method_identifier}(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> {{ + packet.add(AVP::from_ipv6_prefix({type_identifier}, value)?); + Ok(()) +}} +pub fn lookup_{method_identifier}(packet: &Packet) -> Option, AVPError>> {{ + packet.lookup({type_identifier}).map(|v| v.encode_ipv6_prefix()) +}} +pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result>, AVPError> {{ + let mut vec = Vec::new(); + for avp in packet.lookup_all({type_identifier}) {{ + vec.push(avp.encode_ipv6_prefix()?) + }} + Ok(vec) +}} +", + method_identifier = method_identifier, + type_identifier = type_identifier, + ); + w.write_all(code.as_bytes()).unwrap(); +} + fn generate_date_attribute_code( w: &mut BufWriter, method_identifier: &str, diff --git a/dicts/dictionary.rfc3162 b/dicts/dictionary.rfc3162 new file mode 100644 index 0000000..1a03ef2 --- /dev/null +++ b/dicts/dictionary.rfc3162 @@ -0,0 +1,16 @@ +# -*- 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 3162. +# http://www.ietf.org/rfc/rfc3162.txt +# +# $Id$ +# +ATTRIBUTE NAS-Ipv6-Address 95 ipv6addr +ATTRIBUTE Framed-Interface-Id 96 ifid +ATTRIBUTE Framed-Ipv6-Prefix 97 ipv6prefix +ATTRIBUTE Login-Ipv6-Host 98 ipv6addr +ATTRIBUTE Framed-Ipv6-Route 99 string +ATTRIBUTE Framed-Ipv6-Pool 100 string diff --git a/radius/src/avp.rs b/radius/src/avp.rs index 4b849a5..1a4b3be 100644 --- a/radius/src/avp.rs +++ b/radius/src/avp.rs @@ -103,6 +103,18 @@ impl AVP { } } + pub fn from_ipv6_prefix(typ: AVPType, prefix: &[u8]) -> Result { + let prefix_len = prefix.len(); + if prefix_len > 16 { + return Err(AVPError::InvalidAttributeLengthError(prefix_len)); + } + + Ok(AVP { + typ, + value: [vec![0x00, prefix_len as u8], prefix.to_vec()].concat::(), + }) + } + pub fn from_user_password( typ: AVPType, plain_text: &[u8], @@ -374,6 +386,13 @@ impl AVP { } } + pub fn encode_ipv6_prefix(&self) -> Result, AVPError> { + match self.value.len() > 2 { + true => Ok(self.value[2..].to_owned()), + false => Err(AVPError::InvalidAttributeLengthError(self.value.len())), + } + } + pub fn encode_user_password( &self, secret: &[u8], diff --git a/radius/src/lib.rs b/radius/src/lib.rs index 7c0da0a..0b8d35b 100644 --- a/radius/src/lib.rs +++ b/radius/src/lib.rs @@ -8,6 +8,7 @@ pub mod rfc2866; pub mod rfc2867; pub mod rfc2868; pub mod rfc2869; +pub mod rfc3162; pub mod rfc3576; pub mod rfc4072; pub mod rfc5090; diff --git a/radius/src/rfc3162.rs b/radius/src/rfc3162.rs new file mode 100644 index 0000000..702fae3 --- /dev/null +++ b/radius/src/rfc3162.rs @@ -0,0 +1,131 @@ +// Code generated by machine generator; DO NOT EDIT. + +use std::net::Ipv6Addr; + +use crate::avp::{AVPError, AVPType, AVP}; +use crate::packet::Packet; + +pub const NAS_IPV_6_ADDRESS_TYPE: AVPType = 95; +pub fn delete_nas_ipv_6_address(packet: &mut Packet) { + packet.delete(NAS_IPV_6_ADDRESS_TYPE); +} +pub fn add_nas_ipv_6_address(packet: &mut Packet, value: &Ipv6Addr) { + packet.add(AVP::from_ipv6(NAS_IPV_6_ADDRESS_TYPE, value)); +} +pub fn lookup_nas_ipv_6_address(packet: &Packet) -> Option> { + packet + .lookup(NAS_IPV_6_ADDRESS_TYPE) + .map(|v| v.encode_ipv6()) +} +pub fn lookup_all_nas_ipv_6_address(packet: &Packet) -> Result, AVPError> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(NAS_IPV_6_ADDRESS_TYPE) { + vec.push(avp.encode_ipv6()?) + } + Ok(vec) +} + +pub const FRAMED_INTERFACE_ID_TYPE: AVPType = 96; +pub fn delete_framed_interface_id(packet: &mut Packet) { + packet.delete(FRAMED_INTERFACE_ID_TYPE); +} +pub fn add_framed_interface_id(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { + if value.len() != 8 { + return Err(AVPError::InvalidAttributeLengthError(8)); + } + packet.add(AVP::from_bytes(FRAMED_INTERFACE_ID_TYPE, value)); + Ok(()) +} +pub fn lookup_framed_interface_id(packet: &Packet) -> Option> { + packet + .lookup(FRAMED_INTERFACE_ID_TYPE) + .map(|v| v.encode_bytes()) +} +pub fn lookup_all_framed_interface_id(packet: &Packet) -> Vec> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(FRAMED_INTERFACE_ID_TYPE) { + vec.push(avp.encode_bytes()) + } + vec +} + +pub const FRAMED_IPV_6_PREFIX_TYPE: AVPType = 97; +pub fn delete_framed_ipv_6_prefix(packet: &mut Packet) { + packet.delete(FRAMED_IPV_6_PREFIX_TYPE); +} +pub fn add_framed_ipv_6_prefix(packet: &mut Packet, value: &[u8]) -> Result<(), AVPError> { + packet.add(AVP::from_ipv6_prefix(FRAMED_IPV_6_PREFIX_TYPE, value)?); + Ok(()) +} +pub fn lookup_framed_ipv_6_prefix(packet: &Packet) -> Option, AVPError>> { + packet + .lookup(FRAMED_IPV_6_PREFIX_TYPE) + .map(|v| v.encode_ipv6_prefix()) +} +pub fn lookup_all_framed_ipv_6_prefix(packet: &Packet) -> Result>, AVPError> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(FRAMED_IPV_6_PREFIX_TYPE) { + vec.push(avp.encode_ipv6_prefix()?) + } + Ok(vec) +} + +pub const LOGIN_IPV_6_HOST_TYPE: AVPType = 98; +pub fn delete_login_ipv_6_host(packet: &mut Packet) { + packet.delete(LOGIN_IPV_6_HOST_TYPE); +} +pub fn add_login_ipv_6_host(packet: &mut Packet, value: &Ipv6Addr) { + packet.add(AVP::from_ipv6(LOGIN_IPV_6_HOST_TYPE, value)); +} +pub fn lookup_login_ipv_6_host(packet: &Packet) -> Option> { + packet + .lookup(LOGIN_IPV_6_HOST_TYPE) + .map(|v| v.encode_ipv6()) +} +pub fn lookup_all_login_ipv_6_host(packet: &Packet) -> Result, AVPError> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(LOGIN_IPV_6_HOST_TYPE) { + vec.push(avp.encode_ipv6()?) + } + Ok(vec) +} + +pub const FRAMED_IPV_6_ROUTE_TYPE: AVPType = 99; +pub fn delete_framed_ipv_6_route(packet: &mut Packet) { + packet.delete(FRAMED_IPV_6_ROUTE_TYPE); +} +pub fn add_framed_ipv_6_route(packet: &mut Packet, value: &str) { + packet.add(AVP::from_string(FRAMED_IPV_6_ROUTE_TYPE, value)); +} +pub fn lookup_framed_ipv_6_route(packet: &Packet) -> Option> { + packet + .lookup(FRAMED_IPV_6_ROUTE_TYPE) + .map(|v| v.encode_string()) +} +pub fn lookup_all_framed_ipv_6_route(packet: &Packet) -> Result, AVPError> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(FRAMED_IPV_6_ROUTE_TYPE) { + vec.push(avp.encode_string()?) + } + Ok(vec) +} + +pub const FRAMED_IPV_6_POOL_TYPE: AVPType = 100; +pub fn delete_framed_ipv_6_pool(packet: &mut Packet) { + packet.delete(FRAMED_IPV_6_POOL_TYPE); +} +pub fn add_framed_ipv_6_pool(packet: &mut Packet, value: &str) { + packet.add(AVP::from_string(FRAMED_IPV_6_POOL_TYPE, value)); +} +pub fn lookup_framed_ipv_6_pool(packet: &Packet) -> Option> { + packet + .lookup(FRAMED_IPV_6_POOL_TYPE) + .map(|v| v.encode_string()) +} +pub fn lookup_all_framed_ipv_6_pool(packet: &Packet) -> Result, AVPError> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(FRAMED_IPV_6_POOL_TYPE) { + vec.push(avp.encode_string()?) + } + Ok(vec) +}