rustls_pki_types/
server_name.rs

1//! DNS name validation according to RFC1035, but with underscores allowed.
2
3#[cfg(all(feature = "alloc", feature = "std"))]
4use alloc::borrow::Cow;
5#[cfg(feature = "alloc")]
6use alloc::string::{String, ToString};
7use core::hash::{Hash, Hasher};
8use core::{fmt, mem, str};
9#[cfg(feature = "std")]
10use std::error::Error as StdError;
11
12/// Encodes ways a client can know the expected name of the server.
13///
14/// This currently covers knowing the DNS name of the server, but
15/// will be extended in the future to supporting privacy-preserving names
16/// for the server ("ECH").  For this reason this enum is `non_exhaustive`.
17///
18/// # Making one
19///
20/// If you have a DNS name as a `&str`, this type implements `TryFrom<&str>`,
21/// so you can do:
22///
23/// ```
24/// # use rustls_pki_types::ServerName;
25/// ServerName::try_from("example.com").expect("invalid DNS name");
26/// ```
27///
28/// If you have an owned `String`, you can use `TryFrom` directly:
29///
30/// ```
31/// # use rustls_pki_types::ServerName;
32/// let name = "example.com".to_string();
33/// #[cfg(feature = "alloc")]
34/// ServerName::try_from(name).expect("invalid DNS name");
35/// ```
36///
37/// which will yield a `ServerName<'static>` if successful.
38///
39/// or, alternatively...
40///
41/// ```
42/// # use rustls_pki_types::ServerName;
43/// let x: ServerName = "example.com".try_into().expect("invalid DNS name");
44/// ```
45#[non_exhaustive]
46#[derive(Clone, Eq, Hash, PartialEq)]
47pub enum ServerName<'a> {
48    /// The server is identified by a DNS name.  The name
49    /// is sent in the TLS Server Name Indication (SNI)
50    /// extension.
51    DnsName(DnsName<'a>),
52
53    /// The server is identified by an IP address. SNI is not
54    /// done.
55    IpAddress(IpAddr),
56}
57
58impl ServerName<'_> {
59    /// Produce an owned `ServerName` from this (potentially borrowed) `ServerName`.
60    #[cfg(feature = "alloc")]
61    pub fn to_owned(&self) -> ServerName<'static> {
62        match self {
63            Self::DnsName(d) => ServerName::DnsName(d.to_owned()),
64            Self::IpAddress(i) => ServerName::IpAddress(*i),
65        }
66    }
67
68    /// Return the string representation of this `ServerName`.
69    ///
70    /// In the case of a `ServerName::DnsName` instance, this function returns a borrowed `str`.
71    /// For a `ServerName::IpAddress` instance it returns an allocated `String`.
72    #[cfg(feature = "std")]
73    pub fn to_str(&self) -> Cow<'_, str> {
74        match self {
75            Self::DnsName(d) => d.as_ref().into(),
76            Self::IpAddress(i) => std::net::IpAddr::from(*i).to_string().into(),
77        }
78    }
79}
80
81impl fmt::Debug for ServerName<'_> {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        match self {
84            Self::DnsName(d) => f.debug_tuple("DnsName").field(&d.as_ref()).finish(),
85            Self::IpAddress(i) => f.debug_tuple("IpAddress").field(i).finish(),
86        }
87    }
88}
89
90#[cfg(feature = "alloc")]
91impl TryFrom<String> for ServerName<'static> {
92    type Error = InvalidDnsNameError;
93
94    fn try_from(value: String) -> Result<Self, Self::Error> {
95        match DnsName::try_from_string(value) {
96            Ok(dns) => Ok(Self::DnsName(dns)),
97            Err(value) => match IpAddr::try_from(value.as_str()) {
98                Ok(ip) => Ok(Self::IpAddress(ip)),
99                Err(_) => Err(InvalidDnsNameError),
100            },
101        }
102    }
103}
104
105impl<'a> TryFrom<&'a [u8]> for ServerName<'a> {
106    type Error = InvalidDnsNameError;
107
108    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
109        match str::from_utf8(value) {
110            Ok(s) => Self::try_from(s),
111            Err(_) => Err(InvalidDnsNameError),
112        }
113    }
114}
115
116/// Attempt to make a ServerName from a string by parsing as a DNS name or IP address.
117impl<'a> TryFrom<&'a str> for ServerName<'a> {
118    type Error = InvalidDnsNameError;
119    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
120        match DnsName::try_from(s) {
121            Ok(dns) => Ok(Self::DnsName(dns)),
122            Err(InvalidDnsNameError) => match IpAddr::try_from(s) {
123                Ok(ip) => Ok(Self::IpAddress(ip)),
124                Err(_) => Err(InvalidDnsNameError),
125            },
126        }
127    }
128}
129
130impl From<IpAddr> for ServerName<'_> {
131    fn from(addr: IpAddr) -> Self {
132        Self::IpAddress(addr)
133    }
134}
135
136#[cfg(feature = "std")]
137impl From<std::net::IpAddr> for ServerName<'_> {
138    fn from(addr: std::net::IpAddr) -> Self {
139        Self::IpAddress(addr.into())
140    }
141}
142
143impl From<Ipv4Addr> for ServerName<'_> {
144    fn from(v4: Ipv4Addr) -> Self {
145        Self::IpAddress(IpAddr::V4(v4))
146    }
147}
148
149impl From<Ipv6Addr> for ServerName<'_> {
150    fn from(v6: Ipv6Addr) -> Self {
151        Self::IpAddress(IpAddr::V6(v6))
152    }
153}
154
155#[cfg(feature = "std")]
156impl From<std::net::Ipv4Addr> for ServerName<'_> {
157    fn from(v4: std::net::Ipv4Addr) -> Self {
158        Self::IpAddress(IpAddr::V4(v4.into()))
159    }
160}
161
162#[cfg(feature = "std")]
163impl From<std::net::Ipv6Addr> for ServerName<'_> {
164    fn from(v6: std::net::Ipv6Addr) -> Self {
165        Self::IpAddress(IpAddr::V6(v6.into()))
166    }
167}
168
169impl<'a> From<DnsName<'a>> for ServerName<'a> {
170    fn from(dns_name: DnsName<'a>) -> Self {
171        Self::DnsName(dns_name)
172    }
173}
174
175/// A type which encapsulates a string (borrowed or owned) that is a syntactically valid DNS name.
176#[derive(Clone, Debug, Eq, Hash, PartialEq)]
177pub struct DnsName<'a>(DnsNameInner<'a>);
178
179impl<'a> DnsName<'a> {
180    /// Produce a borrowed `DnsName` from this owned `DnsName`.
181    pub fn borrow(&'a self) -> Self {
182        Self(match self {
183            Self(DnsNameInner::Borrowed(s)) => DnsNameInner::Borrowed(s),
184            #[cfg(feature = "alloc")]
185            Self(DnsNameInner::Owned(s)) => DnsNameInner::Borrowed(s.as_str()),
186        })
187    }
188
189    /// Copy this object to produce an owned `DnsName`, smashing the case to lowercase
190    /// in one operation.
191    #[cfg(feature = "alloc")]
192    pub fn to_lowercase_owned(&self) -> DnsName<'static> {
193        DnsName(DnsNameInner::Owned(self.as_ref().to_ascii_lowercase()))
194    }
195
196    /// Produce an owned `DnsName` from this (potentially borrowed) `DnsName`.
197    #[cfg(feature = "alloc")]
198    pub fn to_owned(&self) -> DnsName<'static> {
199        DnsName(DnsNameInner::Owned(match self {
200            Self(DnsNameInner::Borrowed(s)) => s.to_string(),
201            #[cfg(feature = "alloc")]
202            Self(DnsNameInner::Owned(s)) => s.clone(),
203        }))
204    }
205
206    #[cfg(feature = "alloc")]
207    fn try_from_string(s: String) -> Result<Self, String> {
208        match validate(s.as_bytes()) {
209            Ok(_) => Ok(Self(DnsNameInner::Owned(s))),
210            Err(_) => Err(s),
211        }
212    }
213
214    /// Produces a borrowed [`DnsName`] from a borrowed [`str`].
215    pub const fn try_from_str(s: &str) -> Result<DnsName<'_>, InvalidDnsNameError> {
216        match validate(s.as_bytes()) {
217            Ok(_) => Ok(DnsName(DnsNameInner::Borrowed(s))),
218            Err(err) => Err(err),
219        }
220    }
221}
222
223#[cfg(feature = "alloc")]
224impl TryFrom<String> for DnsName<'static> {
225    type Error = InvalidDnsNameError;
226
227    fn try_from(value: String) -> Result<Self, Self::Error> {
228        Self::try_from_string(value).map_err(|_| InvalidDnsNameError)
229    }
230}
231
232impl<'a> TryFrom<&'a str> for DnsName<'a> {
233    type Error = InvalidDnsNameError;
234
235    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
236        DnsName::try_from_str(value)
237    }
238}
239
240impl<'a> TryFrom<&'a [u8]> for DnsName<'a> {
241    type Error = InvalidDnsNameError;
242
243    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
244        validate(value)?;
245        Ok(Self(DnsNameInner::Borrowed(str::from_utf8(value).unwrap())))
246    }
247}
248
249impl AsRef<str> for DnsName<'_> {
250    fn as_ref(&self) -> &str {
251        match self {
252            Self(DnsNameInner::Borrowed(s)) => s,
253            #[cfg(feature = "alloc")]
254            Self(DnsNameInner::Owned(s)) => s.as_str(),
255        }
256    }
257}
258
259#[derive(Clone, Eq)]
260enum DnsNameInner<'a> {
261    Borrowed(&'a str),
262    #[cfg(feature = "alloc")]
263    Owned(String),
264}
265
266impl PartialEq<Self> for DnsNameInner<'_> {
267    fn eq(&self, other: &Self) -> bool {
268        match (self, other) {
269            (Self::Borrowed(s), Self::Borrowed(o)) => s.eq_ignore_ascii_case(o),
270            #[cfg(feature = "alloc")]
271            (Self::Borrowed(s), Self::Owned(o)) => s.eq_ignore_ascii_case(o.as_str()),
272            #[cfg(feature = "alloc")]
273            (Self::Owned(s), Self::Borrowed(o)) => s.eq_ignore_ascii_case(o),
274            #[cfg(feature = "alloc")]
275            (Self::Owned(s), Self::Owned(o)) => s.eq_ignore_ascii_case(o.as_str()),
276        }
277    }
278}
279
280impl Hash for DnsNameInner<'_> {
281    fn hash<H: Hasher>(&self, state: &mut H) {
282        let s = match self {
283            Self::Borrowed(s) => s,
284            #[cfg(feature = "alloc")]
285            Self::Owned(s) => s.as_str(),
286        };
287
288        s.chars().for_each(|c| c.to_ascii_lowercase().hash(state));
289    }
290}
291
292impl fmt::Debug for DnsNameInner<'_> {
293    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294        match self {
295            Self::Borrowed(s) => f.write_fmt(format_args!("{s:?}")),
296            #[cfg(feature = "alloc")]
297            Self::Owned(s) => f.write_fmt(format_args!("{s:?}")),
298        }
299    }
300}
301
302/// The provided input could not be parsed because
303/// it is not a syntactically-valid DNS Name.
304#[allow(clippy::exhaustive_structs)]
305#[derive(Debug)]
306pub struct InvalidDnsNameError;
307
308impl fmt::Display for InvalidDnsNameError {
309    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310        f.write_str("invalid dns name")
311    }
312}
313
314#[cfg(feature = "std")]
315impl StdError for InvalidDnsNameError {}
316
317const fn validate(input: &[u8]) -> Result<(), InvalidDnsNameError> {
318    enum State {
319        Start,
320        Next,
321        NumericOnly { len: usize },
322        NextAfterNumericOnly,
323        Subsequent { len: usize },
324        Hyphen { len: usize },
325    }
326
327    use State::*;
328    let mut state = Start;
329
330    /// "Labels must be 63 characters or less."
331    const MAX_LABEL_LENGTH: usize = 63;
332
333    /// https://devblogs.microsoft.com/oldnewthing/20120412-00/?p=7873
334    const MAX_NAME_LENGTH: usize = 253;
335
336    if input.len() > MAX_NAME_LENGTH {
337        return Err(InvalidDnsNameError);
338    }
339
340    let mut idx = 0;
341    while idx < input.len() {
342        let ch = input[idx];
343        state = match (state, ch) {
344            (Start | Next | NextAfterNumericOnly | Hyphen { .. }, b'.') => {
345                return Err(InvalidDnsNameError);
346            }
347            (Subsequent { .. }, b'.') => Next,
348            (NumericOnly { .. }, b'.') => NextAfterNumericOnly,
349            (Subsequent { len } | NumericOnly { len } | Hyphen { len }, _)
350                if len >= MAX_LABEL_LENGTH =>
351            {
352                return Err(InvalidDnsNameError);
353            }
354            (Start | Next | NextAfterNumericOnly, b'0'..=b'9') => NumericOnly { len: 1 },
355            (NumericOnly { len }, b'0'..=b'9') => NumericOnly { len: len + 1 },
356            (Start | Next | NextAfterNumericOnly, b'a'..=b'z' | b'A'..=b'Z' | b'_') => {
357                Subsequent { len: 1 }
358            }
359            (Subsequent { len } | NumericOnly { len } | Hyphen { len }, b'-') => {
360                Hyphen { len: len + 1 }
361            }
362            (
363                Subsequent { len } | NumericOnly { len } | Hyphen { len },
364                b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'0'..=b'9',
365            ) => Subsequent { len: len + 1 },
366            _ => return Err(InvalidDnsNameError),
367        };
368        idx += 1;
369    }
370
371    if matches!(
372        state,
373        Start | Hyphen { .. } | NumericOnly { .. } | NextAfterNumericOnly
374    ) {
375        return Err(InvalidDnsNameError);
376    }
377
378    Ok(())
379}
380
381/// `no_std` implementation of `std::net::IpAddr`.
382///
383/// Note: because we intend to replace this type with `core::net::IpAddr` as soon as it is
384/// stabilized, the identity of this type should not be considered semver-stable. However, the
385/// attached interfaces are stable; they form a subset of those provided by `core::net::IpAddr`.
386#[allow(clippy::exhaustive_enums)]
387#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
388pub enum IpAddr {
389    /// An Ipv4 address.
390    V4(Ipv4Addr),
391    /// An Ipv6 address.
392    V6(Ipv6Addr),
393}
394
395impl TryFrom<&str> for IpAddr {
396    type Error = AddrParseError;
397
398    fn try_from(value: &str) -> Result<Self, Self::Error> {
399        match Ipv4Addr::try_from(value) {
400            Ok(v4) => Ok(Self::V4(v4)),
401            Err(_) => match Ipv6Addr::try_from(value) {
402                Ok(v6) => Ok(Self::V6(v6)),
403                Err(e) => Err(e),
404            },
405        }
406    }
407}
408
409#[cfg(feature = "std")]
410impl From<std::net::IpAddr> for IpAddr {
411    fn from(addr: std::net::IpAddr) -> Self {
412        match addr {
413            std::net::IpAddr::V4(v4) => Self::V4(v4.into()),
414            std::net::IpAddr::V6(v6) => Self::V6(v6.into()),
415        }
416    }
417}
418
419#[cfg(feature = "std")]
420impl From<IpAddr> for std::net::IpAddr {
421    fn from(value: IpAddr) -> Self {
422        match value {
423            IpAddr::V4(v4) => Self::from(std::net::Ipv4Addr::from(v4)),
424            IpAddr::V6(v6) => Self::from(std::net::Ipv6Addr::from(v6)),
425        }
426    }
427}
428
429#[cfg(feature = "std")]
430impl From<std::net::Ipv4Addr> for IpAddr {
431    fn from(v4: std::net::Ipv4Addr) -> Self {
432        Self::V4(v4.into())
433    }
434}
435
436#[cfg(feature = "std")]
437impl From<std::net::Ipv6Addr> for IpAddr {
438    fn from(v6: std::net::Ipv6Addr) -> Self {
439        Self::V6(v6.into())
440    }
441}
442
443/// `no_std` implementation of `std::net::Ipv4Addr`.
444///
445/// Note: because we intend to replace this type with `core::net::Ipv4Addr` as soon as it is
446/// stabilized, the identity of this type should not be considered semver-stable. However, the
447/// attached interfaces are stable; they form a subset of those provided by `core::net::Ipv4Addr`.
448#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
449pub struct Ipv4Addr([u8; 4]);
450
451impl From<[u8; 4]> for Ipv4Addr {
452    fn from(value: [u8; 4]) -> Self {
453        Self(value)
454    }
455}
456
457impl TryFrom<&str> for Ipv4Addr {
458    type Error = AddrParseError;
459
460    fn try_from(value: &str) -> Result<Self, Self::Error> {
461        // don't try to parse if too long
462        if value.len() > 15 {
463            Err(AddrParseError(AddrKind::Ipv4))
464        } else {
465            Parser::new(value.as_bytes()).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
466        }
467    }
468}
469
470#[cfg(feature = "std")]
471impl From<std::net::Ipv4Addr> for Ipv4Addr {
472    fn from(addr: std::net::Ipv4Addr) -> Self {
473        Self(addr.octets())
474    }
475}
476
477#[cfg(feature = "std")]
478impl From<Ipv4Addr> for std::net::Ipv4Addr {
479    fn from(value: Ipv4Addr) -> Self {
480        Self::from(value.0)
481    }
482}
483
484impl AsRef<[u8; 4]> for Ipv4Addr {
485    fn as_ref(&self) -> &[u8; 4] {
486        &self.0
487    }
488}
489
490/// `no_std` implementation of `std::net::Ipv6Addr`.
491///
492/// Note: because we intend to replace this type with `core::net::Ipv6Addr` as soon as it is
493/// stabilized, the identity of this type should not be considered semver-stable. However, the
494/// attached interfaces are stable; they form a subset of those provided by `core::net::Ipv6Addr`.
495#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
496pub struct Ipv6Addr([u8; 16]);
497
498impl TryFrom<&str> for Ipv6Addr {
499    type Error = AddrParseError;
500
501    fn try_from(value: &str) -> Result<Self, Self::Error> {
502        Parser::new(value.as_bytes()).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
503    }
504}
505
506impl From<[u16; 8]> for Ipv6Addr {
507    fn from(value: [u16; 8]) -> Self {
508        // Adapted from `std::net::Ipv6Addr::new()`
509        let addr16 = [
510            value[0].to_be(),
511            value[1].to_be(),
512            value[2].to_be(),
513            value[3].to_be(),
514            value[4].to_be(),
515            value[5].to_be(),
516            value[6].to_be(),
517            value[7].to_be(),
518        ];
519        Self(
520            // All elements in `addr16` are big endian.
521            // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
522            unsafe { mem::transmute::<[u16; 8], [u8; 16]>(addr16) },
523        )
524    }
525}
526
527#[cfg(feature = "std")]
528impl From<std::net::Ipv6Addr> for Ipv6Addr {
529    fn from(addr: std::net::Ipv6Addr) -> Self {
530        Self(addr.octets())
531    }
532}
533
534#[cfg(feature = "std")]
535impl From<Ipv6Addr> for std::net::Ipv6Addr {
536    fn from(value: Ipv6Addr) -> Self {
537        Self::from(value.0)
538    }
539}
540
541impl AsRef<[u8; 16]> for Ipv6Addr {
542    fn as_ref(&self) -> &[u8; 16] {
543        &self.0
544    }
545}
546
547// Adapted from core, 2023-11-23
548//
549// https://github.com/rust-lang/rust/blob/fc13ca6d70f7381513c22443fc5aaee1d151ea45/library/core/src/net/parser.rs#L34
550mod parser {
551    use super::{AddrParseError, Ipv4Addr, Ipv6Addr};
552
553    pub(super) struct Parser<'a> {
554        // Parsing as ASCII, so can use byte array.
555        state: &'a [u8],
556    }
557
558    impl<'a> Parser<'a> {
559        pub(super) const fn new(input: &'a [u8]) -> Self {
560            Parser { state: input }
561        }
562
563        /// Run a parser, and restore the pre-parse state if it fails.
564        fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
565        where
566            F: FnOnce(&mut Parser<'_>) -> Option<T>,
567        {
568            let state = self.state;
569            let result = inner(self);
570            if result.is_none() {
571                self.state = state;
572            }
573            result
574        }
575
576        /// Run a parser, but fail if the entire input wasn't consumed.
577        /// Doesn't run atomically.
578        pub(super) fn parse_with<T, F>(
579            &mut self,
580            inner: F,
581            kind: AddrKind,
582        ) -> Result<T, AddrParseError>
583        where
584            F: FnOnce(&mut Parser<'_>) -> Option<T>,
585        {
586            let result = inner(self);
587            if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind))
588        }
589
590        /// Peek the next character from the input
591        fn peek_char(&self) -> Option<char> {
592            self.state.first().map(|&b| char::from(b))
593        }
594
595        /// Read the next character from the input
596        fn read_char(&mut self) -> Option<char> {
597            self.state.split_first().map(|(&b, tail)| {
598                self.state = tail;
599                char::from(b)
600            })
601        }
602
603        #[must_use]
604        /// Read the next character from the input if it matches the target.
605        fn read_given_char(&mut self, target: char) -> Option<()> {
606            self.read_atomically(|p| {
607                p.read_char()
608                    .and_then(|c| if c == target { Some(()) } else { None })
609            })
610        }
611
612        /// Helper for reading separators in an indexed loop. Reads the separator
613        /// character iff index > 0, then runs the parser. When used in a loop,
614        /// the separator character will only be read on index > 0 (see
615        /// read_ipv4_addr for an example)
616        fn read_separator<T, F>(&mut self, sep: char, index: usize, inner: F) -> Option<T>
617        where
618            F: FnOnce(&mut Parser<'_>) -> Option<T>,
619        {
620            self.read_atomically(move |p| {
621                if index > 0 {
622                    p.read_given_char(sep)?;
623                }
624                inner(p)
625            })
626        }
627
628        // Read a number off the front of the input in the given radix, stopping
629        // at the first non-digit character or eof. Fails if the number has more
630        // digits than max_digits or if there is no number.
631        fn read_number<T: ReadNumberHelper>(
632            &mut self,
633            radix: u32,
634            max_digits: Option<usize>,
635            allow_zero_prefix: bool,
636        ) -> Option<T> {
637            self.read_atomically(move |p| {
638                let mut result = T::ZERO;
639                let mut digit_count = 0;
640                let has_leading_zero = p.peek_char() == Some('0');
641
642                while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
643                    result = result.checked_mul(radix)?;
644                    result = result.checked_add(digit)?;
645                    digit_count += 1;
646                    if let Some(max_digits) = max_digits {
647                        if digit_count > max_digits {
648                            return None;
649                        }
650                    }
651                }
652
653                if digit_count == 0 || (!allow_zero_prefix && has_leading_zero && digit_count > 1) {
654                    None
655                } else {
656                    Some(result)
657                }
658            })
659        }
660
661        /// Read an IPv4 address.
662        pub(super) fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
663            self.read_atomically(|p| {
664                let mut groups = [0; 4];
665
666                for (i, slot) in groups.iter_mut().enumerate() {
667                    *slot = p.read_separator('.', i, |p| {
668                        // Disallow octal number in IP string.
669                        // https://tools.ietf.org/html/rfc6943#section-3.1.1
670                        p.read_number(10, Some(3), false)
671                    })?;
672                }
673
674                Some(Ipv4Addr(groups))
675            })
676        }
677
678        /// Read an IPv6 Address.
679        pub(super) fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
680            /// Read a chunk of an IPv6 address into `groups`. Returns the number
681            /// of groups read, along with a bool indicating if an embedded
682            /// trailing IPv4 address was read. Specifically, read a series of
683            /// colon-separated IPv6 groups (0x0000 - 0xFFFF), with an optional
684            /// trailing embedded IPv4 address.
685            fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) {
686                let limit = groups.len();
687
688                for (i, slot) in groups.iter_mut().enumerate() {
689                    // Try to read a trailing embedded IPv4 address. There must be
690                    // at least two groups left.
691                    if i < limit - 1 {
692                        let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr());
693
694                        if let Some(v4_addr) = ipv4 {
695                            let [one, two, three, four] = v4_addr.0;
696                            groups[i] = u16::from_be_bytes([one, two]);
697                            groups[i + 1] = u16::from_be_bytes([three, four]);
698                            return (i + 2, true);
699                        }
700                    }
701
702                    let group = p.read_separator(':', i, |p| p.read_number(16, Some(4), true));
703
704                    match group {
705                        Some(g) => *slot = g,
706                        None => return (i, false),
707                    }
708                }
709                (groups.len(), false)
710            }
711
712            self.read_atomically(|p| {
713                // Read the front part of the address; either the whole thing, or up
714                // to the first ::
715                let mut head = [0; 8];
716                let (head_size, head_ipv4) = read_groups(p, &mut head);
717
718                if head_size == 8 {
719                    return Some(head.into());
720                }
721
722                // IPv4 part is not allowed before `::`
723                if head_ipv4 {
724                    return None;
725                }
726
727                // Read `::` if previous code parsed less than 8 groups.
728                // `::` indicates one or more groups of 16 bits of zeros.
729                p.read_given_char(':')?;
730                p.read_given_char(':')?;
731
732                // Read the back part of the address. The :: must contain at least one
733                // set of zeroes, so our max length is 7.
734                let mut tail = [0; 7];
735                let limit = 8 - (head_size + 1);
736                let (tail_size, _) = read_groups(p, &mut tail[..limit]);
737
738                // Concat the head and tail of the IP address
739                head[(8 - tail_size)..8].copy_from_slice(&tail[..tail_size]);
740
741                Some(head.into())
742            })
743        }
744    }
745
746    trait ReadNumberHelper: Sized {
747        const ZERO: Self;
748        fn checked_mul(&self, other: u32) -> Option<Self>;
749        fn checked_add(&self, other: u32) -> Option<Self>;
750    }
751
752    macro_rules! impl_helper {
753        ($($t:ty)*) => ($(impl ReadNumberHelper for $t {
754            const ZERO: Self = 0;
755            #[inline]
756            fn checked_mul(&self, other: u32) -> Option<Self> {
757                Self::checked_mul(*self, other.try_into().ok()?)
758            }
759            #[inline]
760            fn checked_add(&self, other: u32) -> Option<Self> {
761                Self::checked_add(*self, other.try_into().ok()?)
762            }
763        })*)
764    }
765
766    impl_helper! { u8 u16 u32 }
767
768    #[derive(Debug, Clone, Copy, Eq, PartialEq)]
769    pub(super) enum AddrKind {
770        Ipv4,
771        Ipv6,
772    }
773}
774
775use parser::{AddrKind, Parser};
776
777/// Failure to parse an IP address
778#[derive(Debug, Clone, Copy, Eq, PartialEq)]
779pub struct AddrParseError(AddrKind);
780
781impl fmt::Display for AddrParseError {
782    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
783        f.write_str(match self.0 {
784            AddrKind::Ipv4 => "invalid IPv4 address syntax",
785            AddrKind::Ipv6 => "invalid IPv6 address syntax",
786        })
787    }
788}
789
790#[cfg(feature = "std")]
791impl ::std::error::Error for AddrParseError {}
792
793#[cfg(test)]
794mod tests {
795    use super::*;
796    #[cfg(feature = "alloc")]
797    use alloc::format;
798
799    #[cfg(feature = "alloc")]
800    static TESTS: &[(&str, bool)] = &[
801        ("", false),
802        ("localhost", true),
803        ("LOCALHOST", true),
804        (".localhost", false),
805        ("..localhost", false),
806        ("1.2.3.4", false),
807        ("127.0.0.1", false),
808        ("absolute.", true),
809        ("absolute..", false),
810        ("multiple.labels.absolute.", true),
811        ("foo.bar.com", true),
812        ("infix-hyphen-allowed.com", true),
813        ("-prefixhypheninvalid.com", false),
814        ("suffixhypheninvalid--", false),
815        ("suffixhypheninvalid-.com", false),
816        ("foo.lastlabelendswithhyphen-", false),
817        ("infix_underscore_allowed.com", true),
818        ("_prefixunderscorevalid.com", true),
819        ("labelendswithnumber1.bar.com", true),
820        ("xn--bcher-kva.example", true),
821        (
822            "sixtythreesixtythreesixtythreesixtythreesixtythreesixtythreesix.com",
823            true,
824        ),
825        (
826            "sixtyfoursixtyfoursixtyfoursixtyfoursixtyfoursixtyfoursixtyfours.com",
827            false,
828        ),
829        (
830            "012345678901234567890123456789012345678901234567890123456789012.com",
831            true,
832        ),
833        (
834            "0123456789012345678901234567890123456789012345678901234567890123.com",
835            false,
836        ),
837        (
838            "01234567890123456789012345678901234567890123456789012345678901-.com",
839            false,
840        ),
841        (
842            "012345678901234567890123456789012345678901234567890123456789012-.com",
843            false,
844        ),
845        ("numeric-only-final-label.1", false),
846        ("numeric-only-final-label.absolute.1.", false),
847        ("1starts-with-number.com", true),
848        ("1Starts-with-number.com", true),
849        ("1.2.3.4.com", true),
850        ("123.numeric-only-first-label", true),
851        ("a123b.com", true),
852        ("numeric-only-middle-label.4.com", true),
853        ("1000-sans.badssl.com", true),
854        (
855            "twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfi",
856            true,
857        ),
858        (
859            "twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourc",
860            false,
861        ),
862    ];
863
864    #[cfg(feature = "alloc")]
865    #[test]
866    fn test_validation() {
867        for (input, expected) in TESTS {
868            #[cfg(feature = "std")]
869            println!("test: {input:?} expected valid? {expected:?}");
870            let name_ref = DnsName::try_from(*input);
871            assert_eq!(*expected, name_ref.is_ok());
872            let name = DnsName::try_from(input.to_string());
873            assert_eq!(*expected, name.is_ok());
874        }
875    }
876
877    #[cfg(feature = "alloc")]
878    #[test]
879    fn error_is_debug() {
880        assert_eq!(format!("{InvalidDnsNameError:?}"), "InvalidDnsNameError");
881    }
882
883    #[cfg(feature = "alloc")]
884    #[test]
885    fn error_is_display() {
886        assert_eq!(format!("{InvalidDnsNameError}"), "invalid dns name");
887    }
888
889    #[cfg(feature = "alloc")]
890    #[test]
891    fn dns_name_is_debug() {
892        let example = DnsName::try_from("example.com".to_string()).unwrap();
893        assert_eq!(format!("{example:?}"), "DnsName(\"example.com\")");
894    }
895
896    #[cfg(feature = "alloc")]
897    #[test]
898    fn dns_name_traits() {
899        let example = DnsName::try_from("example.com".to_string()).unwrap();
900        assert_eq!(example, example); // PartialEq
901
902        #[cfg(feature = "std")]
903        {
904            use std::collections::HashSet;
905            let mut h = HashSet::<DnsName<'_>>::new();
906            h.insert(example);
907        }
908    }
909
910    #[cfg(feature = "alloc")]
911    #[test]
912    fn try_from_ascii_rejects_bad_utf8() {
913        assert_eq!(
914            format!("{:?}", DnsName::try_from(&b"\x80"[..])),
915            "Err(InvalidDnsNameError)"
916        );
917    }
918
919    const fn ipv4_address(
920        ip_address: &str,
921        octets: [u8; 4],
922    ) -> (&str, Result<Ipv4Addr, AddrParseError>) {
923        (ip_address, Ok(Ipv4Addr(octets)))
924    }
925
926    const IPV4_ADDRESSES: &[(&str, Result<Ipv4Addr, AddrParseError>)] = &[
927        // Valid IPv4 addresses
928        ipv4_address("0.0.0.0", [0, 0, 0, 0]),
929        ipv4_address("1.1.1.1", [1, 1, 1, 1]),
930        ipv4_address("205.0.0.0", [205, 0, 0, 0]),
931        ipv4_address("0.205.0.0", [0, 205, 0, 0]),
932        ipv4_address("0.0.205.0", [0, 0, 205, 0]),
933        ipv4_address("0.0.0.205", [0, 0, 0, 205]),
934        ipv4_address("0.0.0.20", [0, 0, 0, 20]),
935        // Invalid IPv4 addresses
936        ("", Err(AddrParseError(AddrKind::Ipv4))),
937        ("...", Err(AddrParseError(AddrKind::Ipv4))),
938        (".0.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
939        ("0.0.0.0.", Err(AddrParseError(AddrKind::Ipv4))),
940        ("0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
941        ("0.0.0.", Err(AddrParseError(AddrKind::Ipv4))),
942        ("256.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
943        ("0.256.0.0", Err(AddrParseError(AddrKind::Ipv4))),
944        ("0.0.256.0", Err(AddrParseError(AddrKind::Ipv4))),
945        ("0.0.0.256", Err(AddrParseError(AddrKind::Ipv4))),
946        ("1..1.1.1", Err(AddrParseError(AddrKind::Ipv4))),
947        ("1.1..1.1", Err(AddrParseError(AddrKind::Ipv4))),
948        ("1.1.1..1", Err(AddrParseError(AddrKind::Ipv4))),
949        ("025.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
950        ("0.025.0.0", Err(AddrParseError(AddrKind::Ipv4))),
951        ("0.0.025.0", Err(AddrParseError(AddrKind::Ipv4))),
952        ("0.0.0.025", Err(AddrParseError(AddrKind::Ipv4))),
953        ("1234.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
954        ("0.1234.0.0", Err(AddrParseError(AddrKind::Ipv4))),
955        ("0.0.1234.0", Err(AddrParseError(AddrKind::Ipv4))),
956        ("0.0.0.1234", Err(AddrParseError(AddrKind::Ipv4))),
957    ];
958
959    #[test]
960    fn parse_ipv4_address_test() {
961        for &(ip_address, expected_result) in IPV4_ADDRESSES {
962            assert_eq!(Ipv4Addr::try_from(ip_address), expected_result);
963        }
964    }
965
966    const fn ipv6_address(
967        ip_address: &str,
968        octets: [u8; 16],
969    ) -> (&str, Result<Ipv6Addr, AddrParseError>) {
970        (ip_address, Ok(Ipv6Addr(octets)))
971    }
972
973    const IPV6_ADDRESSES: &[(&str, Result<Ipv6Addr, AddrParseError>)] = &[
974        // Valid IPv6 addresses
975        ipv6_address(
976            "2a05:d018:076c:b685:e8ab:afd3:af51:3aed",
977            [
978                0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
979                0x3a, 0xed,
980            ],
981        ),
982        ipv6_address(
983            "2A05:D018:076C:B685:E8AB:AFD3:AF51:3AED",
984            [
985                0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
986                0x3a, 0xed,
987            ],
988        ),
989        ipv6_address(
990            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
991            [
992                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
993                0xff, 0xff,
994            ],
995        ),
996        ipv6_address(
997            "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
998            [
999                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1000                0xff, 0xff,
1001            ],
1002        ),
1003        ipv6_address(
1004            "FFFF:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1005            [
1006                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1007                0xff, 0xff,
1008            ],
1009        ),
1010        // Wrong hexadecimal characters on different positions
1011        (
1012            "ffgf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1013            Err(AddrParseError(AddrKind::Ipv6)),
1014        ),
1015        (
1016            "ffff:gfff:ffff:ffff:ffff:ffff:ffff:ffff",
1017            Err(AddrParseError(AddrKind::Ipv6)),
1018        ),
1019        (
1020            "ffff:ffff:fffg:ffff:ffff:ffff:ffff:ffff",
1021            Err(AddrParseError(AddrKind::Ipv6)),
1022        ),
1023        (
1024            "ffff:ffff:ffff:ffgf:ffff:ffff:ffff:ffff",
1025            Err(AddrParseError(AddrKind::Ipv6)),
1026        ),
1027        (
1028            "ffff:ffff:ffff:ffff:gfff:ffff:ffff:ffff",
1029            Err(AddrParseError(AddrKind::Ipv6)),
1030        ),
1031        (
1032            "ffff:ffff:ffff:ffff:ffff:fgff:ffff:ffff",
1033            Err(AddrParseError(AddrKind::Ipv6)),
1034        ),
1035        (
1036            "ffff:ffff:ffff:ffff:ffff:ffff:ffgf:ffff",
1037            Err(AddrParseError(AddrKind::Ipv6)),
1038        ),
1039        (
1040            "ffff:ffff:ffff:ffff:ffff:ffff:ffgf:fffg",
1041            Err(AddrParseError(AddrKind::Ipv6)),
1042        ),
1043        // Wrong colons on uncompressed addresses
1044        (
1045            ":ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1046            Err(AddrParseError(AddrKind::Ipv6)),
1047        ),
1048        (
1049            "ffff::ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1050            Err(AddrParseError(AddrKind::Ipv6)),
1051        ),
1052        (
1053            "ffff:ffff::ffff:ffff:ffff:ffff:ffff:ffff",
1054            Err(AddrParseError(AddrKind::Ipv6)),
1055        ),
1056        (
1057            "ffff:ffff:ffff::ffff:ffff:ffff:ffff:ffff",
1058            Err(AddrParseError(AddrKind::Ipv6)),
1059        ),
1060        (
1061            "ffff:ffff:ffff:ffff::ffff:ffff:ffff:ffff",
1062            Err(AddrParseError(AddrKind::Ipv6)),
1063        ),
1064        (
1065            "ffff:ffff:ffff:ffff:ffff::ffff:ffff:ffff",
1066            Err(AddrParseError(AddrKind::Ipv6)),
1067        ),
1068        (
1069            "ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff",
1070            Err(AddrParseError(AddrKind::Ipv6)),
1071        ),
1072        (
1073            "ffff:ffff:ffff:ffff:ffff:ffff:ffff::ffff",
1074            Err(AddrParseError(AddrKind::Ipv6)),
1075        ),
1076        // More colons than allowed
1077        (
1078            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:",
1079            Err(AddrParseError(AddrKind::Ipv6)),
1080        ),
1081        (
1082            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1083            Err(AddrParseError(AddrKind::Ipv6)),
1084        ),
1085        // v Invalid hexadecimal
1086        (
1087            "ga05:d018:076c:b685:e8ab:afd3:af51:3aed",
1088            Err(AddrParseError(AddrKind::Ipv6)),
1089        ),
1090        // Cannot start with colon
1091        (
1092            ":a05:d018:076c:b685:e8ab:afd3:af51:3aed",
1093            Err(AddrParseError(AddrKind::Ipv6)),
1094        ),
1095        // Cannot end with colon
1096        (
1097            "2a05:d018:076c:b685:e8ab:afd3:af51:3ae:",
1098            Err(AddrParseError(AddrKind::Ipv6)),
1099        ),
1100        // Cannot have more than seven colons
1101        (
1102            "2a05:d018:076c:b685:e8ab:afd3:af51:3a::",
1103            Err(AddrParseError(AddrKind::Ipv6)),
1104        ),
1105        // Cannot contain two colons in a row
1106        (
1107            "2a05::018:076c:b685:e8ab:afd3:af51:3aed",
1108            Err(AddrParseError(AddrKind::Ipv6)),
1109        ),
1110        // v Textual block size is longer
1111        (
1112            "2a056:d018:076c:b685:e8ab:afd3:af51:3ae",
1113            Err(AddrParseError(AddrKind::Ipv6)),
1114        ),
1115        // v Textual block size is shorter
1116        (
1117            "2a0:d018:076c:b685:e8ab:afd3:af51:3aed ",
1118            Err(AddrParseError(AddrKind::Ipv6)),
1119        ),
1120        // Shorter IPv6 address
1121        (
1122            "d018:076c:b685:e8ab:afd3:af51:3aed",
1123            Err(AddrParseError(AddrKind::Ipv6)),
1124        ),
1125        // Longer IPv6 address
1126        (
1127            "2a05:d018:076c:b685:e8ab:afd3:af51:3aed3aed",
1128            Err(AddrParseError(AddrKind::Ipv6)),
1129        ),
1130    ];
1131
1132    #[test]
1133    fn parse_ipv6_address_test() {
1134        for &(ip_address, expected_result) in IPV6_ADDRESSES {
1135            assert_eq!(Ipv6Addr::try_from(ip_address), expected_result);
1136        }
1137    }
1138
1139    #[test]
1140    fn try_from_ascii_ip_address_test() {
1141        const IP_ADDRESSES: &[(&str, Result<IpAddr, AddrParseError>)] = &[
1142            // Valid IPv4 addresses
1143            ("127.0.0.1", Ok(IpAddr::V4(Ipv4Addr([127, 0, 0, 1])))),
1144            // Invalid IPv4 addresses
1145            (
1146                // Ends with a dot; misses one octet
1147                "127.0.0.",
1148                Err(AddrParseError(AddrKind::Ipv6)),
1149            ),
1150            // Valid IPv6 addresses
1151            (
1152                "0000:0000:0000:0000:0000:0000:0000:0001",
1153                Ok(IpAddr::V6(Ipv6Addr([
1154                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1155                ]))),
1156            ),
1157            // Something else
1158            (
1159                // A hostname
1160                "example.com",
1161                Err(AddrParseError(AddrKind::Ipv6)),
1162            ),
1163        ];
1164        for &(ip_address, expected_result) in IP_ADDRESSES {
1165            assert_eq!(IpAddr::try_from(ip_address), expected_result)
1166        }
1167    }
1168
1169    #[test]
1170    fn try_from_ascii_str_ip_address_test() {
1171        const IP_ADDRESSES: &[(&str, Result<IpAddr, AddrParseError>)] = &[
1172            // Valid IPv4 addresses
1173            ("127.0.0.1", Ok(IpAddr::V4(Ipv4Addr([127, 0, 0, 1])))),
1174            // Invalid IPv4 addresses
1175            (
1176                // Ends with a dot; misses one octet
1177                "127.0.0.",
1178                Err(AddrParseError(AddrKind::Ipv6)),
1179            ),
1180            // Valid IPv6 addresses
1181            (
1182                "0000:0000:0000:0000:0000:0000:0000:0001",
1183                Ok(IpAddr::V6(Ipv6Addr([
1184                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1185                ]))),
1186            ),
1187            // Something else
1188            (
1189                // A hostname
1190                "example.com",
1191                Err(AddrParseError(AddrKind::Ipv6)),
1192            ),
1193        ];
1194        for &(ip_address, expected_result) in IP_ADDRESSES {
1195            assert_eq!(IpAddr::try_from(ip_address), expected_result)
1196        }
1197    }
1198
1199    #[test]
1200    #[cfg(feature = "std")]
1201    fn to_str() {
1202        let domain_str = "example.com";
1203        let domain_servername = ServerName::try_from(domain_str).unwrap();
1204        assert_eq!(domain_str, domain_servername.to_str());
1205
1206        let ipv4_str = "127.0.0.1";
1207        let ipv4_servername = ServerName::try_from("127.0.0.1").unwrap();
1208        assert_eq!(ipv4_str, ipv4_servername.to_str());
1209
1210        let ipv6_str = "::1";
1211        let ipv6_servername = ServerName::try_from(ipv6_str).unwrap();
1212        assert_eq!("::1", ipv6_servername.to_str());
1213    }
1214}