Skip to content

Commit

Permalink
fix(openconnect): let openconnect use its config
Browse files Browse the repository at this point in the history
- Openconnect will now use the custom config provided to Vopono.
- Openconnect is now able to authenticate with the provided
  password
- It's not possible to provide a username via Vopono to
  Openconnect
- Openconnect will use the optionally provided server, or the
  server from its custom config

Fixes jamesmcm#39
  • Loading branch information
david-jointech committed Jun 28, 2022
1 parent 20ccb31 commit 7614548
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 30 deletions.
35 changes: 25 additions & 10 deletions src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,30 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
.protocol
.unwrap_or_else(|| get_config_file_protocol(path));
provider = VpnProvider::Custom;
// Encode filename with base58 so we can fit it within 16 chars for the veth pair name
let sname = bs58::encode(&path.to_str().unwrap()).into_string();

server_name = sname[0..std::cmp::min(11, sname.len())].to_string();
if protocol != Protocol::OpenConnect {
// Encode filename with base58 so we can fit it within 16 chars for the veth pair name
let sname = bs58::encode(&path.to_str().unwrap()).into_string();

server_name = sname[0..std::cmp::min(11, sname.len())].to_string();
} else {
// For OpenConnect the server-name can be provided via the usual config or
// command-line-options. Since it also can be provided via the custom-config we will
// set an empty-string if it isn't provided.
server_name = command
.server
.or_else(|| {
vopono_config_settings
.get("server")
.map_err(|e| {
debug!("vopono config.toml: {:?}", e);
anyhow!("Failed to read config file")
})
.ok()
})
.or_else(|| Some(String::new()))
.unwrap();
}
} else {
// Get server and provider
provider = command
Expand Down Expand Up @@ -251,12 +271,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
}?;
Some(get_config_from_alias(&cdir, &server_name)?)
} else {
// Config file required for non OpenConnect custom providers
if protocol != Protocol::OpenConnect {
Some(custom_config.expect("No custom config provided"))
} else {
None
}
Some(custom_config.expect("No custom config provided"))
};

// Better to check for lockfile exists?
Expand Down Expand Up @@ -379,7 +394,7 @@ pub fn exec(command: ExecCommand) -> anyhow::Result<()> {
// TODO: DNS suffixes?
ns.dns_config(&dns, &[], command.hosts_entries.as_ref())?;
ns.run_openconnect(
config_file,
config_file.expect("No OpenConnect config file provided"),
command.open_ports.as_ref(),
command.forward_ports.as_ref(),
firewall,
Expand Down
3 changes: 2 additions & 1 deletion src/netns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ impl NetworkNamespace {
handle.stdout(Stdio::piped());
handle.stderr(Stdio::piped());
}
handle.stdin(Stdio::piped());

debug!(
"ip netns exec {}{} {}",
Expand Down Expand Up @@ -280,7 +281,7 @@ impl NetworkNamespace {

pub fn run_openconnect(
&mut self,
config_file: Option<PathBuf>,
config_file: PathBuf,
open_ports: Option<&Vec<u16>>,
forward_ports: Option<&Vec<u16>>,
firewall: Firewall,
Expand Down
46 changes: 27 additions & 19 deletions src/openconnect.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use super::firewall::Firewall;
use super::netns::NetworkNamespace;
use anyhow::{anyhow, Context};
use dialoguer::{Input, Password};
use dialoguer::Password;
use log::{debug, error, info};
use serde::{Deserialize, Serialize};
use std::io::Write;
use std::path::{Path, PathBuf};

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -15,7 +16,7 @@ impl OpenConnect {
#[allow(clippy::too_many_arguments)]
pub fn run(
netns: &NetworkNamespace,
config_file: Option<PathBuf>,
config_file: PathBuf,
open_ports: Option<&Vec<u16>>,
forward_ports: Option<&Vec<u16>>,
firewall: Firewall,
Expand All @@ -29,23 +30,34 @@ impl OpenConnect {
));
}

let creds = {
if let Some(config_file) = config_file {
let config_file_path = config_file.canonicalize().context("Invalid path given")?;
get_creds_from_file(&config_file_path)
} else {
request_creds()
}
}?;
let pass = request_creds();

let password = pass.expect("Provide password via Stdin!");

info!("Launching OpenConnect...");
// TODO: Auth
let user_arg = format!("--user={}", creds.0);
let command_vec = (&["openconnect", &user_arg, "--passwd-on-stdin", server]).to_vec();
let mut command_vec = (&[
"openconnect",
"--config",
config_file.to_str().expect("Invalid config path"),
"--passwd-on-stdin",
])
.to_vec();

if !server.is_empty() {
command_vec.push(server.as_ref());
}

let handle = netns
.exec_no_block(&command_vec, None, false, false, None)
.context("Failed to launch OpenConnect - is openconnect installed?")?;

handle
.stdin
.as_ref()
.unwrap()
.write_all(password.as_bytes())
.expect("Failed to write to stdin");

let id = handle.id();

// Allow input to and output from open ports (for port forwarding in tunnel)
Expand Down Expand Up @@ -73,16 +85,12 @@ fn get_creds_from_file(auth_file: &Path) -> anyhow::Result<(String, String)> {
Ok((user.to_string(), pass.to_string()))
}

fn request_creds() -> anyhow::Result<(String, String)> {
let username = Input::<String>::new()
.with_prompt("OpenConnect username")
.interact()?;
let username = username.trim();
fn request_creds() -> anyhow::Result<String> {
let password = Password::new()
.with_prompt("OpenConnect password")
.interact()?;
let password = password.trim();
Ok((username.to_string(), password.to_string()))
Ok(password.to_string())
}

impl Drop for OpenConnect {
Expand Down

0 comments on commit 7614548

Please sign in to comment.