add allowed_ips config option for peers, formatting

This commit is contained in:
Lyn 2025-01-18 03:08:30 +01:00
parent a8957c9558
commit af07d1653c
2 changed files with 50 additions and 17 deletions

View file

@ -74,6 +74,8 @@ address = "10.14.1.2"
endpoint = "77.207.15.215" endpoint = "77.207.15.215"
# (Optional) endpoint port # (Optional) endpoint port
port = 33722 port = 33722
# (Optional) Subnets allowed to be routed through this peer. If no value is given, this defaults to only the peers address itself.
allowed_ips = ["10.14.1.2/32","192.168.0.0/16"]
[[peers]] [[peers]]
interface = "wg0" interface = "wg0"

View file

@ -9,6 +9,7 @@ use std::thread;
use std::time::Duration; use std::time::Duration;
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use ipnet::{IpNet, Ipv4Net, Ipv6Net};
use log::*; use log::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -58,7 +59,7 @@ struct Config {
interfaces: Vec<InterfaceSetting>, interfaces: Vec<InterfaceSetting>,
#[serde(default)] #[serde(default)]
forbidden_nets: Vec<ipnet::IpNet>, forbidden_nets: Vec<IpNet>,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -73,6 +74,9 @@ struct Peer {
port: Option<u16>, port: Option<u16>,
/// An optional Wireguard endpoint used to initialize a connection to this peer /// An optional Wireguard endpoint used to initialize a connection to this peer
endpoint: Option<String>, endpoint: Option<String>,
/// Subnets allowed to be routed through this peer. Defaults to only the IP of the peer itself if no value is given.
#[serde(default)]
allowed_ips: Vec<IpNet>,
} }
/// Settings for Wireguard interfaces /// Settings for Wireguard interfaces
#[derive(Deserialize)] #[derive(Deserialize)]
@ -101,6 +105,15 @@ fn main() -> Result<()> {
let config_str = std::fs::read_to_string(config_path)?; let config_str = std::fs::read_to_string(config_path)?;
toml::from_str(&config_str)? toml::from_str(&config_str)?
}; };
for peer in &mut config.peers {
if peer.allowed_ips.is_empty() {
let ip_net = match peer.address {
IpAddr::V4(ipv4) => IpNet::V4(Ipv4Net::new(ipv4, 32)?),
IpAddr::V6(ipv6) => IpNet::V6(Ipv6Net::new(ipv6, 128)?),
};
peer.allowed_ips.push(ip_net);
}
}
if let Some(f) = &config.gossip_secret_file { if let Some(f) = &config.gossip_secret_file {
if config.gossip_secret.is_some() { if config.gossip_secret.is_some() {
@ -471,15 +484,21 @@ impl Daemon {
}); });
} }
} }
fn generate_portmaps(&self) -> (HashMap<u16,u16>, Vec<u16>) { fn generate_portmaps(&self) -> (HashMap<u16, u16>, Vec<u16>) {
let mut portmap_v4: HashMap<u16, u16> = HashMap::new(); let mut portmap_v4: HashMap<u16, u16> = HashMap::new();
//collect interfaces that have peers with IPv4 addresses (-> IPv4 port mappings need to exist) //collect interfaces that have peers with IPv4 addresses (-> IPv4 port mappings need to exist)
let binding = self.state.lock().unwrap(); let binding = self.state.lock().unwrap();
let interfaces = binding.interfaces.iter(); let interfaces = binding.interfaces.iter();
let v4ifs: Vec<_> = binding.interfaces.iter() let v4ifs: Vec<_> = binding
.interfaces
.iter()
.filter_map(|(ifname, ifinfo)| { .filter_map(|(ifname, ifinfo)| {
if ifinfo.listen_port != 0 if ifinfo.listen_port != 0
&& self.config.peers.iter().any(|peer| peer.interface == **ifname && peer.address.is_ipv4()) && self
.config
.peers
.iter()
.any(|peer| peer.interface == **ifname && peer.address.is_ipv4())
{ {
Some((ifname, ifinfo)) Some((ifname, ifinfo))
} else { } else {
@ -490,9 +509,8 @@ impl Daemon {
//create portmap //create portmap
for ifsetting in &self.config.interfaces { for ifsetting in &self.config.interfaces {
if let Some(external_port) = ifsetting.upnp_ext_port_v4 { if let Some(external_port) = ifsetting.upnp_ext_port_v4 {
if let Some((_ifname, ifinfo)) = v4ifs if let Some((_ifname, ifinfo)) =
.iter() v4ifs.iter().find(|(ifname, _)| **ifname == ifsetting.name)
.find(|(ifname, _)| **ifname == ifsetting.name)
{ {
portmap_v4.insert(ifinfo.listen_port, external_port); portmap_v4.insert(ifinfo.listen_port, external_port);
} }
@ -501,16 +519,16 @@ impl Daemon {
//collect ports of interfaces that have peers with IPv6 addresses (-> pinholes for the IPv6 listen ports should be created) //collect ports of interfaces that have peers with IPv6 addresses (-> pinholes for the IPv6 listen ports should be created)
let v6ports: Vec<u16> = interfaces let v6ports: Vec<u16> = interfaces
.filter(|(ifname, ifinfo)| { .filter(|(ifname, ifinfo)| {
ifinfo.listen_port!=0 ifinfo.listen_port != 0
&& self.config && self
.peers .config
.iter() .peers
.any(|peer| peer.interface == **ifname && peer.address.is_ipv6()) .iter()
.any(|peer| peer.interface == **ifname && peer.address.is_ipv6())
}) })
.map(|(_, ifinfo)|ifinfo.listen_port) .map(|(_, ifinfo)| ifinfo.listen_port)
.collect(); .collect();
(portmap_v4, v6ports) (portmap_v4, v6ports)
} }
fn make_packet(&self, gossip: &Gossip) -> Result<Vec<u8>> { fn make_packet(&self, gossip: &Gossip) -> Result<Vec<u8>> {
@ -674,7 +692,10 @@ impl State {
// 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
&& !forbidden_endpoint
&& now < peer.last_seen + TIMEOUT.as_secs()
{ {
Command::new("wg") Command::new("wg")
.args([ .args([
@ -754,7 +775,12 @@ impl State {
"persistent-keepalive", "persistent-keepalive",
"10", "10",
"allowed-ips", "allowed-ips",
"::/0,0.0.0.0/0", &peer_cfg
.allowed_ips
.iter()
.map(|ip| ip.to_string())
.collect::<Vec<_>>()
.join(","),
]) ])
.output()?; .output()?;
let packet = daemon.make_packet(&Gossip::Ping)?; let packet = daemon.make_packet(&Gossip::Ping)?;
@ -772,7 +798,12 @@ impl State {
"peer", "peer",
&peer_cfg.pubkey, &peer_cfg.pubkey,
"allowed-ips", "allowed-ips",
"::/0,0.0.0.0/0", &peer_cfg
.allowed_ips
.iter()
.map(|ip| ip.to_string())
.collect::<Vec<_>>()
.join(","),
]) ])
.output()?; .output()?;
} }