Files
trojan-go/tunnel/shadowsocks/server.go
T

83 lines
2.2 KiB
Go

package shadowsocks
import (
"context"
"net"
"github.com/shadowsocks/go-shadowsocks2/core"
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/config"
"github.com/p4gefau1t/trojan-go/log"
"github.com/p4gefau1t/trojan-go/redirector"
"github.com/p4gefau1t/trojan-go/tunnel"
)
type Server struct {
core.Cipher
*redirector.Redirector
underlay tunnel.Server
redirAddr net.Addr
}
func (s *Server) AcceptConn(overlay tunnel.Tunnel) (tunnel.Conn, error) {
conn, err := s.underlay.AcceptConn(&Tunnel{})
if err != nil {
return nil, common.NewError("shadowsocks failed to accept connection from underlying tunnel").Base(err)
}
rewindConn := common.NewRewindConn(conn)
rewindConn.SetBufferSize(1024)
defer rewindConn.StopBuffering()
// try to read something from this connection
buf := [1024]byte{}
testConn := s.Cipher.StreamConn(rewindConn)
if _, err := testConn.Read(buf[:]); err != nil {
// we are under attack
log.Error(common.NewError("shadowsocks failed to decrypt").Base(err))
rewindConn.Rewind()
rewindConn.StopBuffering()
s.Redirect(&redirector.Redirection{
RedirectTo: s.redirAddr,
InboundConn: rewindConn,
})
return nil, common.NewError("invalid aead payload")
}
rewindConn.Rewind()
rewindConn.StopBuffering()
return &Conn{
aeadConn: s.Cipher.StreamConn(rewindConn),
Conn: conn,
}, nil
}
func (s *Server) AcceptPacket(t tunnel.Tunnel) (tunnel.PacketConn, error) {
panic("not supported")
}
func (s *Server) Close() error {
return s.underlay.Close()
}
func NewServer(ctx context.Context, underlay tunnel.Server) (*Server, error) {
cfg := config.FromContext(ctx, Name).(*Config)
cipher, err := core.PickCipher(cfg.Shadowsocks.Method, nil, cfg.Shadowsocks.Password)
if err != nil {
return nil, common.NewError("invalid shadowsocks cipher").Base(err)
}
if cfg.RemoteHost == "" {
return nil, common.NewError("invalid shadowsocks redirection address")
}
if cfg.RemotePort == 0 {
return nil, common.NewError("invalid shadowsocks redirection port")
}
log.Debug("shadowsocks client created")
return &Server{
underlay: underlay,
Cipher: cipher,
Redirector: redirector.NewRedirector(ctx),
redirAddr: tunnel.NewAddressFromHostPort("tcp", cfg.RemoteHost, cfg.RemotePort),
}, nil
}