mirror of
https://github.com/fatedier/frp.git
synced 2026-07-30 20:22:54 +08:00
Compare commits
6
Commits
c23894f156
...
cf396563f8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf396563f8 | ||
|
|
0b4f83cd04 | ||
|
|
e9f7a1a9f2 | ||
|
|
d644593342 | ||
|
|
427c4ca3ae | ||
|
|
f2d1f3739a |
+39
-25
@@ -16,6 +16,7 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -122,6 +123,33 @@ func (pxy *BaseProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapWorkConn applies rate limiting, encryption, and compression
|
||||||
|
// to a work connection based on the proxy's transport configuration.
|
||||||
|
// The returned recycle function should be called when the stream is no longer in use
|
||||||
|
// to return compression resources to the pool. It is safe to not call recycle,
|
||||||
|
// in which case resources will be garbage collected normally.
|
||||||
|
func (pxy *BaseProxy) wrapWorkConn(conn net.Conn, encKey []byte) (io.ReadWriteCloser, func(), error) {
|
||||||
|
var rwc io.ReadWriteCloser = conn
|
||||||
|
if pxy.limiter != nil {
|
||||||
|
rwc = libio.WrapReadWriteCloser(limit.NewReader(conn, pxy.limiter), limit.NewWriter(conn, pxy.limiter), func() error {
|
||||||
|
return conn.Close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if pxy.baseCfg.Transport.UseEncryption {
|
||||||
|
var err error
|
||||||
|
rwc, err = libio.WithEncryption(rwc, encKey)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, nil, fmt.Errorf("create encryption stream error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var recycleFn func()
|
||||||
|
if pxy.baseCfg.Transport.UseCompression {
|
||||||
|
rwc, recycleFn = libio.WithCompressionFromPool(rwc)
|
||||||
|
}
|
||||||
|
return rwc, recycleFn, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (pxy *BaseProxy) SetInWorkConnCallback(cb func(*v1.ProxyBaseConfig, net.Conn, *msg.StartWorkConn) bool) {
|
func (pxy *BaseProxy) SetInWorkConnCallback(cb func(*v1.ProxyBaseConfig, net.Conn, *msg.StartWorkConn) bool) {
|
||||||
pxy.inWorkConnCallback = cb
|
pxy.inWorkConnCallback = cb
|
||||||
}
|
}
|
||||||
@@ -139,30 +167,14 @@ func (pxy *BaseProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
|
|||||||
func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWorkConn, encKey []byte) {
|
func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWorkConn, encKey []byte) {
|
||||||
xl := pxy.xl
|
xl := pxy.xl
|
||||||
baseCfg := pxy.baseCfg
|
baseCfg := pxy.baseCfg
|
||||||
var (
|
|
||||||
remote io.ReadWriteCloser
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
remote = workConn
|
|
||||||
if pxy.limiter != nil {
|
|
||||||
remote = libio.WrapReadWriteCloser(limit.NewReader(workConn, pxy.limiter), limit.NewWriter(workConn, pxy.limiter), func() error {
|
|
||||||
return workConn.Close()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
xl.Tracef("handle tcp work connection, useEncryption: %t, useCompression: %t",
|
xl.Tracef("handle tcp work connection, useEncryption: %t, useCompression: %t",
|
||||||
baseCfg.Transport.UseEncryption, baseCfg.Transport.UseCompression)
|
baseCfg.Transport.UseEncryption, baseCfg.Transport.UseCompression)
|
||||||
if baseCfg.Transport.UseEncryption {
|
|
||||||
remote, err = libio.WithEncryption(remote, encKey)
|
remote, recycleFn, err := pxy.wrapWorkConn(workConn, encKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
workConn.Close()
|
xl.Errorf("wrap work connection: %v", err)
|
||||||
xl.Errorf("create encryption stream error: %v", err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var compressionResourceRecycleFn func()
|
|
||||||
if baseCfg.Transport.UseCompression {
|
|
||||||
remote, compressionResourceRecycleFn = libio.WithCompressionFromPool(remote)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we need to send proxy protocol info
|
// check if we need to send proxy protocol info
|
||||||
@@ -178,7 +190,6 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
|
|||||||
}
|
}
|
||||||
|
|
||||||
if baseCfg.Transport.ProxyProtocolVersion != "" && m.SrcAddr != "" && m.SrcPort != 0 {
|
if baseCfg.Transport.ProxyProtocolVersion != "" && m.SrcAddr != "" && m.SrcPort != 0 {
|
||||||
// Use the common proxy protocol builder function
|
|
||||||
header := netpkg.BuildProxyProtocolHeaderStruct(connInfo.SrcAddr, connInfo.DstAddr, baseCfg.Transport.ProxyProtocolVersion)
|
header := netpkg.BuildProxyProtocolHeaderStruct(connInfo.SrcAddr, connInfo.DstAddr, baseCfg.Transport.ProxyProtocolVersion)
|
||||||
connInfo.ProxyProtocolHeader = header
|
connInfo.ProxyProtocolHeader = header
|
||||||
}
|
}
|
||||||
@@ -187,12 +198,18 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
|
|||||||
|
|
||||||
if pxy.proxyPlugin != nil {
|
if pxy.proxyPlugin != nil {
|
||||||
// if plugin is set, let plugin handle connection first
|
// if plugin is set, let plugin handle connection first
|
||||||
|
// Don't recycle compression resources here because plugins may
|
||||||
|
// retain the connection after Handle returns.
|
||||||
xl.Debugf("handle by plugin: %s", pxy.proxyPlugin.Name())
|
xl.Debugf("handle by plugin: %s", pxy.proxyPlugin.Name())
|
||||||
pxy.proxyPlugin.Handle(pxy.ctx, &connInfo)
|
pxy.proxyPlugin.Handle(pxy.ctx, &connInfo)
|
||||||
xl.Debugf("handle by plugin finished")
|
xl.Debugf("handle by plugin finished")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if recycleFn != nil {
|
||||||
|
defer recycleFn()
|
||||||
|
}
|
||||||
|
|
||||||
localConn, err := libnet.Dial(
|
localConn, err := libnet.Dial(
|
||||||
net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)),
|
net.JoinHostPort(baseCfg.LocalIP, strconv.Itoa(baseCfg.LocalPort)),
|
||||||
libnet.WithTimeout(10*time.Second),
|
libnet.WithTimeout(10*time.Second),
|
||||||
@@ -220,7 +237,4 @@ func (pxy *BaseProxy) HandleTCPWorkConnection(workConn net.Conn, m *msg.StartWor
|
|||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
xl.Tracef("join connections errors: %v", errs)
|
xl.Tracef("join connections errors: %v", errs)
|
||||||
}
|
}
|
||||||
if compressionResourceRecycleFn != nil {
|
|
||||||
compressionResourceRecycleFn()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-22
@@ -17,7 +17,6 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -25,12 +24,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
libio "github.com/fatedier/golib/io"
|
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/msg"
|
"github.com/fatedier/frp/pkg/msg"
|
||||||
"github.com/fatedier/frp/pkg/proto/udp"
|
"github.com/fatedier/frp/pkg/proto/udp"
|
||||||
"github.com/fatedier/frp/pkg/util/limit"
|
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -83,27 +80,13 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
|||||||
xl := pxy.xl
|
xl := pxy.xl
|
||||||
xl.Infof("incoming a new work connection for sudp proxy, %s", conn.RemoteAddr().String())
|
xl.Infof("incoming a new work connection for sudp proxy, %s", conn.RemoteAddr().String())
|
||||||
|
|
||||||
var rwc io.ReadWriteCloser = conn
|
remote, _, err := pxy.wrapWorkConn(conn, pxy.encryptionKey)
|
||||||
var err error
|
if err != nil {
|
||||||
if pxy.limiter != nil {
|
xl.Errorf("wrap work connection: %v", err)
|
||||||
rwc = libio.WrapReadWriteCloser(limit.NewReader(conn, pxy.limiter), limit.NewWriter(conn, pxy.limiter), func() error {
|
return
|
||||||
return conn.Close()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if pxy.cfg.Transport.UseEncryption {
|
|
||||||
rwc, err = libio.WithEncryption(rwc, pxy.encryptionKey)
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
xl.Errorf("create encryption stream error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if pxy.cfg.Transport.UseCompression {
|
|
||||||
rwc = libio.WithCompression(rwc)
|
|
||||||
}
|
|
||||||
conn = netpkg.WrapReadWriteCloserToConn(rwc, conn)
|
|
||||||
|
|
||||||
workConn := conn
|
workConn := netpkg.WrapReadWriteCloserToConn(remote, conn)
|
||||||
readCh := make(chan *msg.UDPPacket, 1024)
|
readCh := make(chan *msg.UDPPacket, 1024)
|
||||||
sendCh := make(chan msg.Message, 1024)
|
sendCh := make(chan msg.Message, 1024)
|
||||||
isClose := false
|
isClose := false
|
||||||
|
|||||||
+5
-22
@@ -17,19 +17,16 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
libio "github.com/fatedier/golib/io"
|
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/msg"
|
"github.com/fatedier/frp/pkg/msg"
|
||||||
"github.com/fatedier/frp/pkg/proto/udp"
|
"github.com/fatedier/frp/pkg/proto/udp"
|
||||||
"github.com/fatedier/frp/pkg/util/limit"
|
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -94,28 +91,14 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, _ *msg.StartWorkConn) {
|
|||||||
// close resources related with old workConn
|
// close resources related with old workConn
|
||||||
pxy.Close()
|
pxy.Close()
|
||||||
|
|
||||||
var rwc io.ReadWriteCloser = conn
|
remote, _, err := pxy.wrapWorkConn(conn, pxy.encryptionKey)
|
||||||
var err error
|
if err != nil {
|
||||||
if pxy.limiter != nil {
|
xl.Errorf("wrap work connection: %v", err)
|
||||||
rwc = libio.WrapReadWriteCloser(limit.NewReader(conn, pxy.limiter), limit.NewWriter(conn, pxy.limiter), func() error {
|
return
|
||||||
return conn.Close()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if pxy.cfg.Transport.UseEncryption {
|
|
||||||
rwc, err = libio.WithEncryption(rwc, pxy.encryptionKey)
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
xl.Errorf("create encryption stream error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if pxy.cfg.Transport.UseCompression {
|
|
||||||
rwc = libio.WithCompression(rwc)
|
|
||||||
}
|
|
||||||
conn = netpkg.WrapReadWriteCloserToConn(rwc, conn)
|
|
||||||
|
|
||||||
pxy.mu.Lock()
|
pxy.mu.Lock()
|
||||||
pxy.workConn = conn
|
pxy.workConn = netpkg.WrapReadWriteCloserToConn(remote, conn)
|
||||||
pxy.readCh = make(chan *msg.UDPPacket, 1024)
|
pxy.readCh = make(chan *msg.UDPPacket, 1024)
|
||||||
pxy.sendCh = make(chan msg.Message, 1024)
|
pxy.sendCh = make(chan msg.Message, 1024)
|
||||||
pxy.closed = false
|
pxy.closed = false
|
||||||
|
|||||||
@@ -171,15 +171,14 @@ func Convert_ServerCommonConf_To_v1(conf *ServerCommonConf) *v1.ServerConfig {
|
|||||||
func transformHeadersFromPluginParams(params map[string]string) v1.HeaderOperations {
|
func transformHeadersFromPluginParams(params map[string]string) v1.HeaderOperations {
|
||||||
out := v1.HeaderOperations{}
|
out := v1.HeaderOperations{}
|
||||||
for k, v := range params {
|
for k, v := range params {
|
||||||
if !strings.HasPrefix(k, "plugin_header_") {
|
k, ok := strings.CutPrefix(k, "plugin_header_")
|
||||||
|
if !ok || k == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if k = strings.TrimPrefix(k, "plugin_header_"); k != "" {
|
if out.Set == nil {
|
||||||
if out.Set == nil {
|
out.Set = make(map[string]string)
|
||||||
out.Set = make(map[string]string)
|
|
||||||
}
|
|
||||||
out.Set[k] = v
|
|
||||||
}
|
}
|
||||||
|
out.Set[k] = v
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ func GetMapWithoutPrefix(set map[string]string, prefix string) map[string]string
|
|||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
|
|
||||||
for key, value := range set {
|
for key, value := range set {
|
||||||
if strings.HasPrefix(key, prefix) {
|
if trimmed, ok := strings.CutPrefix(key, prefix); ok {
|
||||||
m[strings.TrimPrefix(key, prefix)] = value
|
m[trimmed] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
package source
|
package source
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"maps"
|
||||||
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
@@ -97,21 +99,11 @@ func (a *Aggregator) mapsToSortedSlices(
|
|||||||
proxyMap map[string]v1.ProxyConfigurer,
|
proxyMap map[string]v1.ProxyConfigurer,
|
||||||
visitorMap map[string]v1.VisitorConfigurer,
|
visitorMap map[string]v1.VisitorConfigurer,
|
||||||
) ([]v1.ProxyConfigurer, []v1.VisitorConfigurer) {
|
) ([]v1.ProxyConfigurer, []v1.VisitorConfigurer) {
|
||||||
proxies := make([]v1.ProxyConfigurer, 0, len(proxyMap))
|
proxies := slices.SortedFunc(maps.Values(proxyMap), func(x, y v1.ProxyConfigurer) int {
|
||||||
for _, p := range proxyMap {
|
return cmp.Compare(x.GetBaseConfig().Name, y.GetBaseConfig().Name)
|
||||||
proxies = append(proxies, p)
|
|
||||||
}
|
|
||||||
sort.Slice(proxies, func(i, j int) bool {
|
|
||||||
return proxies[i].GetBaseConfig().Name < proxies[j].GetBaseConfig().Name
|
|
||||||
})
|
})
|
||||||
|
visitors := slices.SortedFunc(maps.Values(visitorMap), func(x, y v1.VisitorConfigurer) int {
|
||||||
visitors := make([]v1.VisitorConfigurer, 0, len(visitorMap))
|
return cmp.Compare(x.GetBaseConfig().Name, y.GetBaseConfig().Name)
|
||||||
for _, v := range visitorMap {
|
|
||||||
visitors = append(visitors, v)
|
|
||||||
}
|
|
||||||
sort.Slice(visitors, func(i, j int) bool {
|
|
||||||
return visitors[i].GetBaseConfig().Name < visitors[j].GetBaseConfig().Name
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return proxies, visitors
|
return proxies, visitors
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,6 +196,27 @@ func TestAggregator_VisitorMerge(t *testing.T) {
|
|||||||
require.Len(visitors, 2)
|
require.Len(visitors, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAggregator_Load_ReturnsSortedByName(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
agg := newTestAggregator(t, nil)
|
||||||
|
err := agg.ConfigSource().ReplaceAll(
|
||||||
|
[]v1.ProxyConfigurer{mockProxy("charlie"), mockProxy("alice"), mockProxy("bob")},
|
||||||
|
[]v1.VisitorConfigurer{mockVisitor("zulu"), mockVisitor("alpha")},
|
||||||
|
)
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
proxies, visitors, err := agg.Load()
|
||||||
|
require.NoError(err)
|
||||||
|
require.Len(proxies, 3)
|
||||||
|
require.Equal("alice", proxies[0].GetBaseConfig().Name)
|
||||||
|
require.Equal("bob", proxies[1].GetBaseConfig().Name)
|
||||||
|
require.Equal("charlie", proxies[2].GetBaseConfig().Name)
|
||||||
|
require.Len(visitors, 2)
|
||||||
|
require.Equal("alpha", visitors[0].GetBaseConfig().Name)
|
||||||
|
require.Equal("zulu", visitors[1].GetBaseConfig().Name)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAggregator_Load_ReturnsDefensiveCopies(t *testing.T) {
|
func TestAggregator_Load_ReturnsDefensiveCopies(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
|
|||||||
@@ -70,24 +70,18 @@ func (q *BandwidthQuantity) UnmarshalString(s string) error {
|
|||||||
f float64
|
f float64
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
switch {
|
if fstr, ok := strings.CutSuffix(s, "MB"); ok {
|
||||||
case strings.HasSuffix(s, "MB"):
|
|
||||||
base = MB
|
base = MB
|
||||||
fstr := strings.TrimSuffix(s, "MB")
|
|
||||||
f, err = strconv.ParseFloat(fstr, 64)
|
f, err = strconv.ParseFloat(fstr, 64)
|
||||||
if err != nil {
|
} else if fstr, ok := strings.CutSuffix(s, "KB"); ok {
|
||||||
return err
|
|
||||||
}
|
|
||||||
case strings.HasSuffix(s, "KB"):
|
|
||||||
base = KB
|
base = KB
|
||||||
fstr := strings.TrimSuffix(s, "KB")
|
|
||||||
f, err = strconv.ParseFloat(fstr, 64)
|
f, err = strconv.ParseFloat(fstr, 64)
|
||||||
if err != nil {
|
} else {
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("unit not support")
|
return errors.New("unit not support")
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
q.s = s
|
q.s = s
|
||||||
q.i = int64(f * float64(base))
|
q.i = int64(f * float64(base))
|
||||||
|
|||||||
@@ -39,6 +39,31 @@ func TestBandwidthQuantity(t *testing.T) {
|
|||||||
require.Equal(`{"b":"1KB","int":5}`, string(buf))
|
require.Equal(`{"b":"1KB","int":5}`, string(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBandwidthQuantity_MB(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
var w Wrap
|
||||||
|
err := json.Unmarshal([]byte(`{"b":"2MB","int":1}`), &w)
|
||||||
|
require.NoError(err)
|
||||||
|
require.EqualValues(2*MB, w.B.Bytes())
|
||||||
|
|
||||||
|
buf, err := json.Marshal(&w)
|
||||||
|
require.NoError(err)
|
||||||
|
require.Equal(`{"b":"2MB","int":1}`, string(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBandwidthQuantity_InvalidUnit(t *testing.T) {
|
||||||
|
var w Wrap
|
||||||
|
err := json.Unmarshal([]byte(`{"b":"1GB","int":1}`), &w)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBandwidthQuantity_InvalidNumber(t *testing.T) {
|
||||||
|
var w Wrap
|
||||||
|
err := json.Unmarshal([]byte(`{"b":"abcKB","int":1}`), &w)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPortsRangeSlice2String(t *testing.T) {
|
func TestPortsRangeSlice2String(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -16,9 +16,8 @@ func StripUserPrefix(user, name string) string {
|
|||||||
if user == "" {
|
if user == "" {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
prefix := user + "."
|
if trimmed, ok := strings.CutPrefix(name, user+"."); ok {
|
||||||
if strings.HasPrefix(name, prefix) {
|
return trimmed
|
||||||
return strings.TrimPrefix(name, prefix)
|
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,12 +70,8 @@ func ClassifyNATFeature(addresses []string, localIPs []string) (*NatFeature, err
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if portNum > portMax {
|
portMax = max(portMax, portNum)
|
||||||
portMax = portNum
|
portMin = min(portMin, portNum)
|
||||||
}
|
|
||||||
if portNum < portMin {
|
|
||||||
portMin = portNum
|
|
||||||
}
|
|
||||||
if baseIP != ip {
|
if baseIP != ip {
|
||||||
ipChanged = true
|
ipChanged = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
@@ -64,12 +65,7 @@ func (p *httpPlugin) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *httpPlugin) IsSupport(op string) bool {
|
func (p *httpPlugin) IsSupport(op string) bool {
|
||||||
for _, v := range p.options.Ops {
|
return slices.Contains(p.options.Ops, op)
|
||||||
if v == op {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *httpPlugin) Handle(ctx context.Context, op string, content any) (*Response, any, error) {
|
func (p *httpPlugin) Handle(ctx context.Context, op string, content any) (*Response, any, error) {
|
||||||
|
|||||||
@@ -63,11 +63,12 @@ func (l *Logger) AddPrefix(prefix LogPrefix) *Logger {
|
|||||||
if prefix.Priority <= 0 {
|
if prefix.Priority <= 0 {
|
||||||
prefix.Priority = 10
|
prefix.Priority = 10
|
||||||
}
|
}
|
||||||
for _, p := range l.prefixes {
|
for i, p := range l.prefixes {
|
||||||
if p.Name == prefix.Name {
|
if p.Name == prefix.Name {
|
||||||
found = true
|
found = true
|
||||||
p.Value = prefix.Value
|
l.prefixes[i].Value = prefix.Value
|
||||||
p.Priority = prefix.Priority
|
l.prefixes[i].Priority = prefix.Priority
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
|
|||||||
+10
-40
@@ -75,16 +75,21 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
addrs := make([]string, 0)
|
domains := make([]string, 0, len(pxy.cfg.CustomDomains)+1)
|
||||||
for _, domain := range pxy.cfg.CustomDomains {
|
for _, d := range pxy.cfg.CustomDomains {
|
||||||
if domain == "" {
|
if d != "" {
|
||||||
continue
|
domains = append(domains, d)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if pxy.cfg.SubDomain != "" {
|
||||||
|
domains = append(domains, pxy.cfg.SubDomain+"."+pxy.serverCfg.SubDomainHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs := make([]string, 0)
|
||||||
|
for _, domain := range domains {
|
||||||
routeConfig.Domain = domain
|
routeConfig.Domain = domain
|
||||||
for _, location := range locations {
|
for _, location := range locations {
|
||||||
routeConfig.Location = location
|
routeConfig.Location = location
|
||||||
|
|
||||||
tmpRouteConfig := routeConfig
|
tmpRouteConfig := routeConfig
|
||||||
|
|
||||||
// handle group
|
// handle group
|
||||||
@@ -93,12 +98,10 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
||||||
pxy.rc.HTTPGroupCtl.UnRegister(pxy.name, pxy.cfg.LoadBalancer.Group, tmpRouteConfig)
|
pxy.rc.HTTPGroupCtl.UnRegister(pxy.name, pxy.cfg.LoadBalancer.Group, tmpRouteConfig)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// no group
|
|
||||||
err = pxy.rc.HTTPReverseProxy.Register(routeConfig)
|
err = pxy.rc.HTTPReverseProxy.Register(routeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -112,39 +115,6 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
|
|||||||
routeConfig.Domain, routeConfig.Location, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser)
|
routeConfig.Domain, routeConfig.Location, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
|
||||||
routeConfig.Domain = pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
|
|
||||||
for _, location := range locations {
|
|
||||||
routeConfig.Location = location
|
|
||||||
|
|
||||||
tmpRouteConfig := routeConfig
|
|
||||||
|
|
||||||
// handle group
|
|
||||||
if pxy.cfg.LoadBalancer.Group != "" {
|
|
||||||
err = pxy.rc.HTTPGroupCtl.Register(pxy.name, pxy.cfg.LoadBalancer.Group, pxy.cfg.LoadBalancer.GroupKey, routeConfig)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
|
||||||
pxy.rc.HTTPGroupCtl.UnRegister(pxy.name, pxy.cfg.LoadBalancer.Group, tmpRouteConfig)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
err = pxy.rc.HTTPReverseProxy.Register(routeConfig)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
|
||||||
pxy.rc.HTTPReverseProxy.UnRegister(tmpRouteConfig)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
addrs = append(addrs, util.CanonicalAddr(tmpRouteConfig.Domain, pxy.serverCfg.VhostHTTPPort))
|
|
||||||
|
|
||||||
xl.Infof("http proxy listen for host [%s] location [%s] group [%s], routeByHTTPUser [%s]",
|
|
||||||
routeConfig.Domain, routeConfig.Location, pxy.cfg.LoadBalancer.Group, pxy.cfg.RouteByHTTPUser)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
remoteAddr = strings.Join(addrs, ",")
|
remoteAddr = strings.Join(addrs, ",")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-14
@@ -53,23 +53,18 @@ func (pxy *HTTPSProxy) Run() (remoteAddr string, err error) {
|
|||||||
pxy.Close()
|
pxy.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
addrs := make([]string, 0)
|
domains := make([]string, 0, len(pxy.cfg.CustomDomains)+1)
|
||||||
for _, domain := range pxy.cfg.CustomDomains {
|
for _, d := range pxy.cfg.CustomDomains {
|
||||||
if domain == "" {
|
if d != "" {
|
||||||
continue
|
domains = append(domains, d)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
l, err := pxy.listenForDomain(routeConfig, domain)
|
if pxy.cfg.SubDomain != "" {
|
||||||
if err != nil {
|
domains = append(domains, pxy.cfg.SubDomain+"."+pxy.serverCfg.SubDomainHost)
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
pxy.listeners = append(pxy.listeners, l)
|
|
||||||
addrs = append(addrs, util.CanonicalAddr(domain, pxy.serverCfg.VhostHTTPSPort))
|
|
||||||
xl.Infof("https proxy listen for host [%s] group [%s]", domain, pxy.cfg.LoadBalancer.Group)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
addrs := make([]string, 0)
|
||||||
domain := pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
|
for _, domain := range domains {
|
||||||
l, err := pxy.listenForDomain(routeConfig, domain)
|
l, err := pxy.listenForDomain(routeConfig, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
+10
-12
@@ -72,21 +72,19 @@ func (pxy *TCPMuxProxy) httpConnectListen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *TCPMuxProxy) httpConnectRun() (remoteAddr string, err error) {
|
func (pxy *TCPMuxProxy) httpConnectRun() (remoteAddr string, err error) {
|
||||||
addrs := make([]string, 0)
|
domains := make([]string, 0, len(pxy.cfg.CustomDomains)+1)
|
||||||
for _, domain := range pxy.cfg.CustomDomains {
|
for _, d := range pxy.cfg.CustomDomains {
|
||||||
if domain == "" {
|
if d != "" {
|
||||||
continue
|
domains = append(domains, d)
|
||||||
}
|
|
||||||
|
|
||||||
addrs, err = pxy.httpConnectListen(domain, pxy.cfg.RouteByHTTPUser, pxy.cfg.HTTPUser, pxy.cfg.HTTPPassword, addrs)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
if pxy.cfg.SubDomain != "" {
|
||||||
addrs, err = pxy.httpConnectListen(pxy.cfg.SubDomain+"."+pxy.serverCfg.SubDomainHost,
|
domains = append(domains, pxy.cfg.SubDomain+"."+pxy.serverCfg.SubDomainHost)
|
||||||
pxy.cfg.RouteByHTTPUser, pxy.cfg.HTTPUser, pxy.cfg.HTTPPassword, addrs)
|
}
|
||||||
|
|
||||||
|
addrs := make([]string, 0)
|
||||||
|
for _, domain := range domains {
|
||||||
|
addrs, err = pxy.httpConnectListen(domain, pxy.cfg.RouteByHTTPUser, pxy.cfg.HTTPUser, pxy.cfg.HTTPPassword, addrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user