mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2024-04-21 12:21:34 +00:00
83 lines
2.2 KiB
Go
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
|
|
}
|