├── x ├── trojanx │ ├── Makefile │ ├── .gitignore │ ├── internal │ │ ├── pool │ │ │ └── pool.go │ │ ├── pipe │ │ │ └── pipe.go │ │ ├── tunnel │ │ │ ├── udpConn.go │ │ │ └── trojanConn.go │ │ └── common │ │ │ └── common.go │ ├── config.go │ ├── LICENSE │ ├── option.go │ ├── example │ │ ├── main.go │ │ └── selfsign.go │ ├── callback.go │ ├── README.md │ └── protocol │ │ └── protocol.go ├── socks5 │ ├── .travis.yml │ ├── .gitignore │ ├── resolver_test.go │ ├── credentials_test.go │ ├── credentials.go │ ├── ruleset_test.go │ ├── resolver.go │ ├── README.md │ ├── LICENSE │ ├── ruleset.go │ ├── relay.go │ ├── socks5_test.go │ ├── auth_test.go │ └── auth.go ├── kcp │ ├── assets │ │ ├── flame.png │ │ ├── frame.png │ │ └── kcp-go.png │ ├── wireshark │ │ ├── README.md │ │ └── kcp_dissector.lua │ ├── transport.go │ ├── pkg.go │ ├── .gitignore │ ├── .travis.yml │ ├── LICENSE │ ├── tx_generic.go │ ├── readloop_generic.go │ ├── resolver.go │ ├── batchconn.go │ ├── tx.go │ ├── conn.go │ ├── readloop.go │ ├── entropy.go │ ├── tx_linux.go │ ├── icmp.go │ ├── autotune_test.go │ ├── buffer.go │ ├── autotune.go │ ├── fec_test.go │ ├── readloop_linux.go │ └── kcp_test.go └── utils │ ├── aes_test.go │ ├── map.go │ ├── clash.go │ ├── log.go │ ├── xor.go │ ├── address.go │ ├── aes.go │ └── tls.go ├── rem.go ├── .gitignore ├── protocol ├── cio │ ├── writer.go │ ├── reader.go │ ├── limiter.go │ ├── buffer.go │ ├── conn.go │ └── io.go ├── serve │ ├── raw │ │ └── raw.go │ ├── portforward │ │ └── forward.go │ ├── trojan │ │ ├── utils.go │ │ └── trojan.go │ └── externalc2 │ │ └── externalc2.go ├── core │ ├── proxy.go │ ├── outbound.go │ ├── consts.go │ ├── inbound.go │ ├── wrapper.go │ └── tunnel.go ├── message │ ├── extend.go │ ├── msg.proto │ └── msg.go ├── wrapper │ ├── snappy_test.go │ ├── snappy.go │ ├── xor.go │ ├── aes.go │ ├── wrapper.go │ ├── padding.go │ └── websocket.go └── tunnel │ ├── unix │ ├── unix.go │ ├── unix_unix.go │ └── unix_windows.go │ ├── advance.go │ ├── tcp │ └── tcp.go │ ├── udp │ └── udp.go │ ├── http │ └── http.go │ ├── icmp │ └── icmp.go │ ├── websocket │ └── websocket.go │ ├── memory │ └── memory.go │ └── tunnel.go ├── runner ├── index.go ├── runner.go └── console_test.go ├── agent └── config.go ├── README.md ├── .goreleaser.yml ├── go.mod ├── cmd └── cmd │ └── cmd.go └── .github └── workflows └── release.yml /x/trojanx/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | go test 3 | -------------------------------------------------------------------------------- /x/socks5/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.1 4 | - tip 5 | -------------------------------------------------------------------------------- /x/trojanx/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | 4 | .DS_Store 5 | 6 | /build 7 | -------------------------------------------------------------------------------- /x/kcp/assets/flame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chainreactors/rem/HEAD/x/kcp/assets/flame.png -------------------------------------------------------------------------------- /x/kcp/assets/frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chainreactors/rem/HEAD/x/kcp/assets/frame.png -------------------------------------------------------------------------------- /x/kcp/assets/kcp-go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chainreactors/rem/HEAD/x/kcp/assets/kcp-go.png -------------------------------------------------------------------------------- /x/kcp/wireshark/README.md: -------------------------------------------------------------------------------- 1 | ## macOS 2 | - Copy kcp_dissector.lua to /Applications/Wireshark.app/Contents/PlugIns/wireshark 3 | -------------------------------------------------------------------------------- /x/utils/aes_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestPKCS7Padding(t *testing.T) { 8 | print(string(PKCS7Padding([]byte{}, 16))) 9 | } 10 | -------------------------------------------------------------------------------- /x/kcp/transport.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | import ( 4 | "net" 5 | ) 6 | 7 | // PacketConn is the basic interface for packet-based connections 8 | type PacketConn interface { 9 | net.PacketConn 10 | } 11 | -------------------------------------------------------------------------------- /rem.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/chainreactors/rem/cmd/cmd" 5 | ) 6 | 7 | //go:generate protoc --go_out=paths=source_relative:. .\message\msg.proto 8 | func main() { 9 | cmd.RUN() 10 | } 11 | -------------------------------------------------------------------------------- /x/utils/map.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func MergeMaps(map1, map2 map[string]string) map[string]string { 4 | mergedMap := make(map[string]string) 5 | 6 | for key, value := range map1 { 7 | mergedMap[key] = value 8 | } 9 | 10 | for key, value := range map2 { 11 | mergedMap[key] = value 12 | } 13 | 14 | return mergedMap 15 | } 16 | -------------------------------------------------------------------------------- /x/socks5/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /x/kcp/pkg.go: -------------------------------------------------------------------------------- 1 | // Package kcp-go is a Reliable-UDP library for golang. 2 | // 3 | // This library intents to provide a smooth, resilient, ordered, 4 | // error-checked and anonymous delivery of streams over UDP packets. 5 | // 6 | // The interfaces of this package aims to be compatible with 7 | // net.Conn in standard library, but offers powerful features for advanced users. 8 | package kcp 9 | -------------------------------------------------------------------------------- /x/kcp/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | /vendor/ 10 | 11 | # Architecture specific extensions/prefixes 12 | *.[568vq] 13 | [568vq].out 14 | 15 | *.cgo1.go 16 | *.cgo2.c 17 | _cgo_defun.c 18 | _cgo_gotypes.go 19 | _cgo_export.* 20 | 21 | _testmain.go 22 | 23 | *.exe 24 | *.test 25 | *.prof 26 | -------------------------------------------------------------------------------- /x/trojanx/internal/pool/pool.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import "sync" 4 | 5 | const ( 6 | DefaultSize = 4096 7 | ) 8 | 9 | var pool = sync.Pool{ 10 | New: func() interface{} { 11 | return make([]byte, DefaultSize) 12 | }, 13 | } 14 | 15 | func Get() []byte { 16 | return pool.Get().([]byte) 17 | } 18 | 19 | func Put(b []byte) { 20 | if len(b) == DefaultSize { 21 | pool.Put(b) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Go template 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | *.log 15 | 16 | # Dependency directories (remove the comment below to include it) 17 | # vendor/ 18 | .idea/ 19 | /bin 20 | /dist 21 | -------------------------------------------------------------------------------- /x/socks5/resolver_test.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "testing" 5 | 6 | "context" 7 | ) 8 | 9 | func TestDNSResolver(t *testing.T) { 10 | d := DNSResolver{} 11 | ctx := context.Background() 12 | 13 | _, addr, err := d.Resolve(ctx, "localhost") 14 | if err != nil { 15 | t.Fatalf("err: %v", err) 16 | } 17 | 18 | if !addr.IsLoopback() { 19 | t.Fatalf("expected loopback") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /x/socks5/credentials_test.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestStaticCredentials(t *testing.T) { 8 | creds := StaticCredentials{ 9 | "foo": "bar", 10 | "baz": "", 11 | } 12 | 13 | if !creds.Valid("foo", "bar") { 14 | t.Fatalf("expect valid") 15 | } 16 | 17 | if !creds.Valid("baz", "") { 18 | t.Fatalf("expect valid") 19 | } 20 | 21 | if creds.Valid("foo", "") { 22 | t.Fatalf("expect invalid") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /x/kcp/.travis.yml: -------------------------------------------------------------------------------- 1 | arch: 2 | - amd64 3 | - ppc64le 4 | language: go 5 | 6 | go: 7 | - 1.11.x 8 | - 1.12.x 9 | - 1.13.x 10 | 11 | env: 12 | - GO111MODULE=on 13 | 14 | before_install: 15 | - go get -t -v ./... 16 | 17 | install: 18 | - go get github.com/xtaci/kcp-go 19 | 20 | script: 21 | - go test -coverprofile=coverage.txt -covermode=atomic -bench . -timeout 10m 22 | 23 | after_success: 24 | - bash <(curl -s https://codecov.io/bash) 25 | -------------------------------------------------------------------------------- /x/socks5/credentials.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | // CredentialStore is used to support user/pass authentication 4 | type CredentialStore interface { 5 | Valid(user, password string) bool 6 | } 7 | 8 | // StaticCredentials enables using a map directly as a credential store 9 | type StaticCredentials map[string]string 10 | 11 | func (s StaticCredentials) Valid(user, password string) bool { 12 | pass, ok := s[user] 13 | if !ok { 14 | return false 15 | } 16 | return password == pass 17 | } 18 | -------------------------------------------------------------------------------- /protocol/cio/writer.go: -------------------------------------------------------------------------------- 1 | package cio 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | ) 7 | 8 | type Writer struct { 9 | writer *bufio.Writer 10 | } 11 | 12 | func NewWriter(conn io.Writer) *Writer { 13 | return &Writer{ 14 | writer: bufio.NewWriter(conn), 15 | } 16 | } 17 | 18 | // Write 将数据写入缓冲区。 19 | func (bd *Writer) Write(data []byte) (int, error) { 20 | n, err := bd.writer.Write(data) 21 | if err != nil { 22 | return 0, err 23 | } 24 | err = bd.writer.Flush() 25 | if err != nil { 26 | return 0, err 27 | } 28 | return n, nil 29 | } 30 | -------------------------------------------------------------------------------- /x/socks5/ruleset_test.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "testing" 5 | 6 | "context" 7 | ) 8 | 9 | func TestPermitCommand(t *testing.T) { 10 | ctx := context.Background() 11 | r := &PermitCommand{true, false, false} 12 | 13 | if _, ok := r.Allow(ctx, &Request{Command: ConnectCommand}); !ok { 14 | t.Fatalf("expect connect") 15 | } 16 | 17 | if _, ok := r.Allow(ctx, &Request{Command: BindCommand}); ok { 18 | t.Fatalf("do not expect bind") 19 | } 20 | 21 | if _, ok := r.Allow(ctx, &Request{Command: AssociateCommand}); ok { 22 | t.Fatalf("do not expect associate") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /x/socks5/resolver.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "net" 5 | 6 | "context" 7 | ) 8 | 9 | // NameResolver is used to implement custom name resolution 10 | type NameResolver interface { 11 | Resolve(ctx context.Context, name string) (context.Context, net.IP, error) 12 | } 13 | 14 | // DNSResolver uses the system DNS to resolve host names 15 | type DNSResolver struct{} 16 | 17 | func (d DNSResolver) Resolve(ctx context.Context, name string) (context.Context, net.IP, error) { 18 | addr, err := net.ResolveIPAddr("ip", name) 19 | if err != nil { 20 | return ctx, nil, err 21 | } 22 | return ctx, addr.IP, err 23 | } 24 | -------------------------------------------------------------------------------- /x/trojanx/internal/pipe/pipe.go: -------------------------------------------------------------------------------- 1 | package pipe 2 | 3 | import ( 4 | "github.com/chainreactors/rem/x/trojanx/internal/pool" 5 | "github.com/pkg/errors" 6 | "io" 7 | "net" 8 | ) 9 | 10 | func Copy(dst net.Conn, src net.Conn) (written int64, err error) { 11 | defer dst.Close() 12 | buffer := pool.Get() 13 | defer pool.Put(buffer) 14 | for { 15 | n, err := src.Read(buffer) 16 | if n > 0 { 17 | n, err := dst.Write(buffer[:n]) 18 | if err != nil { 19 | if errors.Is(err, io.EOF) { 20 | return written, nil 21 | } 22 | return written, err 23 | } 24 | written += int64(n) 25 | } 26 | if err != nil { 27 | return written, err 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /protocol/serve/raw/raw.go: -------------------------------------------------------------------------------- 1 | package raw 2 | 3 | import ( 4 | "io" 5 | "net" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | "github.com/chainreactors/rem/x/utils" 9 | ) 10 | 11 | func init() { 12 | core.InboundRegister(core.RawServe, NewRawInbound) 13 | } 14 | 15 | func NewRawInbound(params map[string]string) (core.Inbound, error) { 16 | utils.Log.Importantf("[agent.inbound] raw relay serving") 17 | return &RawPlugin{}, nil 18 | } 19 | 20 | type RawPlugin struct { 21 | } 22 | 23 | func (r *RawPlugin) Name() string { 24 | return core.RawServe 25 | } 26 | 27 | func (r *RawPlugin) ToClash() *utils.Proxies { 28 | return nil 29 | } 30 | 31 | func (r *RawPlugin) Relay(conn net.Conn, bridge io.ReadWriteCloser) (net.Conn, error) { 32 | return conn, nil 33 | } 34 | -------------------------------------------------------------------------------- /protocol/core/proxy.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "context" 5 | "github.com/chainreactors/proxyclient" 6 | "net" 7 | ) 8 | 9 | type ContextDialer interface { 10 | DialContext(ctx context.Context, network, address string) (net.Conn, error) 11 | Dial(network, address string) (net.Conn, error) 12 | } 13 | 14 | func NewProxyDialer(client proxyclient.Dial) *ProxyDialer { 15 | return &ProxyDialer{dial: client} 16 | } 17 | 18 | type ProxyDialer struct { 19 | dial proxyclient.Dial 20 | } 21 | 22 | func (client *ProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { 23 | return client.dial.DialContext(ctx, network, address) 24 | } 25 | 26 | func (client *ProxyDialer) Dial(network, address string) (net.Conn, error) { 27 | return client.dial.Dial(network, address) 28 | } 29 | -------------------------------------------------------------------------------- /protocol/message/extend.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "fmt" 5 | "github.com/chainreactors/rem/protocol/core" 6 | ) 7 | 8 | func (c *Control) LocalURL() *core.URL { 9 | u, _ := core.NewURL(c.Local) 10 | return u 11 | } 12 | 13 | func (c *Control) RemoteURL() *core.URL { 14 | u, _ := core.NewURL(c.Remote) 15 | return u 16 | } 17 | 18 | // 19 | //func (c *Control) Username() string { 20 | // if c.Plugin != nil { 21 | // return c.Plugin.Options["username"] 22 | // } 23 | // return "" 24 | //} 25 | // 26 | //func (c *Control) Password() string { 27 | // if c.Plugin != nil { 28 | // return c.Plugin.Options["password"] 29 | // } 30 | // return "" 31 | //} 32 | 33 | func (l *Login) ConsoleURL() *core.URL { 34 | u, _ := core.NewURL(fmt.Sprintf("%s://%s:%d", l.ConsoleProto, l.ConsoleIP, l.ConsolePort)) 35 | return u 36 | } 37 | -------------------------------------------------------------------------------- /x/trojanx/config.go: -------------------------------------------------------------------------------- 1 | package trojanx 2 | 3 | import ( 4 | "crypto/tls" 5 | ) 6 | 7 | type TrojanConfig struct { 8 | Password string `json:"password"` 9 | TLSConfig *TLSConfig `json:"tls_config"` 10 | ReverseProxyConfig *ReverseProxyConfig `json:"reverse_proxy"` 11 | } 12 | 13 | type TLSConfig struct { 14 | MinVersion uint16 `json:"min_version"` 15 | MaxVersion uint16 `json:"max_version"` 16 | Certificate tls.Certificate 17 | } 18 | 19 | type CertificateFileConfig struct { 20 | PublicKeyFile string `json:"public_key_file"` 21 | PrivateKeyFile string `json:"private_key_file"` 22 | } 23 | 24 | type ReverseProxyConfig struct { 25 | RemoteURL string `json:"remote_url"` 26 | Scheme string `json:"scheme"` 27 | Host string `json:"host"` 28 | Port int `json:"port"` 29 | } 30 | -------------------------------------------------------------------------------- /protocol/wrapper/snappy_test.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "testing" 8 | ) 9 | 10 | func TestNewSnappyWrapper(t *testing.T) { 11 | originalData := []byte("Hello, this is a test for Snappy compression!") 12 | 13 | // 压缩 14 | var compressed bytes.Buffer 15 | writerWrapper := NewSnappyWrapper(nil, &compressed, nil) 16 | writerWrapper.Write(originalData) 17 | writerWrapper.Close() 18 | 19 | fmt.Printf("Original size: %d bytes, Compressed size: %d bytes\n", len(originalData), compressed.Len()) 20 | 21 | // 解压 22 | readerWrapper := NewSnappyWrapper(&compressed, nil, nil) 23 | decompressed := new(bytes.Buffer) 24 | _, err := io.Copy(decompressed, readerWrapper) 25 | if err != nil { 26 | fmt.Println("Error decompressing:", err) 27 | return 28 | } 29 | 30 | fmt.Println("Decompressed data:", decompressed.String()) 31 | } 32 | -------------------------------------------------------------------------------- /protocol/wrapper/snappy.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "github.com/chainreactors/rem/protocol/core" 5 | "github.com/golang/snappy" 6 | "io" 7 | ) 8 | 9 | type SnappyWrapper struct { 10 | reader io.Reader 11 | writer io.Writer 12 | } 13 | 14 | func NewSnappyWrapper(r io.Reader, w io.Writer, opt map[string]string) core.Wrapper { 15 | return &SnappyWrapper{ 16 | reader: snappy.NewReader(r), // 创建Snappy解压Reader 17 | writer: snappy.NewWriter(w), // 创建Snappy压缩Writer 18 | } 19 | } 20 | 21 | func (w *SnappyWrapper) Name() string { 22 | return "snappy" 23 | } 24 | 25 | func (w *SnappyWrapper) Read(p []byte) (n int, err error) { 26 | return w.reader.Read(p) // 从解压流读取数据 27 | } 28 | 29 | func (w *SnappyWrapper) Write(p []byte) (n int, err error) { 30 | return w.writer.Write(p) // 向压缩流写入数据 31 | } 32 | 33 | func (w *SnappyWrapper) Close() error { 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /x/socks5/README.md: -------------------------------------------------------------------------------- 1 | go-socks5 [![Build Status](https://travis-ci.org/armon/go-socks5.png)](https://travis-ci.org/armon/go-socks5) 2 | ========= 3 | 4 | Provides the `socks5` package that implements a [SOCKS5 server](http://en.wikipedia.org/wiki/SOCKS). 5 | SOCKS (Secure Sockets) is used to route traffic between a client and server through 6 | an intermediate proxy layer. This can be used to bypass firewalls or NATs. 7 | 8 | Feature 9 | ======= 10 | 11 | The package has the following features: 12 | * "No Auth" mode 13 | * User/Password authentication 14 | * Support for the CONNECT command 15 | * Rules to do granular filtering of commands 16 | * Custom DNS resolution 17 | * Unit tests 18 | 19 | TODO 20 | ==== 21 | 22 | The package still needs the following: 23 | * Support for the BIND command 24 | * Support for the ASSOCIATE command 25 | 26 | 27 | Example 28 | ======= 29 | 30 | Below is a simple example of usage 31 | 32 | 33 | -------------------------------------------------------------------------------- /protocol/tunnel/unix/unix.go: -------------------------------------------------------------------------------- 1 | package unix 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | ) 9 | 10 | func init() { 11 | core.DialerRegister(core.UNIXTunnel, func(ctx context.Context) (core.TunnelDialer, error) { 12 | return NewUnixDialer(ctx), nil 13 | }) 14 | core.ListenerRegister(core.UNIXTunnel, func(ctx context.Context) (core.TunnelListener, error) { 15 | return NewUnixListener(ctx), nil 16 | }) 17 | } 18 | 19 | // UnixDialer 实现了 Dial 接口 20 | type UnixDialer struct { 21 | net.Conn 22 | meta core.Metas 23 | } 24 | 25 | // UnixListener 实现了 net.Listener 接口 26 | type UnixListener struct { 27 | listener net.Listener 28 | meta core.Metas 29 | } 30 | 31 | func (c *UnixListener) Addr() net.Addr { 32 | return c.meta.URL() 33 | } 34 | 35 | func (c *UnixListener) Accept() (net.Conn, error) { 36 | return c.listener.Accept() 37 | } 38 | 39 | func (c *UnixListener) Close() error { 40 | return c.listener.Close() 41 | } 42 | -------------------------------------------------------------------------------- /x/trojanx/internal/tunnel/udpConn.go: -------------------------------------------------------------------------------- 1 | package tunnel 2 | 3 | import ( 4 | "github.com/chainreactors/rem/x/trojanx/internal/common" 5 | "net" 6 | ) 7 | 8 | type UDPConn struct { 9 | *net.UDPConn 10 | } 11 | 12 | func (c *UDPConn) WriteWithMetadata(p []byte, adder *common.Address) (int, error) { 13 | return c.WriteTo(p, adder) 14 | } 15 | 16 | func (c *UDPConn) ReadWithMetadata(p []byte) (int, *common.Address, error) { 17 | n, addr, err := c.ReadFrom(p) 18 | if err != nil { 19 | return 0, nil, err 20 | } 21 | address, err := common.NewAddressFromAddr("udp", addr.String()) 22 | return n, address, nil 23 | } 24 | 25 | func (c *UDPConn) WriteTo(p []byte, addr net.Addr) (int, error) { 26 | if udpAddr, ok := addr.(*net.UDPAddr); ok { 27 | return c.WriteToUDP(p, udpAddr) 28 | } 29 | ip, err := addr.(*common.Address).ResolveIP() 30 | if err != nil { 31 | return 0, err 32 | } 33 | udpAddr := &net.UDPAddr{ 34 | IP: ip, 35 | Port: addr.(*common.Address).Port, 36 | } 37 | return c.WriteToUDP(p, udpAddr) 38 | } 39 | -------------------------------------------------------------------------------- /protocol/core/outbound.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "github.com/chainreactors/rem/x/utils" 6 | "io" 7 | "net" 8 | ) 9 | 10 | type Outbound interface { 11 | Name() string 12 | 13 | Handle(conn io.ReadWriteCloser, realConn net.Conn) (net.Conn, error) 14 | 15 | ToClash() *utils.Proxies 16 | } 17 | 18 | var outBoundCreators = make(map[string]OutboundCreatorFn) 19 | 20 | // params has prefix "plugin_" 21 | type OutboundCreatorFn func(options map[string]string, dial ContextDialer) (Outbound, error) 22 | 23 | func OutboundRegister(name string, fn OutboundCreatorFn) { 24 | if _, exist := outBoundCreators[name]; exist { 25 | panic(fmt.Sprintf("plugin [%s] is already registered", name)) 26 | } 27 | outBoundCreators[name] = fn 28 | } 29 | 30 | func OutboundCreate(name string, options map[string]string, dialer ContextDialer) (p Outbound, err error) { 31 | if fn, ok := outBoundCreators[name]; ok { 32 | p, err = fn(options, dialer) 33 | } else { 34 | err = fmt.Errorf("plugin [%s] is not registered", name) 35 | } 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /runner/index.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | // basic 4 | import ( 5 | _ "github.com/chainreactors/rem/protocol/wrapper" 6 | ) 7 | 8 | // application 9 | import ( 10 | _ "github.com/chainreactors/rem/protocol/serve/http" 11 | _ "github.com/chainreactors/rem/protocol/serve/portforward" 12 | _ "github.com/chainreactors/rem/protocol/serve/raw" 13 | _ "github.com/chainreactors/rem/protocol/serve/socks" 14 | //_ "github.com/chainreactors/rem/protocol/serve/externalc2" 15 | //_ "github.com/chainreactors/rem/protocol/serve/shadowsocks" 16 | //_ "github.com/chainreactors/rem/protocol/serve/trojan" 17 | ) 18 | 19 | // transport 20 | import ( 21 | _ "github.com/chainreactors/rem/protocol/tunnel/http" 22 | _ "github.com/chainreactors/rem/protocol/tunnel/tcp" 23 | _ "github.com/chainreactors/rem/protocol/tunnel/udp" 24 | //_ "github.com/chainreactors/rem/protocol/tunnel/unix" 25 | //_ "github.com/chainreactors/rem/protocol/tunnel/websocket" 26 | //_ "github.com/chainreactors/rem/protocol/tunnel/wireguard" 27 | //_ "github.com/chainreactors/rem/protocol/tunnel/icmp" 28 | ) 29 | -------------------------------------------------------------------------------- /protocol/tunnel/unix/unix_unix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package unix 5 | 6 | import ( 7 | "net" 8 | "os" 9 | 10 | "github.com/chainreactors/rem/protocol/core" 11 | ) 12 | 13 | func NewUnixDialer(ctx context.Context) *UnixDialer { 14 | return &UnixDialer{ 15 | meta: core.GetMetas(ctx), 16 | } 17 | } 18 | 19 | func (c *UnixDialer) Dial(dst string) (net.Conn, error) { 20 | u, err := core.NewURL(dst) 21 | if err != nil { 22 | return nil, err 23 | } 24 | c.meta["url"] = u 25 | return net.Dial("unix", u.Path) 26 | } 27 | 28 | func NewUnixListener(ctx context.Context) *UnixListener { 29 | return &UnixListener{ 30 | meta: core.GetMetas(ctx), 31 | } 32 | } 33 | 34 | func (c *UnixListener) Listen(dst string) (net.Listener, error) { 35 | u, err := core.NewURL(dst) 36 | if err != nil { 37 | return nil, err 38 | } 39 | c.meta["url"] = u 40 | 41 | // Remove existing socket file if it exists 42 | os.Remove(u.Path) 43 | 44 | listener, err := net.Listen("unix", u.Path) 45 | if err != nil { 46 | return nil, err 47 | } 48 | c.listener = listener 49 | return listener, nil 50 | } 51 | -------------------------------------------------------------------------------- /x/trojanx/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 KallyDev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /x/kcp/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 xtaci 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /x/socks5/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Armon Dadgar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /x/trojanx/option.go: -------------------------------------------------------------------------------- 1 | package trojanx 2 | 3 | import ( 4 | "context" 5 | "github.com/sirupsen/logrus" 6 | "net" 7 | ) 8 | 9 | type Option func(s *Server) 10 | 11 | func WithLogger(l *logrus.Logger) Option { 12 | return func(s *Server) { 13 | s.logger = l 14 | } 15 | } 16 | 17 | func WithConfig(config *TrojanConfig) Option { 18 | return func(s *Server) { 19 | s.config = config 20 | } 21 | } 22 | 23 | func WithDial(dial func(ctx context.Context, network, addr string) (net.Conn, error)) Option { 24 | return func(s *Server) { 25 | s.dial = dial 26 | } 27 | } 28 | 29 | func WithConnectHandler(handler connectHandler) Option { 30 | return func(s *Server) { 31 | s.connectHandler = handler 32 | } 33 | } 34 | 35 | func WhichAuthenticationHandler(handler authenticationHandler) Option { 36 | return func(s *Server) { 37 | s.authenticationHandler = handler 38 | } 39 | } 40 | 41 | func WhichRequestHandler(handler requestHandler) Option { 42 | return func(s *Server) { 43 | s.requestHandler = handler 44 | } 45 | } 46 | 47 | func WhichErrorHandler(handler errorHandler) Option { 48 | return func(s *Server) { 49 | s.errorHandler = handler 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /x/socks5/ruleset.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | // RuleSet is used to provide custom rules to allow or prohibit actions 8 | type RuleSet interface { 9 | Allow(ctx context.Context, req *Request) (context.Context, bool) 10 | } 11 | 12 | // PermitAll returns a RuleSet which allows all types of connections 13 | func PermitAll() RuleSet { 14 | return &PermitCommand{true, true, true} 15 | } 16 | 17 | // PermitNone returns a RuleSet which disallows all types of connections 18 | func PermitNone() RuleSet { 19 | return &PermitCommand{false, false, false} 20 | } 21 | 22 | // PermitCommand is an implementation of the RuleSet which 23 | // enables filtering supported commands 24 | type PermitCommand struct { 25 | EnableConnect bool 26 | EnableBind bool 27 | EnableAssociate bool 28 | } 29 | 30 | func (p *PermitCommand) Allow(ctx context.Context, req *Request) (context.Context, bool) { 31 | switch req.Command { 32 | case ConnectCommand: 33 | return ctx, p.EnableConnect 34 | case BindCommand: 35 | return ctx, p.EnableBind 36 | case AssociateCommand: 37 | return ctx, p.EnableAssociate 38 | } 39 | 40 | return ctx, false 41 | } 42 | -------------------------------------------------------------------------------- /protocol/tunnel/advance.go: -------------------------------------------------------------------------------- 1 | //go:build advance 2 | // +build advance 3 | 4 | package tunnel 5 | 6 | func WithShadowTLS(server bool, addr, password string) TunnelOption { 7 | if server { 8 | return newFuncTunnelOption(func(do *TunnelService) { 9 | do.afterHooks = append(do.afterHooks, core.AfterHook{ 10 | Priority: TLSPriority, 11 | AcceptHook: func(ctx context.Context, c net.Conn) (context.Context, net.Conn, error) { 12 | tlsConn, err := shadowtls.NewTLSServer(c, shadowtls.NewShadowTLSConfig(addr, password)) 13 | if err != nil { 14 | return ctx, c, err 15 | } 16 | return ctx, tlsConn, nil 17 | }, 18 | }) 19 | }) 20 | } else { 21 | return newFuncTunnelOption(func(do *TunnelService) { 22 | do.meta["shadowtls"] = true 23 | do.afterHooks = append(do.afterHooks, core.AfterHook{ 24 | Priority: TLSPriority, 25 | DialerHook: func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) { 26 | conn, err := shadowtls.NewTLSClient(c, shadowtls.NewShadowTLSConfig(addr, password)) 27 | if err != nil { 28 | return ctx, c, err 29 | } 30 | return ctx, conn, nil 31 | }, 32 | }) 33 | }) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /runner/runner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "github.com/chainreactors/rem/protocol/core" 5 | "github.com/chainreactors/rem/x/utils" 6 | "net/url" 7 | "runtime/debug" 8 | "sync" 9 | ) 10 | 11 | type RunnerConfig struct { 12 | *Options 13 | URLs *core.URLs 14 | ConsoleURLs []*core.URL 15 | Proxies []*url.URL 16 | } 17 | 18 | func (r *RunnerConfig) NewURLs(con *core.URL) *core.URLs { 19 | urls := r.URLs.Copy() 20 | urls.ConsoleURL = con 21 | return urls 22 | } 23 | 24 | func (r *RunnerConfig) Run() error { 25 | //recover 26 | defer func() { 27 | if err := recover(); err != nil { 28 | debug.PrintStack() 29 | } 30 | }() 31 | 32 | var wg sync.WaitGroup 33 | for _, cURL := range r.ConsoleURLs { 34 | wg.Add(1) 35 | console, err := NewConsole(r, r.NewURLs(cURL)) 36 | if err != nil { 37 | utils.Log.Error("[console] " + err.Error()) 38 | return err 39 | } 40 | if r.Mod == "bind" { 41 | go func() { 42 | err := console.Bind() 43 | if err != nil { 44 | utils.Log.Error(err.Error()) 45 | } 46 | wg.Done() 47 | }() 48 | } else { 49 | go func() { 50 | err := console.Run() 51 | if err != nil { 52 | utils.Log.Error(err) 53 | } 54 | wg.Done() 55 | }() 56 | } 57 | 58 | } 59 | 60 | wg.Wait() 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /x/kcp/tx_generic.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | //go:build !linux 24 | 25 | package kcp 26 | 27 | import ( 28 | "golang.org/x/net/ipv4" 29 | ) 30 | 31 | func (s *KCPSession) tx(txqueue []ipv4.Message) { 32 | s.defaultTx(txqueue) 33 | } 34 | -------------------------------------------------------------------------------- /x/kcp/readloop_generic.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | //go:build !linux 24 | 25 | package kcp 26 | 27 | func (s *KCPSession) readLoop() { 28 | s.defaultReadLoop() 29 | } 30 | 31 | func (l *Listener) monitor() { 32 | l.defaultMonitor() 33 | } 34 | -------------------------------------------------------------------------------- /agent/config.go: -------------------------------------------------------------------------------- 1 | package agent 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | "net/url" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | "github.com/chainreactors/rem/protocol/message" 9 | ) 10 | 11 | const ( 12 | monitorInterval = 30 13 | ) 14 | 15 | var ( 16 | ErrNotFoundBridge = errors.New("not found bridge") 17 | ErrNotFoundAgent = errors.New("not found agent") 18 | ) 19 | 20 | type Config struct { 21 | *core.URLs 22 | ExternalIP string 23 | Alias string 24 | Redirect string 25 | Type string 26 | AuthKey []byte 27 | Mod string 28 | Proxies []*url.URL 29 | Params map[string]string 30 | Interfaces []string 31 | Username string 32 | Hostname string 33 | Controller *message.Control 34 | } 35 | 36 | func (c *Config) Clone(ctrl *message.Control) *Config { 37 | return &Config{ 38 | URLs: &core.URLs{ 39 | ConsoleURL: c.ConsoleURL.Copy(), 40 | RemoteURL: ctrl.RemoteURL(), 41 | LocalURL: ctrl.LocalURL(), 42 | }, 43 | ExternalIP: c.ExternalIP, 44 | Alias: ctrl.Source, 45 | Mod: ctrl.Mod, 46 | Redirect: ctrl.Destination, 47 | Type: c.Type, 48 | AuthKey: c.AuthKey, 49 | Proxies: c.Proxies, 50 | Params: c.Params, 51 | Controller: c.Controller, 52 | } 53 | } 54 | 55 | func (c *Config) LocalAddr() string { 56 | return c.LocalURL.Host 57 | } 58 | 59 | func (c *Config) RemoteAddr() string { 60 | return c.RemoteURL.Host 61 | } 62 | -------------------------------------------------------------------------------- /protocol/message/msg.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package message; 4 | option go_package="/;message"; 5 | 6 | message Login { 7 | string ConsoleIP = 1; 8 | int32 ConsolePort = 2; 9 | string ConsoleProto =3; 10 | string Mod = 4; 11 | string Token = 5; 12 | string Agent = 8; 13 | repeated string Interfaces = 9; 14 | string Hostname = 10; 15 | string Username = 11; 16 | string Wrapper = 13; 17 | } 18 | 19 | message Control { 20 | string Source = 2; 21 | string Destination = 3; 22 | string Mod = 5; 23 | string Remote = 6; 24 | string Local = 7; 25 | bool Fork = 8; 26 | map options = 12; 27 | } 28 | 29 | message Ack { 30 | int32 Status = 1; 31 | string Error = 2; 32 | int32 Port = 3; 33 | } 34 | 35 | message Ping { 36 | string Ping = 1; 37 | } 38 | 39 | message Pong { 40 | string Pong = 1; 41 | } 42 | 43 | message ConnStart{ 44 | uint64 ID = 1; 45 | string Destination = 3; 46 | string Source = 4; 47 | // Plugin plugin = 5; 48 | } 49 | 50 | message ConnEnd{ 51 | uint64 ID = 1; 52 | string Msg = 2; 53 | } 54 | 55 | message Packet{ 56 | uint64 ID = 1; 57 | int32 Index = 2; 58 | bytes Data = 5; 59 | } 60 | 61 | message Redirect { 62 | string Source = 1; 63 | string Destination = 2; 64 | string Route = 3; 65 | oneof msg { 66 | ConnStart start = 10; 67 | Packet packet = 11; 68 | ConnEnd end = 12; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /x/kcp/resolver.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | import ( 4 | "net" 5 | "strings" 6 | 7 | "github.com/pkg/errors" 8 | ) 9 | 10 | // Resolver 定义了地址解析的接口 11 | type Resolver interface { 12 | // ResolveAddr 解析地址为net.Addr 13 | ResolveAddr(network, address string) (net.Addr, error) 14 | } 15 | 16 | // resolver工厂函数,根据网络类型返回对应的resolver 17 | func newResolver(network string) Resolver { 18 | switch { 19 | case strings.HasPrefix(network, "udp"): 20 | return &udpResolver{} 21 | case strings.HasPrefix(network, "ip"): 22 | return &icmpResolver{} 23 | default: 24 | return &simplexResolver{} // 默认使用UDP 25 | } 26 | } 27 | 28 | // UDP resolver实现 29 | type udpResolver struct{} 30 | 31 | func (r *udpResolver) ResolveAddr(network, address string) (net.Addr, error) { 32 | return net.ResolveUDPAddr(network, address) 33 | } 34 | 35 | // ICMP resolver实现 36 | type icmpResolver struct{} 37 | 38 | func (r *icmpResolver) ResolveAddr(network, address string) (net.Addr, error) { 39 | host, err := splitHostOnly(address) 40 | if err != nil { 41 | return nil, errors.WithStack(err) 42 | } 43 | // ICMP只需要IP地址 44 | return net.ResolveIPAddr("ip", host) 45 | } 46 | 47 | // HTTP resolver实现 48 | type simplexResolver struct{} 49 | 50 | func (r *simplexResolver) ResolveAddr(network, address string) (net.Addr, error) { 51 | return ResolveSimplexAddr(network, address) 52 | } 53 | 54 | // 辅助函数:只返回host部分 55 | func splitHostOnly(address string) (string, error) { 56 | host, _, err := net.SplitHostPort(address) 57 | return host, err 58 | } 59 | -------------------------------------------------------------------------------- /x/kcp/batchconn.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | import "golang.org/x/net/ipv4" 26 | 27 | const ( 28 | batchSize = 16 29 | ) 30 | 31 | // batchConn defines the interface used in batch IO 32 | type batchConn interface { 33 | WriteBatch(ms []ipv4.Message, flags int) (int, error) 34 | ReadBatch(ms []ipv4.Message, flags int) (int, error) 35 | } 36 | -------------------------------------------------------------------------------- /protocol/cio/reader.go: -------------------------------------------------------------------------------- 1 | package cio 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "github.com/chainreactors/rem/protocol/core" 7 | "github.com/pkg/errors" 8 | "io" 9 | "sync" 10 | ) 11 | 12 | var ( 13 | ErrorInvalidPadding = errors.New("invalid padding") 14 | ErrorInvalidLength = errors.New("invalid length") 15 | ) 16 | 17 | type Reader struct { 18 | Buffer *Buffer 19 | Reader *bufio.Reader 20 | fillMutex sync.Mutex // fill 锁 21 | } 22 | 23 | func NewReader(conn io.Reader) *Reader { 24 | return &Reader{ 25 | Buffer: NewBuffer(core.MaxPacketSize), 26 | Reader: bufio.NewReader(conn), 27 | } 28 | } 29 | 30 | func (r *Reader) FillN(n int64) error { 31 | r.fillMutex.Lock() 32 | defer r.fillMutex.Unlock() 33 | recv, err := io.CopyN(r.Buffer, r.Reader, n) 34 | if err != nil { 35 | return err 36 | } 37 | if recv != n { 38 | return ErrorInvalidLength 39 | } 40 | return nil 41 | } 42 | 43 | func (r *Reader) PeekAndRead(bs []byte) error { 44 | if len(bs) == 0 { 45 | return nil 46 | } 47 | prefix, err := r.Peek(len(bs)) 48 | if err != nil { 49 | return err 50 | } 51 | if !bytes.Equal(prefix, bs) { 52 | return ErrorInvalidPadding 53 | } else { 54 | _, err = r.Reader.Read(make([]byte, len(bs))) 55 | return err 56 | } 57 | } 58 | 59 | // Read 从缓冲区读取数据。 60 | func (r *Reader) Read(p []byte) (int, error) { 61 | if r.Buffer.Size() > 0 { 62 | return r.Buffer.Read(p) 63 | } 64 | r.fillMutex.Lock() 65 | defer r.fillMutex.Unlock() 66 | return r.Reader.Read(p) 67 | } 68 | 69 | // Peek 查看缓冲区中的数据而不移动读取指针。 70 | func (r *Reader) Peek(n int) ([]byte, error) { 71 | return r.Reader.Peek(n) 72 | } 73 | -------------------------------------------------------------------------------- /x/utils/clash.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "strconv" 4 | 5 | func NewProxies(options map[string]string) *Proxies { 6 | return &Proxies{ 7 | Name: options["name"], 8 | Type: options["type"], 9 | Server: options["server"], 10 | Port: StringToInt(options["port"]), 11 | Username: options["username"], 12 | Password: options["password"], 13 | Udp: true, 14 | Tls: false, 15 | SkipCertVerify: true, 16 | Cipher: options["cipher"], 17 | } 18 | } 19 | 20 | type Proxies struct { 21 | Name string `yaml:"name,omitempty"` 22 | Type string `yaml:"type"` 23 | Server string `yaml:"server"` 24 | Port int `yaml:"port"` 25 | Username string `yaml:"username,omitempty"` 26 | Password string `yaml:"password,omitempty"` 27 | Udp bool `yaml:"udp"` 28 | Tls bool `yaml:"tls"` 29 | SkipCertVerify bool `yaml:"skip-cert-verify"` 30 | Cipher string `yaml:"cipher,omitempty"` 31 | } 32 | 33 | // StringToInt 将字符串转换为整数,如果转换失败则返回0 34 | func StringToInt(s string) int { 35 | if s == "" { 36 | return 0 37 | } 38 | i, err := strconv.Atoi(s) 39 | if err != nil { 40 | return 0 41 | } 42 | return i 43 | } 44 | 45 | type ProxyGroup struct { 46 | Name string `yaml:"name"` 47 | Type string `yaml:"type"` 48 | Proxies []string `yaml:"proxies"` 49 | } 50 | 51 | type ClashConfig struct { 52 | Proxies []*Proxies `yaml:"proxies"` 53 | Mode string `yaml:"mode"` 54 | Rules []string `yaml:"rules"` 55 | ProxyGroups []*ProxyGroup `yaml:"proxy-groups"` 56 | } 57 | -------------------------------------------------------------------------------- /x/trojanx/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "github.com/chainreactors/rem/x/trojanx" 6 | "github.com/sirupsen/logrus" 7 | "log" 8 | "net" 9 | "net/http" 10 | "time" 11 | ) 12 | 13 | func main() { 14 | go func() { 15 | server := &http.Server{ 16 | Addr: "127.0.0.1:80", 17 | ReadTimeout: 3 * time.Second, 18 | WriteTimeout: 3 * time.Second, 19 | } 20 | server.SetKeepAlivesEnabled(false) 21 | http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 22 | defer request.Body.Close() 23 | logrus.Debugln(request.RemoteAddr, request.RequestURI) 24 | host, _, _ := net.SplitHostPort(request.Host) 25 | switch host { 26 | default: 27 | writer.Header().Set("Connection", "close") 28 | writer.Header().Set("Referrer-Policy", "no-referrer") 29 | http.Redirect(writer, request, "https://www.baidu.com/", http.StatusFound) 30 | } 31 | }) 32 | if err := server.ListenAndServe(); err != nil { 33 | log.Fatalln(err) 34 | } 35 | }() 36 | 37 | signed, _ := generateSelfSigned() 38 | config := &trojanx.TrojanConfig{ 39 | Password: "password", 40 | TLSConfig: &trojanx.TLSConfig{ 41 | MinVersion: tls.VersionTLS13, 42 | MaxVersion: tls.VersionTLS13, 43 | Certificate: signed, 44 | }, 45 | ReverseProxyConfig: &trojanx.ReverseProxyConfig{ 46 | Scheme: "http", 47 | Host: "127.0.0.1", 48 | Port: 80, 49 | }, 50 | } 51 | 52 | srv := trojanx.NewServer( 53 | trojanx.WithConfig(config), 54 | trojanx.WithLogger(&logrus.Logger{}), 55 | ) 56 | if err := srv.ListenAndServe("tcp", ":443"); err != nil { 57 | logrus.Fatalln(err) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rem 2 | 3 | ## What is it? 4 | 5 | rem是全新架构的全场景应用层/传输层代理工具. 6 | 7 | 相比frp的架构取消了server的概念, server与client融合为平等的agent. 以实现更加自由的流量转发. 并且可以对流量的每个细节自定义. 8 | 9 | 相比iox实现了更复杂的流量处理, 不单纯是点对点的转发, 而是在点对点之间插入了agent, 在agent之间对流量隧道进行控制, 可以做到流量自定义加密混淆, wrapper各种功能. 10 | 11 | ## Feature 12 | 13 | * 支持任意方向,任意信道的代理与端口转发 14 | * 支持流量特征自定义与加密方式自定义 15 | * 极简的命令行设计 16 | * 全平台兼容 17 | 18 | ## docs 19 | 20 | https://chainreactors.github.io/wiki/rem/usage/ 21 | 22 | ## Roadmap 23 | 24 | ### 第一阶段 重构rem 25 | 26 | - [x] 调整主体文件结构 27 | - [x] 调整函数,文件,变量命名 28 | - [x] 重构代理逻辑 29 | - [x] 代码解耦 30 | - [x] 重构monitor与流量控制 31 | - [x] 重新设计cli ui 32 | - [x] 支持rportfwd 33 | - [x] 重新设计msg 34 | - [x] 重新设计wrapper v0.1.0 35 | - [x] 支持neoregeorg, 将半双工信道升级为全双工 36 | - [x] 支持云函数, cdn等 37 | - [x] 支持配置任意数量的多级透明socks5/socks4a/socks4/http/https代理 38 | - [x] 支持tls协议 39 | - [x] 支持级联 40 | - [ ] 支持端口复用(working) 41 | - [ ] 支持端口敲门(working) 42 | - [x] RPORTFWD_LOCAL与PORTFWD_LOCAL 43 | - [x] 重构proxyclient 44 | 45 | **讨论中的高级功能** 46 | 47 | - [x] Proxy as a service, 提供一套流量协议标准以及多语言跨平台sdk, 无性能损耗的转发流量 (working) 48 | - [x] 心跳代理, 使用非长连接的方式建立代理, 实现更复杂的流量与统计学特征混淆 49 | - [ ] P2P式的多级代理, 类似STUN协议 50 | - [x] 重载任意C2的listener, 最终目的将listener从C2中解耦出来 51 | - [x] 实现编译期, 自定义templates. 实现随机流量特征与最小文件体积 52 | - [ ] 通过ebpf与raw packet实现更高级的信道建立与隐蔽 53 | 54 | ## Similar or related works 55 | 56 | * [frp](https://github.com/fatedier/frp) 最常使用, 最稳定的反向代理工具. 配置相对麻烦, 有一些强特征已被主流防护设备识别, 类似的还有nps, ngrok, rathole, spp. 57 | * [gost](https://github.com/go-gost/gost) 一款强大的正向代理工具, v2版本不支持反向代理, v3开始支持, 未来可期. 58 | * [iox](https://github.com/EddieIvan01/iox) 轻量但稳定的端口转发工具 59 | * [xray](https://github.com/XTLS/Xray-core) 正向代理工具, 在协议的隐蔽性与性能上非常强大, 并拥有最好的密码学特性(向前加密, 无特征等) -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: rem 2 | 3 | before: 4 | hooks: 5 | - go mod tidy 6 | 7 | builds: 8 | - 9 | main: . 10 | binary: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" 11 | goos: 12 | - windows 13 | - linux 14 | - darwin 15 | - freebsd 16 | - solaris 17 | - android 18 | goarch: 19 | - amd64 20 | - "386" 21 | - arm64 22 | - arm 23 | - mips 24 | - mips64 25 | ignore: 26 | - goos: darwin 27 | goarch: "386" 28 | - goos: linux 29 | goarch: mips64 30 | - goos: android 31 | goarch: amd64 32 | - goos: android 33 | goarch: "386" 34 | - goos: android 35 | goarch: arm 36 | ldflags: "-s -w -X 'github.com/chainreactors/rem/cmd/cmd.ver={{ .Tag }}'" 37 | flags: 38 | - -trimpath 39 | asmflags: 40 | - all=-trimpath={{.Env.GOPATH}} 41 | gcflags: 42 | - all=-trimpath={{.Env.GOPATH}} 43 | no_unique_dist_dir: true 44 | env: 45 | - CGO_ENABLED=0 46 | tags: 47 | - forceposix 48 | - osusergo 49 | - netgo 50 | 51 | upx: 52 | - 53 | enabled: true 54 | goos: [linux, windows] 55 | goarch: 56 | - amd64 57 | - "386" 58 | 59 | archives: 60 | - 61 | name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" 62 | format: binary 63 | 64 | checksum: 65 | name_template: "{{ .ProjectName }}_checksums.txt" 66 | 67 | changelog: 68 | sort: desc 69 | filters: 70 | exclude: 71 | - '^MERGE' 72 | - "{{ .Tag }}" 73 | - "^docs" 74 | 75 | release: 76 | disable: true 77 | skip_upload: true 78 | github: 79 | owner: chainreactors 80 | name: rem 81 | draft: true -------------------------------------------------------------------------------- /x/utils/log.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "container/ring" 5 | "fmt" 6 | "github.com/chainreactors/logs" 7 | "strings" 8 | "sync" 9 | ) 10 | 11 | var ( 12 | DUMPLog logs.Level = 1 13 | IOLog logs.Level = 2 14 | Log *logs.Logger 15 | ) 16 | 17 | type RingLogWriter struct { 18 | buffer *ring.Ring 19 | mu sync.RWMutex 20 | size int 21 | quiet bool 22 | } 23 | 24 | func NewRingLogWriter(size int) *RingLogWriter { 25 | return &RingLogWriter{ 26 | buffer: ring.New(size), 27 | size: size, 28 | } 29 | } 30 | 31 | func (w *RingLogWriter) Write(p []byte) (n int, err error) { 32 | w.mu.Lock() 33 | defer w.mu.Unlock() 34 | s := string(p) 35 | w.buffer.Value = s 36 | w.buffer = w.buffer.Next() 37 | fmt.Print(s) 38 | return len(p), nil 39 | } 40 | 41 | // 获取最近的日志 42 | func (w *RingLogWriter) GetRecentLogs() []string { 43 | w.mu.RLock() 44 | defer w.mu.RUnlock() 45 | 46 | logs := make([]string, 0, w.size) 47 | w.buffer.Do(func(v interface{}) { 48 | if v != nil { 49 | logs = append(logs, v.(string)) 50 | } 51 | }) 52 | 53 | return logs 54 | } 55 | 56 | // 清空日志 57 | func (w *RingLogWriter) Clear() { 58 | w.mu.Lock() 59 | defer w.mu.Unlock() 60 | 61 | w.buffer = ring.New(w.size) 62 | } 63 | 64 | // 获取日志数量 65 | func (w *RingLogWriter) Len() int { 66 | w.mu.RLock() 67 | defer w.mu.RUnlock() 68 | 69 | count := 0 70 | w.buffer.Do(func(v interface{}) { 71 | if v != nil { 72 | count++ 73 | } 74 | }) 75 | return count 76 | } 77 | 78 | // 导出日志为字符串 79 | func (w *RingLogWriter) String() string { 80 | logs := w.GetRecentLogs() 81 | var result strings.Builder 82 | for _, entry := range logs { 83 | result.WriteString(entry) 84 | } 85 | return result.String() 86 | } 87 | -------------------------------------------------------------------------------- /runner/console_test.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "fmt" 5 | "github.com/chainreactors/logs" 6 | "github.com/chainreactors/proxyclient" 7 | "net/http" 8 | "net/url" 9 | "testing" 10 | "time" 11 | ) 12 | 13 | func TestNewConsole(t *testing.T) { 14 | u, _ := url.Parse("rem+tcp://nonenonenonenone:@127.0.0.1:34996/?wrapper=raw") 15 | proxy, err := proxyclient.NewClient(u) 16 | 17 | client := &http.Client{ 18 | Transport: &http.Transport{ 19 | DialContext: proxy.DialContext, 20 | }, 21 | } 22 | _, err = client.Get("http://localhost:8000") 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | time.Sleep(time.Second) 28 | } 29 | 30 | func TestClient(t *testing.T) { 31 | utils.Log.SetLevel(logs.DebugLevel) 32 | var copt Options 33 | // -c tcp://nonenonenonenone:@127.0.0.1:34996/?wrapper=raw -n 34 | copt.ParseArgs([]string{"-c", "tcp://nonenonenonenone:@127.0.0.1:34996/?wrapper=raw", "-n", "-a", "test", "--debug"}) 35 | client, err := copt.Prepare() 36 | if err != nil { 37 | fmt.Println(err.Error()) 38 | return 39 | } 40 | err = client.Run() 41 | if err != nil { 42 | fmt.Println(err.Error()) 43 | return 44 | } 45 | } 46 | 47 | func TestServer(t *testing.T) { 48 | utils.Log.SetLevel(logs.DebugLevel) 49 | var server *Console 50 | go func() { 51 | var err error 52 | server, err = NewConsoleWithCMD(" --debug -c tcp:///?wrapper=raw -i 127.0.0.1") 53 | err = server.Run() 54 | if err != nil { 55 | fmt.Println(err.Error()) 56 | return 57 | } 58 | }() 59 | time.Sleep(10 * time.Second) 60 | 61 | _, err := server.Fork("test", []string{"-m", "reverse", "-l", "127.0.0.1:8000", "-r", "port://:12345"}) 62 | if err != nil { 63 | fmt.Println(err.Error()) 64 | return 65 | } 66 | select {} 67 | } 68 | -------------------------------------------------------------------------------- /protocol/tunnel/tcp/tcp.go: -------------------------------------------------------------------------------- 1 | package tcp 2 | 3 | import ( 4 | "context" 5 | "github.com/chainreactors/rem/protocol/core" 6 | "net" 7 | ) 8 | 9 | func init() { 10 | core.DialerRegister(core.TCPTunnel, func(ctx context.Context) (core.TunnelDialer, error) { 11 | return NewTCPDialer(ctx), nil 12 | }) 13 | 14 | core.ListenerRegister(core.TCPTunnel, func(ctx context.Context) (core.TunnelListener, error) { 15 | return NewTCPListener(ctx), nil 16 | }) 17 | } 18 | 19 | type TCPDialer struct { 20 | net.Conn 21 | meta core.Metas 22 | } 23 | 24 | func NewTCPDialer(ctx context.Context) *TCPDialer { 25 | return &TCPDialer{ 26 | meta: core.GetMetas(ctx), 27 | } 28 | } 29 | 30 | func (c *TCPDialer) Dial(dst string) (net.Conn, error) { 31 | u, err := core.NewURL(dst) 32 | if err != nil { 33 | return nil, err 34 | } 35 | c.meta["url"] = u 36 | return net.Dial("tcp", u.Host) 37 | } 38 | 39 | type TCPListener struct { 40 | listener net.Listener 41 | meta core.Metas 42 | } 43 | 44 | func NewTCPListener(ctx context.Context) *TCPListener { 45 | return &TCPListener{ 46 | meta: core.GetMetas(ctx), 47 | } 48 | } 49 | 50 | func (c *TCPListener) Listen(dst string) (net.Listener, error) { 51 | u, err := core.NewURL(dst) 52 | if err != nil { 53 | return nil, err 54 | } 55 | c.meta["url"] = u 56 | 57 | listener, err := net.Listen("tcp", u.Host) 58 | if err != nil { 59 | return nil, err 60 | } 61 | c.listener = listener 62 | return listener, nil 63 | } 64 | 65 | func (c *TCPListener) Accept() (net.Conn, error) { 66 | return c.listener.Accept() 67 | } 68 | 69 | func (c *TCPListener) Close() error { 70 | if c.listener != nil { 71 | return c.listener.Close() 72 | } 73 | return nil 74 | } 75 | 76 | func (c *TCPListener) Addr() net.Addr { 77 | return c.meta.URL() 78 | } 79 | -------------------------------------------------------------------------------- /x/trojanx/callback.go: -------------------------------------------------------------------------------- 1 | package trojanx 2 | 3 | import ( 4 | "context" 5 | "crypto/sha256" 6 | "encoding/hex" 7 | "github.com/chainreactors/rem/x/trojanx/protocol" 8 | "net" 9 | ) 10 | 11 | type ( 12 | connectHandler = func(ctx context.Context) bool 13 | authenticationHandler = func(ctx context.Context, reqHash string, serverHash string) bool 14 | requestHandler = func(ctx context.Context, request protocol.Request) bool 15 | errorHandler = func(ctx context.Context, err error) 16 | ) 17 | 18 | func (s *Server) defaultConnectHandler(ctx context.Context) bool { 19 | return true 20 | } 21 | 22 | func (s *Server) defaultAuthenticationHandler(ctx context.Context, reqHash string, serverHash string) bool { 23 | switch reqHash { 24 | case sha224(serverHash): 25 | return true 26 | default: 27 | return false 28 | } 29 | } 30 | 31 | func sha224(password string) string { 32 | hash224 := sha256.New224() 33 | hash224.Write([]byte(password)) 34 | sha224Hash := hash224.Sum(nil) 35 | return hex.EncodeToString(sha224Hash) 36 | } 37 | 38 | func (s *Server) defaultRequestHandler(ctx context.Context, request protocol.Request) bool { 39 | var remoteIP net.IP 40 | if request.AddressType == protocol.AddressTypeDomain { 41 | tcpAddr, err := net.ResolveTCPAddr("tcp", request.DescriptionAddress) 42 | if err != nil { 43 | s.logger.Errorln(err) 44 | return false 45 | } 46 | remoteIP = tcpAddr.IP 47 | } else { 48 | remoteIP = net.ParseIP(request.DescriptionAddress) 49 | } 50 | if remoteIP.IsLoopback() || remoteIP.IsLinkLocalUnicast() || remoteIP.IsLinkLocalMulticast() || remoteIP.IsPrivate() { 51 | return false 52 | } 53 | return true 54 | } 55 | 56 | func (s *Server) defaultErrorHandler(ctx context.Context, err error) { 57 | s.logger.Errorln(err) 58 | } 59 | -------------------------------------------------------------------------------- /x/trojanx/README.md: -------------------------------------------------------------------------------- 1 | # TrojanX 2 | 3 | Trojan server **framework**. 4 | 5 | ## Example 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "crypto/tls" 12 | "github.com/7ten7/trojanx" 13 | "github.com/sirupsen/logrus" 14 | "log" 15 | "net" 16 | "net/http" 17 | "time" 18 | ) 19 | 20 | func main() { 21 | go func() { 22 | server := &http.Server{ 23 | Addr: "127.0.0.1:80", 24 | ReadTimeout: 3 * time.Second, 25 | WriteTimeout: 3 * time.Second, 26 | } 27 | server.SetKeepAlivesEnabled(false) 28 | http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 29 | defer request.Body.Close() 30 | logrus.Debugln(request.RemoteAddr, request.RequestURI) 31 | host, _, _ := net.SplitHostPort(request.Host) 32 | switch host { 33 | default: 34 | writer.Header().Set("Connection", "close") 35 | writer.Header().Set("Referrer-Policy", "no-referrer") 36 | http.Redirect(writer, request, "https://www.baidu.com/", http.StatusFound) 37 | } 38 | }) 39 | if err := server.ListenAndServe(); err != nil { 40 | log.Fatalln(err) 41 | } 42 | }() 43 | 44 | signed, _ := generateSelfSigned() 45 | config := &trojanx.TrojanConfig{ 46 | Password: "password", 47 | TLSConfig: &trojanx.TLSConfig{ 48 | MinVersion: tls.VersionTLS13, 49 | MaxVersion: tls.VersionTLS13, 50 | Certificate: signed, 51 | }, 52 | ReverseProxyConfig: &trojanx.ReverseProxyConfig{ 53 | Scheme: "http", 54 | Host: "127.0.0.1", 55 | Port: 80, 56 | }, 57 | } 58 | 59 | srv := trojanx.NewServer( 60 | trojanx.WithConfig(config), 61 | trojanx.WithLogger(&logrus.Logger{}), 62 | ) 63 | if err := srv.ListenAndServe("tcp", ":443"); err != nil { 64 | logrus.Fatalln(err) 65 | } 66 | } 67 | ``` 68 | 69 | ## LICENSE 70 | 71 | [MIT License](LICENSE) 72 | -------------------------------------------------------------------------------- /protocol/tunnel/unix/unix_windows.go: -------------------------------------------------------------------------------- 1 | package unix 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | 8 | "github.com/Microsoft/go-winio" 9 | "github.com/chainreactors/rem/protocol/core" 10 | "github.com/chainreactors/rem/x/utils" 11 | ) 12 | 13 | func NewUnixDialer(ctx context.Context) *UnixDialer { 14 | return &UnixDialer{ 15 | meta: core.GetMetas(ctx), 16 | } 17 | } 18 | 19 | func (c *UnixDialer) Dial(dst string) (net.Conn, error) { 20 | u, err := core.NewURL(dst) 21 | if err != nil { 22 | return nil, err 23 | } 24 | c.meta["url"] = u 25 | host := u.Hostname() 26 | pipePath := `\\` + host + `\pipe\` + u.PathString() 27 | utils.Log.Debugf("dial pipe: %s", pipePath) 28 | return winio.DialPipe(pipePath, nil) 29 | } 30 | 31 | func NewUnixListener(ctx context.Context) *UnixListener { 32 | return &UnixListener{ 33 | meta: core.GetMetas(ctx), 34 | } 35 | } 36 | 37 | func (c *UnixListener) Listen(dst string) (net.Listener, error) { 38 | pipeUrl, err := core.NewURL(dst) 39 | if err != nil { 40 | return nil, err 41 | } 42 | if pipeUrl.Hostname() == "0.0.0.0" { 43 | pipeUrl.Host = "." 44 | } 45 | if pipeUrl.PathString() == "" { 46 | pipeUrl.Path = "/" + c.meta["pipe"].(string) 47 | } 48 | pipePath := fmt.Sprintf(`\\%s\pipe\%s`, pipeUrl.Hostname(), pipeUrl.PathString()) 49 | c.meta["url"] = pipeUrl 50 | config := &winio.PipeConfig{ 51 | SecurityDescriptor: "D:P(A;;GA;;;WD)", // WD 表示 Everyone,允许所有人访问 52 | MessageMode: true, // 消息模式 53 | InputBufferSize: 65536, // 默认缓冲区大 54 | OutputBufferSize: 65536, 55 | } 56 | 57 | listener, err := winio.ListenPipe(pipePath, config) 58 | if err != nil { 59 | return nil, err 60 | } 61 | utils.Log.Debugf("listen pipe: %s", pipePath) 62 | c.listener = listener 63 | return listener, nil 64 | } 65 | -------------------------------------------------------------------------------- /x/utils/xor.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/cipher" 5 | "io" 6 | ) 7 | 8 | // XorStream 实现cipher.Stream接口 9 | type XorStream struct { 10 | key []byte 11 | iv []byte 12 | counter int 13 | } 14 | 15 | // XORKeyStream 实现cipher.Stream接口 16 | func (x *XorStream) XORKeyStream(dst, src []byte) { 17 | keyLen := len(x.key) 18 | ivLen := len(x.iv) 19 | 20 | for i := range src { 21 | index := x.counter + i 22 | keyByte := x.key[index%keyLen] 23 | ivByte := x.iv[index%ivLen] 24 | dst[i] = src[i] ^ keyByte ^ ivByte 25 | } 26 | 27 | x.counter += len(src) 28 | } 29 | 30 | // XorEncryptor 封装了加密和解密的Stream 31 | type XorEncryptor struct { 32 | key []byte 33 | iv []byte 34 | stream cipher.Stream 35 | } 36 | 37 | // NewXorEncryptor 创建一个新的XorEncryptor 38 | func NewXorEncryptor(key []byte, iv []byte) *XorEncryptor { 39 | stream := &XorStream{ 40 | key: key, 41 | iv: iv, 42 | counter: 0, 43 | } 44 | return &XorEncryptor{ 45 | key: key, 46 | iv: iv, 47 | stream: stream, 48 | } 49 | } 50 | 51 | // GetStream 获取当前的cipher.Stream实例 52 | func (e *XorEncryptor) GetStream() cipher.Stream { 53 | return e.stream 54 | } 55 | 56 | // Encrypt 使用cipher.StreamWriter进行加密 57 | func (e *XorEncryptor) Encrypt(dst io.Writer, src io.Reader) error { 58 | writer := &cipher.StreamWriter{S: e.stream, W: dst} 59 | _, err := io.Copy(writer, src) 60 | return err 61 | } 62 | 63 | // Decrypt 使用cipher.StreamReader进行解密 64 | func (e *XorEncryptor) Decrypt(dst io.Writer, src io.Reader) error { 65 | reader := &cipher.StreamReader{S: e.stream, R: src} 66 | _, err := io.Copy(dst, reader) 67 | return err 68 | } 69 | 70 | // Reset 重置加密器状态 71 | func (e *XorEncryptor) Reset() error { 72 | e.stream = &XorStream{ 73 | key: e.key, 74 | iv: e.iv, 75 | counter: 0, 76 | } 77 | return nil 78 | } 79 | -------------------------------------------------------------------------------- /x/kcp/tx.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | import ( 26 | "sync/atomic" 27 | 28 | "github.com/pkg/errors" 29 | "golang.org/x/net/ipv4" 30 | ) 31 | 32 | // defaultTx is the default procedure to transmit data 33 | func (s *KCPSession) defaultTx(txqueue []ipv4.Message) { 34 | nbytes := 0 35 | npkts := 0 36 | for k := range txqueue { 37 | if n, err := s.conn.WriteTo(txqueue[k].Buffers[0], txqueue[k].Addr); err == nil { 38 | nbytes += n 39 | npkts++ 40 | } else { 41 | s.notifyWriteError(errors.WithStack(err)) 42 | break 43 | } 44 | } 45 | atomic.AddUint64(&DefaultSnmp.OutPkts, uint64(npkts)) 46 | atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes)) 47 | } 48 | -------------------------------------------------------------------------------- /x/kcp/conn.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | import ( 4 | "context" 5 | "io" 6 | ) 7 | 8 | type KCPConn struct { 9 | *KCPSession 10 | ctx context.Context 11 | cancel context.CancelFunc 12 | } 13 | 14 | func RadicalKCPConfig(conn *KCPSession) { 15 | conn.SetWriteDelay(false) 16 | conn.SetWindowSize(1024, 1024) 17 | conn.SetReadBuffer(1024 * 1024) 18 | conn.SetWriteBuffer(1024 * 1024) 19 | conn.SetNoDelay(1, 100, 2, 1) 20 | conn.SetMtu(1400) 21 | conn.SetACKNoDelay(true) 22 | } 23 | 24 | func HTTPKCPConfig(conn *KCPSession) { 25 | conn.SetWriteDelay(true) 26 | //conn.SetWindowSize(16, 16) 27 | conn.SetReadBuffer(1024 * 1024) 28 | conn.SetWriteBuffer(1024 * 1024) 29 | conn.SetNoDelay(0, 100, 10, 0) 30 | conn.SetMtu(mtuLimit - 16*1024) 31 | conn.SetACKNoDelay(true) 32 | } 33 | 34 | // NewKCPConn 创建新的KCP连接包装器 35 | func NewKCPConn(conn *KCPSession, confn func(*KCPSession)) *KCPConn { 36 | ctx, cancel := context.WithCancel(context.Background()) 37 | confn(conn) 38 | return &KCPConn{ 39 | KCPSession: conn, 40 | ctx: ctx, 41 | cancel: cancel, 42 | } 43 | } 44 | 45 | // Read 重写Read方法,处理EOF问题,尽可能读满缓冲区 46 | func (k *KCPConn) Read(p []byte) (n int, err error) { 47 | for n < len(p) { 48 | select { 49 | case <-k.ctx.Done(): 50 | if n > 0 { 51 | return n, nil 52 | } 53 | return 0, io.ErrClosedPipe 54 | default: 55 | nr, err := k.KCPSession.Read(p[n:]) 56 | if nr > 0 { 57 | n += nr 58 | } 59 | if err != nil { 60 | return n, err 61 | } 62 | } 63 | } 64 | return n, nil 65 | } 66 | 67 | // Write 重写Write方法,添加超时控制 68 | func (k *KCPConn) Write(p []byte) (n int, err error) { 69 | select { 70 | case <-k.ctx.Done(): 71 | return 0, io.ErrClosedPipe 72 | default: 73 | return k.KCPSession.Write(p) 74 | } 75 | } 76 | 77 | // Close 关闭连接 78 | func (k *KCPConn) Close() error { 79 | k.cancel() 80 | return k.KCPSession.Close() 81 | } 82 | -------------------------------------------------------------------------------- /protocol/cio/limiter.go: -------------------------------------------------------------------------------- 1 | package cio 2 | 3 | import ( 4 | "sync/atomic" 5 | 6 | "golang.org/x/time/rate" 7 | ) 8 | 9 | var GlobalLimiter *Limiter 10 | 11 | func init() { 12 | GlobalLimiter = NewLimiter(rate.Inf, rate.Inf, 1024*1024) 13 | } 14 | 15 | // Limiter 全局限速器 16 | type Limiter struct { 17 | readLimiter *rate.Limiter 18 | writeLimiter *rate.Limiter 19 | readEnabled atomic.Value // 读限速开关 20 | writeEnabled atomic.Value // 写限速开关 21 | readCount int64 // 读取计数器 22 | writeCount int64 // 写入计数器 23 | } 24 | 25 | func NewLimiter(readRate, writeRate rate.Limit, burstSize int) *Limiter { 26 | l := &Limiter{ 27 | readLimiter: rate.NewLimiter(readRate, burstSize), 28 | writeLimiter: rate.NewLimiter(writeRate, burstSize), 29 | } 30 | l.readEnabled.Store(false) 31 | l.writeEnabled.Store(false) 32 | return l 33 | } 34 | 35 | // GetCounts 获取读写计数 36 | func (l *Limiter) GetCounts() (readCount, writeCount int64) { 37 | return atomic.LoadInt64(&l.readCount), atomic.LoadInt64(&l.writeCount) 38 | } 39 | 40 | // SetReadRate 设置读取速率 41 | func (l *Limiter) SetReadRate(readRate rate.Limit) { 42 | l.readLimiter.SetLimit(readRate) 43 | } 44 | 45 | // SetWriteRate 设置写入速率 46 | func (l *Limiter) SetWriteRate(writeRate rate.Limit) { 47 | l.writeLimiter.SetLimit(writeRate) 48 | } 49 | 50 | // EnableReadLimit 启用/禁用读限速 51 | func (l *Limiter) EnableReadLimit(enable bool) { 52 | l.readEnabled.Store(enable) 53 | } 54 | 55 | // EnableWriteLimit 启用/禁用写限速 56 | func (l *Limiter) EnableWriteLimit(enable bool) { 57 | l.writeEnabled.Store(enable) 58 | } 59 | 60 | // GetLimits 获取当前的限速设置 61 | func (l *Limiter) GetLimits() (readLimit, writeLimit rate.Limit) { 62 | return l.readLimiter.Limit(), l.writeLimiter.Limit() 63 | } 64 | 65 | // IsReadEnabled 检查读限速是否启用 66 | func (l *Limiter) IsReadEnabled() bool { 67 | return l.readEnabled.Load().(bool) 68 | } 69 | 70 | // IsWriteEnabled 检查写限速是否启用 71 | func (l *Limiter) IsWriteEnabled() bool { 72 | return l.writeEnabled.Load().(bool) 73 | } 74 | -------------------------------------------------------------------------------- /protocol/core/consts.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | var ( 4 | MaxPacketSize = 1024 * 128 5 | DefaultKey = "nonenonenonenone" 6 | 7 | DefaultScheme = "default" 8 | DefaultConsoleProto = "tcp" 9 | DefaultConsolePort = "34996" 10 | DefaultUsername = "remno1" 11 | DefaultPassword = "0onmer" 12 | 13 | LOCALHOST = "127.0.0.1" 14 | ) 15 | 16 | const ( 17 | InboundPlugin = "inbound" 18 | OutboundPlugin = "outbound" 19 | ) 20 | 21 | // proto 22 | const ( 23 | RawServe = "raw" 24 | //RelayServe = "relay" // custom socks5 protocol 25 | Socks5Serve = "socks5" 26 | HTTPServe = "http" 27 | ShadowSocksServe = "ss" 28 | TrojanServe = "trojan" 29 | PortForwardServe = "forward" 30 | CobaltStrikeServe = "cs" 31 | ) 32 | 33 | // transport 34 | const ( 35 | ICMPTunnel = "icmp" 36 | HTTPTunnel = "http" 37 | UDPTunnel = "udp" 38 | TCPTunnel = "tcp" 39 | UNIXTunnel = "unix" 40 | WebSocketTunnel = "ws" 41 | WireGuardTunnel = "wireguard" 42 | MemoryTunnel = "memory" 43 | ) 44 | 45 | func Normalize(s string) string { 46 | switch s { 47 | case "socks5", "s5", "socks": 48 | return Socks5Serve 49 | case "ss", "shadowsocks": 50 | return ShadowSocksServe 51 | case "trojan": 52 | return TrojanServe 53 | case "forward", "port", "pf", "portfoward": 54 | return PortForwardServe 55 | case "http", "https": 56 | return HTTPServe 57 | case "raw": 58 | return RawServe 59 | case "smb", "pipe", "unix", "sock": 60 | return UNIXTunnel 61 | case "ws", "websocket", "wss": 62 | return WebSocketTunnel 63 | case "wireguard", "wg": 64 | return WireGuardTunnel 65 | 66 | default: 67 | return s 68 | } 69 | } 70 | 71 | // wrapper 72 | const ( 73 | XORWrapper = "xor" 74 | AESWrapper = "aes" 75 | PaddingWrapper = "padding" 76 | ) 77 | 78 | const ( 79 | Reverse = "reverse" 80 | Proxy = "proxy" 81 | Bind = "bind" 82 | Connect = "connect" 83 | ) 84 | 85 | // agent type 86 | const ( 87 | SERVER = "server" 88 | 89 | CLIENT = "client" 90 | 91 | Redirect = "redirect" 92 | ) 93 | -------------------------------------------------------------------------------- /protocol/core/inbound.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "github.com/chainreactors/rem/x/utils" 6 | "io" 7 | "net" 8 | ) 9 | 10 | type Inbound interface { 11 | Name() string 12 | Relay(conn net.Conn, bridge io.ReadWriteCloser) (net.Conn, error) 13 | ToClash() *utils.Proxies 14 | } 15 | 16 | var inboundCreators = make(map[string]InboundCreatorFn) 17 | 18 | // params has prefix "relay_" 19 | type InboundCreatorFn func(options map[string]string) (Inbound, error) 20 | 21 | func InboundRegister(name string, fn InboundCreatorFn) { 22 | if _, exist := inboundCreators[name]; exist { 23 | panic(fmt.Sprintf("relay [%s] is already registered", name)) 24 | } 25 | inboundCreators[name] = fn 26 | } 27 | 28 | func InboundCreate(name string, options map[string]string) (p Inbound, err error) { 29 | if fn, ok := inboundCreators[name]; ok { 30 | p, err = fn(options) 31 | } else { 32 | err = fmt.Errorf("relay [%s] is not registered", name) 33 | } 34 | return 35 | } 36 | 37 | func NewPluginOption(options map[string]string, mod, typ string) *PluginOption { 38 | options["type"] = typ 39 | return &PluginOption{ 40 | options: options, 41 | Proxy: utils.NewProxies(options), 42 | } 43 | } 44 | 45 | type PluginOption struct { 46 | Proxy *utils.Proxies 47 | Mod string 48 | options map[string]string 49 | } 50 | 51 | func (relay *PluginOption) String() string { 52 | return fmt.Sprintf("%s %s %d %s %s", 53 | relay.Proxy.Type, 54 | relay.Proxy.Server, 55 | relay.Proxy.Port, 56 | relay.Proxy.Username, 57 | relay.Proxy.Password) 58 | } 59 | 60 | func (relay *PluginOption) URL() string { 61 | if relay.Proxy.Username != "" { 62 | return fmt.Sprintf("%s://%s:%s@%s:%d", 63 | relay.Proxy.Type, 64 | relay.Proxy.Username, 65 | relay.Proxy.Password, 66 | relay.Proxy.Server, 67 | relay.Proxy.Port, 68 | ) 69 | } else { 70 | return fmt.Sprintf("%s://%s:%d", 71 | relay.Proxy.Type, 72 | relay.Proxy.Server, 73 | relay.Proxy.Port, 74 | ) 75 | } 76 | } 77 | 78 | func (relay *PluginOption) ToClash() *utils.Proxies { 79 | return relay.Proxy 80 | } 81 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/chainreactors/rem 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/Microsoft/go-winio v0.5.1 7 | github.com/chainreactors/go-metrics v0.0.0-20220926021830-24787b7a10f8 8 | github.com/chainreactors/logs v0.0.0-20250312104344-9f30fa69d3c9 9 | github.com/chainreactors/proxyclient v1.0.2 10 | github.com/golang/snappy v1.0.0 11 | github.com/jessevdk/go-flags v1.5.0 12 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 13 | github.com/klauspost/reedsolomon v1.12.0 14 | github.com/pkg/errors v0.9.1 15 | github.com/shadowsocks/go-shadowsocks2 v0.1.5 16 | github.com/sirupsen/logrus v1.9.3 17 | github.com/stretchr/testify v1.10.0 18 | github.com/templexxx/xorsimd v0.4.3 19 | github.com/tjfoc/gmsm v1.4.1 20 | github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae 21 | golang.org/x/sys v0.30.0 22 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0 23 | golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b 24 | golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 25 | google.golang.org/protobuf v1.33.0 26 | gopkg.in/yaml.v3 v3.0.1 27 | ) 28 | 29 | // compatibility 30 | require ( 31 | golang.org/x/crypto v0.33.0 32 | golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 33 | golang.org/x/net v0.25.0 34 | ) 35 | 36 | require ( 37 | github.com/chainreactors/files v0.0.0-20231102192550-a652458cee26 // indirect 38 | github.com/davecgh/go-spew v1.1.1 // indirect 39 | github.com/google/btree v1.0.1 // indirect 40 | github.com/klauspost/cpuid/v2 v2.2.6 // indirect 41 | github.com/pmezard/go-difflib v1.0.0 // indirect 42 | github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect 43 | github.com/templexxx/cpu v0.1.1 // indirect 44 | golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect 45 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 46 | gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0 // indirect 47 | ) 48 | 49 | replace github.com/chainreactors/proxyclient => github.com/chainreactors/proxyclient v1.0.3 50 | 51 | replace ( 52 | golang.org/x/crypto => golang.org/x/crypto v0.24.0 53 | golang.org/x/net => golang.org/x/net v0.23.0 54 | ) 55 | -------------------------------------------------------------------------------- /protocol/tunnel/udp/udp.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | "github.com/chainreactors/rem/x/kcp" 9 | ) 10 | 11 | func init() { 12 | core.DialerRegister(core.UDPTunnel, func(ctx context.Context) (core.TunnelDialer, error) { 13 | return NewUDPDialer(ctx), nil 14 | }) 15 | core.ListenerRegister(core.UDPTunnel, func(ctx context.Context) (core.TunnelListener, error) { 16 | return NewUDPListener(ctx), nil 17 | }) 18 | } 19 | 20 | type UDPDialer struct { 21 | net.Conn 22 | meta core.Metas 23 | } 24 | 25 | type UDPListener struct { 26 | listener *kcp.Listener 27 | meta core.Metas 28 | } 29 | 30 | func NewUDPDialer(ctx context.Context) *UDPDialer { 31 | return &UDPDialer{ 32 | meta: core.GetMetas(ctx), 33 | } 34 | } 35 | 36 | func NewUDPListener(ctx context.Context) *UDPListener { 37 | return &UDPListener{ 38 | meta: core.GetMetas(ctx), 39 | } 40 | } 41 | 42 | func (c *UDPListener) Accept() (net.Conn, error) { 43 | conn, err := c.listener.AcceptKCP() 44 | if err != nil { 45 | return nil, err 46 | } 47 | return kcp.NewKCPConn(conn, kcp.RadicalKCPConfig), nil 48 | } 49 | 50 | func (c *UDPDialer) Dial(dst string) (net.Conn, error) { 51 | u, _ := core.NewURL(dst) 52 | c.meta["url"] = u 53 | 54 | conn, err := kcp.DialWithOptions("udp", u.Host, nil, 0, 0) 55 | if err != nil { 56 | return nil, err 57 | } 58 | 59 | return kcp.NewKCPConn(conn, kcp.RadicalKCPConfig), nil 60 | } 61 | 62 | func (c *UDPListener) Listen(dst string) (net.Listener, error) { 63 | u, _ := core.NewURL(dst) 64 | c.meta["url"] = u 65 | 66 | listener, err := kcp.Listen("udp", u.Host) 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | // 设置监听器参数 72 | if l, ok := listener.(*kcp.Listener); ok { 73 | l.SetReadBuffer(core.MaxPacketSize) 74 | l.SetWriteBuffer(core.MaxPacketSize) 75 | l.SetDSCP(46) 76 | c.listener = l 77 | } 78 | 79 | return listener, nil 80 | } 81 | 82 | func (c *UDPListener) Close() error { 83 | if c.listener != nil { 84 | return c.listener.Close() 85 | } 86 | return nil 87 | } 88 | 89 | func (c *UDPListener) Addr() net.Addr { 90 | return c.meta.URL() 91 | } 92 | -------------------------------------------------------------------------------- /protocol/wrapper/xor.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "crypto/cipher" 5 | "io" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | "github.com/chainreactors/rem/x/utils" 9 | ) 10 | 11 | func init() { 12 | core.WrapperRegister(core.XORWrapper, func(r io.Reader, w io.Writer, opt map[string]string) (core.Wrapper, error) { 13 | return NewXorWrapper(r, w, opt), nil 14 | }) 15 | core.AvailableWrappers = append(core.AvailableWrappers, core.XORWrapper) 16 | } 17 | 18 | type XorWrapper struct { 19 | reader io.Reader 20 | writer io.Writer 21 | encStream cipher.Stream 22 | decStream cipher.Stream 23 | key []byte 24 | iv []byte 25 | } 26 | 27 | func NewXorWrapper(r io.Reader, w io.Writer, opt map[string]string) core.Wrapper { 28 | var key []byte 29 | if k, ok := opt["key"]; ok { 30 | key = []byte(k) 31 | } else { 32 | key = []byte{} // 使用空字节切片作为默认值 33 | } 34 | 35 | var iv []byte 36 | if i, ok := opt["iv"]; ok { 37 | iv = []byte(i) 38 | } else { 39 | iv = key // 如果没有提供iv,使用key作为iv 40 | } 41 | 42 | encryptor := utils.NewXorEncryptor(key, iv) 43 | decryptor := utils.NewXorEncryptor(key, iv) 44 | 45 | return &XorWrapper{ 46 | reader: &cipher.StreamReader{S: decryptor.GetStream(), R: r}, 47 | writer: &cipher.StreamWriter{S: encryptor.GetStream(), W: w}, 48 | encStream: encryptor.GetStream(), 49 | decStream: decryptor.GetStream(), 50 | key: key, 51 | iv: iv, 52 | } 53 | } 54 | 55 | func (w *XorWrapper) Name() string { 56 | return core.XORWrapper 57 | } 58 | 59 | func (w *XorWrapper) Read(p []byte) (n int, err error) { 60 | return w.reader.Read(p) 61 | } 62 | 63 | func (w *XorWrapper) Write(p []byte) (n int, err error) { 64 | return w.writer.Write(p) 65 | } 66 | 67 | func (w *XorWrapper) Close() error { 68 | encryptor := utils.NewXorEncryptor(w.key, w.iv) 69 | decryptor := utils.NewXorEncryptor(w.key, w.iv) 70 | w.encStream = encryptor.GetStream() 71 | w.decStream = decryptor.GetStream() 72 | w.reader = &cipher.StreamReader{S: w.decStream, R: w.reader.(*cipher.StreamReader).R} 73 | w.writer = &cipher.StreamWriter{S: w.encStream, W: w.writer.(*cipher.StreamWriter).W} 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /protocol/tunnel/http/http.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | "github.com/chainreactors/rem/x/kcp" 9 | ) 10 | 11 | func init() { 12 | core.DialerRegister(core.HTTPTunnel, func(ctx context.Context) (core.TunnelDialer, error) { 13 | return NewHTTPDialer(ctx), nil 14 | }) 15 | 16 | core.ListenerRegister(core.HTTPTunnel, func(ctx context.Context) (core.TunnelListener, error) { 17 | return NewHTTPListener(ctx), nil 18 | }) 19 | } 20 | 21 | type HTTPDialer struct { 22 | net.Conn 23 | meta core.Metas 24 | } 25 | 26 | type HTTPListener struct { 27 | listener *kcp.Listener 28 | meta core.Metas 29 | } 30 | 31 | func NewHTTPDialer(ctx context.Context) *HTTPDialer { 32 | return &HTTPDialer{ 33 | meta: ctx.Value("meta").(core.Metas), 34 | } 35 | } 36 | 37 | func NewHTTPListener(ctx context.Context) *HTTPListener { 38 | return &HTTPListener{ 39 | meta: ctx.Value("meta").(core.Metas), 40 | } 41 | } 42 | 43 | func (c *HTTPListener) Addr() net.Addr { 44 | return c.meta.URL() 45 | } 46 | 47 | func (c *HTTPDialer) Dial(dst string) (net.Conn, error) { 48 | u, _ := core.NewURL(dst) 49 | c.meta["url"] = u 50 | kcp.SetKCPMTULimit(c.meta["mtu"].(int)) 51 | conn, err := kcp.DialWithOptions(u.RawScheme, u.Host, nil, 0, 0) 52 | if err != nil { 53 | return nil, err 54 | } 55 | return kcp.NewKCPConn(conn, kcp.HTTPKCPConfig), nil 56 | } 57 | 58 | func (c *HTTPListener) Listen(dst string) (net.Listener, error) { 59 | u, _ := core.NewURL(dst) 60 | c.meta["url"] = u 61 | kcp.SetKCPMTULimit(c.meta["mtu"].(int)) 62 | lsn, err := kcp.ListenWithOptions(u.RawScheme, u.Host, nil, 0, 0) 63 | if err != nil { 64 | return nil, err 65 | } 66 | c.listener = lsn 67 | c.listener.SetReadBuffer(core.MaxPacketSize) 68 | c.listener.SetWriteBuffer(core.MaxPacketSize) 69 | return lsn, nil 70 | } 71 | 72 | func (c *HTTPListener) Accept() (net.Conn, error) { 73 | conn, err := c.listener.AcceptKCP() 74 | if err != nil { 75 | return nil, err 76 | } 77 | return kcp.NewKCPConn(conn, kcp.HTTPKCPConfig), nil 78 | } 79 | 80 | func (c *HTTPListener) Close() error { 81 | if c.listener != nil { 82 | return c.listener.Close() 83 | } 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /x/trojanx/internal/tunnel/trojanConn.go: -------------------------------------------------------------------------------- 1 | package tunnel 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "github.com/chainreactors/rem/x/trojanx/internal/common" 7 | "github.com/pkg/errors" 8 | "io" 9 | "io/ioutil" 10 | "net" 11 | ) 12 | 13 | type TrojanConn struct { 14 | net.Conn 15 | } 16 | 17 | func (t *TrojanConn) ReadFrom(payload []byte) (int, net.Addr, error) { 18 | return t.ReadWithMetadata(payload) 19 | } 20 | 21 | func (t *TrojanConn) WriteTo(payload []byte, addr net.Addr) (int, error) { 22 | address, err := common.NewAddressFromAddr("udp", addr.String()) 23 | if err != nil { 24 | return 0, err 25 | } 26 | return t.WriteWithMetadata(payload, address) 27 | } 28 | 29 | func (t *TrojanConn) WriteWithMetadata(payload []byte, addr *common.Address) (int, error) { 30 | packet := make([]byte, 0, common.MaxPacketSize) 31 | w := bytes.NewBuffer(packet) 32 | addr.WriteTo(w) 33 | length := len(payload) 34 | lengthBuf := [2]byte{} 35 | crlf := [2]byte{0x0d, 0x0a} 36 | 37 | binary.BigEndian.PutUint16(lengthBuf[:], uint16(length)) 38 | w.Write(lengthBuf[:]) 39 | w.Write(crlf[:]) 40 | w.Write(payload) 41 | 42 | _, err := t.Conn.Write(w.Bytes()) 43 | 44 | return len(payload), err 45 | } 46 | 47 | func (t *TrojanConn) ReadWithMetadata(payload []byte) (int, *common.Address, error) { 48 | addr := &common.Address{ 49 | NetworkType: "udp", 50 | } 51 | if err := addr.ReadFrom(t.Conn); err != nil { 52 | return 0, nil, errors.New("failed to parse udp packet addr") 53 | } 54 | lengthBuf := [2]byte{} 55 | if _, err := io.ReadFull(t.Conn, lengthBuf[:]); err != nil { 56 | return 0, nil, errors.New("failed to read length") 57 | } 58 | length := int(binary.BigEndian.Uint16(lengthBuf[:])) 59 | 60 | crlf := [2]byte{} 61 | if _, err := io.ReadFull(t.Conn, crlf[:]); err != nil { 62 | return 0, nil, errors.New("failed to read crlf") 63 | } 64 | 65 | if len(payload) < length || length > common.MaxPacketSize { 66 | io.CopyN(ioutil.Discard, t.Conn, int64(length)) 67 | return 0, nil, errors.New("incoming packet size is too large") 68 | } 69 | 70 | if _, err := io.ReadFull(t.Conn, payload[:length]); err != nil { 71 | return 0, nil, errors.New("failed to read payload") 72 | } 73 | 74 | return length, addr, nil 75 | } 76 | -------------------------------------------------------------------------------- /x/socks5/relay.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "net" 7 | "strconv" 8 | ) 9 | 10 | func NewRelay(s string) (*RelayRequest, error) { 11 | host, port, err := net.SplitHostPort(s) 12 | if err != nil { 13 | return nil, err 14 | } 15 | portS, err := strconv.Atoi(port) 16 | if err != nil { 17 | return nil, err 18 | } 19 | ip := net.ParseIP(host) 20 | var req *RelayRequest 21 | if ip != nil { 22 | req = &RelayRequest{&AddrSpec{ 23 | IP: ip, 24 | Port: portS, 25 | }} 26 | } else { 27 | req = &RelayRequest{&AddrSpec{ 28 | FQDN: host, 29 | Port: portS, 30 | }} 31 | } 32 | return req, nil 33 | } 34 | 35 | type RelayRequest struct { 36 | // AddrSpec of the desired destination 37 | DestAddr *AddrSpec 38 | } 39 | 40 | func (req *RelayRequest) String() string { 41 | return req.DestAddr.String() 42 | } 43 | 44 | func (req *RelayRequest) BuildRelay() []byte { 45 | buf := &bytes.Buffer{} 46 | 47 | buf.Write([]byte{ 48 | 0x05, // VER 49 | 0x01, // NMETHODS 50 | 0x03, // METHOD (Relay Auth) 51 | }) 52 | buf.Write([]byte{ 53 | 0x05, // VER 54 | 0x01, // CMD 55 | 0x00, // RSV 56 | }) 57 | 58 | if req.DestAddr.IP != nil { 59 | if ip4 := req.DestAddr.IP.To4(); ip4 != nil { 60 | buf.WriteByte(0x01) // IPv4 61 | buf.Write(ip4) 62 | } else { 63 | buf.WriteByte(0x04) // IPv6 64 | buf.Write(req.DestAddr.IP) 65 | } 66 | } else { 67 | buf.WriteByte(0x03) // Domain 68 | buf.WriteByte(byte(len(req.DestAddr.FQDN))) 69 | buf.WriteString(req.DestAddr.FQDN) 70 | } 71 | 72 | buf.Write([]byte{ 73 | byte(req.DestAddr.Port >> 8), 74 | byte(req.DestAddr.Port), 75 | }) 76 | 77 | return buf.Bytes() 78 | } 79 | 80 | func (req *RelayRequest) HandleRelay(conn net.Conn, rwc io.ReadWriteCloser) error { 81 | _, err := rwc.Write(req.BuildRelay()) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | _, addr, err := ReadReply(rwc) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | replyData, err := BuildReply(SuccessReply, addr) 92 | if err != nil { 93 | return err 94 | } 95 | _, err = conn.Write(replyData) 96 | if err != nil { 97 | return err 98 | } 99 | return nil 100 | } 101 | -------------------------------------------------------------------------------- /protocol/wrapper/aes.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "crypto/cipher" 5 | "io" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | "github.com/chainreactors/rem/x/utils" 9 | ) 10 | 11 | func init() { 12 | core.WrapperRegister(core.AESWrapper, func(r io.Reader, w io.Writer, opt map[string]string) (core.Wrapper, error) { 13 | return NewAesWrapper(r, w, opt) 14 | }) 15 | core.AvailableWrappers = append(core.AvailableWrappers, core.AESWrapper) 16 | } 17 | 18 | type AESWrapper struct { 19 | reader io.Reader 20 | writer io.Writer 21 | encStream cipher.Stream 22 | decStream cipher.Stream 23 | key [32]byte 24 | iv [16]byte 25 | } 26 | 27 | func NewAesWrapper(r io.Reader, w io.Writer, opt map[string]string) (core.Wrapper, error) { 28 | var key [32]byte 29 | if k, ok := opt["key"]; ok { 30 | copy(key[:], k) 31 | } 32 | 33 | var iv [16]byte 34 | if i, ok := opt["iv"]; ok { 35 | copy(iv[:], i) 36 | } else { 37 | copy(iv[:], key[:16]) // 如果没有提供iv,使用key的前16字节 38 | } 39 | 40 | encStream, err := utils.NewAesStream(key, iv) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | decStream, err := utils.NewAesStream(key, iv) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | return &AESWrapper{ 51 | reader: &cipher.StreamReader{S: decStream, R: r}, 52 | writer: &cipher.StreamWriter{S: encStream, W: w}, 53 | encStream: encStream, 54 | decStream: decStream, 55 | key: key, 56 | iv: iv, 57 | }, nil 58 | } 59 | 60 | func (w *AESWrapper) Name() string { 61 | return core.AESWrapper 62 | } 63 | 64 | func (w *AESWrapper) Read(p []byte) (n int, err error) { 65 | return w.reader.Read(p) 66 | } 67 | 68 | func (w *AESWrapper) Write(p []byte) (n int, err error) { 69 | return w.writer.Write(p) 70 | } 71 | 72 | func (w *AESWrapper) Close() error { 73 | encStream, err := utils.NewAesStream(w.key, w.iv) 74 | if err != nil { 75 | return err 76 | } 77 | decStream, err := utils.NewAesStream(w.key, w.iv) 78 | if err != nil { 79 | return err 80 | } 81 | w.encStream = encStream 82 | w.decStream = decStream 83 | w.reader = &cipher.StreamReader{S: w.decStream, R: w.reader.(*cipher.StreamReader).R} 84 | w.writer = &cipher.StreamWriter{S: w.encStream, W: w.writer.(*cipher.StreamWriter).W} 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /protocol/serve/portforward/forward.go: -------------------------------------------------------------------------------- 1 | package portforward 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | 8 | "github.com/chainreactors/rem/protocol/core" 9 | "github.com/chainreactors/rem/x/socks5" 10 | "github.com/chainreactors/rem/x/utils" 11 | ) 12 | 13 | func init() { 14 | core.InboundRegister(core.PortForwardServe, NewForwardInbound) 15 | core.OutboundRegister(core.PortForwardServe, NewForwardOutbound) 16 | } 17 | 18 | func NewForwardInbound(params map[string]string) (core.Inbound, error) { 19 | dest, ok := params["dest"] 20 | if !ok { 21 | return nil, fmt.Errorf("dest not found") 22 | } 23 | ip, port := utils.SplitAddr(dest) 24 | utils.Log.Importantf("[agent.inbound] portforward serving: %s -> %s", params["src"], dest) 25 | return &ForwardPlugin{ 26 | Dest: &socks5.RelayRequest{DestAddr: &socks5.AddrSpec{ 27 | IP: net.ParseIP(ip), 28 | Port: port, 29 | }}, 30 | }, nil 31 | } 32 | 33 | func NewForwardOutbound(params map[string]string, dial core.ContextDialer) (core.Outbound, error) { 34 | dest, ok := params["dest"] 35 | if !ok { 36 | return nil, fmt.Errorf("dest not found") 37 | } 38 | ip, port := utils.SplitAddr(dest) 39 | utils.Log.Importantf("[agent.outbound] portforward serving: %s -> %s", dest, params["src"]) 40 | return &ForwardPlugin{ 41 | Dest: &socks5.RelayRequest{DestAddr: &socks5.AddrSpec{ 42 | IP: net.ParseIP(ip), 43 | Port: port, 44 | }}, 45 | dial: dial, 46 | }, nil 47 | } 48 | 49 | type ForwardPlugin struct { 50 | Dest *socks5.RelayRequest 51 | dial core.ContextDialer 52 | } 53 | 54 | func (plug *ForwardPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn) (net.Conn, error) { 55 | remote, err := plug.dial.Dial("tcp", plug.Dest.String()) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return remote, nil 60 | } 61 | 62 | func (plug *ForwardPlugin) Relay(conn net.Conn, bridge io.ReadWriteCloser) (net.Conn, error) { 63 | _, err := bridge.Write(plug.Dest.BuildRelay()) 64 | if err != nil { 65 | return nil, err 66 | } 67 | 68 | _, _, err = socks5.ReadReply(bridge) 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | return conn, nil 74 | } 75 | 76 | func (plug *ForwardPlugin) Name() string { 77 | return core.PortForwardServe 78 | } 79 | 80 | func (plug *ForwardPlugin) ToClash() *utils.Proxies { 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /x/kcp/readloop.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | import ( 26 | "sync/atomic" 27 | 28 | "github.com/pkg/errors" 29 | ) 30 | 31 | // defaultReadLoop is the standard procedure for reading from a connection 32 | func (s *KCPSession) defaultReadLoop() { 33 | buf := make([]byte, mtuLimit) 34 | var src string 35 | for { 36 | if n, addr, err := s.conn.ReadFrom(buf); err == nil { 37 | // make sure the packet is from the same source 38 | if src == "" { // set source address 39 | src = addr.String() 40 | } else if addr.String() != src { 41 | atomic.AddUint64(&DefaultSnmp.InErrs, 1) 42 | continue 43 | } 44 | s.packetInput(buf[:n]) 45 | } else { 46 | s.notifyReadError(errors.WithStack(err)) 47 | return 48 | } 49 | } 50 | } 51 | 52 | // defaultReadLoop is the standard procedure for reading and accepting connections on a listener 53 | func (l *Listener) defaultMonitor() { 54 | buf := make([]byte, mtuLimit) 55 | for { 56 | if n, from, err := l.conn.ReadFrom(buf); err == nil { 57 | if n == 0 { 58 | return 59 | } 60 | l.packetInput(buf[:n], from) 61 | } else { 62 | l.notifyReadError(errors.WithStack(err)) 63 | return 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /protocol/tunnel/icmp/icmp.go: -------------------------------------------------------------------------------- 1 | package icmp 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/chainreactors/rem/protocol/core" 8 | "github.com/chainreactors/rem/x/kcp" 9 | ) 10 | 11 | func init() { 12 | core.DialerRegister(core.ICMPTunnel, func(ctx context.Context) (core.TunnelDialer, error) { 13 | return NewICMPDialer(ctx), nil 14 | }) 15 | core.ListenerRegister(core.ICMPTunnel, func(ctx context.Context) (core.TunnelListener, error) { 16 | return NewICMPListener(ctx), nil 17 | }) 18 | } 19 | 20 | type ICMPDialer struct { 21 | net.Conn 22 | meta core.Metas 23 | } 24 | 25 | type ICMPListener struct { 26 | listener *kcp.Listener 27 | meta core.Metas 28 | } 29 | 30 | func NewICMPDialer(ctx context.Context) *ICMPDialer { 31 | return &ICMPDialer{ 32 | meta: core.GetMetas(ctx), 33 | } 34 | } 35 | 36 | func NewICMPListener(ctx context.Context) *ICMPListener { 37 | return &ICMPListener{ 38 | meta: core.GetMetas(ctx), 39 | } 40 | } 41 | 42 | func (c *ICMPListener) Addr() net.Addr { 43 | return c.meta.URL() 44 | } 45 | 46 | func (c *ICMPDialer) Dial(dst string) (net.Conn, error) { 47 | u, _ := core.NewURL(dst) 48 | c.meta["url"] = u 49 | //host, _, err := net.SplitHostPort(dst) 50 | //if err != nil { 51 | // return nil, err 52 | //} 53 | conn, err := kcp.DialWithOptions(parseICMPNetwork(u.Hostname()), u.Host, nil, 0, 0) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return kcp.NewKCPConn(conn, kcp.RadicalKCPConfig), nil 58 | } 59 | 60 | func (c *ICMPListener) Listen(dst string) (net.Listener, error) { 61 | u, _ := core.NewURL(dst) 62 | c.meta["url"] = u 63 | lsn, err := kcp.ListenWithOptions(parseICMPNetwork(u.Hostname()), u.Host, nil, 0, 0) 64 | if err != nil { 65 | return nil, err 66 | } 67 | c.listener = lsn 68 | c.listener.SetReadBuffer(core.MaxPacketSize) 69 | c.listener.SetWriteBuffer(core.MaxPacketSize) 70 | c.listener.SetDSCP(46) 71 | return lsn, nil 72 | } 73 | 74 | func (c *ICMPListener) Accept() (net.Conn, error) { 75 | conn, err := c.listener.AcceptKCP() 76 | if err != nil { 77 | return nil, err 78 | } 79 | return kcp.NewKCPConn(conn, kcp.RadicalKCPConfig), nil 80 | } 81 | 82 | func (c *ICMPListener) Close() error { 83 | if c.listener != nil { 84 | return c.listener.Close() 85 | } 86 | return nil 87 | } 88 | 89 | func parseICMPNetwork(ipStr string) string { 90 | ip := net.ParseIP(ipStr) 91 | 92 | if ip.To4() != nil { 93 | return "ip4:icmp" 94 | } 95 | return "ip6:ipv6-icmp" 96 | } 97 | -------------------------------------------------------------------------------- /x/kcp/entropy.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | import ( 26 | "crypto/aes" 27 | "crypto/cipher" 28 | "crypto/md5" 29 | "crypto/rand" 30 | "io" 31 | ) 32 | 33 | // Entropy defines a entropy source 34 | // 35 | // Entropy in this file generate random bits for the first 16-bytes of each packets. 36 | type Entropy interface { 37 | Init() 38 | Fill(nonce []byte) 39 | } 40 | 41 | // nonceMD5 nonce generator for packet header 42 | type nonceMD5 struct { 43 | seed [md5.Size]byte 44 | } 45 | 46 | func (n *nonceMD5) Init() { /*nothing required*/ } 47 | 48 | func (n *nonceMD5) Fill(nonce []byte) { 49 | if n.seed[0] == 0 { // entropy update 50 | io.ReadFull(rand.Reader, n.seed[:]) 51 | } 52 | n.seed = md5.Sum(n.seed[:]) 53 | copy(nonce, n.seed[:]) 54 | } 55 | 56 | // nonceAES128 nonce generator for packet headers 57 | type nonceAES128 struct { 58 | seed [aes.BlockSize]byte 59 | block cipher.Block 60 | } 61 | 62 | func (n *nonceAES128) Init() { 63 | var key [16]byte //aes-128 64 | io.ReadFull(rand.Reader, key[:]) 65 | io.ReadFull(rand.Reader, n.seed[:]) 66 | block, _ := aes.NewCipher(key[:]) 67 | n.block = block 68 | } 69 | 70 | func (n *nonceAES128) Fill(nonce []byte) { 71 | if n.seed[0] == 0 { // entropy update 72 | io.ReadFull(rand.Reader, n.seed[:]) 73 | } 74 | n.block.Encrypt(n.seed[:], n.seed[:]) 75 | copy(nonce, n.seed[:]) 76 | } 77 | -------------------------------------------------------------------------------- /x/kcp/tx_linux.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | //go:build linux 24 | 25 | package kcp 26 | 27 | import ( 28 | "net" 29 | "os" 30 | "sync/atomic" 31 | 32 | "github.com/pkg/errors" 33 | "golang.org/x/net/ipv4" 34 | ) 35 | 36 | // tx is the optimized procedure to transmit packets utilizing the linux sendmmsg system call 37 | func (s *KCPSession) tx(txqueue []ipv4.Message) { 38 | // default version 39 | if s.xconn == nil || s.xconnWriteError != nil { 40 | s.defaultTx(txqueue) 41 | return 42 | } 43 | 44 | // x/net version 45 | nbytes := 0 46 | npkts := 0 47 | for len(txqueue) > 0 { 48 | if n, err := s.xconn.WriteBatch(txqueue, 0); err == nil { 49 | for k := range txqueue[:n] { 50 | nbytes += len(txqueue[k].Buffers[0]) 51 | } 52 | npkts += n 53 | txqueue = txqueue[n:] 54 | } else { 55 | // compatibility issue: 56 | // for linux kernel<=2.6.32, support for sendmmsg is not available 57 | // an error of type os.SyscallError will be returned 58 | if operr, ok := err.(*net.OpError); ok { 59 | if se, ok := operr.Err.(*os.SyscallError); ok { 60 | if se.Syscall == "sendmmsg" { 61 | s.xconnWriteError = se 62 | s.defaultTx(txqueue) 63 | return 64 | } 65 | } 66 | } 67 | s.notifyWriteError(errors.WithStack(err)) 68 | break 69 | } 70 | } 71 | 72 | atomic.AddUint64(&DefaultSnmp.OutPkts, uint64(npkts)) 73 | atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes)) 74 | } 75 | -------------------------------------------------------------------------------- /protocol/wrapper/wrapper.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "bufio" 5 | "github.com/chainreactors/rem/protocol/core" 6 | "net" 7 | ) 8 | 9 | // WrapperChain 实现了wrapper链式调用 10 | type WrapperChain struct { 11 | wrappers []core.Wrapper 12 | conn net.Conn 13 | reader *ChainReader 14 | } 15 | 16 | type ChainReader struct { 17 | wrapper core.Wrapper 18 | next *ChainReader 19 | reader *bufio.Reader 20 | } 21 | 22 | func NewChainReader(w core.Wrapper) *ChainReader { 23 | return &ChainReader{ 24 | wrapper: w, 25 | reader: bufio.NewReader(w), 26 | } 27 | } 28 | 29 | func (r *ChainReader) Chain(next *ChainReader) { 30 | r.next = next 31 | } 32 | 33 | func (r *ChainReader) Read(p []byte) (n int, err error) { 34 | if r.next != nil { 35 | return r.next.Read(p) 36 | } 37 | return r.wrapper.Read(p) 38 | } 39 | 40 | // NewChainWrapper 创建一个wrapper链 41 | func NewChainWrapper(conn net.Conn, opts []*core.WrapperOption) (core.Wrapper, error) { 42 | chain := &WrapperChain{ 43 | conn: conn, 44 | wrappers: make([]core.Wrapper, 0, len(opts)), 45 | } 46 | 47 | // 创建写入链 48 | var current core.Wrapper = nil 49 | for _, opt := range opts { 50 | var w core.Wrapper 51 | var err error 52 | if current == nil { 53 | w, err = core.WrapperCreate(opt.Name, conn, conn, opt.Options) 54 | } else { 55 | w, err = core.WrapperCreate(opt.Name, current, current, opt.Options) 56 | } 57 | if err != nil { 58 | return nil, err 59 | } 60 | chain.wrappers = append(chain.wrappers, w) 61 | current = w 62 | } 63 | 64 | // 创建读取链 65 | var reader *ChainReader 66 | for i := len(chain.wrappers) - 1; i >= 0; i-- { 67 | w := chain.wrappers[i] 68 | newReader := NewChainReader(w) 69 | if reader != nil { 70 | newReader.Chain(reader) 71 | } 72 | reader = newReader 73 | } 74 | chain.reader = reader 75 | 76 | return chain, nil 77 | } 78 | 79 | func (c *WrapperChain) Name() string { 80 | return "chain" 81 | } 82 | 83 | // Read 从最后一个wrapper开始读,保持解密顺序 84 | func (c *WrapperChain) Read(p []byte) (n int, err error) { 85 | if c.reader == nil { 86 | return c.conn.Read(p) 87 | } 88 | return c.reader.Read(p) 89 | } 90 | 91 | // Write 从第一个wrapper开始写,保持加密顺序 92 | func (c *WrapperChain) Write(p []byte) (n int, err error) { 93 | if len(c.wrappers) == 0 { 94 | return c.conn.Write(p) 95 | } 96 | return c.wrappers[len(c.wrappers)-1].Write(p) 97 | } 98 | 99 | // Close 关闭所有wrapper 100 | func (c *WrapperChain) Close() error { 101 | for _, w := range c.wrappers { 102 | if err := w.Close(); err != nil { 103 | return err 104 | } 105 | } 106 | return c.conn.Close() 107 | } 108 | -------------------------------------------------------------------------------- /x/socks5/socks5_test.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "io" 7 | "log" 8 | "net" 9 | "os" 10 | "testing" 11 | "time" 12 | ) 13 | 14 | func TestSOCKS5_Connect(t *testing.T) { 15 | // Create a local listener 16 | l, err := net.Listen("tcp", "127.0.0.1:0") 17 | if err != nil { 18 | t.Fatalf("err: %v", err) 19 | } 20 | go func() { 21 | conn, err := l.Accept() 22 | if err != nil { 23 | t.Fatalf("err: %v", err) 24 | } 25 | defer conn.Close() 26 | 27 | buf := make([]byte, 4) 28 | if _, err := io.ReadAtLeast(conn, buf, 4); err != nil { 29 | t.Fatalf("err: %v", err) 30 | } 31 | 32 | if !bytes.Equal(buf, []byte("ping")) { 33 | t.Fatalf("bad: %v", buf) 34 | } 35 | conn.Write([]byte("pong")) 36 | }() 37 | lAddr := l.Addr().(*net.TCPAddr) 38 | 39 | // Create a socks server 40 | creds := StaticCredentials{ 41 | "foo": "bar", 42 | } 43 | cator := UserPassAuthenticator{Credentials: creds} 44 | conf := &Config{ 45 | AuthMethods: []Authenticator{cator}, 46 | Logger: log.New(os.Stdout, "", log.LstdFlags), 47 | } 48 | serv, err := New(conf) 49 | if err != nil { 50 | t.Fatalf("err: %v", err) 51 | } 52 | 53 | // Start listening 54 | go func() { 55 | if err := serv.ListenAndServe("tcp", "127.0.0.1:12365"); err != nil { 56 | t.Fatalf("err: %v", err) 57 | } 58 | }() 59 | time.Sleep(10 * time.Millisecond) 60 | 61 | // Get a local conn 62 | conn, err := net.Dial("tcp", "127.0.0.1:12365") 63 | if err != nil { 64 | t.Fatalf("err: %v", err) 65 | } 66 | 67 | // Connect, auth and connec to local 68 | req := bytes.NewBuffer(nil) 69 | req.Write([]byte{5}) 70 | req.Write([]byte{2, NoAuth, UserPassAuth}) 71 | req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'}) 72 | req.Write([]byte{5, 1, 0, 1, 127, 0, 0, 1}) 73 | 74 | port := []byte{0, 0} 75 | binary.BigEndian.PutUint16(port, uint16(lAddr.Port)) 76 | req.Write(port) 77 | 78 | // Send a ping 79 | req.Write([]byte("ping")) 80 | 81 | // Send all the bytes 82 | conn.Write(req.Bytes()) 83 | 84 | // Verify response 85 | expected := []byte{ 86 | socks5Version, UserPassAuth, 87 | 1, authSuccess, 88 | 5, 89 | 0, 90 | 0, 91 | 1, 92 | 127, 0, 0, 1, 93 | 0, 0, 94 | 'p', 'o', 'n', 'g', 95 | } 96 | out := make([]byte, len(expected)) 97 | 98 | conn.SetDeadline(time.Now().Add(time.Second)) 99 | if _, err := io.ReadAtLeast(conn, out, len(out)); err != nil { 100 | t.Fatalf("err: %v", err) 101 | } 102 | 103 | // Ignore the port 104 | out[12] = 0 105 | out[13] = 0 106 | 107 | if !bytes.Equal(out, expected) { 108 | t.Fatalf("bad: %v", out) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /cmd/cmd/cmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "github.com/chainreactors/logs" 7 | "github.com/chainreactors/rem/runner" 8 | "github.com/chainreactors/rem/x/utils" 9 | "github.com/jessevdk/go-flags" 10 | "github.com/kballard/go-shellquote" 11 | "os" 12 | "time" 13 | ) 14 | 15 | var ver = "" 16 | 17 | func RUN() { 18 | defer exit() 19 | var option runner.Options 20 | parser := flags.NewParser(&option, flags.Default) 21 | parser.Usage = ` 22 | WIKI: https://chainreactors.github.io/wiki/rem 23 | 24 | QUICKSTART: 25 | serving: 26 | ./rem 27 | 28 | reverse socks5 proxy: 29 | ./rem -c [link] 30 | 31 | serve socks5 proxy on client: 32 | ./rem -c [link] -m proxy 33 | 34 | remote port forward: 35 | ./rem -c [link] -l port://:8080 36 | 37 | local port forward: 38 | ./rem -c [link] -r port://:8080 39 | 40 | ` 41 | var args []string 42 | reader := bufio.NewReader(os.Stdin) 43 | ch := make(chan string) 44 | 45 | go func() { 46 | data, _ := reader.ReadString('\n') 47 | ch <- data 48 | }() 49 | 50 | select { 51 | case input := <-ch: 52 | split, err := shellquote.Split(input) 53 | if err != nil { 54 | logs.Log.Error(err) 55 | return 56 | } 57 | args = split 58 | case <-time.After(100 * time.Millisecond): 59 | } 60 | 61 | if len(args) == 0 { 62 | args = os.Args[1:] 63 | } 64 | 65 | _, err := parser.ParseArgs(args) 66 | if err != nil { 67 | if err.(*flags.Error).Type != flags.ErrHelp { 68 | fmt.Println(err.Error()) 69 | } 70 | return 71 | } 72 | 73 | if option.Version { 74 | fmt.Println(ver) 75 | return 76 | } 77 | // 如果命令行参数为空,使用编译时设置的默认值 78 | if option.Mod == "" { 79 | option.Mod = runner.DefaultMod 80 | } 81 | if len(option.ConsoleAddr) == 0 { 82 | option.ConsoleAddr = []string{runner.DefaultConsole} 83 | } 84 | if option.LocalAddr == "" { 85 | option.LocalAddr = runner.DefaultLocal 86 | } 87 | if option.RemoteAddr == "" { 88 | option.RemoteAddr = runner.DefaultRemote 89 | } 90 | 91 | if option.Debug { 92 | utils.Log = logs.NewLogger(logs.DebugLevel) 93 | utils.Log.LogFileName = "maitai.log" 94 | utils.Log.Init() 95 | } else if option.Detail { 96 | utils.Log = logs.NewLogger(utils.IOLog) 97 | } else if option.Quiet { 98 | utils.Log = logs.NewLogger(100) 99 | } else { 100 | utils.Log = logs.NewLogger(logs.InfoLevel) 101 | } 102 | 103 | runner, err := option.Prepare() 104 | if err != nil { 105 | fmt.Println(err.Error()) 106 | return 107 | } 108 | 109 | utils.Log.Debugf("rem version: %s", ver) 110 | err = runner.Run() 111 | if err != nil { 112 | fmt.Println(err.Error()) 113 | return 114 | } 115 | } 116 | 117 | func exit() { 118 | os.Exit(0) 119 | } 120 | -------------------------------------------------------------------------------- /x/kcp/icmp.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | import ( 4 | "encoding/binary" 5 | "net" 6 | "sync" 7 | "sync/atomic" 8 | 9 | "golang.org/x/net/icmp" 10 | "golang.org/x/net/ipv4" 11 | ) 12 | 13 | type remoteInfo struct { 14 | addr net.Addr 15 | id int 16 | } 17 | 18 | type icmpConn struct { 19 | *icmp.PacketConn 20 | id int // convid作为ICMP ID 21 | port int // port作为token 22 | seq int32 23 | isClient bool 24 | 25 | // 连接池相关 26 | remotes sync.Map // key: addr.String(), value: *remoteInfo 27 | } 28 | 29 | func (c *icmpConn) getOrCreateRemote(addr net.Addr, id int) *remoteInfo { 30 | key := addr.String() 31 | if info, ok := c.remotes.Load(key); ok { 32 | return info.(*remoteInfo) 33 | } 34 | 35 | info := &remoteInfo{ 36 | addr: addr, 37 | id: id, 38 | } 39 | c.remotes.Store(key, info) 40 | return info 41 | } 42 | 43 | func (c *icmpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 44 | seq := atomic.AddInt32(&c.seq, 1) 45 | msgType := ipv4.ICMPTypeEcho 46 | 47 | // 在数据前加入port作为token 48 | data := make([]byte, 2+len(p)) 49 | binary.BigEndian.PutUint16(data[:2], uint16(c.port)) 50 | copy(data[2:], p) 51 | 52 | var remoteID int 53 | if !c.isClient { 54 | msgType = ipv4.ICMPTypeEchoReply 55 | // 从连接池获取对应的remote信息 56 | if info, ok := c.remotes.Load(addr.String()); ok { 57 | remoteID = info.(*remoteInfo).id 58 | } else { 59 | return 0, nil 60 | } 61 | } else { 62 | remoteID = c.id 63 | } 64 | 65 | m := &icmp.Message{ 66 | Type: msgType, 67 | Code: 0, 68 | Body: &icmp.Echo{ 69 | ID: remoteID, 70 | Seq: int(seq), 71 | Data: data, 72 | }, 73 | } 74 | 75 | wb, err := m.Marshal(nil) 76 | if err != nil { 77 | return 0, err 78 | } 79 | 80 | n, err = c.PacketConn.WriteTo(wb, addr) 81 | if err != nil { 82 | return 0, err 83 | } 84 | 85 | return len(p), nil 86 | } 87 | 88 | func (c *icmpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 89 | for { 90 | n, addr, err = c.PacketConn.ReadFrom(p) 91 | if err != nil { 92 | return 93 | } 94 | 95 | msg, err := icmp.ParseMessage(1, p[:n]) 96 | if err != nil { 97 | continue 98 | } 99 | 100 | if echo, ok := msg.Body.(*icmp.Echo); ok { 101 | if len(echo.Data) < 2 { 102 | continue 103 | } 104 | 105 | // 验证port token 106 | recvPort := int(binary.BigEndian.Uint16(echo.Data[:2])) 107 | if recvPort != c.port { 108 | continue 109 | } 110 | 111 | if !c.isClient { 112 | // 服务端收到新连接,记录到连接池 113 | c.getOrCreateRemote(addr, echo.ID) 114 | } 115 | 116 | // 返回数据时去除port token 117 | n = copy(p, echo.Data[2:]) 118 | return n, addr, nil 119 | } 120 | } 121 | } 122 | 123 | func (c *icmpConn) LocalAddr() net.Addr { 124 | return c.PacketConn.LocalAddr() 125 | } 126 | -------------------------------------------------------------------------------- /x/kcp/autotune_test.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | import ( 26 | "testing" 27 | 28 | "github.com/stretchr/testify/assert" 29 | ) 30 | 31 | func TestAutoTune(t *testing.T) { 32 | signals := []uint32{0, 0, 0, 0, 0, 0} 33 | 34 | tune := autoTune{} 35 | for i := 0; i < len(signals); i++ { 36 | if signals[i] == 0 { 37 | tune.Sample(false, uint32(i)) 38 | } else { 39 | tune.Sample(true, uint32(i)) 40 | } 41 | } 42 | 43 | assert.Equal(t, -1, tune.FindPeriod(false)) 44 | assert.Equal(t, -1, tune.FindPeriod(true)) 45 | 46 | signals = []uint32{1, 0, 1, 0, 0, 1} 47 | tune = autoTune{} 48 | for i := 0; i < len(signals); i++ { 49 | if signals[i] == 0 { 50 | tune.Sample(false, uint32(i)) 51 | } else { 52 | tune.Sample(true, uint32(i)) 53 | } 54 | } 55 | assert.Equal(t, 1, tune.FindPeriod(false)) 56 | assert.Equal(t, 1, tune.FindPeriod(true)) 57 | 58 | signals = []uint32{1, 0, 0, 0, 0, 1} 59 | tune = autoTune{} 60 | for i := 0; i < len(signals); i++ { 61 | if signals[i] == 0 { 62 | tune.Sample(false, uint32(i)) 63 | } else { 64 | tune.Sample(true, uint32(i)) 65 | } 66 | } 67 | assert.Equal(t, -1, tune.FindPeriod(true)) 68 | assert.Equal(t, 4, tune.FindPeriod(false)) 69 | 70 | // minimal test 71 | tune = autoTune{} 72 | for i := 0; i < 1024; i++ { 73 | if i%maxAutoTuneSamples == 0 { 74 | tune.Sample(false, uint32(i)) 75 | } else { 76 | tune.Sample(true, uint32(i)) 77 | } 78 | } 79 | assert.NotEqual(t, 0, tune.pulses[0].seq) 80 | minSeq := tune.pulses[0].seq 81 | t.Log("minimal seq", tune.pulses[0].seq) 82 | 83 | tune.Sample(false, minSeq-1) 84 | assert.Equal(t, minSeq, tune.pulses[0].seq) 85 | } 86 | -------------------------------------------------------------------------------- /protocol/wrapper/padding.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "io" 7 | 8 | "github.com/chainreactors/rem/protocol/cio" 9 | "github.com/chainreactors/rem/protocol/core" 10 | ) 11 | 12 | func init() { 13 | core.WrapperRegister(core.PaddingWrapper, func(r io.Reader, w io.Writer, opt map[string]string) (core.Wrapper, error) { 14 | return NewPaddingWrapper(r, w, opt), nil 15 | }) 16 | } 17 | 18 | // PaddingOption 定义padding wrapper的配置选项 19 | type PaddingOption struct { 20 | Prefix []byte 21 | Suffix []byte 22 | } 23 | 24 | type PaddingWrapper struct { 25 | reader *cio.Reader 26 | writer *cio.Writer 27 | parseLength func(reader *cio.Reader) (uint32, error) 28 | genLength func(p []byte) []byte 29 | suffix []byte 30 | prefix []byte 31 | } 32 | 33 | func NewPaddingWrapper(r io.Reader, w io.Writer, opt map[string]string) core.Wrapper { 34 | var prefix, suffix string 35 | if p, ok := opt["prefix"]; ok { 36 | prefix = p 37 | } 38 | if s, ok := opt["suffix"]; ok { 39 | suffix = s 40 | } 41 | 42 | return &PaddingWrapper{ 43 | reader: cio.NewReader(r), 44 | writer: cio.NewWriter(w), 45 | prefix: []byte(prefix), 46 | suffix: []byte(suffix), 47 | genLength: defaultGenLength, 48 | parseLength: defaultParserLength, 49 | } 50 | } 51 | 52 | func (w *PaddingWrapper) Name() string { 53 | return "padding" 54 | } 55 | 56 | func (w *PaddingWrapper) Fill() error { 57 | err := w.reader.PeekAndRead(w.prefix) 58 | if err != nil { 59 | return err 60 | } 61 | n, err := w.parseLength(w.reader) 62 | if err != nil { 63 | return err 64 | } 65 | err = w.reader.FillN(int64(n)) 66 | if err != nil { 67 | return err 68 | } 69 | 70 | return w.reader.PeekAndRead(w.suffix) 71 | } 72 | 73 | func (w *PaddingWrapper) Read(p []byte) (n int, err error) { 74 | if w.reader.Buffer.Size() == 0 { 75 | err = w.Fill() 76 | if err != nil { 77 | return 0, err 78 | } 79 | } 80 | return w.reader.Read(p) 81 | } 82 | 83 | func (w *PaddingWrapper) Write(p []byte) (n int, err error) { 84 | var buf bytes.Buffer 85 | buf.Write(w.prefix) 86 | buf.Write(w.genLength(p)) 87 | buf.Write(p) 88 | buf.Write(w.suffix) 89 | 90 | n, err = w.writer.Write(buf.Bytes()) 91 | if err != nil { 92 | return n, err 93 | } 94 | return len(p), nil 95 | } 96 | 97 | func (w *PaddingWrapper) Close() error { 98 | return nil 99 | } 100 | 101 | func defaultParserLength(reader *cio.Reader) (uint32, error) { 102 | p := make([]byte, 4) 103 | _, err := reader.Read(p) 104 | if err != nil { 105 | return 0, err 106 | } 107 | return binary.LittleEndian.Uint32(p), nil 108 | } 109 | 110 | func defaultGenLength(p []byte) []byte { 111 | buf := make([]byte, 4) 112 | binary.LittleEndian.PutUint32(buf, uint32(len(p))) 113 | return buf 114 | } 115 | -------------------------------------------------------------------------------- /x/utils/address.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/sha256" 5 | "fmt" 6 | "math/rand" 7 | "net" 8 | "os" 9 | "reflect" 10 | "strconv" 11 | "strings" 12 | "time" 13 | ) 14 | 15 | func init() { 16 | rand.Seed(time.Now().UnixNano()) 17 | } 18 | 19 | func SplitAddr(addr string) (string, int) { 20 | parsed := strings.Split(addr, ":") 21 | port, _ := strconv.Atoi(parsed[1]) 22 | return parsed[0], port 23 | } 24 | 25 | func ResetInt(period int, rester *int, orgin *int) { 26 | valueOfr := reflect.ValueOf(rester) 27 | valueOfr = valueOfr.Elem() 28 | select { 29 | case <-time.After(time.Duration(period) * time.Millisecond): 30 | 31 | valueOfr.SetInt(int64(*orgin)) 32 | } 33 | 34 | } 35 | 36 | func RandomString(length int) string { 37 | const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 38 | var seededRand = rand.New(rand.NewSource(time.Now().UnixNano())) 39 | 40 | // 创建结果字节数组 41 | result := make([]byte, length) 42 | for i := range result { 43 | result[i] = charset[seededRand.Intn(len(charset))] 44 | } 45 | return string(result) 46 | } 47 | 48 | func RandPort() int { 49 | return rand.Intn(30000-20000) + 20000 50 | } 51 | 52 | func JoinHostPort(ip string, port int) string { 53 | return fmt.Sprintf("%s:%d", ip, port) 54 | } 55 | 56 | func GetLocalAddr() string { 57 | addrs, err := net.InterfaceAddrs() 58 | 59 | if err != nil { 60 | fmt.Println(err) 61 | os.Exit(1) 62 | } 63 | 64 | for _, address := range addrs { 65 | 66 | // 检查ip地址判断是否回环地址 67 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 68 | if ipnet.IP.To4() != nil { 69 | return ipnet.IP.String() 70 | } 71 | } 72 | } 73 | return "127.0.0.1" 74 | } 75 | 76 | func getMachineMacAddress() (string, error) { 77 | interfaces, err := net.Interfaces() 78 | if err != nil { 79 | return "", err 80 | } 81 | // 选择第一个有效的网络接口 82 | for _, iface := range interfaces { 83 | if len(iface.HardwareAddr) > 0 { 84 | return iface.HardwareAddr.String(), nil 85 | } 86 | } 87 | return "", fmt.Errorf("no valid MAC address found") 88 | } 89 | 90 | func GenerateMachineHash() string { 91 | mac, err := getMachineMacAddress() 92 | if err != nil { 93 | return RandomString(32) 94 | } 95 | 96 | // 使用 SHA-256 算法生成哈希 97 | hash := sha256.New() 98 | hash.Write([]byte(mac)) 99 | hashBytes := hash.Sum(nil) 100 | return fmt.Sprintf("%x", hashBytes) 101 | } 102 | 103 | func GetLocalSubnet() []string { 104 | addrs, err := net.InterfaceAddrs() 105 | if err != nil { 106 | return nil 107 | } 108 | var ss []string 109 | for _, addr := range addrs { 110 | if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 111 | if i := ipnet.IP.To4(); i != nil && i[0] != 169 { 112 | ss = append(ss, ipnet.String()) 113 | } 114 | } 115 | } 116 | return ss 117 | } 118 | -------------------------------------------------------------------------------- /x/kcp/wireshark/kcp_dissector.lua: -------------------------------------------------------------------------------- 1 | -- create protocol 2 | kcp_protocol = Proto("KCP", "KCP Protocol") 3 | 4 | -- fields for kcp 5 | conv = ProtoField.uint32("kcp.conv", "conv", base.DEC) 6 | cmd = ProtoField.uint8("kcp.cmd", "cmd", base.DEC) 7 | frg = ProtoField.uint8("kcp.frg", "frg", base.DEC) 8 | wnd = ProtoField.uint16("kcp.wnd", "wnd", base.DEC) 9 | ts = ProtoField.uint32("kcp.ts", "ts", base.DEC) 10 | sn = ProtoField.uint32("kcp.sn", "sn", base.DEC) 11 | una = ProtoField.uint32("kcp.una", "una", base.DEC) 12 | len = ProtoField.uint32("kcp.len", "len", base.DEC) 13 | 14 | kcp_protocol.fields = {conv, cmd, frg, wnd, ts, sn, una, len} 15 | 16 | -- dissect each udp packet 17 | function kcp_protocol.dissector(buffer, pinfo, tree) 18 | length = buffer:len() 19 | if length == 0 then 20 | return 21 | end 22 | 23 | local offset_s = 8 24 | local first_sn = buffer(offset_s + 12, 4):le_int() 25 | local first_len = buffer(offset_s + 20, 4):le_int() 26 | local first_cmd_name = get_cmd_name(buffer(offset_s + 4, 1):le_int()) 27 | local info = string.format("[%s] Sn=%d Kcplen=%d", first_cmd_name, first_sn, first_len) 28 | 29 | pinfo.cols.protocol = kcp_protocol.name 30 | udp_info = string.gsub(tostring(pinfo.cols.info), "Len", "Udplen", 1) 31 | pinfo.cols.info = string.gsub(udp_info, " U", info .. " U", 1) 32 | 33 | -- dssect multi kcp packet in udp 34 | local offset = 8 35 | while offset < buffer:len() do 36 | local conv_buf = buffer(offset + 0, 4) 37 | local cmd_buf = buffer(offset + 4, 1) 38 | local wnd_buf = buffer(offset + 6, 2) 39 | local sn_buf = buffer(offset + 12, 4) 40 | local len_buf = buffer(offset + 20, 4) 41 | 42 | local cmd_name = get_cmd_name(cmd_buf:le_int()) 43 | local data_len = len_buf:le_int() 44 | 45 | local tree_title = 46 | string.format( 47 | "KCP Protocol, %s, Sn: %d, Conv: %d, Wnd: %d, Len: %d", 48 | cmd_name, 49 | sn_buf:le_int(), 50 | conv_buf:le_int(), 51 | wnd_buf:le_int(), 52 | data_len 53 | ) 54 | local subtree = tree:add(kcp_protocol, buffer(), tree_title) 55 | subtree:add_le(conv, conv_buf) 56 | subtree:add_le(cmd, cmd_buf):append_text(" (" .. cmd_name .. ")") 57 | subtree:add_le(frg, buffer(offset + 5, 1)) 58 | subtree:add_le(wnd, wnd_buf) 59 | subtree:add_le(ts, buffer(offset + 8, 4)) 60 | subtree:add_le(sn, sn_buf) 61 | subtree:add_le(una, buffer(offset + 16, 4)) 62 | subtree:add_le(len, len_buf) 63 | offset = offset + 24 + data_len 64 | end 65 | end 66 | 67 | function get_cmd_name(cmd_val) 68 | if cmd_val == 81 then 69 | return "PSH" 70 | elseif cmd_val == 82 then 71 | return "ACK" 72 | elseif cmd_val == 83 then 73 | return "ASK" 74 | elseif cmd_val == 84 then 75 | return "TELL" 76 | end 77 | end 78 | 79 | -- register kcp dissector to udp 80 | local udp_port = DissectorTable.get("udp.port") 81 | -- replace 8081 to the port for kcp 82 | udp_port:add(8081, kcp_protocol) 83 | -------------------------------------------------------------------------------- /x/socks5/auth_test.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestNoAuth(t *testing.T) { 9 | req := bytes.NewBuffer(nil) 10 | req.Write([]byte{1, NoAuth}) 11 | var resp bytes.Buffer 12 | 13 | s, _ := New(&Config{}) 14 | ctx, err := s.authenticate(&resp, req) 15 | if err != nil { 16 | t.Fatalf("err: %v", err) 17 | } 18 | 19 | if ctx.Method != NoAuth { 20 | t.Fatal("Invalid Context Method") 21 | } 22 | 23 | out := resp.Bytes() 24 | if !bytes.Equal(out, []byte{socks5Version, NoAuth}) { 25 | t.Fatalf("bad: %v", out) 26 | } 27 | } 28 | 29 | func TestPasswordAuth_Valid(t *testing.T) { 30 | req := bytes.NewBuffer(nil) 31 | req.Write([]byte{2, NoAuth, UserPassAuth}) 32 | req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'}) 33 | var resp bytes.Buffer 34 | 35 | cred := StaticCredentials{ 36 | "foo": "bar", 37 | } 38 | 39 | cator := UserPassAuthenticator{Credentials: cred} 40 | 41 | s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) 42 | 43 | ctx, err := s.authenticate(&resp, req) 44 | if err != nil { 45 | t.Fatalf("err: %v", err) 46 | } 47 | 48 | if ctx.Method != UserPassAuth { 49 | t.Fatal("Invalid Context Method") 50 | } 51 | 52 | val, ok := ctx.Payload["Username"] 53 | if !ok { 54 | t.Fatal("Missing key Username in auth context's payload") 55 | } 56 | 57 | if val != "foo" { 58 | t.Fatal("Invalid Username in auth context's payload") 59 | } 60 | 61 | out := resp.Bytes() 62 | if !bytes.Equal(out, []byte{socks5Version, UserPassAuth, 1, authSuccess}) { 63 | t.Fatalf("bad: %v", out) 64 | } 65 | } 66 | 67 | func TestPasswordAuth_Invalid(t *testing.T) { 68 | req := bytes.NewBuffer(nil) 69 | req.Write([]byte{2, NoAuth, UserPassAuth}) 70 | req.Write([]byte{1, 3, 'f', 'o', 'o', 3, 'b', 'a', 'z'}) 71 | var resp bytes.Buffer 72 | 73 | cred := StaticCredentials{ 74 | "foo": "bar", 75 | } 76 | cator := UserPassAuthenticator{Credentials: cred} 77 | s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) 78 | 79 | ctx, err := s.authenticate(&resp, req) 80 | if err != UserAuthFailed { 81 | t.Fatalf("err: %v", err) 82 | } 83 | 84 | if ctx != nil { 85 | t.Fatal("Invalid Context Method") 86 | } 87 | 88 | out := resp.Bytes() 89 | if !bytes.Equal(out, []byte{socks5Version, UserPassAuth, 1, authFailure}) { 90 | t.Fatalf("bad: %v", out) 91 | } 92 | } 93 | 94 | func TestNoSupportedAuth(t *testing.T) { 95 | req := bytes.NewBuffer(nil) 96 | req.Write([]byte{1, NoAuth}) 97 | var resp bytes.Buffer 98 | 99 | cred := StaticCredentials{ 100 | "foo": "bar", 101 | } 102 | cator := UserPassAuthenticator{Credentials: cred} 103 | 104 | s, _ := New(&Config{AuthMethods: []Authenticator{cator}}) 105 | 106 | ctx, err := s.authenticate(&resp, req) 107 | if err != NoSupportedAuth { 108 | t.Fatalf("err: %v", err) 109 | } 110 | 111 | if ctx != nil { 112 | t.Fatal("Invalid Context Method") 113 | } 114 | 115 | out := resp.Bytes() 116 | if !bytes.Equal(out, []byte{socks5Version, noAcceptable}) { 117 | t.Fatalf("bad: %v", out) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /x/trojanx/protocol/protocol.go: -------------------------------------------------------------------------------- 1 | package protocol 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "github.com/chainreactors/rem/x/trojanx/internal/pool" 8 | "github.com/pkg/errors" 9 | "io" 10 | "net" 11 | ) 12 | 13 | const ( 14 | LenToken = 56 15 | LenCRLF = 2 16 | LenCommand = 1 17 | LenAddressType = 1 18 | LenIPv4 = 4 19 | LenDomain = 1 20 | LenIPv6 = 16 21 | LenPort = 2 22 | 23 | CommandConnect = 0x01 24 | CommandUDP = 0x03 25 | 26 | AddressTypeIPv4 = 0x01 27 | AddressTypeDomain = 0x03 28 | AddressTypeIPv6 = 0x04 29 | ) 30 | 31 | var ( 32 | CRLF = []byte{'\x0D', '\x0A'} 33 | ) 34 | 35 | func GetToken(conn net.Conn) (string, error) { 36 | buffer := pool.Get() 37 | defer pool.Put(buffer) 38 | if n, err := conn.Read(buffer[:LenToken]); err != nil || n != LenToken { 39 | if err != nil { 40 | return string(buffer[:LenToken]), err 41 | } 42 | return string(buffer[:LenToken]), errors.New("token length error") 43 | } 44 | return string(buffer[:LenToken]), nil 45 | } 46 | 47 | type Request struct { 48 | Command byte 49 | AddressType byte 50 | DescriptionAddress string 51 | DescriptionPort int 52 | } 53 | 54 | func ParseRequest(conn net.Conn) (*Request, error) { 55 | request := &Request{} 56 | buffer := pool.Get() 57 | defer pool.Put(buffer) 58 | if _, err := io.ReadFull(conn, buffer[:LenCRLF]); err != nil { 59 | return nil, err 60 | } 61 | if !bytes.Equal(buffer[:LenCRLF], CRLF) { 62 | return nil, errors.New("not is crlf data") 63 | } 64 | if _, err := io.ReadFull(conn, buffer[:LenCommand]); err != nil { 65 | return nil, err 66 | } 67 | request.Command = buffer[LenCommand-1] 68 | if _, err := io.ReadFull(conn, buffer[:LenAddressType]); err != nil { 69 | return nil, err 70 | } 71 | request.AddressType = buffer[LenAddressType-1] 72 | switch request.AddressType { 73 | case AddressTypeIPv4: 74 | if _, err := io.ReadFull(conn, buffer[:LenIPv4]); err != nil { 75 | return nil, err 76 | } 77 | request.DescriptionAddress = net.IP(buffer[:LenIPv4]).String() 78 | case AddressTypeDomain: 79 | if _, err := io.ReadFull(conn, buffer[:LenDomain]); err != nil { 80 | return nil, err 81 | } 82 | l := buffer[LenDomain-1] 83 | if _, err := io.ReadFull(conn, buffer[:l]); err != nil { 84 | return nil, err 85 | } 86 | request.DescriptionAddress = string(buffer[:l]) 87 | case AddressTypeIPv6: 88 | if _, err := io.ReadFull(conn, buffer[:LenIPv6]); err != nil { 89 | return nil, err 90 | } 91 | request.DescriptionAddress = net.IP(buffer[:LenIPv6]).String() 92 | default: 93 | return nil, fmt.Errorf("unsupported address type %d", request.AddressType) 94 | } 95 | if _, err := io.ReadFull(conn, buffer[:LenPort]); err != nil { 96 | return nil, err 97 | } 98 | request.DescriptionPort = int(binary.BigEndian.Uint16(buffer[:LenPort])) 99 | if _, err := io.ReadFull(conn, buffer[:LenCRLF]); err != nil { 100 | return nil, err 101 | } 102 | if !bytes.Equal(buffer[:LenCRLF], CRLF) { 103 | return nil, errors.New("not is crlf data") 104 | } 105 | return request, nil 106 | } 107 | -------------------------------------------------------------------------------- /protocol/tunnel/websocket/websocket.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "fmt" 7 | "golang.org/x/net/websocket" 8 | "net" 9 | "net/http" 10 | 11 | "github.com/chainreactors/rem/protocol/core" 12 | ) 13 | 14 | func init() { 15 | core.ListenerRegister(core.WebSocketTunnel, func(ctx context.Context) (core.TunnelListener, error) { 16 | return NewWebsocketListener(ctx), nil 17 | }) 18 | core.DialerRegister(core.WebSocketTunnel, func(ctx context.Context) (core.TunnelDialer, error) { 19 | return NewWebsocketDialer(ctx), nil 20 | }) 21 | } 22 | 23 | type WebsocketDialer struct { 24 | net.Conn 25 | meta core.Metas 26 | } 27 | 28 | func NewWebsocketDialer(ctx context.Context) *WebsocketDialer { 29 | return &WebsocketDialer{ 30 | meta: core.GetMetas(ctx), 31 | } 32 | } 33 | 34 | func (c *WebsocketDialer) Dial(dst string) (net.Conn, error) { 35 | u, err := core.NewURL(dst) 36 | if err != nil { 37 | return nil, err 38 | } 39 | c.meta["url"] = u 40 | 41 | scheme := "ws" 42 | if v, ok := c.meta["tls"]; ok && v.(bool) { 43 | scheme = "wss" 44 | } 45 | 46 | conf, err := websocket.NewConfig(fmt.Sprintf("%s://%s/%s", scheme, u.Host, u.PathString()), "http://127.0.0.1") 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | if tlsconf := c.meta["tlsConfig"]; tlsconf != nil { 52 | conf.TlsConfig = tlsconf.(*tls.Config) 53 | } 54 | 55 | conn, err := websocket.DialConfig(conf) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return conn, nil 60 | } 61 | 62 | type WebsocketListener struct { 63 | acceptCh chan *websocket.Conn 64 | server *http.Server 65 | listener net.Listener 66 | meta core.Metas 67 | } 68 | 69 | func NewWebsocketListener(ctx context.Context) *WebsocketListener { 70 | return &WebsocketListener{ 71 | meta: core.GetMetas(ctx), 72 | } 73 | } 74 | 75 | func (c *WebsocketListener) Listen(dst string) (net.Listener, error) { 76 | u, err := core.NewURL(dst) 77 | if err != nil { 78 | return nil, err 79 | } 80 | c.meta["url"] = u 81 | if u.PathString() == "" { 82 | u.Path = "/" + c.meta.GetString("path") 83 | } 84 | ln, err := net.Listen("tcp", u.Host) 85 | if err != nil { 86 | return nil, err 87 | } 88 | c.listener = ln 89 | 90 | c.acceptCh = make(chan *websocket.Conn) 91 | muxer := http.NewServeMux() 92 | muxer.Handle(u.Path, websocket.Handler(func(conn *websocket.Conn) { 93 | notifyCh := make(chan struct{}) 94 | c.acceptCh <- conn 95 | <-notifyCh 96 | })) 97 | 98 | c.server = &http.Server{ 99 | Handler: muxer, 100 | TLSConfig: &tls.Config{ 101 | InsecureSkipVerify: true, 102 | }, 103 | } 104 | go c.server.Serve(ln) 105 | 106 | return c, nil 107 | } 108 | 109 | func (c *WebsocketListener) Accept() (net.Conn, error) { 110 | conn, ok := <-c.acceptCh 111 | if !ok { 112 | return nil, fmt.Errorf("websocket error") 113 | } 114 | return conn, nil 115 | } 116 | 117 | func (c *WebsocketListener) Close() error { 118 | if c.server != nil { 119 | return c.server.Close() 120 | } 121 | return nil 122 | } 123 | 124 | func (c *WebsocketListener) Addr() net.Addr { 125 | return c.meta.URL() 126 | } 127 | -------------------------------------------------------------------------------- /x/utils/aes.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "io" 8 | ) 9 | 10 | // AesStream 实现cipher.Stream接口 11 | type AesStream struct { 12 | block cipher.Block 13 | iv []byte 14 | counter []byte 15 | stream cipher.Stream 16 | } 17 | 18 | // NewAesStream 创建一个新的AES流加密器 19 | func NewAesStream(key [32]byte, iv [16]byte) (cipher.Stream, error) { 20 | block, err := aes.NewCipher(key[:]) 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | stream := cipher.NewCTR(block, iv[:]) 26 | return stream, nil 27 | } 28 | 29 | // AesCtrEncryptor 封装了加密和解密的Stream 30 | type AesCtrEncryptor struct { 31 | key [32]byte 32 | iv [16]byte 33 | stream cipher.Stream 34 | } 35 | 36 | // NewAesCtrEncryptor 创建一个新的AesCtrEncryptor 37 | func NewAesCtrEncryptor(key [32]byte, iv [16]byte) (*AesCtrEncryptor, error) { 38 | block, err := aes.NewCipher(key[:]) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | stream := cipher.NewCTR(block, iv[:]) 44 | return &AesCtrEncryptor{ 45 | key: key, 46 | iv: iv, 47 | stream: stream, 48 | }, nil 49 | } 50 | 51 | // GetStream 获取当前的cipher.Stream实例 52 | func (e *AesCtrEncryptor) GetStream() cipher.Stream { 53 | return e.stream 54 | } 55 | 56 | // Encrypt 使用cipher.StreamWriter进行加密 57 | func (e *AesCtrEncryptor) Encrypt(dst io.Writer, src io.Reader) error { 58 | writer := &cipher.StreamWriter{S: e.stream, W: dst} 59 | _, err := io.Copy(writer, src) 60 | return err 61 | } 62 | 63 | // Decrypt 使用cipher.StreamReader进行解密 64 | func (e *AesCtrEncryptor) Decrypt(dst io.Writer, src io.Reader) error { 65 | reader := &cipher.StreamReader{S: e.stream, R: src} 66 | _, err := io.Copy(dst, reader) 67 | return err 68 | } 69 | 70 | // Reset 重置加密器状态 71 | func (e *AesCtrEncryptor) Reset() error { 72 | block, err := aes.NewCipher(e.key[:]) 73 | if err != nil { 74 | return err 75 | } 76 | e.stream = cipher.NewCTR(block, e.iv[:]) 77 | return nil 78 | } 79 | 80 | func PKCS7Padding(ciphertext []byte, blockSize int) []byte { 81 | padding := blockSize - len(ciphertext)%blockSize 82 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 83 | return append(ciphertext, padtext...) 84 | } 85 | 86 | func PKCS7UnPadding(origData []byte) []byte { 87 | length := len(origData) 88 | unpadding := int(origData[length-1]) 89 | return origData[:(length - unpadding)] 90 | } 91 | 92 | // AES加密,CBC 93 | func AesEncrypt(origData, key []byte) ([]byte, error) { 94 | block, err := aes.NewCipher(key) 95 | if err != nil { 96 | return nil, err 97 | } 98 | blockSize := block.BlockSize() 99 | origData = PKCS7Padding(origData, blockSize) 100 | blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) 101 | crypted := make([]byte, len(origData)) 102 | blockMode.CryptBlocks(crypted, origData) 103 | return crypted, nil 104 | } 105 | 106 | // AES解密 107 | func AesDecrypt(crypted, key []byte) ([]byte, error) { 108 | block, err := aes.NewCipher(key) 109 | if err != nil { 110 | return nil, err 111 | } 112 | blockSize := block.BlockSize() 113 | blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) 114 | origData := make([]byte, len(crypted)) 115 | blockMode.CryptBlocks(origData, crypted) 116 | origData = PKCS7UnPadding(origData) 117 | return origData, nil 118 | } 119 | -------------------------------------------------------------------------------- /protocol/tunnel/memory/memory.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | "net/url" 8 | "sync" 9 | 10 | "github.com/chainreactors/proxyclient" 11 | socksproxy "github.com/chainreactors/proxyclient/socks" 12 | "github.com/chainreactors/rem/protocol/core" 13 | ) 14 | 15 | var ( 16 | globalBridge = NewMemoryBridge() 17 | ) 18 | 19 | func init() { 20 | core.DialerRegister(core.MemoryTunnel, func(ctx context.Context) (core.TunnelDialer, error) { 21 | return &MemoryDialer{meta: core.GetMetas(ctx)}, nil 22 | }) 23 | 24 | core.ListenerRegister(core.MemoryTunnel, func(ctx context.Context) (core.TunnelListener, error) { 25 | return &MemoryListener{meta: core.GetMetas(ctx)}, nil 26 | }) 27 | 28 | // 注册 memory 作为代理协议 29 | proxyclient.RegisterScheme("MEMORY", newMemoryProxyClient) 30 | } 31 | 32 | // 实现 DialFactory 函数 33 | func newMemoryProxyClient(proxyURL *url.URL, upstreamDial proxyclient.Dial) (proxyclient.Dial, error) { 34 | return func(ctx context.Context, network, address string) (net.Conn, error) { 35 | // 首先获取内存通道连接 36 | dialer := &MemoryDialer{meta: make(core.Metas)} 37 | 38 | conf := &socksproxy.SOCKSConf{ 39 | Dial: func(ctx context.Context, _, _ string) (net.Conn, error) { 40 | return dialer.Dial(proxyURL.Host) 41 | }, 42 | } 43 | 44 | client, err := socksproxy.NewClient(&url.URL{Scheme: "socks5"}, conf) 45 | if err != nil { 46 | return nil, err 47 | } 48 | 49 | return client.Dial(ctx, network, address) 50 | }, nil 51 | } 52 | 53 | type MemoryBridge struct { 54 | connMap sync.Map // map[string]chan net.Conn 55 | } 56 | 57 | func NewMemoryBridge() *MemoryBridge { 58 | return &MemoryBridge{} 59 | } 60 | 61 | func (b *MemoryBridge) CreateChannel(id string) chan net.Conn { 62 | ch := make(chan net.Conn, 1) 63 | b.connMap.Store(id, ch) 64 | return ch 65 | } 66 | 67 | func (b *MemoryBridge) GetChannel(id string) (chan net.Conn, error) { 68 | ch, ok := b.connMap.Load(id) 69 | if ok { 70 | return ch.(chan net.Conn), nil 71 | } else { 72 | return nil, fmt.Errorf("not found memory listener") 73 | } 74 | } 75 | 76 | type MemoryDialer struct { 77 | meta core.Metas 78 | } 79 | 80 | type MemoryListener struct { 81 | meta core.Metas 82 | connChan chan net.Conn 83 | } 84 | 85 | // Dialer implementation 86 | func (d *MemoryDialer) Dial(dst string) (net.Conn, error) { 87 | u, err := core.NewURL(dst) 88 | if err != nil { 89 | return nil, err 90 | } 91 | d.meta["url"] = u 92 | 93 | client, server := net.Pipe() 94 | ch, err := globalBridge.GetChannel(u.Hostname()) 95 | if err != nil { 96 | return nil, err 97 | } 98 | ch <- server 99 | 100 | return client, nil 101 | } 102 | 103 | // Listener implementation 104 | func (l *MemoryListener) Listen(dst string) (net.Listener, error) { 105 | u, err := core.NewURL(dst) 106 | if err != nil { 107 | return nil, err 108 | } 109 | l.meta["url"] = u 110 | l.connChan = globalBridge.CreateChannel(u.Hostname()) 111 | return l, nil 112 | } 113 | 114 | func (l *MemoryListener) Accept() (net.Conn, error) { 115 | conn := <-l.connChan 116 | return conn, nil 117 | } 118 | 119 | func (l *MemoryListener) Close() error { 120 | return nil 121 | } 122 | 123 | func (l *MemoryListener) Addr() net.Addr { 124 | return l.meta.URL() 125 | } 126 | -------------------------------------------------------------------------------- /x/kcp/buffer.go: -------------------------------------------------------------------------------- 1 | package kcp 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | // Buffer 是一个线程安全的带大小限制的缓冲区 12 | type Buffer struct { 13 | buf *bytes.Buffer 14 | mu sync.RWMutex 15 | cond *sync.Cond 16 | maxLen int 17 | } 18 | 19 | // NewBuffer 创建一个新的Buffer 20 | func NewBuffer(maxLen int) *Buffer { 21 | b := &Buffer{ 22 | buf: bytes.NewBuffer(nil), 23 | maxLen: maxLen, 24 | } 25 | b.cond = sync.NewCond(&b.mu) 26 | return b 27 | } 28 | 29 | // Write 写入数据,如果缓冲区满则阻塞等待 30 | func (b *Buffer) Write(p []byte) (n int, err error) { 31 | b.mu.Lock() 32 | defer b.mu.Unlock() 33 | 34 | remaining := len(p) 35 | written := 0 36 | 37 | for remaining > 0 { 38 | // 计算当前可写入的空间 39 | availSpace := b.maxLen - b.buf.Len() 40 | if availSpace <= 0 { 41 | // 如果没有可用空间,等待 42 | b.cond.Wait() // Wait会自动释放锁并在返回时重新获取 43 | continue 44 | } 45 | 46 | // 确定本次写入的长度 47 | writeLen := remaining 48 | if writeLen > availSpace { 49 | writeLen = availSpace 50 | } 51 | 52 | n, _ = b.buf.Write(p[written : written+writeLen]) 53 | 54 | written += n 55 | remaining -= n 56 | 57 | b.cond.Signal() 58 | } 59 | 60 | return written, nil 61 | } 62 | 63 | // Read 读取数据,如果没有数据则返回EOF 64 | func (b *Buffer) Read(p []byte) (n int, err error) { 65 | if b.buf.Len() == 0 { 66 | return 0, io.EOF 67 | } 68 | 69 | b.mu.Lock() 70 | n, err = b.buf.Read(p) 71 | if n > 0 { 72 | b.cond.Signal() 73 | } 74 | b.mu.Unlock() 75 | return 76 | } 77 | 78 | // ReadAtLeast 读取数据,如果缓冲区为空则阻塞等待,直到有数据可读 79 | func (b *Buffer) ReadAtLeast(p []byte) (n int, err error) { 80 | b.mu.Lock() 81 | defer b.mu.Unlock() 82 | 83 | // 如果没有数据,等待直到有数据 84 | for b.buf.Len() == 0 { 85 | b.cond.Wait() 86 | } 87 | 88 | n, err = b.buf.Read(p) 89 | if n > 0 { 90 | b.cond.Signal() 91 | } 92 | return 93 | } 94 | 95 | // Close 关闭缓冲区 96 | func (b *Buffer) Close() error { 97 | b.mu.Lock() 98 | b.buf.Reset() 99 | // 关闭时需要唤醒所有等待者 100 | b.cond.Broadcast() 101 | b.mu.Unlock() 102 | return nil 103 | } 104 | 105 | // Size 返回当前缓冲区长度 106 | func (b *Buffer) Size() int { 107 | b.mu.RLock() 108 | defer b.mu.RUnlock() // 这里可以用defer,因为没有Wait操作 109 | return b.buf.Len() 110 | } 111 | 112 | // Cap 返回缓冲区容量 113 | func (b *Buffer) Cap() int { 114 | return b.maxLen 115 | } 116 | 117 | func NewChannel(size int, timeout time.Duration) *ChannelBuffer { 118 | if size == 0 { 119 | return &ChannelBuffer{ 120 | ch: make(chan []byte, 1), 121 | timeout: timeout, 122 | } 123 | } else { 124 | return &ChannelBuffer{ 125 | ch: make(chan []byte, size), 126 | timeout: timeout, 127 | } 128 | } 129 | } 130 | 131 | type ChannelBuffer struct { 132 | ch chan []byte 133 | timeout time.Duration 134 | } 135 | 136 | func (ch *ChannelBuffer) Get() ([]byte, error) { 137 | select { 138 | case data := <-ch.ch: 139 | return data, nil 140 | case <-time.After(ch.timeout): 141 | return nil, fmt.Errorf("timeout") 142 | } 143 | } 144 | 145 | func (ch *ChannelBuffer) Put(data []byte) (int, error) { 146 | select { 147 | case ch.ch <- data: 148 | return len(data), nil 149 | case <-time.After(ch.timeout): 150 | return 0, fmt.Errorf("timeout") 151 | } 152 | } 153 | 154 | func (ch *ChannelBuffer) Close() error { 155 | close(ch.ch) 156 | return nil 157 | } 158 | 159 | func (ch *ChannelBuffer) Len() int { 160 | return len(ch.ch) 161 | } 162 | -------------------------------------------------------------------------------- /protocol/serve/trojan/utils.go: -------------------------------------------------------------------------------- 1 | package trojan 2 | 3 | import ( 4 | "crypto" 5 | "crypto/ecdsa" 6 | "crypto/ed25519" 7 | "crypto/elliptic" 8 | "crypto/rand" 9 | "crypto/rsa" 10 | "crypto/tls" 11 | "crypto/x509" 12 | "crypto/x509/pkix" 13 | "github.com/pkg/errors" 14 | "math/big" 15 | "time" 16 | ) 17 | 18 | // SPDX-FileCopyrightText: 2023 The Pion community 19 | // SPDX-License-Identifier: MIT 20 | 21 | var errInvalidPrivateKey = errors.New("selfsign: invalid private key type") 22 | 23 | // GenerateSelfSigned creates a self-signed certificate 24 | func generateSelfSigned() (tls.Certificate, error) { 25 | priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 26 | if err != nil { 27 | return tls.Certificate{}, err 28 | } 29 | 30 | return SelfSign(priv) 31 | } 32 | 33 | // GenerateSelfSignedWithDNS creates a self-signed certificate 34 | func GenerateSelfSignedWithDNS(cn string, sans ...string) (tls.Certificate, error) { 35 | priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 36 | if err != nil { 37 | return tls.Certificate{}, err 38 | } 39 | 40 | return WithDNS(priv, cn, sans...) 41 | } 42 | 43 | // SelfSign creates a self-signed certificate from a elliptic curve key 44 | func SelfSign(key crypto.PrivateKey) (tls.Certificate, error) { 45 | return WithDNS(key, "self-signed cert") 46 | } 47 | 48 | // WithDNS creates a self-signed certificate from a elliptic curve key 49 | func WithDNS(key crypto.PrivateKey, cn string, sans ...string) (tls.Certificate, error) { 50 | var ( 51 | pubKey crypto.PublicKey 52 | maxBigInt = new(big.Int) // Max random value, a 130-bits integer, i.e 2^130 - 1 53 | ) 54 | 55 | switch k := key.(type) { 56 | case ed25519.PrivateKey: 57 | pubKey = k.Public() 58 | case *ecdsa.PrivateKey: 59 | pubKey = k.Public() 60 | case *rsa.PrivateKey: 61 | pubKey = k.Public() 62 | default: 63 | return tls.Certificate{}, errInvalidPrivateKey 64 | } 65 | 66 | /* #nosec */ 67 | maxBigInt.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxBigInt, big.NewInt(1)) 68 | /* #nosec */ 69 | serialNumber, err := rand.Int(rand.Reader, maxBigInt) 70 | if err != nil { 71 | return tls.Certificate{}, err 72 | } 73 | 74 | names := []string{cn} 75 | names = append(names, sans...) 76 | 77 | keyUsage := x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign 78 | if _, isRSA := key.(*rsa.PrivateKey); isRSA { 79 | keyUsage |= x509.KeyUsageKeyEncipherment 80 | } 81 | 82 | template := x509.Certificate{ 83 | ExtKeyUsage: []x509.ExtKeyUsage{ 84 | x509.ExtKeyUsageClientAuth, 85 | x509.ExtKeyUsageServerAuth, 86 | }, 87 | BasicConstraintsValid: true, 88 | NotBefore: time.Now(), 89 | KeyUsage: keyUsage, 90 | NotAfter: time.Now().AddDate(0, 1, 0), 91 | SerialNumber: serialNumber, 92 | Version: 2, 93 | IsCA: true, 94 | DNSNames: names, 95 | Subject: pkix.Name{ 96 | CommonName: cn, 97 | }, 98 | } 99 | 100 | raw, err := x509.CreateCertificate(rand.Reader, &template, &template, pubKey, key) 101 | if err != nil { 102 | return tls.Certificate{}, err 103 | } 104 | 105 | leaf, err := x509.ParseCertificate(raw) 106 | if err != nil { 107 | return tls.Certificate{}, err 108 | } 109 | 110 | return tls.Certificate{ 111 | Certificate: [][]byte{raw}, 112 | PrivateKey: key, 113 | Leaf: leaf, 114 | }, nil 115 | } 116 | -------------------------------------------------------------------------------- /x/kcp/autotune.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | const maxAutoTuneSamples = 258 26 | 27 | // pulse represents a 0/1 signal with time sequence 28 | type pulse struct { 29 | bit bool // 0 or 1 30 | seq uint32 // sequence of the signal 31 | } 32 | 33 | // autoTune object to detect pulses in a signal 34 | type autoTune struct { 35 | pulses [maxAutoTuneSamples]pulse 36 | } 37 | 38 | // Sample adds a signal sample to the pulse buffer 39 | func (tune *autoTune) Sample(bit bool, seq uint32) { 40 | // ensure seq is in range [pulses[0].seq, pulses[0].seq + maxAutoTuneSamples] 41 | if seq >= tune.pulses[0].seq && seq <= tune.pulses[0].seq+maxAutoTuneSamples { 42 | tune.pulses[seq%maxAutoTuneSamples] = pulse{bit, seq} 43 | } 44 | } 45 | 46 | // Find a period for a given signal 47 | // returns -1 if not found 48 | // 49 | // 50 | // Signal Level 51 | // | 52 | // 1.0 | _____ _____ 53 | // | | | | | 54 | // 0.5 | _____ | | _____ | | _____ 55 | // | | | | | | || | | | 56 | // 0.0 __|_____| |____| |__| || |__| |_____ 57 | // | 58 | // |-----------------------------------------------------> Time 59 | // A B C D E F G H I 60 | 61 | func (tune *autoTune) FindPeriod(bit bool) int { 62 | // last pulse and initial index setup 63 | lastPulse := tune.pulses[0] 64 | idx := 1 65 | 66 | // left edge 67 | var leftEdge int 68 | for ; idx < len(tune.pulses); idx++ { 69 | if lastPulse.bit != bit && tune.pulses[idx].bit == bit { // edge found 70 | if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure edge continuity 71 | leftEdge = idx 72 | break 73 | } 74 | } 75 | lastPulse = tune.pulses[idx] 76 | } 77 | 78 | // right edge 79 | var rightEdge int 80 | lastPulse = tune.pulses[leftEdge] 81 | idx = leftEdge + 1 82 | 83 | for ; idx < len(tune.pulses); idx++ { 84 | if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure pulses in this level monotonic 85 | if lastPulse.bit == bit && tune.pulses[idx].bit != bit { // edge found 86 | rightEdge = idx 87 | break 88 | } 89 | } else { 90 | return -1 91 | } 92 | lastPulse = tune.pulses[idx] 93 | } 94 | 95 | return rightEdge - leftEdge 96 | } 97 | -------------------------------------------------------------------------------- /x/kcp/fec_test.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | import ( 26 | "encoding/binary" 27 | "math/rand" 28 | "testing" 29 | "time" 30 | ) 31 | 32 | func TestFECEncodeConsecutive(t *testing.T) { 33 | const dataSize = 10 34 | const paritySize = 3 35 | const payLoad = 1500 36 | 37 | encoder := newFECEncoder(dataSize, paritySize, 0) 38 | t.Logf("dataSize:%v, paritySize:%v", dataSize, paritySize) 39 | group := 0 40 | sent := 0 41 | for i := 0; i < 100; i++ { 42 | if i%dataSize == 0 { 43 | group++ 44 | } 45 | 46 | data := make([]byte, payLoad) 47 | duration := time.Duration(rand.Int()%300) * time.Millisecond 48 | t.Logf("Sleep: %v, packet %v", duration, sent) 49 | <-time.After(duration) 50 | 51 | ps := encoder.encode(data, 200) 52 | sent++ 53 | 54 | if len(ps) > 0 { 55 | t.Log("has parity:", len(ps)) 56 | for idx, p := range ps { 57 | seqid := binary.LittleEndian.Uint32(p) 58 | expected := uint32((group-1)*(dataSize+paritySize) + dataSize + idx) 59 | if seqid != expected { 60 | t.Fatalf("expected parity shard:%v actual seqid %v", expected, seqid) 61 | } 62 | } 63 | } else if sent%dataSize == 0 { 64 | t.Log("no parity:", len(ps)) 65 | } 66 | } 67 | } 68 | 69 | func BenchmarkFECDecode(b *testing.B) { 70 | const dataSize = 10 71 | const paritySize = 3 72 | const payLoad = 1500 73 | decoder := newFECDecoder(dataSize, paritySize) 74 | b.ReportAllocs() 75 | b.SetBytes(payLoad) 76 | for i := 0; i < b.N; i++ { 77 | if rand.Int()%(dataSize+paritySize) == 0 { // random loss 78 | continue 79 | } 80 | pkt := make([]byte, payLoad) 81 | binary.LittleEndian.PutUint32(pkt, uint32(i)) 82 | if i%(dataSize+paritySize) >= dataSize { 83 | binary.LittleEndian.PutUint16(pkt[4:], typeParity) 84 | } else { 85 | binary.LittleEndian.PutUint16(pkt[4:], typeData) 86 | } 87 | decoder.decode(pkt) 88 | } 89 | } 90 | 91 | func BenchmarkFECEncode(b *testing.B) { 92 | const dataSize = 10 93 | const paritySize = 3 94 | const payLoad = 1500 95 | 96 | b.ReportAllocs() 97 | b.SetBytes(payLoad) 98 | encoder := newFECEncoder(dataSize, paritySize, 0) 99 | for i := 0; i < b.N; i++ { 100 | data := make([]byte, payLoad) 101 | encoder.encode(data, 200) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /x/trojanx/example/selfsign.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2023 The Pion community 2 | // SPDX-License-Identifier: MIT 3 | 4 | // Package selfsign is a test helper that generates self signed certificate. 5 | package main 6 | 7 | import ( 8 | "crypto" 9 | "crypto/ecdsa" 10 | "crypto/ed25519" 11 | "crypto/elliptic" 12 | "crypto/rand" 13 | "crypto/rsa" 14 | "crypto/tls" 15 | "crypto/x509" 16 | "crypto/x509/pkix" 17 | "github.com/pkg/errors" 18 | "math/big" 19 | "time" 20 | ) 21 | 22 | var errInvalidPrivateKey = errors.New("selfsign: invalid private key type") 23 | 24 | // GenerateSelfSigned creates a self-signed certificate 25 | func generateSelfSigned() (tls.Certificate, error) { 26 | priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 27 | if err != nil { 28 | return tls.Certificate{}, err 29 | } 30 | 31 | return SelfSign(priv) 32 | } 33 | 34 | // GenerateSelfSignedWithDNS creates a self-signed certificate 35 | func GenerateSelfSignedWithDNS(cn string, sans ...string) (tls.Certificate, error) { 36 | priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 37 | if err != nil { 38 | return tls.Certificate{}, err 39 | } 40 | 41 | return WithDNS(priv, cn, sans...) 42 | } 43 | 44 | // SelfSign creates a self-signed certificate from a elliptic curve key 45 | func SelfSign(key crypto.PrivateKey) (tls.Certificate, error) { 46 | return WithDNS(key, "self-signed cert") 47 | } 48 | 49 | // WithDNS creates a self-signed certificate from a elliptic curve key 50 | func WithDNS(key crypto.PrivateKey, cn string, sans ...string) (tls.Certificate, error) { 51 | var ( 52 | pubKey crypto.PublicKey 53 | maxBigInt = new(big.Int) // Max random value, a 130-bits integer, i.e 2^130 - 1 54 | ) 55 | 56 | switch k := key.(type) { 57 | case ed25519.PrivateKey: 58 | pubKey = k.Public() 59 | case *ecdsa.PrivateKey: 60 | pubKey = k.Public() 61 | case *rsa.PrivateKey: 62 | pubKey = k.Public() 63 | default: 64 | return tls.Certificate{}, errInvalidPrivateKey 65 | } 66 | 67 | /* #nosec */ 68 | maxBigInt.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxBigInt, big.NewInt(1)) 69 | /* #nosec */ 70 | serialNumber, err := rand.Int(rand.Reader, maxBigInt) 71 | if err != nil { 72 | return tls.Certificate{}, err 73 | } 74 | 75 | names := []string{cn} 76 | names = append(names, sans...) 77 | 78 | keyUsage := x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign 79 | if _, isRSA := key.(*rsa.PrivateKey); isRSA { 80 | keyUsage |= x509.KeyUsageKeyEncipherment 81 | } 82 | 83 | template := x509.Certificate{ 84 | ExtKeyUsage: []x509.ExtKeyUsage{ 85 | x509.ExtKeyUsageClientAuth, 86 | x509.ExtKeyUsageServerAuth, 87 | }, 88 | BasicConstraintsValid: true, 89 | NotBefore: time.Now(), 90 | KeyUsage: keyUsage, 91 | NotAfter: time.Now().AddDate(0, 1, 0), 92 | SerialNumber: serialNumber, 93 | Version: 2, 94 | IsCA: true, 95 | DNSNames: names, 96 | Subject: pkix.Name{ 97 | CommonName: cn, 98 | }, 99 | } 100 | 101 | raw, err := x509.CreateCertificate(rand.Reader, &template, &template, pubKey, key) 102 | if err != nil { 103 | return tls.Certificate{}, err 104 | } 105 | 106 | leaf, err := x509.ParseCertificate(raw) 107 | if err != nil { 108 | return tls.Certificate{}, err 109 | } 110 | 111 | return tls.Certificate{ 112 | Certificate: [][]byte{raw}, 113 | PrivateKey: key, 114 | Leaf: leaf, 115 | }, nil 116 | } 117 | -------------------------------------------------------------------------------- /protocol/core/wrapper.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "io" 7 | "math/rand" 8 | 9 | "github.com/chainreactors/rem/x/utils" 10 | "gopkg.in/yaml.v3" 11 | ) 12 | 13 | var AvailableWrappers []string 14 | 15 | func ParseWrapperOptions(s string, key string) (WrapperOptions, error) { 16 | decodedData, err := base64.StdEncoding.DecodeString(s) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | decryptedData, err := utils.AesDecrypt(decodedData, utils.PKCS7Padding([]byte(key), 16)) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | var options WrapperOptions 27 | err = yaml.Unmarshal(decryptedData, &options) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | return options, nil 33 | } 34 | 35 | type WrapperOptions []*WrapperOption 36 | 37 | func (opts WrapperOptions) String(key string) string { 38 | marshal, err := yaml.Marshal(opts) 39 | if err != nil { 40 | utils.Log.Error(err) 41 | return "" 42 | } 43 | data, err := utils.AesEncrypt(marshal, utils.PKCS7Padding([]byte(key), 16)) 44 | if err != nil { 45 | utils.Log.Error(err) 46 | return "" 47 | } 48 | 49 | return base64.StdEncoding.EncodeToString(data) 50 | } 51 | 52 | // WrapperOption 定义wrapper的基本配置结构 53 | type WrapperOption struct { 54 | Name string `yaml:"name"` 55 | Options map[string]string `yaml:"options"` 56 | } 57 | 58 | // Wrapper 定义了数据包装器的基本接口 59 | type Wrapper interface { 60 | Name() string 61 | io.ReadWriteCloser 62 | } 63 | 64 | // WrapperCreatorFn 是创建wrapper的工厂函数类型 65 | type WrapperCreatorFn func(r io.Reader, w io.Writer, opt map[string]string) (Wrapper, error) 66 | 67 | var wrapperCreators = make(map[string]WrapperCreatorFn) 68 | 69 | // WrapperRegister 注册一个wrapper类型 70 | func WrapperRegister(name string, fn WrapperCreatorFn) { 71 | if _, exist := wrapperCreators[name]; exist { 72 | panic(fmt.Sprintf("wrapper [%s] is already registered", name)) 73 | } 74 | wrapperCreators[name] = fn 75 | } 76 | 77 | // WrapperCreate 创建一个指定类型的wrapper 78 | func WrapperCreate(name string, r io.Reader, w io.Writer, opt map[string]string) (Wrapper, error) { 79 | if fn, ok := wrapperCreators[name]; ok { 80 | return fn(r, w, opt) 81 | } 82 | return nil, fmt.Errorf("wrapper [%s] is not registered", name) 83 | } 84 | 85 | // GenerateRandomWrapperOption 生成单个随机的WrapperOption 86 | func GenerateRandomWrapperOption() *WrapperOption { 87 | name := AvailableWrappers[rand.Intn(len(AvailableWrappers))] 88 | 89 | opt := &WrapperOption{ 90 | Name: name, 91 | Options: make(map[string]string), 92 | } 93 | 94 | switch name { 95 | case AESWrapper: 96 | opt.Options["key"] = utils.RandomString(32) 97 | opt.Options["iv"] = utils.RandomString(16) 98 | case XORWrapper: 99 | opt.Options["key"] = utils.RandomString(32) 100 | opt.Options["iv"] = utils.RandomString(16) 101 | } 102 | 103 | return opt 104 | } 105 | 106 | // GenerateRandomWrapperOptions 生成随机数量、随机组合的Wrapper配置 107 | func GenerateRandomWrapperOptions(minCount, maxCount int) WrapperOptions { 108 | if minCount < 1 { 109 | minCount = 1 110 | } 111 | if maxCount < minCount { 112 | maxCount = minCount 113 | } 114 | 115 | count := minCount 116 | if maxCount > minCount { 117 | count += rand.Intn(maxCount - minCount + 1) 118 | } 119 | 120 | var opts WrapperOptions 121 | for i := 0; i < count; i++ { 122 | opt := GenerateRandomWrapperOption() 123 | opts = append(opts, opt) 124 | } 125 | 126 | rand.Shuffle(len(opts), func(i, j int) { 127 | opts[i], opts[j] = opts[j], opts[i] 128 | }) 129 | 130 | return opts 131 | } 132 | -------------------------------------------------------------------------------- /x/utils/tls.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "crypto/tls" 7 | "crypto/x509" 8 | "crypto/x509/pkix" 9 | "encoding/pem" 10 | "math/big" 11 | "os" 12 | "time" 13 | ) 14 | 15 | func newCustomTLSKeyPair(certfile, keyfile string) (*tls.Certificate, error) { 16 | tlsCert, err := tls.LoadX509KeyPair(certfile, keyfile) 17 | if err != nil { 18 | return nil, err 19 | } 20 | return &tlsCert, nil 21 | } 22 | 23 | func NewRandomTLSKeyPair() *tls.Certificate { 24 | key, err := rsa.GenerateKey(rand.Reader, 2048) 25 | if err != nil { 26 | panic(err) 27 | } 28 | 29 | // 设置证书的有效期 30 | notBefore := time.Now() 31 | notAfter := notBefore.Add(365 * 24 * time.Hour) // 证书有效期为1年 32 | 33 | serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) 34 | if err != nil { 35 | panic(err) 36 | } 37 | 38 | template := x509.Certificate{ 39 | SerialNumber: serialNumber, 40 | Subject: pkix.Name{ 41 | Organization: []string{"Example Organization"}, 42 | CommonName: "example.com", 43 | }, 44 | NotBefore: notBefore, 45 | NotAfter: notAfter, 46 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 47 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 48 | BasicConstraintsValid: true, 49 | } 50 | 51 | certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) 52 | if err != nil { 53 | panic(err) 54 | } 55 | 56 | keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) 57 | certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 58 | 59 | tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) 60 | if err != nil { 61 | panic(err) 62 | } 63 | return &tlsCert 64 | } 65 | 66 | func newCertPool(caPath string) (*x509.CertPool, error) { 67 | pool := x509.NewCertPool() 68 | 69 | caCrt, err := os.ReadFile(caPath) 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | pool.AppendCertsFromPEM(caCrt) 75 | 76 | return pool, nil 77 | } 78 | 79 | func NewServerTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) { 80 | base := &tls.Config{} 81 | 82 | if certPath == "" || keyPath == "" { 83 | // server will generate tls conf by itself 84 | cert := NewRandomTLSKeyPair() 85 | base.Certificates = []tls.Certificate{*cert} 86 | } else { 87 | cert, err := newCustomTLSKeyPair(certPath, keyPath) 88 | if err != nil { 89 | return nil, err 90 | } 91 | 92 | base.Certificates = []tls.Certificate{*cert} 93 | } 94 | 95 | if caPath != "" { 96 | pool, err := newCertPool(caPath) 97 | if err != nil { 98 | return nil, err 99 | } 100 | 101 | base.ClientAuth = tls.RequireAndVerifyClientCert 102 | base.ClientCAs = pool 103 | } 104 | 105 | return base, nil 106 | } 107 | 108 | func NewClientTLSConfig(certPath, keyPath, caPath, serverName string) (*tls.Config, error) { 109 | base := &tls.Config{} 110 | 111 | if certPath != "" && keyPath != "" { 112 | cert, err := newCustomTLSKeyPair(certPath, keyPath) 113 | if err != nil { 114 | return nil, err 115 | } 116 | 117 | base.Certificates = []tls.Certificate{*cert} 118 | } 119 | 120 | base.ServerName = serverName 121 | 122 | if caPath != "" { 123 | pool, err := newCertPool(caPath) 124 | if err != nil { 125 | return nil, err 126 | } 127 | 128 | base.RootCAs = pool 129 | base.InsecureSkipVerify = false 130 | } else { 131 | base.InsecureSkipVerify = true 132 | } 133 | 134 | return base, nil 135 | } 136 | -------------------------------------------------------------------------------- /protocol/wrapper/websocket.go: -------------------------------------------------------------------------------- 1 | package wrapper 2 | 3 | //func NewWebsocketWrapper(opt map[string]string) *WebsocketWrapper { 4 | // return &WebsocketWrapper{ 5 | // firstClientHeader: []byte(fmt.Sprintf("GET / HTTP/1.1\r\nHost: %s\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: vAh876rpLu6p92ksdGbInQ==\r\nOrigin: http://%s\r\nSec-WebSocket-Version: 13\r\n\r\n", opt["host"], opt["host"])), 6 | // firstServerHeader: []byte("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: opR2RscMuMKa7DBr+NTinftdxTg=\r\n\r\n"), 7 | // clientHeader: []byte("\x81\x8c\x77\x7b\x49\xdd"), 8 | // } 9 | //} 10 | // 11 | //type WebsocketWrapper struct { 12 | // clientHeader []byte 13 | // serverHeader []byte 14 | // firstClientHeader []byte 15 | // firstServerHeader []byte 16 | //} 17 | // 18 | //func (w *WebsocketWrapper) headerSize(isClient bool) int { 19 | // if isClient { 20 | // return len(w.firstClientHeader) + greetLength 21 | // } else { 22 | // return len(w.firstServerHeader) + greetLength 23 | // } 24 | //} 25 | // 26 | //func (w *WebsocketWrapper) headerStr(isClient bool) []byte { 27 | // if isClient { 28 | // return w.firstClientHeader 29 | // } else { 30 | // return w.firstServerHeader 31 | // } 32 | //} 33 | // 34 | //func (w *WebsocketWrapper) Name() string { 35 | // return "websocket" 36 | //} 37 | // 38 | //func (w *WebsocketWrapper) Wrap(data []byte) ([]byte, error) { 39 | // return data, nil 40 | //} 41 | // 42 | //func (w *WebsocketWrapper) UnWrap(data []byte) ([]byte, error) { 43 | // return data, nil 44 | //} 45 | // 46 | //func (w *WebsocketWrapper) ReadGreet(conn net.Conn) (int8, uint32, error) { 47 | // var greet []byte 48 | // header := make([]byte, 5) 49 | // n, err := io.ReadFull(conn, header) 50 | // if err != nil { 51 | // return 0, 0, err 52 | // } 53 | // if bytes.Equal([]byte("HTTP/"), header) || bytes.Equal([]byte("GET /"), header) { 54 | // reader, err := readWithStop(conn, []byte{'\r', '\n', '\r', '\n'}) 55 | // if err != nil { 56 | // return 0, 0, err 57 | // } 58 | // utils.Log.Logf(consts.DUMPLog, "[read.greet] %v", append(header, reader...)) 59 | // greet = make([]byte, greetLength) 60 | // n, err = io.ReadFull(conn, greet) 61 | // if err != nil || n != greetLength { 62 | // return 0, 0, err 63 | // } 64 | // } else { 65 | // greet = header 66 | // } 67 | // return int8(greet[0]), uint32(binary.LittleEndian.Uint32(greet[1:])), nil 68 | //} 69 | // 70 | //func (w *WebsocketWrapper) GenGreet(msgtype int8, length uint32, isClient bool) []byte { 71 | // var reader bytes.Buffer 72 | // if msgtype == int8(message.LoginRespMsg) || msgtype == int8(message.LoginReqMsg) { 73 | // reader.Write(w.headerStr(isClient)) 74 | // } 75 | // reader.WriteByte(byte(msgtype)) 76 | // l := make([]byte, 4) 77 | // binary.LittleEndian.PutUint32(l, length) 78 | // reader.Write(l) 79 | // return reader.Bytes() 80 | //} 81 | // 82 | //func readWithStop(conn io.Reader, stop []byte) ([]byte, error) { 83 | // var err error 84 | // var n int 85 | // length := len(stop) 86 | // stopSigh := make([]byte, length) 87 | // ch := make([]byte, 1) 88 | // var reader bytes.Buffer 89 | // for { 90 | // n, err = conn.Read(ch) 91 | // if err != nil { 92 | // return nil, err 93 | // } 94 | // if n == 1 { 95 | // reader.Write(ch) 96 | // if length == 1 { 97 | // stopSigh = ch 98 | // } else { 99 | // for j := 0; j <= length-2; j++ { 100 | // stopSigh[j] = stopSigh[j+1] 101 | // } 102 | // stopSigh[length-1] = ch[0] 103 | // } 104 | // if bytes.Equal(stop, stopSigh) { 105 | // return reader.Bytes(), nil 106 | // } 107 | // } 108 | // } 109 | //} 110 | -------------------------------------------------------------------------------- /protocol/core/tunnel.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "fmt" 7 | "net" 8 | ) 9 | 10 | type TunnelDialer interface { 11 | Dial(dst string) (net.Conn, error) 12 | } 13 | 14 | type WrappedDialer struct { 15 | TunnelDialer 16 | Dialer func(string) (net.Conn, error) 17 | } 18 | 19 | func (w *WrappedDialer) Dial(dst string) (net.Conn, error) { 20 | if w.Dialer != nil { 21 | return w.Dialer(dst) 22 | } 23 | return w.Dial(dst) 24 | } 25 | 26 | type TunnelListener interface { 27 | net.Listener 28 | Listen(dst string) (net.Listener, error) 29 | } 30 | 31 | type WrappedListener struct { 32 | TunnelListener 33 | Lns net.Listener 34 | } 35 | 36 | func (w *WrappedListener) Accept() (net.Conn, error) { 37 | if w.Lns != nil { 38 | return w.Lns.Accept() 39 | } 40 | return w.Accept() 41 | } 42 | 43 | // DialerCreatorFn 是创建 dialer 的工厂函数 44 | type DialerCreatorFn func(ctx context.Context) (TunnelDialer, error) 45 | 46 | // ListenerCreatorFn 是创建 listener 的工厂函数 47 | type ListenerCreatorFn func(ctx context.Context) (TunnelListener, error) 48 | 49 | var ( 50 | dialerCreators = make(map[string]DialerCreatorFn) 51 | listenerCreators = make(map[string]ListenerCreatorFn) 52 | ) 53 | 54 | // DialerRegister 注册一个 dialer 类型 55 | func DialerRegister(name string, fn DialerCreatorFn) { 56 | if _, exist := dialerCreators[name]; exist { 57 | panic(fmt.Sprintf("dialer [%s] is already registered", name)) 58 | } 59 | dialerCreators[name] = fn 60 | } 61 | 62 | // ListenerRegister 注册一个 listener 类型 63 | func ListenerRegister(name string, fn ListenerCreatorFn) { 64 | if _, exist := listenerCreators[name]; exist { 65 | panic(fmt.Sprintf("listener [%s] is already registered", name)) 66 | } 67 | listenerCreators[name] = fn 68 | } 69 | 70 | // DialerCreate 创建一个指定类型的 dialer 71 | func DialerCreate(name string, ctx context.Context) (TunnelDialer, error) { 72 | if fn, ok := dialerCreators[name]; ok { 73 | return fn(ctx) 74 | } 75 | return nil, fmt.Errorf("dialer [%s] is not registered", name) 76 | } 77 | 78 | // ListenerCreate 创建一个指定类型的 listener 79 | func ListenerCreate(name string, ctx context.Context) (TunnelListener, error) { 80 | if fn, ok := listenerCreators[name]; ok { 81 | return fn(ctx) 82 | } 83 | return nil, fmt.Errorf("listener [%s] is not registered", name) 84 | } 85 | 86 | func GetMetas(ctx context.Context) Metas { 87 | if m, ok := ctx.Value("meta").(Metas); ok { 88 | return m 89 | } 90 | return nil 91 | } 92 | 93 | type Metas map[string]interface{} 94 | 95 | func (m Metas) Value(key string) interface{} { 96 | return m[key] 97 | } 98 | 99 | func (m Metas) GetString(key string) string { 100 | v, ok := m[key] 101 | if ok { 102 | s, ok := v.(string) 103 | if ok { 104 | return s 105 | } 106 | return "" 107 | } 108 | return "" 109 | } 110 | func (m Metas) URL() *URL { 111 | return m["url"].(*URL) 112 | } 113 | 114 | func (m Metas) TLSConfig() *tls.Config { 115 | if v, ok := m["tls"]; ok { 116 | return v.(*tls.Config) 117 | } 118 | return nil 119 | } 120 | 121 | type BeforeHook struct { 122 | DialHook func(ctx context.Context, addr string) context.Context 123 | AcceptHook func(ctx context.Context) context.Context 124 | ListenHook func(ctx context.Context, addr string) context.Context 125 | } 126 | 127 | type AfterHookFunc func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) 128 | 129 | type AfterHook struct { 130 | Priority uint 131 | DialerHook func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) 132 | AcceptHook func(ctx context.Context, c net.Conn) (context.Context, net.Conn, error) 133 | ListenHook func(ctx context.Context, listener net.Listener) (context.Context, net.Listener, error) 134 | } 135 | -------------------------------------------------------------------------------- /protocol/message/msg.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "fmt" 5 | "github.com/chainreactors/rem/x/utils" 6 | "google.golang.org/protobuf/proto" 7 | ) 8 | 9 | // MsgType 定义消息类型 10 | type MsgType int8 11 | 12 | // 定义消息状态常量 13 | const ( 14 | StatusFailed = 0 15 | StatusSuccess = 1 16 | ) 17 | 18 | // 定义消息类型常量 19 | const ( 20 | LoginMsg MsgType = iota + 1 21 | AckMsg 22 | ControlMsg 23 | PingMsg 24 | PongMsg 25 | PacketMsg 26 | ConnStartMsg 27 | ConnEndMsg 28 | RedirectMsg 29 | End 30 | ) 31 | 32 | // 定义标准错误类型 33 | var ( 34 | ErrEmptyMessage = fmt.Errorf("empty message") 35 | ErrInvalidType = fmt.Errorf("invalid message type") 36 | ErrUnknownType = fmt.Errorf("unknown message type") 37 | ErrMarshal = fmt.Errorf("marshal error") 38 | ErrUnmarshal = fmt.Errorf("unmarshal error") 39 | ErrTypeMismatch = fmt.Errorf("message type mismatch") 40 | ErrMessageLength = fmt.Errorf("message length error") 41 | ErrInvalidStatus = fmt.Errorf("invalid message status") 42 | ErrConnectionError = fmt.Errorf("connection error") 43 | ) 44 | 45 | // msgRegistry 存储消息类型到消息创建函数的映射 46 | var msgRegistry = map[MsgType]func() proto.Message{ 47 | LoginMsg: func() proto.Message { return &Login{} }, 48 | AckMsg: func() proto.Message { return &Ack{} }, 49 | ControlMsg: func() proto.Message { return &Control{} }, 50 | PingMsg: func() proto.Message { return &Ping{} }, 51 | PongMsg: func() proto.Message { return &Pong{} }, 52 | PacketMsg: func() proto.Message { return &Packet{} }, 53 | ConnStartMsg: func() proto.Message { return &ConnStart{} }, 54 | ConnEndMsg: func() proto.Message { 55 | return &ConnEnd{} 56 | }, 57 | RedirectMsg: func() proto.Message { return &Redirect{} }, 58 | } 59 | 60 | // NewMessage 根据消息类型创建新的消息实例 61 | func NewMessage(msgType MsgType) proto.Message { 62 | if creator, ok := msgRegistry[msgType]; ok { 63 | return creator() 64 | } 65 | return nil 66 | } 67 | 68 | // ValidateMessageType 验证消息类型是否有效 69 | func ValidateMessageType(msgType MsgType) bool { 70 | return msgType > 0 && msgType < End 71 | } 72 | 73 | // WrapError 包装错误信息 74 | func WrapError(err error, format string, args ...interface{}) error { 75 | if err == nil { 76 | return nil 77 | } 78 | return fmt.Errorf("%w: "+format, append([]interface{}{err}, args...)...) 79 | } 80 | 81 | // GetMessageType 根据消息实例获取消息类型 82 | func GetMessageType(msg proto.Message) MsgType { 83 | if msg == nil { 84 | return 0 85 | } 86 | 87 | switch msg.(type) { 88 | case *Login: 89 | return LoginMsg 90 | case *Ack: 91 | return AckMsg 92 | case *Control: 93 | return ControlMsg 94 | case *Ping: 95 | return PingMsg 96 | case *Pong: 97 | return PongMsg 98 | case *Packet: 99 | return PacketMsg 100 | case *ConnStart: 101 | return ConnStartMsg 102 | case *ConnEnd: 103 | return ConnEndMsg 104 | case *Redirect: 105 | return RedirectMsg 106 | default: 107 | return 0 108 | } 109 | } 110 | 111 | func Wrap(src, dst string, m proto.Message) *Redirect { 112 | msg := &Redirect{ 113 | Source: src, 114 | Destination: dst, 115 | } 116 | switch m.(type) { 117 | case *Packet: 118 | msg.Msg = &Redirect_Packet{Packet: m.(*Packet)} 119 | case *ConnStart: 120 | msg.Msg = &Redirect_Start{Start: m.(*ConnStart)} 121 | case *ConnEnd: 122 | msg.Msg = &Redirect_End{End: m.(*ConnEnd)} 123 | default: 124 | utils.Log.Error(ErrInvalidType) 125 | } 126 | return msg 127 | } 128 | 129 | func Unwrap(m *Redirect) proto.Message { 130 | var msg proto.Message 131 | switch m.GetMsg().(type) { 132 | case *Redirect_Packet: 133 | msg = m.GetPacket() 134 | case *Redirect_Start: 135 | msg = m.GetStart() 136 | case *Redirect_End: 137 | msg = m.GetEnd() 138 | default: 139 | utils.Log.Error(ErrInvalidType) 140 | } 141 | return msg 142 | } 143 | -------------------------------------------------------------------------------- /protocol/serve/trojan/trojan.go: -------------------------------------------------------------------------------- 1 | package trojan 2 | 3 | import ( 4 | "crypto/tls" 5 | log "github.com/sirupsen/logrus" 6 | "io" 7 | "net" 8 | "os" 9 | 10 | "github.com/chainreactors/rem/protocol/cio" 11 | "github.com/chainreactors/rem/protocol/core" 12 | "github.com/chainreactors/rem/x/socks5" 13 | "github.com/chainreactors/rem/x/trojanx" 14 | "github.com/chainreactors/rem/x/trojanx/protocol" 15 | "github.com/chainreactors/rem/x/utils" 16 | ) 17 | 18 | func init() { 19 | core.InboundRegister(core.TrojanServe, NewTrojanInbound) 20 | core.OutboundRegister(core.TrojanServe, NewTrojanOutbound) 21 | } 22 | 23 | func NewTrojanOutbound(options map[string]string, dial core.ContextDialer) (core.Outbound, error) { 24 | pwd := options["password"] 25 | config := &trojanx.TrojanConfig{ 26 | Password: pwd, 27 | } 28 | server := trojanx.NewServer( 29 | trojanx.WithConfig(config), 30 | trojanx.WithLogger(&log.Logger{ 31 | Level: log.WarnLevel, 32 | ReportCaller: true, 33 | Out: os.Stdout, 34 | }), 35 | trojanx.WithDial(dial.DialContext), 36 | ) 37 | base := core.NewPluginOption(options, core.OutboundPlugin, core.TrojanServe) 38 | utils.Log.Importantf("[agent.outbound] trojan serving: %s, %s", base.String(), base.URL()) 39 | return &TrojanPlugin{Server: server, PluginOption: base}, nil 40 | } 41 | 42 | func NewTrojanInbound(options map[string]string) (core.Inbound, error) { 43 | pwd := options["password"] 44 | config := &trojanx.TrojanConfig{ 45 | Password: pwd, 46 | } 47 | server := trojanx.NewServer( 48 | trojanx.WithConfig(config), 49 | trojanx.WithLogger(&log.Logger{ 50 | Level: log.WarnLevel, 51 | ReportCaller: true, 52 | Out: os.Stdout, 53 | }), 54 | ) 55 | base := core.NewPluginOption(options, core.InboundPlugin, core.TrojanServe) 56 | utils.Log.Importantf("[agent.inbound] trojan serving: %s , %s", base.String(), base.URL()) 57 | return &TrojanPlugin{Server: server, PluginOption: base}, nil 58 | } 59 | 60 | type TrojanPlugin struct { 61 | Server *trojanx.Server 62 | *core.PluginOption 63 | } 64 | 65 | func (plug *TrojanPlugin) genSelfSign() []tls.Certificate { 66 | signed, _ := generateSelfSigned() 67 | var tlsCertificates []tls.Certificate 68 | tlsCertificates = append(tlsCertificates, signed) 69 | return tlsCertificates 70 | } 71 | 72 | func (plug *TrojanPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn) (net.Conn, error) { 73 | defer conn.Close() 74 | wrapConn := cio.WrapConn(realConn, conn) 75 | server := tls.Server(wrapConn, &tls.Config{ 76 | Certificates: plug.genSelfSign(), 77 | }) 78 | plug.Server.ServeConn(server) 79 | return nil, nil 80 | } 81 | 82 | func (plug *TrojanPlugin) Relay(conn net.Conn, bridge io.ReadWriteCloser) (net.Conn, error) { 83 | signed, _ := generateSelfSigned() 84 | var tlsCertificates []tls.Certificate 85 | tlsCertificates = append(tlsCertificates, signed) 86 | tlsConn := tls.Server(conn, &tls.Config{ 87 | Certificates: tlsCertificates, 88 | }) 89 | req, err := plug.Server.ParseRequest(tlsConn) 90 | if err != nil { 91 | return nil, err 92 | } 93 | 94 | dest := &socks5.AddrSpec{Port: req.DescriptionPort} 95 | switch req.AddressType { 96 | case protocol.AddressTypeIPv6, protocol.AddressTypeIPv4: 97 | dest.IP = net.ParseIP(req.DescriptionAddress) 98 | case protocol.AddressTypeDomain: 99 | dest.FQDN = req.DescriptionAddress 100 | } 101 | relayReq := &socks5.RelayRequest{ 102 | DestAddr: dest, 103 | } 104 | 105 | _, err = bridge.Write(relayReq.BuildRelay()) 106 | if err != nil { 107 | return nil, err 108 | } 109 | 110 | _, _, err = socks5.ReadReply(bridge) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | return tlsConn, nil 116 | } 117 | 118 | func (plug *TrojanPlugin) Name() string { 119 | return core.TrojanServe 120 | } 121 | -------------------------------------------------------------------------------- /protocol/serve/externalc2/externalc2.go: -------------------------------------------------------------------------------- 1 | package externalc2 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | "net" 8 | 9 | "github.com/chainreactors/rem/protocol/core" 10 | "github.com/chainreactors/rem/x/utils" 11 | ) 12 | 13 | // Warnning! this is demo for CobaltStrike external C2 impl 14 | func init() { 15 | core.OutboundRegister(core.CobaltStrikeServe, NewExternalC2Outbound) 16 | core.InboundRegister(core.CobaltStrikeServe, NewExternalC2Inbound) 17 | } 18 | 19 | type ExternalC2Plugin struct { 20 | *core.PluginOption 21 | dial core.ContextDialer 22 | Dest string 23 | } 24 | 25 | // Frame 表示ExternalC2的帧格式 26 | type Frame struct { 27 | Length uint32 28 | Data []byte 29 | } 30 | 31 | // ReadFrame 从io.Reader读取一个帧 32 | func ReadFrame(r io.Reader) (*Frame, error) { 33 | var length uint32 34 | if err := binary.Read(r, binary.LittleEndian, &length); err != nil { 35 | return nil, err 36 | } 37 | 38 | data := make([]byte, length) 39 | if _, err := io.ReadFull(r, data); err != nil { 40 | return nil, err 41 | } 42 | 43 | return &Frame{Length: length, Data: data}, nil 44 | } 45 | 46 | // WriteFrame 将帧写入io.Writer 47 | func WriteFrame(w io.Writer, data []byte) error { 48 | length := uint32(len(data)) 49 | if err := binary.Write(w, binary.LittleEndian, length); err != nil { 50 | return err 51 | } 52 | _, err := w.Write(data) 53 | return err 54 | } 55 | 56 | type Config struct { 57 | Arch string 58 | Pipename string 59 | Block string 60 | } 61 | 62 | func (c *Config) GetStager(w io.ReadWriter) ([]byte, error) { 63 | err := WriteFrame(w, []byte("arch="+c.Arch)) 64 | if err != nil { 65 | return nil, err 66 | } 67 | err = WriteFrame(w, []byte("pipename="+c.Pipename)) 68 | if err != nil { 69 | return nil, err 70 | } 71 | err = WriteFrame(w, []byte("block="+c.Block)) 72 | if err != nil { 73 | return nil, err 74 | } 75 | err = WriteFrame(w, []byte("go")) 76 | if err != nil { 77 | return nil, err 78 | } 79 | stager, err := ReadFrame(w) 80 | if err != nil { 81 | return nil, err 82 | } 83 | return stager.Data, nil 84 | } 85 | 86 | func (ep *ExternalC2Plugin) Handle(conn io.ReadWriteCloser, realConn net.Conn) (net.Conn, error) { 87 | // 连接到Cobalt Strike的External C2服务器 88 | remote, err := ep.dial.Dial("tcp", ep.Dest) 89 | if err != nil { 90 | return nil, fmt.Errorf("failed to connect to External C2 server: %v", err) 91 | } 92 | 93 | // 读取配置选项 94 | config := &Config{ 95 | Arch: "x64", 96 | Pipename: "foobar", 97 | Block: "500", 98 | } 99 | stager, err := config.GetStager(remote) 100 | if err != nil { 101 | remote.Close() 102 | return nil, err 103 | } 104 | 105 | if err := WriteFrame(conn, stager); err != nil { 106 | remote.Close() 107 | return nil, fmt.Errorf("failed to write payload stage: %v", err) 108 | } 109 | 110 | return remote, nil 111 | } 112 | 113 | func (ep *ExternalC2Plugin) Relay(conn net.Conn, bridge io.ReadWriteCloser) (net.Conn, error) { 114 | return conn, nil 115 | } 116 | 117 | func NewExternalC2Inbound(params map[string]string) (core.Inbound, error) { 118 | dest, ok := params["dest"] 119 | if !ok { 120 | return nil, fmt.Errorf("dest not found") 121 | } 122 | 123 | base := core.NewPluginOption(params, core.InboundPlugin, core.CobaltStrikeServe) 124 | utils.Log.Importantf("[agent.inbound] ExternalC2 serving: %s -> %s", params["src"], dest) 125 | return &ExternalC2Plugin{ 126 | PluginOption: base, 127 | Dest: dest, 128 | }, nil 129 | } 130 | 131 | func NewExternalC2Outbound(params map[string]string, dial core.ContextDialer) (core.Outbound, error) { 132 | dest, ok := params["dest"] 133 | if !ok { 134 | return nil, fmt.Errorf("dest not found") 135 | } 136 | 137 | base := core.NewPluginOption(params, core.OutboundPlugin, core.CobaltStrikeServe) 138 | utils.Log.Importantf("[agent.outbound] ExternalC2 serving: %s -> %s", dest, params["src"]) 139 | return &ExternalC2Plugin{ 140 | PluginOption: base, 141 | dial: dial, 142 | Dest: dest, 143 | }, nil 144 | } 145 | 146 | func (ep *ExternalC2Plugin) Name() string { 147 | return core.CobaltStrikeServe 148 | } 149 | -------------------------------------------------------------------------------- /protocol/cio/buffer.go: -------------------------------------------------------------------------------- 1 | package cio 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "sync" 7 | "sync/atomic" 8 | ) 9 | 10 | var ( 11 | bufPool16k sync.Pool 12 | bufPool5k sync.Pool 13 | bufPool2k sync.Pool 14 | bufPool1k sync.Pool 15 | bufPool sync.Pool 16 | ) 17 | 18 | func GetBuf(size int) []byte { 19 | var x interface{} 20 | if size >= 16*1024 { 21 | x = bufPool16k.Get() 22 | } else if size >= 5*1024 { 23 | x = bufPool5k.Get() 24 | } else if size >= 2*1024 { 25 | x = bufPool2k.Get() 26 | } else if size >= 1*1024 { 27 | x = bufPool1k.Get() 28 | } else { 29 | x = bufPool.Get() 30 | } 31 | if x == nil { 32 | return make([]byte, size) 33 | } 34 | buf := x.([]byte) 35 | if cap(buf) < size { 36 | return make([]byte, size) 37 | } 38 | return buf[:size] 39 | } 40 | 41 | func PutBuf(buf []byte) { 42 | size := cap(buf) 43 | if size >= 16*1024 { 44 | bufPool16k.Put(buf) 45 | } else if size >= 5*1024 { 46 | bufPool5k.Put(buf) 47 | } else if size >= 2*1024 { 48 | bufPool2k.Put(buf) 49 | } else if size >= 1*1024 { 50 | bufPool1k.Put(buf) 51 | } else { 52 | bufPool.Put(buf) 53 | } 54 | } 55 | 56 | // Buffer is a non-thread-safe buffer with pipe 57 | type Buffer struct { 58 | curSize int64 59 | WriteCount int64 60 | ReadCount int64 61 | dataCh chan []byte 62 | pipeR *io.PipeReader 63 | pipeW *io.PipeWriter 64 | ctx context.Context 65 | cancel context.CancelFunc 66 | maxBuf int 67 | chunkSize int 68 | closed int32 // 0 表示 false, 1 表示 true 69 | } 70 | 71 | func NewBuffer(maxBufSize int) *Buffer { 72 | return NewBufferContext(context.Background(), maxBufSize) 73 | } 74 | 75 | func NewBufferContext(ctx context.Context, maxBufSize int) *Buffer { 76 | pipeR, pipeW := io.Pipe() 77 | ctx, cancel := context.WithCancel(ctx) 78 | bp := &Buffer{ 79 | dataCh: make(chan []byte, 1024), 80 | pipeR: pipeR, 81 | pipeW: pipeW, 82 | ctx: ctx, 83 | cancel: cancel, 84 | maxBuf: maxBufSize, 85 | chunkSize: maxBufSize / 10, 86 | } 87 | go bp.processLoop() 88 | return bp 89 | } 90 | 91 | func (bp *Buffer) processLoop() { 92 | defer bp.pipeW.Close() 93 | 94 | for { 95 | select { 96 | case <-bp.ctx.Done(): 97 | return 98 | case data := <-bp.dataCh: 99 | n, err := bp.pipeW.Write(data) 100 | if n > 0 { 101 | bp.curSize -= int64(n) 102 | } 103 | PutBuf(data) 104 | if err != nil { 105 | continue 106 | } 107 | } 108 | } 109 | } 110 | 111 | func (bp *Buffer) Write(p []byte) (n int, err error) { 112 | if atomic.LoadInt32(&bp.closed) == 1 { 113 | return 0, io.ErrClosedPipe 114 | } 115 | 116 | bp.WriteCount += int64(len(p)) 117 | 118 | if len(p) > bp.chunkSize { 119 | n, err = bp.writeChunks(p) 120 | if err != nil { 121 | return n, err 122 | } 123 | return n, nil 124 | } else { 125 | data := GetBuf(len(p)) 126 | copy(data, p) 127 | 128 | err = bp.writeOne(data) 129 | if err != nil { 130 | PutBuf(data) 131 | return 0, err 132 | } 133 | 134 | bp.curSize += int64(len(p)) 135 | return len(p), nil 136 | } 137 | } 138 | 139 | func (bp *Buffer) writeChunks(p []byte) (n int, err error) { 140 | total := len(p) 141 | for i := 0; i < total; i += bp.chunkSize { 142 | end := i + bp.chunkSize 143 | if end > total { 144 | end = total 145 | } 146 | 147 | chunk := GetBuf(end - i) 148 | copy(chunk, p[i:end]) 149 | 150 | if err := bp.writeOne(chunk); err != nil { 151 | PutBuf(chunk) 152 | return i, err 153 | } 154 | bp.curSize += int64(end - i) 155 | } 156 | return total, nil 157 | } 158 | 159 | func (bp *Buffer) writeOne(p []byte) error { 160 | select { 161 | case bp.dataCh <- p: 162 | return nil 163 | case <-bp.ctx.Done(): 164 | return io.ErrClosedPipe 165 | } 166 | } 167 | 168 | func (bp *Buffer) Read(p []byte) (n int, err error) { 169 | if atomic.LoadInt32(&bp.closed) == 1 { 170 | return 0, io.ErrClosedPipe 171 | } 172 | n, err = bp.pipeR.Read(p) 173 | if n > 0 { 174 | bp.ReadCount += int64(n) 175 | } 176 | return 177 | } 178 | 179 | func (bp *Buffer) Close() error { 180 | if atomic.CompareAndSwapInt32(&bp.closed, 0, 1) { 181 | close(bp.dataCh) 182 | bp.cancel() 183 | } 184 | return nil 185 | } 186 | 187 | func (bp *Buffer) Size() int { 188 | return int(bp.curSize) 189 | } 190 | -------------------------------------------------------------------------------- /x/kcp/readloop_linux.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | //go:build linux 24 | // +build linux 25 | 26 | package kcp 27 | 28 | import ( 29 | "net" 30 | "os" 31 | "sync/atomic" 32 | 33 | "github.com/pkg/errors" 34 | "golang.org/x/net/ipv4" 35 | "golang.org/x/net/ipv6" 36 | ) 37 | 38 | // readLoop is the optimized version of readLoop for linux utilizing recvmmsg syscall 39 | func (s *KCPSession) readLoop() { 40 | // default version 41 | if s.xconn == nil { 42 | s.defaultReadLoop() 43 | return 44 | } 45 | 46 | // x/net version 47 | var src string 48 | msgs := make([]ipv4.Message, batchSize) 49 | for k := range msgs { 50 | msgs[k].Buffers = [][]byte{make([]byte, mtuLimit)} 51 | } 52 | 53 | for { 54 | if count, err := s.xconn.ReadBatch(msgs, 0); err == nil { 55 | for i := 0; i < count; i++ { 56 | msg := &msgs[i] 57 | // make sure the packet is from the same source 58 | if src == "" { // set source address if nil 59 | src = msg.Addr.String() 60 | } else if msg.Addr.String() != src { 61 | atomic.AddUint64(&DefaultSnmp.InErrs, 1) 62 | continue 63 | } 64 | 65 | // source and size has validated 66 | s.packetInput(msg.Buffers[0][:msg.N]) 67 | } 68 | } else { 69 | // compatibility issue: 70 | // for linux kernel<=2.6.32, support for sendmmsg is not available 71 | // an error of type os.SyscallError will be returned 72 | if operr, ok := err.(*net.OpError); ok { 73 | if se, ok := operr.Err.(*os.SyscallError); ok { 74 | if se.Syscall == "recvmmsg" { 75 | s.defaultReadLoop() 76 | return 77 | } 78 | } 79 | } 80 | s.notifyReadError(errors.WithStack(err)) 81 | return 82 | } 83 | } 84 | } 85 | 86 | // monitor is the optimized version of monitor for linux utilizing recvmmsg syscall 87 | func (l *Listener) monitor() { 88 | var xconn batchConn 89 | if _, ok := l.conn.(*net.UDPConn); ok { 90 | addr, err := net.ResolveUDPAddr("udp", l.conn.LocalAddr().String()) 91 | if err == nil { 92 | if addr.IP.To4() != nil { 93 | xconn = ipv4.NewPacketConn(l.conn) 94 | } else { 95 | xconn = ipv6.NewPacketConn(l.conn) 96 | } 97 | } 98 | } 99 | 100 | // default version 101 | if xconn == nil { 102 | l.defaultMonitor() 103 | return 104 | } 105 | 106 | // x/net version 107 | msgs := make([]ipv4.Message, batchSize) 108 | for k := range msgs { 109 | msgs[k].Buffers = [][]byte{make([]byte, mtuLimit)} 110 | } 111 | 112 | for { 113 | if count, err := xconn.ReadBatch(msgs, 0); err == nil { 114 | for i := 0; i < count; i++ { 115 | msg := &msgs[i] 116 | l.packetInput(msg.Buffers[0][:msg.N], msg.Addr) 117 | } 118 | } else { 119 | // compatibility issue: 120 | // for linux kernel<=2.6.32, support for sendmmsg is not available 121 | // an error of type os.SyscallError will be returned 122 | if operr, ok := err.(*net.OpError); ok { 123 | if se, ok := operr.Err.(*os.SyscallError); ok { 124 | if se.Syscall == "recvmmsg" { 125 | l.defaultMonitor() 126 | return 127 | } 128 | } 129 | } 130 | l.notifyReadError(errors.WithStack(err)) 131 | return 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /protocol/cio/conn.go: -------------------------------------------------------------------------------- 1 | package cio 2 | 3 | import ( 4 | "context" 5 | "github.com/chainreactors/rem/x/utils" 6 | "io" 7 | "net" 8 | "sync" 9 | "sync/atomic" 10 | ) 11 | 12 | func JoinWithError(c1 io.ReadWriteCloser, c2 io.ReadWriteCloser) (inCount int64, outCount int64, errors []error) { 13 | var wait sync.WaitGroup 14 | recordErrs := make([]error, 2) 15 | pipe := func(number int, to io.ReadWriteCloser, from io.ReadWriteCloser, count *int64) { 16 | defer func() { 17 | wait.Done() 18 | to.Close() 19 | from.Close() 20 | }() 21 | buf := GetBuf(16 * 1024) 22 | defer PutBuf(buf) 23 | *count, recordErrs[number] = io.CopyBuffer(to, from, buf) 24 | } 25 | 26 | wait.Add(2) 27 | go pipe(0, c1, c2, &inCount) 28 | go pipe(1, c2, c1, &outCount) 29 | wait.Wait() 30 | 31 | for _, e := range recordErrs { 32 | if e != nil { 33 | errors = append(errors, e) 34 | } 35 | } 36 | return 37 | } 38 | 39 | // Join two io.ReadWriteCloser and do some operations. 40 | func Join(c1 io.ReadWriteCloser, c2 io.ReadWriteCloser) (inCount int64, outCount int64) { 41 | var wait sync.WaitGroup 42 | pipe := func(to io.ReadWriteCloser, from io.ReadWriteCloser, count *int64) { 43 | defer func() { 44 | to.Close() 45 | from.Close() 46 | wait.Done() 47 | }() 48 | 49 | buf := GetBuf(16 * 1024) 50 | defer PutBuf(buf) 51 | var err error 52 | *count, err = io.CopyBuffer(to, from, buf) 53 | if err != nil { 54 | utils.Log.Debug(err) 55 | } 56 | } 57 | 58 | wait.Add(2) 59 | go pipe(c1, c2, &inCount) 60 | go pipe(c2, c1, &outCount) 61 | wait.Wait() 62 | return 63 | } 64 | 65 | // closeFn will be called only once 66 | func WrapConn(conn net.Conn, rwc io.ReadWriteCloser) net.Conn { 67 | return &WrappedConn{ 68 | rwc: rwc, 69 | Conn: conn, 70 | } 71 | } 72 | 73 | type WrappedConn struct { 74 | rwc io.ReadWriteCloser 75 | net.Conn 76 | } 77 | 78 | func (conn *WrappedConn) Read(p []byte) (n int, err error) { 79 | return conn.rwc.Read(p) 80 | } 81 | 82 | func (conn *WrappedConn) Write(p []byte) (n int, err error) { 83 | return conn.rwc.Write(p) 84 | } 85 | 86 | func (conn *WrappedConn) Close() error { 87 | return conn.rwc.Close() 88 | } 89 | 90 | type ReadWriteCloser struct { 91 | r io.Reader 92 | w io.Writer 93 | closeFn func() error 94 | 95 | closed bool 96 | mu sync.Mutex 97 | } 98 | 99 | func WrapReadWriteCloser(r io.Reader, w io.Writer, closeFn func() error) io.ReadWriteCloser { 100 | return &ReadWriteCloser{ 101 | r: r, 102 | w: w, 103 | closeFn: closeFn, 104 | closed: false, 105 | } 106 | } 107 | 108 | func (rwc *ReadWriteCloser) Read(p []byte) (n int, err error) { 109 | return rwc.r.Read(p) 110 | } 111 | 112 | func (rwc *ReadWriteCloser) Write(p []byte) (n int, err error) { 113 | return rwc.w.Write(p) 114 | } 115 | 116 | func (rwc *ReadWriteCloser) Close() error { 117 | rwc.mu.Lock() 118 | if rwc.closed { 119 | rwc.mu.Unlock() 120 | return nil 121 | } 122 | rwc.closed = true 123 | rwc.mu.Unlock() 124 | 125 | if rwc.closeFn != nil { 126 | return rwc.closeFn() 127 | } 128 | return nil 129 | } 130 | 131 | // LimitedConn 限速连接 132 | type LimitedConn struct { 133 | net.Conn 134 | ReadCount int64 135 | WriteCount int64 136 | } 137 | 138 | func NewLimitedConn(conn net.Conn) *LimitedConn { 139 | return &LimitedConn{ 140 | Conn: conn, 141 | } 142 | } 143 | 144 | func (l *LimitedConn) Read(p []byte) (n int, err error) { 145 | if !GlobalLimiter.IsReadEnabled() { 146 | n, err = l.Conn.Read(p) 147 | if n > 0 { 148 | GlobalLimiter.readCount += int64(n) 149 | atomic.AddInt64(&l.ReadCount, int64(n)) 150 | } 151 | return 152 | } 153 | 154 | n, err = l.Conn.Read(p) 155 | if n > 0 { 156 | if err := GlobalLimiter.readLimiter.WaitN(context.Background(), n); err != nil { 157 | return n, err 158 | } 159 | GlobalLimiter.readCount += int64(n) 160 | atomic.AddInt64(&l.ReadCount, int64(n)) 161 | } 162 | return 163 | } 164 | 165 | func (l *LimitedConn) Write(p []byte) (n int, err error) { 166 | if !GlobalLimiter.IsWriteEnabled() { 167 | n, err = l.Conn.Write(p) 168 | if n > 0 { 169 | GlobalLimiter.writeCount += int64(n) 170 | atomic.AddInt64(&l.WriteCount, int64(n)) 171 | } 172 | return 173 | } 174 | 175 | n, err = l.Conn.Write(p) 176 | if n > 0 { 177 | if err := GlobalLimiter.writeLimiter.WaitN(context.Background(), n); err != nil { 178 | return n, err 179 | } 180 | GlobalLimiter.writeCount += int64(n) 181 | atomic.AddInt64(&l.WriteCount, int64(n)) 182 | } 183 | return 184 | } 185 | -------------------------------------------------------------------------------- /protocol/cio/io.go: -------------------------------------------------------------------------------- 1 | package cio 2 | 3 | import ( 4 | "encoding/binary" 5 | "google.golang.org/protobuf/proto" 6 | "io" 7 | "net" 8 | 9 | "github.com/chainreactors/rem/protocol/core" 10 | "github.com/chainreactors/rem/protocol/message" 11 | "github.com/chainreactors/rem/x/utils" 12 | ) 13 | 14 | func unpack(bs []byte, mType message.MsgType) (proto.Message, error) { 15 | if len(bs) == 0 { 16 | return nil, message.ErrEmptyMessage 17 | } 18 | 19 | if !message.ValidateMessageType(mType) { 20 | return nil, message.WrapError(message.ErrInvalidType, "type: %d", mType) 21 | } 22 | 23 | msg := message.NewMessage(mType) 24 | if msg == nil { 25 | return nil, message.WrapError(message.ErrUnknownType, "type: %d", mType) 26 | } 27 | 28 | if err := proto.Unmarshal(bs, msg); err != nil { 29 | return nil, message.WrapError(message.ErrUnmarshal, err.Error()) 30 | } 31 | return msg, nil 32 | } 33 | 34 | func pack(msg proto.Message) ([]byte, error) { 35 | msgType := message.GetMessageType(msg) 36 | if msgType == 0 { 37 | return nil, message.ErrInvalidType 38 | } 39 | 40 | content, err := proto.Marshal(msg) 41 | if err != nil { 42 | return nil, message.WrapError(message.ErrMarshal, err.Error()) 43 | } 44 | 45 | buf := GetBuf(1 + 4 + len(content)) 46 | buf[0] = byte(msgType) 47 | binary.LittleEndian.PutUint32(buf[1:5], uint32(len(content))) 48 | copy(buf[5:], content) 49 | return buf, nil 50 | } 51 | 52 | func WriteMsg(conn net.Conn, msg proto.Message) error { 53 | packedmsg, err := pack(msg) 54 | if err != nil { 55 | utils.Log.Debugf("pack error, %s", err.Error()) 56 | return err 57 | } 58 | utils.Log.Logf(utils.IOLog, "[write] %s to %s, %d bytes\n", 59 | conn.LocalAddr().String(), conn.RemoteAddr().String(), len(packedmsg)) 60 | utils.Log.Logf(utils.DUMPLog, "[write] %v", packedmsg) 61 | n, err := conn.Write(packedmsg) 62 | if n != len(packedmsg) { 63 | utils.Log.Debugf("write error, %s", err.Error()) 64 | return message.WrapError(message.ErrConnectionError, 65 | "write %d bytes, expected %d bytes", n, len(packedmsg)) 66 | } 67 | return err 68 | } 69 | 70 | func ReadMsg(conn net.Conn) (proto.Message, error) { 71 | header := GetBuf(5) 72 | defer PutBuf(header) 73 | 74 | _, err := io.ReadFull(conn, header) 75 | if err != nil { 76 | utils.Log.Logf(utils.IOLog, "[read] %s from %s: read greet error, %s\n", 77 | conn.RemoteAddr().String(), conn.LocalAddr().String(), err.Error()) 78 | return nil, message.WrapError(message.ErrConnectionError, err.Error()) 79 | } 80 | 81 | mtype := message.MsgType(header[0]) 82 | if int(mtype) >= int(message.End) { 83 | return nil, message.WrapError(message.ErrInvalidType, 84 | "invalid message type %d", header[0]) 85 | } 86 | 87 | length := binary.LittleEndian.Uint32(header[1:5]) 88 | if int(length) > core.MaxPacketSize { 89 | return nil, message.WrapError(message.ErrMessageLength, 90 | "message length %d exceeds max size %d", length, core.MaxPacketSize) 91 | } 92 | 93 | utils.Log.Logf(utils.IOLog, "[read] %s from %s, %d bytes \n", 94 | conn.RemoteAddr().String(), conn.LocalAddr().String(), length) 95 | 96 | bs := GetBuf(int(length)) 97 | defer PutBuf(bs) 98 | 99 | n, err := io.ReadFull(conn, bs) 100 | if err != nil { 101 | return nil, message.WrapError(message.ErrConnectionError, err.Error()) 102 | } 103 | if n != int(length) { 104 | return nil, message.WrapError(message.ErrMessageLength, 105 | "expected %d, got %d", length, n) 106 | } 107 | 108 | msg, err := unpack(bs, mtype) 109 | if err != nil { 110 | return nil, err 111 | } 112 | 113 | utils.Log.Logf(utils.DUMPLog, "[read] %v", bs) 114 | return msg, nil 115 | } 116 | 117 | func ReadAndAssertMsg(conn net.Conn, expect message.MsgType) (proto.Message, error) { 118 | msg, err := ReadMsg(conn) 119 | if err != nil { 120 | return nil, err 121 | } 122 | 123 | actualType := message.GetMessageType(msg) 124 | if actualType != expect { 125 | return nil, message.WrapError(message.ErrTypeMismatch, 126 | "expected type %d, got %d", expect, actualType) 127 | } 128 | return msg, nil 129 | } 130 | 131 | func WriteAndAssertMsg(conn net.Conn, msg proto.Message) (*message.Ack, error) { 132 | err := WriteMsg(conn, msg) 133 | if err != nil { 134 | return nil, err 135 | } 136 | 137 | ackMsg, err := ReadAndAssertMsg(conn, message.AckMsg) 138 | if err != nil { 139 | return nil, err 140 | } 141 | 142 | ack := ackMsg.(*message.Ack) 143 | if ack.Status != message.StatusSuccess { 144 | return nil, message.WrapError(message.ErrInvalidStatus, ack.Error) 145 | } 146 | return ack, nil 147 | } 148 | -------------------------------------------------------------------------------- /x/trojanx/internal/common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "github.com/pkg/errors" 7 | "io" 8 | "net" 9 | "strconv" 10 | ) 11 | 12 | const ( 13 | IPv4 AddressType = 1 14 | DomainName AddressType = 3 15 | IPv6 AddressType = 4 16 | MaxPacketSize = 1024 * 8 17 | ) 18 | 19 | type AddressType byte 20 | 21 | type Address struct { 22 | DomainName string 23 | Port int 24 | NetworkType string 25 | net.IP 26 | AddressType 27 | } 28 | 29 | type PacketConn interface { 30 | net.PacketConn 31 | WriteWithMetadata([]byte, *Address) (int, error) 32 | ReadWithMetadata([]byte) (int, *Address, error) 33 | } 34 | 35 | func NewAddressFromAddr(network string, addr string) (*Address, error) { 36 | host, portStr, err := net.SplitHostPort(addr) 37 | port, err := strconv.ParseInt(portStr, 10, 32) 38 | if err != nil { 39 | return nil, err 40 | } 41 | return NewAddressFromHostPort(network, host, int(port)), nil 42 | } 43 | 44 | func NewAddressFromHostPort(network string, host string, port int) *Address { 45 | if ip := net.ParseIP(host); ip != nil { 46 | if ip.To4() != nil { 47 | return &Address{ 48 | IP: ip, 49 | Port: port, 50 | AddressType: IPv4, 51 | NetworkType: network, 52 | } 53 | } 54 | return &Address{ 55 | IP: ip, 56 | Port: port, 57 | AddressType: IPv6, 58 | NetworkType: network, 59 | } 60 | } 61 | return &Address{ 62 | DomainName: host, 63 | Port: port, 64 | AddressType: DomainName, 65 | NetworkType: network, 66 | } 67 | } 68 | 69 | func (a *Address) String() string { 70 | switch a.AddressType { 71 | case IPv4: 72 | return fmt.Sprintf("%s:%d", a.IP.String(), a.Port) 73 | case IPv6: 74 | return fmt.Sprintf("[%s]:%d", a.IP.String(), a.Port) 75 | case DomainName: 76 | return fmt.Sprintf("%s:%d", a.DomainName, a.Port) 77 | default: 78 | return "INVALID_ADDRESS_TYPE" 79 | } 80 | } 81 | 82 | func (a *Address) Network() string { 83 | return a.NetworkType 84 | } 85 | 86 | func (a *Address) ResolveIP() (net.IP, error) { 87 | if a.AddressType == IPv4 || a.AddressType == IPv6 { 88 | return a.IP, nil 89 | } 90 | if a.IP != nil { 91 | return a.IP, nil 92 | } 93 | addr, err := net.ResolveIPAddr("ip", a.DomainName) 94 | if err != nil { 95 | return nil, err 96 | } 97 | a.IP = addr.IP 98 | return addr.IP, nil 99 | } 100 | 101 | func (a *Address) ReadFrom(r io.Reader) error { 102 | byteBuf := [1]byte{} 103 | _, err := io.ReadFull(r, byteBuf[:]) 104 | if err != nil { 105 | return errors.New("unable to read ATYP") 106 | } 107 | a.AddressType = AddressType(byteBuf[0]) 108 | switch a.AddressType { 109 | case IPv4: 110 | var buf [6]byte 111 | _, err := io.ReadFull(r, buf[:]) 112 | if err != nil { 113 | return errors.New("failed to read IPv4") 114 | } 115 | a.IP = buf[0:4] 116 | a.Port = int(binary.BigEndian.Uint16(buf[4:6])) 117 | case IPv6: 118 | var buf [18]byte 119 | _, err := io.ReadFull(r, buf[:]) 120 | if err != nil { 121 | return errors.New("failed to read IPv6") 122 | } 123 | a.IP = buf[0:16] 124 | a.Port = int(binary.BigEndian.Uint16(buf[16:18])) 125 | case DomainName: 126 | _, err := io.ReadFull(r, byteBuf[:]) 127 | length := byteBuf[0] 128 | if err != nil { 129 | return errors.New("failed to read domain name length") 130 | } 131 | buf := make([]byte, length+2) 132 | _, err = io.ReadFull(r, buf) 133 | if err != nil { 134 | return errors.New("failed to read domain name") 135 | } 136 | // the fucking browser uses IP as a domain name sometimes 137 | host := buf[0:length] 138 | if ip := net.ParseIP(string(host)); ip != nil { 139 | a.IP = ip 140 | if ip.To4() != nil { 141 | a.AddressType = IPv4 142 | } else { 143 | a.AddressType = IPv6 144 | } 145 | } else { 146 | a.DomainName = string(host) 147 | } 148 | a.Port = int(binary.BigEndian.Uint16(buf[length : length+2])) 149 | default: 150 | return errors.New("invalid ATYP " + strconv.FormatInt(int64(a.AddressType), 10)) 151 | } 152 | return nil 153 | } 154 | 155 | func (a *Address) WriteTo(w io.Writer) error { 156 | _, err := w.Write([]byte{byte(a.AddressType)}) 157 | if err != nil { 158 | return err 159 | } 160 | switch a.AddressType { 161 | case DomainName: 162 | w.Write([]byte{byte(len(a.DomainName))}) 163 | _, err = w.Write([]byte(a.DomainName)) 164 | case IPv4: 165 | _, err = w.Write(a.IP.To4()) 166 | case IPv6: 167 | _, err = w.Write(a.IP.To16()) 168 | default: 169 | return errors.New("invalid ATYP " + strconv.FormatInt(int64(a.AddressType), 10)) 170 | } 171 | if err != nil { 172 | return err 173 | } 174 | port := [2]byte{} 175 | binary.BigEndian.PutUint16(port[:], uint16(a.Port)) 176 | _, err = w.Write(port[:]) 177 | return err 178 | } 179 | -------------------------------------------------------------------------------- /x/kcp/kcp_test.go: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 xtaci 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package kcp 24 | 25 | import ( 26 | "io" 27 | "net" 28 | "sync" 29 | "testing" 30 | "time" 31 | 32 | "github.com/xtaci/lossyconn" 33 | ) 34 | 35 | const repeat = 16 36 | 37 | func TestLossyConn1(t *testing.T) { 38 | t.Log("testing loss rate 10%, rtt 200ms") 39 | t.Log("testing link with nodelay parameters:1 10 2 1") 40 | client, err := lossyconn.NewLossyConn(0.1, 100) 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | 45 | server, err := lossyconn.NewLossyConn(0.1, 100) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | testlink(t, client, server, 1, 10, 2, 1) 50 | } 51 | 52 | func TestLossyConn2(t *testing.T) { 53 | t.Log("testing loss rate 20%, rtt 200ms") 54 | t.Log("testing link with nodelay parameters:1 10 2 1") 55 | client, err := lossyconn.NewLossyConn(0.2, 100) 56 | if err != nil { 57 | t.Fatal(err) 58 | } 59 | 60 | server, err := lossyconn.NewLossyConn(0.2, 100) 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | testlink(t, client, server, 1, 10, 2, 1) 65 | } 66 | 67 | func TestLossyConn3(t *testing.T) { 68 | t.Log("testing loss rate 30%, rtt 200ms") 69 | t.Log("testing link with nodelay parameters:1 10 2 1") 70 | client, err := lossyconn.NewLossyConn(0.3, 100) 71 | if err != nil { 72 | t.Fatal(err) 73 | } 74 | 75 | server, err := lossyconn.NewLossyConn(0.3, 100) 76 | if err != nil { 77 | t.Fatal(err) 78 | } 79 | testlink(t, client, server, 1, 10, 2, 1) 80 | } 81 | 82 | func TestLossyConn4(t *testing.T) { 83 | t.Log("testing loss rate 10%, rtt 200ms") 84 | t.Log("testing link with nodelay parameters:1 10 2 0") 85 | client, err := lossyconn.NewLossyConn(0.1, 100) 86 | if err != nil { 87 | t.Fatal(err) 88 | } 89 | 90 | server, err := lossyconn.NewLossyConn(0.1, 100) 91 | if err != nil { 92 | t.Fatal(err) 93 | } 94 | testlink(t, client, server, 1, 10, 2, 0) 95 | } 96 | 97 | func testlink(t *testing.T, client *lossyconn.LossyConn, server *lossyconn.LossyConn, nodelay, interval, resend, nc int) { 98 | t.Log("testing with nodelay parameters:", nodelay, interval, resend, nc) 99 | sess, _ := NewConn2(server.LocalAddr(), nil, 0, 0, client) 100 | listener, _ := ServeConn(nil, 0, 0, server) 101 | echoServer := func(l *Listener) { 102 | for { 103 | conn, err := l.AcceptKCP() 104 | if err != nil { 105 | return 106 | } 107 | go func() { 108 | conn.SetNoDelay(nodelay, interval, resend, nc) 109 | buf := make([]byte, 65536) 110 | for { 111 | n, err := conn.Read(buf) 112 | if err != nil { 113 | return 114 | } 115 | conn.Write(buf[:n]) 116 | } 117 | }() 118 | } 119 | } 120 | 121 | echoTester := func(s *KCPSession, raddr net.Addr) { 122 | s.SetNoDelay(nodelay, interval, resend, nc) 123 | buf := make([]byte, 64) 124 | var rtt time.Duration 125 | for i := 0; i < repeat; i++ { 126 | start := time.Now() 127 | s.Write(buf) 128 | io.ReadFull(s, buf) 129 | rtt += time.Since(start) 130 | } 131 | 132 | t.Log("client:", client) 133 | t.Log("server:", server) 134 | t.Log("avg rtt:", rtt/repeat) 135 | t.Logf("total time: %v for %v round trip:", rtt, repeat) 136 | } 137 | 138 | go echoServer(listener) 139 | echoTester(sess, server.LocalAddr()) 140 | } 141 | 142 | func BenchmarkFlush(b *testing.B) { 143 | kcp := NewKCP(1, func(buf []byte, size int) {}) 144 | kcp.snd_buf = make([]segment, 1024) 145 | for k := range kcp.snd_buf { 146 | kcp.snd_buf[k].xmit = 1 147 | kcp.snd_buf[k].resendts = currentMs() + 10000 148 | } 149 | b.ResetTimer() 150 | b.ReportAllocs() 151 | var mu sync.Mutex 152 | for i := 0; i < b.N; i++ { 153 | mu.Lock() 154 | kcp.flush(false) 155 | mu.Unlock() 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*.*.*" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | goreleaser: 11 | runs-on: ubuntu-22.04 12 | environment: release 13 | env: 14 | EDITION: ${{ vars.EDITION || 'community' }} 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | token: ${{ secrets.GITHUB_TOKEN }} 21 | submodules: recursive 22 | 23 | - name: Install dependencies 24 | run: | 25 | sudo dpkg --add-architecture i386 26 | sudo apt-get update 27 | sudo apt-get install -y \ 28 | gcc-multilib \ 29 | g++-multilib \ 30 | libc6-dev-i386 \ 31 | upx \ 32 | zip \ 33 | mingw-w64 \ 34 | gcc-mingw-w64-i686 \ 35 | gcc-mingw-w64-x86-64 36 | 37 | - name: Set up GCC 38 | uses: egor-tensin/setup-gcc@v1 39 | with: 40 | version: latest 41 | platform: x64 42 | 43 | - name: Set up Go 44 | uses: actions/setup-go@v3 45 | with: 46 | go-version: 1.18 47 | 48 | - name: Run GoReleaser 49 | uses: goreleaser/goreleaser-action@v4 50 | with: 51 | distribution: goreleaser 52 | version: latest 53 | args: release 54 | env: 55 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 56 | GOPATH: "/home/runner/go" 57 | 58 | - name: Build Libraries 59 | run: | 60 | mkdir -p dist/lib 61 | 62 | # Windows DLL (64-bit) 63 | echo "Building Windows x64 DLL..." 64 | CGO_ENABLED=1 \ 65 | GOOS=windows \ 66 | GOARCH=amd64 \ 67 | CC=x86_64-w64-mingw32-gcc \ 68 | go build -buildmode=c-shared \ 69 | -o dist/lib/rem_${EDITION}_windows_amd64.dll \ 70 | -ldflags "-s -w -X 'github.com/chainreactors/rem/cmd/cmd.ver=${{ github.ref_name }}'" \ 71 | -buildvcs=false ./cmd/export/ 72 | 73 | # Windows DLL (32-bit) 74 | echo "Building Windows x86 DLL..." 75 | CGO_ENABLED=1 \ 76 | GOOS=windows \ 77 | GOARCH=386 \ 78 | CC=i686-w64-mingw32-gcc \ 79 | go build -buildmode=c-shared \ 80 | -o dist/lib/rem_${EDITION}_windows_386.dll \ 81 | -ldflags "-s -w -X 'github.com/chainreactors/rem/cmd/cmd.ver=${{ github.ref_name }}'" \ 82 | -buildvcs=false ./cmd/export/ 83 | 84 | # Linux .so (64-bit) 85 | echo "Building Linux x64 SO..." 86 | CGO_ENABLED=1 \ 87 | GOOS=linux \ 88 | GOARCH=amd64 \ 89 | go build -buildmode=c-shared \ 90 | -o dist/lib/rem_${EDITION}_linux_amd64.so \ 91 | -ldflags "-s -w -X 'github.com/chainreactors/rem/cmd/cmd.ver=${{ github.ref_name }}'" \ 92 | -buildvcs=false ./cmd/export/ 93 | 94 | # Linux .so (32-bit) 95 | echo "Building Linux x86 SO..." 96 | CGO_ENABLED=1 \ 97 | GOOS=linux \ 98 | GOARCH=386 \ 99 | PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig \ 100 | go build -buildmode=c-shared \ 101 | -o dist/lib/rem_${EDITION}_linux_386.so \ 102 | -ldflags "-s -w -X 'github.com/chainreactors/rem/cmd/cmd.ver=${{ github.ref_name }}'" \ 103 | -buildvcs=false ./cmd/export/ 104 | 105 | # Static Libraries (.a) 106 | echo "Building Linux x64 Static Library..." 107 | CGO_ENABLED=1 \ 108 | GOOS=linux \ 109 | GOARCH=amd64 \ 110 | go build -buildmode=c-archive \ 111 | -o dist/lib/librem_${EDITION}_linux_amd64.a \ 112 | -ldflags "-s -w -X 'github.com/chainreactors/rem/cmd/cmd.ver=${{ github.ref_name }}'" \ 113 | -buildvcs=false ./cmd/export/ 114 | 115 | echo "Building Windows x64 Static Library..." 116 | CGO_ENABLED=1 \ 117 | GOOS=windows \ 118 | GOARCH=amd64 \ 119 | CC=x86_64-w64-mingw32-gcc \ 120 | go build -buildmode=c-archive \ 121 | -o dist/lib/librem_${EDITION}_windows_amd64.a \ 122 | -ldflags "-s -w -X 'github.com/chainreactors/rem/cmd/cmd.ver=${{ github.ref_name }}'" \ 123 | -buildvcs=false ./cmd/export/ 124 | 125 | - name: Zip files 126 | run: | 127 | zip -r -j dist/rem_archive.zip dist/rem* 128 | zip -r dist/rem_lib.zip dist/lib/ -x "*.h" 129 | 130 | - name: Upload binaries to release 131 | uses: svenstaro/upload-release-action@v2 132 | with: 133 | repo_token: ${{ secrets.GITHUB_TOKEN }} 134 | file: dist/rem* 135 | tag: ${{ github.ref }} 136 | overwrite: true 137 | file_glob: true 138 | draft: true 139 | -------------------------------------------------------------------------------- /x/socks5/auth.go: -------------------------------------------------------------------------------- 1 | package socks5 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | const ( 9 | NoAuth = uint8(0) 10 | noAcceptable = uint8(255) 11 | UserPassAuth = uint8(2) 12 | RelaAuth = uint8(3) 13 | userAuthVersion = uint8(1) 14 | authSuccess = uint8(0) 15 | authFailure = uint8(1) 16 | ) 17 | 18 | var ( 19 | UserAuthFailed = fmt.Errorf("User authentication failed") 20 | NoSupportedAuth = fmt.Errorf("No supported authentication mechanism") 21 | ) 22 | 23 | // A Request encapsulates authentication state provided 24 | // during negotiation 25 | type AuthContext struct { 26 | // Provided auth method 27 | Method uint8 28 | // Payload provided during negotiation. 29 | // Keys depend on the used auth method. 30 | // For UserPassauth contains Username 31 | Payload map[string]string 32 | } 33 | 34 | type Authenticator interface { 35 | Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) 36 | GetCode() uint8 37 | } 38 | 39 | // NoAuthAuthenticator is used to handle the "No Authentication" mode 40 | type NoAuthAuthenticator struct{} 41 | 42 | func (a NoAuthAuthenticator) GetCode() uint8 { 43 | return NoAuth 44 | } 45 | 46 | func (a NoAuthAuthenticator) Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) { 47 | _, err := writer.Write([]byte{socks5Version, NoAuth}) 48 | return &AuthContext{NoAuth, nil}, err 49 | } 50 | 51 | // UserPassAuthenticator is used to handle username/password based 52 | // authentication 53 | type UserPassAuthenticator struct { 54 | Credentials CredentialStore 55 | } 56 | 57 | func (a UserPassAuthenticator) GetCode() uint8 { 58 | return UserPassAuth 59 | } 60 | 61 | func (a UserPassAuthenticator) Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) { 62 | // Tell the client to use user/pass auth 63 | if _, err := writer.Write([]byte{socks5Version, UserPassAuth}); err != nil { 64 | return nil, err 65 | } 66 | 67 | // Get the version and username length 68 | header := []byte{0, 0} 69 | if _, err := io.ReadAtLeast(reader, header, 2); err != nil { 70 | return nil, err 71 | } 72 | 73 | // Ensure we are compatible 74 | if header[0] != userAuthVersion { 75 | return nil, fmt.Errorf("Unsupported auth version: %v", header[0]) 76 | } 77 | 78 | // Get the user name 79 | userLen := int(header[1]) 80 | user := make([]byte, userLen) 81 | if _, err := io.ReadAtLeast(reader, user, userLen); err != nil { 82 | return nil, err 83 | } 84 | 85 | // Get the password length 86 | if _, err := reader.Read(header[:1]); err != nil { 87 | return nil, err 88 | } 89 | 90 | // Get the password 91 | passLen := int(header[0]) 92 | pass := make([]byte, passLen) 93 | if _, err := io.ReadAtLeast(reader, pass, passLen); err != nil { 94 | return nil, err 95 | } 96 | 97 | // Verify the password 98 | if a.Credentials.Valid(string(user), string(pass)) { 99 | if _, err := writer.Write([]byte{userAuthVersion, authSuccess}); err != nil { 100 | return nil, err 101 | } 102 | } else { 103 | if _, err := writer.Write([]byte{userAuthVersion, authFailure}); err != nil { 104 | return nil, err 105 | } 106 | return nil, UserAuthFailed 107 | } 108 | 109 | // Done 110 | return &AuthContext{UserPassAuth, map[string]string{"Username": string(user), "Password": string(pass)}}, nil 111 | } 112 | 113 | type RelayAuthenticator struct{} 114 | 115 | func (a RelayAuthenticator) GetCode() uint8 { 116 | return RelaAuth 117 | } 118 | 119 | func (a RelayAuthenticator) Authenticate(reader io.Reader, writer io.Writer) (*AuthContext, error) { 120 | return &AuthContext{RelaAuth, nil}, nil 121 | } 122 | 123 | // authenticate is used to handle connection authentication 124 | func (s *Server) authenticate(conn io.Writer, bufConn io.Reader) (*AuthContext, error) { 125 | // Get the methods 126 | methods, err := readMethods(bufConn) 127 | if err != nil { 128 | return nil, fmt.Errorf("Failed to get auth methods: %v", err) 129 | } 130 | 131 | // Select a usable method 132 | for _, method := range methods { 133 | cator, found := s.authMethods[method] 134 | if found { 135 | return cator.Authenticate(bufConn, conn) 136 | } 137 | } 138 | 139 | // No usable method found 140 | return nil, noAcceptableAuth(conn) 141 | } 142 | 143 | // noAcceptableAuth is used to handle when we have no eligible 144 | // authentication mechanism 145 | func noAcceptableAuth(conn io.Writer) error { 146 | conn.Write([]byte{socks5Version, noAcceptable}) 147 | return NoSupportedAuth 148 | } 149 | 150 | // readMethods is used to read the number of methods 151 | // and proceeding auth methods 152 | func readMethods(r io.Reader) ([]byte, error) { 153 | header := []byte{0} 154 | if _, err := r.Read(header); err != nil { 155 | return nil, err 156 | } 157 | 158 | numMethods := int(header[0]) 159 | methods := make([]byte, numMethods) 160 | _, err := io.ReadAtLeast(r, methods, numMethods) 161 | return methods, err 162 | } 163 | -------------------------------------------------------------------------------- /protocol/tunnel/tunnel.go: -------------------------------------------------------------------------------- 1 | package tunnel 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | "sort" 8 | 9 | "github.com/chainreactors/rem/protocol/core" 10 | "github.com/chainreactors/rem/x/utils" 11 | ) 12 | 13 | var ( 14 | ctxKey = "meta" 15 | ) 16 | 17 | func NewTunnel(ctx context.Context, proto string, isLns bool, opts ...TunnelOption) (*TunnelService, error) { 18 | options := map[string]interface{}{ 19 | "mtu": core.MaxPacketSize, 20 | } 21 | 22 | tun := &TunnelService{ 23 | meta: options, 24 | wrapperPriority: DefaultHookPriority, 25 | } 26 | 27 | tun.ctx = context.WithValue(ctx, ctxKey, tun.meta) 28 | var err error 29 | if isLns { 30 | tun.listener, err = core.ListenerCreate(proto, tun.ctx) 31 | if err != nil { 32 | return nil, err 33 | } 34 | opts = append([]TunnelOption{WithListener(tun.listener)}, opts...) 35 | } else { 36 | tun.dialer, err = core.DialerCreate(proto, tun.ctx) 37 | if err != nil { 38 | return nil, err 39 | } 40 | opts = append([]TunnelOption{WithDialer(tun.dialer)}, opts...) 41 | } 42 | 43 | switch proto { 44 | case core.WebSocketTunnel: 45 | opts = append(opts, WithMeta(map[string]interface{}{ 46 | "path": utils.RandomString(8), 47 | })) 48 | case core.UNIXTunnel: 49 | opts = append(opts, WithMeta(map[string]interface{}{ 50 | "pipe": utils.RandomString(8), 51 | })) 52 | } 53 | 54 | for _, opt := range opts { 55 | opt.Apply(tun) 56 | } 57 | 58 | sort.SliceStable(tun.afterHooks, func(i, j int) bool { 59 | return tun.afterHooks[i].Priority > tun.afterHooks[j].Priority 60 | }) 61 | 62 | return tun, nil 63 | } 64 | 65 | type TunnelService struct { 66 | dialer core.TunnelDialer 67 | listener core.TunnelListener 68 | 69 | meta core.Metas 70 | wrapperPriority uint 71 | ctx context.Context 72 | hooks 73 | } 74 | 75 | func WithDialer(d core.TunnelDialer) TunnelOption { 76 | return newFuncTunnelOption(func(do *TunnelService) { 77 | do.dialer = d 78 | }) 79 | } 80 | 81 | func WithListener(l core.TunnelListener) TunnelOption { 82 | return newFuncTunnelOption(func(do *TunnelService) { 83 | do.listener = l 84 | }) 85 | } 86 | 87 | func (op *TunnelService) isListener() bool { 88 | if op.listener != nil { 89 | return true 90 | } 91 | return false 92 | } 93 | 94 | func (op *TunnelService) Dial(addr string) (c net.Conn, err error) { 95 | ctx := op.ctx 96 | for _, v := range op.beforeHooks { 97 | if v.DialHook != nil { 98 | ctx = v.DialHook(ctx, addr) 99 | } 100 | } 101 | 102 | if op.dialer != nil { 103 | c, err = op.dialer.Dial(addr) 104 | } else { 105 | return nil, fmt.Errorf("no dialer available") 106 | } 107 | 108 | if err != nil { 109 | return nil, err 110 | } 111 | 112 | lastSuccConn := c 113 | for _, v := range op.afterHooks { 114 | if v.DialerHook == nil { 115 | continue 116 | } 117 | ctx, c, err = v.DialerHook(ctx, c, addr) 118 | if err != nil { 119 | lastSuccConn.Close() 120 | return nil, err 121 | } 122 | lastSuccConn = c 123 | } 124 | return 125 | } 126 | 127 | func (op *TunnelService) Accept() (c net.Conn, err error) { 128 | ctx := op.ctx 129 | 130 | for _, v := range op.beforeHooks { 131 | if v.AcceptHook != nil { 132 | ctx = v.AcceptHook(ctx) 133 | } 134 | } 135 | 136 | if op.listener != nil { 137 | c, err = op.listener.Accept() 138 | } else { 139 | return nil, fmt.Errorf("no listener available") 140 | } 141 | 142 | if err != nil { 143 | return nil, err 144 | } 145 | 146 | lastSuccConn := c 147 | for _, v := range op.afterHooks { 148 | if v.AcceptHook == nil { 149 | continue 150 | } 151 | ctx, c, err = v.AcceptHook(ctx, c) 152 | if err != nil { 153 | lastSuccConn.Close() 154 | return nil, err 155 | } 156 | lastSuccConn = c 157 | } 158 | return 159 | } 160 | 161 | func (op *TunnelService) Listen(dst string) (net.Listener, error) { 162 | if op.listener == nil { 163 | return nil, fmt.Errorf("listener not set") 164 | } 165 | 166 | ctx := context.WithValue(context.Background(), ctxKey, op.meta) 167 | 168 | for _, v := range op.beforeHooks { 169 | if v.ListenHook != nil { 170 | ctx = v.ListenHook(ctx, dst) 171 | } 172 | } 173 | 174 | lsn, err := op.listener.Listen(dst) 175 | if err != nil { 176 | return nil, err 177 | } 178 | 179 | for _, v := range op.afterHooks { 180 | if v.ListenHook == nil { 181 | continue 182 | } 183 | ctx, lsn, err = v.ListenHook(ctx, lsn) 184 | if err != nil { 185 | op.listener.Close() 186 | return nil, err 187 | } 188 | op.listener = &core.WrappedListener{ 189 | TunnelListener: op.listener, 190 | Lns: lsn, 191 | } 192 | } 193 | 194 | return op.listener, nil 195 | } 196 | 197 | func (op *TunnelService) Close() error { 198 | if op.listener != nil { 199 | return op.listener.Close() 200 | } 201 | return nil 202 | } 203 | 204 | func (op *TunnelService) Addr() net.Addr { 205 | if op.listener != nil { 206 | return op.listener.Addr() 207 | } 208 | return nil 209 | } 210 | --------------------------------------------------------------------------------