2017-11-02 11:55:10 +08:00
|
|
|
#![cfg_attr(not(feature = "proto-ipv6"), allow(dead_code))]
|
|
|
|
|
2017-03-05 12:48:09 +08:00
|
|
|
use core::str::FromStr;
|
2017-01-26 03:41:02 +08:00
|
|
|
use core::result;
|
2017-11-02 11:55:10 +08:00
|
|
|
|
2017-12-24 01:09:35 +08:00
|
|
|
use wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint};
|
2017-11-02 11:55:10 +08:00
|
|
|
use wire::{Ipv4Address, Ipv4Cidr};
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
use wire::{Ipv6Address, Ipv6Cidr};
|
2017-01-26 03:41:02 +08:00
|
|
|
|
|
|
|
type Result<T> = result::Result<T, ()>;
|
|
|
|
|
|
|
|
struct Parser<'a> {
|
|
|
|
data: &'a [u8],
|
|
|
|
pos: usize
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
fn new(data: &'a str) -> Parser<'a> {
|
|
|
|
Parser {
|
|
|
|
data: data.as_bytes(),
|
|
|
|
pos: 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
fn lookahead_char(&self, ch: u8) -> bool {
|
|
|
|
if self.pos < self.data.len() {
|
|
|
|
self.data[self.pos] == ch
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
fn advance(&mut self) -> Result<u8> {
|
|
|
|
match self.data.get(self.pos) {
|
|
|
|
Some(&chr) => {
|
|
|
|
self.pos += 1;
|
|
|
|
Ok(chr)
|
|
|
|
}
|
|
|
|
None => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try<F, T>(&mut self, f: F) -> Option<T>
|
|
|
|
where F: FnOnce(&mut Parser<'a>) -> Result<T> {
|
|
|
|
let pos = self.pos;
|
|
|
|
match f(self) {
|
|
|
|
Ok(res) => Some(res),
|
|
|
|
Err(()) => {
|
|
|
|
self.pos = pos;
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept_eof(&mut self) -> Result<()> {
|
|
|
|
if self.data.len() == self.pos {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn until_eof<F, T>(&mut self, f: F) -> Result<T>
|
|
|
|
where F: FnOnce(&mut Parser<'a>) -> Result<T> {
|
|
|
|
let res = f(self)?;
|
|
|
|
self.accept_eof()?;
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept_char(&mut self, chr: u8) -> Result<()> {
|
|
|
|
if self.advance()? == chr {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
fn accept_str(&mut self, string: &[u8]) -> Result<()> {
|
|
|
|
for byte in string.iter() {
|
|
|
|
self.accept_char(*byte)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
fn accept_digit(&mut self, hex: bool) -> Result<u8> {
|
|
|
|
let digit = self.advance()?;
|
|
|
|
if digit >= b'0' && digit <= b'9' {
|
|
|
|
Ok(digit - b'0')
|
|
|
|
} else if hex && digit >= b'a' && digit <= b'f' {
|
|
|
|
Ok(digit - b'a' + 10)
|
|
|
|
} else if hex && digit >= b'A' && digit <= b'F' {
|
|
|
|
Ok(digit - b'A' + 10)
|
|
|
|
} else {
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept_number(&mut self, max_digits: usize, max_value: u32,
|
|
|
|
hex: bool) -> Result<u32> {
|
|
|
|
let mut value = self.accept_digit(hex)? as u32;
|
|
|
|
for _ in 1..max_digits {
|
|
|
|
match self.try(|p| p.accept_digit(hex)) {
|
|
|
|
Some(digit) => {
|
|
|
|
value *= if hex { 16 } else { 10 };
|
|
|
|
value += digit as u32;
|
|
|
|
}
|
|
|
|
None => break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if value < max_value {
|
|
|
|
Ok(value)
|
|
|
|
} else {
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-27 01:26:54 +08:00
|
|
|
fn accept_mac_joined_with(&mut self, separator: u8) -> Result<EthernetAddress> {
|
2017-01-26 03:41:02 +08:00
|
|
|
let mut octets = [0u8; 6];
|
|
|
|
for n in 0..6 {
|
|
|
|
octets[n] = self.accept_number(2, 0x100, true)? as u8;
|
|
|
|
if n != 5 {
|
2017-01-27 01:26:54 +08:00
|
|
|
self.accept_char(separator)?;
|
2017-01-26 03:41:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(EthernetAddress(octets))
|
|
|
|
}
|
|
|
|
|
2017-01-27 01:26:54 +08:00
|
|
|
fn accept_mac(&mut self) -> Result<EthernetAddress> {
|
|
|
|
if let Some(mac) = self.try(|p| p.accept_mac_joined_with(b'-')) {
|
|
|
|
return Ok(mac)
|
|
|
|
}
|
|
|
|
if let Some(mac) = self.try(|p| p.accept_mac_joined_with(b':')) {
|
|
|
|
return Ok(mac)
|
|
|
|
}
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
fn accept_ipv6_part(&mut self, (head, tail): (&mut [u16; 8], &mut [u16; 6]),
|
|
|
|
(head_idx, tail_idx): (&mut usize, &mut usize),
|
|
|
|
mut use_tail: bool, is_cidr: bool) -> Result<()> {
|
|
|
|
let double_colon = match self.try(|p| p.accept_str(b"::")) {
|
|
|
|
Some(_) if !use_tail && *head_idx < 7 => {
|
|
|
|
// Found a double colon. Start filling out the
|
|
|
|
// tail and set the double colon flag in case
|
|
|
|
// this is the last character we can parse.
|
|
|
|
use_tail = true;
|
|
|
|
true
|
|
|
|
},
|
|
|
|
Some(_) => {
|
|
|
|
// This is a bad address. Only one double colon is
|
|
|
|
// allowed and an address is only 128 bits.
|
|
|
|
return Err(());
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
if *head_idx != 0 || use_tail && *tail_idx != 0 {
|
|
|
|
// If this is not the first number or the position following
|
|
|
|
// a double colon, we expect there to be a single colon.
|
|
|
|
self.accept_char(b':')?;
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match self.try(|p| p.accept_number(4, 0x10000, true)) {
|
|
|
|
Some(part) if !use_tail && *head_idx < 8 => {
|
|
|
|
// Valid u16 to be added to the address
|
|
|
|
head[*head_idx] = part as u16;
|
|
|
|
*head_idx += 1;
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
Some(part) if *tail_idx < 6 => {
|
|
|
|
// Valid u16 to be added to the address
|
|
|
|
tail[*tail_idx] = part as u16;
|
|
|
|
*tail_idx += 1;
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
Some(_) => {
|
|
|
|
// Tail or head section is too long
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
None if double_colon && (is_cidr || self.pos == self.data.len()) => {
|
|
|
|
// The address ends with "::". E.g. 1234:: or ::
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// Invalid address
|
|
|
|
Err(())
|
|
|
|
}
|
|
|
|
}?;
|
|
|
|
|
|
|
|
if *head_idx + *tail_idx > 8 {
|
|
|
|
// The head and tail indexes add up to a bad address length.
|
|
|
|
Err(())
|
|
|
|
} else if !self.lookahead_char(b':') {
|
|
|
|
if *head_idx < 8 && !use_tail {
|
|
|
|
// There was no double colon found, and the head is too short
|
|
|
|
return Err(());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
// Continue recursing
|
|
|
|
self.accept_ipv6_part((head, tail), (head_idx, tail_idx), use_tail, is_cidr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
fn accept_ipv6(&mut self, is_cidr: bool) -> Result<Ipv6Address> {
|
|
|
|
// IPv6 addresses may contain a "::" to indicate a series of
|
|
|
|
// 16 bit sections that evaluate to 0. E.g.
|
|
|
|
//
|
|
|
|
// fe80:0000:0000:0000:0000:0000:0000:0001
|
|
|
|
//
|
|
|
|
// May be written as
|
|
|
|
//
|
|
|
|
// fe80::1
|
|
|
|
//
|
|
|
|
// As a result, we need to find the first section of colon
|
|
|
|
// delimited u16's before a possible "::", then the
|
|
|
|
// possible second section after the "::", and finally
|
|
|
|
// combine the second optional section to the end of the
|
|
|
|
// final address.
|
2017-11-30 21:22:56 +08:00
|
|
|
//
|
|
|
|
// See https://tools.ietf.org/html/rfc4291#section-2.2
|
|
|
|
// for details.
|
2017-11-02 11:55:10 +08:00
|
|
|
let (mut addr, mut tail) = ([0u16; 8], [0u16; 6]);
|
|
|
|
let (mut head_idx, mut tail_idx) = (0, 0);
|
|
|
|
|
|
|
|
self.accept_ipv6_part((&mut addr, &mut tail), (&mut head_idx, &mut tail_idx), false, is_cidr)?;
|
|
|
|
|
|
|
|
// We need to copy the tail portion (the portion following the "::") to the
|
|
|
|
// end of the address.
|
|
|
|
addr[8 - tail_idx..].copy_from_slice(&tail[..tail_idx]);
|
|
|
|
|
|
|
|
Ok(Ipv6Address::from_parts(&addr))
|
|
|
|
}
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
fn accept_ipv4(&mut self) -> Result<Ipv4Address> {
|
|
|
|
let mut octets = [0u8; 4];
|
|
|
|
for n in 0..4 {
|
|
|
|
octets[n] = self.accept_number(3, 0x100, false)? as u8;
|
|
|
|
if n != 3 {
|
|
|
|
self.accept_char(b'.')?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(Ipv4Address(octets))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept_ip(&mut self) -> Result<IpAddress> {
|
|
|
|
if let Some(ipv4) = self.try(|p| p.accept_ipv4()) {
|
|
|
|
return Ok(IpAddress::Ipv4(ipv4))
|
|
|
|
}
|
2017-11-02 11:55:10 +08:00
|
|
|
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
match self.try(|p| p.accept_ipv6(false)) {
|
|
|
|
Some(ipv6) => return Ok(IpAddress::Ipv6(ipv6)),
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
Err(())
|
|
|
|
}
|
2017-12-24 01:09:35 +08:00
|
|
|
|
|
|
|
fn accept_ipv4_endpoint(&mut self) -> Result<IpEndpoint> {
|
|
|
|
let ip = self.accept_ipv4()?;
|
|
|
|
|
|
|
|
let port = if self.accept_eof().is_ok() {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
self.accept_char(b':')?;
|
|
|
|
self.accept_number(5, 65535, false)?
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(IpEndpoint { addr: IpAddress::Ipv4(ip), port: port as u16 })
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
fn accept_ipv6_endpoint(&mut self, is_cidr: bool) -> Result<IpEndpoint> {
|
|
|
|
if self.lookahead_char(b'[') {
|
|
|
|
self.accept_char(b'[')?;
|
|
|
|
let ip = self.accept_ipv6(false)?;
|
|
|
|
self.accept_char(b']')?;
|
|
|
|
self.accept_char(b':')?;
|
|
|
|
let port = self.accept_number(5, 65535, false)?;
|
|
|
|
|
|
|
|
Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: port as u16 })
|
|
|
|
} else {
|
|
|
|
let ip = self.accept_ipv6(is_cidr)?;
|
|
|
|
Ok(IpEndpoint { addr: IpAddress::Ipv6(ip), port: 0 })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept_ip_endpoint(&mut self) -> Result<IpEndpoint> {
|
|
|
|
if let Some(ipv4) = self.try(|p| p.accept_ipv4_endpoint()) {
|
|
|
|
return Ok(ipv4)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
match self.try(|p| p.accept_ipv6_endpoint(false)) {
|
|
|
|
Some(ipv6) => return Ok(ipv6),
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(())
|
|
|
|
}
|
2017-01-26 03:41:02 +08:00
|
|
|
}
|
|
|
|
|
2017-03-05 12:48:09 +08:00
|
|
|
impl FromStr for EthernetAddress {
|
|
|
|
type Err = ();
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
/// Parse a string representation of an Ethernet address.
|
2017-03-05 12:48:09 +08:00
|
|
|
fn from_str(s: &str) -> Result<EthernetAddress> {
|
2017-01-26 03:41:02 +08:00
|
|
|
Parser::new(s).until_eof(|p| p.accept_mac())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 12:48:09 +08:00
|
|
|
impl FromStr for Ipv4Address {
|
|
|
|
type Err = ();
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
/// Parse a string representation of an IPv4 address.
|
2017-03-05 12:48:09 +08:00
|
|
|
fn from_str(s: &str) -> Result<Ipv4Address> {
|
2017-01-26 03:41:02 +08:00
|
|
|
Parser::new(s).until_eof(|p| p.accept_ipv4())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
impl FromStr for Ipv6Address {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
/// Parse a string representation of an IPv6 address.
|
|
|
|
fn from_str(s: &str) -> Result<Ipv6Address> {
|
|
|
|
Parser::new(s).until_eof(|p| p.accept_ipv6(false))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-05 12:48:09 +08:00
|
|
|
impl FromStr for IpAddress {
|
|
|
|
type Err = ();
|
|
|
|
|
2017-10-30 15:20:23 +08:00
|
|
|
/// Parse a string representation of an IP address.
|
2017-03-05 12:48:09 +08:00
|
|
|
fn from_str(s: &str) -> Result<IpAddress> {
|
2017-01-26 03:41:02 +08:00
|
|
|
Parser::new(s).until_eof(|p| p.accept_ip())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-03 15:26:31 +08:00
|
|
|
impl FromStr for Ipv4Cidr {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
/// Parse a string representation of an IPv4 CIDR.
|
|
|
|
fn from_str(s: &str) -> Result<Ipv4Cidr> {
|
|
|
|
Parser::new(s).until_eof(|p| {
|
|
|
|
let ip = p.accept_ipv4()?;
|
|
|
|
p.accept_char(b'/')?;
|
|
|
|
let prefix_len = p.accept_number(2, 33, false)? as u8;
|
|
|
|
Ok(Ipv4Cidr::new(ip, prefix_len))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
impl FromStr for Ipv6Cidr {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
/// Parse a string representation of an IPv6 CIDR.
|
|
|
|
fn from_str(s: &str) -> Result<Ipv6Cidr> {
|
2017-11-30 21:22:56 +08:00
|
|
|
// https://tools.ietf.org/html/rfc4291#section-2.3
|
2017-11-02 11:55:10 +08:00
|
|
|
Parser::new(s).until_eof(|p| {
|
|
|
|
let ip = p.accept_ipv6(true)?;
|
|
|
|
p.accept_char(b'/')?;
|
|
|
|
let prefix_len = p.accept_number(3, 129, false)? as u8;
|
|
|
|
Ok(Ipv6Cidr::new(ip, prefix_len))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-03 15:26:31 +08:00
|
|
|
impl FromStr for IpCidr {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
/// Parse a string representation of an IP CIDR.
|
|
|
|
fn from_str(s: &str) -> Result<IpCidr> {
|
2017-11-02 11:55:10 +08:00
|
|
|
if let Ok(ipv4) = Ipv4Cidr::from_str(s) {
|
|
|
|
return Ok(IpCidr::Ipv4(ipv4))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
match Ipv6Cidr::from_str(s) {
|
|
|
|
Ok(cidr) => return Ok(IpCidr::Ipv6(cidr)),
|
|
|
|
Err(_) => ()
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(())
|
2017-10-03 15:26:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-24 01:09:35 +08:00
|
|
|
impl FromStr for IpEndpoint {
|
|
|
|
type Err = ();
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<IpEndpoint> {
|
|
|
|
Parser::new(s).until_eof(|p| Ok(p.accept_ip_endpoint()?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
macro_rules! check_cidr_test_array {
|
|
|
|
($tests:expr, $from_str:path, $variant:path) => {
|
|
|
|
for &(s, cidr) in &$tests {
|
|
|
|
assert_eq!($from_str(s), cidr);
|
|
|
|
assert_eq!(IpCidr::from_str(s), cidr.map($variant));
|
|
|
|
|
|
|
|
if let Ok(cidr) = cidr {
|
|
|
|
assert_eq!($from_str(&format!("{}", cidr)), Ok(cidr));
|
|
|
|
assert_eq!(IpCidr::from_str(&format!("{}", cidr)),
|
|
|
|
Ok($variant(cidr)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-26 03:41:02 +08:00
|
|
|
#[test]
|
|
|
|
fn test_mac() {
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(EthernetAddress::from_str(""), Err(()));
|
|
|
|
assert_eq!(EthernetAddress::from_str("02:00:00:00:00:00"),
|
2017-01-26 03:41:02 +08:00
|
|
|
Ok(EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x00])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(EthernetAddress::from_str("01:23:45:67:89:ab"),
|
2017-01-26 03:41:02 +08:00
|
|
|
Ok(EthernetAddress([0x01, 0x23, 0x45, 0x67, 0x89, 0xab])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(EthernetAddress::from_str("cd:ef:10:00:00:00"),
|
2017-01-26 03:41:02 +08:00
|
|
|
Ok(EthernetAddress([0xcd, 0xef, 0x10, 0x00, 0x00, 0x00])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(EthernetAddress::from_str("00:00:00:ab:cd:ef"),
|
2017-01-26 03:41:02 +08:00
|
|
|
Ok(EthernetAddress([0x00, 0x00, 0x00, 0xab, 0xcd, 0xef])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(EthernetAddress::from_str("00-00-00-ab-cd-ef"),
|
2017-01-27 01:26:54 +08:00
|
|
|
Ok(EthernetAddress([0x00, 0x00, 0x00, 0xab, 0xcd, 0xef])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(EthernetAddress::from_str("AB-CD-EF-00-00-00"),
|
2017-01-27 01:26:54 +08:00
|
|
|
Ok(EthernetAddress([0xab, 0xcd, 0xef, 0x00, 0x00, 0x00])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(EthernetAddress::from_str("100:00:00:00:00:00"), Err(()));
|
|
|
|
assert_eq!(EthernetAddress::from_str("002:00:00:00:00:00"), Err(()));
|
|
|
|
assert_eq!(EthernetAddress::from_str("02:00:00:00:00:000"), Err(()));
|
|
|
|
assert_eq!(EthernetAddress::from_str("02:00:00:00:00:0x"), Err(()));
|
2017-01-26 03:41:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ipv4() {
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(Ipv4Address::from_str(""), Err(()));
|
|
|
|
assert_eq!(Ipv4Address::from_str("1.2.3.4"),
|
2017-01-26 03:41:02 +08:00
|
|
|
Ok(Ipv4Address([1, 2, 3, 4])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(Ipv4Address::from_str("001.2.3.4"),
|
2017-01-26 03:41:02 +08:00
|
|
|
Ok(Ipv4Address([1, 2, 3, 4])));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(Ipv4Address::from_str("0001.2.3.4"), Err(()));
|
|
|
|
assert_eq!(Ipv4Address::from_str("999.2.3.4"), Err(()));
|
|
|
|
assert_eq!(Ipv4Address::from_str("1.2.3.4.5"), Err(()));
|
|
|
|
assert_eq!(Ipv4Address::from_str("1.2.3"), Err(()));
|
|
|
|
assert_eq!(Ipv4Address::from_str("1.2.3."), Err(()));
|
|
|
|
assert_eq!(Ipv4Address::from_str("1.2.3.4."), Err(()));
|
2017-01-26 03:41:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2017-11-02 11:55:10 +08:00
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
fn test_ipv6() {
|
|
|
|
// Obviously not valid
|
|
|
|
assert_eq!(Ipv6Address::from_str(""), Err(()));
|
|
|
|
assert_eq!(Ipv6Address::from_str("fe80:0:0:0:0:0:0:1"),
|
|
|
|
Ok(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1)));
|
|
|
|
assert_eq!(Ipv6Address::from_str("::1"),
|
|
|
|
Ok(Ipv6Address::LOOPBACK));
|
|
|
|
assert_eq!(Ipv6Address::from_str("::"),
|
|
|
|
Ok(Ipv6Address::UNSPECIFIED));
|
|
|
|
assert_eq!(Ipv6Address::from_str("fe80::1"),
|
|
|
|
Ok(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1)));
|
|
|
|
assert_eq!(Ipv6Address::from_str("1234:5678::"),
|
|
|
|
Ok(Ipv6Address::new(0x1234, 0x5678, 0, 0, 0, 0, 0, 0)));
|
|
|
|
assert_eq!(Ipv6Address::from_str("1234:5678::8765:4321"),
|
|
|
|
Ok(Ipv6Address::new(0x1234, 0x5678, 0, 0, 0, 0, 0x8765, 0x4321)));
|
|
|
|
// Two double colons in address
|
|
|
|
assert_eq!(Ipv6Address::from_str("1234:5678::1::1"),
|
|
|
|
Err(()));
|
|
|
|
assert_eq!(Ipv6Address::from_str("4444:333:22:1::4"),
|
|
|
|
Ok(Ipv6Address::new(0x4444, 0x0333, 0x0022, 0x0001, 0, 0, 0, 4)));
|
|
|
|
assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1::"),
|
|
|
|
Ok(Ipv6Address::new(1, 1, 1, 1, 1, 1, 0, 0)));
|
|
|
|
assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1"),
|
|
|
|
Ok(Ipv6Address::new(0, 0, 1, 1, 1, 1, 1, 1)));
|
|
|
|
assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1:1"),
|
|
|
|
Err(()));
|
|
|
|
// Double colon appears too late indicating an address that is too long
|
|
|
|
assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1::"),
|
|
|
|
Err(()));
|
|
|
|
// Section after double colon is too long for a valid address
|
|
|
|
assert_eq!(Ipv6Address::from_str("::1:1:1:1:1:1:1"),
|
|
|
|
Err(()));
|
|
|
|
// Obviously too long
|
|
|
|
assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1:1:1"),
|
|
|
|
Err(()));
|
|
|
|
// Address is too short
|
|
|
|
assert_eq!(Ipv6Address::from_str("1:1:1:1:1:1:1"),
|
|
|
|
Err(()));
|
|
|
|
// Long number
|
|
|
|
assert_eq!(Ipv6Address::from_str("::000001"),
|
|
|
|
Err(()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ip_ipv4() {
|
2017-10-30 15:20:23 +08:00
|
|
|
assert_eq!(IpAddress::from_str(""), Err(()));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(IpAddress::from_str("1.2.3.4"),
|
2017-01-26 03:41:02 +08:00
|
|
|
Ok(IpAddress::Ipv4(Ipv4Address([1, 2, 3, 4]))));
|
2017-03-05 12:48:09 +08:00
|
|
|
assert_eq!(IpAddress::from_str("x"), Err(()));
|
2017-01-26 03:41:02 +08:00
|
|
|
}
|
2017-10-03 15:26:31 +08:00
|
|
|
|
|
|
|
#[test]
|
2017-11-02 11:55:10 +08:00
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
fn test_ip_ipv6() {
|
|
|
|
assert_eq!(IpAddress::from_str(""), Err(()));
|
|
|
|
assert_eq!(IpAddress::from_str("fe80::1"),
|
|
|
|
Ok(IpAddress::Ipv6(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1))));
|
|
|
|
assert_eq!(IpAddress::from_str("x"), Err(()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_cidr_ipv4() {
|
2017-10-03 15:26:31 +08:00
|
|
|
let tests = [
|
|
|
|
("127.0.0.1/8",
|
|
|
|
Ok(Ipv4Cidr::new(Ipv4Address([127, 0, 0, 1]), 8u8))),
|
|
|
|
("192.168.1.1/24",
|
|
|
|
Ok(Ipv4Cidr::new(Ipv4Address([192, 168, 1, 1]), 24u8))),
|
|
|
|
("8.8.8.8/32",
|
|
|
|
Ok(Ipv4Cidr::new(Ipv4Address([8, 8, 8, 8]), 32u8))),
|
|
|
|
("8.8.8.8/0",
|
|
|
|
Ok(Ipv4Cidr::new(Ipv4Address([8, 8, 8, 8]), 0u8))),
|
|
|
|
("", Err(())),
|
|
|
|
("1", Err(())),
|
|
|
|
("127.0.0.1", Err(())),
|
|
|
|
("127.0.0.1/", Err(())),
|
|
|
|
("127.0.0.1/33", Err(())),
|
|
|
|
("127.0.0.1/111", Err(())),
|
|
|
|
("/32", Err(())),
|
|
|
|
];
|
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
check_cidr_test_array!(tests, Ipv4Cidr::from_str, IpCidr::Ipv4);
|
|
|
|
}
|
2017-10-03 15:26:31 +08:00
|
|
|
|
2017-11-02 11:55:10 +08:00
|
|
|
#[test]
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
fn test_cidr_ipv6() {
|
|
|
|
let tests = [
|
|
|
|
("fe80::1/64",
|
|
|
|
Ok(Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64u8))),
|
|
|
|
("fe80::/64",
|
|
|
|
Ok(Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0), 64u8))),
|
|
|
|
("::1/128",
|
|
|
|
Ok(Ipv6Cidr::new(Ipv6Address::LOOPBACK, 128u8))),
|
|
|
|
("::/128",
|
|
|
|
Ok(Ipv6Cidr::new(Ipv6Address::UNSPECIFIED, 128u8))),
|
|
|
|
("fe80:0:0:0:0:0:0:1/64",
|
|
|
|
Ok(Ipv6Cidr::new(Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64u8))),
|
|
|
|
("fe80:0:0:0:0:0:0:1|64",
|
|
|
|
Err(())),
|
|
|
|
("fe80::|64",
|
|
|
|
Err(())),
|
|
|
|
("fe80::1::/64",
|
|
|
|
Err(()))
|
|
|
|
];
|
|
|
|
check_cidr_test_array!(tests, Ipv6Cidr::from_str, IpCidr::Ipv6);
|
2017-10-03 15:26:31 +08:00
|
|
|
}
|
2017-12-24 01:09:35 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_endpoint_ipv4() {
|
|
|
|
assert_eq!(IpEndpoint::from_str(""), Err(()));
|
|
|
|
assert_eq!(IpEndpoint::from_str("x"), Err(()));
|
|
|
|
assert_eq!(
|
|
|
|
IpEndpoint::from_str("127.0.0.1"),
|
|
|
|
Ok(IpEndpoint { addr: IpAddress::v4(127, 0, 0, 1), port: 0 })
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
IpEndpoint::from_str("127.0.0.1:12345"),
|
|
|
|
Ok(IpEndpoint { addr: IpAddress::v4(127, 0, 0, 1), port: 12345 })
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
|
fn test_endpoint_ipv6() {
|
|
|
|
assert_eq!(IpEndpoint::from_str(""), Err(()));
|
|
|
|
assert_eq!(IpEndpoint::from_str("x"), Err(()));
|
|
|
|
assert_eq!(
|
|
|
|
IpEndpoint::from_str("fe80::1"),
|
|
|
|
Ok(IpEndpoint { addr: IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), port: 0 })
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
IpEndpoint::from_str("[fe80::1]:12345"),
|
|
|
|
Ok(IpEndpoint { addr: IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), port: 12345 })
|
|
|
|
);
|
|
|
|
}
|
2017-01-26 03:41:02 +08:00
|
|
|
}
|