Compare commits

..

No commits in common. "a1a95f2865076cd9147e3634e43e88e4546b1c67" and "fb83d6e04f0cc78b3b8f76c0ede6e19d342ca331" have entirely different histories.

3 changed files with 25 additions and 90 deletions

12
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
@ -452,15 +452,6 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "ipnet"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "ipnetwork" name = "ipnetwork"
version = "0.20.0" version = "0.20.0"
@ -1010,7 +1001,6 @@ dependencies = [
"bincode", "bincode",
"blake3", "blake3",
"futures", "futures",
"ipnet",
"log", "log",
"pnet", "pnet",
"pretty_env_logger", "pretty_env_logger",

View file

@ -20,4 +20,3 @@ pnet = "0.35.0"
rupnp = "2.0.0" rupnp = "2.0.0"
tokio = { version = "1.41.1", features = ["rt", "rt-multi-thread", "macros"] } tokio = { version = "1.41.1", features = ["rt", "rt-multi-thread", "macros"] }
futures = "0.3.31" futures = "0.3.31"
ipnet = { version = "2.10.1", features = ["serde"] }

View file

@ -29,8 +29,6 @@ const PERSIST_INTERVAL: Duration = Duration::from_secs(600);
const LAN_BROADCAST_INTERVAL: Duration = Duration::from_secs(60); const LAN_BROADCAST_INTERVAL: Duration = Duration::from_secs(60);
const IGD_INTERVAL: Duration = Duration::from_secs(60); const IGD_INTERVAL: Duration = Duration::from_secs(60);
const IGD_LEASE_DURATION: Duration = Duration::from_secs(300);
type Pubkey = String; type Pubkey = String;
#[derive(Deserialize)] #[derive(Deserialize)]
@ -58,9 +56,6 @@ struct Config {
/// Settings for the Wireguard interfaces (currently only necessary if you want to use igd features) /// Settings for the Wireguard interfaces (currently only necessary if you want to use igd features)
#[serde(default)] #[serde(default)]
interfaces: Vec<InterfaceSetting>, interfaces: Vec<InterfaceSetting>,
#[serde(default)]
forbidden_nets: Vec<ipnet::IpNet>,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -173,11 +168,7 @@ fn wg_dump(interface: &str) -> Result<IfInfo> {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Ok(IfInfo { Ok(IfInfo { our_pubkey, listen_port, peers })
our_pubkey,
listen_port,
peers,
})
} }
// ============ DAEMON CODE ================= // ============ DAEMON CODE =================
@ -219,39 +210,26 @@ impl Daemon {
fn new(config: Config) -> Result<Self> { fn new(config: Config) -> Result<Self> {
let gossip_key = kdf(config.gossip_secret.as_deref().unwrap_or_default()); let gossip_key = kdf(config.gossip_secret.as_deref().unwrap_or_default());
let interface_names = config let interface_names = config.peers.iter().map(|peer| peer.interface.clone()).collect::<HashSet<_>>();
.peers let interfaces = interface_names.into_iter().map(|interface_name| wg_dump(&interface_name).map(|ifinfo| (interface_name, ifinfo))).collect::<Result<HashMap<_, _>>>()?;
.iter()
.map(|peer| peer.interface.clone())
.collect::<HashSet<_>>();
let interfaces = interface_names
.into_iter()
.map(|interface_name| wg_dump(&interface_name).map(|ifinfo| (interface_name, ifinfo)))
.collect::<Result<HashMap<_, _>>>()?;
let socket = UdpSocket::bind(SocketAddr::new("::".parse()?, config.gossip_port))?; let socket = UdpSocket::bind(SocketAddr::new("::".parse()?, config.gossip_port))?;
socket.set_broadcast(true)?; socket.set_broadcast(true)?;
//socket.set_ttl(1)?; socket.set_ttl(1)?;
let our_pubkey = interfaces.iter().next().unwrap().1.our_pubkey.clone(); let our_pubkey = interfaces.iter().next().unwrap().1.our_pubkey.clone();
let peers = config let peers = config.peers.iter().map(|peer_cfg| {
.peers (
.iter() peer_cfg.pubkey.clone(),
.map(|peer_cfg| { PeerInfo {
( gossip_ip: peer_cfg.address,
peer_cfg.pubkey.clone(), gossip_prio: fasthash(format!("{}-{}", our_pubkey, peer_cfg.pubkey).as_bytes()),
PeerInfo { endpoint: None, // Is resolved as DNS name later
gossip_ip: peer_cfg.address, last_seen: u64::MAX,
gossip_prio: fasthash( lan_endpoint: None,
format!("{}-{}", our_pubkey, peer_cfg.pubkey).as_bytes(), }
), )
endpoint: None, // Is resolved as DNS name later }).collect();
last_seen: u64::MAX,
lan_endpoint: None,
},
)
})
.collect();
Ok(Daemon { Ok(Daemon {
config, config,
@ -379,7 +357,9 @@ impl Daemon {
self.socket.send_to(&packet, from)?; self.socket.send_to(&packet, from)?;
} }
} }
Gossip::LanBroadcast { pubkey } => { Gossip::LanBroadcast {
pubkey,
} => {
if self.config.lan_discovery { if self.config.lan_discovery {
if let Some(peer) = state.peers.get_mut(&pubkey) { if let Some(peer) = state.peers.get_mut(&pubkey) {
peer.lan_endpoint = Some((from.ip(), time())); peer.lan_endpoint = Some((from.ip(), time()));
@ -548,20 +528,7 @@ impl State {
let mut peer_vec = self let mut peer_vec = self
.peers .peers
.iter() .iter()
.filter(|(_, info)| { .filter(|(_, info)| info.last_seen != u64::MAX && now < info.last_seen + TIMEOUT.as_secs() && info.endpoint.is_some())
let seen = info.last_seen != u64::MAX && now < info.last_seen + TIMEOUT.as_secs();
let endpoint_valid = info
.endpoint
.map(|ep| {
!daemon
.config
.forbidden_nets
.iter()
.any(|net| net.contains(&ep))
})
.unwrap_or(false);
seen && endpoint_valid
})
.map(|(_, info)| (info.gossip_ip, info.gossip_prio)) .map(|(_, info)| (info.gossip_ip, info.gossip_prio))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
peer_vec.sort_by_key(|(_, prio)| *prio); peer_vec.sort_by_key(|(_, prio)| *prio);
@ -622,6 +589,7 @@ impl State {
} }
fn read_wg_peers(&mut self) -> Result<()> { fn read_wg_peers(&mut self) -> Result<()> {
// Clear old known endpoints if any // Clear old known endpoints if any
for (_, peer) in self.peers.iter_mut() { for (_, peer) in self.peers.iter_mut() {
peer.endpoint = None; peer.endpoint = None;
@ -662,22 +630,10 @@ impl State {
(Some((addr1, _)), Some(addr2)) => addr1 != addr2, (Some((addr1, _)), Some(addr2)) => addr1 != addr2,
_ => false, _ => false,
}; };
// If the current endpoint is in a forbidden net, reconfigure the peer even if it has a connection
let forbidden_endpoint = peer
.endpoint
.map(|ep| {
daemon
.config
.forbidden_nets
.iter()
.any(|net| net.contains(&ep))
})
.unwrap_or(false);
// if peer is connected and endpoint is the correct one, // if peer is connected and endpoint is the correct one,
// set higher keepalive and then skip reconfiguring it // set higher keepalive and then skip reconfiguring it
if !bad_endpoint && peer.last_seen != u64::MAX && !forbidden_endpoint && now < peer.last_seen + TIMEOUT.as_secs() if !bad_endpoint && peer.last_seen != u64::MAX && now < peer.last_seen + TIMEOUT.as_secs() {
{
Command::new("wg") Command::new("wg")
.args([ .args([
"set", "set",
@ -717,16 +673,6 @@ impl State {
} }
} }
endpoints.sort(); endpoints.sort();
endpoints = endpoints
.into_iter()
.filter(|(ep, _)| {
!daemon
.config
.forbidden_nets
.iter()
.any(|net| net.contains(ep))
})
.collect();
endpoints endpoints
} }
}; };
@ -756,7 +702,7 @@ impl State {
"persistent-keepalive", "persistent-keepalive",
"10", "10",
"allowed-ips", "allowed-ips",
"::/0,0.0.0.0/0", "::/0,0.0.0.0/0"
]) ])
.output()?; .output()?;
let packet = daemon.make_packet(&Gossip::Ping)?; let packet = daemon.make_packet(&Gossip::Ping)?;
@ -774,7 +720,7 @@ impl State {
"peer", "peer",
&peer_cfg.pubkey, &peer_cfg.pubkey,
"allowed-ips", "allowed-ips",
"::/0,0.0.0.0/0", "::/0,0.0.0.0/0"
]) ])
.output()?; .output()?;
} }