On Fri, Apr 04, 2025 at 09:51:05AM +0200, Stefan Hanreich wrote: > Thanks for your review - comments inline > > On 4/4/25 09:31, Wolfgang Bumiller wrote: > > On Tue, Apr 01, 2025 at 04:52:44PM +0200, Stefan Hanreich wrote: > >> Add a type for representing Linux hostnames. These are the same > >> constraints as the installer enforces [1]. Lowercasing is fine as > >> well, since practically everything treats hostnames case-insensitively > >> as RFC 952 stipulates: > >> > >>> No distinction is made between upper and lower case. > >> > >> [1] > >> https://git.proxmox.com/?p=pve-installer.git;a=blob;f=Proxmox/Sys/Net.pm;h=81cb15f0042b195461324fffeca53d732133629e;hb=HEAD#l11 > >> [2] https://www.rfc-editor.org/rfc/rfc952.txt > >> > >> Signed-off-by: Stefan Hanreich <s.hanre...@proxmox.com> > >> --- > >> > >> Notes: > >> sending this separately because this contains the new types, that > >> haven't been a part of proxmox-ve-rs before. > >> > >> Changes from v2: > >> * improved hostname validation (thanks @Maximiliano @Christoph) > >> * added additional unit tests > >> > >> Changes from v1: > >> * added unit tests > >> > >> proxmox-network-types/src/hostname.rs | 103 ++++++++++++++++++++++++++ > >> proxmox-network-types/src/lib.rs | 1 + > >> 2 files changed, 104 insertions(+) > >> create mode 100644 proxmox-network-types/src/hostname.rs > >> > >> diff --git a/proxmox-network-types/src/hostname.rs > >> b/proxmox-network-types/src/hostname.rs > >> new file mode 100644 > >> index 00000000..4b2f7ede > >> --- /dev/null > >> +++ b/proxmox-network-types/src/hostname.rs > >> @@ -0,0 +1,103 @@ > >> +use std::fmt::Display; > >> + > >> +use serde::{Deserialize, Serialize}; > >> +use thiserror::Error; > >> + > >> +#[derive(Error, Debug)] > >> +pub enum HostnameError { > >> + #[error("the hostname must be from 1 to 63 characters long")] > >> + InvalidLength, > >> + #[error("the hostname has an invalid format")] > >> + InvalidFormat, > >> +} > >> + > >> +/// Hostname of a Debian system > > > > ^ Why debian specific? Should this then not be in a different namespace > > or have a different name? > > As Christoph mentioned, Debian explicitly forbids numeric-only > hostnames. They are technically valid, just *strongly* discouraged since > depending on the implementation they are interpreted as IPs rather than > hostnames. 0 or 1 or 234728934 for instance is a valid IPv4 after all > (ping accepts them as input for instance). > > Since we're debian-based I figured I'd add it to the validation since > it's very much relevant for our use-case here. I have nothing against > changing the name though to DebianHostname. > > >> +/// > >> +/// It checks for the following conditions: > >> +/// * At most 63 characters long. > >> +/// * It must not start or end with a hyphen. > >> +/// * Must only contain ASCII alphanumeric characters as well as hyphens. > >> +/// * It must not be purely numerical. > >> +#[derive(Debug, Deserialize, Serialize, Clone, Eq, Hash, PartialOrd, Ord, > >> PartialEq)] > >> +pub struct Hostname(String); > >> + > >> +impl std::str::FromStr for Hostname { > >> + type Err = HostnameError; > >> + > >> + fn from_str(hostname: &str) -> Result<Self, Self::Err> { > >> + Self::new(hostname) > >> + } > >> +} > >> + > >> +impl AsRef<str> for Hostname { > >> + fn as_ref(&self) -> &str { > >> + &self.0 > >> + } > >> +} > >> + > >> +impl Display for Hostname { > >> + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { > >> + self.0.fmt(f) > >> + } > >> +} > >> + > >> +impl Hostname { > >> + /// Constructs a new hostname from a string > >> + /// > >> + /// This function accepts characters in any case, but the resulting > >> hostname will be > >> + /// lowercased. > >> + pub fn new(name_ref: impl AsRef<str>) -> Result<Self, HostnameError> { > > > > Nit: I'd recommend using a `check()` function which does not create the > > `Hostname` itself, because then: > > > > - in `FromStr` we know we have a reference (&str) and need to clone. > > - We could add a `TryFrom<&str>` wich just uses `.parse()` > > - We could add a `TryFrom<String>` which avoids the clone. > > > > But... > > > >> + let name: &str = name_ref.as_ref(); > >> + > >> + if name.is_empty() || name.len() > 63 { > >> + return Err(HostnameError::InvalidLength); > >> + } > >> + > >> + if !(name.starts_with(|c: char| c.is_ascii_alphanumeric()) > >> + && name.ends_with(|c: char| c.is_ascii_alphanumeric())) { > >> + return Err(HostnameError::InvalidFormat); > >> + } > >> + > >> + if !name.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') { > >> + return Err(HostnameError::InvalidFormat); > >> + }
(Oh btw. if we move this up above the upper check, that one could be shortened to `.{starts,ends}_with('-')`, no?) > >> + > >> + if name.chars().all(|c| c.is_ascii_digit()) { > >> + return Err(HostnameError::InvalidFormat); > >> + } > >> + > >> + Ok(Self(name.to_lowercase())) > > > > ...do we really want/need to do this? (Note that if we really do this, > > it should IMO be documented on the *type*, too, not just this method.) > > The idea was that, since hostnames are treated case-insensitively by > basically every application, it would make no sense to create two > *different* hostnames, that would be the same in practice. It's > something we could maybe move to a (Partial)Eq implementation and remove > the lowercasing here? > > > I mean, I'm not completely against it, but if we "normalize", would we > > not technically also have to punycode non-ascii hostnames? > > > > (But at the very least it seems that punycode does case-folding... at > > least a quick online-punycode conversion tool seems to convert both 'Ө' > > and 'ө' to 'xn--j6a') > > I see your point, but I decided to stick to what the installer allows > for hostnames, which is ASCII-only characters without doing any punycode > conversion (correct me if I'm wrong there, but I don't remember this > being the case). My main point is actually that this crate has a generic "network-types" name, which means someone may end up using it for *generic* code and suddenly things will fail. So I'd strongly suggest a `debian` submodule or something. _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel