mirror of
https://github.com/fatedier/frp.git
synced 2025-06-17 17:18:21 +00:00
Compare commits
5 Commits
9ce592ace3
...
28fa52f175
Author | SHA1 | Date | |
---|---|---|---|
|
28fa52f175 | ||
|
f3a71bc08f | ||
|
dd7e2e8473 | ||
|
07946e9752 | ||
|
a13b23e7ed |
@ -1,6 +1,6 @@
|
|||||||
service:
|
service:
|
||||||
golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly
|
golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly
|
||||||
|
|
||||||
run:
|
run:
|
||||||
concurrency: 4
|
concurrency: 4
|
||||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||||
@ -86,12 +86,8 @@ linters-settings:
|
|||||||
severity: "low"
|
severity: "low"
|
||||||
confidence: "low"
|
confidence: "low"
|
||||||
excludes:
|
excludes:
|
||||||
- G102
|
|
||||||
- G112
|
|
||||||
- G306
|
|
||||||
- G401
|
- G401
|
||||||
- G402
|
- G402
|
||||||
- G404
|
|
||||||
- G501
|
- G501
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
|
@ -1 +1,7 @@
|
|||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
* Show tcpmux proxies on the frps dashboard.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* When an HTTP proxy request times out, it returns 504 instead of 404 now.
|
||||||
|
File diff suppressed because one or more lines are too long
@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>frps dashboard</title>
|
<title>frps dashboard</title>
|
||||||
<script type="module" crossorigin src="./index-Q42Pu2_S.js"></script>
|
<script type="module" crossorigin src="./index-82-40HIG.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./index-rzPDshRD.css">
|
<link rel="stylesheet" crossorigin href="./index-rzPDshRD.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -253,7 +253,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(svr.configFilePath, body, 0o644); err != nil {
|
if err := os.WriteFile(svr.configFilePath, body, 0o600); err != nil {
|
||||||
res.Code = 500
|
res.Code = 500
|
||||||
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)
|
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)
|
||||||
log.Warnf("%s", res.Msg)
|
log.Warnf("%s", res.Msg)
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
libdial "github.com/fatedier/golib/net/dial"
|
libnet "github.com/fatedier/golib/net"
|
||||||
fmux "github.com/hashicorp/yamux"
|
fmux "github.com/hashicorp/yamux"
|
||||||
quic "github.com/quic-go/quic-go"
|
quic "github.com/quic-go/quic-go"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
@ -169,44 +169,44 @@ func (c *defaultConnectorImpl) realConnect() (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyType, addr, auth, err := libdial.ParseProxyURL(c.cfg.Transport.ProxyURL)
|
proxyType, addr, auth, err := libnet.ParseProxyURL(c.cfg.Transport.ProxyURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
xl.Errorf("fail to parse proxy url")
|
xl.Errorf("fail to parse proxy url")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dialOptions := []libdial.DialOption{}
|
dialOptions := []libnet.DialOption{}
|
||||||
protocol := c.cfg.Transport.Protocol
|
protocol := c.cfg.Transport.Protocol
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case "websocket":
|
case "websocket":
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")}))
|
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, "")}))
|
||||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
|
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
|
||||||
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
|
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
|
||||||
}))
|
}))
|
||||||
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
|
dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
|
||||||
case "wss":
|
case "wss":
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
dialOptions = append(dialOptions, libdial.WithTLSConfigAndPriority(100, tlsConfig))
|
dialOptions = append(dialOptions, libnet.WithTLSConfigAndPriority(100, tlsConfig))
|
||||||
// Make sure that if it is wss, the websocket hook is executed after the tls hook.
|
// Make sure that if it is wss, the websocket hook is executed after the tls hook.
|
||||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
|
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{Hook: netpkg.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
|
||||||
default:
|
default:
|
||||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
|
dialOptions = append(dialOptions, libnet.WithAfterHook(libnet.AfterHook{
|
||||||
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
|
Hook: netpkg.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(c.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
|
||||||
}))
|
}))
|
||||||
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
|
dialOptions = append(dialOptions, libnet.WithTLSConfig(tlsConfig))
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.cfg.Transport.ConnectServerLocalIP != "" {
|
if c.cfg.Transport.ConnectServerLocalIP != "" {
|
||||||
dialOptions = append(dialOptions, libdial.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP))
|
dialOptions = append(dialOptions, libnet.WithLocalAddr(c.cfg.Transport.ConnectServerLocalIP))
|
||||||
}
|
}
|
||||||
dialOptions = append(dialOptions,
|
dialOptions = append(dialOptions,
|
||||||
libdial.WithProtocol(protocol),
|
libnet.WithProtocol(protocol),
|
||||||
libdial.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second),
|
libnet.WithTimeout(time.Duration(c.cfg.Transport.DialServerTimeout)*time.Second),
|
||||||
libdial.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second),
|
libnet.WithKeepAlive(time.Duration(c.cfg.Transport.DialServerKeepAlive)*time.Second),
|
||||||
libdial.WithProxy(proxyType, addr),
|
libnet.WithProxy(proxyType, addr),
|
||||||
libdial.WithProxyAuth(auth),
|
libnet.WithProxyAuth(auth),
|
||||||
)
|
)
|
||||||
conn, err := libdial.DialContext(
|
conn, err := libnet.DialContext(
|
||||||
c.ctx,
|
c.ctx,
|
||||||
net.JoinHostPort(c.cfg.ServerAddr, strconv.Itoa(c.cfg.ServerPort)),
|
net.JoinHostPort(c.cfg.ServerAddr, strconv.Itoa(c.cfg.ServerPort)),
|
||||||
dialOptions...,
|
dialOptions...,
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
libio "github.com/fatedier/golib/io"
|
libio "github.com/fatedier/golib/io"
|
||||||
libdial "github.com/fatedier/golib/net/dial"
|
libnet "github.com/fatedier/golib/net"
|
||||||
pp "github.com/pires/go-proxyproto"
|
pp "github.com/pires/go-proxyproto"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
@ -197,9 +197,9 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
localConn, err := libdial.Dial(
|
localConn, err := libnet.Dial(
|
||||||
net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)),
|
net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)),
|
||||||
libdial.WithTimeout(10*time.Second),
|
libnet.WithTimeout(10*time.Second),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
|
@ -65,7 +65,7 @@ type Wrapper struct {
|
|||||||
// underlying proxy
|
// underlying proxy
|
||||||
pxy Proxy
|
pxy Proxy
|
||||||
|
|
||||||
// if ProxyConf has healcheck config
|
// if ProxyConf has health check config
|
||||||
// monitor will watch if it is alive
|
// monitor will watch if it is alive
|
||||||
monitor *health.Monitor
|
monitor *health.Monitor
|
||||||
|
|
||||||
|
@ -157,9 +157,9 @@ func (sv *XTCPVisitor) keepTunnelOpenWorker() {
|
|||||||
|
|
||||||
func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
|
func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
|
||||||
xl := xlog.FromContextSafe(sv.ctx)
|
xl := xlog.FromContextSafe(sv.ctx)
|
||||||
isConnTrasfered := false
|
isConnTransferred := false
|
||||||
defer func() {
|
defer func() {
|
||||||
if !isConnTrasfered {
|
if !isConnTransferred {
|
||||||
userConn.Close()
|
userConn.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -187,7 +187,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
|
|||||||
xl.Errorf("transfer connection to visitor %s error: %v", sv.cfg.FallbackTo, err)
|
xl.Errorf("transfer connection to visitor %s error: %v", sv.cfg.FallbackTo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
isConnTrasfered = true
|
isConnTransferred = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
go.mod
4
go.mod
@ -5,10 +5,10 @@ go 1.22
|
|||||||
require (
|
require (
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||||
github.com/coreos/go-oidc/v3 v3.10.0
|
github.com/coreos/go-oidc/v3 v3.10.0
|
||||||
github.com/fatedier/golib v0.4.3
|
github.com/fatedier/golib v0.5.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/gorilla/websocket v1.5.1
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/hashicorp/yamux v0.1.1
|
github.com/hashicorp/yamux v0.1.1
|
||||||
github.com/onsi/ginkgo/v2 v2.17.1
|
github.com/onsi/ginkgo/v2 v2.17.1
|
||||||
github.com/onsi/gomega v1.32.0
|
github.com/onsi/gomega v1.32.0
|
||||||
|
8
go.sum
8
go.sum
@ -24,8 +24,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatedier/golib v0.4.3 h1:eOcDBZauYqoNKwnJY9xWWa1pu7ff/JPZBizXeZOtj7k=
|
github.com/fatedier/golib v0.5.0 h1:hNcH7hgfIFqVWbP+YojCCAj4eO94pPf4dEF8lmq2jWs=
|
||||||
github.com/fatedier/golib v0.4.3/go.mod h1:W6kIYkIFxHsTzbgqg5piCxIiDo4LzwgTY6R5W8l9NFQ=
|
github.com/fatedier/golib v0.5.0/go.mod h1:W6kIYkIFxHsTzbgqg5piCxIiDo4LzwgTY6R5W8l9NFQ=
|
||||||
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo=
|
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo=
|
||||||
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||||
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
||||||
@ -64,8 +64,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
@ -19,11 +19,15 @@ package plugin
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
|
stdlog "log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
|
||||||
|
"github.com/fatedier/golib/pool"
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
|
"github.com/fatedier/frp/pkg/util/log"
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,7 +71,9 @@ func NewHTTP2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
|||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Transport: tr,
|
Transport: tr,
|
||||||
|
BufferPool: pool.NewBuffer(32 * 1024),
|
||||||
|
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
p.s = &http.Server{
|
p.s = &http.Server{
|
||||||
|
@ -54,7 +54,8 @@ func NewHTTPProxyPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hp.s = &http.Server{
|
hp.s = &http.Server{
|
||||||
Handler: hp,
|
Handler: hp,
|
||||||
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -20,12 +20,17 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
stdlog "log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatedier/golib/pool"
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/transport"
|
"github.com/fatedier/frp/pkg/transport"
|
||||||
|
"github.com/fatedier/frp/pkg/util/log"
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,10 +68,13 @@ func NewHTTPS2HTTPPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
|||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
BufferPool: pool.NewBuffer(32 * 1024),
|
||||||
|
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
p.s = &http.Server{
|
p.s = &http.Server{
|
||||||
Handler: rp,
|
Handler: rp,
|
||||||
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -20,12 +20,17 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
stdlog "log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatedier/golib/pool"
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/transport"
|
"github.com/fatedier/frp/pkg/transport"
|
||||||
|
"github.com/fatedier/frp/pkg/util/log"
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,11 +73,14 @@ func NewHTTPS2HTTPSPlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
|||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Transport: tr,
|
Transport: tr,
|
||||||
|
BufferPool: pool.NewBuffer(32 * 1024),
|
||||||
|
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
p.s = &http.Server{
|
p.s = &http.Server{
|
||||||
Handler: rp,
|
Handler: rp,
|
||||||
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -60,7 +60,8 @@ func NewStaticFilePlugin(options v1.ClientPluginOptions) (Plugin, error) {
|
|||||||
router.Use(netpkg.NewHTTPAuthMiddleware(opts.HTTPUser, opts.HTTPPassword).SetAuthFailDelay(200 * time.Millisecond).Middleware)
|
router.Use(netpkg.NewHTTPAuthMiddleware(opts.HTTPUser, opts.HTTPPassword).SetAuthFailDelay(200 * time.Millisecond).Middleware)
|
||||||
router.PathPrefix(prefix).Handler(netpkg.MakeHTTPGzipHandler(http.StripPrefix(prefix, http.FileServer(http.Dir(opts.LocalPath))))).Methods("GET")
|
router.PathPrefix(prefix).Handler(netpkg.MakeHTTPGzipHandler(http.StripPrefix(prefix, http.FileServer(http.Dir(opts.LocalPath))))).Methods("GET")
|
||||||
sp.s = &http.Server{
|
sp.s = &http.Server{
|
||||||
Handler: router,
|
Handler: router,
|
||||||
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
_ = sp.s.Serve(listener)
|
_ = sp.s.Serve(listener)
|
||||||
|
@ -15,11 +15,20 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/fatedier/golib/log"
|
"github.com/fatedier/golib/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
TraceLevel = log.TraceLevel
|
||||||
|
DebugLevel = log.DebugLevel
|
||||||
|
InfoLevel = log.InfoLevel
|
||||||
|
WarnLevel = log.WarnLevel
|
||||||
|
ErrorLevel = log.ErrorLevel
|
||||||
|
)
|
||||||
|
|
||||||
var Logger *log.Logger
|
var Logger *log.Logger
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -77,3 +86,24 @@ func Debugf(format string, v ...interface{}) {
|
|||||||
func Tracef(format string, v ...interface{}) {
|
func Tracef(format string, v ...interface{}) {
|
||||||
Logger.Tracef(format, v...)
|
Logger.Tracef(format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Logf(level log.Level, offset int, format string, v ...interface{}) {
|
||||||
|
Logger.Logf(level, offset, format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type WriteLogger struct {
|
||||||
|
level log.Level
|
||||||
|
offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWriteLogger(level log.Level, offset int) *WriteLogger {
|
||||||
|
return &WriteLogger{
|
||||||
|
level: level,
|
||||||
|
offset: offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WriteLogger) Write(p []byte) (n int, err error) {
|
||||||
|
Logger.Log(w.level, w.offset, string(bytes.TrimRight(p, "\n")))
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
@ -5,11 +5,11 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
libdial "github.com/fatedier/golib/net/dial"
|
libnet "github.com/fatedier/golib/net"
|
||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) libdial.AfterHookFunc {
|
func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) libnet.AfterHookFunc {
|
||||||
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
||||||
if enableTLS && !disableCustomTLSHeadByte {
|
if enableTLS && !disableCustomTLSHeadByte {
|
||||||
_, err := c.Write([]byte{byte(FRPTLSHeadByte)})
|
_, err := c.Write([]byte{byte(FRPTLSHeadByte)})
|
||||||
@ -21,7 +21,7 @@ func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) li
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DialHookWebsocket(protocol string, host string) libdial.AfterHookFunc {
|
func DialHookWebsocket(protocol string, host string) libnet.AfterHookFunc {
|
||||||
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
||||||
if protocol != "wss" {
|
if protocol != "wss" {
|
||||||
protocol = "ws"
|
protocol = "ws"
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
)
|
)
|
||||||
@ -39,8 +40,9 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
wl.server = &http.Server{
|
wl.server = &http.Server{
|
||||||
Addr: ln.Addr().String(),
|
Addr: ln.Addr().String(),
|
||||||
Handler: muxer,
|
Handler: muxer,
|
||||||
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
package vhost
|
package vhost
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
@ -116,10 +115,16 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
BufferPool: newWrapPool(),
|
BufferPool: pool.NewBuffer(32 * 1024),
|
||||||
ErrorLog: stdlog.New(newWrapLogger(), "", 0),
|
ErrorLog: stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
|
||||||
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
|
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||||
log.Warnf("do http proxy request [host: %s] error: %v", req.Host, err)
|
log.Logf(log.WarnLevel, 1, "do http proxy request [host: %s] error: %v", req.Host, err)
|
||||||
|
if err != nil {
|
||||||
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
||||||
|
rw.WriteHeader(http.StatusGatewayTimeout)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
rw.WriteHeader(http.StatusNotFound)
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
_, _ = rw.Write(getNotFoundPageContent())
|
_, _ = rw.Write(getNotFoundPageContent())
|
||||||
},
|
},
|
||||||
@ -322,20 +327,3 @@ func (rp *HTTPReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)
|
|||||||
rp.proxy.ServeHTTP(rw, newreq)
|
rp.proxy.ServeHTTP(rw, newreq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type wrapPool struct{}
|
|
||||||
|
|
||||||
func newWrapPool() *wrapPool { return &wrapPool{} }
|
|
||||||
|
|
||||||
func (p *wrapPool) Get() []byte { return pool.GetBuf(32 * 1024) }
|
|
||||||
|
|
||||||
func (p *wrapPool) Put(buf []byte) { pool.PutBuf(buf) }
|
|
||||||
|
|
||||||
type wrapLogger struct{}
|
|
||||||
|
|
||||||
func newWrapLogger() *wrapLogger { return &wrapLogger{} }
|
|
||||||
|
|
||||||
func (l *wrapLogger) Write(p []byte) (n int, err error) {
|
|
||||||
log.Warnf("%s", string(bytes.TrimRight(p, "\n")))
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
func TestGetHTTPSHostname(t *testing.T) {
|
func TestGetHTTPSHostname(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
l, err := net.Listen("tcp", ":")
|
l, err := net.Listen("tcp", "127.0.0.1:")
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
|
@ -146,7 +146,8 @@ type TCPOutConf struct {
|
|||||||
type TCPMuxOutConf struct {
|
type TCPMuxOutConf struct {
|
||||||
BaseOutConf
|
BaseOutConf
|
||||||
v1.DomainConfig
|
v1.DomainConfig
|
||||||
Multiplexer string `json:"multiplexer"`
|
Multiplexer string `json:"multiplexer"`
|
||||||
|
RouteByHTTPUser string `json:"routeByHTTPUser"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UDPOutConf struct {
|
type UDPOutConf struct {
|
||||||
|
@ -286,12 +286,13 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
|
|||||||
|
|
||||||
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPPort))
|
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPPort))
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Addr: address,
|
Addr: address,
|
||||||
Handler: rp,
|
Handler: rp,
|
||||||
|
ReadHeaderTimeout: 60 * time.Second,
|
||||||
}
|
}
|
||||||
var l net.Listener
|
var l net.Listener
|
||||||
if httpMuxOn {
|
if httpMuxOn {
|
||||||
l = svr.muxer.ListenHttp(1)
|
l = svr.muxer.ListenHTTP(1)
|
||||||
} else {
|
} else {
|
||||||
l, err = net.Listen("tcp", address)
|
l, err = net.Listen("tcp", address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -308,7 +309,7 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
|
|||||||
if cfg.VhostHTTPSPort > 0 {
|
if cfg.VhostHTTPSPort > 0 {
|
||||||
var l net.Listener
|
var l net.Listener
|
||||||
if httpsMuxOn {
|
if httpsMuxOn {
|
||||||
l = svr.muxer.ListenHttps(1)
|
l = svr.muxer.ListenHTTPS(1)
|
||||||
} else {
|
} else {
|
||||||
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPSPort))
|
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPSPort))
|
||||||
l, err = net.Listen("tcp", address)
|
l, err = net.Listen("tcp", address)
|
||||||
|
@ -260,7 +260,7 @@ func (f *Framework) SetEnvs(envs []string) {
|
|||||||
|
|
||||||
func (f *Framework) WriteTempFile(name string, content string) string {
|
func (f *Framework) WriteTempFile(name string, content string) string {
|
||||||
filePath := filepath.Join(f.TempDirectory, name)
|
filePath := filepath.Join(f.TempDirectory, name)
|
||||||
err := os.WriteFile(filePath, []byte(content), 0o766)
|
err := os.WriteFile(filePath, []byte(content), 0o600)
|
||||||
ExpectNoError(err)
|
ExpectNoError(err)
|
||||||
return filePath
|
return filePath
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str
|
|||||||
currentServerProcesses := make([]*process.Process, 0, len(serverTemplates))
|
currentServerProcesses := make([]*process.Process, 0, len(serverTemplates))
|
||||||
for i := range serverTemplates {
|
for i := range serverTemplates {
|
||||||
path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-server-%d", i))
|
path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-server-%d", i))
|
||||||
err = os.WriteFile(path, []byte(outs[i]), 0o666)
|
err = os.WriteFile(path, []byte(outs[i]), 0o600)
|
||||||
ExpectNoError(err)
|
ExpectNoError(err)
|
||||||
|
|
||||||
if TestContext.Debug {
|
if TestContext.Debug {
|
||||||
@ -48,7 +48,7 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str
|
|||||||
for i := range clientTemplates {
|
for i := range clientTemplates {
|
||||||
index := i + len(serverTemplates)
|
index := i + len(serverTemplates)
|
||||||
path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-client-%d", i))
|
path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-client-%d", i))
|
||||||
err = os.WriteFile(path, []byte(outs[index]), 0o666)
|
err = os.WriteFile(path, []byte(outs[index]), 0o600)
|
||||||
ExpectNoError(err)
|
ExpectNoError(err)
|
||||||
|
|
||||||
if TestContext.Debug {
|
if TestContext.Debug {
|
||||||
@ -94,7 +94,7 @@ func (f *Framework) RunFrpc(args ...string) (*process.Process, string, error) {
|
|||||||
func (f *Framework) GenerateConfigFile(content string) string {
|
func (f *Framework) GenerateConfigFile(content string) string {
|
||||||
f.configFileIndex++
|
f.configFileIndex++
|
||||||
path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-config-%d", f.configFileIndex))
|
path := filepath.Join(f.TempDirectory, fmt.Sprintf("frp-e2e-config-%d", f.configFileIndex))
|
||||||
err := os.WriteFile(path, []byte(content), 0o666)
|
err := os.WriteFile(path, []byte(content), 0o600)
|
||||||
ExpectNoError(err)
|
ExpectNoError(err)
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
libdial "github.com/fatedier/golib/net/dial"
|
libnet "github.com/fatedier/golib/net"
|
||||||
|
|
||||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||||
"github.com/fatedier/frp/test/e2e/pkg/rpc"
|
"github.com/fatedier/frp/test/e2e/pkg/rpc"
|
||||||
@ -160,11 +160,11 @@ func (r *Request) Do() (*Response, error) {
|
|||||||
if r.protocol != "tcp" {
|
if r.protocol != "tcp" {
|
||||||
return nil, fmt.Errorf("only tcp protocol is allowed for proxy")
|
return nil, fmt.Errorf("only tcp protocol is allowed for proxy")
|
||||||
}
|
}
|
||||||
proxyType, proxyAddress, auth, err := libdial.ParseProxyURL(r.proxyURL)
|
proxyType, proxyAddress, auth, err := libnet.ParseProxyURL(r.proxyURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse ProxyURL error: %v", err)
|
return nil, fmt.Errorf("parse ProxyURL error: %v", err)
|
||||||
}
|
}
|
||||||
conn, err = libdial.Dial(addr, libdial.WithProxy(proxyType, proxyAddress), libdial.WithProxyAuth(auth))
|
conn, err = libnet.Dial(addr, libnet.WithProxy(proxyType, proxyAddress), libnet.WithProxyAuth(auth))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/onsi/ginkgo/v2"
|
"github.com/onsi/ginkgo/v2"
|
||||||
@ -385,4 +386,48 @@ var _ = ginkgo.Describe("[Feature: HTTP]", func() {
|
|||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
framework.ExpectEqualValues(consts.TestString, string(msg))
|
framework.ExpectEqualValues(consts.TestString, string(msg))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ginkgo.It("vhostHTTPTimeout", func() {
|
||||||
|
vhostHTTPPort := f.AllocPort()
|
||||||
|
serverConf := getDefaultServerConf(vhostHTTPPort)
|
||||||
|
serverConf += `
|
||||||
|
vhostHTTPTimeout = 2
|
||||||
|
`
|
||||||
|
|
||||||
|
delayDuration := 0 * time.Second
|
||||||
|
localPort := f.AllocPort()
|
||||||
|
localServer := httpserver.New(
|
||||||
|
httpserver.WithBindPort(localPort),
|
||||||
|
httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
time.Sleep(delayDuration)
|
||||||
|
_, _ = w.Write([]byte(req.Host))
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
f.RunServer("", localServer)
|
||||||
|
|
||||||
|
clientConf := consts.DefaultClientConfig
|
||||||
|
clientConf += fmt.Sprintf(`
|
||||||
|
[[proxies]]
|
||||||
|
name = "test"
|
||||||
|
type = "http"
|
||||||
|
localPort = %d
|
||||||
|
customDomains = ["normal.example.com"]
|
||||||
|
`, localPort)
|
||||||
|
|
||||||
|
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
||||||
|
|
||||||
|
framework.NewRequestExpect(f).Port(vhostHTTPPort).
|
||||||
|
RequestModify(func(r *request.Request) {
|
||||||
|
r.HTTP().HTTPHost("normal.example.com").HTTP().Timeout(time.Second)
|
||||||
|
}).
|
||||||
|
ExpectResp([]byte("normal.example.com")).
|
||||||
|
Ensure()
|
||||||
|
|
||||||
|
delayDuration = 3 * time.Second
|
||||||
|
framework.NewRequestExpect(f).Port(vhostHTTPPort).
|
||||||
|
RequestModify(func(r *request.Request) {
|
||||||
|
r.HTTP().HTTPHost("normal.example.com").HTTP().Timeout(5 * time.Second)
|
||||||
|
}).
|
||||||
|
Ensure(framework.ExpectResponseCode(504))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
1
web/frps/components.d.ts
vendored
1
web/frps/components.d.ts
vendored
@ -31,6 +31,7 @@ declare module 'vue' {
|
|||||||
ProxiesSTCP: typeof import('./src/components/ProxiesSTCP.vue')['default']
|
ProxiesSTCP: typeof import('./src/components/ProxiesSTCP.vue')['default']
|
||||||
ProxiesSUDP: typeof import('./src/components/ProxiesSUDP.vue')['default']
|
ProxiesSUDP: typeof import('./src/components/ProxiesSUDP.vue')['default']
|
||||||
ProxiesTCP: typeof import('./src/components/ProxiesTCP.vue')['default']
|
ProxiesTCP: typeof import('./src/components/ProxiesTCP.vue')['default']
|
||||||
|
ProxiesTCPMux: typeof import('./src/components/ProxiesTCPMux.vue')['default']
|
||||||
ProxiesUDP: typeof import('./src/components/ProxiesUDP.vue')['default']
|
ProxiesUDP: typeof import('./src/components/ProxiesUDP.vue')['default']
|
||||||
ProxyView: typeof import('./src/components/ProxyView.vue')['default']
|
ProxyView: typeof import('./src/components/ProxyView.vue')['default']
|
||||||
ProxyViewExpand: typeof import('./src/components/ProxyViewExpand.vue')['default']
|
ProxyViewExpand: typeof import('./src/components/ProxyViewExpand.vue')['default']
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
<el-menu-item index="/proxies/udp">UDP</el-menu-item>
|
<el-menu-item index="/proxies/udp">UDP</el-menu-item>
|
||||||
<el-menu-item index="/proxies/http">HTTP</el-menu-item>
|
<el-menu-item index="/proxies/http">HTTP</el-menu-item>
|
||||||
<el-menu-item index="/proxies/https">HTTPS</el-menu-item>
|
<el-menu-item index="/proxies/https">HTTPS</el-menu-item>
|
||||||
|
<el-menu-item index="/proxies/tcpmux">TCPMUX</el-menu-item>
|
||||||
<el-menu-item index="/proxies/stcp">STCP</el-menu-item>
|
<el-menu-item index="/proxies/stcp">STCP</el-menu-item>
|
||||||
<el-menu-item index="/proxies/sudp">SUDP</el-menu-item>
|
<el-menu-item index="/proxies/sudp">SUDP</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
|
38
web/frps/src/components/ProxiesTCPMux.vue
Normal file
38
web/frps/src/components/ProxiesTCPMux.vue
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<ProxyView :proxies="proxies" proxyType="tcpmux" @refresh="fetchData" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { TCPMuxProxy } from '../utils/proxy.js'
|
||||||
|
import ProxyView from './ProxyView.vue'
|
||||||
|
|
||||||
|
let proxies = ref<TCPMuxProxy[]>([])
|
||||||
|
|
||||||
|
const fetchData = () => {
|
||||||
|
let tcpmuxHTTPConnectPort: number
|
||||||
|
let subdomainHost: string
|
||||||
|
fetch('../api/serverinfo', { credentials: 'include' })
|
||||||
|
.then((res) => {
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
tcpmuxHTTPConnectPort = json.tcpmuxHTTPConnectPort
|
||||||
|
subdomainHost = json.subdomainHost
|
||||||
|
|
||||||
|
fetch('../api/proxy/tcpmux', { credentials: 'include' })
|
||||||
|
.then((res) => {
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
proxies.value = []
|
||||||
|
for (let proxyStats of json.proxies) {
|
||||||
|
proxies.value.push(new TCPMuxProxy(proxyStats, tcpmuxHTTPConnectPort, subdomainHost))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fetchData()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form
|
<el-form
|
||||||
label-position="left"
|
label-position="left"
|
||||||
|
label-width="auto"
|
||||||
inline
|
inline
|
||||||
class="proxy-table-expand"
|
class="proxy-table-expand"
|
||||||
v-if="proxyType === 'http' || proxyType === 'https'"
|
|
||||||
>
|
>
|
||||||
<el-form-item label="Name">
|
<el-form-item label="Name">
|
||||||
<span>{{ row.name }}</span>
|
<span>{{ row.name }}</span>
|
||||||
@ -11,18 +11,6 @@
|
|||||||
<el-form-item label="Type">
|
<el-form-item label="Type">
|
||||||
<span>{{ row.type }}</span>
|
<span>{{ row.type }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Domains">
|
|
||||||
<span>{{ row.customDomains }}</span>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="SubDomain">
|
|
||||||
<span>{{ row.subdomain }}</span>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="locations">
|
|
||||||
<span>{{ row.locations }}</span>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="HostRewrite">
|
|
||||||
<span>{{ row.hostHeaderRewrite }}</span>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="Encryption">
|
<el-form-item label="Encryption">
|
||||||
<span>{{ row.encryption }}</span>
|
<span>{{ row.encryption }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -35,30 +23,40 @@
|
|||||||
<el-form-item label="Last Close">
|
<el-form-item label="Last Close">
|
||||||
<span>{{ row.lastCloseTime }}</span>
|
<span>{{ row.lastCloseTime }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
|
||||||
|
|
||||||
<el-form label-position="left" inline class="proxy-table-expand" v-else>
|
<div v-if="proxyType === 'http' || proxyType === 'https'">
|
||||||
<el-form-item label="Name">
|
<el-form-item label="Domains">
|
||||||
<span>{{ row.name }}</span>
|
<span>{{ row.customDomains }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Type">
|
<el-form-item label="SubDomain">
|
||||||
<span>{{ row.type }}</span>
|
<span>{{ row.subdomain }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Addr">
|
<el-form-item label="locations">
|
||||||
<span>{{ row.addr }}</span>
|
<span>{{ row.locations }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Encryption">
|
<el-form-item label="HostRewrite">
|
||||||
<span>{{ row.encryption }}</span>
|
<span>{{ row.hostHeaderRewrite }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Compression">
|
</div>
|
||||||
<span>{{ row.compression }}</span>
|
<div v-else-if="proxyType === 'tcpmux'">
|
||||||
</el-form-item>
|
<el-form-item label="Multiplexer">
|
||||||
<el-form-item label="Last Start">
|
<span>{{ row.multiplexer }}</span>
|
||||||
<span>{{ row.lastStartTime }}</span>
|
</el-form-item>
|
||||||
</el-form-item>
|
<el-form-item label="RouteByHTTPUser">
|
||||||
<el-form-item label="Last Close">
|
<span>{{ row.routeByHTTPUser }}</span>
|
||||||
<span>{{ row.lastCloseTime }}</span>
|
</el-form-item>
|
||||||
</el-form-item>
|
<el-form-item label="Domains">
|
||||||
|
<span>{{ row.customDomains }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="SubDomain">
|
||||||
|
<span>{{ row.subdomain }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<el-form-item label="Addr">
|
||||||
|
<span>{{ row.addr }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<div v-if="row.annotations && row.annotations.size > 0">
|
<div v-if="row.annotations && row.annotations.size > 0">
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
<el-form-item label="QUIC Bind Port" v-if="data.quicBindPort != 0">
|
<el-form-item label="QUIC Bind Port" v-if="data.quicBindPort != 0">
|
||||||
<span>{{ data.quicBindPort }}</span>
|
<span>{{ data.quicBindPort }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Http Port" v-if="data.vhostHTTPPort != 0">
|
<el-form-item label="HTTP Port" v-if="data.vhostHTTPPort != 0">
|
||||||
<span>{{ data.vhostHTTPPort }}</span>
|
<span>{{ data.vhostHTTPPort }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Https Port" v-if="data.vhostHTTPSPort != 0">
|
<el-form-item label="HTTPS Port" v-if="data.vhostHTTPSPort != 0">
|
||||||
<span>{{ data.vhostHTTPSPort }}</span>
|
<span>{{ data.vhostHTTPSPort }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
|
@ -4,6 +4,7 @@ import ProxiesTCP from '../components/ProxiesTCP.vue'
|
|||||||
import ProxiesUDP from '../components/ProxiesUDP.vue'
|
import ProxiesUDP from '../components/ProxiesUDP.vue'
|
||||||
import ProxiesHTTP from '../components/ProxiesHTTP.vue'
|
import ProxiesHTTP from '../components/ProxiesHTTP.vue'
|
||||||
import ProxiesHTTPS from '../components/ProxiesHTTPS.vue'
|
import ProxiesHTTPS from '../components/ProxiesHTTPS.vue'
|
||||||
|
import ProxiesTCPMux from '../components/ProxiesTCPMux.vue'
|
||||||
import ProxiesSTCP from '../components/ProxiesSTCP.vue'
|
import ProxiesSTCP from '../components/ProxiesSTCP.vue'
|
||||||
import ProxiesSUDP from '../components/ProxiesSUDP.vue'
|
import ProxiesSUDP from '../components/ProxiesSUDP.vue'
|
||||||
|
|
||||||
@ -35,6 +36,11 @@ const router = createRouter({
|
|||||||
name: 'ProxiesHTTPS',
|
name: 'ProxiesHTTPS',
|
||||||
component: ProxiesHTTPS,
|
component: ProxiesHTTPS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/proxies/tcpmux',
|
||||||
|
name: 'ProxiesTCPMux',
|
||||||
|
component: ProxiesTCPMux,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/proxies/stcp',
|
path: '/proxies/stcp',
|
||||||
name: 'ProxiesSTCP',
|
name: 'ProxiesSTCP',
|
||||||
|
@ -110,6 +110,28 @@ class HTTPSProxy extends BaseProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TCPMuxProxy extends BaseProxy {
|
||||||
|
multiplexer: string
|
||||||
|
routeByHTTPUser: string
|
||||||
|
|
||||||
|
constructor(proxyStats: any, port: number, subdomainHost: string) {
|
||||||
|
super(proxyStats)
|
||||||
|
this.type = 'tcpmux'
|
||||||
|
this.port = port
|
||||||
|
this.multiplexer = ''
|
||||||
|
this.routeByHTTPUser = ''
|
||||||
|
|
||||||
|
if (proxyStats.conf) {
|
||||||
|
this.customDomains = proxyStats.conf.customDomains || this.customDomains
|
||||||
|
this.multiplexer = proxyStats.conf.multiplexer
|
||||||
|
this.routeByHTTPUser = proxyStats.conf.routeByHTTPUser
|
||||||
|
if (proxyStats.conf.subdomain) {
|
||||||
|
this.subdomain = `${proxyStats.conf.subdomain}.${subdomainHost}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class STCPProxy extends BaseProxy {
|
class STCPProxy extends BaseProxy {
|
||||||
constructor(proxyStats: any) {
|
constructor(proxyStats: any) {
|
||||||
super(proxyStats)
|
super(proxyStats)
|
||||||
@ -128,6 +150,7 @@ export {
|
|||||||
BaseProxy,
|
BaseProxy,
|
||||||
TCPProxy,
|
TCPProxy,
|
||||||
UDPProxy,
|
UDPProxy,
|
||||||
|
TCPMuxProxy,
|
||||||
HTTPProxy,
|
HTTPProxy,
|
||||||
HTTPSProxy,
|
HTTPSProxy,
|
||||||
STCPProxy,
|
STCPProxy,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user