chiark / gitweb /
support v6 private addresses
[hippotat.git] / src / types.rs
index 38fcbfec452ca6678aa97c9733fddf2d338abc31..bb4fffb0869ef13774f44a8b0322a7280e269b76 100644 (file)
@@ -1,35 +1,43 @@
 // 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)]
+#[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)]
-pub struct ClientName(pub Ipv4Addr);
+#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq,Ord,PartialOrd)]
+pub struct ClientName(pub IpAddr);
 
-#[derive(Debug,Clone)]
-pub enum SectionName {
-  Link { server: ServerName, client: ClientName },
-  Client(ClientName),
-  Server(ServerName), // includes SERVER, which is slightly special
-  Common,
-  Default,
+#[derive(Debug,Clone,Hash,Eq,PartialEq,Ord,PartialOrd)]
+pub struct LinkName {
+  pub server: ServerName,
+  pub client: ClientName,
 }
-pub use SectionName as SN;
 
 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)"))
+      }
+    )
   }
 }
 
@@ -41,10 +49,10 @@ impl FromStr for ServerName {
         ^ (?: SERVER
             | [0-9a-z][-0-9a-z]* (:? \.
               [0-9a-z][-0-9a-z]*        )*
-          )"x, s) {
+          ) $"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)"));
     }
@@ -52,24 +60,17 @@ impl FromStr for ServerName {
   }
 }
 
-impl FromStr for SectionName {
-  type Err = AE;
-  #[throws(AE)]
-  fn from_str(s: &str) -> Self {
-    match s {
-      "COMMON" => return SN::Common,
-      "DEFAULT" => return SN::Default,
-      _ => { }
-    };
-    if let Ok(n@ ServerName(_)) = s.parse() { return SN::Server(n) }
-    if let Ok(n@ ClientName(_)) = s.parse() { return SN::Client(n) }
-    let (server, client) = s.split_ascii_whitespace().collect_tuple()
-      .ok_or_else(|| anyhow!(
-        "bad section name \
-         (must be COMMON, DEFAULT, <server>, <client>, or <server> <client>"
-      ))?;
-    let server = server.parse().context("server name in link section name")?;
-    let client = client.parse().context("client name in link section name")?;
-    SN::Link { server, client }
+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)?;
   }
 }