sspi/
network_client.rs

1use std::fmt::Debug;
2use std::future::Future;
3use std::pin::Pin;
4
5use crate::generator::NetworkRequest;
6use crate::Result;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum NetworkProtocol {
10    Tcp,
11    Udp,
12    Http,
13    Https,
14}
15
16impl NetworkProtocol {
17    pub const ALL: &'static [Self] = &[Self::Tcp, Self::Udp, Self::Http, Self::Https];
18
19    pub(crate) fn from_url_scheme(scheme: &str) -> Option<Self> {
20        match scheme {
21            "tcp" => Some(Self::Tcp),
22            "udp" => Some(Self::Udp),
23            "http" => Some(Self::Http),
24            "https" => Some(Self::Https),
25            _ => None,
26        }
27    }
28}
29
30/// Represents an abstract asynchronous network client.
31///
32/// This trait is primarily used for implementing network clients for WASM target
33/// and in other cases where a synchronous network client is not an option.
34pub trait AsyncNetworkClient: Send + Sync {
35    /// Send request to the server and return the response.
36    ///
37    /// URL scheme is guaranteed to be the same as specified by `protocol` argument.
38    /// `sspi-rs` will call this method only if `NetworkClient::is_protocol_supported`
39    /// returned true prior to the call, so unsupported `protocol` values could be marked as `unreachable!`.
40    fn send<'a>(
41        &'a mut self,
42        network_request: &'a NetworkRequest,
43    ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>> + 'a>>;
44}
45
46pub trait NetworkClient: Send + Sync {
47    /// Send request to the server and return the response. URL scheme is guaranteed to be
48    /// the same as specified by `protocol` argument. `sspi-rs` will call this method only if
49    /// `NetworkClient::is_protocol_supported` returned true prior to the call, so unsupported
50    /// `protocol` values could be marked as `unreachable!`.
51    fn send(&self, request: &NetworkRequest) -> Result<Vec<u8>>;
52}
53
54#[cfg(feature = "network_client")]
55pub mod reqwest_network_client {
56    use std::io::{Read, Write};
57    use std::net::{IpAddr, Ipv4Addr, TcpStream, UdpSocket};
58
59    use byteorder::{BigEndian, ReadBytesExt};
60    use url::Url;
61
62    use super::{NetworkClient, NetworkProtocol};
63    use crate::generator::NetworkRequest;
64    use crate::{Error, ErrorKind, Result};
65
66    #[derive(Debug, Clone, Default)]
67    pub struct ReqwestNetworkClient;
68
69    impl ReqwestNetworkClient {
70        fn send_tcp(&self, url: &Url, data: &[u8]) -> Result<Vec<u8>> {
71            let addr = format!("{}:{}", url.host_str().unwrap_or_default(), url.port().unwrap_or(88));
72            let mut stream = TcpStream::connect(addr)
73                .map_err(|e| Error::new(ErrorKind::NoAuthenticatingAuthority, format!("{:?}", e)))?;
74
75            stream
76                .write(data)
77                .map_err(|e| Error::new(ErrorKind::NoAuthenticatingAuthority, format!("{:?}", e)))?;
78
79            let len = stream
80                .read_u32::<BigEndian>()
81                .map_err(|e| Error::new(ErrorKind::NoAuthenticatingAuthority, format!("{:?}", e)))?;
82
83            let mut buf = vec![0; len as usize + 4];
84            buf[0..4].copy_from_slice(&(len.to_be_bytes()));
85
86            stream
87                .read_exact(&mut buf[4..])
88                .map_err(|e| Error::new(ErrorKind::NoAuthenticatingAuthority, format!("{:?}", e)))?;
89
90            Ok(buf)
91        }
92
93        fn send_udp(&self, url: &Url, data: &[u8]) -> Result<Vec<u8>> {
94            let port =
95                portpicker::pick_unused_port().ok_or_else(|| Error::new(ErrorKind::InternalError, "No free ports"))?;
96            let udp_socket = UdpSocket::bind((IpAddr::V4(Ipv4Addr::LOCALHOST), port))?;
97
98            let addr = format!("{}:{}", url.host_str().unwrap_or_default(), url.port().unwrap_or(88));
99            udp_socket.send_to(data, addr)?;
100
101            // 48 000 bytes: default maximum token len in Windows
102            let mut buf = vec![0; 0xbb80];
103
104            let n = udp_socket.recv(&mut buf)?;
105
106            let mut reply_buf = Vec::with_capacity(n + 4);
107            reply_buf.extend_from_slice(&(n as u32).to_be_bytes());
108            reply_buf.extend_from_slice(&buf[0..n]);
109
110            Ok(reply_buf)
111        }
112
113        fn send_http(&self, url: &Url, data: &[u8]) -> Result<Vec<u8>> {
114            crate::rustls::install_default_crypto_provider_if_necessary().map_err(|()| {
115                Error::new(
116                    ErrorKind::SecurityPackageNotFound,
117                    "failed to install the default crypto provider for TLS",
118                )
119            })?;
120
121            let client = crate::rustls::load_native_certs(reqwest::blocking::ClientBuilder::new())
122                .build()
123                .map_err(|e| {
124                    Error::new(
125                        ErrorKind::NoAuthenticatingAuthority,
126                        format!("failed to build reqwest client: {e}"),
127                    )
128                })?;
129
130            let response = client
131                .post(url.clone())
132                .body(data.to_vec())
133                .send()
134                .map_err(|err| match err {
135                    err if err.to_string().to_lowercase().contains("certificate") => Error::new(
136                        ErrorKind::CertificateUnknown,
137                        format!("Invalid certificate data: {:?}", err),
138                    ),
139                    _ => Error::new(
140                        ErrorKind::NoAuthenticatingAuthority,
141                        format!("Unable to send the data to the KDC Proxy: {:?}", err),
142                    ),
143                })?
144                .error_for_status()
145                .map_err(|err| Error::new(ErrorKind::NoAuthenticatingAuthority, format!("KDC Proxy: {err}")))?;
146
147            let body = response.bytes().map_err(|err| {
148                Error::new(
149                    ErrorKind::NoAuthenticatingAuthority,
150                    format!("Unable to read the response data from the KDC Proxy: {:?}", err),
151                )
152            })?;
153
154            // The type bytes::Bytes has a special From implementation for Vec<u8>.
155            let body = Vec::from(body);
156
157            Ok(body)
158        }
159    }
160
161    impl NetworkClient for ReqwestNetworkClient {
162        fn send(&self, request: &NetworkRequest) -> Result<Vec<u8>> {
163            match request.protocol {
164                NetworkProtocol::Tcp => self.send_tcp(&request.url, &request.data),
165                NetworkProtocol::Udp => self.send_udp(&request.url, &request.data),
166                NetworkProtocol::Http | NetworkProtocol::Https => self.send_http(&request.url, &request.data),
167            }
168        }
169    }
170}