GithubHelp home page GithubHelp logo

tun2proxy / rust-tun Goto Github PK

View Code? Open in Web Editor NEW

This project forked from meh/rust-tun

34.0 34.0 15.0 342 KB

TUN device creation and handling.

Home Page: https://docs.rs/tun2/

Rust 99.32% Nix 0.68%

rust-tun's Introduction

tun2proxy

A tunnel interface for HTTP and SOCKS proxies on Linux, Android, macOS, iOS and Windows.

Crates.io tun2proxy Documentation Download License

Additional information can be found in the wiki

Features

  • HTTP proxy support (unauthenticated, basic and digest auth)
  • SOCKS4 and SOCKS5 support (unauthenticated, username/password auth)
  • SOCKS4a and SOCKS5h support (through the virtual DNS feature)
  • Minimal configuration setup for routing all traffic
  • IPv4 and IPv6 support
  • GFW evasion mechanism for certain use cases (see issue #35)
  • SOCKS5 UDP support
  • Native support for proxying DNS over TCP

Build

Clone the repository and cd into the project folder. Then run the following:

cargo build --release

Building Framework for Apple Devices

To build an XCFramework for macOS and iOS, run the following:

./build-apple.sh

Installation

Install from binary

Download the binary from releases and put it in your PATH.

Authenticity Verification

Since v0.2.23 build provenance attestations are supported. These allow you to ensure that the builds have been generated from the code on GitHub through the GitHub CI/CD pipeline. To verify the authenticity of the build files, you can use the GitHub CLI:

gh attestation verify <*.zip file> --owner tun2proxy

Install from source

If you have rust toolchain installed, this should work:

cargo install tun2proxy

Note: In Windows, you need to copy wintun DLL to the same directory as the binary. It's %USERPROFILE%\.cargo\bin by default.

Setup

Automated Setup

Using --setup, you can have tun2proxy configure your system to automatically route all traffic through the specified proxy. This requires running the tool as root and will roughly perform the steps outlined in the section describing the manual setup, except that a bind mount is used to overlay the /etc/resolv.conf file.

You would then run the tool as follows:

sudo ./target/release/tun2proxy --setup --proxy "socks5://1.2.3.4:1080"

Apart from SOCKS5, SOCKS4 and HTTP are supported.

Note that if your proxy is a non-global IP address (e.g. because the proxy is provided by some tunneling tool running locally), you will additionally need to provide the public IP address of the server through which the traffic is actually tunneled. In such a case, the tool will tell you to specify the address through --bypass <IP/CIDR> if you wish to make use of the automated setup feature.

Manual Setup

A standard setup, which would route all traffic from your system through the tunnel interface, could look as follows:

# The proxy type can be either SOCKS4, SOCKS5 or HTTP.
PROXY_TYPE=SOCKS5
PROXY_IP=1.2.3.4
PROXY_PORT=1080
BYPASS_IP=123.45.67.89

# Create a tunnel interface named tun0 which you can bind to,
# so we don't need to run tun2proxy as root.
sudo ip tuntap add name tun0 mode tun
sudo ip link set tun0 up

# To prevent a routing loop, we add a route to the proxy server that behaves
# like the default route.
sudo ip route add "$BYPASS_IP" $(ip route | grep '^default' | cut -d ' ' -f 2-)

# Route all your traffic through tun0 without interfering with the default route.
sudo ip route add 128.0.0.0/1 dev tun0
sudo ip route add 0.0.0.0/1 dev tun0

# If you wish to also route IPv6 traffic through the proxy, these two commands will do.
sudo ip route add ::/1 dev tun0
sudo ip route add 8000::/1 dev tun0

# Make sure that DNS queries are routed through the tunnel.
sudo sh -c "echo nameserver 198.18.0.1 > /etc/resolv.conf"

./target/release/tun2proxy --tun tun0 --proxy "$PROXY_TYPE://$PROXY_IP:$PROXY_PORT"

This tool implements a virtual DNS feature that is used by switch --dns virtual. When a DNS packet to port 53 is detected, an IP address from 198.18.0.0/15 is chosen and mapped to the query name. Connections destined for an IP address from that range will supply the proxy with the mapped query name instead of the IP address. Since many proxies do not support UDP, this enables an out-of-the-box experience in most cases, without relying on third-party resolvers or applications. Depending on your use case, you may want to disable this feature using --dns direct. In that case, you might need an additional tool like dnsproxy that is configured to listen on a local UDP port and communicates with a third-party upstream DNS server via TCP.

When you terminate this program and want to eliminate the impact caused by the above several commands, you can execute the following command. The routes will be automatically deleted with the tunnel device.

sudo ip link del tun0

CLI

Tunnel interface to proxy.

Usage: tun2proxy [OPTIONS] --proxy <URL> [ADMIN_COMMAND]...

Arguments:
  [ADMIN_COMMAND]...  Specify a command to run with root-like capabilities in the new namespace when using `--unshare`.
                      This could be useful to start additional daemons, e.g. `openvpn` instance

Options:
  -p, --proxy <URL>            Proxy URL in the form proto://[username[:password]@]host:port, where proto is one of
                               socks4, socks5, http. For example: socks5://myname:[email protected]:1080
  -t, --tun <name>             Name of the tun interface, such as tun0, utun4, etc. If this option is not provided, the
                               OS will generate a random one
      --tun-fd <fd>            File descriptor of the tun interface
      --unshare                Create a tun interface in a newly created unprivileged namespace while maintaining proxy
                               connectivity via the global network namespace
  -6, --ipv6-enabled           IPv6 enabled
  -s, --setup                  Routing and system setup, which decides whether to setup the routing and system
                               configuration. This option is only available on Linux and requires root-like privileges.
                               See `capabilities(7)`
  -d, --dns <strategy>         DNS handling strategy [default: direct] [possible values: virtual, over-tcp, direct]
      --dns-addr <IP>          DNS resolver address [default: 8.8.8.8]
  -b, --bypass <IP/CIDR>       IPs used in routing setup which should bypass the tunnel, in the form of IP or IP/CIDR.
                               Multiple IPs can be specified, e.g. --bypass 3.4.5.0/24 --bypass 5.6.7.8
      --tcp-timeout <seconds>  TCP timeout in seconds [default: 600]
      --udp-timeout <seconds>  UDP timeout in seconds [default: 10]
  -v, --verbosity <level>      Verbosity level [default: info] [possible values: off, error, warn, info, debug, trace]
  -h, --help                   Print help
  -V, --version                Print version

Currently, tun2proxy supports HTTP, SOCKS4/SOCKS4a and SOCKS5. A proxy is supplied to the --proxy argument in the URL format. For example, an HTTP proxy at 1.2.3.4:3128 with a username of john.doe and a password of secret is supplied as --proxy http://john.doe:[email protected]:3128. This works analogously to curl's --proxy argument.

Docker Support

Tun2proxy can serve as a proxy for other Docker containers. To make use of that feature, first build the image:

docker build -t tun2proxy .

Next, start a container from the tun2proxy image:

docker run -d \
	-v /dev/net/tun:/dev/net/tun \
	--sysctl net.ipv6.conf.default.disable_ipv6=0 \
	--cap-add NET_ADMIN \
	--name tun2proxy \
	tun2proxy --proxy proto://[username[:password]@]host:port

You can then provide the running container's network to another worker container by sharing the network namespace (like kubernetes sidecar):

docker run -it \
	--network "container:tun2proxy" \
	ubuntu:latest

Configuration Tips

DNS

When DNS resolution is performed by a service on your machine or through a server in your local network, DNS resolution will not be performed through the tunnel interface, since the routes to localhost or your local network are more specific than 0.0.0.0/1 and 128.0.0.0/1. In this case, it may be advisable to update your /etc/resolv.conf file to use a nameserver address that is routed through the tunnel interface. When virtual DNS is working correctly, you will see log messages like DNS query: example.org for hostnames which your machine is connecting to after having resolved them through DNS.

Note that software like the NetworkManager may change the /etc/resolv.conf file automatically at any time, which will result in DNS leaks. A hacky solution to prevent this consists in making the file immutable as follows: sudo chattr +i "$(realpath /etc/resolv.conf)".

IPv6

Some proxy servers might not support IPv6. When using virtual DNS, this is not a problem as DNS names are resolved by the proxy server. When DNS names are resolved to IPv6 addresses locally, this becomes a problem as the proxy will be asked to open connections to IPv6 destinations. In such a case, you can disable IPv6 on your machine. This can be done either through sysctl -w net.ipv6.conf.all.disable_ipv6=1 and sysctl -w net.ipv6.conf.default.disable_ipv6=1 or through ip -6 route del default, which causes the libc resolver (and other software) to not issue DNS AAAA requests for IPv6 addresses.

rust-tun's People

Contributors

0e4ef622 avatar black-binary avatar branliang avatar cavivie avatar ch00k avatar dependabot[bot] avatar ekkog avatar eycorsican avatar gdetal avatar imlk0 avatar inceabdullah avatar jibi avatar luozijun avatar meh avatar mlegner avatar neacsu avatar pftbest avatar pinkisemils avatar realityone avatar rishidhupar avatar rodmitry avatar ssrlive avatar xmh0511 avatar zonyitoo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rust-tun's Issues

Win7 error

thread 'main' panicked at src\main.rs:17:41:
called `Result::unwrap()` on an `Err` value: WintunError(String("Unable to find
matching {7C276CB3-823B-4AD3-816C-1D3EA30E7297}"))
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

I am using the example you provided

let mut config = tun2::Configuration::default();
config
    .address((10, 0, 0, 9))
    .netmask((255, 255, 255, 0))
    .destination((10, 0, 0, 1))
    .up();

#[cfg(target_os = "linux")]
config.platform_config(|config| {
    // requiring root privilege to acquire complete functions
    config.ensure_root_privileges(true);
});

let mut dev = tun2::create(&config).unwrap();
let mut buf = [0; 4096];

loop {
    let amount = dev.read(&mut buf).unwrap();
    println!("{:?}", &buf[0..amount]);
}

add split api?

I am wondering why we require mut self for read and write.
If this is the case, how can we read/write at the same time?
If this is not supported, I believe the use is very limited.

If mut self is really required, can we do a split to get a readhalf and writehalf? Just like what we did for streams?

Routing setup seems broken in macOS and FreeBSD

I'm migrating to this fork since the original repo is unmaintained.

While migrating I noticed a problem concerning the automatic route setup on macOS and FreeBSD, this is a nice feature you introduced but I think there could something wrong.

image

image

First picture is the routing table after a manual setup by myself using the original repo, which works.

Second picture is the routing table after the automatic setup by this fork, which seems to not allow any packets to be sent out.

Note: in this example the TUN IP is 10.0.0.113

How to generate GUID (Windows)

I need help generating the guid for the tun device. How can I check if an interface already exists with this guid? Or is there any API to get the guid from the tun device after creating it for the first time (using tun2::create_as_async)

Replacing `cidr_util` with `ipnet`

In #40, a dependency to cidr_util was added. From what I understand, it's a one-time use crate just for tun2.

Could we not replace this with something such as ipnet, which:

  • is relatively popular (hence more likely to be used by dependents of tun2)
  • provides the required features
  • could also be useful later on with the integration of IPv6
    ?

Apple(iOS) libc::sockaddr_in does not impl Debug trait

Apple(iOS) libc::sockaddr_in does not impl Debug trait, but tun2 defines SockAddr struct with Debug trait implmentation.

https://github.com/tun2proxy/rust-tun/blob/v2/src/platform/posix/sockaddr.rs#L20

   Compiling tun2 v1.2.8
error[E0277]: `sockaddr_in` doesn't implement `Debug`
  --> .../.cargo/registry/src/index.crates.io-6f17d22bba15001f/tun2-1.2.8/src/platform/posix/sockaddr.rs:21:21
   |
20 | #[derive(Copy, Clone, Debug)]
   |                       ----- in this derive macro expansion
21 | pub struct SockAddr(sockaddr_in);
   |                     ^^^^^^^^^^^ `sockaddr_in` cannot be formatted using `{:?}` because it doesn't implement `Debug`
   |
   = help: the trait `Debug` is not implemented for `sockaddr_in`, which is required by `&sockaddr_in: Debug`
   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)

better experience with different platforms

for example, MacOS does not allow name the tun device. I configure it with a name. it failed creating the tun. remove the name, it works.

This is a great crate, I think it will be greater if we can finetune the creating process of every platform.

Also, you may want to add the default route for MacOS?
This way, it's truly unified experience. At least, finetune this create to this direction?

It's just my thought.

Support for vectored operations

It seems that in #23, support for vectored operations has been removed.

Is there any particular reason for this move? I know there has been an issue with vectored operations being much slower than standard ones (at least in my testing), but I've never been able to pinpoint the source of the issue. However, it would be useful to have if this project ever got to implementing GSO/GRO.

Weird Wintun error

When created a tun with a name vpnproxy in windows, I got this:
01/29/2024 21:00:52-WinTun: Failed to find matching adapter name: Element not found. (Code 0x00000490)
01/29/2024 21:00:52-WinTun: Using existing driver 0.14
01/29/2024 21:00:52-WinTun: Creating adapter
01/29/2024 21:00:52-WinTun: Removed orphaned adapter "vpnproxy 1"
-------------------------------------------------------------------------------
Then the tun is created, everything works fine.
It's just weird to get this error message. My code looks like the following. It seems I am having problems with tun names. Maybe I used it the wrong way?
-------------
fn create_tun(name: &str, ip: &str, _: u8) -> Result<tun2::AsyncDevice, tun2::Error> {
    let mut config = tun2::Configuration::default();
    config
        .address(ip)
        .name(name)
        .netmask((255, 255, 255, 0))
        .up();

    #[cfg(target_os = "linux")]
    config.platform_config(|config| {
        config.packet_information(true);
        config.apply_settings(true);
    });

    tun2::create_as_async(&config)
}

Suggestion: Changing the type of mtu from usize to u16

As the tun interface operates on the network layer and above, I am not aware of any protocol that allows carrying more than 2^16 bytes in a single packet, which is the maximum value for an IP packet. The current implementation may lead some developers to choose the wrong value. Therefore, I suggest changing the mtu variable type from usize to u16 to prevent potential mistakes by developers.

IPv6 Support

Thoughts on what is needed to support IPv6?

It looks like rust-tun is mostly hard-wired to IPv4 (except for PacketProtocol) so seems non-trivial.

IPv6 is supported on tun devices on (at least) Linux, macOS and Windows (inc. wintun.dll and the wintun crate) so I don't think there is any fundamental reason preventing this.

This old issue (meh#4) suggests there is a key problem to solve but there are few details:

the problem is you need to go through a netlink socket to set up IPv6 addresses

I may be able to help with this as i'm motivated to have IPv6 support in rust-tun.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.