Browse Source

MITM: Allow forwarding local negotiated ALPN http/1.1 to the real website

https://github.com/XTLS/Xray-core/issues/4348#issuecomment-2633656408

https://github.com/XTLS/Xray-core/issues/4348#issuecomment-2633865039

Local negotiated ALPN http/1.1 was sent by browser/app or is written in dokodemo-door RAW's `tlsSettings`.

Set `"alpn": ["fromMitm"]` in freedom RAW's `tlsSettings` to forward it to the real website.
RPRX 9 months ago
parent
commit
9b7841178a
3 changed files with 27 additions and 1 deletions
  1. 12 0
      common/session/context.go
  2. 4 0
      proxy/dokodemo/dokodemo.go
  3. 11 1
      transport/internet/tcp/dialer.go

+ 12 - 0
common/session/context.go

@@ -23,6 +23,7 @@ const (
 	timeoutOnlyKey            ctx.SessionKey = 8
 	timeoutOnlyKey            ctx.SessionKey = 8
 	allowedNetworkKey         ctx.SessionKey = 9
 	allowedNetworkKey         ctx.SessionKey = 9
 	handlerSessionKey         ctx.SessionKey = 10
 	handlerSessionKey         ctx.SessionKey = 10
+	mitmAlpn11Key             ctx.SessionKey = 11
 )
 )
 
 
 func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
 func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
@@ -162,3 +163,14 @@ func AllowedNetworkFromContext(ctx context.Context) net.Network {
 	}
 	}
 	return net.Network_Unknown
 	return net.Network_Unknown
 }
 }
+
+func ContextWithMitmAlpn11(ctx context.Context, alpn11 bool) context.Context {
+	return context.WithValue(ctx, mitmAlpn11Key, alpn11)
+}
+
+func MitmAlpn11FromContext(ctx context.Context) bool {
+	if val, ok := ctx.Value(mitmAlpn11Key).(bool); ok {
+		return val
+	}
+	return false
+}

+ 4 - 0
proxy/dokodemo/dokodemo.go

@@ -18,6 +18,7 @@ import (
 	"github.com/xtls/xray-core/features/policy"
 	"github.com/xtls/xray-core/features/policy"
 	"github.com/xtls/xray-core/features/routing"
 	"github.com/xtls/xray-core/features/routing"
 	"github.com/xtls/xray-core/transport/internet/stat"
 	"github.com/xtls/xray-core/transport/internet/stat"
+	"github.com/xtls/xray-core/transport/internet/tls"
 )
 )
 
 
 func init() {
 func init() {
@@ -90,6 +91,9 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
 			addr := handshake.HandshakeAddressContext(ctx)
 			addr := handshake.HandshakeAddressContext(ctx)
 			if addr != nil {
 			if addr != nil {
 				dest.Address = addr
 				dest.Address = addr
+				if conn.(*tls.Conn).ConnectionState().NegotiatedProtocol == "http/1.1" {
+					ctx = session.ContextWithMitmAlpn11(ctx, true)
+				}
 				destinationOverridden = true
 				destinationOverridden = true
 			}
 			}
 		}
 		}

+ 11 - 1
transport/internet/tcp/dialer.go

@@ -2,10 +2,12 @@ package tcp
 
 
 import (
 import (
 	"context"
 	"context"
+	"strings"
 
 
 	"github.com/xtls/xray-core/common"
 	"github.com/xtls/xray-core/common"
 	"github.com/xtls/xray-core/common/errors"
 	"github.com/xtls/xray-core/common/errors"
 	"github.com/xtls/xray-core/common/net"
 	"github.com/xtls/xray-core/common/net"
+	"github.com/xtls/xray-core/common/session"
 	"github.com/xtls/xray-core/transport/internet"
 	"github.com/xtls/xray-core/transport/internet"
 	"github.com/xtls/xray-core/transport/internet/reality"
 	"github.com/xtls/xray-core/transport/internet/reality"
 	"github.com/xtls/xray-core/transport/internet/stat"
 	"github.com/xtls/xray-core/transport/internet/stat"
@@ -24,7 +26,8 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
 		tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
 		tlsConfig := config.GetTLSConfig(tls.WithDestination(dest))
 		if fingerprint := tls.GetFingerprint(config.Fingerprint); fingerprint != nil {
 		if fingerprint := tls.GetFingerprint(config.Fingerprint); fingerprint != nil {
 			conn = tls.UClient(conn, tlsConfig, fingerprint)
 			conn = tls.UClient(conn, tlsConfig, fingerprint)
-			if len(tlsConfig.NextProtos) == 1 && tlsConfig.NextProtos[0] == "http/1.1" {
+			if len(tlsConfig.NextProtos) == 1 && (tlsConfig.NextProtos[0] == "http/1.1" ||
+				(strings.ToLower(tlsConfig.NextProtos[0]) == "frommitm" && session.MitmAlpn11FromContext(ctx))) {
 				if err := conn.(*tls.UConn).WebsocketHandshakeContext(ctx); err != nil {
 				if err := conn.(*tls.UConn).WebsocketHandshakeContext(ctx); err != nil {
 					return nil, err
 					return nil, err
 				}
 				}
@@ -34,6 +37,13 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
 				}
 				}
 			}
 			}
 		} else {
 		} else {
+			if len(tlsConfig.NextProtos) == 1 && strings.ToLower(tlsConfig.NextProtos[0]) == "frommitm" {
+				if session.MitmAlpn11FromContext(ctx) {
+					tlsConfig.NextProtos = []string{"http/1.1"} // new slice
+				} else {
+					tlsConfig.NextProtos = nil
+				}
+			}
 			conn = tls.Client(conn, tlsConfig)
 			conn = tls.Client(conn, tlsConfig)
 		}
 		}
 	} else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {
 	} else if config := reality.ConfigFromStreamSettings(streamSettings); config != nil {