2
0
mirror of https://github.com/stefan01/transocks.git synced 2025-02-22 03:30:45 +07:00
transocks/DESIGN.md

116 lines
3.1 KiB
Markdown
Raw Permalink Normal View History

2016-03-04 07:54:59 +06:00
Design notes
============
transocks should work as a SOCKS5 client used as a transparent proxy
agent running on every hosts in trusted (i.e. data center) networks.
Destination NAT (DNAT)
----------------------
On Linux, redirecting locally-generated packet to transocks can be done
by iptables with DNAT (or REDIRECT) target.
Since DNAT/REDIRECT modifies packet's destination address, transocks
need to recover the destination address by using `getsockopt` with
`SO_ORIGINAL_DST` for IPv4 or with `IP6T_SO_ORIGINAL_DST` for IPv6.
This is, of course, Linux-specific, and Go does not provide standard
API for them.
Policy-based routing
--------------------
Except for DNAT, some operating systems provide a way to route packets
to a specific program. In order to receive such packets, the program
need to set special options on the listening socket before `bind`.
Difficult is that Go does not allow setting socket options before `bind`.
### Linux TPROXY
Linux iptables has [TPROXY][] target that can route packets to a
specific local port. The socket option is:
* IPv4
```
setsockopt(IPPROTO_IP, IP_TRANSPARENT)
```
* IPv6
```
setsockopt(IPPROTO_IPV6, IPV6_TRANSPARENT)
```
To set this option, transocks must have `CAP_NET_ADMIN` capability.
Run transocks as root user, or grant `CAP_NET_ADMIN` for the file by:
```
sudo setcap 'cap_net_admin+ep' transocks
```
### FreeBSD, NetBSD, OpenBSD
Use [PF with divert-to][pf] to route packets to a specific local port.
The listening program needs to set a socket option before `bind`:
* FreeBSD (IPv4)
```
setsockopt(IPPROTO_IP, IP_BINDANY)
```
* FreeBSD (IPv6)
```
setsockopt(IPPROTO_IPV6, IPV6_BINDANY)
```
* NetBSD, OpenBSD
```
setsockopt(SOL_SOCKET, SO_BINDANY)
```
For this to work, transocks must run as root.
Implementation strategy
-----------------------
We use Go for its efficiency and simpleness.
For SOCKS5, [golang.org/x/net/proxy][x/net] already provides SOCKS5 client.
For Linux NAT, we need to use [golang.org/x/sys/unix][x/sys] and
[unsafe.Pointer][] to use non-standard `getsockopt` options.
To set socket options before `bind`, we need to create sockets manually
by using [golang.org/x/sys/unix] and then convert the native socket to
`*net.TCPListener` by [net.FileListener][].
CONNECT tunnel
--------------
As golang.org/x/net/proxy can add custom dialers, we can implement
a proxy using http CONNECT method for tunneling through HTTP proxies
such as [Squid][].
Note that the default Squid configuration file installed for
Ubuntu 14.04 prohibits CONNECT to ports other than 443.
```
# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports
```
Remove or comment out the line to allow CONNECT to ports other than 443.
[TPROXY]: https://www.kernel.org/doc/Documentation/networking/tproxy.txt
[pf]: http://wiki.squid-cache.org/ConfigExamples/Intercept/OpenBsdPf
[x/net]: https://godoc.org/golang.org/x/net/proxy#SOCKS5
[x/sys]: https://godoc.org/golang.org/x/sys/unix
[unsafe.Pointer]: https://golang.org/pkg/unsafe/#Pointer
[net.FileListener]: https://golang.org/pkg/net/#FileListener
[Squid]: http://www.squid-cache.org/