Skip to content
This repository has been archived by the owner on Apr 21, 2023. It is now read-only.

Latest commit

 

History

History
115 lines (79 loc) · 3.13 KB

DESIGN.md

File metadata and controls

115 lines (79 loc) · 3.13 KB

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 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 already provides SOCKS5 client.

For Linux NAT, we need to use golang.org/x/sys/unix 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.