Fix IPv6 socket address parsing

This commit is contained in:
Jan Trefil 2023-08-19 15:19:29 +02:00
parent 29e357da5e
commit e401fee01c

View file

@ -1,7 +1,9 @@
use serde::de::{self, Visitor}; use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use std::fmt::{self, Formatter}; use std::fmt::{self, Formatter};
use std::net::SocketAddr;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr;
use tokio_rustls::rustls::ServerName; use tokio_rustls::rustls::ServerName;
#[derive(Deserialize)] #[derive(Deserialize)]
@ -39,8 +41,16 @@ impl<'de> Visitor<'de> for ServerVisitor {
where where
E: de::Error, E: de::Error,
{ {
// Parsing IPv6 socket addresses can get quite hairy, so let the SocketAddr parser do it for us.
if let Ok(socket_addr) = SocketAddr::from_str(data) {
return Ok(Server {
hostname: ServerName::IpAddress(socket_addr.ip()),
port: socket_addr.port(),
});
}
let (hostname, port) = data let (hostname, port) = data
.rsplit_once(':') .split_once(':')
.ok_or_else(|| E::custom("No port provided"))?; .ok_or_else(|| E::custom("No port provided"))?;
let hostname = hostname.try_into().map_err(E::custom)?; let hostname = hostname.try_into().map_err(E::custom)?;
@ -49,3 +59,64 @@ impl<'de> Visitor<'de> for ServerVisitor {
Ok(Server { hostname, port }) Ok(Server { hostname, port })
} }
} }
#[cfg(test)]
mod tests {
use std::net::Ipv6Addr;
use super::*;
#[derive(Deserialize)]
struct Data {
server: Server,
}
#[test]
fn server_dns() {
let parsed = toml::from_str::<Data>(r#"server = "example.com:8523""#)
.unwrap()
.server;
let expected = Server {
hostname: "example.com".try_into().unwrap(),
port: 8523,
};
assert_eq!(parsed.hostname, expected.hostname);
assert_eq!(parsed.port, expected.port);
}
#[test]
fn server_ipv4() {
let parsed = toml::from_str::<Data>(r#"server = "127.0.0.1:8523""#)
.unwrap()
.server;
let expected = Server {
hostname: "127.0.0.1".try_into().unwrap(),
port: 8523,
};
assert_eq!(parsed.hostname, expected.hostname);
assert_eq!(parsed.port, expected.port);
}
#[test]
fn server_ipv6() {
let parsed = toml::from_str::<Data>(r#"server = "[::1]:8523""#)
.unwrap()
.server;
let expected = Server {
hostname: "::1".try_into().unwrap(),
port: 8523,
};
assert_eq!(parsed.hostname, expected.hostname);
assert_eq!(parsed.port, expected.port);
let parsed_ip = match parsed.hostname {
ServerName::IpAddress(parsed_ip) => parsed_ip,
_ => unreachable!(),
};
assert_eq!(parsed_ip, Ipv6Addr::from_str("::1").unwrap());
}
}