chiark / gitweb /
support v6 private addresses
[hippotat.git] / src / types.rs
index a18ee8bed0d524f149acf6f57bf7c9d7a89dd0e6..bb4fffb0869ef13774f44a8b0322a7280e269b76 100644 (file)
@@ -1,16 +1,19 @@
 // Copyright 2021 Ian Jackson and contributors to Hippotat
-// SPDX-License-Identifier: AGPL-3.0-or-later
+// SPDX-License-Identifier: GPL-3.0-or-later
 // There is NO WARRANTY.
 
 use crate::prelude::*;
 
-#[derive(Debug,Clone,Hash,Eq,PartialEq)]
+#[derive(Debug,Copy,Clone)]
+pub enum LinkEnd { Server, Client }
+
+#[derive(Debug,Clone,Hash,Eq,PartialEq,Ord,PartialOrd)]
 pub struct ServerName(pub String);
 
-#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
-pub struct ClientName(pub Ipv4Addr);
+#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd)]
+pub struct ClientName(pub IpAddr);
 
-#[derive(Debug,Clone,Hash,Eq,PartialEq)]
+#[derive(Debug,Clone,Hash,Eq,PartialEq,Ord,PartialOrd)]
 pub struct LinkName {
   pub server: ServerName,
   pub client: ClientName,
@@ -20,12 +23,21 @@ impl FromStr for ClientName {
   type Err = AE;
   #[throws(AE)]
   fn from_str(s: &str) -> Self {
-    let v4addr: Ipv4Addr = s.parse()
-      .context("invalid client name (IPv4 address)")?;
-    if s != v4addr.to_string() {
-      throw!(anyhow!("invalid client name (unusual IPv4 address syntax)"));
-    }
-    ClientName(v4addr)
+    ClientName(
+      if let Ok(v4addr) = s.parse::<Ipv4Addr>() {
+        if s != v4addr.to_string() {
+          throw!(anyhow!("invalid client name (unusual IPv4 address syntax)"));
+        }
+        v4addr.into()
+      } else if let Ok(v6addr) = s.parse::<Ipv6Addr>() {
+        if s != v6addr.to_string() {
+          throw!(anyhow!("invalid client name (non-canonical IPv6 address)"));
+        }
+        v6addr.into()
+      } else {
+        throw!(anyhow!("invalid client name (IPv4 or IPv6 address)"))
+      }
+    )
   }
 }
 
@@ -40,10 +52,25 @@ impl FromStr for ServerName {
           ) $"x, s) {
       throw!(anyhow!("bad syntax for server name"));
     }
-    if ! regex_is_match!(r"[a-z-]", s) {
+    if ! regex_is_match!(r"[A-Za-z-]", s) {
       throw!(anyhow!("bad syntax for server name \
                       (too much like an IPv4 address)"));
     }
     ServerName(s.into())
   }
 }
+
+impl Display for ServerName {
+  #[throws(fmt::Error)]
+  fn fmt(&self, f: &mut fmt::Formatter) { Display::fmt(&self.0, f)?; }
+}
+impl Display for ClientName {
+  #[throws(fmt::Error)]
+  fn fmt(&self, f: &mut fmt::Formatter) { Display::fmt(&self.0, f)?; }
+}
+impl Display for LinkName {
+  #[throws(fmt::Error)]
+  fn fmt(&self, f: &mut fmt::Formatter) {
+    write!(f, "[{} {}]", &self.server, &self.client)?;
+  }
+}