Merge branch 'dev' into feature/detailed-errors-to-client

# Conflicts:
#	models/config/server_common.go
This commit is contained in:
Guy Lewin 2020-02-11 11:25:04 +02:00
commit 9440bc5d72
5 changed files with 111 additions and 2 deletions

View File

@ -461,6 +461,8 @@ Config `tls_enable = true` in the `[common]` section to `frpc.ini` to enable thi
For port multiplexing, frp sends a first byte `0x17` to dial a TLS connection. For port multiplexing, frp sends a first byte `0x17` to dial a TLS connection.
To enforce `frps` to only accept TLS connections - configure `tls_only = true` in the `[common]` section in `frps.ini`.
### Hot-Reloading frpc configuration ### Hot-Reloading frpc configuration
The `admin_addr` and `admin_port` fields are required for enabling HTTP API: The `admin_addr` and `admin_port` fields are required for enabling HTTP API:

View File

@ -131,6 +131,9 @@ type ServerCommonConf struct {
// may proxy to. If this value is 0, no limit will be applied. By default, // may proxy to. If this value is 0, no limit will be applied. By default,
// this value is 0. // this value is 0.
MaxPortsPerClient int64 `json:"max_ports_per_client"` MaxPortsPerClient int64 `json:"max_ports_per_client"`
// TlsOnly specifies whether to only accept TLS-encrypted connections. By
// default, the value is false.
TlsOnly bool `json:"tls_only"`
// HeartBeatTimeout specifies the maximum time to wait for a heartbeat // HeartBeatTimeout specifies the maximum time to wait for a heartbeat
// before terminating the connection. It is not recommended to change this // before terminating the connection. It is not recommended to change this
// value. By default, this value is 90. // value. By default, this value is 90.
@ -171,6 +174,7 @@ func GetDefaultServerConf() ServerCommonConf {
AllowPorts: make(map[int]struct{}), AllowPorts: make(map[int]struct{}),
MaxPoolCount: 5, MaxPoolCount: 5,
MaxPortsPerClient: 0, MaxPortsPerClient: 0,
TlsOnly: false,
HeartBeatTimeout: 90, HeartBeatTimeout: 90,
UserConnTimeout: 10, UserConnTimeout: 10,
Custom404Page: "", Custom404Page: "",
@ -388,6 +392,12 @@ func UnmarshalServerConfFromIni(content string) (cfg ServerCommonConf, err error
cfg.HeartBeatTimeout = v cfg.HeartBeatTimeout = v
} }
} }
if tmpStr, ok = conf.Get("common", "tls_only"); ok && tmpStr == "true" {
cfg.TlsOnly = true
} else {
cfg.TlsOnly = false
}
return return
} }

View File

@ -284,7 +284,7 @@ func (svr *Service) HandleListener(l net.Listener) {
log.Trace("start check TLS connection...") log.Trace("start check TLS connection...")
originConn := c originConn := c
c, err = frpNet.CheckAndEnableTLSServerConnWithTimeout(c, svr.tlsConfig, connReadTimeout) c, err = frpNet.CheckAndEnableTLSServerConnWithTimeout(c, svr.tlsConfig, svr.cfg.TlsOnly, connReadTimeout)
if err != nil { if err != nil {
log.Warn("CheckAndEnableTLSServerConnWithTimeout error: %v", err) log.Warn("CheckAndEnableTLSServerConnWithTimeout error: %v", err)
originConn.Close() originConn.Close()

View File

@ -186,3 +186,95 @@ func TestTLSOverWebsocket(t *testing.T) {
assert.NoError(err) assert.NoError(err)
assert.Equal(consts.TEST_TCP_ECHO_STR, res) assert.Equal(consts.TEST_TCP_ECHO_STR, res)
} }
const FRPS_TLS_ONLY_TCP_CONF = `
[common]
bind_addr = 0.0.0.0
bind_port = 20000
log_file = console
log_level = debug
token = 123456
tls_only = true
`
const FRPC_TLS_ONLY_TCP_CONF = `
[common]
server_addr = 127.0.0.1
server_port = 20000
log_file = console
log_level = debug
token = 123456
protocol = tcp
tls_enable = true
[tcp]
type = tcp
local_port = 10701
remote_port = 20801
`
const FRPC_TLS_ONLY_NO_TLS_TCP_CONF = `
[common]
server_addr = 127.0.0.1
server_port = 20000
log_file = console
log_level = debug
token = 123456
protocol = tcp
tls_enable = false
[tcp]
type = tcp
local_port = 10701
remote_port = 20802
`
func TestTlsOnlyOverTCP(t *testing.T) {
assert := assert.New(t)
frpsCfgPath, err := config.GenerateConfigFile(consts.FRPS_NORMAL_CONFIG, FRPS_TLS_ONLY_TCP_CONF)
if assert.NoError(err) {
defer os.Remove(frpsCfgPath)
}
frpcWithTlsCfgPath, err := config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_TLS_ONLY_TCP_CONF)
if assert.NoError(err) {
defer os.Remove(frpcWithTlsCfgPath)
}
frpsProcess := util.NewProcess(consts.FRPS_BIN_PATH, []string{"-c", frpsCfgPath})
err = frpsProcess.Start()
if assert.NoError(err) {
defer frpsProcess.Stop()
}
time.Sleep(200 * time.Millisecond)
frpcProcessWithTls := util.NewProcess(consts.FRPC_BIN_PATH, []string{"-c", frpcWithTlsCfgPath})
err = frpcProcessWithTls.Start()
if assert.NoError(err) {
defer frpcProcessWithTls.Stop()
}
time.Sleep(500 * time.Millisecond)
// test tcp over tls
res, err := util.SendTcpMsg("127.0.0.1:20801", consts.TEST_TCP_ECHO_STR)
assert.NoError(err)
assert.Equal(consts.TEST_TCP_ECHO_STR, res)
frpcProcessWithTls.Stop()
frpcWithoutTlsCfgPath, err := config.GenerateConfigFile(consts.FRPC_NORMAL_CONFIG, FRPC_TLS_ONLY_NO_TLS_TCP_CONF)
if assert.NoError(err) {
defer os.Remove(frpcWithTlsCfgPath)
}
frpcProcessWithoutTls := util.NewProcess(consts.FRPC_BIN_PATH, []string{"-c", frpcWithoutTlsCfgPath})
err = frpcProcessWithoutTls.Start()
if assert.NoError(err) {
defer frpcProcessWithoutTls.Stop()
}
time.Sleep(500 * time.Millisecond)
// test tcp without tls
_, err = util.SendTcpMsg("127.0.0.1:20802", consts.TEST_TCP_ECHO_STR)
assert.Error(err)
}

View File

@ -16,6 +16,7 @@ package net
import ( import (
"crypto/tls" "crypto/tls"
"fmt"
"net" "net"
"time" "time"
@ -32,7 +33,7 @@ func WrapTLSClientConn(c net.Conn, tlsConfig *tls.Config) (out net.Conn) {
return return
} }
func CheckAndEnableTLSServerConnWithTimeout(c net.Conn, tlsConfig *tls.Config, timeout time.Duration) (out net.Conn, err error) { func CheckAndEnableTLSServerConnWithTimeout(c net.Conn, tlsConfig *tls.Config, tlsOnly bool, timeout time.Duration) (out net.Conn, err error) {
sc, r := gnet.NewSharedConnSize(c, 2) sc, r := gnet.NewSharedConnSize(c, 2)
buf := make([]byte, 1) buf := make([]byte, 1)
var n int var n int
@ -46,6 +47,10 @@ func CheckAndEnableTLSServerConnWithTimeout(c net.Conn, tlsConfig *tls.Config, t
if n == 1 && int(buf[0]) == FRP_TLS_HEAD_BYTE { if n == 1 && int(buf[0]) == FRP_TLS_HEAD_BYTE {
out = tls.Server(c, tlsConfig) out = tls.Server(c, tlsConfig)
} else { } else {
if tlsOnly {
err = fmt.Errorf("non-TLS connection received on a TlsOnly server")
return
}
out = sc out = sc
} }
return return