github.com/metacubex/mihomo@v1.18.5/adapter/outbound/trojan.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net" 8 "net/http" 9 "strconv" 10 11 N "github.com/metacubex/mihomo/common/net" 12 "github.com/metacubex/mihomo/component/ca" 13 "github.com/metacubex/mihomo/component/dialer" 14 "github.com/metacubex/mihomo/component/proxydialer" 15 tlsC "github.com/metacubex/mihomo/component/tls" 16 C "github.com/metacubex/mihomo/constant" 17 "github.com/metacubex/mihomo/transport/gun" 18 "github.com/metacubex/mihomo/transport/trojan" 19 ) 20 21 type Trojan struct { 22 *Base 23 instance *trojan.Trojan 24 option *TrojanOption 25 26 // for gun mux 27 gunTLSConfig *tls.Config 28 gunConfig *gun.Config 29 transport *gun.TransportWrap 30 31 realityConfig *tlsC.RealityConfig 32 } 33 34 type TrojanOption struct { 35 BasicOption 36 Name string `proxy:"name"` 37 Server string `proxy:"server"` 38 Port int `proxy:"port"` 39 Password string `proxy:"password"` 40 ALPN []string `proxy:"alpn,omitempty"` 41 SNI string `proxy:"sni,omitempty"` 42 SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` 43 Fingerprint string `proxy:"fingerprint,omitempty"` 44 UDP bool `proxy:"udp,omitempty"` 45 Network string `proxy:"network,omitempty"` 46 RealityOpts RealityOptions `proxy:"reality-opts,omitempty"` 47 GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` 48 WSOpts WSOptions `proxy:"ws-opts,omitempty"` 49 ClientFingerprint string `proxy:"client-fingerprint,omitempty"` 50 } 51 52 func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) { 53 if t.option.Network == "ws" { 54 host, port, _ := net.SplitHostPort(t.addr) 55 wsOpts := &trojan.WebsocketOption{ 56 Host: host, 57 Port: port, 58 Path: t.option.WSOpts.Path, 59 V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade, 60 V2rayHttpUpgradeFastOpen: t.option.WSOpts.V2rayHttpUpgradeFastOpen, 61 Headers: http.Header{}, 62 } 63 64 if t.option.SNI != "" { 65 wsOpts.Host = t.option.SNI 66 } 67 68 if len(t.option.WSOpts.Headers) != 0 { 69 for key, value := range t.option.WSOpts.Headers { 70 wsOpts.Headers.Add(key, value) 71 } 72 } 73 74 return t.instance.StreamWebsocketConn(ctx, c, wsOpts) 75 } 76 77 return t.instance.StreamConn(ctx, c) 78 } 79 80 // StreamConnContext implements C.ProxyAdapter 81 func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { 82 var err error 83 84 if tlsC.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 { 85 t.option.ClientFingerprint = tlsC.GetGlobalFingerprint() 86 } 87 88 if t.transport != nil { 89 c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig, t.realityConfig) 90 } else { 91 c, err = t.plainStream(ctx, c) 92 } 93 94 if err != nil { 95 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 96 } 97 98 if metadata.NetWork == C.UDP { 99 err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) 100 return c, err 101 } 102 err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)) 103 return c, err 104 } 105 106 // DialContext implements C.ProxyAdapter 107 func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { 108 // gun transport 109 if t.transport != nil && len(opts) == 0 { 110 c, err := gun.StreamGunWithTransport(t.transport, t.gunConfig) 111 if err != nil { 112 return nil, err 113 } 114 115 if err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)); err != nil { 116 c.Close() 117 return nil, err 118 } 119 120 return NewConn(c, t), nil 121 } 122 return t.DialContextWithDialer(ctx, dialer.NewDialer(t.Base.DialOptions(opts...)...), metadata) 123 } 124 125 // DialContextWithDialer implements C.ProxyAdapter 126 func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { 127 if len(t.option.DialerProxy) > 0 { 128 dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) 129 if err != nil { 130 return nil, err 131 } 132 } 133 c, err := dialer.DialContext(ctx, "tcp", t.addr) 134 if err != nil { 135 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 136 } 137 N.TCPKeepAlive(c) 138 139 defer func(c net.Conn) { 140 safeConnClose(c, err) 141 }(c) 142 143 c, err = t.StreamConnContext(ctx, c, metadata) 144 if err != nil { 145 return nil, err 146 } 147 148 return NewConn(c, t), err 149 } 150 151 // ListenPacketContext implements C.ProxyAdapter 152 func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { 153 var c net.Conn 154 155 // grpc transport 156 if t.transport != nil && len(opts) == 0 { 157 c, err = gun.StreamGunWithTransport(t.transport, t.gunConfig) 158 if err != nil { 159 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 160 } 161 defer func(c net.Conn) { 162 safeConnClose(c, err) 163 }(c) 164 err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) 165 if err != nil { 166 return nil, err 167 } 168 169 pc := t.instance.PacketConn(c) 170 return newPacketConn(pc, t), err 171 } 172 return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.Base.DialOptions(opts...)...), metadata) 173 } 174 175 // ListenPacketWithDialer implements C.ProxyAdapter 176 func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { 177 if len(t.option.DialerProxy) > 0 { 178 dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) 179 if err != nil { 180 return nil, err 181 } 182 } 183 c, err := dialer.DialContext(ctx, "tcp", t.addr) 184 if err != nil { 185 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 186 } 187 defer func(c net.Conn) { 188 safeConnClose(c, err) 189 }(c) 190 N.TCPKeepAlive(c) 191 c, err = t.plainStream(ctx, c) 192 if err != nil { 193 return nil, fmt.Errorf("%s connect error: %w", t.addr, err) 194 } 195 196 err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) 197 if err != nil { 198 return nil, err 199 } 200 201 pc := t.instance.PacketConn(c) 202 return newPacketConn(pc, t), err 203 } 204 205 // SupportWithDialer implements C.ProxyAdapter 206 func (t *Trojan) SupportWithDialer() C.NetWork { 207 return C.ALLNet 208 } 209 210 // ListenPacketOnStreamConn implements C.ProxyAdapter 211 func (t *Trojan) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { 212 pc := t.instance.PacketConn(c) 213 return newPacketConn(pc, t), err 214 } 215 216 // SupportUOT implements C.ProxyAdapter 217 func (t *Trojan) SupportUOT() bool { 218 return true 219 } 220 221 func NewTrojan(option TrojanOption) (*Trojan, error) { 222 addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) 223 224 tOption := &trojan.Option{ 225 Password: option.Password, 226 ALPN: option.ALPN, 227 ServerName: option.Server, 228 SkipCertVerify: option.SkipCertVerify, 229 Fingerprint: option.Fingerprint, 230 ClientFingerprint: option.ClientFingerprint, 231 } 232 233 if option.SNI != "" { 234 tOption.ServerName = option.SNI 235 } 236 237 t := &Trojan{ 238 Base: &Base{ 239 name: option.Name, 240 addr: addr, 241 tp: C.Trojan, 242 udp: option.UDP, 243 tfo: option.TFO, 244 mpTcp: option.MPTCP, 245 iface: option.Interface, 246 rmark: option.RoutingMark, 247 prefer: C.NewDNSPrefer(option.IPVersion), 248 }, 249 instance: trojan.New(tOption), 250 option: &option, 251 } 252 253 var err error 254 t.realityConfig, err = option.RealityOpts.Parse() 255 if err != nil { 256 return nil, err 257 } 258 tOption.Reality = t.realityConfig 259 260 if option.Network == "grpc" { 261 dialFn := func(network, addr string) (net.Conn, error) { 262 var err error 263 var cDialer C.Dialer = dialer.NewDialer(t.Base.DialOptions()...) 264 if len(t.option.DialerProxy) > 0 { 265 cDialer, err = proxydialer.NewByName(t.option.DialerProxy, cDialer) 266 if err != nil { 267 return nil, err 268 } 269 } 270 c, err := cDialer.DialContext(context.Background(), "tcp", t.addr) 271 if err != nil { 272 return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error()) 273 } 274 N.TCPKeepAlive(c) 275 return c, nil 276 } 277 278 tlsConfig := &tls.Config{ 279 NextProtos: option.ALPN, 280 MinVersion: tls.VersionTLS12, 281 InsecureSkipVerify: tOption.SkipCertVerify, 282 ServerName: tOption.ServerName, 283 } 284 285 var err error 286 tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) 287 if err != nil { 288 return nil, err 289 } 290 291 t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint, t.realityConfig) 292 293 t.gunTLSConfig = tlsConfig 294 t.gunConfig = &gun.Config{ 295 ServiceName: option.GrpcOpts.GrpcServiceName, 296 Host: tOption.ServerName, 297 } 298 } 299 300 return t, nil 301 }