priorize LAN endpoint if available

This commit is contained in:
Alex 2023-03-09 13:52:53 +01:00
parent b7a1b4d454
commit b969c9ada6

View file

@ -141,11 +141,14 @@ struct Daemon {
} }
struct PeerInfo { struct PeerInfo {
endpoint: Option<SocketAddr>, // Info known from config
lan_endpoint: Option<(SocketAddr, u64)>,
last_seen: u64,
gossip_ip: IpAddr, gossip_ip: IpAddr,
gossip_prio: u64, gossip_prio: u64,
// Info retrieved from wireguard
endpoint: Option<SocketAddr>,
last_seen: u64,
// Info received by LAN broadcast
lan_endpoint: Option<(SocketAddr, u64)>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -158,7 +161,7 @@ enum Gossip {
LanBroadcast { LanBroadcast {
pubkey: Pubkey, pubkey: Pubkey,
listen_port: u16, listen_port: u16,
} },
} }
impl Daemon { impl Daemon {
@ -267,10 +270,14 @@ impl Daemon {
self.socket.send_to(&packet, from)?; self.socket.send_to(&packet, from)?;
} }
} }
Gossip::LanBroadcast{ pubkey, listen_port } => { Gossip::LanBroadcast {
pubkey,
listen_port,
} => {
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((SocketAddr::new(from.ip(), listen_port), time())); let addr = SocketAddr::new(from.ip(), listen_port);
peer.lan_endpoint = Some((addr, time()));
} }
} }
} }
@ -464,43 +471,59 @@ impl State {
Ok(()) Ok(())
} }
fn setup_wg_peers(&self, daemon: &Daemon, i: usize) -> Result<()> { fn setup_wg_peers(&mut self, daemon: &Daemon, i: usize) -> Result<()> {
let now = time(); let now = time();
for peer in daemon.config.peers.iter() { for peer_cfg in daemon.config.peers.iter() {
// Skip ourself // Skip ourself
if peer.pubkey == daemon.our_pubkey { if peer_cfg.pubkey == daemon.our_pubkey {
continue; continue;
} }
// If peer is connected, use higher keepalive and then skip reconfiguring it
if self if let Some(peer) = self.peers.get_mut(&peer_cfg.pubkey) {
.peers // remove LAN endpoint info if it is obsolete
.get(&peer.pubkey) if matches!(peer.lan_endpoint, Some((_, t)) if now > t + TIMEOUT.as_secs()) {
.map(|x| now < x.last_seen + TIMEOUT.as_secs()) peer.lan_endpoint = None;
.unwrap_or(false) }
{
// make sure we aren't skipping this peer (see below) if we can switch to LAN
// endpoint instead of currently connected one
let bad_endpoint = match (&peer.lan_endpoint, &peer.endpoint) {
(Some((addr1, _)), Some(addr2)) => addr1 != addr2,
_ => false,
};
// if peer is connected and endpoint is the correct one,
// set higher keepalive and then skip reconfiguring it
if !bad_endpoint && now < peer.last_seen + TIMEOUT.as_secs() {
Command::new("wg") Command::new("wg")
.args([ .args([
"set", "set",
&daemon.config.interface, &daemon.config.interface,
"peer", "peer",
&peer.pubkey, &peer_cfg.pubkey,
"persistent-keepalive", "persistent-keepalive",
"30", "30",
]) ])
.output()?; .output()?;
continue; continue;
} }
}
// For disconnected peers, cycle through the IP addresses that we know of // For disconnected peers, cycle through the endpoint addresses that we know of
let lan_endpoint = self.peers.get(&peer.pubkey) let lan_endpoint = self
.and_then(|peer| peer.lan_endpoint) .peers
.filter(|(_, t)| time() < t + TIMEOUT.as_secs()); .get(&peer_cfg.pubkey)
.and_then(|peer| peer.lan_endpoint);
let endpoints = match lan_endpoint { let endpoints = match lan_endpoint {
Some(endpoint) => vec![endpoint], Some(endpoint) => vec![endpoint],
None => { None => {
let mut endpoints = self.gossip.get(&peer.pubkey).cloned().unwrap_or_default(); let mut endpoints = self
if let Some(endpoint) = &peer.endpoint { .gossip
.get(&peer_cfg.pubkey)
.cloned()
.unwrap_or_default();
if let Some(endpoint) = &peer_cfg.endpoint {
match endpoint.to_socket_addrs() { match endpoint.to_socket_addrs() {
Err(e) => error!("Could not resolve DNS for {}: {}", endpoint, e), Err(e) => error!("Could not resolve DNS for {}: {}", endpoint, e),
Ok(iter) => { Ok(iter) => {
@ -517,31 +540,31 @@ impl State {
if !endpoints.is_empty() { if !endpoints.is_empty() {
let endpoint = endpoints[i % endpoints.len()]; let endpoint = endpoints[i % endpoints.len()];
info!("Configure {} with endpoint {}", peer.pubkey, endpoint.0); info!("Configure {} with endpoint {}", peer_cfg.pubkey, endpoint.0);
Command::new("wg") Command::new("wg")
.args([ .args([
"set", "set",
&daemon.config.interface, &daemon.config.interface,
"peer", "peer",
&peer.pubkey, &peer_cfg.pubkey,
"endpoint", "endpoint",
&endpoint.0.to_string(), &endpoint.0.to_string(),
"persistent-keepalive", "persistent-keepalive",
"10", "10",
"allowed-ips", "allowed-ips",
&format!("{}/32", peer.address), &format!("{}/32", peer_cfg.address),
]) ])
.output()?; .output()?;
} else { } else {
info!("Configure {} with no known endpoint", peer.pubkey); info!("Configure {} with no known endpoint", peer_cfg.pubkey);
Command::new("wg") Command::new("wg")
.args([ .args([
"set", "set",
&daemon.config.interface, &daemon.config.interface,
"peer", "peer",
&peer.pubkey, &peer_cfg.pubkey,
"allowed-ips", "allowed-ips",
&format!("{}/32", peer.address), &format!("{}/32", peer_cfg.address),
]) ])
.output()?; .output()?;
} }