Skip to content

Commit

Permalink
Use ip -6 addr command for setting ipv6 addr on linux
Browse files Browse the repository at this point in the history
Using tun throws strange I/O errors. There may be a bug related to ipv6
in tun 0.7.10
  • Loading branch information
hulthe committed Jan 9, 2025
1 parent b01de0b commit 020c0a7
Showing 1 changed file with 25 additions and 25 deletions.
50 changes: 25 additions & 25 deletions talpid-tunnel/src/tun_provider/unix.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,22 @@
use super::TunConfig;
#[cfg(target_os = "macos")]
use std::io;
use std::{
net::IpAddr,
ops::Deref,
os::unix::io::{AsRawFd, RawFd},
process::Command,
};
use tun::{AbstractDevice, Configuration};

/// Errors that can occur while setting up a tunnel device.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Failed to set IP address on tunnel device
#[cfg(target_os = "linux")]
#[error("Failed to set IP address on tunnel device")]
SetIp(#[source] tun::Error),

/// Failed to set IPv4 address on tunnel device
#[cfg(target_os = "macos")]
#[error("Failed to set IPv4 address")]
SetIpv4(#[source] tun::Error),

/// Failed to set IPv6 address on tunnel device
#[cfg(target_os = "macos")]
#[error("Failed to set IPv6 address")]
SetIpv6(#[source] io::Error),
SetIpv6(#[source] std::io::Error),

/// Unable to open a tunnel device
#[error("Unable to open a tunnel device")]
Expand Down Expand Up @@ -148,29 +140,37 @@ impl AsRawFd for TunnelDevice {
}

impl TunnelDevice {
#[cfg(target_os = "linux")]
fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> {
self.dev.set_address(ip).map_err(Error::SetIp)?;
Ok(())
}

#[cfg(target_os = "macos")]
fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> {
match ip {
// NOTE: As of `tun 0.7`, `Device::set_address` accepts an `IpAddr` but
// only supports the `IpAddr::V4` address kind and panics if you pass it an
// `IpAddr::V6` value..
IpAddr::V4(ipv4) => {
self.dev.set_address(ipv4.into()).map_err(Error::SetIpv4)?;
}

// NOTE: On MacOs, As of `tun 0.7`, `Device::set_address` accepts an `IpAddr` but
// only supports the `IpAddr::V4` address kind and panics if you pass it an
// `IpAddr::V6` value.
#[cfg(target_os = "macos")]
IpAddr::V6(ipv6) => {
use std::process::Command;
// ifconfig <device> inet6 <ipv6 address> alias
let address = ipv6.to_string();
let ipv6 = ipv6.to_string();
let device = self.dev.tun_name().unwrap(); // TODO: Do not unwrap!
Command::new("ifconfig")
.args([&device, "inet6", &ipv6, "alias"])
.output()
.map_err(Error::SetIpv6)?;
}

// NOTE: On Linux, As of `tun 0.7`, `Device::set_address` throws an I/O error if you
// pass it an IPv6-address.
#[cfg(target_os = "linux")]
IpAddr::V6(ipv6) => {
// ip -6 addr add <ipv6 address> dev <device>
let ipv6 = ipv6.to_string();
let device = self.dev.tun_name().unwrap(); // TODO: Do not unwrap!
let mut ifconfig = Command::new("ifconfig");
ifconfig.args([&device, "inet6", &address, "alias"]);
ifconfig.output().map_err(Error::SetIpv6)?;
Command::new("ip")
.args(["-6", "addr", "add", &ipv6, "dev", &device])
.output()
.map_err(Error::SetIpv6)?;
}
}
Ok(())
Expand Down

0 comments on commit 020c0a7

Please sign in to comment.