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