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        (
841            "twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfiftythreecharacters.twohundredandfi",
842            true,
843        ),
844        (
845            "twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourcharacters.twohundredandfiftyfourc",
846            false,
847        ),
848    ];
849
850    #[cfg(feature = "alloc")]
851    #[test]
852    fn test_validation() {
853        for (input, expected) in TESTS {
854            #[cfg(feature = "std")]
855            println!("test: {:?} expected valid? {:?}", input, expected);
856            let name_ref = DnsName::try_from(*input);
857            assert_eq!(*expected, name_ref.is_ok());
858            let name = DnsName::try_from(input.to_string());
859            assert_eq!(*expected, name.is_ok());
860        }
861    }
862
863    #[cfg(feature = "alloc")]
864    #[test]
865    fn error_is_debug() {
866        assert_eq!(format!("{:?}", InvalidDnsNameError), "InvalidDnsNameError");
867    }
868
869    #[cfg(feature = "alloc")]
870    #[test]
871    fn error_is_display() {
872        assert_eq!(format!("{}", InvalidDnsNameError), "invalid dns name");
873    }
874
875    #[cfg(feature = "alloc")]
876    #[test]
877    fn dns_name_is_debug() {
878        let example = DnsName::try_from("example.com".to_string()).unwrap();
879        assert_eq!(format!("{:?}", example), "DnsName(\"example.com\")");
880    }
881
882    #[cfg(feature = "alloc")]
883    #[test]
884    fn dns_name_traits() {
885        let example = DnsName::try_from("example.com".to_string()).unwrap();
886        assert_eq!(example, example); // PartialEq
887
888        #[cfg(feature = "std")]
889        {
890            use std::collections::HashSet;
891            let mut h = HashSet::<DnsName>::new();
892            h.insert(example);
893        }
894    }
895
896    #[cfg(feature = "alloc")]
897    #[test]
898    fn try_from_ascii_rejects_bad_utf8() {
899        assert_eq!(
900            format!("{:?}", DnsName::try_from(&b"\x80"[..])),
901            "Err(InvalidDnsNameError)"
902        );
903    }
904
905    const fn ipv4_address(
906        ip_address: &str,
907        octets: [u8; 4],
908    ) -> (&str, Result<Ipv4Addr, AddrParseError>) {
909        (ip_address, Ok(Ipv4Addr(octets)))
910    }
911
912    const IPV4_ADDRESSES: &[(&str, Result<Ipv4Addr, AddrParseError>)] = &[
913        // Valid IPv4 addresses
914        ipv4_address("0.0.0.0", [0, 0, 0, 0]),
915        ipv4_address("1.1.1.1", [1, 1, 1, 1]),
916        ipv4_address("205.0.0.0", [205, 0, 0, 0]),
917        ipv4_address("0.205.0.0", [0, 205, 0, 0]),
918        ipv4_address("0.0.205.0", [0, 0, 205, 0]),
919        ipv4_address("0.0.0.205", [0, 0, 0, 205]),
920        ipv4_address("0.0.0.20", [0, 0, 0, 20]),
921        // Invalid IPv4 addresses
922        ("", Err(AddrParseError(AddrKind::Ipv4))),
923        ("...", Err(AddrParseError(AddrKind::Ipv4))),
924        (".0.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
925        ("0.0.0.0.", Err(AddrParseError(AddrKind::Ipv4))),
926        ("0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
927        ("0.0.0.", Err(AddrParseError(AddrKind::Ipv4))),
928        ("256.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
929        ("0.256.0.0", Err(AddrParseError(AddrKind::Ipv4))),
930        ("0.0.256.0", Err(AddrParseError(AddrKind::Ipv4))),
931        ("0.0.0.256", Err(AddrParseError(AddrKind::Ipv4))),
932        ("1..1.1.1", Err(AddrParseError(AddrKind::Ipv4))),
933        ("1.1..1.1", Err(AddrParseError(AddrKind::Ipv4))),
934        ("1.1.1..1", Err(AddrParseError(AddrKind::Ipv4))),
935        ("025.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
936        ("0.025.0.0", Err(AddrParseError(AddrKind::Ipv4))),
937        ("0.0.025.0", Err(AddrParseError(AddrKind::Ipv4))),
938        ("0.0.0.025", Err(AddrParseError(AddrKind::Ipv4))),
939        ("1234.0.0.0", Err(AddrParseError(AddrKind::Ipv4))),
940        ("0.1234.0.0", Err(AddrParseError(AddrKind::Ipv4))),
941        ("0.0.1234.0", Err(AddrParseError(AddrKind::Ipv4))),
942        ("0.0.0.1234", Err(AddrParseError(AddrKind::Ipv4))),
943    ];
944
945    #[test]
946    fn parse_ipv4_address_test() {
947        for &(ip_address, expected_result) in IPV4_ADDRESSES {
948            assert_eq!(Ipv4Addr::try_from(ip_address), expected_result);
949        }
950    }
951
952    const fn ipv6_address(
953        ip_address: &str,
954        octets: [u8; 16],
955    ) -> (&str, Result<Ipv6Addr, AddrParseError>) {
956        (ip_address, Ok(Ipv6Addr(octets)))
957    }
958
959    const IPV6_ADDRESSES: &[(&str, Result<Ipv6Addr, AddrParseError>)] = &[
960        // Valid IPv6 addresses
961        ipv6_address(
962            "2a05:d018:076c:b685:e8ab:afd3:af51:3aed",
963            [
964                0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
965                0x3a, 0xed,
966            ],
967        ),
968        ipv6_address(
969            "2A05:D018:076C:B685:E8AB:AFD3:AF51:3AED",
970            [
971                0x2a, 0x05, 0xd0, 0x18, 0x07, 0x6c, 0xb6, 0x85, 0xe8, 0xab, 0xaf, 0xd3, 0xaf, 0x51,
972                0x3a, 0xed,
973            ],
974        ),
975        ipv6_address(
976            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
977            [
978                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
979                0xff, 0xff,
980            ],
981        ),
982        ipv6_address(
983            "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
984            [
985                0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
986                0xff, 0xff,
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        // Wrong hexadecimal characters on different positions
997        (
998            "ffgf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
999            Err(AddrParseError(AddrKind::Ipv6)),
1000        ),
1001        (
1002            "ffff:gfff:ffff:ffff:ffff:ffff:ffff:ffff",
1003            Err(AddrParseError(AddrKind::Ipv6)),
1004        ),
1005        (
1006            "ffff:ffff:fffg:ffff:ffff:ffff:ffff:ffff",
1007            Err(AddrParseError(AddrKind::Ipv6)),
1008        ),
1009        (
1010            "ffff:ffff:ffff:ffgf:ffff:ffff:ffff:ffff",
1011            Err(AddrParseError(AddrKind::Ipv6)),
1012        ),
1013        (
1014            "ffff:ffff:ffff:ffff:gfff:ffff:ffff:ffff",
1015            Err(AddrParseError(AddrKind::Ipv6)),
1016        ),
1017        (
1018            "ffff:ffff:ffff:ffff:ffff:fgff:ffff:ffff",
1019            Err(AddrParseError(AddrKind::Ipv6)),
1020        ),
1021        (
1022            "ffff:ffff:ffff:ffff:ffff:ffff:ffgf:ffff",
1023            Err(AddrParseError(AddrKind::Ipv6)),
1024        ),
1025        (
1026            "ffff:ffff:ffff:ffff:ffff:ffff:ffgf:fffg",
1027            Err(AddrParseError(AddrKind::Ipv6)),
1028        ),
1029        // Wrong colons on uncompressed addresses
1030        (
1031            ":ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1032            Err(AddrParseError(AddrKind::Ipv6)),
1033        ),
1034        (
1035            "ffff::ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1036            Err(AddrParseError(AddrKind::Ipv6)),
1037        ),
1038        (
1039            "ffff:ffff::ffff:ffff:ffff:ffff:ffff:ffff",
1040            Err(AddrParseError(AddrKind::Ipv6)),
1041        ),
1042        (
1043            "ffff:ffff:ffff::ffff:ffff:ffff:ffff:ffff",
1044            Err(AddrParseError(AddrKind::Ipv6)),
1045        ),
1046        (
1047            "ffff:ffff:ffff:ffff::ffff:ffff:ffff:ffff",
1048            Err(AddrParseError(AddrKind::Ipv6)),
1049        ),
1050        (
1051            "ffff:ffff:ffff:ffff:ffff::ffff:ffff:ffff",
1052            Err(AddrParseError(AddrKind::Ipv6)),
1053        ),
1054        (
1055            "ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff",
1056            Err(AddrParseError(AddrKind::Ipv6)),
1057        ),
1058        (
1059            "ffff:ffff:ffff:ffff:ffff:ffff:ffff::ffff",
1060            Err(AddrParseError(AddrKind::Ipv6)),
1061        ),
1062        // More colons than allowed
1063        (
1064            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:",
1065            Err(AddrParseError(AddrKind::Ipv6)),
1066        ),
1067        (
1068            "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
1069            Err(AddrParseError(AddrKind::Ipv6)),
1070        ),
1071        // v Invalid hexadecimal
1072        (
1073            "ga05:d018:076c:b685:e8ab:afd3:af51:3aed",
1074            Err(AddrParseError(AddrKind::Ipv6)),
1075        ),
1076        // Cannot start with colon
1077        (
1078            ":a05:d018:076c:b685:e8ab:afd3:af51:3aed",
1079            Err(AddrParseError(AddrKind::Ipv6)),
1080        ),
1081        // Cannot end with colon
1082        (
1083            "2a05:d018:076c:b685:e8ab:afd3:af51:3ae:",
1084            Err(AddrParseError(AddrKind::Ipv6)),
1085        ),
1086        // Cannot have more than seven colons
1087        (
1088            "2a05:d018:076c:b685:e8ab:afd3:af51:3a::",
1089            Err(AddrParseError(AddrKind::Ipv6)),
1090        ),
1091        // Cannot contain two colons in a row
1092        (
1093            "2a05::018:076c:b685:e8ab:afd3:af51:3aed",
1094            Err(AddrParseError(AddrKind::Ipv6)),
1095        ),
1096        // v Textual block size is longer
1097        (
1098            "2a056:d018:076c:b685:e8ab:afd3:af51:3ae",
1099            Err(AddrParseError(AddrKind::Ipv6)),
1100        ),
1101        // v Textual block size is shorter
1102        (
1103            "2a0:d018:076c:b685:e8ab:afd3:af51:3aed ",
1104            Err(AddrParseError(AddrKind::Ipv6)),
1105        ),
1106        // Shorter IPv6 address
1107        (
1108            "d018:076c:b685:e8ab:afd3:af51:3aed",
1109            Err(AddrParseError(AddrKind::Ipv6)),
1110        ),
1111        // Longer IPv6 address
1112        (
1113            "2a05:d018:076c:b685:e8ab:afd3:af51:3aed3aed",
1114            Err(AddrParseError(AddrKind::Ipv6)),
1115        ),
1116    ];
1117
1118    #[test]
1119    fn parse_ipv6_address_test() {
1120        for &(ip_address, expected_result) in IPV6_ADDRESSES {
1121            assert_eq!(Ipv6Addr::try_from(ip_address), expected_result);
1122        }
1123    }
1124
1125    #[test]
1126    fn try_from_ascii_ip_address_test() {
1127        const IP_ADDRESSES: &[(&str, Result<IpAddr, AddrParseError>)] = &[
1128            // Valid IPv4 addresses
1129            ("127.0.0.1", Ok(IpAddr::V4(Ipv4Addr([127, 0, 0, 1])))),
1130            // Invalid IPv4 addresses
1131            (
1132                // Ends with a dot; misses one octet
1133                "127.0.0.",
1134                Err(AddrParseError(AddrKind::Ipv6)),
1135            ),
1136            // Valid IPv6 addresses
1137            (
1138                "0000:0000:0000:0000:0000:0000:0000:0001",
1139                Ok(IpAddr::V6(Ipv6Addr([
1140                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1141                ]))),
1142            ),
1143            // Something else
1144            (
1145                // A hostname
1146                "example.com",
1147                Err(AddrParseError(AddrKind::Ipv6)),
1148            ),
1149        ];
1150        for &(ip_address, expected_result) in IP_ADDRESSES {
1151            assert_eq!(IpAddr::try_from(ip_address), expected_result)
1152        }
1153    }
1154
1155    #[test]
1156    fn try_from_ascii_str_ip_address_test() {
1157        const IP_ADDRESSES: &[(&str, Result<IpAddr, AddrParseError>)] = &[
1158            // Valid IPv4 addresses
1159            ("127.0.0.1", Ok(IpAddr::V4(Ipv4Addr([127, 0, 0, 1])))),
1160            // Invalid IPv4 addresses
1161            (
1162                // Ends with a dot; misses one octet
1163                "127.0.0.",
1164                Err(AddrParseError(AddrKind::Ipv6)),
1165            ),
1166            // Valid IPv6 addresses
1167            (
1168                "0000:0000:0000:0000:0000:0000:0000:0001",
1169                Ok(IpAddr::V6(Ipv6Addr([
1170                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1171                ]))),
1172            ),
1173            // Something else
1174            (
1175                // A hostname
1176                "example.com",
1177                Err(AddrParseError(AddrKind::Ipv6)),
1178            ),
1179        ];
1180        for &(ip_address, expected_result) in IP_ADDRESSES {
1181            assert_eq!(IpAddr::try_from(ip_address), expected_result)
1182        }
1183    }
1184
1185    #[test]
1186    #[cfg(feature = "std")]
1187    fn to_str() {
1188        let domain_str = "example.com";
1189        let domain_servername = ServerName::try_from(domain_str).unwrap();
1190        assert_eq!(domain_str, domain_servername.to_str());
1191
1192        let ipv4_str = "127.0.0.1";
1193        let ipv4_servername = ServerName::try_from("127.0.0.1").unwrap();
1194        assert_eq!(ipv4_str, ipv4_servername.to_str());
1195
1196        let ipv6_str = "::1";
1197        let ipv6_servername = ServerName::try_from(ipv6_str).unwrap();
1198        assert_eq!("::1", ipv6_servername.to_str());
1199    }
1200}