diff --git a/Apple/NetworkExtension/DataTypes.swift b/Apple/NetworkExtension/DataTypes.swift index 391bfed..1409fde 100644 --- a/Apple/NetworkExtension/DataTypes.swift +++ b/Apple/NetworkExtension/DataTypes.swift @@ -31,7 +31,7 @@ struct BurrowStartRequest: Codable { let no_pi: Bool let tun_excl: Bool let tun_retrieve: Bool - let address: String? + let address: [String] } struct StartOptions: Codable { let tun: TunOptions @@ -51,7 +51,7 @@ struct BurrowResult: Codable where T: Codable { struct ServerConfigData: Codable { struct InternalConfig: Codable { - let address: String? + let address: [String] let name: String? let mtu: Int32? } diff --git a/Apple/NetworkExtension/PacketTunnelProvider.swift b/Apple/NetworkExtension/PacketTunnelProvider.swift index 9231676..bfdb34a 100644 --- a/Apple/NetworkExtension/PacketTunnelProvider.swift +++ b/Apple/NetworkExtension/PacketTunnelProvider.swift @@ -31,7 +31,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { command: BurrowStartRequest( Start: BurrowStartRequest.StartOptions( 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? { 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") - 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)") return nst } diff --git a/Cargo.lock b/Cargo.lock index 85f11e7..a75bd28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1074,7 +1074,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "socket2", "tokio", "tower-service", "tracing", @@ -2114,16 +2114,6 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "socket2" version = "0.5.5" @@ -2305,7 +2295,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.5", + "socket2", "tokio-macros", "tracing", "windows-sys 0.48.0", @@ -2547,7 +2537,7 @@ dependencies = [ "reqwest", "schemars", "serde", - "socket2 0.4.10", + "socket2", "ssri", "tempfile", "tokio", diff --git a/Dockerfile b/Dockerfile index 3c12d45..9f54478 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 LLVM_VERSION=16 diff --git a/Makefile b/Makefile index 18b4b27..97d2d5a 100644 --- a/Makefile +++ b/Makefile @@ -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_norm := RUST_BACKTRACE=1 RUST_LOG=debug cargo run @@ -19,15 +19,28 @@ start: test-dns: @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 test-https: @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 +v4_target := 146.190.62.39 test-http: - @sudo route delete 146.190.62.39 - @sudo route add 146.190.62.39 -interface utun$(tun_num) - @curl -vv 146.190.62.39:80 + @sudo route delete ${v4_target} + @sudo route add ${v4_target} -interface $(tun) + @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} diff --git a/burrow-server-compose.yml b/burrow-server-compose.yml new file mode 100644 index 0000000..4ba31ee --- /dev/null +++ b/burrow-server-compose.yml @@ -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 \ No newline at end of file diff --git a/burrow/src/daemon/response.rs b/burrow/src/daemon/response.rs index 172d4c7..37ee5d9 100644 --- a/burrow/src/daemon/response.rs +++ b/burrow/src/daemon/response.rs @@ -57,7 +57,7 @@ impl TryFrom<&TunInterface> for ServerInfo { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct ServerConfig { - pub address: Option, + pub address: Vec, pub name: Option, pub mtu: Option, } @@ -65,7 +65,7 @@ pub struct ServerConfig { impl Default for ServerConfig { fn default() -> 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, mtu: None, } diff --git a/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization-2.snap b/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization-2.snap index 0eb9096..f78eeaa 100644 --- a/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization-2.snap +++ b/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization-2.snap @@ -2,4 +2,4 @@ source: burrow/src/daemon/command.rs 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":[]}}} diff --git a/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization.snap b/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization.snap index bfd5117..eee563d 100644 --- a/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization.snap +++ b/burrow/src/daemon/snapshots/burrow__daemon__command__daemoncommand_serialization.snap @@ -2,4 +2,4 @@ source: burrow/src/daemon/command.rs 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":[]}}} diff --git a/burrow/src/daemon/snapshots/burrow__daemon__response__response_serialization-4.snap b/burrow/src/daemon/snapshots/burrow__daemon__response__response_serialization-4.snap index 9752ebc..0b9385c 100644 --- a/burrow/src/daemon/snapshots/burrow__daemon__response__response_serialization-4.snap +++ b/burrow/src/daemon/snapshots/burrow__daemon__response__response_serialization-4.snap @@ -2,4 +2,4 @@ source: burrow/src/daemon/response.rs expression: "serde_json::to_string(&DaemonResponse::new(Ok::(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} diff --git a/burrow/src/main.rs b/burrow/src/main.rs index 79bb70b..71d1c02 100644 --- a/burrow/src/main.rs +++ b/burrow/src/main.rs @@ -55,7 +55,7 @@ async fn try_start() -> Result<()> { let mut client = DaemonClient::new().await?; client .send_command(DaemonCommand::Start(DaemonStartOptions { - tun: TunOptions::new().address("10.13.13.2"), + tun: TunOptions::new().address(vec!["10.13.13.2", "::2"]), })) .await .map(|_| ()) diff --git a/burrow/src/tracing.rs b/burrow/src/tracing.rs index 279f45d..861b41f 100644 --- a/burrow/src/tracing.rs +++ b/burrow/src/tracing.rs @@ -39,6 +39,7 @@ pub fn initialize() { tracing_subscriber::fmt::layer() .with_level(true) .with_writer(std::io::stderr) + .with_line_number(true) .compact() .with_filter(EnvFilter::from_default_env()) }); diff --git a/burrow/src/wireguard/config.rs b/burrow/src/wireguard/config.rs index afe7499..ed7b3cd 100644 --- a/burrow/src/wireguard/config.rs +++ b/burrow/src/wireguard/config.rs @@ -42,7 +42,7 @@ pub struct Peer { pub struct Interface { pub private_key: String, - pub address: String, + pub address: Vec, pub listen_port: u32, pub dns: Vec, pub mtu: Option, @@ -93,8 +93,8 @@ impl Default for Config { fn default() -> Self { Self { interface: Interface { - private_key: "GNqIAOCRxjl/cicZyvkvpTklgQuUmGUIEkH7IXF/sEE=".into(), - address: "10.13.13.2/24".into(), + private_key: "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=".into(), + address: vec!["10.13.13.2/24".into()], listen_port: 51820, dns: Default::default(), mtu: Default::default(), @@ -102,8 +102,8 @@ impl Default for Config { peers: vec![Peer { endpoint: "wg.burrow.rs:51820".into(), allowed_ips: vec!["8.8.8.8/32".into(), "0.0.0.0/0".into()], - public_key: "uy75leriJay0+oHLhRMpV+A5xAQ0hCJ+q7Ww81AOvT4=".into(), - preshared_key: Some("s7lx/mg+reVEMnGnqeyYOQkzD86n2+gYnx1M9ygi08k=".into()), + public_key: "8GaFjVO6c4luCHG4ONO+1bFG8tO+Zz5/Gy+Geht1USM=".into(), + preshared_key: Some("ha7j4BjD49sIzyF9SNlbueK0AMHghlj6+u0G3bzC698=".into()), persistent_keepalive: Default::default(), name: Default::default(), }], diff --git a/server_patch.txt b/server_patch.txt new file mode 100644 index 0000000..de8e14c --- /dev/null +++ b/server_patch.txt @@ -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 \ No newline at end of file diff --git a/tun/Cargo.toml b/tun/Cargo.toml index e67e45f..7413f65 100644 --- a/tun/Cargo.toml +++ b/tun/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" libc = "0.2" fehler = "1.0" nix = { version = "0.26", features = ["ioctl"] } -socket2 = "0.4" +socket2 = "0.5" tokio = { version = "1.28", features = [] } byteorder = "1.4" tracing = "0.1" diff --git a/tun/src/options.rs b/tun/src/options.rs index 339f71a..e21bf5f 100644 --- a/tun/src/options.rs +++ b/tun/src/options.rs @@ -21,7 +21,7 @@ pub struct TunOptions { /// (Apple) Retrieve the tun interface pub tun_retrieve: bool, /// (Linux) The IP address of the tun interface. - pub address: Option, + pub address: Vec, } impl TunOptions { @@ -44,8 +44,8 @@ impl TunOptions { self } - pub fn address(mut self, address: impl ToString) -> Self { - self.address = Some(address.to_string()); + pub fn address(mut self, address: Vec) -> Self { + self.address = address.iter().map(|x| x.to_string()).collect(); self } diff --git a/tun/src/unix/apple/kern_control.rs b/tun/src/unix/apple/kern_control.rs index 76e576f..6075233 100644 --- a/tun/src/unix/apple/kern_control.rs +++ b/tun/src/unix/apple/kern_control.rs @@ -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)? }; let (_, addr) = unsafe { - socket2::SockAddr::init(|addr_storage, len| { + socket2::SockAddr::try_init(|addr_storage, len| { *len = size_of::() as u32; let addr: &mut sys::sockaddr_ctl = &mut *addr_storage.cast(); diff --git a/tun/src/unix/apple/mod.rs b/tun/src/unix/apple/mod.rs index 2787cde..6e859ca 100644 --- a/tun/src/unix/apple/mod.rs +++ b/tun/src/unix/apple/mod.rs @@ -1,13 +1,11 @@ -use std::{ - io::{Error, IoSlice}, - mem, - net::{Ipv4Addr, SocketAddrV4}, - os::fd::{AsRawFd, FromRawFd, RawFd}, -}; +use std::{io::{Error, IoSlice}, mem, net::{Ipv4Addr, SocketAddrV4}, os::fd::{AsRawFd, FromRawFd, RawFd}, ptr}; +use std::net::{IpAddr, Ipv6Addr, SocketAddrV6}; +use std::ptr::addr_of; use byteorder::{ByteOrder, NetworkEndian}; 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 tracing::{self, instrument}; @@ -49,7 +47,7 @@ impl TunInterface { pub fn retrieve() -> Option { (3..100) .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::() as u32; libc::getpeername(fd, storage as *mut _, len); Ok(()) @@ -71,9 +69,12 @@ impl TunInterface { #[throws] fn configure(&self, options: TunOptions) { - if let Some(addr) = options.address { - if let Ok(addr) = addr.parse() { - self.set_ipv4_addr(addr)?; + for addr in options.address{ + if let Ok(addr) = addr.parse::() { + 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 } + #[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] #[instrument] pub fn set_ipv4_addr(&self, addr: Ipv4Addr) { @@ -136,6 +145,21 @@ impl TunInterface { 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] fn perform(&self, perform: impl FnOnce(RawFd) -> Result) -> R { let span = tracing::info_span!("perform", fd = self.as_raw_fd()); @@ -145,6 +169,15 @@ impl TunInterface { perform(socket.as_raw_fd())? } + #[throws] + fn perform6(&self, perform: impl FnOnce(RawFd) -> Result) -> 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] #[instrument] pub fn mtu(&self) -> i32 { diff --git a/tun/src/unix/apple/sys.rs b/tun/src/unix/apple/sys.rs index b4d4a6a..d48d6ee 100644 --- a/tun/src/unix/apple/sys.rs +++ b/tun/src/unix/apple/sys.rs @@ -1,6 +1,6 @@ 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::{ c_void, 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 MAX_KCTL_NAME: usize = 96; +pub const SCOPE6_ID_MAX: usize = 16; #[repr(C)] #[derive(Copy, Clone, Debug)] @@ -74,7 +75,107 @@ pub struct ifreq { 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::()); +pub const SIOCSIFADDR_IN6: c_ulong = request_code_write!(b'i', 12, mem::size_of::()); pub const SIOCGIFMTU: c_ulong = request_code_readwrite!(b'i', 51, mem::size_of::()); pub const SIOCSIFMTU: c_ulong = request_code_write!(b'i', 52, mem::size_of::()); pub const SIOCGIFNETMASK: c_ulong = request_code_readwrite!(b'i', 37, mem::size_of::()); @@ -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_netmask, SIOCGIFNETMASK, 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_netmask, SIOCSIFNETMASK, ifreq); diff --git a/tun/tests/packets.rs b/tun/tests/packets.rs index 28090a2..80c078b 100644 --- a/tun/tests/packets.rs +++ b/tun/tests/packets.rs @@ -1,4 +1,5 @@ use std::{io::Error, net::Ipv4Addr}; +use std::net::Ipv6Addr; use fehler::throws; use tun::TunInterface; @@ -33,3 +34,15 @@ fn write_packets() { let bytes_written = tun.send(&buf)?; 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)?; +} \ No newline at end of file