Skip to content

Commit

Permalink
Refactor traffic capture
Browse files Browse the repository at this point in the history
  • Loading branch information
riobard committed Feb 26, 2020
1 parent 7a2a602 commit 695d571
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 153 deletions.
1 change: 0 additions & 1 deletion dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ func fastdialer(u ...string) (*dialer, error) {
if err != nil {
return c, err
}
tcpKeepAlive(c)
c = ciph.StreamConn(c)
return c, nil
}
Expand Down
83 changes: 83 additions & 0 deletions listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package main

import (
"errors"
"net"

"github.com/riobard/go-shadowsocks2/socks"
)

var listeners map[string]func(network, address string) (net.Listener, error)

func init() {
listeners = make(map[string]func(network, address string) (net.Listener, error))
}

func listen(kind, network, address string) (net.Listener, error) {
f, ok := listeners[kind]
if ok {
return f(network, address)
}
return nil, errors.New("unsupported listener " + kind)
}

type strAddr string

func (a strAddr) Network() string { return "tcp" }
func (a strAddr) String() string { return string(a) }

type tunConn struct {
net.Conn
target net.Addr
}

func (c *tunConn) LocalAddr() net.Addr { return c.target }

type tunListener struct {
net.Listener
target net.Addr
}

func tunListen(network, address, target string) (net.Listener, error) {
l, err := net.Listen(network, address)
if err != nil {
return nil, err
}
return &tunListener{l, strAddr(target)}, err
}

func (l *tunListener) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &tunConn{c, l.target}, nil
}

type socksConn struct{ net.Conn }

func (sc socksConn) LocalAddr() net.Addr {
addr, err := socks.Handshake(sc.Conn)
if err != nil {
return nil
}
return strAddr(addr.String())
}

type socksListener struct{ net.Listener }

func (l *socksListener) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return socksConn{c}, nil
}

func socksListen(network, addr string) (net.Listener, error) {
l, err := net.Listen(network, addr)
if err != nil {
return nil, err
}
return &socksListener{l}, nil
}
43 changes: 43 additions & 0 deletions listener_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"net"

"github.com/riobard/go-shadowsocks2/pfutil"
)

func init() {
listeners["redir"] = pfListen
}

type pfConn struct{ net.Conn }

func (c *pfConn) LocalAddr() net.Addr {
tc, ok := c.Conn.(*net.TCPConn)
if !ok {
return nil
}
addr, err := pfutil.NatLookup(tc)
if err != nil {
return nil
}
return addr
}

type pfListener struct{ net.Listener }

func (l *pfListener) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &pfConn{c}, nil
}

func pfListen(network, address string) (net.Listener, error) {
l, err := net.Listen(network, address)
if err != nil {
return nil, err
}
return &pfListener{l}, nil
}
62 changes: 62 additions & 0 deletions listener_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main

import (
"context"
"net"
"syscall"

"github.com/riobard/go-shadowsocks2/nfutil"
)

func init() {
listeners["redir"] = nfListen
listeners["tproxy"] = tproxyListen
}

type nfConn struct{ net.Conn }

func (c *nfConn) LocalAddr() net.Addr {
tc, ok := c.Conn.(*net.TCPConn)
if !ok {
return nil
}
addr, err := nfutil.GetOrigDst(tc, false) // TODO: detect if c is ipv6
if err != nil {
return nil
}
return addr
}

type nfListener struct{ net.Listener }

func (l *nfListener) Accept() (net.Conn, error) {
c, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &nfConn{c}, nil
}

func nfListen(network, address string) (net.Listener, error) {
l, err := net.Listen(network, address)
if err != nil {
return nil, err
}
return &nfListener{l}, nil
}

func tproxyListen(network, address string) (net.Listener, error) {
lcfg := net.ListenConfig{Control: func(network, address string, rc syscall.RawConn) error {
var err1, err2 error
err2 = rc.Control(func(fd uintptr) { err1 = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1) })
if err1 != nil {
return err1
}
return err2
}}
l, err := lcfg.Listen(context.Background(), network, address)
if err != nil {
return nil, err
}
return l, nil
}
35 changes: 25 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ func main() {
flag.Var(&flags.UDPTun, "udptun", "(client-only) UDP tunnel (laddr1=raddr1,laddr2=raddr2,...)")
flag.StringVar(&flags.Socks, "socks", "", "(client-only) SOCKS listen address")
flag.StringVar(&flags.RedirTCP, "redir", "", "(client-only) redirect TCP from this address")
flag.StringVar(&flags.RedirTCP6, "redir6", "", "(client-only) redirect TCP IPv6 from this address")
flag.StringVar(&flags.TproxyTCP, "tproxytcp", "", "(client-only) TPROXY TCP listen address")
flag.StringVar(&flags.TproxyTCP, "tproxytcp", "", "(Linux client-only) TPROXY TCP listen address")
flag.DurationVar(&config.UDPTimeout, "udptimeout", 120*time.Second, "UDP tunnel timeout")
flag.Parse()

Expand Down Expand Up @@ -83,24 +82,40 @@ func main() {

if len(flags.TCPTun) > 0 {
for _, p := range flags.TCPTun {
go tcpTun(p[0], p[1], d)
l, err := tunListen("tcp", p[0], p[1])
if err != nil {
log.Fatal(err)
}
logf("tcptun %v --> %v", p[0], p[1])
go tcpLocal(l, d)
}
}

if flags.Socks != "" {
go socksLocal(flags.Socks, d)
l, err := socksListen("tcp", flags.Socks)
if err != nil {
log.Fatal(err)
}
logf("socks %v", flags.Socks)
go tcpLocal(l, d)
}

if flags.RedirTCP != "" {
go redirLocal(flags.RedirTCP, d)
}

if flags.RedirTCP6 != "" {
go redir6Local(flags.RedirTCP6, d)
l, err := listen("redir", "tcp", flags.RedirTCP)
if err != nil {
log.Fatal(err)
}
logf("redir tcp %v", flags.RedirTCP)
go tcpLocal(l, d)
}

if flags.TproxyTCP != "" {
go tproxyTCP(flags.TproxyTCP, d)
l, err := listen("tproxy", "tcp", flags.TproxyTCP)
if err != nil {
log.Fatal(err)
}
logf("tproxy tcp %v", flags.TproxyTCP)
go tcpLocal(l, d)
}
}

Expand Down
53 changes: 5 additions & 48 deletions tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,64 +9,23 @@ import (
"github.com/riobard/go-shadowsocks2/socks"
)

func tcpKeepAlive(c net.Conn) {
if tcp, ok := c.(*net.TCPConn); ok {
tcp.SetKeepAlive(true)
tcp.SetKeepAlivePeriod(3 * time.Minute)
}
}

// Create a SOCKS server listening on addr and proxy to server.
func socksLocal(addr string, d Dialer) {
logf("SOCKS proxy %s", addr)
tcpLocal(addr, d, func(c net.Conn) (socks.Addr, error) { return socks.Handshake(c) })
}

// Create a TCP tunnel from addr to target via server.
func tcpTun(addr, target string, d Dialer) {
tgt := socks.ParseAddr(target)
if tgt == nil {
logf("invalid target address %q", target)
return
}
logf("TCP tunnel %s <-> %s", addr, target)
tcpLocal(addr, d, func(net.Conn) (socks.Addr, error) { return tgt, nil })
}

// Listen on addr and proxy to server to reach target from getAddr.
func tcpLocal(addr string, d Dialer, getAddr func(net.Conn) (socks.Addr, error)) {
l, err := net.Listen("tcp", addr)
if err != nil {
logf("failed to listen on %s: %v", addr, err)
return
}

func tcpLocal(l net.Listener, d Dialer) {
for {
c, err := l.Accept()
if err != nil {
logf("failed to accept: %s", err)
logf("failed to accept: %v", err)
continue
}

go func() {
defer c.Close()
tcpKeepAlive(c)

tgt, err := getAddr(c)
if err != nil {
logf("failed to get target address: %v", err)
return
}

rc, err := d.Dial("tcp", tgt.String())
laddr := c.LocalAddr()
rc, err := d.Dial(laddr.Network(), laddr.String())
if err != nil {
logf("failed to connect: %v", err)
return
}
defer rc.Close()
tcpKeepAlive(rc)

logf("proxy %s <--[%s]--> %s", c.RemoteAddr(), rc.RemoteAddr(), tgt)
logf("proxy %s <--[%s]--> %s", c.RemoteAddr(), rc.RemoteAddr(), laddr)
if err = relay(rc, c); err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
return // ignore i/o timeout
Expand Down Expand Up @@ -95,7 +54,6 @@ func tcpRemote(addr string, shadow func(net.Conn) net.Conn) {

go func() {
defer c.Close()
tcpKeepAlive(c)
c = shadow(c)

tgt, err := socks.ReadAddr(c)
Expand All @@ -110,7 +68,6 @@ func tcpRemote(addr string, shadow func(net.Conn) net.Conn) {
return
}
defer rc.Close()
tcpKeepAlive(rc)

logf("proxy %s <-> %s", c.RemoteAddr(), tgt)
if err = relay(c, rc); err != nil {
Expand Down
20 changes: 0 additions & 20 deletions tcp_darwin.go

This file was deleted.

Loading

0 comments on commit 695d571

Please sign in to comment.