Compare commits

...
23 Commits
Author SHA1 Message Date
fatedierandGitHub 3bf1eb8565 Merge pull request #2216 from fatedier/dev
bump version
2021-01-25 16:15:52 +08:00
fatedier a821db3f45 add release note 2021-01-25 16:06:38 +08:00
fatedierandGitHub ecb6ed9258 revert web code (#2215) 2021-01-25 16:04:33 +08:00
fatedierandGitHub b2ae433e18 Merge pull request #2206 from fatedier/dev
bump version
2021-01-19 20:56:06 +08:00
fatedier b26080589b bump version 2021-01-19 20:51:06 +08:00
yuyuleiandGitHub aff979c2b6 Merge pull request #2199 from fatedier/fix
vhost: set DisableKeepAlives = false and fix websocket not work
2021-01-19 15:40:41 +08:00
fatedier 46f809d711 vhost: set DisableKeepAlives = false and fix websocket not work 2021-01-18 21:49:44 +08:00
yuyuleiandGitHub 72595b2da8 Add user remote address info log (#2184) 2021-01-11 16:52:17 +08:00
XNGandGitHub c842558ace Reduced log level of "get hostname error" (#2165)
Reduced log level of "get hostname from http/https request error" to debug so that it won't overwhelms the log file when user is using apache/ngix as their own SSL backend
2020-12-25 13:39:26 +08:00
yuyuleiandGitHub ed61049041 Bugfix: add ipv6 parsing with address of frps (#2163) 2020-12-24 21:48:26 +08:00
fatedier abe6f580c0 update README 2020-12-03 20:41:37 +08:00
fatedier e940066012 auto generate web assets 2020-12-03 20:23:43 +08:00
huberyandGitHub 1e846df870 some dashboard refactor (#2101) 2020-12-03 20:20:48 +08:00
Mike CardwellandGitHub 0ab055e946 Allow server plugin to talk to https services. Option for skipping tls verification (#2103)
* Allow server plugin to talk to https services. Option for skipping tls verification

* Rename TlsVerify to TLSVerify

* Server plugin should use default http transport when scheme is not https
2020-12-03 14:36:14 +08:00
fatedier fca59c71e2 clear Release.md 2020-11-23 17:34:09 +08:00
wxiaoguangandGitHub fae2f8768d tweak logs: (#2100)
* show what config frps uses (config file / command line)
* optimize the "start successfully" log message
2020-11-23 17:01:31 +08:00
fatedier 3d9499f554 autogen web assets 2020-11-23 15:21:07 +08:00
huberyandGitHub 7adeeedd55 fix dashboard horizontal scrollbar (#2096) 2020-11-23 14:52:55 +08:00
yuyuleiandGitHub 127a31ea6a Fix typo (#2089) 2020-11-23 11:38:21 +08:00
fatedier a85bd9a4d9 update 2020-11-20 20:10:08 +08:00
fatedier 01d551ec8d update 2020-11-20 18:10:33 +08:00
fatedier 16cabf4127 add .circleci 2020-11-20 18:04:44 +08:00
fatedier 968be4a2c2 use self token 2020-11-20 17:35:06 +08:00
42 changed files with 8223 additions and 20611 deletions
+25
View File
@@ -0,0 +1,25 @@
version: 2
jobs:
test1:
docker:
- image: circleci/golang:1.15-node
working_directory: /go/src/github.com/fatedier/frp
steps:
- checkout
- run: make
- run: make alltest
test2:
docker:
- image: circleci/golang:1.14-node
working_directory: /go/src/github.com/fatedier/frp
steps:
- checkout
- run: make
- run: make alltest
workflows:
version: 2
build_and_test:
jobs:
- test1
- test2
+1 -1
View File
@@ -27,4 +27,4 @@ jobs:
version: latest
args: release --rm-dist --release-notes=./Release.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GPR_TOKEN }}
-12
View File
@@ -1,12 +0,0 @@
sudo: false
language: go
go:
- 1.14.x
- 1.15.x
install:
- make
script:
- make alltest
+1 -1
View File
@@ -1,6 +1,6 @@
# frp
[![Build Status](https://travis-ci.org/fatedier/frp.svg?branch=master)](https://travis-ci.org/fatedier/frp)
[![Build Status](https://circleci.com/gh/fatedier/frp.svg?style=shield)](https://circleci.com/gh/fatedier/frp)
[![GitHub release](https://img.shields.io/github/tag/fatedier/frp.svg?label=release)](https://github.com/fatedier/frp/releases)
[README](README.md) | [中文文档](README_zh.md)
+2 -2
View File
@@ -1,3 +1,3 @@
### New
### Fix
* Command line parameters support `enable_prometheus`.
* Reduce binary file size.
+1 -1
View File
@@ -1 +1 @@
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frp client admin UI</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?d2cd6337d30c7b22e836"></script><script type="text/javascript" src="vendor.js?edb271e1d9c81f857840"></script></body> </html>
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frp client admin UI</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?f30e0e5ff7dbde4611e0"></script><script type="text/javascript" src="vendor.js?a82aed5fb0b844cbdb29"></script></body> </html>
+1 -1
View File
@@ -1 +1 @@
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"edb271e1d9c81f857840"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"a82aed5fb0b844cbdb29"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
<!DOCTYPE html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?14bea8276eef86cc7c61"></script><script type="text/javascript" src="vendor.js?51925ec1a77936b64d61"></script></body> </html>
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?b8b55d8156200869417b"></script><script type="text/javascript" src="vendor.js?3e078a9d741093b909de"></script></body> </html>
+1 -1
View File
@@ -1 +1 @@
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"51925ec1a77936b64d61"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,u,c){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in u)Object.prototype.hasOwnProperty.call(u,i)&&(e[i]=u[i]);for(r&&r(t,u,c);s.length;)s.shift()();if(c)for(l=0;l<c.length;l++)f=n(n.s=c[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var u=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=u;var c=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"3e078a9d741093b909de"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,c.appendChild(i),u},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7 -5
View File
@@ -17,10 +17,10 @@ package client
import (
"context"
"crypto/tls"
"fmt"
"io"
"net"
"runtime/debug"
"strconv"
"sync"
"time"
@@ -222,8 +222,10 @@ func (ctl *Control) connectServer() (conn net.Conn, err error) {
return
}
}
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HTTPProxy, ctl.clientCfg.Protocol,
fmt.Sprintf("%s:%d", ctl.clientCfg.ServerAddr, ctl.clientCfg.ServerPort), tlsConfig)
address := net.JoinHostPort(ctl.clientCfg.ServerAddr, strconv.Itoa(ctl.clientCfg.ServerPort))
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HTTPProxy, ctl.clientCfg.Protocol, address, tlsConfig)
if err != nil {
xl.Warn("start new connection to server error: %v", err)
return
@@ -295,7 +297,7 @@ func (ctl *Control) msgHandler() {
}()
defer ctl.msgHandlerShutdown.Done()
hbSend := time.NewTicker(time.Duration(ctl.clientCfg.HeartBeatInterval) * time.Second)
hbSend := time.NewTicker(time.Duration(ctl.clientCfg.HeartbeatInterval) * time.Second)
defer hbSend.Stop()
hbCheck := time.NewTicker(time.Second)
defer hbCheck.Stop()
@@ -314,7 +316,7 @@ func (ctl *Control) msgHandler() {
}
ctl.sendCh <- pingMsg
case <-hbCheck.C:
if time.Since(ctl.lastPong) > time.Duration(ctl.clientCfg.HeartBeatTimeout)*time.Second {
if time.Since(ctl.lastPong) > time.Duration(ctl.clientCfg.HeartbeatTimeout)*time.Second {
xl.Warn("heartbeat timeout")
// let reader() stop
ctl.conn.Close()
+4 -2
View File
@@ -21,6 +21,7 @@ import (
"io/ioutil"
"net"
"runtime"
"strconv"
"sync"
"sync/atomic"
"time"
@@ -215,8 +216,9 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) {
return
}
}
conn, err = frpNet.ConnectServerByProxyWithTLS(svr.cfg.HTTPProxy, svr.cfg.Protocol,
fmt.Sprintf("%s:%d", svr.cfg.ServerAddr, svr.cfg.ServerPort), tlsConfig)
address := net.JoinHostPort(svr.cfg.ServerAddr, strconv.Itoa(svr.cfg.ServerPort))
conn, err = frpNet.ConnectServerByProxyWithTLS(svr.cfg.HTTPProxy, svr.cfg.Protocol, address, tlsConfig)
if err != nil {
return
}
+7 -8
View File
@@ -157,17 +157,16 @@ func parseClientCommonCfgFromIni(content string) (config.ClientCommonConf, error
func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
cfg = config.GetDefaultClientConf()
strs := strings.Split(serverAddr, ":")
if len(strs) < 2 {
err = fmt.Errorf("invalid server_addr")
ipStr, portStr, err := net.SplitHostPort(serverAddr)
if err != nil {
err = fmt.Errorf("invalid server_addr: %v", err)
return
}
if strs[0] != "" {
cfg.ServerAddr = strs[0]
}
cfg.ServerPort, err = strconv.Atoi(strs[1])
cfg.ServerAddr = ipStr
cfg.ServerPort, err = strconv.Atoi(portStr)
if err != nil {
err = fmt.Errorf("invalid server_addr")
err = fmt.Errorf("invalid server_addr: %v", err)
return
}
+3 -1
View File
@@ -105,6 +105,7 @@ var rootCmd = &cobra.Command{
var cfg config.ServerCommonConf
var err error
if cfgFile != "" {
log.Info("frps uses config file: %s", cfgFile)
var content string
content, err = config.GetRenderedConfFromFile(cfgFile)
if err != nil {
@@ -112,6 +113,7 @@ var rootCmd = &cobra.Command{
}
cfg, err = parseServerCommonCfg(CfgFileTypeIni, content)
} else {
log.Info("frps uses command line arguments for config")
cfg, err = parseServerCommonCfg(CfgFileTypeCmd, "")
}
if err != nil {
@@ -212,7 +214,7 @@ func runServer(cfg config.ServerCommonConf) (err error) {
if err != nil {
return err
}
log.Info("start frps success")
log.Info("frps started successfully")
svr.Run()
return
}
+17 -2
View File
@@ -23,15 +23,30 @@ log_max_days = 3
disable_log_color = false
# for authentication, should be same as your frps.ini
# AuthenticateHeartBeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
# authenticate_heartbeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
authenticate_heartbeats = false
# AuthenticateNewWorkConns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
# authenticate_new_work_conns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
authenticate_new_work_conns = false
# auth token
token = 12345678
# oidc_client_id specifies the client ID to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
# By default, this value is "".
oidc_client_id =
# oidc_client_secret specifies the client secret to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
# By default, this value is "".
oidc_client_secret =
# oidc_audience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
oidc_audience =
# oidc_token_endpoint_url specifies the URL which implements OIDC Token Endpoint.
# It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "".
oidc_token_endpoint_url =
# set admin address for control frpc's action by http api such as reload
admin_addr = 127.0.0.1
admin_port = 7400
+20 -13
View File
@@ -23,7 +23,7 @@ vhost_https_port = 443
# response header timeout(seconds) for vhost http server, default is 60s
# vhost_http_timeout = 60
# TcpMuxHttpConnectPort specifies the port that the server listens for TCP
# tcpmux_httpconnect_port specifies the port that the server listens for TCP
# HTTP CONNECT requests. If the value is 0, the server will not multiplex TCP
# requests on one single port. If it's not - it will listen on this value for
# HTTP CONNECT requests. By default, this value is 0.
@@ -44,6 +44,7 @@ enable_prometheus = true
# dashboard assets directory(only for debug mode)
# assets_dir = ./static
# console or real logFile path like ./frps.log
log_file = ./frps.log
@@ -58,12 +59,12 @@ disable_log_color = false
# DetailedErrorsToClient defines whether to send the specific error (with debug info) to frpc. By default, this value is true.
detailed_errors_to_client = true
# AuthenticationMethod specifies what authentication method to use authenticate frpc with frps.
# authentication_method specifies what authentication method to use authenticate frpc with frps.
# If "token" is specified - token will be read into login message.
# If "oidc" is specified - OIDC (Open ID Connect) token will be issued using OIDC settings. By default, this value is "token".
authentication_method = token
# AuthenticateHeartBeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
# authenticate_heartbeats specifies whether to include authentication token in heartbeats sent to frps. By default, this value is false.
authenticate_heartbeats = false
# AuthenticateNewWorkConns specifies whether to include authentication token in new work connections sent to frps. By default, this value is false.
@@ -72,25 +73,31 @@ authenticate_new_work_conns = false
# auth token
token = 12345678
# OidcClientId specifies the client ID to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
# oidc_issuer specifies the issuer to verify OIDC tokens with.
# By default, this value is "".
oidc_client_id =
oidc_issuer =
# OidcClientSecret specifies the client secret to use to get a token in OIDC authentication if AuthenticationMethod == "oidc".
# oidc_audience specifies the audience OIDC tokens should contain when validated.
# By default, this value is "".
oidc_client_secret =
oidc_audience =
# OidcAudience specifies the audience of the token in OIDC authentication if AuthenticationMethod == "oidc". By default, this value is "".
oidc_audience =
# oidc_skip_expiry_check specifies whether to skip checking if the OIDC token is expired.
# By default, this value is false.
oidc_skip_expiry_check = false
# OidcTokenEndpointUrl specifies the URL which implements OIDC Token Endpoint.
# It will be used to get an OIDC token if AuthenticationMethod == "oidc". By default, this value is "".
oidc_token_endpoint_url =
# oidc_skip_issuer_check specifies whether to skip checking if the OIDC token's issuer claim matches the issuer specified in OidcIssuer.
# By default, this value is false.
oidc_skip_issuer_check = false
# heartbeat configure, it's not recommended to modify the default value
# the default value of heartbeat_timeout is 90
# heartbeat_timeout = 90
# user_conn_timeout configure, it's not recommended to modify the default value
# the default value of user_conn_timeout is 10
# user_conn_timeout = 10
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
allow_ports = 2000-3000,3001,3003,4000-50000
@@ -100,7 +107,7 @@ max_pool_count = 5
# max ports can be used for each client, default value is 0 means no limit
max_ports_per_client = 0
# TlsOnly specifies whether to only accept TLS-encrypted connections. By default, the value is false.
# tls_only specifies whether to only accept TLS-encrypted connections. By default, the value is false.
tls_only = false
# tls_cert_file = server.crt
+4 -3
View File
@@ -209,9 +209,10 @@ path = /handler
ops = NewProxy
```
addr: the address where the external RPC service listens on.
path: http request url path for the POST request.
ops: operations plugin needs to handle (e.g. "Login", "NewProxy", ...).
- addr: the address where the external RPC service listens. Defaults to http. For https, specify the schema: `addr = https://127.0.0.1:9001`.
- path: http request url path for the POST request.
- ops: operations plugin needs to handle (e.g. "Login", "NewProxy", ...).
- tls_verify: When the schema is https, we verify by default. Set this value to false if you want to skip verification.
### Metadata
+8 -8
View File
@@ -121,11 +121,11 @@ type ClientCommonConf struct {
// HeartBeatInterval specifies at what interval heartbeats are sent to the
// server, in seconds. It is not recommended to change this value. By
// default, this value is 30.
HeartBeatInterval int64 `json:"heartbeat_interval"`
HeartbeatInterval int64 `json:"heartbeat_interval"`
// HeartBeatTimeout specifies the maximum allowed heartbeat response delay
// before the connection is terminated, in seconds. It is not recommended
// to change this value. By default, this value is 90.
HeartBeatTimeout int64 `json:"heartbeat_timeout"`
HeartbeatTimeout int64 `json:"heartbeat_timeout"`
// Client meta info
Metas map[string]string `json:"metas"`
// UDPPacketSize specifies the udp packet size
@@ -160,8 +160,8 @@ func GetDefaultClientConf() ClientCommonConf {
TLSCertFile: "",
TLSKeyFile: "",
TLSTrustedCaFile: "",
HeartBeatInterval: 30,
HeartBeatTimeout: 90,
HeartbeatInterval: 30,
HeartbeatTimeout: 90,
Metas: make(map[string]string),
UDPPacketSize: 1500,
}
@@ -312,7 +312,7 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout")
return
}
cfg.HeartBeatTimeout = v
cfg.HeartbeatTimeout = v
}
if tmpStr, ok = conf.Get("common", "heartbeat_interval"); ok {
@@ -320,7 +320,7 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
return
}
cfg.HeartBeatInterval = v
cfg.HeartbeatInterval = v
}
for k, v := range conf.Section("common") {
if strings.HasPrefix(k, "meta_") {
@@ -338,12 +338,12 @@ func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error
}
func (cfg *ClientCommonConf) Check() (err error) {
if cfg.HeartBeatInterval <= 0 {
if cfg.HeartbeatInterval <= 0 {
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
return
}
if cfg.HeartBeatTimeout < cfg.HeartBeatInterval {
if cfg.HeartbeatTimeout < cfg.HeartbeatInterval {
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval")
return
}
+13 -8
View File
@@ -83,7 +83,7 @@ type ServerCommonConf struct {
// AssetsDir specifies the local directory that the dashboard will load
// resources from. If this value is "", assets will be loaded from the
// bundled executable using statik. By default, this value is "".
AssetsDir string `json:"asserts_dir"`
AssetsDir string `json:"assets_dir"`
// LogFile specifies a file where logs will be written to. This value will
// only be used if LogWay is set appropriately. By default, this value is
// "console".
@@ -154,7 +154,7 @@ type ServerCommonConf struct {
// HeartBeatTimeout specifies the maximum time to wait for a heartbeat
// before terminating the connection. It is not recommended to change this
// value. By default, this value is 90.
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
HeartbeatTimeout int64 `json:"heartbeat_timeout"`
// UserConnTimeout specifies the maximum time to wait for a work
// connection. By default, this value is 10.
UserConnTimeout int64 `json:"user_conn_timeout"`
@@ -199,7 +199,7 @@ func GetDefaultServerConf() ServerCommonConf {
TLSCertFile: "",
TLSKeyFile: "",
TLSTrustedCaFile: "",
HeartBeatTimeout: 90,
HeartbeatTimeout: 90,
UserConnTimeout: 10,
Custom404Page: "",
HTTPPlugins: make(map[string]plugin.HTTPPluginOptions),
@@ -421,7 +421,7 @@ func UnmarshalServerConfFromIni(content string) (cfg ServerCommonConf, err error
err = fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
return
}
cfg.HeartBeatTimeout = v
cfg.HeartbeatTimeout = v
}
if tmpStr, ok = conf.Get("common", "tls_only"); ok && tmpStr == "true" {
@@ -458,11 +458,16 @@ func UnmarshalPluginsFromIni(sections ini.File, cfg *ServerCommonConf) {
for name, section := range sections {
if strings.HasPrefix(name, "plugin.") {
name = strings.TrimSpace(strings.TrimPrefix(name, "plugin."))
var tls_verify, err = strconv.ParseBool(section["tls_verify"])
if err != nil {
tls_verify = true
}
options := plugin.HTTPPluginOptions{
Name: name,
Addr: section["addr"],
Path: section["path"],
Ops: strings.Split(section["ops"], ","),
Name: name,
Addr: section["addr"],
Path: section["path"],
Ops: strings.Split(section["ops"], ","),
TLSVerify: tls_verify,
}
for i := range options.Ops {
options.Ops[i] = strings.TrimSpace(options.Ops[i])
+24 -6
View File
@@ -17,19 +17,22 @@ package plugin
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"strings"
)
type HTTPPluginOptions struct {
Name string
Addr string
Path string
Ops []string
Name string
Addr string
Path string
Ops []string
TLSVerify bool
}
type httpPlugin struct {
@@ -40,10 +43,25 @@ type httpPlugin struct {
}
func NewHTTPPluginOptions(options HTTPPluginOptions) Plugin {
var url = fmt.Sprintf("%s%s", options.Addr, options.Path)
var client *http.Client
if strings.HasPrefix(url, "https://") {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: options.TLSVerify == false},
}
client = &http.Client{Transport: tr}
} else {
client = &http.Client{}
}
if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") {
url = "http://" + url
}
return &httpPlugin{
options: options,
url: fmt.Sprintf("http://%s%s", options.Addr, options.Path),
client: &http.Client{},
url: url,
client: client,
}
}
+33
View File
@@ -15,6 +15,7 @@
package util
import (
"net"
"net/http"
"strings"
)
@@ -33,6 +34,7 @@ func OkResponse() *http.Response {
return res
}
// TODO: use "CanonicalHost" func to replace all "GetHostFromAddr" func.
func GetHostFromAddr(addr string) (host string) {
strs := strings.Split(addr, ":")
if len(strs) > 1 {
@@ -42,3 +44,34 @@ func GetHostFromAddr(addr string) (host string) {
}
return
}
// canonicalHost strips port from host if present and returns the canonicalized
// host name.
func CanonicalHost(host string) (string, error) {
var err error
host = strings.ToLower(host)
if hasPort(host) {
host, _, err = net.SplitHostPort(host)
if err != nil {
return "", err
}
}
if strings.HasSuffix(host, ".") {
// Strip trailing dot from fully qualified domain names.
host = host[:len(host)-1]
}
return host, nil
}
// hasPort reports whether host contains a port number. host may be a host
// name, an IPv4 or an IPv6 address.
func hasPort(host string) bool {
colons := strings.Count(host, ":")
if colons == 0 {
return false
}
if colons == 1 {
return true
}
return host[0] == '[' && strings.Contains(host, "]:")
}
+1 -1
View File
@@ -19,7 +19,7 @@ import (
"strings"
)
var version string = "0.34.3"
var version string = "0.35.1"
func Full() string {
return version
+23 -9
View File
@@ -17,6 +17,7 @@ package vhost
import (
"bytes"
"context"
"encoding/base64"
"errors"
"fmt"
"log"
@@ -59,20 +60,25 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
req.URL.Scheme = "http"
url := req.Context().Value(RouteInfoURL).(string)
oldHost := util.GetHostFromAddr(req.Context().Value(RouteInfoHost).(string))
host := rp.GetRealHost(oldHost, url)
if host != "" {
req.Host = host
}
req.URL.Host = req.Host
rc := rp.GetRouteConfig(oldHost, url)
if rc != nil {
if rc.RewriteHost != "" {
req.Host = rc.RewriteHost
}
// Set {domain}.{location} as URL host here to let http transport reuse connections.
req.URL.Host = rc.Domain + "." + base64.StdEncoding.EncodeToString([]byte(rc.Location))
headers := rp.GetHeaders(oldHost, url)
for k, v := range headers {
req.Header.Set(k, v)
for k, v := range rc.Headers {
req.Header.Set(k, v)
}
} else {
req.URL.Host = req.Host
}
},
Transport: &http.Transport{
ResponseHeaderTimeout: rp.responseHeaderTimeout,
DisableKeepAlives: true,
IdleConnTimeout: 60 * time.Second,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
url := ctx.Value(RouteInfoURL).(string)
host := util.GetHostFromAddr(ctx.Value(RouteInfoHost).(string))
@@ -107,6 +113,14 @@ func (rp *HTTPReverseProxy) UnRegister(domain string, location string) {
rp.vhostRouter.Del(domain, location)
}
func (rp *HTTPReverseProxy) GetRouteConfig(domain string, location string) *RouteConfig {
vr, ok := rp.getVhost(domain, location)
if ok {
return vr.payload.(*RouteConfig)
}
return nil
}
func (rp *HTTPReverseProxy) GetRealHost(domain string, location string) (host string) {
vr, ok := rp.getVhost(domain, location)
if ok {
+1 -1
View File
@@ -144,7 +144,7 @@ func (v *Muxer) handle(c net.Conn) {
sConn, reqInfoMap, err := v.vhostFunc(c)
if err != nil {
log.Warn("get hostname from http/https request error: %v", err)
log.Debug("get hostname from http/https request error: %v", err)
c.Close()
return
}
+1 -1
View File
@@ -408,7 +408,7 @@ func (ctl *Control) manager() {
for {
select {
case <-heartbeat.C:
if time.Since(ctl.lastPing) > time.Duration(ctl.serverCfg.HeartBeatTimeout)*time.Second {
if time.Since(ctl.lastPing) > time.Duration(ctl.serverCfg.HeartbeatTimeout)*time.Second {
xl.Warn("heartbeat timeout")
return
}
+1 -1
View File
@@ -74,7 +74,7 @@ func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
SubdomainHost: svr.cfg.SubDomainHost,
MaxPoolCount: svr.cfg.MaxPoolCount,
MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
HeartBeatTimeout: svr.cfg.HeartBeatTimeout,
HeartBeatTimeout: svr.cfg.HeartbeatTimeout,
TotalTrafficIn: serverStats.TotalTrafficIn,
TotalTrafficOut: serverStats.TotalTrafficOut,
+2 -2
View File
@@ -100,7 +100,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
xl.Warn("failed to get work connection: %v", err)
return
}
xl.Info("get a new work connection: [%s]", workConn.RemoteAddr().String())
xl.Debug("get a new work connection: [%s]", workConn.RemoteAddr().String())
xl.Spawn().AppendPrefix(pxy.GetName())
workConn = frpNet.NewContextConn(pxy.ctx, workConn)
@@ -159,7 +159,7 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn,
xl.Info("listener is closed")
return
}
xl.Debug("get a user connection [%s]", c.RemoteAddr().String())
xl.Info("get a user connection [%s]", c.RemoteAddr().String())
go handler(p, c, pxy.serverCfg)
}
}(listener)
+24 -8
View File
@@ -139,6 +139,7 @@ func TestHealthCheck(t *testing.T) {
}
httpSvc3 := mock.NewHTTPServer(15005, func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second)
w.Write([]byte("http3"))
})
err = httpSvc3.Start()
@@ -147,6 +148,7 @@ func TestHealthCheck(t *testing.T) {
}
httpSvc4 := mock.NewHTTPServer(15006, func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second)
w.Write([]byte("http4"))
})
err = httpSvc4.Start()
@@ -277,16 +279,30 @@ func TestHealthCheck(t *testing.T) {
// ****** load balancing type http ******
result = make([]string, 0)
var wait sync.WaitGroup
var mu sync.Mutex
wait.Add(2)
code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
assert.NoError(err)
assert.Equal(200, code)
result = append(result, body)
go func() {
defer wait.Done()
code, body, _, err := util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
assert.NoError(err)
assert.Equal(200, code)
mu.Lock()
result = append(result, body)
mu.Unlock()
}()
code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
assert.NoError(err)
assert.Equal(200, code)
result = append(result, body)
go func() {
defer wait.Done()
code, body, _, err = util.SendHTTPMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
assert.NoError(err)
assert.Equal(200, code)
mu.Lock()
result = append(result, body)
mu.Unlock()
}()
wait.Wait()
assert.Contains(result, "http3")
assert.Contains(result, "http4")
-9334
View File
File diff suppressed because it is too large Load Diff
+1615 -1839
View File
File diff suppressed because it is too large Load Diff
-9334
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@
</el-row>
</header>
<section>
<el-row :gutter="20">
<el-row>
<el-col id="side-nav" :xs="24" :md="4">
<el-menu default-active="1" mode="vertical" theme="light" router="false" @select="handleSelect">
<el-menu-item index="/">Overview</el-menu-item>
+6377
View File
File diff suppressed because it is too large Load Diff