Skip to content

Commit 12f4a01

Browse files
committed
VLESS Reverse Proxy: Transfer real Source & Local (IP & port), enabled by default
https://t.me/projectXtls/1039 #5101 (comment)
1 parent 9cc7907 commit 12f4a01

File tree

10 files changed

+130
-48
lines changed

10 files changed

+130
-48
lines changed

app/proxyman/outbound/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
108108
}
109109
h.proxyConfig = proxyConfig
110110

111-
ctx = session.ContextWithHandler(ctx, h)
111+
ctx = session.ContextWithFullHandler(ctx, h)
112112

113113
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
114114
if err != nil {

app/reverse/bridge.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,11 @@ func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
198198

199199
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
200200
if !isInternalDomain(dest) {
201-
ctx = session.ContextWithInbound(ctx, &session.Inbound{
202-
Tag: w.Tag,
203-
})
201+
if session.InboundFromContext(ctx) == nil {
202+
ctx = session.ContextWithInbound(ctx, &session.Inbound{
203+
Tag: w.Tag,
204+
})
205+
}
204206
return w.Dispatcher.Dispatch(ctx, dest)
205207
}
206208

@@ -221,9 +223,11 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
221223

222224
func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, link *transport.Link) error {
223225
if !isInternalDomain(dest) {
224-
ctx = session.ContextWithInbound(ctx, &session.Inbound{
225-
Tag: w.Tag,
226-
})
226+
if session.InboundFromContext(ctx) == nil {
227+
ctx = session.ContextWithInbound(ctx, &session.Inbound{
228+
Tag: w.Tag,
229+
})
230+
}
227231
return w.Dispatcher.DispatchLink(ctx, dest, link)
228232
}
229233

common/mux/client.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,11 @@ func fetchInput(ctx context.Context, s *Session, output buf.Writer) {
264264
transferType = protocol.TransferTypePacket
265265
}
266266
s.transferType = transferType
267-
writer := NewWriter(s.ID, ob.Target, output, transferType, xudp.GetGlobalID(ctx))
267+
var inbound *session.Inbound
268+
if session.IsReverseMuxFromContext(ctx) {
269+
inbound = session.InboundFromContext(ctx)
270+
}
271+
writer := NewWriter(s.ID, ob.Target, output, transferType, xudp.GetGlobalID(ctx), inbound)
268272
defer s.Close(false)
269273
defer writer.Close()
270274

@@ -384,7 +388,7 @@ func (m *ClientWorker) fetchOutput() {
384388

385389
var meta FrameMetadata
386390
for {
387-
err := meta.Unmarshal(reader)
391+
err := meta.Unmarshal(reader, false)
388392
if err != nil {
389393
if errors.Cause(err) != io.EOF {
390394
errors.LogInfoInner(context.Background(), err, "failed to read metadata")

common/mux/frame.go

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/xtls/xray-core/common/net"
1212
"github.com/xtls/xray-core/common/protocol"
1313
"github.com/xtls/xray-core/common/serial"
14+
"github.com/xtls/xray-core/common/session"
1415
)
1516

1617
type SessionStatus byte
@@ -60,6 +61,7 @@ type FrameMetadata struct {
6061
Option bitmask.Byte
6162
SessionStatus SessionStatus
6263
GlobalID [8]byte
64+
Inbound *session.Inbound
6365
}
6466

6567
func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
@@ -79,11 +81,23 @@ func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
7981
case net.Network_UDP:
8082
common.Must(b.WriteByte(byte(TargetNetworkUDP)))
8183
}
82-
8384
if err := addrParser.WriteAddressPort(b, f.Target.Address, f.Target.Port); err != nil {
8485
return err
8586
}
86-
if b.UDP != nil { // make sure it's user's proxy request
87+
if f.Inbound != nil {
88+
if f.Inbound.Source.Network == net.Network_TCP || f.Inbound.Source.Network == net.Network_UDP {
89+
common.Must(b.WriteByte(byte(f.Inbound.Source.Network - 1)))
90+
if err := addrParser.WriteAddressPort(b, f.Inbound.Source.Address, f.Inbound.Source.Port); err != nil {
91+
return err
92+
}
93+
if f.Inbound.Local.Network == net.Network_TCP || f.Inbound.Local.Network == net.Network_UDP {
94+
common.Must(b.WriteByte(byte(f.Inbound.Local.Network - 1)))
95+
if err := addrParser.WriteAddressPort(b, f.Inbound.Local.Address, f.Inbound.Local.Port); err != nil {
96+
return err
97+
}
98+
}
99+
}
100+
} else if b.UDP != nil { // make sure it's user's proxy request
87101
b.Write(f.GlobalID[:]) // no need to check whether it's empty
88102
}
89103
} else if b.UDP != nil {
@@ -97,7 +111,7 @@ func (f FrameMetadata) WriteTo(b *buf.Buffer) error {
97111
}
98112

99113
// Unmarshal reads FrameMetadata from the given reader.
100-
func (f *FrameMetadata) Unmarshal(reader io.Reader) error {
114+
func (f *FrameMetadata) Unmarshal(reader io.Reader, readSourceAndLocal bool) error {
101115
metaLen, err := serial.ReadUint16(reader)
102116
if err != nil {
103117
return err
@@ -112,12 +126,12 @@ func (f *FrameMetadata) Unmarshal(reader io.Reader) error {
112126
if _, err := b.ReadFullFrom(reader, int32(metaLen)); err != nil {
113127
return err
114128
}
115-
return f.UnmarshalFromBuffer(b)
129+
return f.UnmarshalFromBuffer(b, readSourceAndLocal)
116130
}
117131

118132
// UnmarshalFromBuffer reads a FrameMetadata from the given buffer.
119133
// Visible for testing only.
120-
func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
134+
func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer, readSourceAndLocal bool) error {
121135
if b.Len() < 4 {
122136
return errors.New("insufficient buffer: ", b.Len())
123137
}
@@ -150,6 +164,54 @@ func (f *FrameMetadata) UnmarshalFromBuffer(b *buf.Buffer) error {
150164
}
151165
}
152166

167+
if f.SessionStatus == SessionStatusNew && readSourceAndLocal {
168+
f.Inbound = &session.Inbound{}
169+
170+
if b.Len() == 0 {
171+
return nil // for heartbeat, etc.
172+
}
173+
network := TargetNetwork(b.Byte(0))
174+
if network == 0 {
175+
return nil // may be padding
176+
}
177+
b.Advance(1)
178+
addr, port, err := addrParser.ReadAddressPort(nil, b)
179+
if err != nil {
180+
return errors.New("reading source: failed to parse address and port").Base(err)
181+
}
182+
switch network {
183+
case TargetNetworkTCP:
184+
f.Inbound.Source = net.TCPDestination(addr, port)
185+
case TargetNetworkUDP:
186+
f.Inbound.Source = net.UDPDestination(addr, port)
187+
default:
188+
return errors.New("reading source: unknown network type: ", network)
189+
}
190+
191+
if b.Len() == 0 {
192+
return nil
193+
}
194+
network = TargetNetwork(b.Byte(0))
195+
if network == 0 {
196+
return nil
197+
}
198+
b.Advance(1)
199+
addr, port, err = addrParser.ReadAddressPort(nil, b)
200+
if err != nil {
201+
return errors.New("reading local: failed to parse address and port").Base(err)
202+
}
203+
switch network {
204+
case TargetNetworkTCP:
205+
f.Inbound.Local = net.TCPDestination(addr, port)
206+
case TargetNetworkUDP:
207+
f.Inbound.Local = net.UDPDestination(addr, port)
208+
default:
209+
return errors.New("reading local: unknown network type: ", network)
210+
}
211+
212+
return nil
213+
}
214+
153215
// Application data is essential, to test whether the pipe is closed.
154216
if f.SessionStatus == SessionStatusNew && f.Option.Has(OptionData) &&
155217
f.Target.Network == net.Network_UDP && b.Len() >= 8 {

common/mux/mux_test.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
. "github.com/xtls/xray-core/common/mux"
1111
"github.com/xtls/xray-core/common/net"
1212
"github.com/xtls/xray-core/common/protocol"
13+
"github.com/xtls/xray-core/common/session"
1314
"github.com/xtls/xray-core/transport/pipe"
1415
)
1516

@@ -32,13 +33,13 @@ func TestReaderWriter(t *testing.T) {
3233
pReader, pWriter := pipe.New(pipe.WithSizeLimit(1024))
3334

3435
dest := net.TCPDestination(net.DomainAddress("example.com"), 80)
35-
writer := NewWriter(1, dest, pWriter, protocol.TransferTypeStream, [8]byte{})
36+
writer := NewWriter(1, dest, pWriter, protocol.TransferTypeStream, [8]byte{}, &session.Inbound{})
3637

3738
dest2 := net.TCPDestination(net.LocalHostIP, 443)
38-
writer2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream, [8]byte{})
39+
writer2 := NewWriter(2, dest2, pWriter, protocol.TransferTypeStream, [8]byte{}, &session.Inbound{})
3940

4041
dest3 := net.TCPDestination(net.LocalHostIPv6, 18374)
41-
writer3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream, [8]byte{})
42+
writer3 := NewWriter(3, dest3, pWriter, protocol.TransferTypeStream, [8]byte{}, &session.Inbound{})
4243

4344
writePayload := func(writer *Writer, payload ...byte) error {
4445
b := buf.New()
@@ -62,7 +63,7 @@ func TestReaderWriter(t *testing.T) {
6263

6364
{
6465
var meta FrameMetadata
65-
common.Must(meta.Unmarshal(bytesReader))
66+
common.Must(meta.Unmarshal(bytesReader, false))
6667
if r := cmp.Diff(meta, FrameMetadata{
6768
SessionID: 1,
6869
SessionStatus: SessionStatusNew,
@@ -81,7 +82,7 @@ func TestReaderWriter(t *testing.T) {
8182

8283
{
8384
var meta FrameMetadata
84-
common.Must(meta.Unmarshal(bytesReader))
85+
common.Must(meta.Unmarshal(bytesReader, false))
8586
if r := cmp.Diff(meta, FrameMetadata{
8687
SessionStatus: SessionStatusNew,
8788
SessionID: 2,
@@ -94,7 +95,7 @@ func TestReaderWriter(t *testing.T) {
9495

9596
{
9697
var meta FrameMetadata
97-
common.Must(meta.Unmarshal(bytesReader))
98+
common.Must(meta.Unmarshal(bytesReader, false))
9899
if r := cmp.Diff(meta, FrameMetadata{
99100
SessionID: 1,
100101
SessionStatus: SessionStatusKeep,
@@ -112,7 +113,7 @@ func TestReaderWriter(t *testing.T) {
112113

113114
{
114115
var meta FrameMetadata
115-
common.Must(meta.Unmarshal(bytesReader))
116+
common.Must(meta.Unmarshal(bytesReader, false))
116117
if r := cmp.Diff(meta, FrameMetadata{
117118
SessionID: 3,
118119
SessionStatus: SessionStatusNew,
@@ -131,7 +132,7 @@ func TestReaderWriter(t *testing.T) {
131132

132133
{
133134
var meta FrameMetadata
134-
common.Must(meta.Unmarshal(bytesReader))
135+
common.Must(meta.Unmarshal(bytesReader, false))
135136
if r := cmp.Diff(meta, FrameMetadata{
136137
SessionID: 1,
137138
SessionStatus: SessionStatusEnd,
@@ -143,7 +144,7 @@ func TestReaderWriter(t *testing.T) {
143144

144145
{
145146
var meta FrameMetadata
146-
common.Must(meta.Unmarshal(bytesReader))
147+
common.Must(meta.Unmarshal(bytesReader, false))
147148
if r := cmp.Diff(meta, FrameMetadata{
148149
SessionID: 3,
149150
SessionStatus: SessionStatusEnd,
@@ -155,7 +156,7 @@ func TestReaderWriter(t *testing.T) {
155156

156157
{
157158
var meta FrameMetadata
158-
common.Must(meta.Unmarshal(bytesReader))
159+
common.Must(meta.Unmarshal(bytesReader, false))
159160
if r := cmp.Diff(meta, FrameMetadata{
160161
SessionID: 2,
161162
SessionStatus: SessionStatusKeep,
@@ -173,7 +174,7 @@ func TestReaderWriter(t *testing.T) {
173174

174175
{
175176
var meta FrameMetadata
176-
common.Must(meta.Unmarshal(bytesReader))
177+
common.Must(meta.Unmarshal(bytesReader, false))
177178
if r := cmp.Diff(meta, FrameMetadata{
178179
SessionID: 2,
179180
SessionStatus: SessionStatusEnd,
@@ -187,7 +188,7 @@ func TestReaderWriter(t *testing.T) {
187188

188189
{
189190
var meta FrameMetadata
190-
err := meta.Unmarshal(bytesReader)
191+
err := meta.Unmarshal(bytesReader, false)
191192
if err == nil {
192193
t.Error("nil error")
193194
}

common/mux/server.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.Bu
166166

167167
func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata, reader *buf.BufferedReader) error {
168168
ctx = session.SubContextFromMuxInbound(ctx)
169+
if meta.Inbound != nil && meta.Inbound.Source.IsValid() && meta.Inbound.Local.IsValid() {
170+
if inbound := session.InboundFromContext(ctx); inbound != nil {
171+
newInbound := *inbound
172+
newInbound.Source = meta.Inbound.Source
173+
newInbound.Local = meta.Inbound.Local
174+
ctx = session.ContextWithInbound(ctx, &newInbound)
175+
}
176+
}
169177
errors.LogInfo(ctx, "received request for ", meta.Target)
170178
{
171179
msg := &log.AccessMessage{
@@ -329,7 +337,7 @@ func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.Buffered
329337

330338
func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedReader) error {
331339
var meta FrameMetadata
332-
err := meta.Unmarshal(reader)
340+
err := meta.Unmarshal(reader, session.IsReverseMuxFromContext(ctx))
333341
if err != nil {
334342
return errors.New("failed to read metadata").Base(err)
335343
}
@@ -340,7 +348,7 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
340348
case SessionStatusEnd:
341349
err = w.handleStatusEnd(&meta, reader)
342350
case SessionStatusNew:
343-
err = w.handleStatusNew(ctx, &meta, reader)
351+
err = w.handleStatusNew(session.ContextWithIsReverseMux(ctx, false), &meta, reader)
344352
case SessionStatusKeep:
345353
err = w.handleStatusKeep(&meta, reader)
346354
default:

common/mux/writer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/xtls/xray-core/common/net"
77
"github.com/xtls/xray-core/common/protocol"
88
"github.com/xtls/xray-core/common/serial"
9+
"github.com/xtls/xray-core/common/session"
910
)
1011

1112
type Writer struct {
@@ -16,16 +17,18 @@ type Writer struct {
1617
hasError bool
1718
transferType protocol.TransferType
1819
globalID [8]byte
20+
inbound *session.Inbound
1921
}
2022

21-
func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType, globalID [8]byte) *Writer {
23+
func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType, globalID [8]byte, inbound *session.Inbound) *Writer {
2224
return &Writer{
2325
id: id,
2426
dest: dest,
2527
writer: writer,
2628
followup: false,
2729
transferType: transferType,
2830
globalID: globalID,
31+
inbound: inbound,
2932
}
3033
}
3134

@@ -43,6 +46,7 @@ func (w *Writer) getNextFrameMeta() FrameMetadata {
4346
SessionID: w.id,
4447
Target: w.dest,
4548
GlobalID: w.globalID,
49+
Inbound: w.inbound,
4650
}
4751

4852
if w.followup {

0 commit comments

Comments
 (0)