-
Notifications
You must be signed in to change notification settings - Fork 384
/
Copy pathnet.rs
120 lines (97 loc) · 3.43 KB
/
net.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use futures::channel::oneshot;
use hyper::{Client, Uri};
use once_cell::sync::Lazy;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::net::SocketAddr;
use tokio_rustls::rustls::ClientConfig;
use crate::{AmIMullvad, Error};
const LE_ROOT_CERT: &[u8] = include_bytes!("../../../mullvad-api/le_root_cert.pem");
static CLIENT_CONFIG: Lazy<ClientConfig> = Lazy::new(|| {
ClientConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_safe_default_protocol_versions()
.unwrap()
.with_root_certificates(read_cert_store())
.with_no_client_auth()
});
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Hash, PartialEq, Eq)]
pub struct SockHandleId(pub usize);
pub struct SockHandle {
stop_tx: Option<oneshot::Sender<()>>,
bind_addr: SocketAddr,
}
impl SockHandle {
pub(crate) async fn start_tcp_forward(
client: crate::service::ServiceClient,
bind_addr: SocketAddr,
via_addr: SocketAddr,
) -> Result<Self, Error> {
let (stop_tx, stop_rx) = oneshot::channel();
let (id, bind_addr) = client
.start_tcp_forward(tarpc::context::current(), bind_addr, via_addr)
.await??;
tokio::spawn(async move {
let _ = stop_rx.await;
log::trace!("Stopping TCP forward");
if let Err(error) = client.stop_tcp_forward(tarpc::context::current(), id).await {
log::error!("Failed to stop TCP forward: {error}");
}
});
Ok(SockHandle {
stop_tx: Some(stop_tx),
bind_addr,
})
}
pub fn stop(&mut self) {
if let Some(stop_tx) = self.stop_tx.take() {
let _ = stop_tx.send(());
}
}
pub fn bind_addr(&self) -> SocketAddr {
self.bind_addr
}
}
impl Drop for SockHandle {
fn drop(&mut self) {
self.stop()
}
}
pub async fn geoip_lookup(mullvad_host: String) -> Result<AmIMullvad, Error> {
let uri = Uri::try_from(format!("https://ipv4.am.i.{mullvad_host}/json"))
.map_err(|_| Error::InvalidUrl)?;
http_get(uri).await
}
pub async fn http_get<T: DeserializeOwned>(url: Uri) -> Result<T, Error> {
log::debug!("GET {url}");
let https = hyper_rustls::HttpsConnectorBuilder::new()
.with_tls_config(CLIENT_CONFIG.clone())
.https_only()
.enable_http1()
.build();
let client: Client<_, hyper::Body> = Client::builder().build(https);
let body = client
.get(url)
.await
.map_err(|error| Error::HttpRequest(error.to_string()))?
.into_body();
// TODO: limit length
let bytes = hyper::body::to_bytes(body).await.map_err(|error| {
log::error!("Failed to convert body to bytes buffer: {}", error);
Error::DeserializeBody
})?;
serde_json::from_slice(&bytes).map_err(|error| {
log::error!("Failed to deserialize response: {}", error);
Error::DeserializeBody
})
}
fn read_cert_store() -> tokio_rustls::rustls::RootCertStore {
let mut cert_store = tokio_rustls::rustls::RootCertStore::empty();
let certs = rustls_pemfile::certs(&mut std::io::BufReader::new(LE_ROOT_CERT))
.expect("Failed to parse pem file");
let (num_certs_added, num_failures) = cert_store.add_parsable_certificates(&certs);
if num_failures > 0 || num_certs_added != 1 {
panic!("Failed to add root cert");
}
cert_store
}