Add ability to configure “own” addresses (#185)

* Add ability to configure “own” addresses

This configuration option permits the declaration of external or public
addresses instead of attempting to learn them from port forwarding or
interfaces. This is useful in situations where it isn’t possible to
accurately obtain the correct external addresses that peers should use.

* Update args and use better parse listen address

Add the --advertise_addresses control argument to accompany the new
configuration option. Also parse the listen address/port to extract the
port to advertise with advertise_addresses instead of assuming it is
just a port.
This commit is contained in:
Jeffrey Schiller 2021-04-09 14:30:16 -04:00 committed by GitHub
parent 7a55529cb9
commit 0f9a0d8f91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 6 deletions

View File

@ -29,7 +29,7 @@ use crate::{
AddrList, NodeInfo, PeerInfo, MESSAGE_TYPE_CLOSE, MESSAGE_TYPE_DATA, MESSAGE_TYPE_KEEPALIVE, AddrList, NodeInfo, PeerInfo, MESSAGE_TYPE_CLOSE, MESSAGE_TYPE_DATA, MESSAGE_TYPE_KEEPALIVE,
MESSAGE_TYPE_NODE_INFO, MESSAGE_TYPE_NODE_INFO,
}, },
net::{mapped_addr, Socket}, net::{mapped_addr, parse_listen, Socket},
payload::Protocol, payload::Protocol,
poll::{WaitImpl, WaitResult}, poll::{WaitImpl, WaitResult},
port_forwarding::PortForwarding, port_forwarding::PortForwarding,
@ -222,11 +222,26 @@ impl<D: Device, P: Protocol, S: Socket, TS: TimeSource> GenericCloud<D, P, S, TS
pub fn reset_own_addresses(&mut self) -> io::Result<()> { pub fn reset_own_addresses(&mut self) -> io::Result<()> {
self.own_addresses.clear(); self.own_addresses.clear();
self.own_addresses.push(self.socket.address().map(mapped_addr)?); if self.config.advertise_addresses.len() > 0 &&
if let Some(ref pfw) = self.port_forwarding { !self.config.listen.starts_with("ws://") {
self.own_addresses.push(pfw.get_internal_ip().into()); // Force advertised addresses based on configuration instead
self.own_addresses.push(pfw.get_external_ip().into()); // of discovery. Note: Disables port forwarding
} // Because the listen config may contain a color (aka
// both address and port are specified) we parse it and
// then extract just the port.
let sockaddr = parse_listen(&self.config.listen);
let port = sockaddr.port();
for address in &self.config.advertise_addresses {
let sockaddr = try_fail!(SocketAddr::from_str(&format!("{}:{}", address, port)), "Invalid IP Address or port {}");
self.own_addresses.push(sockaddr);
}
} else {
self.own_addresses.push(self.socket.address().map(mapped_addr)?);
if let Some(ref pfw) = self.port_forwarding {
self.own_addresses.push(pfw.get_internal_ip().into());
self.own_addresses.push(pfw.get_external_ip().into());
}
}
debug!("Own addresses: {:?}", self.own_addresses); debug!("Own addresses: {:?}", self.own_addresses);
// TODO: detect address changes and call event // TODO: detect address changes and call event
Ok(()) Ok(())

View File

@ -19,6 +19,7 @@ pub struct Config {
pub fix_rp_filter: bool, pub fix_rp_filter: bool,
pub ip: Option<String>, pub ip: Option<String>,
pub advertise_addresses: Vec<String>,
pub ifup: Option<String>, pub ifup: Option<String>,
pub ifdown: Option<String>, pub ifdown: Option<String>,
@ -56,6 +57,7 @@ impl Default for Config {
device_path: None, device_path: None,
fix_rp_filter: false, fix_rp_filter: false,
ip: None, ip: None,
advertise_addresses: vec![],
ifup: None, ifup: None,
ifdown: None, ifdown: None,
crypto: CryptoConfig::default(), crypto: CryptoConfig::default(),
@ -105,6 +107,9 @@ impl Config {
if let Some(val) = file.ip { if let Some(val) = file.ip {
self.ip = Some(val); self.ip = Some(val);
} }
if let Some(mut val) = file.advertise_addresses {
self.advertise_addresses.append(&mut val);
}
if let Some(val) = file.ifup { if let Some(val) = file.ifup {
self.ifup = Some(val); self.ifup = Some(val);
} }
@ -212,6 +217,7 @@ impl Config {
if let Some(val) = args.ifup { if let Some(val) = args.ifup {
self.ifup = Some(val); self.ifup = Some(val);
} }
self.advertise_addresses.append(&mut args.advertise_addresses);
if let Some(val) = args.ifdown { if let Some(val) = args.ifdown {
self.ifdown = Some(val); self.ifdown = Some(val);
} }
@ -318,6 +324,7 @@ impl Config {
ifup: self.ifup, ifup: self.ifup,
ifdown: self.ifdown, ifdown: self.ifdown,
ip: self.ip, ip: self.ip,
advertise_addresses: Some(self.advertise_addresses),
keepalive: self.keepalive, keepalive: self.keepalive,
listen: Some(self.listen), listen: Some(self.listen),
mode: Some(self.mode), mode: Some(self.mode),
@ -467,6 +474,10 @@ pub struct Args {
#[structopt(long)] #[structopt(long)]
pub ip: Option<String>, pub ip: Option<String>,
/// A list of IP Addresses to advertise as our external address(s)
#[structopt(long = "advertise_addresses", use_delimiter = true)]
pub advertise_addresses: Vec<String>,
/// A command to setup the network interface /// A command to setup the network interface
#[structopt(long)] #[structopt(long)]
pub ifup: Option<String>, pub ifup: Option<String>,
@ -606,6 +617,7 @@ pub struct ConfigFile {
pub device: Option<ConfigFileDevice>, pub device: Option<ConfigFileDevice>,
pub ip: Option<String>, pub ip: Option<String>,
pub advertise_addresses: Option<Vec<String>>,
pub ifup: Option<String>, pub ifup: Option<String>,
pub ifdown: Option<String>, pub ifdown: Option<String>,
@ -638,6 +650,9 @@ device:
name: vpncloud%d name: vpncloud%d
path: /dev/net/tun path: /dev/net/tun
ip: 10.0.1.1/16 ip: 10.0.1.1/16
advertise-addresses:
- 192.168.0.1
- 192.168.1.1
ifup: ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up ifup: ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up
ifdown: 'true' ifdown: 'true'
peers: peers:
@ -673,6 +688,7 @@ statsd:
fix_rp_filter: None fix_rp_filter: None
}), }),
ip: Some("10.0.1.1/16".to_string()), ip: Some("10.0.1.1/16".to_string()),
advertise_addresses: Some(vec!["192.168.0.1".to_string(), "192.168.1.1".to_string()]),
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()), ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
ifdown: Some("true".to_string()), ifdown: Some("true".to_string()),
crypto: CryptoConfig::default(), crypto: CryptoConfig::default(),
@ -721,6 +737,7 @@ fn config_merge() {
fix_rp_filter: None, fix_rp_filter: None,
}), }),
ip: None, ip: None,
advertise_addresses: Some(vec![]),
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()), ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
ifdown: Some("true".to_string()), ifdown: Some("true".to_string()),
crypto: CryptoConfig::default(), crypto: CryptoConfig::default(),
@ -757,6 +774,7 @@ fn config_merge() {
device_name: "vpncloud%d".to_string(), device_name: "vpncloud%d".to_string(),
device_path: None, device_path: None,
ip: None, ip: None,
advertise_addresses: vec![],
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()), ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
ifdown: Some("true".to_string()), ifdown: Some("true".to_string()),
listen: "3210".to_string(), listen: "3210".to_string(),
@ -816,6 +834,8 @@ fn config_merge() {
device_path: Some("/dev/null".to_string()), device_path: Some("/dev/null".to_string()),
fix_rp_filter: false, fix_rp_filter: false,
ip: None, ip: None,
advertise_addresses: vec![],
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()), ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
ifdown: Some("ifconfig $IFNAME down".to_string()), ifdown: Some("ifconfig $IFNAME down".to_string()),
crypto: CryptoConfig { password: Some("anothersecret".to_string()), ..CryptoConfig::default() }, crypto: CryptoConfig { password: Some("anothersecret".to_string()), ..CryptoConfig::default() },

View File

@ -109,6 +109,7 @@ impl OldConfigFile {
ifdown: self.ifdown, ifdown: self.ifdown,
ifup: self.ifup, ifup: self.ifup,
ip: None, ip: None,
advertise_addresses: None,
keepalive: self.keepalive, keepalive: self.keepalive,
listen: self.listen.or(self.port.map(|p| format!("{}", p))), listen: self.listen.or(self.port.map(|p| format!("{}", p))),
mode: self.mode, mode: self.mode,