github.com/xxf098/lite-proxy@v0.15.1-0.20230422081941-12c69f323218/outbound/shadowsocksr.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net" 8 "strconv" 9 10 "github.com/Dreamacro/go-shadowsocks2/core" 11 "github.com/Dreamacro/go-shadowsocks2/shadowaead" 12 "github.com/Dreamacro/go-shadowsocks2/shadowstream" 13 C "github.com/xxf098/lite-proxy/constant" 14 "github.com/xxf098/lite-proxy/transport/dialer" 15 "github.com/xxf098/lite-proxy/transport/ssr/obfs" 16 "github.com/xxf098/lite-proxy/transport/ssr/protocol" 17 ) 18 19 type ShadowSocksR struct { 20 *Base 21 cipher core.Cipher 22 obfs obfs.Obfs 23 protocol protocol.Protocol 24 } 25 26 type ShadowSocksROption struct { 27 Name string `proxy:"name,omitempty"` 28 Server string `proxy:"server"` 29 Port int `proxy:"port"` 30 Password string `proxy:"password"` 31 Cipher string `proxy:"cipher"` 32 Obfs string `proxy:"obfs"` 33 ObfsParam string `proxy:"obfs-param,omitempty"` 34 Protocol string `proxy:"protocol"` 35 ProtocolParam string `proxy:"protocol-param,omitempty"` 36 UDP bool `proxy:"udp,omitempty"` 37 Remarks string `proxy:"remarks,omitempty"` 38 } 39 40 func (ssr *ShadowSocksR) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 41 c = ssr.obfs.StreamConn(c) 42 c = ssr.cipher.StreamConn(c) 43 var ( 44 iv []byte 45 err error 46 ) 47 switch conn := c.(type) { 48 case *shadowstream.Conn: 49 iv, err = conn.ObtainWriteIV() 50 if err != nil { 51 return nil, err 52 } 53 case *shadowaead.Conn: 54 return nil, fmt.Errorf("invalid connection type") 55 } 56 c = ssr.protocol.StreamConn(c, iv) 57 _, err = c.Write(serializesSocksAddr(metadata)) 58 return c, err 59 } 60 61 func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) { 62 c, err := dialer.DialContext(ctx, "tcp", ssr.addr) 63 if err != nil { 64 return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err) 65 } 66 tcpKeepAlive(c) 67 68 return ssr.StreamConn(c, metadata) 69 } 70 71 func (ssr *ShadowSocksR) DialUDP(metadata *C.Metadata) (net.PacketConn, error) { 72 pc, err := dialer.ListenPacket("udp", "") 73 if err != nil { 74 return nil, err 75 } 76 77 addr, err := resolveUDPAddr("udp", ssr.addr) 78 if err != nil { 79 return nil, err 80 } 81 82 pc = ssr.cipher.PacketConn(pc) 83 pc = ssr.protocol.PacketConn(pc) 84 return &ssPacketConn{PacketConn: pc, rAddr: addr}, nil 85 } 86 87 func (ssr *ShadowSocksR) MarshalJSON() ([]byte, error) { 88 return json.Marshal(map[string]string{ 89 "type": "shadowsocksr", 90 }) 91 } 92 93 func NewShadowSocksR(option *ShadowSocksROption) (*ShadowSocksR, error) { 94 addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) 95 if option.Cipher == "none" { 96 option.Cipher = "dummy" 97 } 98 cipher := option.Cipher 99 password := option.Password 100 coreCiph, err := core.PickCipher(cipher, nil, password) 101 if err != nil { 102 return nil, fmt.Errorf("ssr %s initialize error: %w", addr, err) 103 } 104 var ( 105 ivSize int 106 key []byte 107 ) 108 if option.Cipher == "dummy" { 109 ivSize = 0 110 key = core.Kdf(option.Password, 16) 111 } else { 112 ciph, ok := coreCiph.(*core.StreamCipher) 113 if !ok { 114 return nil, fmt.Errorf("%s is not dummy or a supported stream cipher in ssr", cipher) 115 } 116 ivSize = ciph.IVSize() 117 key = ciph.Key 118 } 119 120 obfs, obfsOverhead, err := obfs.PickObfs(option.Obfs, &obfs.Base{ 121 Host: option.Server, 122 Port: option.Port, 123 Key: key, 124 IVSize: ivSize, 125 Param: option.ObfsParam, 126 }) 127 if err != nil { 128 return nil, fmt.Errorf("ssr %s initialize obfs error: %w", addr, err) 129 } 130 131 protocol, err := protocol.PickProtocol(option.Protocol, &protocol.Base{ 132 Key: key, 133 Overhead: obfsOverhead, 134 Param: option.ProtocolParam, 135 }) 136 if err != nil { 137 return nil, fmt.Errorf("ssr %s initialize protocol error: %w", addr, err) 138 } 139 140 return &ShadowSocksR{ 141 Base: &Base{ 142 name: option.Name, 143 addr: addr, 144 udp: option.UDP, 145 }, 146 cipher: coreCiph, 147 obfs: obfs, 148 protocol: protocol, 149 }, nil 150 }