Skip to content

Commit

Permalink
Merge pull request #16 from Jigsaw-Code/bemasc-upgrade
Browse files Browse the repository at this point in the history
Upgrade to go-tun2socks 1.16.2
  • Loading branch information
Benjamin M. Schwartz authored Aug 14, 2019
2 parents c8a40c8 + 235525c commit a9057c2
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 60 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ BUILDDIR=$(shell pwd)/build
IMPORT_PATH=github.com/Jigsaw-Code/outline-go-tun2socks
LDFLAGS='-s -w'
ANDROID_LDFLAGS='-w' # Don't strip Android debug symbols so we can upload them to crash reporting tools.
TUN2SOCKS_VERSION=v1.14.2
TUN2SOCKS_VERSION=v1.16.2
TUN2SOCKS_SRC_PATH=$(GOPATH)/src/github.com/eycorsican/go-tun2socks
TUN2SOCKS_MOD_PATH=$(GOPATH)/pkg/mod/github.com/eycorsican/go-tun2socks\@$(TUN2SOCKS_VERSION)
XGO_LDFLAGS='-s -w -X main.version=$(TUN2SOCKS_VERSION)'
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.12

require (
github.com/Jigsaw-Code/getsni v0.0.0-20190807203514-efe2dbf35d1f
github.com/eycorsican/go-tun2socks v1.14.2
github.com/eycorsican/go-tun2socks v1.16.2
github.com/karalabe/xgo v0.0.0-20190301120235-2d6d1848fb02 // indirect
github.com/miekg/dns v1.1.12 // indirect
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/eycorsican/go-tun2socks v1.13.2 h1:8AX0GW0RzsNluDaiz3j4DRpP/62ROxzlE6
github.com/eycorsican/go-tun2socks v1.13.2/go.mod h1:itJVcg8T4Lc1r+72CNpCV/SUNO8of0z/jFeAt31cQbA=
github.com/eycorsican/go-tun2socks v1.14.2 h1:WeceCiqIM38+/6kNygC5ucDEes6D5X5lwImFeecogTk=
github.com/eycorsican/go-tun2socks v1.14.2/go.mod h1:itJVcg8T4Lc1r+72CNpCV/SUNO8of0z/jFeAt31cQbA=
github.com/eycorsican/go-tun2socks v1.16.2 h1:pczsTNxP9NBDAsE9lhTnXoh6VLRf8FaZP2JBLv3KLWA=
github.com/eycorsican/go-tun2socks v1.16.2/go.mod h1:itJVcg8T4Lc1r+72CNpCV/SUNO8of0z/jFeAt31cQbA=
github.com/karalabe/xgo v0.0.0-20190301120235-2d6d1848fb02 h1:nI4Q7WQDcng8eRmi8bRP1SXlJIYLkgdgR7ZhJuzPbhs=
github.com/karalabe/xgo v0.0.0-20190301120235-2d6d1848fb02/go.mod h1:iYGcTYIPUvEWhFo6aKUuLchs+AV4ssYdyuBbQJZGcBk=
github.com/miekg/dns v1.1.6 h1:jVwb4GDwD65q/gtItR/lIZHjNH93QfeGxZUkzJcW9mc=
Expand Down
52 changes: 30 additions & 22 deletions tunnel/intra.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ type IntraListener interface {

type intratunnel struct {
*tunnel
fakedns net.Addr
udpdns net.Addr
tcpdns net.Addr
fakedns string
udpdns string
tcpdns string
alwaysSplitHTTPS bool
listener IntraListener
}
Expand All @@ -45,40 +45,48 @@ type intratunnel struct {
// `udpdns` and `tcpdns` are the actual location of the DNS server in use.
// These will normally be localhost with a high-numbered port.
func NewIntraTunnel(fakedns, udpdns, tcpdns string, tunWriter io.WriteCloser, alwaysSplitHTTPS bool, listener IntraListener) (Tunnel, error) {
fakednsipaddr, err := net.ResolveUDPAddr("udp", fakedns)
if err != nil {
return nil, err
}
tcpdnsipaddr, err := net.ResolveTCPAddr("tcp", tcpdns)
if err != nil {
return nil, err
}
udpdnsipaddr, err := net.ResolveUDPAddr("udp", udpdns)
if err != nil {
return nil, err
}
if tunWriter == nil {
return nil, errors.New("Must provide a valid TUN writer")
}
core.RegisterOutputFn(tunWriter.Write)
base := &tunnel{tunWriter, core.NewLWIPStack(), true}
s := &intratunnel{
tunnel: base,
fakedns: fakednsipaddr,
udpdns: udpdnsipaddr,
tcpdns: tcpdnsipaddr,
fakedns: fakedns,
udpdns: udpdns,
tcpdns: tcpdns,
alwaysSplitHTTPS: alwaysSplitHTTPS,
listener: listener,
}
s.registerConnectionHandlers()
if err := s.registerConnectionHandlers(); err != nil {
return nil, err
}
return s, nil
}

// Registers Intra's custom UDP and TCP connection handlers to the tun2socks core.
func (t *intratunnel) registerConnectionHandlers() {
func (t *intratunnel) registerConnectionHandlers() error {
// RFC 5382 REQ-5 requires a timeout no shorter than 2 hours and 4 minutes.
timeout, _ := time.ParseDuration("2h4m")

core.RegisterUDPConnHandler(intra.NewUDPHandler(t.fakedns, t.udpdns, timeout, t.listener))
core.RegisterTCPConnHandler(intra.NewTCPHandler(t.fakedns, t.tcpdns, t.alwaysSplitHTTPS, t.listener))
udpfakedns, err := net.ResolveUDPAddr("udp", t.fakedns)
if err != nil {
return err
}
udpdns, err := net.ResolveUDPAddr("udp", t.udpdns)
if err != nil {
return err
}
core.RegisterUDPConnHandler(intra.NewUDPHandler(*udpfakedns, *udpdns, timeout, t.listener))

tcpfakedns, err := net.ResolveTCPAddr("tcp", t.fakedns)
if err != nil {
return err
}
tcpdns, err := net.ResolveTCPAddr("tcp", t.tcpdns)
if err != nil {
return err
}
core.RegisterTCPConnHandler(intra.NewTCPHandler(*tcpfakedns, *tcpdns, t.alwaysSplitHTTPS, t.listener))
return nil
}
42 changes: 19 additions & 23 deletions tunnel/intra/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
)

type tcpHandler struct {
fakedns net.Addr
truedns net.Addr
fakedns net.TCPAddr
truedns net.TCPAddr
alwaysSplitHTTPS bool
listener TCPListener
}
Expand Down Expand Up @@ -57,7 +57,7 @@ type DuplexConn interface {
// Currently this class only redirects DNS traffic to a
// specified server. (This should be rare for TCP.)
// All other traffic is forwarded unmodified.
func NewTCPHandler(fakedns, truedns net.Addr, alwaysSplitHTTPS bool, listener TCPListener) core.TCPConnHandler {
func NewTCPHandler(fakedns, truedns net.TCPAddr, alwaysSplitHTTPS bool, listener TCPListener) core.TCPConnHandler {
return &tcpHandler{
fakedns: fakedns,
truedns: truedns,
Expand All @@ -66,27 +66,29 @@ func NewTCPHandler(fakedns, truedns net.Addr, alwaysSplitHTTPS bool, listener TC
}
}

func (h *tcpHandler) handleUpload(local net.Conn, remote DuplexConn, upload chan int64) {
// TODO: Propagate TCP RST using local.Abort(), on appropriate errors.
func (h *tcpHandler) handleUpload(local core.TCPConn, remote DuplexConn, upload chan int64) {
// TODO: Handle half-closed sockets more correctly if upstream
// changes `local` to a more detailed type than `net.Conn`.
bytes, _ := remote.ReadFrom(local)
local.Close()
local.CloseRead()
remote.CloseWrite()
upload <- bytes
}

func (h *tcpHandler) handleDownload(local net.Conn, remote DuplexConn) (bytes int64, err error) {
func (h *tcpHandler) handleDownload(local core.TCPConn, remote DuplexConn) (bytes int64, err error) {
bytes, err = io.Copy(local, remote)
local.Close()
local.CloseWrite()
remote.CloseRead()
return
}

func (h *tcpHandler) forward(local net.Conn, remote DuplexConn, summary *TCPSocketSummary) {
localtcp := local.(core.TCPConn)
upload := make(chan int64)
start := time.Now()
go h.handleUpload(local, remote, upload)
download, _ := h.handleDownload(local, remote)
go h.handleUpload(localtcp, remote, upload)
download, _ := h.handleDownload(localtcp, remote)
summary.DownloadBytes = download
summary.UploadBytes = <-upload
summary.Duration = int32(time.Since(start).Seconds())
Expand All @@ -110,31 +112,25 @@ func filteredPort(addr net.Addr) int16 {
return -1
}

// TODO: Request upstream to make `conn` a `core.TCPConn` so we can have finer-
// grained mimicry.
func (h *tcpHandler) Handle(conn net.Conn, target net.Addr) error {
// TODO: Request upstream to make `conn` a `core.TCPConn` so we can avoid a type assertion.
func (h *tcpHandler) Handle(conn net.Conn, target *net.TCPAddr) error {
// DNS override
// TODO: Consider whether this equality check is acceptable here.
// (e.g. domain names vs IPs, different serialization of IPv6)
if target == h.fakedns {
target = h.truedns
}
tcpaddr, err := net.ResolveTCPAddr(target.Network(), target.String())
if err != nil {
return err
if target.IP.Equal(h.fakedns.IP) && target.Port == h.fakedns.Port {
target = &h.truedns
}
var summary TCPSocketSummary
summary.ServerPort = filteredPort(target)
start := time.Now()
var c DuplexConn
var err error
if summary.ServerPort == 443 {
if h.alwaysSplitHTTPS {
c, err = DialWithSplit(target.Network(), tcpaddr)
c, err = DialWithSplit(target.Network(), target)
} else {
c, err = DialWithSplitRetry(target.Network(), tcpaddr, &summary)
c, err = DialWithSplitRetry(target.Network(), target, &summary)
}
} else {
c, err = net.DialTCP(target.Network(), nil, tcpaddr)
c, err = net.DialTCP(target.Network(), nil, target)
}
if err != nil {
return err
Expand Down
22 changes: 11 additions & 11 deletions tunnel/intra/udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ type udpHandler struct {

timeout time.Duration
udpConns map[core.UDPConn]*tracker
fakedns net.Addr
truedns net.Addr
fakedns net.UDPAddr
truedns net.UDPAddr
listener UDPListener
}

Expand All @@ -67,7 +67,7 @@ type udpHandler struct {
// destination is `fakedns`. Those packets are redirected to `truedns`.
// Similarly, packets arriving from `truedns` have the source address replaced
// with `fakedns`.
func NewUDPHandler(fakedns, truedns net.Addr, timeout time.Duration, listener UDPListener) core.UDPConnHandler {
func NewUDPHandler(fakedns, truedns net.UDPAddr, timeout time.Duration, listener UDPListener) core.UDPConnHandler {
return &udpHandler{
timeout: timeout,
udpConns: make(map[core.UDPConn]*tracker, 8),
Expand Down Expand Up @@ -99,9 +99,10 @@ func (h *udpHandler) fetchUDPInput(conn core.UDPConn, t *tracker) {
return
}

if addr.String() == h.truedns.String() {
udpaddr := addr.(*net.UDPAddr)
if udpaddr.IP.Equal(h.truedns.IP) && udpaddr.Port == h.truedns.Port {
// Pretend that the reply was from the fake DNS server.
addr = h.fakedns
udpaddr = &h.fakedns
if n < 2 {
// Very short packet, cannot possibly be DNS.
t.complex = true
Expand All @@ -117,7 +118,7 @@ func (h *udpHandler) fetchUDPInput(conn core.UDPConn, t *tracker) {
t.complex = true
}
t.download += int64(n)
_, err = conn.WriteFrom(buf[:n], addr)
_, err = conn.WriteFrom(buf[:n], udpaddr)
if err != nil {
log.Warnf("failed to write UDP data to TUN")
return
Expand All @@ -130,7 +131,7 @@ func (h *udpHandler) fetchUDPInput(conn core.UDPConn, t *tracker) {
}
}

func (h *udpHandler) Connect(conn core.UDPConn, target net.Addr) error {
func (h *udpHandler) Connect(conn core.UDPConn, target *net.UDPAddr) error {
bindAddr := &net.UDPAddr{IP: nil, Port: 0}
pc, err := net.ListenUDP(bindAddr.Network(), bindAddr)
if err != nil {
Expand All @@ -146,8 +147,7 @@ func (h *udpHandler) Connect(conn core.UDPConn, target net.Addr) error {
return nil
}

// TODO: Request upstream to make `addr` a `UDPAddr` for more efficient comparisons.
func (h *udpHandler) DidReceiveTo(conn core.UDPConn, data []byte, addr net.Addr) error {
func (h *udpHandler) ReceiveTo(conn core.UDPConn, data []byte, addr *net.UDPAddr) error {
h.Lock()
t, ok1 := h.udpConns[conn]
h.Unlock()
Expand All @@ -156,9 +156,9 @@ func (h *udpHandler) DidReceiveTo(conn core.UDPConn, data []byte, addr net.Addr)
return fmt.Errorf("connection %v->%v does not exists", conn.LocalAddr(), addr)
}

if addr.String() == h.fakedns.String() {
if addr.IP.Equal(h.fakedns.IP) && addr.Port == h.fakedns.Port {
// Send the query to the real DNS server.
addr = h.truedns
addr = &h.truedns
id := queryid(data)
if id < 0 {
t.complex = true
Expand Down
4 changes: 2 additions & 2 deletions tunnel/outline.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ func (t *outlinetunnel) registerConnectionHandlers() {
var udpHandler core.UDPConnHandler
if t.isUDPEnabled {
udpHandler = socks.NewUDPHandler(
t.host, t.port, 30*time.Second, nil, nil)
t.host, t.port, 30*time.Second, nil, nil, nil)
} else {
udpHandler = dnsfallback.NewUDPHandler()
}
core.RegisterTCPConnHandler(socks.NewTCPHandler(t.host, t.port, nil))
core.RegisterTCPConnHandler(socks.NewTCPHandler(t.host, t.port, nil, nil))
core.RegisterUDPConnHandler(udpHandler)
}

0 comments on commit a9057c2

Please sign in to comment.