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