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.
This commit is contained in:
RPRX 2025-02-04 15:10:08 +00:00 committed by GitHub
parent 480c7d7db7
commit 9b7841178a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 1 deletions

View File

@ -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
}

View File

@ -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
} }
} }

View File

@ -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 {