Add Support for IPV6 and Arbitrary Server Address

Add IPV6 support for Apple Devices
Note: Works in GUI not CLI
Adds Support for Arbitrary Server Address
This commit is contained in:
Jett Chen 2024-02-02 14:48:13 +08:00 committed by Conrad Kramer
parent cca5999214
commit 2088ae6ede
20 changed files with 276 additions and 56 deletions

View file

@ -31,7 +31,7 @@ struct BurrowStartRequest: Codable {
let no_pi: Bool let no_pi: Bool
let tun_excl: Bool let tun_excl: Bool
let tun_retrieve: Bool let tun_retrieve: Bool
let address: String? let address: [String]
} }
struct StartOptions: Codable { struct StartOptions: Codable {
let tun: TunOptions let tun: TunOptions
@ -51,7 +51,7 @@ struct BurrowResult<T>: Codable where T: Codable {
struct ServerConfigData: Codable { struct ServerConfigData: Codable {
struct InternalConfig: Codable { struct InternalConfig: Codable {
let address: String? let address: [String]
let name: String? let name: String?
let mtu: Int32? let mtu: Int32?
} }

View file

@ -31,7 +31,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
command: BurrowStartRequest( command: BurrowStartRequest(
Start: BurrowStartRequest.StartOptions( Start: BurrowStartRequest.StartOptions(
tun: BurrowStartRequest.TunOptions( tun: BurrowStartRequest.TunOptions(
name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: nil name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: []
) )
) )
) )
@ -46,12 +46,21 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? { private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
let cfig = from.ServerConfig let cfig = from.ServerConfig
guard let addr = cfig.address else {
return nil
}
// Using a makeshift remote tunnel address
let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1") let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
nst.ipv4Settings = NEIPv4Settings(addresses: [addr], subnetMasks: ["255.255.255.0"]) var v4Addresses = [String]()
var v6Addresses = [String]()
for addr in cfig.address {
if IPv4Address(addr) != nil {
v6Addresses.append(addr)
}
if IPv6Address(addr) != nil {
v4Addresses.append(addr)
}
}
nst.ipv4Settings = NEIPv4Settings(addresses: v4Addresses, subnetMasks: v4Addresses.map { _ in
"255.255.255.0"
})
nst.ipv6Settings = NEIPv6Settings(addresses: v6Addresses, networkPrefixLengths: v6Addresses.map { _ in 64 })
logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)") logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)")
return nst return nst
} }

16
Cargo.lock generated
View file

@ -1074,7 +1074,7 @@ dependencies = [
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"socket2 0.5.5", "socket2",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@ -2114,16 +2114,6 @@ version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
[[package]]
name = "socket2"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.5.5" version = "0.5.5"
@ -2305,7 +2295,7 @@ dependencies = [
"mio", "mio",
"num_cpus", "num_cpus",
"pin-project-lite", "pin-project-lite",
"socket2 0.5.5", "socket2",
"tokio-macros", "tokio-macros",
"tracing", "tracing",
"windows-sys 0.48.0", "windows-sys 0.48.0",
@ -2547,7 +2537,7 @@ dependencies = [
"reqwest", "reqwest",
"schemars", "schemars",
"serde", "serde",
"socket2 0.4.10", "socket2",
"ssri", "ssri",
"tempfile", "tempfile",
"tokio", "tokio",

View file

@ -1,4 +1,4 @@
FROM docker.io/library/rust:1.74.0-slim-bookworm AS builder FROM docker.io/library/rust:1.76.0-slim-bookworm AS builder
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG LLVM_VERSION=16 ARG LLVM_VERSION=16

View file

@ -1,4 +1,4 @@
tun_num := $(shell ifconfig | awk -F 'utun|[: ]' '/utun[0-9]/ {print $$2}' | tail -n 1) tun := $(shell ifconfig -l | sed 's/ /\n/g' | grep utun | tail -n 1)
cargo_console := RUST_BACKTRACE=1 RUST_LOG=debug RUSTFLAGS='--cfg tokio_unstable' cargo run --all-features cargo_console := RUST_BACKTRACE=1 RUST_LOG=debug RUSTFLAGS='--cfg tokio_unstable' cargo run --all-features
cargo_norm := RUST_BACKTRACE=1 RUST_LOG=debug cargo run cargo_norm := RUST_BACKTRACE=1 RUST_LOG=debug cargo run
@ -19,15 +19,28 @@ start:
test-dns: test-dns:
@sudo route delete 8.8.8.8 @sudo route delete 8.8.8.8
@sudo route add 8.8.8.8 -interface utun$(tun_num) @sudo route add 8.8.8.8 -interface $(tun)
@dig @8.8.8.8 hackclub.com @dig @8.8.8.8 hackclub.com
test-https: test-https:
@sudo route delete 193.183.0.162 @sudo route delete 193.183.0.162
@sudo route add 193.183.0.162 -interface utun$(tun_num) @sudo route add 193.183.0.162 -interface $(tun)
@curl -vv https://search.marginalia.nu @curl -vv https://search.marginalia.nu
v4_target := 146.190.62.39
test-http: test-http:
@sudo route delete 146.190.62.39 @sudo route delete ${v4_target}
@sudo route add 146.190.62.39 -interface utun$(tun_num) @sudo route add ${v4_target} -interface $(tun)
@curl -vv 146.190.62.39:80 @curl -vv ${v4_target}:80
test-ipv4:
@sudo route delete ${v4_target}
@sudo route add ${v4_target} -interface $(tun)
@ping ${v4_target}
v6_target := 2001:4860:4860::8888
test-ipv6:
@sudo route delete ${v6_target}
@sudo route -n add -inet6 ${v6_target} -interface $(tun)
@echo preparing
@sudo ping6 -v ${v6_target}

38
burrow-server-compose.yml Normal file
View file

@ -0,0 +1,38 @@
version: "2.1"
networks:
wg6:
enable_ipv6: true
ipam:
driver: default
config:
- subnet: "aa:bb:cc:de::/64"
services:
burrow:
image: lscr.io/linuxserver/wireguard:latest
privileged: true
container_name: burrow_server
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Calcutta
- SERVERURL=wg.burrow.rs
- SERVERPORT=51820
- PEERS=10
- PEERDNS=1.1.1.1
- INTERNAL_SUBNET=10.13.13.0
- ALLOWEDIPS=0.0.0.0/0, ::/0
- PERSISTENTKEEPALIVE_PEERS=all
- LOG_CONFS=true #optional
volumes:
- ./config:/config
- /lib/modules:/lib/modules
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.eth0.proxy_ndp=1
restart: unless-stopped

View file

@ -57,7 +57,7 @@ impl TryFrom<&TunInterface> for ServerInfo {
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
pub struct ServerConfig { pub struct ServerConfig {
pub address: Option<String>, pub address: Vec<String>,
pub name: Option<String>, pub name: Option<String>,
pub mtu: Option<i32>, pub mtu: Option<i32>,
} }
@ -65,7 +65,7 @@ pub struct ServerConfig {
impl Default for ServerConfig { impl Default for ServerConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
address: Some("10.13.13.2".to_string()), // Dummy remote address address: vec!["10.13.13.2".to_string()], // Dummy remote address
name: None, name: None,
mtu: None, mtu: None,
} }

View file

@ -2,4 +2,4 @@
source: burrow/src/daemon/command.rs source: burrow/src/daemon/command.rs
expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions {\n tun: TunOptions { ..TunOptions::default() },\n })).unwrap()" expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions {\n tun: TunOptions { ..TunOptions::default() },\n })).unwrap()"
--- ---
{"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":null}}} {"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":[]}}}

View file

@ -2,4 +2,4 @@
source: burrow/src/daemon/command.rs source: burrow/src/daemon/command.rs
expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions::default())).unwrap()" expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions::default())).unwrap()"
--- ---
{"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":null}}} {"Start":{"tun":{"name":null,"no_pi":false,"tun_excl":false,"tun_retrieve":false,"address":[]}}}

View file

@ -2,4 +2,4 @@
source: burrow/src/daemon/response.rs source: burrow/src/daemon/response.rs
expression: "serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData,\n String>(DaemonResponseData::ServerConfig(ServerConfig::default()))))?" expression: "serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData,\n String>(DaemonResponseData::ServerConfig(ServerConfig::default()))))?"
--- ---
{"result":{"Ok":{"ServerConfig":{"address":"10.13.13.2","name":null,"mtu":null}}},"id":0} {"result":{"Ok":{"ServerConfig":{"address":["10.13.13.2"],"name":null,"mtu":null}}},"id":0}

View file

@ -55,7 +55,7 @@ async fn try_start() -> Result<()> {
let mut client = DaemonClient::new().await?; let mut client = DaemonClient::new().await?;
client client
.send_command(DaemonCommand::Start(DaemonStartOptions { .send_command(DaemonCommand::Start(DaemonStartOptions {
tun: TunOptions::new().address("10.13.13.2"), tun: TunOptions::new().address(vec!["10.13.13.2", "::2"]),
})) }))
.await .await
.map(|_| ()) .map(|_| ())

View file

@ -39,6 +39,7 @@ pub fn initialize() {
tracing_subscriber::fmt::layer() tracing_subscriber::fmt::layer()
.with_level(true) .with_level(true)
.with_writer(std::io::stderr) .with_writer(std::io::stderr)
.with_line_number(true)
.compact() .compact()
.with_filter(EnvFilter::from_default_env()) .with_filter(EnvFilter::from_default_env())
}); });

View file

@ -42,7 +42,7 @@ pub struct Peer {
pub struct Interface { pub struct Interface {
pub private_key: String, pub private_key: String,
pub address: String, pub address: Vec<String>,
pub listen_port: u32, pub listen_port: u32,
pub dns: Vec<String>, pub dns: Vec<String>,
pub mtu: Option<u32>, pub mtu: Option<u32>,
@ -93,8 +93,8 @@ impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
interface: Interface { interface: Interface {
private_key: "GNqIAOCRxjl/cicZyvkvpTklgQuUmGUIEkH7IXF/sEE=".into(), private_key: "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=".into(),
address: "10.13.13.2/24".into(), address: vec!["10.13.13.2/24".into()],
listen_port: 51820, listen_port: 51820,
dns: Default::default(), dns: Default::default(),
mtu: Default::default(), mtu: Default::default(),
@ -102,8 +102,8 @@ impl Default for Config {
peers: vec![Peer { peers: vec![Peer {
endpoint: "wg.burrow.rs:51820".into(), endpoint: "wg.burrow.rs:51820".into(),
allowed_ips: vec!["8.8.8.8/32".into(), "0.0.0.0/0".into()], allowed_ips: vec!["8.8.8.8/32".into(), "0.0.0.0/0".into()],
public_key: "uy75leriJay0+oHLhRMpV+A5xAQ0hCJ+q7Ww81AOvT4=".into(), public_key: "8GaFjVO6c4luCHG4ONO+1bFG8tO+Zz5/Gy+Geht1USM=".into(),
preshared_key: Some("s7lx/mg+reVEMnGnqeyYOQkzD86n2+gYnx1M9ygi08k=".into()), preshared_key: Some("ha7j4BjD49sIzyF9SNlbueK0AMHghlj6+u0G3bzC698=".into()),
persistent_keepalive: Default::default(), persistent_keepalive: Default::default(),
name: Default::default(), name: Default::default(),
}], }],

21
server_patch.txt Normal file
View file

@ -0,0 +1,21 @@
# Add this to ~/server/wg0.conf upon regeneration
PostUp = iptables -A FORWARD -i %i -j ACCEPT
PostUp = iptables -A FORWARD -o %i -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
PostUp = ip6tables -A FORWARD -i %i -j ACCEPT
PostUp = ip6tables -A FORWARD -o %i -j ACCEPT
PostDown = iptables -D FORWARD -i %i -j ACCEPT
PostDown = iptables -D FORWARD -o %i -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE
PostDown = ip6tables -D FORWARD -i %i -j ACCEPT
PostDown = ip6tables -D FORWARD -o %i -j ACCEPT

View file

@ -7,7 +7,7 @@ edition = "2021"
libc = "0.2" libc = "0.2"
fehler = "1.0" fehler = "1.0"
nix = { version = "0.26", features = ["ioctl"] } nix = { version = "0.26", features = ["ioctl"] }
socket2 = "0.4" socket2 = "0.5"
tokio = { version = "1.28", features = [] } tokio = { version = "1.28", features = [] }
byteorder = "1.4" byteorder = "1.4"
tracing = "0.1" tracing = "0.1"

View file

@ -21,7 +21,7 @@ pub struct TunOptions {
/// (Apple) Retrieve the tun interface /// (Apple) Retrieve the tun interface
pub tun_retrieve: bool, pub tun_retrieve: bool,
/// (Linux) The IP address of the tun interface. /// (Linux) The IP address of the tun interface.
pub address: Option<String>, pub address: Vec<String>,
} }
impl TunOptions { impl TunOptions {
@ -44,8 +44,8 @@ impl TunOptions {
self self
} }
pub fn address(mut self, address: impl ToString) -> Self { pub fn address(mut self, address: Vec<impl ToString>) -> Self {
self.address = Some(address.to_string()); self.address = address.iter().map(|x| x.to_string()).collect();
self self
} }

View file

@ -21,7 +21,7 @@ impl SysControlSocket for socket2::Socket {
unsafe { sys::resolve_ctl_info(self.as_raw_fd(), &mut info as *mut sys::ctl_info)? }; unsafe { sys::resolve_ctl_info(self.as_raw_fd(), &mut info as *mut sys::ctl_info)? };
let (_, addr) = unsafe { let (_, addr) = unsafe {
socket2::SockAddr::init(|addr_storage, len| { socket2::SockAddr::try_init(|addr_storage, len| {
*len = size_of::<sys::sockaddr_ctl>() as u32; *len = size_of::<sys::sockaddr_ctl>() as u32;
let addr: &mut sys::sockaddr_ctl = &mut *addr_storage.cast(); let addr: &mut sys::sockaddr_ctl = &mut *addr_storage.cast();

View file

@ -1,13 +1,11 @@
use std::{ use std::{io::{Error, IoSlice}, mem, net::{Ipv4Addr, SocketAddrV4}, os::fd::{AsRawFd, FromRawFd, RawFd}, ptr};
io::{Error, IoSlice}, use std::net::{IpAddr, Ipv6Addr, SocketAddrV6};
mem, use std::ptr::addr_of;
net::{Ipv4Addr, SocketAddrV4},
os::fd::{AsRawFd, FromRawFd, RawFd},
};
use byteorder::{ByteOrder, NetworkEndian}; use byteorder::{ByteOrder, NetworkEndian};
use fehler::throws; use fehler::throws;
use libc::{c_char, iovec, writev, AF_INET, AF_INET6}; use libc::{c_char, iovec, writev, AF_INET, AF_INET6, sockaddr_in6};
use nix::sys::socket::SockaddrIn6;
use socket2::{Domain, SockAddr, Socket, Type}; use socket2::{Domain, SockAddr, Socket, Type};
use tracing::{self, instrument}; use tracing::{self, instrument};
@ -49,7 +47,7 @@ impl TunInterface {
pub fn retrieve() -> Option<TunInterface> { pub fn retrieve() -> Option<TunInterface> {
(3..100) (3..100)
.filter_map(|fd| unsafe { .filter_map(|fd| unsafe {
let peer_addr = socket2::SockAddr::init(|storage, len| { let peer_addr = socket2::SockAddr::try_init(|storage, len| {
*len = mem::size_of::<sys::sockaddr_ctl>() as u32; *len = mem::size_of::<sys::sockaddr_ctl>() as u32;
libc::getpeername(fd, storage as *mut _, len); libc::getpeername(fd, storage as *mut _, len);
Ok(()) Ok(())
@ -71,9 +69,12 @@ impl TunInterface {
#[throws] #[throws]
fn configure(&self, options: TunOptions) { fn configure(&self, options: TunOptions) {
if let Some(addr) = options.address { for addr in options.address{
if let Ok(addr) = addr.parse() { if let Ok(addr) = addr.parse::<IpAddr>() {
self.set_ipv4_addr(addr)?; match addr {
IpAddr::V4(addr) => {self.set_ipv4_addr(addr)?}
IpAddr::V6(addr) => {self.set_ipv6_addr(addr)?}
}
} }
} }
} }
@ -117,6 +118,14 @@ impl TunInterface {
iff iff
} }
#[throws]
#[instrument]
fn in6_ifreq(&self) -> sys::in6_ifreq {
let mut iff: sys::in6_ifreq = unsafe { mem::zeroed() };
iff.ifr_name = string_to_ifname(&self.name()?);
iff
}
#[throws] #[throws]
#[instrument] #[instrument]
pub fn set_ipv4_addr(&self, addr: Ipv4Addr) { pub fn set_ipv4_addr(&self, addr: Ipv4Addr) {
@ -136,6 +145,21 @@ impl TunInterface {
Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr)) Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr))
} }
#[throws]
pub fn set_ipv6_addr(&self, addr: Ipv6Addr) {
// let addr = SockAddr::from(SocketAddrV6::new(addr, 0, 0, 0));
// println!("addr: {:?}", addr);
// let mut iff = self.in6_ifreq()?;
// let sto = addr.as_storage();
// let ifadddr_ptr: *const sockaddr_in6 = addr_of!(sto).cast();
// iff.ifr_ifru.ifru_addr = unsafe { *ifadddr_ptr };
// println!("ifru addr set");
// println!("{:?}", sys::SIOCSIFADDR_IN6);
// self.perform6(|fd| unsafe { sys::if_set_addr6(fd, &iff) })?;
// tracing::info!("ipv6_addr_set");
tracing::warn!("Setting IPV6 address on MacOS CLI mode is not supported yet.");
}
#[throws] #[throws]
fn perform<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R { fn perform<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R {
let span = tracing::info_span!("perform", fd = self.as_raw_fd()); let span = tracing::info_span!("perform", fd = self.as_raw_fd());
@ -145,6 +169,15 @@ impl TunInterface {
perform(socket.as_raw_fd())? perform(socket.as_raw_fd())?
} }
#[throws]
fn perform6<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R {
let span = tracing::info_span!("perform6", fd = self.as_raw_fd());
let _enter = span.enter();
let socket = Socket::new(Domain::IPV6, Type::DGRAM, None)?;
perform(socket.as_raw_fd())?
}
#[throws] #[throws]
#[instrument] #[instrument]
pub fn mtu(&self) -> i32 { pub fn mtu(&self) -> i32 {

View file

@ -1,6 +1,6 @@
use std::mem; use std::mem;
use libc::{c_char, c_int, c_short, c_uint, c_ulong, sockaddr}; use libc::{c_char, c_int, c_short, c_uint, c_ulong, sockaddr, sockaddr_in6, time_t};
pub use libc::{ pub use libc::{
c_void, c_void,
sockaddr_ctl, sockaddr_ctl,
@ -23,6 +23,7 @@ pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
pub const UTUN_OPT_IFNAME: libc::c_int = 2; pub const UTUN_OPT_IFNAME: libc::c_int = 2;
pub const MAX_KCTL_NAME: usize = 96; pub const MAX_KCTL_NAME: usize = 96;
pub const SCOPE6_ID_MAX: usize = 16;
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -74,7 +75,107 @@ pub struct ifreq {
pub ifr_ifru: ifr_ifru, pub ifr_ifru: ifr_ifru,
} }
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct in6_addrlifetime{
pub ia6t_expire: time_t,
pub ia6t_preferred: time_t,
pub ia6t_vltime: u32,
pub ia6t_pltime: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct in6_ifstat {
pub ifs6_in_receive: u64,
pub ifs6_in_hdrerr: u64,
pub ifs6_in_toobig: u64,
pub ifs6_in_noroute: u64,
pub ifs6_in_addrerr: u64,
pub ifs6_in_protounknown: u64,
pub ifs6_in_truncated: u64,
pub ifs6_in_discard: u64,
pub ifs6_in_deliver: u64,
pub ifs6_out_forward: u64,
pub ifs6_out_request: u64,
pub ifs6_out_discard: u64,
pub ifs6_out_fragok: u64,
pub ifs6_out_fragfail: u64,
pub ifs6_out_fragcreat: u64,
pub ifs6_reass_reqd: u64,
pub ifs6_reass_ok: u64,
pub ifs6_atmfrag_rcvd: u64,
pub ifs6_reass_fail: u64,
pub ifs6_in_mcast: u64,
pub ifs6_out_mcast: u64,
pub ifs6_cantfoward_icmp6: u64,
pub ifs6_addr_expiry_cnt: u64,
pub ifs6_pfx_expiry_cnt: u64,
pub ifs6_defrtr_expiry_cnt: u64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct icmp6_ifstat {
pub ifs6_in_msg: u64,
pub ifs6_in_error: u64,
pub ifs6_in_dstunreach: u64,
pub ifs6_in_adminprohib: u64,
pub ifs6_in_timeexceed: u64,
pub ifs6_in_paramprob: u64,
pub ifs6_in_pkttoobig: u64,
pub ifs6_in_echo: u64,
pub ifs6_in_echoreply: u64,
pub ifs6_in_routersolicit: u64,
pub ifs6_in_routeradvert: u64,
pub ifs6_in_neighborsolicit: u64,
pub ifs6_in_neighboradvert: u64,
pub ifs6_in_redirect: u64,
pub ifs6_in_mldquery: u64,
pub ifs6_in_mldreport: u64,
pub ifs6_in_mlddone: u64,
pub ifs6_out_msg: u64,
pub ifs6_out_error: u64,
pub ifs6_out_dstunreach: u64,
pub ifs6_out_adminprohib: u64,
pub ifs6_out_timeexceed: u64,
pub ifs6_out_paramprob: u64,
pub ifs6_out_pkttoobig: u64,
pub ifs6_out_echo: u64,
pub ifs6_out_echoreply: u64,
pub ifs6_out_routersolicit: u64,
pub ifs6_out_routeradvert: u64,
pub ifs6_out_neighborsolicit: u64,
pub ifs6_out_neighboradvert: u64,
pub ifs6_out_redirect: u64,
pub ifs6_out_mldquery: u64,
pub ifs6_out_mldreport: u64,
pub ifs6_out_mlddone: u64,
}
#[repr(C)]
pub union ifr_ifru6 {
pub ifru_addr: sockaddr_in6,
pub ifru_dstaddr: sockaddr_in6,
pub ifru_flags: c_int,
pub ifru_flags6: c_int,
pub ifru_metric: c_int,
pub ifru_intval: c_int,
pub ifru_data: *mut c_char,
pub ifru_lifetime: in6_addrlifetime, // ifru_lifetime
pub ifru_stat: in6_ifstat,
pub ifru_icmp6stat: icmp6_ifstat,
pub ifru_scope_id: [u32; SCOPE6_ID_MAX]
}
#[repr(C)]
pub struct in6_ifreq {
pub ifr_name: [c_char; IFNAMSIZ],
pub ifr_ifru: ifr_ifru6,
}
pub const SIOCSIFADDR: c_ulong = request_code_write!(b'i', 12, mem::size_of::<ifreq>()); pub const SIOCSIFADDR: c_ulong = request_code_write!(b'i', 12, mem::size_of::<ifreq>());
pub const SIOCSIFADDR_IN6: c_ulong = request_code_write!(b'i', 12, mem::size_of::<in6_ifreq>());
pub const SIOCGIFMTU: c_ulong = request_code_readwrite!(b'i', 51, mem::size_of::<ifreq>()); pub const SIOCGIFMTU: c_ulong = request_code_readwrite!(b'i', 51, mem::size_of::<ifreq>());
pub const SIOCSIFMTU: c_ulong = request_code_write!(b'i', 52, mem::size_of::<ifreq>()); pub const SIOCSIFMTU: c_ulong = request_code_write!(b'i', 52, mem::size_of::<ifreq>());
pub const SIOCGIFNETMASK: c_ulong = request_code_readwrite!(b'i', 37, mem::size_of::<ifreq>()); pub const SIOCGIFNETMASK: c_ulong = request_code_readwrite!(b'i', 37, mem::size_of::<ifreq>());
@ -97,5 +198,6 @@ ioctl_read_bad!(if_get_addr, libc::SIOCGIFADDR, ifreq);
ioctl_read_bad!(if_get_mtu, SIOCGIFMTU, ifreq); ioctl_read_bad!(if_get_mtu, SIOCGIFMTU, ifreq);
ioctl_read_bad!(if_get_netmask, SIOCGIFNETMASK, ifreq); ioctl_read_bad!(if_get_netmask, SIOCGIFNETMASK, ifreq);
ioctl_write_ptr_bad!(if_set_addr, SIOCSIFADDR, ifreq); ioctl_write_ptr_bad!(if_set_addr, SIOCSIFADDR, ifreq);
ioctl_write_ptr_bad!(if_set_addr6, SIOCSIFADDR_IN6, in6_ifreq);
ioctl_write_ptr_bad!(if_set_mtu, SIOCSIFMTU, ifreq); ioctl_write_ptr_bad!(if_set_mtu, SIOCSIFMTU, ifreq);
ioctl_write_ptr_bad!(if_set_netmask, SIOCSIFNETMASK, ifreq); ioctl_write_ptr_bad!(if_set_netmask, SIOCSIFNETMASK, ifreq);

View file

@ -1,4 +1,5 @@
use std::{io::Error, net::Ipv4Addr}; use std::{io::Error, net::Ipv4Addr};
use std::net::Ipv6Addr;
use fehler::throws; use fehler::throws;
use tun::TunInterface; use tun::TunInterface;
@ -33,3 +34,15 @@ fn write_packets() {
let bytes_written = tun.send(&buf)?; let bytes_written = tun.send(&buf)?;
assert_eq!(bytes_written, 1504); assert_eq!(bytes_written, 1504);
} }
#[test]
#[throws]
#[ignore = "requires interactivity"]
#[cfg(not(target_os = "windows"))]
fn set_ipv6() {
let tun = TunInterface::new()?;
println!("tun name: {:?}", tun.name()?);
let targ_addr: Ipv6Addr = "::1".parse().unwrap();
println!("v6 addr: {:?}", targ_addr);
tun.set_ipv6_addr(targ_addr)?;
}