server: bind specifically to WireGuard interface on Linux

This is one many upcoming changes to address IP spoofing
issues.

See #26 for more details.
pull/35/head
Jake McGinty 2021-04-05 16:34:21 +09:00
parent d2bc2b3506
commit 41565e46d7
3 changed files with 53 additions and 17 deletions

24
Cargo.lock generated
View File

@ -680,9 +680,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.91"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
[[package]]
name = "libsqlite3-sys"
@ -696,9 +696,9 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176"
dependencies = [
"scopeguard",
]
@ -929,9 +929,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.24"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
@ -1130,6 +1130,7 @@ dependencies = [
"serde",
"serde_json",
"shared",
"socket2",
"structopt",
"tempfile",
"thiserror",
@ -1234,9 +1235,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
[[package]]
name = "syn"
version = "1.0.67"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702"
checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
dependencies = [
"proc-macro2",
"quote",
@ -1329,9 +1330,9 @@ dependencies = [
[[package]]
name = "tinyvec"
version = "1.1.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
dependencies = [
"tinyvec_macros",
]
@ -1551,8 +1552,7 @@ dependencies = [
[[package]]
name = "warp"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332d47745e9a0c38636dbd454729b147d16bd1ed08ae67b3ab281c4506771054"
source = "git+https://github.com/tonarino/warp#bd70fb6249810eb63e9acdfe2dcc79e41ab53304"
dependencies = [
"bytes",
"futures",

View File

@ -34,9 +34,13 @@ structopt = "0.3"
thiserror = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
toml = "0.5"
warp = { version = "0.3", default-features = false }
warp = { git = "https://github.com/tonarino/warp", default-features = false }
wgctrl = { path = "../wgctrl-rs" }
[target.'cfg(target_os = "linux")'.dependencies]
socket2 = { version = "0.4", features = ["all"] }
[dev-dependencies]
anyhow = "1"
tempfile = "3"

View File

@ -1,5 +1,6 @@
use colored::*;
use error::handle_rejection;
use hyper::{server::conn::AddrStream, Body, Request};
use indoc::printdoc;
use ipnetwork::IpNetwork;
use parking_lot::Mutex;
@ -7,10 +8,11 @@ use rusqlite::Connection;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use shared::IoErrorContext;
use std::{
convert::Infallible,
env,
fs::File,
io::prelude::*,
net::{IpAddr, SocketAddr},
net::{IpAddr, SocketAddr, TcpListener},
ops::Deref,
path::{Path, PathBuf},
sync::Arc,
@ -304,13 +306,43 @@ async fn serve(interface: &str, conf: &ServerConfig) -> Result<(), Error> {
log::info!("innernet-server {} starting.", VERSION);
let routes = routes(context.clone()).with(warp::log("warp")).boxed();
warp::serve(routes)
.run((config.address, config.listen_port))
.await;
let listener = get_listener((config.address, config.listen_port).into(), interface)?;
let warp_svc = warp::service(routes);
let make_svc = hyper::service::make_service_fn(move |socket: &AddrStream| {
let remote_addr = socket.remote_addr();
let warp_svc = warp_svc.clone();
async move {
let svc = hyper::service::service_fn(move |req: Request<Body>| {
let warp_svc = warp_svc.clone();
async move { warp_svc.call_with_addr(req, Some(remote_addr)).await }
});
Ok::<_, Infallible>(svc)
}
});
hyper::Server::from_tcp(listener)?.serve(make_svc).await?;
Ok(())
}
#[cfg(target_os = "linux")]
fn get_listener(addr: SocketAddr, interface: &str) -> Result<TcpListener, Error> {
let listener = TcpListener::bind(&addr)?;
listener.set_nonblocking(true)?;
let sock = socket2::Socket::from(listener);
sock.bind_device(Some(interface.as_bytes()))?;
Ok(sock.into())
}
#[cfg(not(target_os = "linux"))]
fn get_listener(addr: SocketAddr, _interface: &str) -> Result<TcpListener, Error> {
let listener = TcpListener::bind(&addr)?;
listener.set_nonblocking(true)?;
Ok(listener)
}
pub fn routes(
context: Context,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {