proxy.go 13.5 KB
Newer Older
F
fatedier 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2017 fatedier, fatedier@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

F
fatedier 已提交
15
package proxy
F
fatedier 已提交
16 17

import (
F
fatedier 已提交
18
	"bytes"
F
fatedier 已提交
19 20
	"fmt"
	"io"
F
fatedier 已提交
21
	"io/ioutil"
F
fatedier 已提交
22
	"net"
F
fatedier 已提交
23 24
	"strconv"
	"strings"
F
fatedier 已提交
25
	"sync"
26
	"time"
F
fatedier 已提交
27

F
fatedier 已提交
28
	"github.com/fatedier/frp/g"
F
fatedier 已提交
29
	"github.com/fatedier/frp/models/config"
F
fatedier 已提交
30
	"github.com/fatedier/frp/models/msg"
31
	"github.com/fatedier/frp/models/plugin"
F
fatedier 已提交
32 33 34
	"github.com/fatedier/frp/models/proto/udp"
	"github.com/fatedier/frp/utils/log"
	frpNet "github.com/fatedier/frp/utils/net"
F
fatedier 已提交
35 36

	"github.com/fatedier/golib/errors"
F
fatedier 已提交
37
	frpIo "github.com/fatedier/golib/io"
F
fatedier 已提交
38
	"github.com/fatedier/golib/pool"
F
fatedier 已提交
39
	fmux "github.com/hashicorp/yamux"
F
fatedier 已提交
40
	pp "github.com/pires/go-proxyproto"
F
fatedier 已提交
41 42
)

F
fatedier 已提交
43
// Proxy defines how to handle work connections for different proxy type.
F
fatedier 已提交
44
type Proxy interface {
F
fatedier 已提交
45
	Run() error
F
fatedier 已提交
46 47

	// InWorkConn accept work connections registered to server.
F
fatedier 已提交
48
	InWorkConn(frpNet.Conn, *msg.StartWorkConn)
F
fatedier 已提交
49

F
fatedier 已提交
50
	Close()
F
fatedier 已提交
51
	log.Logger
F
fatedier 已提交
52 53
}

F
fatedier 已提交
54
func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
F
fatedier 已提交
55
	baseProxy := BaseProxy{
F
fatedier 已提交
56
		Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
F
fatedier 已提交
57
	}
F
fatedier 已提交
58 59 60
	switch cfg := pxyConf.(type) {
	case *config.TcpProxyConf:
		pxy = &TcpProxy{
F
go vet  
fatedier 已提交
61
			BaseProxy: &baseProxy,
F
fatedier 已提交
62
			cfg:       cfg,
F
fatedier 已提交
63 64 65
		}
	case *config.UdpProxyConf:
		pxy = &UdpProxy{
F
go vet  
fatedier 已提交
66
			BaseProxy: &baseProxy,
F
fatedier 已提交
67
			cfg:       cfg,
F
fatedier 已提交
68 69 70
		}
	case *config.HttpProxyConf:
		pxy = &HttpProxy{
F
go vet  
fatedier 已提交
71
			BaseProxy: &baseProxy,
F
fatedier 已提交
72
			cfg:       cfg,
F
fatedier 已提交
73 74 75
		}
	case *config.HttpsProxyConf:
		pxy = &HttpsProxy{
F
go vet  
fatedier 已提交
76
			BaseProxy: &baseProxy,
F
fatedier 已提交
77
			cfg:       cfg,
F
fatedier 已提交
78
		}
F
fatedier 已提交
79 80
	case *config.StcpProxyConf:
		pxy = &StcpProxy{
F
go vet  
fatedier 已提交
81
			BaseProxy: &baseProxy,
F
fatedier 已提交
82 83
			cfg:       cfg,
		}
F
fatedier 已提交
84 85
	case *config.XtcpProxyConf:
		pxy = &XtcpProxy{
F
go vet  
fatedier 已提交
86
			BaseProxy: &baseProxy,
F
fatedier 已提交
87 88
			cfg:       cfg,
		}
F
fatedier 已提交
89 90 91 92
	}
	return
}

F
fatedier 已提交
93
type BaseProxy struct {
F
fatedier 已提交
94 95
	closed bool
	mu     sync.RWMutex
F
fatedier 已提交
96 97 98
	log.Logger
}

F
fatedier 已提交
99 100
// TCP
type TcpProxy struct {
F
go vet  
fatedier 已提交
101
	*BaseProxy
F
fatedier 已提交
102

103 104
	cfg         *config.TcpProxyConf
	proxyPlugin plugin.Plugin
F
fatedier 已提交
105 106
}

F
fatedier 已提交
107
func (pxy *TcpProxy) Run() (err error) {
108 109 110 111 112 113
	if pxy.cfg.Plugin != "" {
		pxy.proxyPlugin, err = plugin.Create(pxy.cfg.Plugin, pxy.cfg.PluginParams)
		if err != nil {
			return
		}
	}
F
fatedier 已提交
114
	return
F
fatedier 已提交
115 116 117
}

func (pxy *TcpProxy) Close() {
118 119 120
	if pxy.proxyPlugin != nil {
		pxy.proxyPlugin.Close()
	}
F
fatedier 已提交
121 122
}

F
fatedier 已提交
123
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
F
fatedier 已提交
124
	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
F
fatedier 已提交
125
		[]byte(g.GlbClientCfg.Token), m)
F
fatedier 已提交
126 127 128 129
}

// HTTP
type HttpProxy struct {
F
go vet  
fatedier 已提交
130
	*BaseProxy
F
fatedier 已提交
131

132 133
	cfg         *config.HttpProxyConf
	proxyPlugin plugin.Plugin
F
fatedier 已提交
134 135
}

F
fatedier 已提交
136
func (pxy *HttpProxy) Run() (err error) {
137 138 139 140 141 142
	if pxy.cfg.Plugin != "" {
		pxy.proxyPlugin, err = plugin.Create(pxy.cfg.Plugin, pxy.cfg.PluginParams)
		if err != nil {
			return
		}
	}
F
fatedier 已提交
143
	return
F
fatedier 已提交
144 145 146
}

func (pxy *HttpProxy) Close() {
147 148 149
	if pxy.proxyPlugin != nil {
		pxy.proxyPlugin.Close()
	}
F
fatedier 已提交
150 151
}

F
fatedier 已提交
152
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
F
fatedier 已提交
153
	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
F
fatedier 已提交
154
		[]byte(g.GlbClientCfg.Token), m)
F
fatedier 已提交
155 156 157 158
}

// HTTPS
type HttpsProxy struct {
F
go vet  
fatedier 已提交
159
	*BaseProxy
F
fatedier 已提交
160

161 162
	cfg         *config.HttpsProxyConf
	proxyPlugin plugin.Plugin
F
fatedier 已提交
163 164
}

F
fatedier 已提交
165
func (pxy *HttpsProxy) Run() (err error) {
166 167 168 169 170 171
	if pxy.cfg.Plugin != "" {
		pxy.proxyPlugin, err = plugin.Create(pxy.cfg.Plugin, pxy.cfg.PluginParams)
		if err != nil {
			return
		}
	}
F
fatedier 已提交
172
	return
F
fatedier 已提交
173 174 175
}

func (pxy *HttpsProxy) Close() {
176 177 178
	if pxy.proxyPlugin != nil {
		pxy.proxyPlugin.Close()
	}
F
fatedier 已提交
179 180
}

F
fatedier 已提交
181
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
F
fatedier 已提交
182
	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
F
fatedier 已提交
183
		[]byte(g.GlbClientCfg.Token), m)
F
fatedier 已提交
184 185
}

F
fatedier 已提交
186 187
// STCP
type StcpProxy struct {
F
go vet  
fatedier 已提交
188
	*BaseProxy
F
fatedier 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209

	cfg         *config.StcpProxyConf
	proxyPlugin plugin.Plugin
}

func (pxy *StcpProxy) Run() (err error) {
	if pxy.cfg.Plugin != "" {
		pxy.proxyPlugin, err = plugin.Create(pxy.cfg.Plugin, pxy.cfg.PluginParams)
		if err != nil {
			return
		}
	}
	return
}

func (pxy *StcpProxy) Close() {
	if pxy.proxyPlugin != nil {
		pxy.proxyPlugin.Close()
	}
}

F
fatedier 已提交
210
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
F
fatedier 已提交
211
	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
F
fatedier 已提交
212
		[]byte(g.GlbClientCfg.Token), m)
F
fatedier 已提交
213 214
}

F
fatedier 已提交
215 216
// XTCP
type XtcpProxy struct {
F
go vet  
fatedier 已提交
217
	*BaseProxy
F
fatedier 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238

	cfg         *config.XtcpProxyConf
	proxyPlugin plugin.Plugin
}

func (pxy *XtcpProxy) Run() (err error) {
	if pxy.cfg.Plugin != "" {
		pxy.proxyPlugin, err = plugin.Create(pxy.cfg.Plugin, pxy.cfg.PluginParams)
		if err != nil {
			return
		}
	}
	return
}

func (pxy *XtcpProxy) Close() {
	if pxy.proxyPlugin != nil {
		pxy.proxyPlugin.Close()
	}
}

F
fatedier 已提交
239
func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
F
fatedier 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252
	defer conn.Close()
	var natHoleSidMsg msg.NatHoleSid
	err := msg.ReadMsgInto(conn, &natHoleSidMsg)
	if err != nil {
		pxy.Error("xtcp read from workConn error: %v", err)
		return
	}

	natHoleClientMsg := &msg.NatHoleClient{
		ProxyName: pxy.cfg.ProxyName,
		Sid:       natHoleSidMsg.Sid,
	}
	raddr, _ := net.ResolveUDPAddr("udp",
F
fatedier 已提交
253
		fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerUdpPort))
F
fatedier 已提交
254 255 256 257 258 259 260 261 262
	clientConn, err := net.DialUDP("udp", nil, raddr)
	defer clientConn.Close()

	err = msg.WriteMsg(clientConn, natHoleClientMsg)
	if err != nil {
		pxy.Error("send natHoleClientMsg to server error: %v", err)
		return
	}

F
fatedier 已提交
263
	// Wait for client address at most 5 seconds.
F
fatedier 已提交
264
	var natHoleRespMsg msg.NatHoleResp
F
fatedier 已提交
265 266 267 268 269 270 271 272 273
	clientConn.SetReadDeadline(time.Now().Add(5 * time.Second))

	buf := pool.GetBuf(1024)
	n, err := clientConn.Read(buf)
	if err != nil {
		pxy.Error("get natHoleRespMsg error: %v", err)
		return
	}
	err = msg.ReadMsgInto(bytes.NewReader(buf[:n]), &natHoleRespMsg)
F
fatedier 已提交
274 275 276 277 278 279
	if err != nil {
		pxy.Error("get natHoleRespMsg error: %v", err)
		return
	}
	clientConn.SetReadDeadline(time.Time{})
	clientConn.Close()
280 281 282 283 284 285

	if natHoleRespMsg.Error != "" {
		pxy.Error("natHoleRespMsg get error info: %s", natHoleRespMsg.Error)
		return
	}

F
fatedier 已提交
286
	pxy.Trace("get natHoleRespMsg, sid [%s], client address [%s] visitor address [%s]", natHoleRespMsg.Sid, natHoleRespMsg.ClientAddr, natHoleRespMsg.VisitorAddr)
F
fatedier 已提交
287

F
fatedier 已提交
288 289 290 291 292
	// Send detect message
	array := strings.Split(natHoleRespMsg.VisitorAddr, ":")
	if len(array) <= 1 {
		pxy.Error("get NatHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr)
	}
F
fatedier 已提交
293
	laddr, _ := net.ResolveUDPAddr("udp", clientConn.LocalAddr().String())
F
fatedier 已提交
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	/*
		for i := 1000; i < 65000; i++ {
			pxy.sendDetectMsg(array[0], int64(i), laddr, "a")
		}
	*/
	port, err := strconv.ParseInt(array[1], 10, 64)
	if err != nil {
		pxy.Error("get natHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr)
		return
	}
	pxy.sendDetectMsg(array[0], int(port), laddr, []byte(natHoleRespMsg.Sid))
	pxy.Trace("send all detect msg done")

	msg.WriteMsg(conn, &msg.NatHoleClientDetectOK{})

	// Listen for clientConn's address and wait for visitor connection
	lConn, err := net.ListenUDP("udp", laddr)
F
fatedier 已提交
311
	if err != nil {
F
fatedier 已提交
312
		pxy.Error("listen on visitorConn's local adress error: %v", err)
F
fatedier 已提交
313 314
		return
	}
F
fatedier 已提交
315
	defer lConn.Close()
F
fatedier 已提交
316

F
fatedier 已提交
317 318 319 320
	lConn.SetReadDeadline(time.Now().Add(8 * time.Second))
	sidBuf := pool.GetBuf(1024)
	var uAddr *net.UDPAddr
	n, uAddr, err = lConn.ReadFromUDP(sidBuf)
F
fatedier 已提交
321
	if err != nil {
F
fatedier 已提交
322
		pxy.Warn("get sid from visitor error: %v", err)
F
fatedier 已提交
323 324
		return
	}
F
fatedier 已提交
325 326 327 328 329 330 331 332 333
	lConn.SetReadDeadline(time.Time{})
	if string(sidBuf[:n]) != natHoleRespMsg.Sid {
		pxy.Warn("incorrect sid from visitor")
		return
	}
	pool.PutBuf(sidBuf)
	pxy.Info("nat hole connection make success, sid [%s]", natHoleRespMsg.Sid)

	lConn.WriteToUDP(sidBuf[:n], uAddr)
F
fatedier 已提交
334

F
fatedier 已提交
335
	kcpConn, err := frpNet.NewKcpConnFromUdp(lConn, false, natHoleRespMsg.VisitorAddr)
F
fatedier 已提交
336 337 338 339 340
	if err != nil {
		pxy.Error("create kcp connection from udp connection error: %v", err)
		return
	}

F
fatedier 已提交
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	fmuxCfg := fmux.DefaultConfig()
	fmuxCfg.KeepAliveInterval = 5 * time.Second
	fmuxCfg.LogOutput = ioutil.Discard
	sess, err := fmux.Server(kcpConn, fmuxCfg)
	if err != nil {
		pxy.Error("create yamux server from kcp connection error: %v", err)
		return
	}
	defer sess.Close()
	muxConn, err := sess.Accept()
	if err != nil {
		pxy.Error("accept for yamux connection error: %v", err)
		return
	}

F
fatedier 已提交
356
	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf,
F
fatedier 已提交
357
		frpNet.WrapConn(muxConn), []byte(pxy.cfg.Sk), m)
F
fatedier 已提交
358 359
}

F
fatedier 已提交
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
func (pxy *XtcpProxy) sendDetectMsg(addr string, port int, laddr *net.UDPAddr, content []byte) (err error) {
	daddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", addr, port))
	if err != nil {
		return err
	}

	tConn, err := net.DialUDP("udp", laddr, daddr)
	if err != nil {
		return err
	}

	//uConn := ipv4.NewConn(tConn)
	//uConn.SetTTL(3)

	tConn.Write(content)
	tConn.Close()
	return nil
}

F
fatedier 已提交
379 380
// UDP
type UdpProxy struct {
F
go vet  
fatedier 已提交
381
	*BaseProxy
F
fatedier 已提交
382

F
fatedier 已提交
383
	cfg *config.UdpProxyConf
F
fatedier 已提交
384 385 386

	localAddr *net.UDPAddr
	readCh    chan *msg.UdpPacket
387 388 389 390

	// include msg.UdpPacket and msg.Ping
	sendCh   chan msg.Message
	workConn frpNet.Conn
F
fatedier 已提交
391 392
}

F
fatedier 已提交
393
func (pxy *UdpProxy) Run() (err error) {
F
fatedier 已提交
394 395 396 397
	pxy.localAddr, err = net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", pxy.cfg.LocalIp, pxy.cfg.LocalPort))
	if err != nil {
		return
	}
F
fatedier 已提交
398
	return
F
fatedier 已提交
399 400 401
}

func (pxy *UdpProxy) Close() {
F
fatedier 已提交
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
	pxy.mu.Lock()
	defer pxy.mu.Unlock()

	if !pxy.closed {
		pxy.closed = true
		if pxy.workConn != nil {
			pxy.workConn.Close()
		}
		if pxy.readCh != nil {
			close(pxy.readCh)
		}
		if pxy.sendCh != nil {
			close(pxy.sendCh)
		}
	}
F
fatedier 已提交
417 418
}

F
fatedier 已提交
419
func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
420
	pxy.Info("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String())
F
fatedier 已提交
421 422 423 424
	// close resources releated with old workConn
	pxy.Close()

	pxy.mu.Lock()
F
fatedier 已提交
425
	pxy.workConn = conn
426 427
	pxy.readCh = make(chan *msg.UdpPacket, 1024)
	pxy.sendCh = make(chan msg.Message, 1024)
F
fatedier 已提交
428 429
	pxy.closed = false
	pxy.mu.Unlock()
F
fatedier 已提交
430

431
	workConnReaderFn := func(conn net.Conn, readCh chan *msg.UdpPacket) {
F
fatedier 已提交
432 433 434 435 436 437 438
		for {
			var udpMsg msg.UdpPacket
			if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil {
				pxy.Warn("read from workConn for udp error: %v", errRet)
				return
			}
			if errRet := errors.PanicToError(func() {
F
fatedier 已提交
439
				pxy.Trace("get udp package from workConn: %s", udpMsg.Content)
440
				readCh <- &udpMsg
F
fatedier 已提交
441
			}); errRet != nil {
F
fatedier 已提交
442
				pxy.Info("reader goroutine for udp work connection closed: %v", errRet)
F
fatedier 已提交
443 444 445 446
				return
			}
		}
	}
447 448 449 450
	workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) {
		defer func() {
			pxy.Info("writer goroutine for udp work connection closed")
		}()
F
fatedier 已提交
451
		var errRet error
452 453 454 455 456 457 458 459 460
		for rawMsg := range sendCh {
			switch m := rawMsg.(type) {
			case *msg.UdpPacket:
				pxy.Trace("send udp package to workConn: %s", m.Content)
			case *msg.Ping:
				pxy.Trace("send ping message to udp workConn")
			}
			if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil {
				pxy.Error("udp work write error: %v", errRet)
F
fatedier 已提交
461 462 463 464
				return
			}
		}
	}
465 466 467 468 469 470 471 472
	heartbeatFn := func(conn net.Conn, sendCh chan msg.Message) {
		var errRet error
		for {
			time.Sleep(time.Duration(30) * time.Second)
			if errRet = errors.PanicToError(func() {
				sendCh <- &msg.Ping{}
			}); errRet != nil {
				pxy.Trace("heartbeat goroutine for udp work connection closed")
F
update  
fatedier 已提交
473
				break
474 475 476
			}
		}
	}
F
fatedier 已提交
477

478 479 480
	go workConnSenderFn(pxy.workConn, pxy.sendCh)
	go workConnReaderFn(pxy.workConn, pxy.readCh)
	go heartbeatFn(pxy.workConn, pxy.sendCh)
F
fatedier 已提交
481
	udp.Forwarder(pxy.localAddr, pxy.readCh, pxy.sendCh)
F
fatedier 已提交
482 483 484
}

// Common handler for tcp work connections.
485
func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.Plugin,
F
fatedier 已提交
486
	baseInfo *config.BaseProxyConf, workConn frpNet.Conn, encKey []byte, m *msg.StartWorkConn) {
F
fatedier 已提交
487

488 489 490 491
	var (
		remote io.ReadWriteCloser
		err    error
	)
F
fatedier 已提交
492
	remote = workConn
F
fatedier 已提交
493

F
fatedier 已提交
494
	if baseInfo.UseEncryption {
F
fatedier 已提交
495
		remote, err = frpIo.WithEncryption(remote, encKey)
F
fatedier 已提交
496
		if err != nil {
F
fatedier 已提交
497
			workConn.Close()
F
fatedier 已提交
498 499 500 501 502
			workConn.Error("create encryption stream error: %v", err)
			return
		}
	}
	if baseInfo.UseCompression {
F
fatedier 已提交
503
		remote = frpIo.WithCompression(remote)
F
fatedier 已提交
504
	}
505 506 507 508

	if proxyPlugin != nil {
		// if plugin is set, let plugin handle connections first
		workConn.Debug("handle by plugin: %s", proxyPlugin.Name())
509
		proxyPlugin.Handle(remote, workConn)
510 511 512
		workConn.Debug("handle by plugin finished")
		return
	} else {
F
fatedier 已提交
513
		localConn, err := frpNet.ConnectServer("tcp", fmt.Sprintf("%s:%d", localInfo.LocalIp, localInfo.LocalPort))
514
		if err != nil {
F
fatedier 已提交
515
			workConn.Close()
516 517 518 519 520 521
			workConn.Error("connect to local service [%s:%d] error: %v", localInfo.LocalIp, localInfo.LocalPort, err)
			return
		}

		workConn.Debug("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
			localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())
F
fatedier 已提交
522 523 524 525

		// check if we need to send proxy protocol info
		if baseInfo.ProxyProtocolVersion != "" {
			if m.SrcAddr != "" && m.SrcPort != 0 {
F
fatedier 已提交
526 527 528
				if m.DstAddr == "" {
					m.DstAddr = "127.0.0.1"
				}
F
fatedier 已提交
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
				h := &pp.Header{
					Command:            pp.PROXY,
					SourceAddress:      net.ParseIP(m.SrcAddr),
					SourcePort:         m.SrcPort,
					DestinationAddress: net.ParseIP(m.DstAddr),
					DestinationPort:    m.DstPort,
				}

				if h.SourceAddress.To16() == nil {
					h.TransportProtocol = pp.TCPv4
				} else {
					h.TransportProtocol = pp.TCPv6
				}

				if baseInfo.ProxyProtocolVersion == "v1" {
					h.Version = 1
				} else if baseInfo.ProxyProtocolVersion == "v2" {
					h.Version = 2
				}

				h.WriteTo(localConn)
			}
		}

F
fatedier 已提交
553
		frpIo.Join(localConn, remote)
554 555
		workConn.Debug("join connections closed")
	}
F
fatedier 已提交
556
}