Skip to content

Commit

Permalink
Fix DeviceHandle::send_uapi_cmd
Browse files Browse the repository at this point in the history
Previous implementation of api_exec was not flushing the writter after
writing to it. The new one does and hance the internal buffer of
BufWriter is cleared. That caused send_uapi_cmd to always return empty
string. With this fix we correctly return the external buffer to which
BufWritter is writing.
  • Loading branch information
jjanowsk committed Dec 13, 2024
1 parent ff3b555 commit 8a3087b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 14 deletions.
33 changes: 23 additions & 10 deletions neptun/src/device/integration_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ mod tests {

/// Represents a single WireGuard interface on local machine
struct WGHandle {
_device: DeviceHandle,
device: DeviceHandle,
name: String,
addr_v4: IpAddr,
addr_v6: IpAddr,
Expand Down Expand Up @@ -278,9 +278,9 @@ mod tests {
fn init_with_config(addr_v4: IpAddr, addr_v6: IpAddr, config: DeviceConfig) -> WGHandle {
// Generate a new name, utun100+ should work on macOS and Linux
let name = format!("utun{}", NEXT_IFACE_IDX.fetch_add(1, Ordering::Relaxed));
let _device = DeviceHandle::new(&name, config).unwrap();
let device = DeviceHandle::new(&name, config).unwrap();
WGHandle {
_device,
device,
name,
addr_v4,
addr_v6,
Expand Down Expand Up @@ -398,7 +398,11 @@ mod tests {
}
}

fn wg_uapi_cmd(&self, cmd: &str) -> String {
fn wg_uapi_device_cmd(&self, cmd: &str) -> String {
self.device.send_uapi_cmd(cmd)
}

fn wg_uapi_socket_cmd(&self, cmd: &str) -> String {
let path = format!("/var/run/wireguard/{}.sock", self.name);
let mut socket = UnixStream::connect(path).unwrap();
socket.write(cmd.as_bytes()).unwrap();
Expand All @@ -411,12 +415,12 @@ mod tests {

/// Issue a get command on the interface
fn wg_get(&self) -> String {
self.wg_uapi_cmd("get=1\n\n")
self.wg_uapi_socket_cmd("get=1\n\n")
}

/// Issue a set command on the interface
fn wg_set(&self, setting: &str) -> String {
self.wg_uapi_cmd(&format!("set=1\n{}\n\n", setting))
self.wg_uapi_socket_cmd(&format!("set=1\n{}\n\n", setting))
}

/// Assign a listen_port to the interface
Expand Down Expand Up @@ -473,15 +477,24 @@ mod tests {
assert!(response.ends_with("errno=0\n\n"));
}

#[test]
#[ignore]
/// Test that send_uapi_cmd interface works corretly
fn test_wireguard_get_on_device() {
let wg = WGHandle::init("192.0.2.0".parse().unwrap(), "::2".parse().unwrap());
let response = wg.wg_uapi_device_cmd("get=1\n\n");
assert!(response.ends_with("errno=0\n\n"));
}

#[test]
#[ignore]
fn test_wireguard_uapi_chaining() {
let wg = WGHandle::init("192.0.2.0".parse().unwrap(), "::2".parse().unwrap());

let response = wg.wg_uapi_cmd("get=1\n\nget=1\n\n");
let response = wg.wg_uapi_socket_cmd("get=1\n\nget=1\n\n");
assert_eq!(response.matches("errno=0\n\n").count(), 2);

let response = wg.wg_uapi_cmd("get=1\n\nset=1\nlisten_port=12345\n\nget=1\n\n");
let response = wg.wg_uapi_socket_cmd("get=1\n\nset=1\nlisten_port=12345\n\nget=1\n\n");
assert_eq!(response.matches("errno=0\n\n").count(), 3);
}

Expand All @@ -494,9 +507,9 @@ mod tests {
// because the \n\n is missing, wireguard-go seems to accept it. That's why
// we accept it too. This test tests that the last character is not being clipped
// as it was done by the previous implementation.
let response = wg.wg_uapi_cmd("set=1\nlisten_port=12345");
let response = wg.wg_uapi_socket_cmd("set=1\nlisten_port=12345");
assert_eq!(response, "errno=0\n\n");
let response = wg.wg_uapi_cmd("get=1\n");
let response = wg.wg_uapi_socket_cmd("get=1\n");
assert_eq!(response, "listen_port=12345\nerrno=0\n\n");
}

Expand Down
11 changes: 7 additions & 4 deletions neptun/src/device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,13 @@ impl DeviceHandle {
}

pub fn send_uapi_cmd(&self, cmd: &str) -> String {
let mut reader = BufReader::new(cmd.as_bytes());
let mut writer = BufWriter::new(Vec::<u8>::new());
api::api_exec(&mut self.device.read(), &mut reader, &mut writer);
std::str::from_utf8(writer.buffer()).unwrap().to_owned()
let mut response = Vec::<u8>::new();
{
let mut reader = BufReader::new(cmd.as_bytes());
let mut writer = BufWriter::new(&mut response);
api::api_exec(&mut self.device.read(), &mut reader, &mut writer);
}
std::str::from_utf8(&response).unwrap().to_owned()
}

pub fn trigger_exit(&self) {
Expand Down

0 comments on commit 8a3087b

Please sign in to comment.