mirror of
https://github.com/fatedier/frp.git
synced 2025-01-05 21:49:10 +01:00
support more proxy type
This commit is contained in:
parent
f90028cf96
commit
b02e1007fb
6
.github/ISSUE_TEMPLATE
vendored
6
.github/ISSUE_TEMPLATE
vendored
@ -1,3 +1,5 @@
|
|||||||
|
Issue is only used for submiting bug report and documents typo. If there are same issues or answers can be found in documents, we will close it directly.
|
||||||
|
|
||||||
Please answer these questions before submitting your issue. Thanks!
|
Please answer these questions before submitting your issue. Thanks!
|
||||||
|
|
||||||
1. What did you do?
|
1. What did you do?
|
||||||
@ -13,3 +15,7 @@ If possible, provide a recipe for reproducing the error.
|
|||||||
|
|
||||||
|
|
||||||
4. What version of frp are you using (./frpc -v or ./frps -v)?
|
4. What version of frp are you using (./frpc -v or ./frps -v)?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
5. Can you point out what caused this issue (optional)?
|
||||||
|
@ -208,11 +208,7 @@ func (ctl *Control) reader() {
|
|||||||
}()
|
}()
|
||||||
defer close(ctl.closedCh)
|
defer close(ctl.closedCh)
|
||||||
|
|
||||||
encReader, err := crypto.NewReader(ctl.conn, []byte(config.ClientCommonCfg.PrivilegeToken))
|
encReader := crypto.NewReader(ctl.conn, []byte(config.ClientCommonCfg.PrivilegeToken))
|
||||||
if err != nil {
|
|
||||||
ctl.conn.Error("crypto new reader error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for {
|
for {
|
||||||
if m, err := msg.ReadMsg(encReader); err != nil {
|
if m, err := msg.ReadMsg(encReader); err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
|
106
client/proxy.go
106
client/proxy.go
@ -72,27 +72,41 @@ func (pxy *TcpProxy) Close() {
|
|||||||
|
|
||||||
func (pxy *TcpProxy) InWorkConn(conn net.Conn) {
|
func (pxy *TcpProxy) InWorkConn(conn net.Conn) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
localConn, err := net.ConnectTcpServer(fmt.Sprintf("%s:%d", pxy.cfg.LocalIp, pxy.cfg.LocalPort))
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, &pxy.cfg.BaseProxyConf, conn)
|
||||||
if err != nil {
|
}
|
||||||
conn.Error("connect to local service [%s:%d] error: %v", pxy.cfg.LocalIp, pxy.cfg.LocalPort, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var remote io.ReadWriteCloser
|
// HTTP
|
||||||
remote = conn
|
type HttpProxy struct {
|
||||||
if pxy.cfg.UseEncryption {
|
cfg *config.HttpProxyConf
|
||||||
remote, err = tcp.WithEncryption(remote, []byte(config.ClientCommonCfg.PrivilegeToken))
|
ctl *Control
|
||||||
if err != nil {
|
}
|
||||||
conn.Error("create encryption stream error: %v", err)
|
|
||||||
return
|
func (pxy *HttpProxy) Run() {
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if pxy.cfg.UseCompression {
|
func (pxy *HttpProxy) Close() {
|
||||||
remote = tcp.WithCompression(remote)
|
}
|
||||||
}
|
|
||||||
conn.Debug("join connections")
|
func (pxy *HttpProxy) InWorkConn(conn net.Conn) {
|
||||||
tcp.Join(localConn, remote)
|
defer conn.Close()
|
||||||
conn.Debug("join connections closed")
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, &pxy.cfg.BaseProxyConf, conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPS
|
||||||
|
type HttpsProxy struct {
|
||||||
|
cfg *config.HttpsProxyConf
|
||||||
|
ctl *Control
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pxy *HttpsProxy) Run() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pxy *HttpsProxy) Close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pxy *HttpsProxy) InWorkConn(conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, &pxy.cfg.BaseProxyConf, conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UDP
|
// UDP
|
||||||
@ -111,34 +125,28 @@ func (pxy *UdpProxy) InWorkConn(conn net.Conn) {
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP
|
// Common handler for tcp work connections.
|
||||||
type HttpProxy struct {
|
func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, baseInfo *config.BaseProxyConf, workConn net.Conn) {
|
||||||
cfg *config.HttpProxyConf
|
localConn, err := net.ConnectTcpServer(fmt.Sprintf("%s:%d", localInfo.LocalIp, localInfo.LocalPort))
|
||||||
ctl *Control
|
if err != nil {
|
||||||
}
|
workConn.Error("connect to local service [%s:%d] error: %v", localInfo.LocalIp, localInfo.LocalPort, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (pxy *HttpProxy) Run() {
|
var remote io.ReadWriteCloser
|
||||||
}
|
remote = workConn
|
||||||
|
if baseInfo.UseEncryption {
|
||||||
func (pxy *HttpProxy) Close() {
|
remote, err = tcp.WithEncryption(remote, []byte(config.ClientCommonCfg.PrivilegeToken))
|
||||||
}
|
if err != nil {
|
||||||
|
workConn.Error("create encryption stream error: %v", err)
|
||||||
func (pxy *HttpProxy) InWorkConn(conn net.Conn) {
|
return
|
||||||
defer conn.Close()
|
}
|
||||||
}
|
}
|
||||||
|
if baseInfo.UseCompression {
|
||||||
// HTTPS
|
remote = tcp.WithCompression(remote)
|
||||||
type HttpsProxy struct {
|
}
|
||||||
cfg *config.HttpsProxyConf
|
workConn.Debug("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
|
||||||
ctl *Control
|
localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
||||||
}
|
tcp.Join(localConn, remote)
|
||||||
|
workConn.Debug("join connections closed")
|
||||||
func (pxy *HttpsProxy) Run() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pxy *HttpsProxy) Close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pxy *HttpsProxy) InWorkConn(conn net.Conn) {
|
|
||||||
defer conn.Close()
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -25,6 +26,27 @@ import (
|
|||||||
ini "github.com/vaughan0/go-ini"
|
ini "github.com/vaughan0/go-ini"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var proxyConfTypeMap map[string]reflect.Type
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proxyConfTypeMap = make(map[string]reflect.Type)
|
||||||
|
proxyConfTypeMap[consts.TcpProxy] = reflect.TypeOf(TcpProxyConf{})
|
||||||
|
proxyConfTypeMap[consts.UdpProxy] = reflect.TypeOf(UdpProxyConf{})
|
||||||
|
proxyConfTypeMap[consts.HttpProxy] = reflect.TypeOf(HttpProxyConf{})
|
||||||
|
proxyConfTypeMap[consts.HttpsProxy] = reflect.TypeOf(HttpsProxyConf{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfByType creates a empty ProxyConf object by proxyType.
|
||||||
|
// If proxyType isn't exist, return nil.
|
||||||
|
func NewConfByType(proxyType string) ProxyConf {
|
||||||
|
v, ok := proxyConfTypeMap[proxyType]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cfg := reflect.New(v).Interface().(ProxyConf)
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
type ProxyConf interface {
|
type ProxyConf interface {
|
||||||
GetName() string
|
GetName() string
|
||||||
GetBaseInfo() *BaseProxyConf
|
GetBaseInfo() *BaseProxyConf
|
||||||
@ -38,16 +60,9 @@ func NewProxyConf(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
|
|||||||
if pMsg.ProxyType == "" {
|
if pMsg.ProxyType == "" {
|
||||||
pMsg.ProxyType = consts.TcpProxy
|
pMsg.ProxyType = consts.TcpProxy
|
||||||
}
|
}
|
||||||
switch pMsg.ProxyType {
|
|
||||||
case consts.TcpProxy:
|
cfg = NewConfByType(pMsg.ProxyType)
|
||||||
cfg = &TcpProxyConf{}
|
if cfg == nil {
|
||||||
case consts.UdpProxy:
|
|
||||||
cfg = &UdpProxyConf{}
|
|
||||||
case consts.HttpProxy:
|
|
||||||
cfg = &HttpProxyConf{}
|
|
||||||
case consts.HttpsProxy:
|
|
||||||
cfg = &HttpsProxyConf{}
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("proxy [%s] type [%s] error", pMsg.ProxyName, pMsg.ProxyType)
|
err = fmt.Errorf("proxy [%s] type [%s] error", pMsg.ProxyName, pMsg.ProxyType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -62,16 +77,8 @@ func NewProxyConfFromFile(name string, section ini.Section) (cfg ProxyConf, err
|
|||||||
proxyType = consts.TcpProxy
|
proxyType = consts.TcpProxy
|
||||||
section["type"] = consts.TcpProxy
|
section["type"] = consts.TcpProxy
|
||||||
}
|
}
|
||||||
switch proxyType {
|
cfg = NewConfByType(proxyType)
|
||||||
case consts.TcpProxy:
|
if cfg == nil {
|
||||||
cfg = &TcpProxyConf{}
|
|
||||||
case consts.UdpProxy:
|
|
||||||
cfg = &UdpProxyConf{}
|
|
||||||
case consts.HttpProxy:
|
|
||||||
cfg = &HttpProxyConf{}
|
|
||||||
case consts.HttpsProxy:
|
|
||||||
cfg = &HttpsProxyConf{}
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("proxy [%s] type [%s] error", name, proxyType)
|
err = fmt.Errorf("proxy [%s] type [%s] error", name, proxyType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -223,7 +230,6 @@ func (cfg *DomainConf) check() (err error) {
|
|||||||
if strings.Contains(cfg.SubDomain, ".") || strings.Contains(cfg.SubDomain, "*") {
|
if strings.Contains(cfg.SubDomain, ".") || strings.Contains(cfg.SubDomain, "*") {
|
||||||
return fmt.Errorf("'.' and '*' is not supported in subdomain")
|
return fmt.Errorf("'.' and '*' is not supported in subdomain")
|
||||||
}
|
}
|
||||||
cfg.SubDomain += "." + ServerCommonCfg.SubDomainHost
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -37,25 +37,21 @@ func init() {
|
|||||||
TypeMap = make(map[byte]reflect.Type)
|
TypeMap = make(map[byte]reflect.Type)
|
||||||
TypeStringMap = make(map[reflect.Type]byte)
|
TypeStringMap = make(map[reflect.Type]byte)
|
||||||
|
|
||||||
TypeMap[TypeLogin] = getTypeFn((*Login)(nil))
|
TypeMap[TypeLogin] = reflect.TypeOf(Login{})
|
||||||
TypeMap[TypeLoginResp] = getTypeFn((*LoginResp)(nil))
|
TypeMap[TypeLoginResp] = reflect.TypeOf(LoginResp{})
|
||||||
TypeMap[TypeNewProxy] = getTypeFn((*NewProxy)(nil))
|
TypeMap[TypeNewProxy] = reflect.TypeOf(NewProxy{})
|
||||||
TypeMap[TypeNewProxyResp] = getTypeFn((*NewProxyResp)(nil))
|
TypeMap[TypeNewProxyResp] = reflect.TypeOf(NewProxyResp{})
|
||||||
TypeMap[TypeNewWorkConn] = getTypeFn((*NewWorkConn)(nil))
|
TypeMap[TypeNewWorkConn] = reflect.TypeOf(NewWorkConn{})
|
||||||
TypeMap[TypeReqWorkConn] = getTypeFn((*ReqWorkConn)(nil))
|
TypeMap[TypeReqWorkConn] = reflect.TypeOf(ReqWorkConn{})
|
||||||
TypeMap[TypeStartWorkConn] = getTypeFn((*StartWorkConn)(nil))
|
TypeMap[TypeStartWorkConn] = reflect.TypeOf(StartWorkConn{})
|
||||||
TypeMap[TypePing] = getTypeFn((*Ping)(nil))
|
TypeMap[TypePing] = reflect.TypeOf(Ping{})
|
||||||
TypeMap[TypePong] = getTypeFn((*Pong)(nil))
|
TypeMap[TypePong] = reflect.TypeOf(Pong{})
|
||||||
|
|
||||||
for k, v := range TypeMap {
|
for k, v := range TypeMap {
|
||||||
TypeStringMap[v] = k
|
TypeStringMap[v] = k
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTypeFn(obj interface{}) reflect.Type {
|
|
||||||
return reflect.TypeOf(obj).Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message wraps socket packages for communicating between frpc and frps.
|
// Message wraps socket packages for communicating between frpc and frps.
|
||||||
type Message interface{}
|
type Message interface{}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ package msg
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -66,7 +67,7 @@ func TestUnPack(t *testing.T) {
|
|||||||
// correct
|
// correct
|
||||||
msg, err = UnPack(TypePong, []byte("{}"))
|
msg, err = UnPack(TypePong, []byte("{}"))
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(getTypeFn(msg), getTypeFn((*Pong)(nil)))
|
assert.Equal(reflect.TypeOf(msg).Elem(), reflect.TypeOf(Pong{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnPackInto(t *testing.T) {
|
func TestUnPackInto(t *testing.T) {
|
||||||
|
@ -19,8 +19,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/crypto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestJoin(t *testing.T) {
|
func TestJoin(t *testing.T) {
|
||||||
@ -67,63 +65,3 @@ func TestJoin(t *testing.T) {
|
|||||||
conn3.Close()
|
conn3.Close()
|
||||||
conn4.Close()
|
conn4.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJoinEncrypt(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
var (
|
|
||||||
n int
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
text1 := "1234567890"
|
|
||||||
text2 := "abcdefghij"
|
|
||||||
key := "authkey"
|
|
||||||
|
|
||||||
// Forward enrypted bytes.
|
|
||||||
pr, pw := io.Pipe()
|
|
||||||
pr2, pw2 := io.Pipe()
|
|
||||||
pr3, pw3 := io.Pipe()
|
|
||||||
pr4, pw4 := io.Pipe()
|
|
||||||
pr5, pw5 := io.Pipe()
|
|
||||||
pr6, pw6 := io.Pipe()
|
|
||||||
|
|
||||||
conn1 := WrapReadWriteCloser(pr, pw2)
|
|
||||||
conn2 := WrapReadWriteCloser(pr2, pw)
|
|
||||||
conn3 := WrapReadWriteCloser(pr3, pw4)
|
|
||||||
conn4 := WrapReadWriteCloser(pr4, pw3)
|
|
||||||
conn5 := WrapReadWriteCloser(pr5, pw6)
|
|
||||||
conn6 := WrapReadWriteCloser(pr6, pw5)
|
|
||||||
|
|
||||||
r1, err := crypto.NewReader(conn3, []byte(key))
|
|
||||||
assert.NoError(err)
|
|
||||||
w1, err := crypto.NewWriter(conn3, []byte(key))
|
|
||||||
assert.NoError(err)
|
|
||||||
|
|
||||||
r2, err := crypto.NewReader(conn4, []byte(key))
|
|
||||||
assert.NoError(err)
|
|
||||||
w2, err := crypto.NewWriter(conn4, []byte(key))
|
|
||||||
assert.NoError(err)
|
|
||||||
|
|
||||||
go Join(conn2, WrapReadWriteCloser(r1, w1))
|
|
||||||
go Join(WrapReadWriteCloser(r2, w2), conn5)
|
|
||||||
|
|
||||||
buf := make([]byte, 128)
|
|
||||||
|
|
||||||
conn1.Write([]byte(text1))
|
|
||||||
conn6.Write([]byte(text2))
|
|
||||||
|
|
||||||
n, err = conn6.Read(buf)
|
|
||||||
assert.NoError(err)
|
|
||||||
assert.Equal(text1, string(buf[:n]))
|
|
||||||
|
|
||||||
n, err = conn1.Read(buf)
|
|
||||||
assert.NoError(err)
|
|
||||||
assert.Equal(text2, string(buf[:n]))
|
|
||||||
|
|
||||||
conn1.Close()
|
|
||||||
conn2.Close()
|
|
||||||
conn3.Close()
|
|
||||||
conn4.Close()
|
|
||||||
conn5.Close()
|
|
||||||
conn6.Close()
|
|
||||||
}
|
|
||||||
|
@ -22,32 +22,16 @@ import (
|
|||||||
"github.com/fatedier/frp/utils/crypto"
|
"github.com/fatedier/frp/utils/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func WithEncryption(rwc io.ReadWriteCloser, key []byte) (res io.ReadWriteCloser, err error) {
|
func WithEncryption(rwc io.ReadWriteCloser, key []byte) (io.ReadWriteCloser, error) {
|
||||||
var (
|
w, err := crypto.NewWriter(rwc, key)
|
||||||
r io.Reader
|
|
||||||
w io.Writer
|
|
||||||
)
|
|
||||||
r, err = crypto.NewReader(rwc, key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
w, err = crypto.NewWriter(rwc, key)
|
return WrapReadWriteCloser(crypto.NewReader(rwc, key), w), nil
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res = WrapReadWriteCloser(r, w)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithCompression(rwc io.ReadWriteCloser) (res io.ReadWriteCloser) {
|
func WithCompression(rwc io.ReadWriteCloser) io.ReadWriteCloser {
|
||||||
var (
|
return WrapReadWriteCloser(snappy.NewReader(rwc), snappy.NewWriter(rwc))
|
||||||
r io.Reader
|
|
||||||
w io.Writer
|
|
||||||
)
|
|
||||||
r = snappy.NewReader(rwc)
|
|
||||||
w = snappy.NewWriter(rwc)
|
|
||||||
res = WrapReadWriteCloser(r, w)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapReadWriteCloser(r io.Reader, w io.Writer) io.ReadWriteCloser {
|
func WrapReadWriteCloser(r io.Reader, w io.Writer) io.ReadWriteCloser {
|
||||||
|
@ -212,11 +212,7 @@ func (ctl *Control) reader() {
|
|||||||
defer ctl.allShutdown.Start()
|
defer ctl.allShutdown.Start()
|
||||||
defer ctl.readerShutdown.Done()
|
defer ctl.readerShutdown.Done()
|
||||||
|
|
||||||
encReader, err := crypto.NewReader(ctl.conn, []byte(config.ServerCommonCfg.PrivilegeToken))
|
encReader := crypto.NewReader(ctl.conn, []byte(config.ServerCommonCfg.PrivilegeToken))
|
||||||
if err != nil {
|
|
||||||
ctl.conn.Error("crypto new reader error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for {
|
for {
|
||||||
if m, err := msg.ReadMsg(encReader); err != nil {
|
if m, err := msg.ReadMsg(encReader); err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@ -260,7 +256,7 @@ func (ctl *Control) stoper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctl.allShutdown.Done()
|
ctl.allShutdown.Done()
|
||||||
ctl.conn.Info("all shutdown success")
|
ctl.conn.Info("client exit success")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) manager() {
|
func (ctl *Control) manager() {
|
||||||
|
113
server/proxy.go
113
server/proxy.go
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/fatedier/frp/models/proto/tcp"
|
"github.com/fatedier/frp/models/proto/tcp"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
"github.com/fatedier/frp/utils/net"
|
"github.com/fatedier/frp/utils/net"
|
||||||
|
"github.com/fatedier/frp/utils/vhost"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Proxy interface {
|
type Proxy interface {
|
||||||
@ -42,6 +43,27 @@ func (pxy *BaseProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// startListenHandler start a goroutine handler for each listener.
|
||||||
|
// p: p will just be passed to handler(Proxy, net.Conn).
|
||||||
|
// handler: each proxy type can set different handler function to deal with connections accepted from listeners.
|
||||||
|
func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn)) {
|
||||||
|
for _, listener := range pxy.listeners {
|
||||||
|
go func(l net.Listener) {
|
||||||
|
for {
|
||||||
|
// block
|
||||||
|
// if listener is closed, err returned
|
||||||
|
c, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
pxy.Info("listener is closed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pxy.Debug("get a user connection [%s]", c.RemoteAddr().String())
|
||||||
|
go handler(p, c)
|
||||||
|
}
|
||||||
|
}(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewProxy(ctl *Control, pxyConf config.ProxyConf) (pxy Proxy, err error) {
|
func NewProxy(ctl *Control, pxyConf config.ProxyConf) (pxy Proxy, err error) {
|
||||||
basePxy := BaseProxy{
|
basePxy := BaseProxy{
|
||||||
name: pxyConf.GetName(),
|
name: pxyConf.GetName(),
|
||||||
@ -83,25 +105,14 @@ type TcpProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *TcpProxy) Run() error {
|
func (pxy *TcpProxy) Run() error {
|
||||||
listener, err := net.ListenTcp(config.ServerCommonCfg.BindAddr, int64(pxy.cfg.RemotePort))
|
listener, err := net.ListenTcp(config.ServerCommonCfg.BindAddr, pxy.cfg.RemotePort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pxy.listeners = append(pxy.listeners, listener)
|
pxy.listeners = append(pxy.listeners, listener)
|
||||||
|
pxy.Info("tcp proxy listen port [%d]", pxy.cfg.RemotePort)
|
||||||
|
|
||||||
go func(l net.Listener) {
|
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
||||||
for {
|
|
||||||
// block
|
|
||||||
// if listener is closed, err returned
|
|
||||||
c, err := l.Accept()
|
|
||||||
if err != nil {
|
|
||||||
pxy.Info("listener is closed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pxy.Debug("got one user connection [%s]", c.RemoteAddr().String())
|
|
||||||
go HandleUserTcpConnection(pxy, c)
|
|
||||||
}
|
|
||||||
}(listener)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +130,43 @@ type HttpProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *HttpProxy) Run() (err error) {
|
func (pxy *HttpProxy) Run() (err error) {
|
||||||
|
routeConfig := &vhost.VhostRouteConfig{
|
||||||
|
RewriteHost: pxy.cfg.HostHeaderRewrite,
|
||||||
|
Username: pxy.cfg.HttpUser,
|
||||||
|
Password: pxy.cfg.HttpPwd,
|
||||||
|
}
|
||||||
|
|
||||||
|
locations := pxy.cfg.Locations
|
||||||
|
if len(locations) == 0 {
|
||||||
|
locations = []string{""}
|
||||||
|
}
|
||||||
|
for _, domain := range pxy.cfg.CustomDomains {
|
||||||
|
routeConfig.Domain = domain
|
||||||
|
for _, location := range locations {
|
||||||
|
routeConfig.Location = location
|
||||||
|
l, err := pxy.ctl.svr.VhostHttpMuxer.Listen(routeConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pxy.Info("http proxy listen for host [%s] location [%s]", routeConfig.Domain, routeConfig.Location)
|
||||||
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pxy.cfg.SubDomain != "" {
|
||||||
|
routeConfig.Domain = pxy.cfg.SubDomain + "." + config.ServerCommonCfg.SubDomainHost
|
||||||
|
for _, location := range locations {
|
||||||
|
routeConfig.Location = location
|
||||||
|
l, err := pxy.ctl.svr.VhostHttpMuxer.Listen(routeConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pxy.Info("http proxy listen for host [%s] location [%s]", routeConfig.Domain, routeConfig.Location)
|
||||||
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +184,29 @@ type HttpsProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *HttpsProxy) Run() (err error) {
|
func (pxy *HttpsProxy) Run() (err error) {
|
||||||
|
routeConfig := &vhost.VhostRouteConfig{}
|
||||||
|
|
||||||
|
for _, domain := range pxy.cfg.CustomDomains {
|
||||||
|
routeConfig.Domain = domain
|
||||||
|
l, err := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
||||||
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pxy.cfg.SubDomain != "" {
|
||||||
|
routeConfig.Domain = pxy.cfg.SubDomain + "." + config.ServerCommonCfg.SubDomainHost
|
||||||
|
l, err := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
||||||
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +251,7 @@ func HandleUserTcpConnection(pxy Proxy, userConn net.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer workConn.Close()
|
defer workConn.Close()
|
||||||
pxy.Info("get one new work connection: %s", workConn.RemoteAddr().String())
|
pxy.Info("get a new work connection: [%s]", workConn.RemoteAddr().String())
|
||||||
workConn.AddLogPrefix(pxy.GetName())
|
workConn.AddLogPrefix(pxy.GetName())
|
||||||
|
|
||||||
err := msg.WriteMsg(workConn, &msg.StartWorkConn{
|
err := msg.WriteMsg(workConn, &msg.StartWorkConn{
|
||||||
@ -199,12 +270,7 @@ func HandleUserTcpConnection(pxy Proxy, userConn net.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var local io.ReadWriteCloser = workConn
|
||||||
local io.ReadWriteCloser
|
|
||||||
remote io.ReadWriteCloser
|
|
||||||
)
|
|
||||||
local = workConn
|
|
||||||
remote = userConn
|
|
||||||
cfg := pxy.GetConf().GetBaseInfo()
|
cfg := pxy.GetConf().GetBaseInfo()
|
||||||
if cfg.UseEncryption {
|
if cfg.UseEncryption {
|
||||||
local, err = tcp.WithEncryption(local, []byte(config.ServerCommonCfg.PrivilegeToken))
|
local, err = tcp.WithEncryption(local, []byte(config.ServerCommonCfg.PrivilegeToken))
|
||||||
@ -216,5 +282,8 @@ func HandleUserTcpConnection(pxy Proxy, userConn net.Conn) {
|
|||||||
if cfg.UseCompression {
|
if cfg.UseCompression {
|
||||||
local = tcp.WithCompression(local)
|
local = tcp.WithCompression(local)
|
||||||
}
|
}
|
||||||
tcp.Join(local, remote)
|
pxy.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
|
||||||
|
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
|
||||||
|
tcp.Join(local, userConn)
|
||||||
|
pxy.Debug("join connections closed")
|
||||||
}
|
}
|
||||||
|
@ -22,15 +22,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWriter(t *testing.T) {
|
|
||||||
// Empty key.
|
|
||||||
assert := assert.New(t)
|
|
||||||
key := ""
|
|
||||||
buffer := bytes.NewBuffer(nil)
|
|
||||||
_, err := NewWriter(buffer, []byte(key))
|
|
||||||
assert.NoError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCrypto(t *testing.T) {
|
func TestCrypto(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
@ -40,12 +31,10 @@ func TestCrypto(t *testing.T) {
|
|||||||
buffer := bytes.NewBuffer(nil)
|
buffer := bytes.NewBuffer(nil)
|
||||||
encWriter, err := NewWriter(buffer, []byte(key))
|
encWriter, err := NewWriter(buffer, []byte(key))
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
|
decReader := NewReader(buffer, []byte(key))
|
||||||
|
|
||||||
encWriter.Write([]byte(text))
|
encWriter.Write([]byte(text))
|
||||||
|
|
||||||
decReader, err := NewReader(buffer, []byte(key))
|
|
||||||
assert.NoError(err)
|
|
||||||
|
|
||||||
c := bytes.NewBuffer(nil)
|
c := bytes.NewBuffer(nil)
|
||||||
io.Copy(c, decReader)
|
io.Copy(c, decReader)
|
||||||
assert.Equal(text, string(c.Bytes()))
|
assert.Equal(text, string(c.Bytes()))
|
||||||
|
@ -24,13 +24,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewReader returns a new Reader that decrypts bytes from r
|
// NewReader returns a new Reader that decrypts bytes from r
|
||||||
func NewReader(r io.Reader, key []byte) (*Reader, error) {
|
func NewReader(r io.Reader, key []byte) *Reader {
|
||||||
key = pbkdf2.Key(key, []byte(salt), 64, aes.BlockSize, sha1.New)
|
key = pbkdf2.Key(key, []byte(salt), 64, aes.BlockSize, sha1.New)
|
||||||
|
|
||||||
return &Reader{
|
return &Reader{
|
||||||
r: r,
|
r: r,
|
||||||
key: key,
|
key: key,
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reader is an io.Reader that can read encrypted bytes.
|
// Reader is an io.Reader that can read encrypted bytes.
|
||||||
|
@ -67,10 +67,6 @@ type Writer struct {
|
|||||||
|
|
||||||
// Write satisfies the io.Writer interface.
|
// Write satisfies the io.Writer interface.
|
||||||
func (w *Writer) Write(p []byte) (nRet int, errRet error) {
|
func (w *Writer) Write(p []byte) (nRet int, errRet error) {
|
||||||
return w.write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Writer) write(p []byte) (nRet int, errRet error) {
|
|
||||||
if w.err != nil {
|
if w.err != nil {
|
||||||
return 0, w.err
|
return 0, w.err
|
||||||
}
|
}
|
||||||
|
@ -50,26 +50,35 @@ func NewVhostMuxer(listener frpNet.Listener, vhostFunc muxFunc, authFunc httpAut
|
|||||||
return mux, nil
|
return mux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// listen for a new domain name, if rewriteHost is not empty and rewriteFunc is not nil, then rewrite the host header to rewriteHost
|
type VhostRouteConfig struct {
|
||||||
func (v *VhostMuxer) Listen(name, location, rewriteHost, userName, passWord string) (l *Listener, err error) {
|
Domain string
|
||||||
|
Location string
|
||||||
|
RewriteHost string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
// listen for a new domain name, if rewriteHost is not empty and rewriteFunc is not nil
|
||||||
|
// then rewrite the host header to rewriteHost
|
||||||
|
func (v *VhostMuxer) Listen(cfg *VhostRouteConfig) (l *Listener, err error) {
|
||||||
v.mutex.Lock()
|
v.mutex.Lock()
|
||||||
defer v.mutex.Unlock()
|
defer v.mutex.Unlock()
|
||||||
|
|
||||||
_, ok := v.registryRouter.Exist(name, location)
|
_, ok := v.registryRouter.Exist(cfg.Domain, cfg.Location)
|
||||||
if ok {
|
if ok {
|
||||||
return nil, fmt.Errorf("hostname [%s] location [%s] is already registered", name, location)
|
return nil, fmt.Errorf("hostname [%s] location [%s] is already registered", cfg.Domain, cfg.Location)
|
||||||
}
|
}
|
||||||
|
|
||||||
l = &Listener{
|
l = &Listener{
|
||||||
name: name,
|
name: cfg.Domain,
|
||||||
location: location,
|
location: cfg.Location,
|
||||||
rewriteHost: rewriteHost,
|
rewriteHost: cfg.RewriteHost,
|
||||||
userName: userName,
|
userName: cfg.Username,
|
||||||
passWord: passWord,
|
passWord: cfg.Password,
|
||||||
mux: v,
|
mux: v,
|
||||||
accept: make(chan frpNet.Conn),
|
accept: make(chan frpNet.Conn),
|
||||||
}
|
}
|
||||||
v.registryRouter.Add(name, location, l)
|
v.registryRouter.Add(cfg.Domain, cfg.Location, l)
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user