Hi, currently I'm trying to implement a https low-level request with windows-rs crate for dns lookup, socket2 crate for low-level socket connection and rustls to create a TLS handshake stream, all of this on Windows 10, version 22H2. The problem I'm facing is that at the moment of reading all the bytes to a buffer, the program ends with an unexpected windows error:
Error: Error { code: HRESULT(0x8000FFFF), message: "Catastrophic failure" }
So I would like to know, what am I doing wrong? That error doesn't says much
It should be noted that I don't have that problem making a request without TLS, everything works perfectly, even with another TLS crate works well, such as native-tls
The code:
Rust version: 1.82.0
[dependencies]
rustls = "0.23.2"
webpki-roots = "0.26.7"
socket2 = "0.5.8"
[dependencies.windows]
version = "0.57"
features = ["Win32_Networking_WinSock", "Win32_Foundation"]
use rustls::pki_types::ServerName;
use socket2::{Domain, Protocol, Socket, Type};
use std::io::{BufReader, Write};
use std::mem;
use std::net::ToSocketAddrs;
use std::slice::from_raw_parts;
use std::sync::Arc;
use std::time::Duration;
use windows::core::*;
use windows::Win32::Networking::WinSock::{
GetAddrInfoW, WSAAddressToStringW, WSAStartup, ADDRINFOW, AF_UNSPEC,
IPPROTO_TCP, SOCK_STREAM, WSADATA,
};
use std::io::Read;
fn main() -> windows::core::Result<()> {
let mut hints: ADDRINFOW = unsafe { mem::zeroed() };
hints.ai_family = AF_UNSPEC.0 as i32;
hints.ai_socktype = SOCK_STREAM.0;
hints.ai_protocol = IPPROTO_TCP.0;
let mut wsdata: WSADATA = unsafe { mem::zeroed() };
unsafe {
let code = WSAStartup(514, &mut wsdata);
if code != 0 {
eprintln!("{:?}", code);
}
}
let mut res = std::ptr::null_mut();
unsafe {
let code =
GetAddrInfoW(w!("google.com"), w!("443"), Some(&hints), &mut res);
if code != 0 {
eprintln!("{:?}", code);
}
}
let addr = unsafe {
let mut cb_buffer = 257_u32;
let mut buffer = Vec::<u16>::with_capacity(cb_buffer as usize);
let lp_buffer = PWSTR(buffer.as_mut_ptr());
WSAAddressToStringW(
(*res).ai_addr,
(*res).ai_addrlen as u32,
None,
lp_buffer,
&mut cb_buffer,
);
let buffer = { from_raw_parts(lp_buffer.0, cb_buffer as usize - 1) };
let addr = String::from_utf16_lossy(buffer);
println!("{}", addr);
addr
};
let mut socket =
Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))?;
let addr = addr.to_socket_addrs()?.collect::<Vec<_>>()[0];
socket.connect_timeout(&addr.into(), Duration::from_secs(10))?;
let root_store = rustls::RootCertStore {
roots: webpki_roots::TLS_SERVER_ROOTS.into(),
};
let mut config = rustls::ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth();
config.key_log = Arc::new(rustls::KeyLogFile::new());
let server_name = ServerName::DnsName("wwww.google.com".try_into().unwrap());
let mut sess =
rustls::ClientConnection::new(Arc::new(config), server_name).unwrap();
sess.send_close_notify();
let mut tls = rustls::Stream::new(&mut sess, &mut socket);
let _ = tls.write(
concat!(
"GET / HTTP/1.1\r\n",
"Host: www.google.com\r\n",
"Connection: close\r\n",
"Accept-Encoding: identity\r\n",
"\r\n"
)
.as_bytes(),
)?;
let mut reader = BufReader::new(tls);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer)?;
println!("{}", String::from_utf8_lossy(&buffer));
Ok(())
}