648 lines
13 KiB
Go
648 lines
13 KiB
Go
package gost
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/url"
|
|
"time"
|
|
|
|
"github.com/go-gost/gosocks5"
|
|
"github.com/go-log/log"
|
|
"github.com/shadowsocks/go-shadowsocks2/core"
|
|
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
|
)
|
|
|
|
const (
|
|
maxSocksAddrLen = 259
|
|
)
|
|
|
|
var (
|
|
_ net.Conn = (*shadowConn)(nil)
|
|
_ net.PacketConn = (*shadowUDPPacketConn)(nil)
|
|
)
|
|
|
|
type shadowConnector struct {
|
|
cipher core.Cipher
|
|
}
|
|
|
|
// ShadowConnector creates a Connector for shadowsocks proxy client.
|
|
// It accepts an optional cipher info for shadowsocks data encryption/decryption.
|
|
func ShadowConnector(info *url.Userinfo) Connector {
|
|
return &shadowConnector{
|
|
cipher: initShadowCipher(info),
|
|
}
|
|
}
|
|
|
|
func (c *shadowConnector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) {
|
|
return c.ConnectContext(context.Background(), conn, "tcp", address, options...)
|
|
}
|
|
|
|
func (c *shadowConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) {
|
|
switch network {
|
|
case "udp", "udp4", "udp6":
|
|
return nil, fmt.Errorf("%s unsupported", network)
|
|
}
|
|
|
|
opts := &ConnectOptions{}
|
|
for _, option := range options {
|
|
option(opts)
|
|
}
|
|
|
|
timeout := opts.Timeout
|
|
if timeout <= 0 {
|
|
timeout = ConnectTimeout
|
|
}
|
|
|
|
socksAddr, err := gosocks5.NewAddr(address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rawaddr := sPool.Get().([]byte)
|
|
defer sPool.Put(rawaddr)
|
|
|
|
n, err := socksAddr.Encode(rawaddr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
conn.SetDeadline(time.Now().Add(timeout))
|
|
defer conn.SetDeadline(time.Time{})
|
|
|
|
if c.cipher != nil {
|
|
conn = c.cipher.StreamConn(conn)
|
|
}
|
|
|
|
sc := &shadowConn{
|
|
Conn: conn,
|
|
}
|
|
|
|
// write the addr at once.
|
|
if opts.NoDelay {
|
|
if _, err := sc.Write(rawaddr[:n]); err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
sc.wbuf.Write(rawaddr[:n]) // cache the header
|
|
}
|
|
|
|
return sc, nil
|
|
}
|
|
|
|
type shadowHandler struct {
|
|
cipher core.Cipher
|
|
options *HandlerOptions
|
|
}
|
|
|
|
// ShadowHandler creates a server Handler for shadowsocks proxy server.
|
|
func ShadowHandler(opts ...HandlerOption) Handler {
|
|
h := &shadowHandler{}
|
|
h.Init(opts...)
|
|
|
|
return h
|
|
}
|
|
|
|
func (h *shadowHandler) Init(options ...HandlerOption) {
|
|
if h.options == nil {
|
|
h.options = &HandlerOptions{}
|
|
}
|
|
|
|
for _, opt := range options {
|
|
opt(h.options)
|
|
}
|
|
if len(h.options.Users) > 0 {
|
|
h.cipher = initShadowCipher(h.options.Users[0])
|
|
}
|
|
}
|
|
|
|
func (h *shadowHandler) Handle(conn net.Conn) {
|
|
defer conn.Close()
|
|
|
|
if h.cipher != nil {
|
|
conn = &shadowConn{
|
|
Conn: h.cipher.StreamConn(conn),
|
|
}
|
|
}
|
|
|
|
conn.SetReadDeadline(time.Now().Add(ReadTimeout))
|
|
|
|
addr, err := readSocksAddr(conn)
|
|
if err != nil {
|
|
log.Logf("[ss] %s -> %s : %s",
|
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
|
return
|
|
}
|
|
|
|
conn.SetReadDeadline(time.Time{})
|
|
|
|
host := addr.String()
|
|
log.Logf("[ss] %s -> %s",
|
|
conn.RemoteAddr(), host)
|
|
|
|
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {
|
|
log.Logf("[ss] %s - %s : Unauthorized to tcp connect to %s",
|
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
|
return
|
|
}
|
|
|
|
if h.options.Bypass.Contains(host) {
|
|
log.Logf("[ss] %s - %s : Bypass %s",
|
|
conn.RemoteAddr(), conn.LocalAddr(), host)
|
|
return
|
|
}
|
|
|
|
retries := 1
|
|
if h.options.Chain != nil && h.options.Chain.Retries > 0 {
|
|
retries = h.options.Chain.Retries
|
|
}
|
|
if h.options.Retries > 0 {
|
|
retries = h.options.Retries
|
|
}
|
|
|
|
var cc net.Conn
|
|
var route *Chain
|
|
for i := 0; i < retries; i++ {
|
|
route, err = h.options.Chain.selectRouteFor(host)
|
|
if err != nil {
|
|
log.Logf("[ss] %s -> %s : %s",
|
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
|
continue
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
fmt.Fprintf(&buf, "%s -> %s -> ",
|
|
conn.RemoteAddr(), h.options.Node.String())
|
|
for _, nd := range route.route {
|
|
fmt.Fprintf(&buf, "%d@%s -> ", nd.ID, nd.String())
|
|
}
|
|
fmt.Fprintf(&buf, "%s", host)
|
|
log.Log("[route]", buf.String())
|
|
|
|
cc, err = route.Dial(host,
|
|
TimeoutChainOption(h.options.Timeout),
|
|
HostsChainOption(h.options.Hosts),
|
|
ResolverChainOption(h.options.Resolver),
|
|
)
|
|
if err == nil {
|
|
break
|
|
}
|
|
log.Logf("[ss] %s -> %s : %s",
|
|
conn.RemoteAddr(), conn.LocalAddr(), err)
|
|
}
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer cc.Close()
|
|
|
|
log.Logf("[ss] %s <-> %s", conn.RemoteAddr(), host)
|
|
transport(conn, cc)
|
|
log.Logf("[ss] %s >-< %s", conn.RemoteAddr(), host)
|
|
}
|
|
|
|
type shadowUDPConnector struct {
|
|
cipher core.Cipher
|
|
}
|
|
|
|
// ShadowUDPConnector creates a Connector for shadowsocks UDP client.
|
|
// It accepts an optional cipher info for shadowsocks data encryption/decryption.
|
|
func ShadowUDPConnector(info *url.Userinfo) Connector {
|
|
return &shadowUDPConnector{
|
|
cipher: initShadowCipher(info),
|
|
}
|
|
}
|
|
|
|
func (c *shadowUDPConnector) Connect(conn net.Conn, address string, options ...ConnectOption) (net.Conn, error) {
|
|
return c.ConnectContext(context.Background(), conn, "udp", address, options...)
|
|
}
|
|
|
|
func (c *shadowUDPConnector) ConnectContext(ctx context.Context, conn net.Conn, network, address string, options ...ConnectOption) (net.Conn, error) {
|
|
switch network {
|
|
case "tcp", "tcp4", "tcp6":
|
|
return nil, fmt.Errorf("%s unsupported", network)
|
|
}
|
|
|
|
opts := &ConnectOptions{}
|
|
for _, option := range options {
|
|
option(opts)
|
|
}
|
|
|
|
timeout := opts.Timeout
|
|
if timeout <= 0 {
|
|
timeout = ConnectTimeout
|
|
}
|
|
|
|
conn.SetDeadline(time.Now().Add(timeout))
|
|
defer conn.SetDeadline(time.Time{})
|
|
|
|
taddr, _ := net.ResolveUDPAddr(network, address)
|
|
if taddr == nil {
|
|
taddr = &net.UDPAddr{}
|
|
}
|
|
|
|
pc, ok := conn.(net.PacketConn)
|
|
if ok {
|
|
if c.cipher != nil {
|
|
pc = c.cipher.PacketConn(pc)
|
|
}
|
|
|
|
return &shadowUDPPacketConn{
|
|
PacketConn: pc,
|
|
raddr: conn.RemoteAddr(),
|
|
taddr: taddr,
|
|
}, nil
|
|
}
|
|
|
|
if c.cipher != nil {
|
|
conn = &shadowConn{
|
|
Conn: c.cipher.StreamConn(conn),
|
|
}
|
|
}
|
|
|
|
return &socks5UDPTunnelConn{
|
|
Conn: conn,
|
|
taddr: taddr,
|
|
}, nil
|
|
}
|
|
|
|
type shadowUDPHandler struct {
|
|
cipher core.Cipher
|
|
options *HandlerOptions
|
|
}
|
|
|
|
// ShadowUDPHandler creates a server Handler for shadowsocks UDP relay server.
|
|
func ShadowUDPHandler(opts ...HandlerOption) Handler {
|
|
h := &shadowUDPHandler{}
|
|
h.Init(opts...)
|
|
|
|
return h
|
|
}
|
|
|
|
func (h *shadowUDPHandler) Init(options ...HandlerOption) {
|
|
if h.options == nil {
|
|
h.options = &HandlerOptions{}
|
|
}
|
|
for _, opt := range options {
|
|
opt(h.options)
|
|
}
|
|
if len(h.options.Users) > 0 {
|
|
h.cipher = initShadowCipher(h.options.Users[0])
|
|
}
|
|
}
|
|
|
|
func (h *shadowUDPHandler) Handle(conn net.Conn) {
|
|
defer conn.Close()
|
|
|
|
var cc net.PacketConn
|
|
c, err := h.options.Chain.DialContext(context.Background(), "udp", "")
|
|
if err != nil {
|
|
log.Logf("[ssu] %s: %s", conn.LocalAddr(), err)
|
|
return
|
|
}
|
|
var ok bool
|
|
cc, ok = c.(net.PacketConn)
|
|
if !ok {
|
|
log.Logf("[ssu] %s: not a packet connection", conn.LocalAddr())
|
|
return
|
|
}
|
|
|
|
defer cc.Close()
|
|
|
|
pc, ok := conn.(net.PacketConn)
|
|
if ok {
|
|
if h.cipher != nil {
|
|
pc = h.cipher.PacketConn(pc)
|
|
}
|
|
log.Logf("[ssu] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr())
|
|
h.transportPacket(pc, cc)
|
|
log.Logf("[ssu] %s >-< %s", conn.RemoteAddr(), conn.LocalAddr())
|
|
return
|
|
}
|
|
|
|
if h.cipher != nil {
|
|
conn = &shadowConn{
|
|
Conn: h.cipher.StreamConn(conn),
|
|
}
|
|
}
|
|
|
|
log.Logf("[ssu] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr())
|
|
h.transportUDP(conn, cc)
|
|
log.Logf("[ssu] %s >-< %s", conn.RemoteAddr(), conn.LocalAddr())
|
|
}
|
|
|
|
func (h *shadowUDPHandler) transportPacket(conn, cc net.PacketConn) (err error) {
|
|
errc := make(chan error, 1)
|
|
var clientAddr net.Addr
|
|
|
|
go func() {
|
|
for {
|
|
err := func() error {
|
|
b := mPool.Get().([]byte)
|
|
defer mPool.Put(b)
|
|
|
|
n, addr, err := conn.ReadFrom(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if clientAddr == nil {
|
|
clientAddr = addr
|
|
}
|
|
|
|
r := bytes.NewBuffer(b[:n])
|
|
saddr, err := readSocksAddr(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
taddr, err := net.ResolveUDPAddr("udp", saddr.String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if Debug {
|
|
log.Logf("[ssu] %s >>> %s length: %d", addr, taddr, r.Len())
|
|
}
|
|
_, err = cc.WriteTo(r.Bytes(), taddr)
|
|
return err
|
|
}()
|
|
|
|
if err != nil {
|
|
errc <- err
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
for {
|
|
err := func() error {
|
|
b := mPool.Get().([]byte)
|
|
defer mPool.Put(b)
|
|
|
|
n, addr, err := cc.ReadFrom(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if clientAddr == nil {
|
|
return nil
|
|
}
|
|
|
|
if Debug {
|
|
log.Logf("[ssu] %s <<< %s length: %d", clientAddr, addr, n)
|
|
}
|
|
|
|
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(addr)), b[:n])
|
|
buf := bytes.Buffer{}
|
|
if err = dgram.Write(&buf); err != nil {
|
|
return err
|
|
}
|
|
_, err = conn.WriteTo(buf.Bytes()[3:], clientAddr)
|
|
return err
|
|
}()
|
|
|
|
if err != nil {
|
|
errc <- err
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
select {
|
|
case err = <-errc:
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (h *shadowUDPHandler) transportUDP(conn net.Conn, cc net.PacketConn) error {
|
|
errc := make(chan error, 1)
|
|
|
|
go func() {
|
|
for {
|
|
er := func() (err error) {
|
|
dgram, err := gosocks5.ReadUDPDatagram(conn)
|
|
if err != nil {
|
|
// log.Logf("[ssu] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
|
return
|
|
}
|
|
if Debug {
|
|
log.Logf("[ssu] %s >>> %s length: %d",
|
|
conn.RemoteAddr(), dgram.Header.Addr.String(), len(dgram.Data))
|
|
}
|
|
addr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String())
|
|
if err != nil {
|
|
return
|
|
}
|
|
if h.options.Bypass.Contains(addr.String()) {
|
|
log.Log("[ssu] bypass", addr)
|
|
return // bypass
|
|
}
|
|
_, err = cc.WriteTo(dgram.Data, addr)
|
|
return
|
|
}()
|
|
|
|
if er != nil {
|
|
errc <- er
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
for {
|
|
er := func() (err error) {
|
|
b := mPool.Get().([]byte)
|
|
defer mPool.Put(b)
|
|
|
|
n, addr, err := cc.ReadFrom(b)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if Debug {
|
|
log.Logf("[ssu] %s <<< %s length: %d", conn.RemoteAddr(), addr, n)
|
|
}
|
|
if h.options.Bypass.Contains(addr.String()) {
|
|
log.Log("[ssu] bypass", addr)
|
|
return // bypass
|
|
}
|
|
dgram := gosocks5.NewUDPDatagram(
|
|
gosocks5.NewUDPHeader(uint16(n), 0, toSocksAddr(addr)), b[:n])
|
|
buf := bytes.Buffer{}
|
|
dgram.Write(&buf)
|
|
_, err = conn.Write(buf.Bytes())
|
|
return
|
|
}()
|
|
|
|
if er != nil {
|
|
errc <- er
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
err := <-errc
|
|
if err != nil && err == io.EOF {
|
|
err = nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Due to in/out byte length is inconsistent of the shadowsocks.Conn.Write,
|
|
// we wrap around it to make io.Copy happy.
|
|
type shadowConn struct {
|
|
net.Conn
|
|
wbuf bytes.Buffer
|
|
}
|
|
|
|
func (c *shadowConn) Write(b []byte) (n int, err error) {
|
|
n = len(b) // force byte length consistent
|
|
if c.wbuf.Len() > 0 {
|
|
c.wbuf.Write(b) // append the data to the cached header
|
|
_, err = c.Conn.Write(c.wbuf.Bytes())
|
|
c.wbuf.Reset()
|
|
return
|
|
}
|
|
_, err = c.Conn.Write(b)
|
|
return
|
|
}
|
|
|
|
type shadowUDPPacketConn struct {
|
|
net.PacketConn
|
|
raddr net.Addr
|
|
taddr net.Addr
|
|
}
|
|
|
|
func (c *shadowUDPPacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
|
buf := mPool.Get().([]byte)
|
|
defer mPool.Put(buf)
|
|
|
|
buf[0] = 0
|
|
buf[1] = 0
|
|
buf[2] = 0
|
|
|
|
n, _, err = c.PacketConn.ReadFrom(buf[3:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
dgram, err := gosocks5.ReadUDPDatagram(bytes.NewReader(buf[:n+3]))
|
|
if err != nil {
|
|
return
|
|
}
|
|
n = copy(b, dgram.Data)
|
|
addr, err = net.ResolveUDPAddr("udp", dgram.Header.Addr.String())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
func (c *shadowUDPPacketConn) Read(b []byte) (n int, err error) {
|
|
n, _, err = c.ReadFrom(b)
|
|
return
|
|
}
|
|
|
|
func (c *shadowUDPPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
|
sa, err := gosocks5.NewAddr(addr.String())
|
|
if err != nil {
|
|
return
|
|
}
|
|
var rawaddr [maxSocksAddrLen]byte
|
|
nn, err := sa.Encode(rawaddr[:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
buf := mPool.Get().([]byte)
|
|
defer mPool.Put(buf)
|
|
|
|
copy(buf, rawaddr[:nn])
|
|
n = copy(buf[nn:], b)
|
|
_, err = c.PacketConn.WriteTo(buf[:n+nn], c.raddr)
|
|
|
|
return
|
|
}
|
|
|
|
func (c *shadowUDPPacketConn) Write(b []byte) (n int, err error) {
|
|
return c.WriteTo(b, c.taddr)
|
|
}
|
|
|
|
func (c *shadowUDPPacketConn) RemoteAddr() net.Addr {
|
|
return c.raddr
|
|
}
|
|
|
|
type shadowCipher struct {
|
|
cipher *ss.Cipher
|
|
}
|
|
|
|
func (c *shadowCipher) StreamConn(conn net.Conn) net.Conn {
|
|
return ss.NewConn(conn, c.cipher.Copy())
|
|
}
|
|
|
|
func (c *shadowCipher) PacketConn(conn net.PacketConn) net.PacketConn {
|
|
return ss.NewSecurePacketConn(conn, c.cipher.Copy())
|
|
}
|
|
|
|
func initShadowCipher(info *url.Userinfo) (cipher core.Cipher) {
|
|
var method, password string
|
|
if info != nil {
|
|
method = info.Username()
|
|
password, _ = info.Password()
|
|
}
|
|
|
|
if method == "" || password == "" {
|
|
return
|
|
}
|
|
|
|
cp, _ := ss.NewCipher(method, password)
|
|
if cp != nil {
|
|
cipher = &shadowCipher{cipher: cp}
|
|
}
|
|
if cipher == nil {
|
|
var err error
|
|
cipher, err = core.PickCipher(method, nil, password)
|
|
if err != nil {
|
|
log.Logf("[ss] %s", err)
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func readSocksAddr(r io.Reader) (*gosocks5.Addr, error) {
|
|
addr := &gosocks5.Addr{}
|
|
b := sPool.Get().([]byte)
|
|
defer sPool.Put(b)
|
|
|
|
_, err := io.ReadFull(r, b[:1])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
addr.Type = b[0]
|
|
|
|
switch addr.Type {
|
|
case gosocks5.AddrIPv4:
|
|
_, err = io.ReadFull(r, b[:net.IPv4len])
|
|
addr.Host = net.IP(b[0:net.IPv4len]).String()
|
|
case gosocks5.AddrIPv6:
|
|
_, err = io.ReadFull(r, b[:net.IPv6len])
|
|
addr.Host = net.IP(b[0:net.IPv6len]).String()
|
|
case gosocks5.AddrDomain:
|
|
if _, err = io.ReadFull(r, b[:1]); err != nil {
|
|
return nil, err
|
|
}
|
|
addrlen := int(b[0])
|
|
_, err = io.ReadFull(r, b[:addrlen])
|
|
addr.Host = string(b[:addrlen])
|
|
default:
|
|
return nil, gosocks5.ErrBadAddrType
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, err = io.ReadFull(r, b[:2])
|
|
addr.Port = binary.BigEndian.Uint16(b[:2])
|
|
return addr, err
|
|
}
|