summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2016-12-13 14:37:43 +0100
committerLinus Färnstrand <linus@mullvad.net>2016-12-13 14:37:43 +0100
commitceff53ed4fe81d3ad35c41d2307815add4347c75 (patch)
tree1014fabf5eeeb028b727db03d2cb3c94d94fc970 /src
parentdbaead758cdd25cde30e7f4b452dc1e8d9eb3d40 (diff)
parentee64cfd9ce1e7f4c604314a083fffaa29b7967b9 (diff)
downloadmullvadvpn-ceff53ed4fe81d3ad35c41d2307815add4347c75.tar.xz
mullvadvpn-ceff53ed4fe81d3ad35c41d2307815add4347c75.zip
Merge branch 'change-remote-addr-representation'
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs2
-rw-r--r--src/net.rs91
2 files changed, 57 insertions, 36 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 7683c6dc3b..c65c221aec 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,8 +2,6 @@
//! The core components of the talpidaemon VPN client.
-extern crate regex;
-
/// Working with processes.
pub mod process;
diff --git a/src/net.rs b/src/net.rs
index 5b2bb2838a..8cbc0c25e6 100644
--- a/src/net.rs
+++ b/src/net.rs
@@ -1,74 +1,90 @@
-use regex::Regex;
-
use std::error::Error;
use std::fmt;
use std::io;
use std::iter;
use std::net::SocketAddr;
+use std::num::ParseIntError;
use std::option;
use std::slice;
use std::str::FromStr;
use std::vec;
-/// Representation of a TCP or UDP endpoint. The host is represented as a String since it can be
-/// both a hostname/domain as well as an IP.
+/// Representation of a TCP or UDP endpoint. The IP level address is represented by either an IP
+/// directly or a hostname/domain. The IP level address together with a port becomes a socket
+/// address.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct RemoteAddr {
- address: String,
- port: u16,
+pub enum RemoteAddr {
+ /// Endpoint represented by an IP and a port.
+ SocketAddr(SocketAddr),
+ /// Endpoint represented by a hostname or domain and a port.
+ Domain(String, u16),
}
impl RemoteAddr {
- /// Constructs a new `RemoteAddr` from the given address and port.
+ /// Constructs a new `RemoteAddr` from the given address (hostname or domain) and port. To
+ /// construct a `RemoteAddr` based on IP rather than domain, use the From<SocketAddr> impl.
pub fn new(address: &str, port: u16) -> Self {
- RemoteAddr {
- address: address.to_owned(),
- port: port,
- }
+ RemoteAddr::Domain(address.to_owned(), port)
}
- /// Returns the address associated with this `RemoteAddr`.
- pub fn address(&self) -> &str {
- &self.address
+ /// Returns the address associated with this `RemoteAddr`. If it is backed by an IP that will
+ /// be formatted as a string.
+ pub fn address(&self) -> String {
+ match *self {
+ RemoteAddr::SocketAddr(ref addr) => addr.ip().to_string(),
+ RemoteAddr::Domain(ref address, _) => address.to_owned(),
+ }
}
/// Returns the port associated with this `RemoteAddr`.
pub fn port(&self) -> u16 {
- self.port
+ match *self {
+ RemoteAddr::SocketAddr(addr) => addr.port(),
+ RemoteAddr::Domain(_, port) => port,
+ }
+ }
+
+ fn from_domain_str(s: &str) -> Result<Self, AddrParseError> {
+ let (address, port_str) = Self::split_at_last_colon(s)?;
+ let port = u16::from_str(port_str)?;
+ if address.len() == 0 || address.contains(':') {
+ return Err(AddrParseError(()));
+ }
+ Ok(RemoteAddr::Domain(address.to_owned(), port))
+ }
+
+ fn split_at_last_colon(s: &str) -> Result<(&str, &str), AddrParseError> {
+ let mut iter = s.rsplitn(2, ":");
+ let port = iter.next().unwrap();
+ let address = iter.next().ok_or(AddrParseError(()))?;
+ Ok((address, port))
}
}
impl From<SocketAddr> for RemoteAddr {
fn from(socket_addr: SocketAddr) -> Self {
- RemoteAddr {
- address: socket_addr.ip().to_string(),
- port: socket_addr.port(),
- }
+ RemoteAddr::SocketAddr(socket_addr)
}
}
impl FromStr for RemoteAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
- let (address, port_str) = split_remote_addr_string(s).map_err(|_| AddrParseError(()))?;
- let port = u16::from_str(port_str).map_err(|_| AddrParseError(()))?;
- Ok(RemoteAddr {
- address: address.to_owned(),
- port: port,
- })
+ if let Ok(addr) = SocketAddr::from_str(s) {
+ Ok(RemoteAddr::from(addr))
+ } else {
+ Self::from_domain_str(s)
+ }
}
}
-fn split_remote_addr_string(s: &str) -> Result<(&str, &str), ()> {
- let with_brackets = Regex::new(r"^\[([^\]]+)\]:([0-9]+)$").unwrap();
- let without_brackets = Regex::new(r"^([^:]+):([0-9]+)$").unwrap();
- let captures = with_brackets.captures(s).or(without_brackets.captures(s));
- captures.map(|cs| (cs.at(1).unwrap(), cs.at(2).unwrap())).ok_or(())
-}
impl fmt::Display for RemoteAddr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "{}:{}", self.address, self.port)
+ match *self {
+ RemoteAddr::SocketAddr(ref addr) => addr.fmt(fmt),
+ RemoteAddr::Domain(ref address, ref port) => write!(fmt, "{}:{}", address, port),
+ }
}
}
@@ -76,6 +92,12 @@ impl fmt::Display for RemoteAddr {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AddrParseError(());
+impl From<ParseIntError> for AddrParseError {
+ fn from(_: ParseIntError) -> Self {
+ AddrParseError(())
+ }
+}
+
impl fmt::Display for AddrParseError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.description())
@@ -145,6 +167,8 @@ fn str_to_remote_addr(s: &str) -> io::Result<RemoteAddr> {
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.description()))
}
+
+
#[cfg(test)]
mod remote_addr_tests {
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
@@ -225,7 +249,6 @@ mod remote_addr_tests {
}
#[test]
- #[ignore]
fn to_string_ipv6() {
let socket_addr = SocketAddr::V6(SocketAddrV6::from_str("[2001:beef::1]:9876").unwrap());
let testee = RemoteAddr::from(socket_addr);