diff --git a/src/config.rs b/src/config.rs index 3c4cb13..a332cca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,6 +17,7 @@ use siphasher::sip::SipHasher24; pub struct Config { pub device_type: Type, pub device_name: String, + pub device_path: Option, pub ifup: Option, pub ifdown: Option, pub crypto: CryptoMethod, @@ -40,7 +41,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { Config { - device_type: Type::Tap, device_name: "vpncloud%d".to_string(), + device_type: Type::Tap, device_name: "vpncloud%d".to_string(), device_path: None, ifup: None, ifdown: None, crypto: CryptoMethod::ChaCha20, shared_key: None, magic: None, @@ -65,6 +66,9 @@ impl Config { if let Some(val) = file.device_name { self.device_name = val; } + if let Some(val) = file.device_path { + self.device_path = Some(val); + } if let Some(val) = file.ifup { self.ifup = Some(val); } @@ -125,6 +129,9 @@ impl Config { if let Some(val) = args.flag_device { self.device_name = val; } + if let Some(val) = args.flag_device_path { + self.device_path = Some(val); + } if let Some(val) = args.flag_ifup { self.ifup = Some(val); } @@ -213,6 +220,7 @@ impl Config { pub struct ConfigFile { pub device_type: Option, pub device_name: Option, + pub device_path: Option, pub ifup: Option, pub ifdown: Option, pub crypto: Option, diff --git a/src/device.rs b/src/device.rs index 3d333f7..21f3ef9 100644 --- a/src/device.rs +++ b/src/device.rs @@ -47,6 +47,7 @@ pub struct Device { type_: Type, } + impl Device { /// Creates a new tun/tap device /// @@ -67,11 +68,12 @@ impl Device { /// /// # Panics /// This method panics if the interface name is longer than 31 bytes. - pub fn new(ifname: &str, type_: Type) -> io::Result { + pub fn new(ifname: &str, type_: Type, path: Option<&str>) -> io::Result { + let path = path.unwrap_or_else(|| Self::default_path(type_)); if type_ == Type::Dummy { - return Self::dummy(ifname, "/dev/null", type_); + return Self::dummy(ifname, path, type_); } - let fd = try!(fs::OpenOptions::new().read(true).write(true).open("/dev/net/tun")); + let fd = try!(fs::OpenOptions::new().read(true).write(true).open(path)); // Add trailing \0 to interface name let mut ifname_string = String::with_capacity(32); ifname_string.push_str(ifname); @@ -95,6 +97,15 @@ impl Device { } } + /// Returns the default device path for a given type + #[inline] + pub fn default_path(type_: Type) -> &'static str { + match type_ { + Type::Tun | Type::Tap => "/dev/net/tun", + Type::Dummy => "/dev/null" + } + } + /// Returns the interface name of this device. #[inline] pub fn ifname(&self) -> &str { diff --git a/src/main.rs b/src/main.rs index 1835757..6cc2159 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,6 +68,7 @@ static USAGE: &'static str = include_str!("usage.txt"); pub struct Args { flag_config: Option, flag_type: Option, + flag_device_path: Option, flag_mode: Option, flag_shared_key: Option, flag_crypto: Option, @@ -204,7 +205,7 @@ impl AnyCloud

{ fn run (config: Config) { - let device = try_fail!(Device::new(&config.device_name, config.device_type), + let device = try_fail!(Device::new(&config.device_name, config.device_type, config.device_path.as_ref().map(|s| s as &str)), "Failed to open virtual {} interface {}: {}", config.device_type, config.device_name); info!("Opened device {}", device.ifname()); let mut ranges = Vec::with_capacity(config.subnets.len()); diff --git a/src/tests.rs b/src/tests.rs index ecde278..2f5e74b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -446,6 +446,7 @@ fn config_file() { let config_file = " device_type: tun device_name: vpncloud%d +device_path: /dev/net/tun magic: 0123ABCD ifup: ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up ifdown: 'true' @@ -470,6 +471,7 @@ stats_file: /var/log/vpncloud.stats assert_eq!(serde_yaml::from_str::(config_file).unwrap(), ConfigFile{ device_type: Some(Type::Tun), device_name: Some("vpncloud%d".to_string()), + device_path: Some("/dev/net/tun".to_string()), ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()), ifdown: Some("true".to_string()), crypto: Some(CryptoMethod::AES256), @@ -496,6 +498,7 @@ fn config_merge() { config.merge_file(ConfigFile{ device_type: Some(Type::Tun), device_name: Some("vpncloud%d".to_string()), + device_path: None, ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()), ifdown: Some("true".to_string()), crypto: Some(CryptoMethod::AES256), @@ -517,6 +520,7 @@ fn config_merge() { assert_eq!(config, Config{ device_type: Type::Tun, device_name: "vpncloud%d".to_string(), + device_path: None, ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()), ifdown: Some("true".to_string()), magic: Some("0123ABCD".to_string()), @@ -539,6 +543,7 @@ fn config_merge() { config.merge_args(Args{ flag_type: Some(Type::Tap), flag_device: Some("vpncloud0".to_string()), + flag_device_path: Some("/dev/null".to_string()), flag_ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()), flag_ifdown: Some("ifconfig $IFNAME down".to_string()), flag_crypto: Some(CryptoMethod::ChaCha20), @@ -562,6 +567,7 @@ fn config_merge() { assert_eq!(config, Config{ device_type: Type::Tap, device_name: "vpncloud0".to_string(), + device_path: Some("/dev/null".to_string()), ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()), ifdown: Some("ifconfig $IFNAME down".to_string()), magic: Some("hash:mynet".to_string()), diff --git a/src/usage.txt b/src/usage.txt index c971ebe..e095665 100644 --- a/src/usage.txt +++ b/src/usage.txt @@ -5,6 +5,7 @@ Options: --config Read configuration options from the specified file. -t , --type Set the type of network ("tap" or "tun"). + --device-path Set the path of the base device. -d , --device Name of the virtual device. -m , --mode The mode of the VPN ("hub", "switch", "router", or "normal"). diff --git a/vpncloud.md b/vpncloud.md index a90929c..99725ed 100644 --- a/vpncloud.md +++ b/vpncloud.md @@ -25,6 +25,10 @@ vpncloud(1) -- Peer-to-peer VPN Name of the virtual device. Any `%d` will be filled with a free number. [default: `vpncloud%d`] + * `--device-path `: + + The path of the base device inode, e.g. /dev/net/run. + * `-m `, `--mode `: The mode of the VPN. The VPN can like a router, a switch or a hub. A **hub** @@ -270,6 +274,7 @@ detailed descriptions of the options. * `device_type`: Set the type of network. Same as `--type` * `device_name`: Name of the virtual device. Same as `--device` +* `device_path`: Set the path of the base device. Same as `--device-path` * `ifup`: A command to setup the network interface. Same as `--ifup` * `ifdown`: A command to bring down the network interface. Same as `--ifdown` * `crypto`: The encryption method to use. Same as `--crypto`