Files
tun2socks/proxy/shadowsocks/tcp.go
2019-07-16 11:37:52 +08:00

86 lines
1.9 KiB
Go

package shadowsocks
import (
"errors"
"fmt"
"io"
"net"
"strconv"
sscore "github.com/shadowsocks/go-shadowsocks2/core"
sssocks "github.com/shadowsocks/go-shadowsocks2/socks"
"github.com/xjasonlyu/tun2socks/common/dns"
"github.com/xjasonlyu/tun2socks/common/log"
"github.com/xjasonlyu/tun2socks/core"
)
type tcpHandler struct {
cipher sscore.Cipher
server string
fakeDns dns.FakeDns
}
func (h *tcpHandler) handleInput(conn net.Conn, input io.ReadCloser) {
defer func() {
conn.Close()
input.Close()
}()
io.Copy(conn, input)
}
func (h *tcpHandler) handleOutput(conn net.Conn, output io.WriteCloser) {
defer func() {
conn.Close()
output.Close()
}()
io.Copy(output, conn)
}
func NewTCPHandler(server, cipher, password string, fakeDns dns.FakeDns) core.TCPConnHandler {
ciph, err := sscore.PickCipher(cipher, []byte{}, password)
if err != nil {
log.Errorf("failed to pick a cipher: %v", err)
}
return &tcpHandler{
cipher: ciph,
server: server,
fakeDns: fakeDns,
}
}
func (h *tcpHandler) Handle(conn net.Conn, target *net.TCPAddr) error {
if target == nil {
log.Fatalf("unexpected nil target")
}
// Connect the relay server.
rc, err := net.Dial("tcp", h.server)
if err != nil {
return errors.New(fmt.Sprintf("dial remote server failed: %v", err))
}
rc = h.cipher.StreamConn(rc)
// Replace with a domain name if target address IP is a fake IP.
var targetHost string
if h.fakeDns != nil && h.fakeDns.IsFakeIP(target.IP) {
targetHost = h.fakeDns.QueryDomain(target.IP)
} else {
targetHost = target.IP.String()
}
dest := net.JoinHostPort(targetHost, strconv.Itoa(target.Port))
// Write target address.
tgt := sssocks.ParseAddr(dest)
_, err = rc.Write(tgt)
if err != nil {
return fmt.Errorf("send target address failed: %v", err)
}
go h.handleInput(conn, rc)
go h.handleOutput(conn, rc)
log.Infof("new proxy connection for target: %s:%s", target.Network(), dest)
return nil
}