github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/node/parser/shadowsocks.go (about) 1 package parser 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "fmt" 7 "net" 8 "net/url" 9 "os" 10 "strconv" 11 "strings" 12 13 "github.com/Asutorufa/yuhaiin/pkg/log" 14 "github.com/Asutorufa/yuhaiin/pkg/protos/node/point" 15 "github.com/Asutorufa/yuhaiin/pkg/protos/node/protocol" 16 "github.com/Asutorufa/yuhaiin/pkg/protos/node/subscribe" 17 ) 18 19 func init() { 20 store.Store(subscribe.Type_shadowsocks, func(data []byte) (*point.Point, error) { 21 ssUrl, err := url.Parse(string(data)) 22 if err != nil { 23 return nil, fmt.Errorf("parse url failed: %w", err) 24 } 25 26 server, portstr := ssUrl.Hostname(), ssUrl.Port() 27 28 var method, password string 29 mps, err := base64.RawURLEncoding.DecodeString(ssUrl.User.String()) 30 if err != nil { 31 log.Warn("parse shadowsocks user failed", "err", err) 32 } 33 if i := bytes.IndexByte(mps, ':'); i != -1 { 34 method, password = string(mps[:i]), string(mps[i+1:]) 35 } 36 37 port, err := strconv.ParseUint(portstr, 10, 16) 38 if err != nil { 39 return nil, fmt.Errorf("parse port failed: %w", err) 40 } 41 42 simple := &protocol.Simple{ 43 Host: server, 44 Port: int32(port), 45 } 46 47 var plugin []*protocol.Protocol 48 pluginopts := parseOpts(ssUrl.Query().Get("plugin")) 49 switch { 50 case pluginopts["obfs-local"] == "true": 51 plugin, err = parseObfs(pluginopts) 52 case pluginopts["v2ray"] == "true": 53 plugin, err = parseV2ray(pluginopts, simple) 54 default: 55 } 56 if err != nil { 57 return nil, fmt.Errorf("parse plugin failed: %w", err) 58 } 59 60 protocols := append([]*protocol.Protocol{ 61 { 62 Protocol: &protocol.Protocol_Simple{ 63 Simple: simple, 64 }, 65 }, 66 }, plugin...) 67 68 return &point.Point{ 69 Origin: point.Origin_remote, 70 Name: "[ss]" + ssUrl.Fragment, 71 Protocols: append(protocols, &protocol.Protocol{ 72 Protocol: &protocol.Protocol_Shadowsocks{ 73 Shadowsocks: &protocol.Shadowsocks{ 74 Method: method, 75 Password: password, 76 }, 77 }, 78 }), 79 }, nil 80 }) 81 } 82 83 func parseV2ray(store map[string]string, simple *protocol.Simple) ([]*protocol.Protocol, error) { 84 // fastOpen := false 85 // path := "/" 86 // host := "cloudfront.com" 87 // tlsEnabled := false 88 // cert := "" 89 // certRaw := "" 90 // mode := "websocket" 91 92 var err error 93 var cert []byte 94 if store["cert"] != "" { 95 cert, err = os.ReadFile(store["cert"]) 96 if err != nil { 97 log.Warn("read cert file failed", "err", err) 98 } 99 } 100 101 ns, _, err := net.SplitHostPort(store["host"]) 102 if err != nil { 103 log.Warn("split host and port failed", "err", err) 104 ns = store["host"] 105 } 106 107 switch store["mode"] { 108 case "websocket": 109 var protocols []*protocol.Protocol 110 protocols = append(protocols, &protocol.Protocol{ 111 Protocol: &protocol.Protocol_Tls{ 112 Tls: &protocol.TlsConfig{ 113 ServerNames: []string{ns}, 114 Enable: store["tls"] == "true", 115 CaCert: [][]byte{cert}, 116 }, 117 }, 118 }) 119 return append(protocols, &protocol.Protocol{ 120 Protocol: &protocol.Protocol_Websocket{ 121 Websocket: &protocol.Websocket{ 122 Host: store["host"], 123 Path: store["path"], 124 }, 125 }, 126 }), nil 127 case "quic": 128 return []*protocol.Protocol{ 129 { 130 Protocol: &protocol.Protocol_Quic{ 131 Quic: &protocol.Quic{ 132 Tls: &protocol.TlsConfig{ 133 ServerNames: []string{ns}, 134 CaCert: [][]byte{cert}, 135 }, 136 }, 137 }, 138 }, 139 }, nil 140 } 141 142 return nil, fmt.Errorf("unsupported mode: %v", store["mode"]) 143 } 144 145 func parseObfs(args map[string]string) ([]*protocol.Protocol, error) { 146 hostname, port, err := net.SplitHostPort(args["obfs-host"]) 147 if err != nil { 148 return nil, err 149 } 150 return []*protocol.Protocol{ 151 { 152 Protocol: &protocol.Protocol_ObfsHttp{ 153 ObfsHttp: &protocol.ObfsHttp{ 154 Host: hostname, 155 Port: port, 156 }, 157 }, 158 }, 159 }, nil 160 } 161 162 func parseOpts(options string) map[string]string { 163 store := make(map[string]string) 164 for _, x := range strings.Split(options, ";") { 165 i := strings.IndexByte(x, '=') 166 if i == -1 { 167 store[x] = "true" 168 } else { 169 key, value := x[:i], x[i+1:] 170 store[key] = value 171 } 172 } 173 return store 174 }