[pve-devel] [PATCH installer 1/5] common: fqdn: do not allow overlong FQDNs as per Debian spec

Christoph Heiss c.heiss at proxmox.com
Thu Feb 15 13:39:34 CET 2024


Debian limits labels to 63 characters each and the total length to 253
characters [0].

While at it, reference all the RFCs that apply when parsing FQDNs.

[0] https://manpages.debian.org/stable/manpages/hostname.7.en.html

Signed-off-by: Christoph Heiss <c.heiss at proxmox.com>
---
 proxmox-installer-common/src/utils.rs | 45 ++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/proxmox-installer-common/src/utils.rs b/proxmox-installer-common/src/utils.rs
index c038524..067e025 100644
--- a/proxmox-installer-common/src/utils.rs
+++ b/proxmox-installer-common/src/utils.rs
@@ -117,6 +117,7 @@ pub enum FqdnParseError {
     MissingHostname,
     NumericHostname,
     InvalidPart(String),
+    TooLong(usize),
 }

 impl fmt::Display for FqdnParseError {
@@ -129,17 +130,46 @@ impl fmt::Display for FqdnParseError {
                 f,
                 "FQDN must only consist of alphanumeric characters and dashes. Invalid part: '{part}'",
             ),
+            TooLong(len) => write!(f, "FQDN too long: {len} > {}", Fqdn::MAX_LENGTH),
         }
     }
 }

+/// A type for safely representing fully-qualified domain names (FQDNs).
+///
+/// It considers following RFCs:
+/// https://www.ietf.org/rfc/rfc952.txt (sec. "ASSUMPTIONS", 1.)
+/// https://www.ietf.org/rfc/rfc1035.txt (sec. 2.3. "Conventions")
+/// https://www.ietf.org/rfc/rfc1123.txt (sec. 2.1. "Host Names and Numbers")
+/// https://www.ietf.org/rfc/rfc3492.txt
+/// https://www.ietf.org/rfc/rfc4343.txt
+///
+/// .. and applies some restriction given by Debian, e.g. 253 instead of 255
+/// maximum total length and maximum 63 characters per label.
+/// https://manpages.debian.org/stable/manpages/hostname.7.en.html
+///
+/// Additionally:
+/// - It enforces the restriction as per Bugzilla #1054, in that
+///   purely numeric hostnames are not allowed - against RFC1123 sec. 2.1.
+///
+/// Some terminology:
+/// - "label" - a single part of a FQDN, e.g. <label>.<label>.<tld>
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct Fqdn {
     parts: Vec<String>,
 }

 impl Fqdn {
+    /// Maximum length of a single label of the FQDN
+    const MAX_LABEL_LENGTH: usize = 63;
+    /// Maximum total length of the FQDN
+    const MAX_LENGTH: usize = 253;
+
     pub fn from(fqdn: &str) -> Result<Self, FqdnParseError> {
+        if fqdn.len() > Self::MAX_LENGTH {
+            return Err(FqdnParseError::TooLong(fqdn.len()));
+        }
+
         let parts = fqdn
             .split('.')
             .map(ToOwned::to_owned)
@@ -154,7 +184,8 @@ impl Fqdn {
         if parts.len() < 2 {
             Err(FqdnParseError::MissingHostname)
         } else if parts[0].chars().all(|c| c.is_ascii_digit()) {
-            // Not allowed/supported on Debian systems.
+            // Do not allow a purely numeric hostname, see:
+            // https://bugzilla.proxmox.com/show_bug.cgi?id=1054
             Err(FqdnParseError::NumericHostname)
         } else {
             Ok(Self { parts })
@@ -182,6 +213,7 @@ impl Fqdn {

     fn validate_single(s: &String) -> bool {
         !s.is_empty()
+            && s.len() <= Self::MAX_LABEL_LENGTH
             // First character must be alphanumeric
             && s.chars()
                 .next()
@@ -243,9 +275,20 @@ mod tests {
         assert_eq!(Fqdn::from("foo.com-"), Err(InvalidPart("com-".to_owned())));
         assert_eq!(Fqdn::from("-o-.com"), Err(InvalidPart("-o-".to_owned())));

+        // https://bugzilla.proxmox.com/show_bug.cgi?id=1054
         assert_eq!(Fqdn::from("123.com"), Err(NumericHostname));
         assert!(Fqdn::from("foo123.com").is_ok());
         assert!(Fqdn::from("123foo.com").is_ok());
+
+        assert!(Fqdn::from(&format!("{}.com", "a".repeat(63))).is_ok());
+        assert_eq!(
+            Fqdn::from(&format!("{}.com", "a".repeat(250))),
+            Err(TooLong(254)),
+        );
+        assert_eq!(
+            Fqdn::from(&format!("{}.com", "a".repeat(64))),
+            Err(InvalidPart("a".repeat(64))),
+        );
     }

     #[test]
--
2.43.0





More information about the pve-devel mailing list