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

View File

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

View File

@ -1,5 +1,6 @@
use colored::*; use colored::*;
use error::handle_rejection; use error::handle_rejection;
use hyper::{server::conn::AddrStream, Body, Request};
use indoc::printdoc; use indoc::printdoc;
use ipnetwork::IpNetwork; use ipnetwork::IpNetwork;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -7,10 +8,11 @@ use rusqlite::Connection;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use shared::IoErrorContext; use shared::IoErrorContext;
use std::{ use std::{
convert::Infallible,
env, env,
fs::File, fs::File,
io::prelude::*, io::prelude::*,
net::{IpAddr, SocketAddr}, net::{IpAddr, SocketAddr, TcpListener},
ops::Deref, ops::Deref,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
@ -304,13 +306,43 @@ async fn serve(interface: &str, conf: &ServerConfig) -> Result<(), Error> {
log::info!("innernet-server {} starting.", VERSION); log::info!("innernet-server {} starting.", VERSION);
let routes = routes(context.clone()).with(warp::log("warp")).boxed(); let routes = routes(context.clone()).with(warp::log("warp")).boxed();
warp::serve(routes)
.run((config.address, config.listen_port)) let listener = get_listener((config.address, config.listen_port).into(), interface)?;
.await;
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(()) 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( pub fn routes(
context: Context, context: Context,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone { ) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {