github.com/xxf098/lite-proxy@v0.15.1-0.20230422081941-12c69f323218/config/parser.go (about) 1 package config 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "net" 8 "net/url" 9 "strconv" 10 "strings" 11 12 "github.com/xxf098/lite-proxy/common/structure" 13 "github.com/xxf098/lite-proxy/outbound" 14 ) 15 16 func ParseProxy(mapping map[string]interface{}, namePrefix string) (string, error) { 17 decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true}) 18 proxyType, existType := mapping["type"].(string) 19 if !existType { 20 return "", fmt.Errorf("missing type") 21 } 22 23 var ( 24 err error 25 link string 26 ) 27 28 switch proxyType { 29 case "ss": 30 ssOption := &outbound.ShadowSocksOption{} 31 err = decoder.Decode(mapping, ssOption) 32 if err != nil { 33 break 34 } 35 auth := fmt.Sprintf("%s:%s", ssOption.Cipher, ssOption.Password) 36 link = fmt.Sprintf("ss://%s@%s", base64.StdEncoding.EncodeToString([]byte(auth)), net.JoinHostPort(ssOption.Server, strconv.Itoa(ssOption.Port))) 37 if len(ssOption.Name) > 0 { 38 link = fmt.Sprintf("%s#%s", link, url.QueryEscape(ssOption.Name)) 39 } 40 case "ssr": 41 ssrOption := &outbound.ShadowSocksROption{} 42 err = decoder.Decode(mapping, ssrOption) 43 if err != nil { 44 break 45 } 46 password := base64.StdEncoding.EncodeToString([]byte(ssrOption.Password)) 47 link = fmt.Sprintf("%s:%s:%s:%s:%s", net.JoinHostPort(ssrOption.Server, strconv.Itoa(ssrOption.Port)), ssrOption.Protocol, ssrOption.Cipher, ssrOption.Obfs, password) 48 remarks := base64.StdEncoding.EncodeToString([]byte(ssrOption.Name)) 49 50 obfsParam := base64.StdEncoding.EncodeToString([]byte(ssrOption.ObfsParam)) 51 protocolParam := base64.StdEncoding.EncodeToString([]byte(ssrOption.ProtocolParam)) 52 link = fmt.Sprintf("%s/?obfsparam=%s&remarks=%s&protoparam=%s", link, url.QueryEscape(obfsParam), url.QueryEscape(remarks), url.QueryEscape(protocolParam)) 53 link = fmt.Sprintf("ssr://%s", base64.StdEncoding.EncodeToString([]byte(link))) 54 case "vmess": 55 // TODO: h2 56 vmessOption := &outbound.VmessOption{ 57 HTTPOpts: outbound.HTTPOptions{ 58 Method: "GET", 59 Path: []string{"/"}, 60 }, 61 } 62 err = decoder.Decode(mapping, vmessOption) 63 if err != nil { 64 break 65 } 66 tls := "" 67 if vmessOption.TLS { 68 tls = "tls" 69 } 70 if len(vmessOption.WSPath) == 0 && len(vmessOption.WSOpts.Path) > 0 { 71 vmessOption.WSPath = vmessOption.WSOpts.Path 72 } 73 host := "" 74 if h, ok := vmessOption.WSHeaders["Host"]; ok { 75 host = h 76 } else { 77 headers := vmessOption.WSOpts.Headers 78 if h, ok := headers["Host"]; ok { 79 host = h 80 } 81 } 82 if len(vmessOption.Network) < 1 { 83 vmessOption.Network = "tcp" 84 } 85 if len(vmessOption.Cipher) < 1 { 86 vmessOption.Cipher = "none" 87 } 88 skipCertVerify := vmessOption.SkipCertVerify 89 if len(vmessOption.ServerName) < 1 { 90 skipCertVerify = true 91 } 92 id := vmessOption.UUID 93 if len(id) < 1 { 94 id = vmessOption.Password 95 } 96 c := VmessConfigMarshal{ 97 Ps: namePrefix + vmessOption.Name, 98 Add: vmessOption.Server, 99 Port: vmessOption.Port, 100 Aid: vmessOption.AlterID, 101 ID: id, 102 Type: vmessOption.Cipher, 103 TLS: tls, 104 Net: vmessOption.Network, 105 Path: vmessOption.WSPath, 106 Host: host, 107 SkipCertVerify: skipCertVerify, 108 ServerName: vmessOption.ServerName, 109 Security: vmessOption.Cipher, 110 } 111 data, err := json.MarshalIndent(&c, "", " ") 112 if err != nil { 113 return "", err 114 } 115 link = fmt.Sprintf("vmess://%s", base64.StdEncoding.EncodeToString(data)) 116 case "trojan": 117 trojanOption := &outbound.TrojanOption{} 118 err = decoder.Decode(mapping, trojanOption) 119 if err != nil { 120 break 121 } 122 123 link = fmt.Sprintf("trojan://%s@%s", trojanOption.Password, net.JoinHostPort(trojanOption.Server, strconv.Itoa(trojanOption.Port))) 124 query := []string{} 125 // allowInsecure 126 if trojanOption.SkipCertVerify { 127 query = append(query, "allowInsecure=1") 128 } else { 129 query = append(query, "security=tls") 130 } 131 if len(trojanOption.SNI) > 0 { 132 query = append(query, fmt.Sprintf("sni=%s", trojanOption.SNI)) 133 } 134 // ws query 135 if trojanOption.Network == "ws" { 136 query = append(query, "type=ws") 137 if len(trojanOption.WSOpts.Path) > 0 { 138 query = append(query, fmt.Sprintf("path=%s", trojanOption.WSOpts.Path)) 139 for k, v := range trojanOption.WSOpts.Headers { 140 query = append(query, fmt.Sprintf("%s=%s", k, v)) 141 } 142 } 143 } 144 // grpc 145 if trojanOption.Network == "grpc" { 146 query = append(query, "type=grpc") 147 if len(trojanOption.GrpcOpts.GrpcServiceName) > 0 { 148 query = append(query, fmt.Sprintf("serviceName=%s", trojanOption.GrpcOpts.GrpcServiceName)) 149 } 150 } 151 152 if len(query) > 0 { 153 link = fmt.Sprintf("%s?%s", link, strings.Join(query, "&")) 154 } 155 if len(trojanOption.Remarks) > 0 { 156 link = fmt.Sprintf("%s#%s%s", link, namePrefix, url.QueryEscape(trojanOption.Remarks)) 157 } 158 if len(trojanOption.Name) > 0 { 159 link = fmt.Sprintf("%s#%s%s", link, namePrefix, url.QueryEscape(trojanOption.Name)) 160 } 161 case "http": 162 httpOption := &outbound.HttpOption{} 163 err = decoder.Decode(mapping, httpOption) 164 if err != nil { 165 break 166 } 167 link = fmt.Sprintf("http://%s@%s", httpOption.Password, net.JoinHostPort(httpOption.Server, strconv.Itoa(httpOption.Port))) 168 query := []string{} 169 query = append(query, fmt.Sprintf("tls=%t", httpOption.TLS)) 170 if len(httpOption.UserName) > 0 { 171 query = append(query, fmt.Sprintf("username=%s", httpOption.UserName)) 172 } 173 // allowInsecure 174 if httpOption.SkipCertVerify { 175 query = append(query, "allowInsecure=1") 176 } 177 if len(httpOption.SNI) > 0 { 178 query = append(query, fmt.Sprintf("sni=%s", httpOption.SNI)) 179 } 180 if len(query) > 0 { 181 link = fmt.Sprintf("%s?%s", link, strings.Join(query, "&")) 182 } 183 if len(httpOption.Name) > 0 { 184 link = fmt.Sprintf("%s#%s%s", link, namePrefix, url.QueryEscape(httpOption.Name)) 185 } 186 default: 187 return "", fmt.Errorf("unsupport proxy type: %s", proxyType) 188 } 189 190 if err != nil { 191 return "", err 192 } 193 194 return link, nil 195 196 }