Browse Source

port to windows or macos (#61)

pull/66/head
ssrlive 3 years ago
committed by GitHub
parent
commit
bbb8d3b244
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .github/workflows/format-build.yml
  2. 4
      Cargo.toml
  3. 1
      src/error.rs
  4. 1
      src/lib.rs
  5. 8
      src/main.rs
  6. 59
      src/tun2proxy.rs
  7. 2
      src/virtdns.rs
  8. 1
      tests/proxy.rs

5
.github/workflows/format-build.yml

@ -35,7 +35,10 @@ jobs:
clippy: clippy:
name: Clippy name: Clippy
runs-on: ubuntu-latest strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1

4
Cargo.toml

@ -14,7 +14,6 @@ ctrlc = "3.4"
digest_auth = "0.3" digest_auth = "0.3"
dotenvy = "0.15" dotenvy = "0.15"
env_logger = "0.10" env_logger = "0.10"
fork = "0.1"
hashlink = "0.8" hashlink = "0.8"
httparse = "1.8" httparse = "1.8"
libc = "0.2" libc = "0.2"
@ -29,6 +28,9 @@ trust-dns-proto = "0.23"
unicase = "2.7" unicase = "2.7"
url = "2.4" url = "2.4"
[target.'cfg(target_family="unix")'.dependencies]
fork = "0.1"
[target.'cfg(target_os="android")'.dependencies] [target.'cfg(target_os="android")'.dependencies]
android_logger = "0.13" android_logger = "0.13"
jni = { version = "0.21", default-features = false } jni = { version = "0.21", default-features = false }

1
src/error.rs

@ -52,6 +52,7 @@ pub enum Error {
#[error("{0}")] #[error("{0}")]
String(String), String(String),
#[cfg(target_family = "unix")]
#[error("nix::errno::Errno {0:?}")] #[error("nix::errno::Errno {0:?}")]
OSError(#[from] nix::errno::Errno), OSError(#[from] nix::errno::Errno),

1
src/lib.rs

@ -29,6 +29,7 @@ pub struct Proxy {
pub enum NetworkInterface { pub enum NetworkInterface {
Named(String), Named(String),
#[cfg(target_family = "unix")]
Fd(std::os::fd::RawFd), Fd(std::os::fd::RawFd),
} }

8
src/main.rs

@ -95,11 +95,15 @@ fn main() -> ExitCode {
options = options.with_ipv6_enabled(); options = options.with_ipv6_enabled();
} }
#[allow(unused_assignments)]
let interface = match args.tun_fd { let interface = match args.tun_fd {
None => NetworkInterface::Named(args.tun.clone()), None => NetworkInterface::Named(args.tun.clone()),
Some(fd) => { Some(_fd) => {
options = options.with_mtu(args.tun_mtu); options = options.with_mtu(args.tun_mtu);
NetworkInterface::Fd(fd) #[cfg(not(target_family = "unix"))]
panic!("Not supported");
#[cfg(target_family = "unix")]
NetworkInterface::Fd(_fd)
} }
}; };

59
src/tun2proxy.rs

@ -1,20 +1,32 @@
#![allow(dead_code)]
use crate::{dns, error::Error, error::Result, virtdevice::VirtualTunDevice, NetworkInterface, Options}; use crate::{dns, error::Error, error::Result, virtdevice::VirtualTunDevice, NetworkInterface, Options};
use mio::{event::Event, net::TcpStream, net::UdpSocket, unix::SourceFd, Events, Interest, Poll, Token}; #[cfg(target_family = "unix")]
use mio::unix::SourceFd;
use mio::{event::Event, net::TcpStream, net::UdpSocket, Events, Interest, Poll, Token};
#[cfg(not(target_family = "unix"))]
use smoltcp::phy::DeviceCapabilities;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use smoltcp::phy::RawSocket;
#[cfg(any(target_os = "linux", target_os = "android"))]
use smoltcp::phy::TunTapInterface;
#[cfg(target_family = "unix")]
use smoltcp::phy::{Device, Medium, RxToken, TxToken};
use smoltcp::{ use smoltcp::{
iface::{Config, Interface, SocketHandle, SocketSet}, iface::{Config, Interface, SocketHandle, SocketSet},
phy::{Device, Medium, RxToken, TunTapInterface, TxToken},
socket::{tcp, tcp::State, udp, udp::UdpMetadata}, socket::{tcp, tcp::State, udp, udp::UdpMetadata},
time::Instant, time::Instant,
wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket, UDP_HEADER_LEN}, wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket, UDP_HEADER_LEN},
}; };
use socks5_impl::protocol::{Address, StreamOperation, UdpHeader, UserKey}; use socks5_impl::protocol::{Address, StreamOperation, UdpHeader, UserKey};
use std::collections::LinkedList; use std::collections::LinkedList;
#[cfg(target_family = "unix")]
use std::os::unix::io::AsRawFd;
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
convert::{From, TryFrom}, convert::{From, TryFrom},
io::{Read, Write}, io::{Read, Write},
net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}, net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr},
os::unix::io::AsRawFd,
rc::Rc, rc::Rc,
str::FromStr, str::FromStr,
}; };
@ -208,7 +220,10 @@ const TUN_TOKEN: Token = Token(0);
const EXIT_TOKEN: Token = Token(2); const EXIT_TOKEN: Token = Token(2);
pub struct TunToProxy<'a> { pub struct TunToProxy<'a> {
#[cfg(any(target_os = "linux", target_os = "android"))]
tun: TunTapInterface, tun: TunTapInterface,
#[cfg(any(target_os = "macos", target_os = "ios"))]
tun: RawSocket,
poll: Poll, poll: Poll,
iface: Interface, iface: Interface,
connection_map: HashMap<ConnectionInfo, ConnectionState>, connection_map: HashMap<ConnectionInfo, ConnectionState>,
@ -218,31 +233,53 @@ pub struct TunToProxy<'a> {
device: VirtualTunDevice, device: VirtualTunDevice,
options: Options, options: Options,
write_sockets: HashSet<Token>, write_sockets: HashSet<Token>,
#[cfg(target_family = "unix")]
_exit_receiver: mio::unix::pipe::Receiver, _exit_receiver: mio::unix::pipe::Receiver,
#[cfg(target_family = "unix")]
exit_sender: mio::unix::pipe::Sender, exit_sender: mio::unix::pipe::Sender,
} }
impl<'a> TunToProxy<'a> { impl<'a> TunToProxy<'a> {
pub fn new(interface: &NetworkInterface, options: Options) -> Result<Self, Error> { pub fn new(_interface: &NetworkInterface, options: Options) -> Result<Self, Error> {
let tun = match interface { #[cfg(any(target_os = "linux", target_os = "android"))]
let tun = match _interface {
NetworkInterface::Named(name) => TunTapInterface::new(name.as_str(), Medium::Ip)?, NetworkInterface::Named(name) => TunTapInterface::new(name.as_str(), Medium::Ip)?,
NetworkInterface::Fd(fd) => TunTapInterface::from_fd(*fd, Medium::Ip, options.mtu.unwrap_or(1500))?, NetworkInterface::Fd(fd) => TunTapInterface::from_fd(*fd, Medium::Ip, options.mtu.unwrap_or(1500))?,
}; };
#[cfg(any(target_os = "macos", target_os = "ios"))]
let tun = match _interface {
NetworkInterface::Named(name) => RawSocket::new(name.as_str(), Medium::Ip)?,
NetworkInterface::Fd(_fd) => panic!("Not supported"),
};
let poll = Poll::new()?; let poll = Poll::new()?;
#[cfg(target_family = "unix")]
poll.registry() poll.registry()
.register(&mut SourceFd(&tun.as_raw_fd()), TUN_TOKEN, Interest::READABLE)?; .register(&mut SourceFd(&tun.as_raw_fd()), TUN_TOKEN, Interest::READABLE)?;
#[cfg(target_family = "unix")]
let (exit_sender, mut exit_receiver) = mio::unix::pipe::new()?; let (exit_sender, mut exit_receiver) = mio::unix::pipe::new()?;
#[cfg(target_family = "unix")]
poll.registry() poll.registry()
.register(&mut exit_receiver, EXIT_TOKEN, Interest::READABLE)?; .register(&mut exit_receiver, EXIT_TOKEN, Interest::READABLE)?;
#[cfg(target_family = "unix")]
#[rustfmt::skip] #[rustfmt::skip]
let config = match tun.capabilities().medium { let config = match tun.capabilities().medium {
Medium::Ethernet => Config::new(smoltcp::wire::EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into()), Medium::Ethernet => Config::new(smoltcp::wire::EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]).into()),
Medium::Ip => Config::new(smoltcp::wire::HardwareAddress::Ip), Medium::Ip => Config::new(smoltcp::wire::HardwareAddress::Ip),
Medium::Ieee802154 => todo!(), Medium::Ieee802154 => todo!(),
}; };
#[cfg(not(target_family = "unix"))]
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
#[cfg(target_family = "unix")]
let mut device = VirtualTunDevice::new(tun.capabilities()); let mut device = VirtualTunDevice::new(tun.capabilities());
#[cfg(not(target_family = "unix"))]
let mut device = VirtualTunDevice::new(DeviceCapabilities::default());
let gateway4: Ipv4Addr = Ipv4Addr::from_str("0.0.0.1")?; let gateway4: Ipv4Addr = Ipv4Addr::from_str("0.0.0.1")?;
let gateway6: Ipv6Addr = Ipv6Addr::from_str("::1")?; let gateway6: Ipv6Addr = Ipv6Addr::from_str("::1")?;
let mut iface = Interface::new(config, &mut device, Instant::now()); let mut iface = Interface::new(config, &mut device, Instant::now());
@ -255,6 +292,7 @@ impl<'a> TunToProxy<'a> {
iface.set_any_ip(true); iface.set_any_ip(true);
let tun = Self { let tun = Self {
#[cfg(target_family = "unix")]
tun, tun,
poll, poll,
iface, iface,
@ -265,7 +303,9 @@ impl<'a> TunToProxy<'a> {
device, device,
options, options,
write_sockets: HashSet::default(), write_sockets: HashSet::default(),
#[cfg(target_family = "unix")]
_exit_receiver: exit_receiver, _exit_receiver: exit_receiver,
#[cfg(target_family = "unix")]
exit_sender, exit_sender,
}; };
Ok(tun) Ok(tun)
@ -286,14 +326,15 @@ impl<'a> TunToProxy<'a> {
self.iface.poll(Instant::now(), &mut self.device, &mut self.sockets); self.iface.poll(Instant::now(), &mut self.device, &mut self.sockets);
while let Some(vec) = self.device.exfiltrate_packet() { while let Some(vec) = self.device.exfiltrate_packet() {
let slice = vec.as_slice(); let _slice = vec.as_slice();
// TODO: Actual write. Replace. // TODO: Actual write. Replace.
#[cfg(target_family = "unix")]
self.tun self.tun
.transmit(Instant::now()) .transmit(Instant::now())
.ok_or("tx token not available")? .ok_or("tx token not available")?
.consume(slice.len(), |buf| { .consume(_slice.len(), |buf| {
buf[..].clone_from_slice(slice); buf[..].clone_from_slice(_slice);
}); });
} }
Ok(()) Ok(())
@ -892,6 +933,7 @@ impl<'a> TunToProxy<'a> {
fn tun_event(&mut self, event: &Event) -> Result<(), Error> { fn tun_event(&mut self, event: &Event) -> Result<(), Error> {
if event.is_readable() { if event.is_readable() {
#[cfg(target_family = "unix")]
while let Some((rx_token, _)) = self.tun.receive(Instant::now()) { while let Some((rx_token, _)) = self.tun.receive(Instant::now()) {
rx_token.consume(|frame| self.receive_tun(frame))?; rx_token.consume(|frame| self.receive_tun(frame))?;
} }
@ -1098,6 +1140,7 @@ impl<'a> TunToProxy<'a> {
} }
pub fn shutdown(&mut self) -> Result<(), Error> { pub fn shutdown(&mut self) -> Result<(), Error> {
#[cfg(target_family = "unix")]
self.exit_sender.write_all(&[1])?; self.exit_sender.write_all(&[1])?;
Ok(()) Ok(())
} }

2
src/virtdns.rs

@ -1,3 +1,5 @@
#![allow(dead_code)]
use crate::error::Result; use crate::error::Result;
use hashlink::{linked_hash_map::RawEntryMut, LruCache}; use hashlink::{linked_hash_map::RawEntryMut, LruCache};
use smoltcp::wire::Ipv4Cidr; use smoltcp::wire::Ipv4Cidr;

1
tests/proxy.rs

@ -1,3 +1,4 @@
#[cfg(target_os = "linux")]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate reqwest; extern crate reqwest;

Loading…
Cancel
Save