mirror of
https://github.com/fatedier/frp.git
synced 2026-04-06 09:09:15 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
371c401f5b | ||
|
|
69919e8ef9 | ||
|
|
9abbe33790 | ||
|
|
4a5c00286e | ||
|
|
dfb892c8f6 | ||
|
|
461c4c18fd | ||
|
|
00b9ba95ae | ||
|
|
c47aad348d | ||
|
|
4cb4da3afc | ||
|
|
c1f57da00d | ||
|
|
fe187eb8ec | ||
|
|
0f6f674a64 | ||
|
|
814afbe1f6 | ||
|
|
3fde9176c9 | ||
|
|
af7cca1a93 | ||
|
|
7dd28a14aa | ||
|
|
1325c59a4c | ||
|
|
82dc1e924f | ||
|
|
3166bdf3f0 | ||
|
|
8af70c8822 | ||
|
|
87763e8251 | ||
|
|
e9241aeb94 | ||
|
|
2eaf134042 | ||
|
|
1739e012d6 | ||
|
|
9e8980429f | ||
|
|
1d0865ca49 | ||
|
|
5c9909aeef |
@@ -2,8 +2,7 @@ sudo: false
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.8.x
|
- 1.10.x
|
||||||
- 1.9.x
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- make
|
- make
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.8
|
FROM golang:1.10
|
||||||
|
|
||||||
COPY . /go/src/github.com/fatedier/frp
|
COPY . /go/src/github.com/fatedier/frp
|
||||||
|
|
||||||
|
|||||||
9
Makefile
9
Makefile
@@ -15,12 +15,7 @@ file:
|
|||||||
go generate ./assets/...
|
go generate ./assets/...
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
go fmt ./assets/...
|
go fmt ./...
|
||||||
go fmt ./client/...
|
|
||||||
go fmt ./cmd/...
|
|
||||||
go fmt ./models/...
|
|
||||||
go fmt ./server/...
|
|
||||||
go fmt ./utils/...
|
|
||||||
|
|
||||||
frps:
|
frps:
|
||||||
go build -o bin/frps ./cmd/frps
|
go build -o bin/frps ./cmd/frps
|
||||||
@@ -44,7 +39,7 @@ ci:
|
|||||||
go test -v ./tests/...
|
go test -v ./tests/...
|
||||||
cd ./tests && ./clean_test.sh && cd -
|
cd ./tests && ./clean_test.sh && cd -
|
||||||
|
|
||||||
ciclean:
|
cic:
|
||||||
cd ./tests && ./clean_test.sh && cd -
|
cd ./tests && ./clean_test.sh && cd -
|
||||||
|
|
||||||
alltest: gotest ci
|
alltest: gotest ci
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ build: app
|
|||||||
app:
|
app:
|
||||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frpc_darwin_amd64 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frpc_darwin_amd64 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frps_darwin_amd64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frps_darwin_amd64 ./cmd/frps
|
||||||
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./frpc_freebsd_386 ./cmd/frpc
|
||||||
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./frps_freebsd_386 ./cmd/frps
|
||||||
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frpc_freebsd_amd64 ./cmd/frpc
|
||||||
|
env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frps_freebsd_amd64 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_386 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_386 ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./frps_linux_386 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "$(LDFLAGS)" -o ./frps_linux_386 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_amd64 ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_amd64 ./cmd/frpc
|
||||||
@@ -23,10 +27,10 @@ app:
|
|||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mips64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mips64 ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_mips64le ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_mips64le ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mips64le ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mips64le ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_mips ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_mips ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mips ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mips ./cmd/frps
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_mipsle ./cmd/frpc
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./frpc_linux_mipsle ./cmd/frpc
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mipsle ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "$(LDFLAGS)" -o ./frps_linux_mipsle ./cmd/frps
|
||||||
|
|
||||||
temp:
|
temp:
|
||||||
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frps_linux_amd64 ./cmd/frps
|
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -o ./frps_linux_amd64 ./cmd/frps
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -31,8 +31,7 @@ frp is a fast reverse proxy to help you expose a local server behind a NAT or fi
|
|||||||
* [Encryption and Compression](#encryption-and-compression)
|
* [Encryption and Compression](#encryption-and-compression)
|
||||||
* [Hot-Reload frpc configuration](#hot-reload-frpc-configuration)
|
* [Hot-Reload frpc configuration](#hot-reload-frpc-configuration)
|
||||||
* [Get proxy status from client](#get-proxy-status-from-client)
|
* [Get proxy status from client](#get-proxy-status-from-client)
|
||||||
* [Privilege Mode](#privilege-mode)
|
* [Port White List](#port-white-list)
|
||||||
* [Port White List](#port-white-list)
|
|
||||||
* [TCP Stream Multiplexing](#tcp-stream-multiplexing)
|
* [TCP Stream Multiplexing](#tcp-stream-multiplexing)
|
||||||
* [Support KCP Protocol](#support-kcp-protocol)
|
* [Support KCP Protocol](#support-kcp-protocol)
|
||||||
* [Connection Pool](#connection-pool)
|
* [Connection Pool](#connection-pool)
|
||||||
@@ -42,6 +41,7 @@ frp is a fast reverse proxy to help you expose a local server behind a NAT or fi
|
|||||||
* [Custom subdomain names](#custom-subdomain-names)
|
* [Custom subdomain names](#custom-subdomain-names)
|
||||||
* [URL routing](#url-routing)
|
* [URL routing](#url-routing)
|
||||||
* [Connect frps by HTTP PROXY](#connect-frps-by-http-proxy)
|
* [Connect frps by HTTP PROXY](#connect-frps-by-http-proxy)
|
||||||
|
* [Range ports mapping](#range-ports-mapping)
|
||||||
* [Plugin](#plugin)
|
* [Plugin](#plugin)
|
||||||
* [Development Plan](#development-plan)
|
* [Development Plan](#development-plan)
|
||||||
* [Contributing](#contributing)
|
* [Contributing](#contributing)
|
||||||
@@ -383,7 +383,7 @@ Then visit `http://[server_addr]:7500` to see dashboard, default username and pa
|
|||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
|
|
||||||
Since v0.10.0, you only need to set `privilege_token` in frps.ini and frpc.ini.
|
Since v0.10.0, you only need to set `token` in frps.ini and frpc.ini.
|
||||||
|
|
||||||
Note that time duration between server of frpc and frps mustn't exceed 15 minutes because timestamp is used for authentication.
|
Note that time duration between server of frpc and frps mustn't exceed 15 minutes because timestamp is used for authentication.
|
||||||
|
|
||||||
@@ -422,21 +422,17 @@ Then run command `frpc reload -c ./frpc.ini` and wait for about 10 seconds to le
|
|||||||
|
|
||||||
Use `frpc status -c ./frpc.ini` to get status of all proxies. You need to set admin port in frpc's configure file.
|
Use `frpc status -c ./frpc.ini` to get status of all proxies. You need to set admin port in frpc's configure file.
|
||||||
|
|
||||||
### Privilege Mode
|
### Port White List
|
||||||
|
|
||||||
Privilege mode is the default and only mode support in frp since v0.10.0. All proxy configurations are set in client.
|
`allow_ports` in frps.ini is used for preventing abuse of ports:
|
||||||
|
|
||||||
#### Port White List
|
|
||||||
|
|
||||||
`privilege_allow_ports` in frps.ini is used for preventing abuse of ports:
|
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# frps.ini
|
# frps.ini
|
||||||
[common]
|
[common]
|
||||||
privilege_allow_ports = 2000-3000,3001,3003,4000-50000
|
allow_ports = 2000-3000,3001,3003,4000-50000
|
||||||
```
|
```
|
||||||
|
|
||||||
`privilege_allow_ports` consists of a specific port or a range of ports divided by `,`.
|
`allow_ports` consists of a specific port or a range of ports divided by `,`.
|
||||||
|
|
||||||
### TCP Stream Multiplexing
|
### TCP Stream Multiplexing
|
||||||
|
|
||||||
@@ -539,7 +535,7 @@ type = http
|
|||||||
local_port = 80
|
local_port = 80
|
||||||
custom_domains = test.yourdomain.com
|
custom_domains = test.yourdomain.com
|
||||||
http_user = abc
|
http_user = abc
|
||||||
http_pwd = abc
|
http_passwd = abc
|
||||||
```
|
```
|
||||||
|
|
||||||
Visit `http://test.yourdomain.com` and now you need to input username and password.
|
Visit `http://test.yourdomain.com` and now you need to input username and password.
|
||||||
|
|||||||
17
README_zh.md
17
README_zh.md
@@ -29,8 +29,7 @@ frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp
|
|||||||
* [加密与压缩](#加密与压缩)
|
* [加密与压缩](#加密与压缩)
|
||||||
* [客户端热加载配置文件](#客户端热加载配置文件)
|
* [客户端热加载配置文件](#客户端热加载配置文件)
|
||||||
* [客户端查看代理状态](#客户端查看代理状态)
|
* [客户端查看代理状态](#客户端查看代理状态)
|
||||||
* [特权模式](#特权模式)
|
* [端口白名单](#端口白名单)
|
||||||
* [端口白名单](#端口白名单)
|
|
||||||
* [TCP 多路复用](#tcp-多路复用)
|
* [TCP 多路复用](#tcp-多路复用)
|
||||||
* [底层通信可选 kcp 协议](#底层通信可选-kcp-协议)
|
* [底层通信可选 kcp 协议](#底层通信可选-kcp-协议)
|
||||||
* [连接池](#连接池)
|
* [连接池](#连接池)
|
||||||
@@ -401,7 +400,7 @@ dashboard_pwd = admin
|
|||||||
|
|
||||||
### 身份验证
|
### 身份验证
|
||||||
|
|
||||||
从 v0.10.0 版本开始,所有 proxy 配置全部放在客户端(也就是之前版本的特权模式),服务端和客户端的 common 配置中的 `privilege_token` 参数一致则身份验证通过。
|
从 v0.10.0 版本开始,所有 proxy 配置全部放在客户端(也就是之前版本的特权模式),服务端和客户端的 common 配置中的 `token` 参数一致则身份验证通过。
|
||||||
|
|
||||||
需要注意的是 frpc 所在机器和 frps 所在机器的时间相差不能超过 15 分钟,因为时间戳会被用于加密验证中,防止报文被劫持后被其他人利用。
|
需要注意的是 frpc 所在机器和 frps 所在机器的时间相差不能超过 15 分钟,因为时间戳会被用于加密验证中,防止报文被劫持后被其他人利用。
|
||||||
|
|
||||||
@@ -450,21 +449,17 @@ admin_port = 7400
|
|||||||
|
|
||||||
frpc 支持通过 `frpc status -c ./frpc.ini` 命令查看代理的状态信息,此功能需要在 frpc 中配置 admin 端口。
|
frpc 支持通过 `frpc status -c ./frpc.ini` 命令查看代理的状态信息,此功能需要在 frpc 中配置 admin 端口。
|
||||||
|
|
||||||
### 特权模式
|
### 端口白名单
|
||||||
|
|
||||||
由于从 v0.10.0 版本开始,所有 proxy 都在客户端配置,原先的特权模式是目前唯一支持的模式。
|
为了防止端口被滥用,可以手动指定允许哪些端口被使用,在 frps.ini 中通过 `allow_ports` 来指定:
|
||||||
|
|
||||||
#### 端口白名单
|
|
||||||
|
|
||||||
为了防止端口被滥用,可以手动指定允许哪些端口被使用,在 frps.ini 中通过 privilege_allow_ports 来指定:
|
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# frps.ini
|
# frps.ini
|
||||||
[common]
|
[common]
|
||||||
privilege_allow_ports = 2000-3000,3001,3003,4000-50000
|
allow_ports = 2000-3000,3001,3003,4000-50000
|
||||||
```
|
```
|
||||||
|
|
||||||
privilege_allow_ports 可以配置允许使用的某个指定端口或者是一个范围内的所有端口,以 `,` 分隔,指定的范围以 `-` 分隔。
|
`allow_ports` 可以配置允许使用的某个指定端口或者是一个范围内的所有端口,以 `,` 分隔,指定的范围以 `-` 分隔。
|
||||||
|
|
||||||
### TCP 多路复用
|
### TCP 多路复用
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/g"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
@@ -35,7 +35,7 @@ func (svr *Service) RunAdminServer(addr string, port int) (err error) {
|
|||||||
// url router
|
// url router
|
||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
|
|
||||||
user, passwd := config.ClientCommonCfg.AdminUser, config.ClientCommonCfg.AdminPwd
|
user, passwd := g.GlbClientCfg.AdminUser, g.GlbClientCfg.AdminPwd
|
||||||
|
|
||||||
// api, see dashboard_api.go
|
// api, see dashboard_api.go
|
||||||
router.GET("/api/reload", frpNet.HttprouterBasicAuth(svr.apiReload, user, passwd))
|
router.GET("/api/reload", frpNet.HttprouterBasicAuth(svr.apiReload, user, passwd))
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package client
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -24,6 +25,7 @@ import (
|
|||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
ini "github.com/vaughan0/go-ini"
|
ini "github.com/vaughan0/go-ini"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
)
|
)
|
||||||
@@ -51,15 +53,16 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request, _ httprout
|
|||||||
|
|
||||||
log.Info("Http request: [/api/reload]")
|
log.Info("Http request: [/api/reload]")
|
||||||
|
|
||||||
conf, err := ini.LoadFile(config.ClientCommonCfg.ConfigFile)
|
b, err := ioutil.ReadFile(g.GlbClientCfg.CfgFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 1
|
res.Code = 1
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
log.Error("reload frpc config file error: %v", err)
|
log.Error("reload frpc config file error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
content := string(b)
|
||||||
|
|
||||||
newCommonCfg, err := config.LoadClientCommonConf(conf)
|
newCommonCfg, err := config.UnmarshalClientConfFromIni(nil, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 2
|
res.Code = 2
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
@@ -67,7 +70,15 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request, _ httprout
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pxyCfgs, visitorCfgs, err := config.LoadProxyConfFromFile(config.ClientCommonCfg.User, conf, newCommonCfg.Start)
|
conf, err := ini.LoadFile(g.GlbClientCfg.CfgFile)
|
||||||
|
if err != nil {
|
||||||
|
res.Code = 1
|
||||||
|
res.Msg = err.Error()
|
||||||
|
log.Error("reload frpc config file error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pxyCfgs, visitorCfgs, err := config.LoadProxyConfFromIni(g.GlbClientCfg.User, conf, newCommonCfg.Start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 3
|
res.Code = 3
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
@@ -125,18 +136,18 @@ func NewProxyStatusResp(status *ProxyStatus) ProxyStatusResp {
|
|||||||
}
|
}
|
||||||
psr.Plugin = cfg.Plugin
|
psr.Plugin = cfg.Plugin
|
||||||
if status.Err != "" {
|
if status.Err != "" {
|
||||||
psr.RemoteAddr = fmt.Sprintf("%s:%d", config.ClientCommonCfg.ServerAddr, cfg.RemotePort)
|
psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
|
||||||
} else {
|
} else {
|
||||||
psr.RemoteAddr = config.ClientCommonCfg.ServerAddr + status.RemoteAddr
|
psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
|
||||||
}
|
}
|
||||||
case *config.UdpProxyConf:
|
case *config.UdpProxyConf:
|
||||||
if cfg.LocalPort != 0 {
|
if cfg.LocalPort != 0 {
|
||||||
psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort)
|
psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort)
|
||||||
}
|
}
|
||||||
if status.Err != "" {
|
if status.Err != "" {
|
||||||
psr.RemoteAddr = fmt.Sprintf("%s:%d", config.ClientCommonCfg.ServerAddr, cfg.RemotePort)
|
psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
|
||||||
} else {
|
} else {
|
||||||
psr.RemoteAddr = config.ClientCommonCfg.ServerAddr + status.RemoteAddr
|
psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
|
||||||
}
|
}
|
||||||
case *config.HttpProxyConf:
|
case *config.HttpProxyConf:
|
||||||
if cfg.LocalPort != 0 {
|
if cfg.LocalPort != 0 {
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtaci/smux"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/utils/crypto"
|
"github.com/fatedier/frp/utils/crypto"
|
||||||
@@ -29,7 +32,6 @@ import (
|
|||||||
"github.com/fatedier/frp/utils/shutdown"
|
"github.com/fatedier/frp/utils/shutdown"
|
||||||
"github.com/fatedier/frp/utils/util"
|
"github.com/fatedier/frp/utils/util"
|
||||||
"github.com/fatedier/frp/utils/version"
|
"github.com/fatedier/frp/utils/version"
|
||||||
"github.com/xtaci/smux"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -82,8 +84,8 @@ func NewControl(svr *Service, pxyCfgs map[string]config.ProxyConf, visitorCfgs m
|
|||||||
loginMsg := &msg.Login{
|
loginMsg := &msg.Login{
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
Os: runtime.GOOS,
|
Os: runtime.GOOS,
|
||||||
PoolCount: config.ClientCommonCfg.PoolCount,
|
PoolCount: g.GlbClientCfg.PoolCount,
|
||||||
User: config.ClientCommonCfg.User,
|
User: g.GlbClientCfg.User,
|
||||||
Version: version.Full(),
|
Version: version.Full(),
|
||||||
}
|
}
|
||||||
ctl := &Control{
|
ctl := &Control{
|
||||||
@@ -110,7 +112,7 @@ func (ctl *Control) Run() (err error) {
|
|||||||
|
|
||||||
// if login_fail_exit is true, just exit this program
|
// if login_fail_exit is true, just exit this program
|
||||||
// otherwise sleep a while and continues relogin to server
|
// otherwise sleep a while and continues relogin to server
|
||||||
if config.ClientCommonCfg.LoginFailExit {
|
if g.GlbClientCfg.LoginFailExit {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
@@ -183,8 +185,8 @@ func (ctl *Control) login() (err error) {
|
|||||||
ctl.session.Close()
|
ctl.session.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := frpNet.ConnectServerByHttpProxy(config.ClientCommonCfg.HttpProxy, config.ClientCommonCfg.Protocol,
|
conn, err := frpNet.ConnectServerByHttpProxy(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
|
||||||
fmt.Sprintf("%s:%d", config.ClientCommonCfg.ServerAddr, config.ClientCommonCfg.ServerPort))
|
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -195,7 +197,7 @@ func (ctl *Control) login() (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if config.ClientCommonCfg.TcpMux {
|
if g.GlbClientCfg.TcpMux {
|
||||||
session, errRet := smux.Client(conn, nil)
|
session, errRet := smux.Client(conn, nil)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
return errRet
|
return errRet
|
||||||
@@ -210,7 +212,7 @@ func (ctl *Control) login() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
ctl.loginMsg.PrivilegeKey = util.GetAuthKey(config.ClientCommonCfg.PrivilegeToken, now)
|
ctl.loginMsg.PrivilegeKey = util.GetAuthKey(g.GlbClientCfg.Token, now)
|
||||||
ctl.loginMsg.Timestamp = now
|
ctl.loginMsg.Timestamp = now
|
||||||
ctl.loginMsg.RunId = ctl.runId
|
ctl.loginMsg.RunId = ctl.runId
|
||||||
|
|
||||||
@@ -234,7 +236,7 @@ func (ctl *Control) login() (err error) {
|
|||||||
ctl.conn = conn
|
ctl.conn = conn
|
||||||
// update runId got from server
|
// update runId got from server
|
||||||
ctl.runId = loginRespMsg.RunId
|
ctl.runId = loginRespMsg.RunId
|
||||||
config.ClientCommonCfg.ServerUdpPort = loginRespMsg.ServerUdpPort
|
g.GlbClientCfg.ServerUdpPort = loginRespMsg.ServerUdpPort
|
||||||
ctl.ClearLogPrefix()
|
ctl.ClearLogPrefix()
|
||||||
ctl.AddLogPrefix(loginRespMsg.RunId)
|
ctl.AddLogPrefix(loginRespMsg.RunId)
|
||||||
ctl.Info("login to server success, get run id [%s], server udp port [%d]", loginRespMsg.RunId, loginRespMsg.ServerUdpPort)
|
ctl.Info("login to server success, get run id [%s], server udp port [%d]", loginRespMsg.RunId, loginRespMsg.ServerUdpPort)
|
||||||
@@ -242,7 +244,7 @@ func (ctl *Control) login() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
||||||
if config.ClientCommonCfg.TcpMux {
|
if g.GlbClientCfg.TcpMux {
|
||||||
stream, errRet := ctl.session.OpenStream()
|
stream, errRet := ctl.session.OpenStream()
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
@@ -251,8 +253,8 @@ func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
|||||||
}
|
}
|
||||||
conn = frpNet.WrapConn(stream)
|
conn = frpNet.WrapConn(stream)
|
||||||
} else {
|
} else {
|
||||||
conn, err = frpNet.ConnectServerByHttpProxy(config.ClientCommonCfg.HttpProxy, config.ClientCommonCfg.Protocol,
|
conn, err = frpNet.ConnectServerByHttpProxy(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
|
||||||
fmt.Sprintf("%s:%d", config.ClientCommonCfg.ServerAddr, config.ClientCommonCfg.ServerPort))
|
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.Warn("start new connection to server error: %v", err)
|
ctl.Warn("start new connection to server error: %v", err)
|
||||||
return
|
return
|
||||||
@@ -271,7 +273,7 @@ func (ctl *Control) reader() {
|
|||||||
defer ctl.readerShutdown.Done()
|
defer ctl.readerShutdown.Done()
|
||||||
defer close(ctl.closedCh)
|
defer close(ctl.closedCh)
|
||||||
|
|
||||||
encReader := crypto.NewReader(ctl.conn, []byte(config.ClientCommonCfg.PrivilegeToken))
|
encReader := crypto.NewReader(ctl.conn, []byte(g.GlbClientCfg.Token))
|
||||||
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 {
|
||||||
@@ -290,7 +292,7 @@ func (ctl *Control) reader() {
|
|||||||
// writer writes messages got from sendCh to frps
|
// writer writes messages got from sendCh to frps
|
||||||
func (ctl *Control) writer() {
|
func (ctl *Control) writer() {
|
||||||
defer ctl.writerShutdown.Done()
|
defer ctl.writerShutdown.Done()
|
||||||
encWriter, err := crypto.NewWriter(ctl.conn, []byte(config.ClientCommonCfg.PrivilegeToken))
|
encWriter, err := crypto.NewWriter(ctl.conn, []byte(g.GlbClientCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.conn.Error("crypto new writer error: %v", err)
|
ctl.conn.Error("crypto new writer error: %v", err)
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
@@ -318,7 +320,7 @@ func (ctl *Control) msgHandler() {
|
|||||||
}()
|
}()
|
||||||
defer ctl.msgHandlerShutdown.Done()
|
defer ctl.msgHandlerShutdown.Done()
|
||||||
|
|
||||||
hbSend := time.NewTicker(time.Duration(config.ClientCommonCfg.HeartBeatInterval) * time.Second)
|
hbSend := time.NewTicker(time.Duration(g.GlbClientCfg.HeartBeatInterval) * time.Second)
|
||||||
defer hbSend.Stop()
|
defer hbSend.Stop()
|
||||||
hbCheck := time.NewTicker(time.Second)
|
hbCheck := time.NewTicker(time.Second)
|
||||||
defer hbCheck.Stop()
|
defer hbCheck.Stop()
|
||||||
@@ -332,7 +334,7 @@ func (ctl *Control) msgHandler() {
|
|||||||
ctl.Debug("send heartbeat to server")
|
ctl.Debug("send heartbeat to server")
|
||||||
ctl.sendCh <- &msg.Ping{}
|
ctl.sendCh <- &msg.Ping{}
|
||||||
case <-hbCheck.C:
|
case <-hbCheck.C:
|
||||||
if time.Since(ctl.lastPong) > time.Duration(config.ClientCommonCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPong) > time.Duration(g.GlbClientCfg.HeartBeatTimeout)*time.Second {
|
||||||
ctl.Warn("heartbeat timeout")
|
ctl.Warn("heartbeat timeout")
|
||||||
// let reader() stop
|
// let reader() stop
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/models/plugin"
|
"github.com/fatedier/frp/models/plugin"
|
||||||
@@ -46,7 +47,7 @@ type Proxy interface {
|
|||||||
|
|
||||||
func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
|
func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
|
||||||
baseProxy := BaseProxy{
|
baseProxy := BaseProxy{
|
||||||
Logger: log.NewPrefixLogger(pxyConf.GetName()),
|
Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
|
||||||
}
|
}
|
||||||
switch cfg := pxyConf.(type) {
|
switch cfg := pxyConf.(type) {
|
||||||
case *config.TcpProxyConf:
|
case *config.TcpProxyConf:
|
||||||
@@ -115,7 +116,7 @@ func (pxy *TcpProxy) Close() {
|
|||||||
|
|
||||||
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn) {
|
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(config.ClientCommonCfg.PrivilegeToken))
|
[]byte(g.GlbClientCfg.Token))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP
|
// HTTP
|
||||||
@@ -144,7 +145,7 @@ func (pxy *HttpProxy) Close() {
|
|||||||
|
|
||||||
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn) {
|
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(config.ClientCommonCfg.PrivilegeToken))
|
[]byte(g.GlbClientCfg.Token))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPS
|
// HTTPS
|
||||||
@@ -173,7 +174,7 @@ func (pxy *HttpsProxy) Close() {
|
|||||||
|
|
||||||
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn) {
|
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(config.ClientCommonCfg.PrivilegeToken))
|
[]byte(g.GlbClientCfg.Token))
|
||||||
}
|
}
|
||||||
|
|
||||||
// STCP
|
// STCP
|
||||||
@@ -202,7 +203,7 @@ func (pxy *StcpProxy) Close() {
|
|||||||
|
|
||||||
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn) {
|
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(config.ClientCommonCfg.PrivilegeToken))
|
[]byte(g.GlbClientCfg.Token))
|
||||||
}
|
}
|
||||||
|
|
||||||
// XTCP
|
// XTCP
|
||||||
@@ -243,7 +244,7 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn) {
|
|||||||
Sid: natHoleSidMsg.Sid,
|
Sid: natHoleSidMsg.Sid,
|
||||||
}
|
}
|
||||||
raddr, _ := net.ResolveUDPAddr("udp",
|
raddr, _ := net.ResolveUDPAddr("udp",
|
||||||
fmt.Sprintf("%s:%d", config.ClientCommonCfg.ServerAddr, config.ClientCommonCfg.ServerUdpPort))
|
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerUdpPort))
|
||||||
clientConn, err := net.DialUDP("udp", nil, raddr)
|
clientConn, err := net.DialUDP("udp", nil, raddr)
|
||||||
defer clientConn.Close()
|
defer clientConn.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ type ProxyStatus struct {
|
|||||||
|
|
||||||
func NewProxyWrapper(cfg config.ProxyConf) *ProxyWrapper {
|
func NewProxyWrapper(cfg config.ProxyConf) *ProxyWrapper {
|
||||||
return &ProxyWrapper{
|
return &ProxyWrapper{
|
||||||
Name: cfg.GetName(),
|
Name: cfg.GetBaseInfo().ProxyName,
|
||||||
Type: cfg.GetType(),
|
Type: cfg.GetBaseInfo().ProxyType,
|
||||||
Status: ProxyStatusNew,
|
Status: ProxyStatusNew,
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
pxy: nil,
|
pxy: nil,
|
||||||
@@ -227,7 +227,7 @@ func (pm *ProxyManager) CheckAndStartProxy(pxyStatus []string) {
|
|||||||
for _, s := range pxyStatus {
|
for _, s := range pxyStatus {
|
||||||
if status == s {
|
if status == s {
|
||||||
var newProxyMsg msg.NewProxy
|
var newProxyMsg msg.NewProxy
|
||||||
pxy.Cfg.UnMarshalToMsg(&newProxyMsg)
|
pxy.Cfg.MarshalToMsg(&newProxyMsg)
|
||||||
err := pm.sendMsg(&newProxyMsg)
|
err := pm.sendMsg(&newProxyMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pm.Warn("[%s] proxy send NewProxy message error")
|
pm.Warn("[%s] proxy send NewProxy message error")
|
||||||
@@ -240,15 +240,16 @@ func (pm *ProxyManager) CheckAndStartProxy(pxyStatus []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, cfg := range pm.visitorCfgs {
|
for _, cfg := range pm.visitorCfgs {
|
||||||
if _, exist := pm.visitors[cfg.GetName()]; !exist {
|
name := cfg.GetBaseInfo().ProxyName
|
||||||
pm.Info("try to start visitor [%s]", cfg.GetName())
|
if _, exist := pm.visitors[name]; !exist {
|
||||||
|
pm.Info("try to start visitor [%s]", name)
|
||||||
visitor := NewVisitor(pm.ctl, cfg)
|
visitor := NewVisitor(pm.ctl, cfg)
|
||||||
err := visitor.Run()
|
err := visitor.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
visitor.Warn("start error: %v", err)
|
visitor.Warn("start error: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pm.visitors[cfg.GetName()] = visitor
|
pm.visitors[name] = visitor
|
||||||
visitor.Info("start visitor success")
|
visitor.Info("start visitor success")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
)
|
)
|
||||||
@@ -41,12 +42,12 @@ func (svr *Service) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ClientCommonCfg.AdminPort != 0 {
|
if g.GlbClientCfg.AdminPort != 0 {
|
||||||
err = svr.RunAdminServer(config.ClientCommonCfg.AdminAddr, config.ClientCommonCfg.AdminPort)
|
err = svr.RunAdminServer(g.GlbClientCfg.AdminAddr, g.GlbClientCfg.AdminPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("run admin server error: %v", err)
|
log.Warn("run admin server error: %v", err)
|
||||||
}
|
}
|
||||||
log.Info("admin server listen on %s:%d", config.ClientCommonCfg.AdminAddr, config.ClientCommonCfg.AdminPort)
|
log.Info("admin server listen on %s:%d", g.GlbClientCfg.AdminAddr, g.GlbClientCfg.AdminPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-svr.closedCh
|
<-svr.closedCh
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
frpIo "github.com/fatedier/frp/utils/io"
|
frpIo "github.com/fatedier/frp/utils/io"
|
||||||
@@ -45,7 +46,7 @@ type Visitor interface {
|
|||||||
func NewVisitor(ctl *Control, pxyConf config.ProxyConf) (visitor Visitor) {
|
func NewVisitor(ctl *Control, pxyConf config.ProxyConf) (visitor Visitor) {
|
||||||
baseVisitor := BaseVisitor{
|
baseVisitor := BaseVisitor{
|
||||||
ctl: ctl,
|
ctl: ctl,
|
||||||
Logger: log.NewPrefixLogger(pxyConf.GetName()),
|
Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
|
||||||
}
|
}
|
||||||
switch cfg := pxyConf.(type) {
|
switch cfg := pxyConf.(type) {
|
||||||
case *config.StcpProxyConf:
|
case *config.StcpProxyConf:
|
||||||
@@ -193,13 +194,13 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
defer userConn.Close()
|
defer userConn.Close()
|
||||||
|
|
||||||
sv.Debug("get a new xtcp user connection")
|
sv.Debug("get a new xtcp user connection")
|
||||||
if config.ClientCommonCfg.ServerUdpPort == 0 {
|
if g.GlbClientCfg.ServerUdpPort == 0 {
|
||||||
sv.Error("xtcp is not supported by server")
|
sv.Error("xtcp is not supported by server")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
raddr, err := net.ResolveUDPAddr("udp",
|
raddr, err := net.ResolveUDPAddr("udp",
|
||||||
fmt.Sprintf("%s:%d", config.ClientCommonCfg.ServerAddr, config.ClientCommonCfg.ServerUdpPort))
|
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerUdpPort))
|
||||||
visitorConn, err := net.DialUDP("udp", nil, raddr)
|
visitorConn, err := net.DialUDP("udp", nil, raddr)
|
||||||
defer visitorConn.Close()
|
defer visitorConn.Close()
|
||||||
|
|
||||||
|
|||||||
286
cmd/frpc/main.go
286
cmd/frpc/main.go
@@ -15,291 +15,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"github.com/fatedier/frp/cmd/frpc/sub"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
docopt "github.com/docopt/docopt-go"
|
|
||||||
"github.com/rodaine/table"
|
|
||||||
ini "github.com/vaughan0/go-ini"
|
|
||||||
|
|
||||||
"github.com/fatedier/frp/client"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
"github.com/fatedier/frp/utils/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
configFile string = "./frpc.ini"
|
|
||||||
)
|
|
||||||
|
|
||||||
var usage string = `frpc is the client of frp
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
frpc [-c config_file] [-L log_file] [--log-level=<log_level>] [--server-addr=<server_addr>]
|
|
||||||
frpc reload [-c config_file]
|
|
||||||
frpc status [-c config_file]
|
|
||||||
frpc -h | --help
|
|
||||||
frpc -v | --version
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c config_file set config file
|
|
||||||
-L log_file set output log file, including console
|
|
||||||
--log-level=<log_level> set log level: debug, info, warn, error
|
|
||||||
--server-addr=<server_addr> addr which frps is listening for, example: 0.0.0.0:7000
|
|
||||||
-h --help show this screen
|
|
||||||
-v --version show version
|
|
||||||
`
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
sub.Execute()
|
||||||
confFile := "./frpc.ini"
|
|
||||||
// the configures parsed from file will be replaced by those from command line if exist
|
|
||||||
args, err := docopt.Parse(usage, nil, true, version.Full(), false)
|
|
||||||
|
|
||||||
if args["-c"] != nil {
|
|
||||||
confFile = args["-c"].(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf, err := ini.LoadFile(confFile)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.ClientCommonCfg, err = config.LoadClientCommonConf(conf)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
config.ClientCommonCfg.ConfigFile = confFile
|
|
||||||
|
|
||||||
// check if reload command
|
|
||||||
if args["reload"] != nil {
|
|
||||||
if args["reload"].(bool) {
|
|
||||||
if err = CmdReload(); err != nil {
|
|
||||||
fmt.Printf("frps reload error: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("reload success\n")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if status command
|
|
||||||
if args["status"] != nil {
|
|
||||||
if args["status"].(bool) {
|
|
||||||
if err = CmdStatus(); err != nil {
|
|
||||||
fmt.Printf("frpc get status error: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
} else {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["-L"] != nil {
|
|
||||||
if args["-L"].(string) == "console" {
|
|
||||||
config.ClientCommonCfg.LogWay = "console"
|
|
||||||
} else {
|
|
||||||
config.ClientCommonCfg.LogWay = "file"
|
|
||||||
config.ClientCommonCfg.LogFile = args["-L"].(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["--log-level"] != nil {
|
|
||||||
config.ClientCommonCfg.LogLevel = args["--log-level"].(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["--server-addr"] != nil {
|
|
||||||
addr := strings.Split(args["--server-addr"].(string), ":")
|
|
||||||
if len(addr) != 2 {
|
|
||||||
fmt.Println("--server-addr format error: example 0.0.0.0:7000")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
serverPort, err := strconv.ParseInt(addr[1], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("--server-addr format error, example 0.0.0.0:7000")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
config.ClientCommonCfg.ServerAddr = addr[0]
|
|
||||||
config.ClientCommonCfg.ServerPort = int(serverPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["-v"] != nil {
|
|
||||||
if args["-v"].(bool) {
|
|
||||||
fmt.Println(version.Full())
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pxyCfgs, visitorCfgs, err := config.LoadProxyConfFromFile(config.ClientCommonCfg.User, conf, config.ClientCommonCfg.Start)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.InitLog(config.ClientCommonCfg.LogWay, config.ClientCommonCfg.LogFile,
|
|
||||||
config.ClientCommonCfg.LogLevel, config.ClientCommonCfg.LogMaxDays)
|
|
||||||
|
|
||||||
svr := client.NewService(pxyCfgs, visitorCfgs)
|
|
||||||
|
|
||||||
// Capture the exit signal if we use kcp.
|
|
||||||
if config.ClientCommonCfg.Protocol == "kcp" {
|
|
||||||
go HandleSignal(svr)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = svr.Run()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleSignal(svr *client.Service) {
|
|
||||||
ch := make(chan os.Signal)
|
|
||||||
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
<-ch
|
|
||||||
svr.Close()
|
|
||||||
time.Sleep(250 * time.Millisecond)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CmdReload() error {
|
|
||||||
if config.ClientCommonCfg.AdminPort == 0 {
|
|
||||||
return fmt.Errorf("admin_port shoud be set if you want to use reload feature")
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://"+
|
|
||||||
config.ClientCommonCfg.AdminAddr+":"+fmt.Sprintf("%d", config.ClientCommonCfg.AdminPort)+"/api/reload", nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(config.ClientCommonCfg.AdminUser+":"+
|
|
||||||
config.ClientCommonCfg.AdminPwd))
|
|
||||||
|
|
||||||
req.Header.Add("Authorization", authStr)
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
return fmt.Errorf("admin api status code [%d]", resp.StatusCode)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
res := &client.GeneralResponse{}
|
|
||||||
err = json.Unmarshal(body, &res)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body)))
|
|
||||||
} else if res.Code != 0 {
|
|
||||||
return fmt.Errorf(res.Msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CmdStatus() error {
|
|
||||||
if config.ClientCommonCfg.AdminPort == 0 {
|
|
||||||
return fmt.Errorf("admin_port shoud be set if you want to get proxy status")
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://"+
|
|
||||||
config.ClientCommonCfg.AdminAddr+":"+fmt.Sprintf("%d", config.ClientCommonCfg.AdminPort)+"/api/status", nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(config.ClientCommonCfg.AdminUser+":"+
|
|
||||||
config.ClientCommonCfg.AdminPwd))
|
|
||||||
|
|
||||||
req.Header.Add("Authorization", authStr)
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
return fmt.Errorf("admin api status code [%d]", resp.StatusCode)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
res := &client.StatusResp{}
|
|
||||||
err = json.Unmarshal(body, &res)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Proxy Status...")
|
|
||||||
if len(res.Tcp) > 0 {
|
|
||||||
fmt.Printf("TCP")
|
|
||||||
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
|
||||||
for _, ps := range res.Tcp {
|
|
||||||
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
|
||||||
}
|
|
||||||
tbl.Print()
|
|
||||||
fmt.Println("")
|
|
||||||
}
|
|
||||||
if len(res.Udp) > 0 {
|
|
||||||
fmt.Printf("UDP")
|
|
||||||
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
|
||||||
for _, ps := range res.Udp {
|
|
||||||
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
|
||||||
}
|
|
||||||
tbl.Print()
|
|
||||||
fmt.Println("")
|
|
||||||
}
|
|
||||||
if len(res.Http) > 0 {
|
|
||||||
fmt.Printf("HTTP")
|
|
||||||
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
|
||||||
for _, ps := range res.Http {
|
|
||||||
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
|
||||||
}
|
|
||||||
tbl.Print()
|
|
||||||
fmt.Println("")
|
|
||||||
}
|
|
||||||
if len(res.Https) > 0 {
|
|
||||||
fmt.Printf("HTTPS")
|
|
||||||
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
|
||||||
for _, ps := range res.Https {
|
|
||||||
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
|
||||||
}
|
|
||||||
tbl.Print()
|
|
||||||
fmt.Println("")
|
|
||||||
}
|
|
||||||
if len(res.Stcp) > 0 {
|
|
||||||
fmt.Printf("STCP")
|
|
||||||
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
|
||||||
for _, ps := range res.Stcp {
|
|
||||||
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
|
||||||
}
|
|
||||||
tbl.Print()
|
|
||||||
fmt.Println("")
|
|
||||||
}
|
|
||||||
if len(res.Xtcp) > 0 {
|
|
||||||
fmt.Printf("XTCP")
|
|
||||||
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
|
||||||
for _, ps := range res.Xtcp {
|
|
||||||
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
|
||||||
}
|
|
||||||
tbl.Print()
|
|
||||||
fmt.Println("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
96
cmd/frpc/sub/http.go
Normal file
96
cmd/frpc/sub/http.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/models/consts"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp or kcp")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
|
httpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
httpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&customDomains, "custom_domain", "d", "", "custom domain")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&locations, "locations", "", "", "locations")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&httpUser, "http_user", "", "admin", "http auth user")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&httpPwd, "http_pwd", "", "admin", "http auth password")
|
||||||
|
httpCmd.PersistentFlags().StringVarP(&hostHeaderRewrite, "host_header_rewrite", "", "", "host header rewrite")
|
||||||
|
httpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
|
||||||
|
httpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(httpCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpCmd = &cobra.Command{
|
||||||
|
Use: "http",
|
||||||
|
Short: "Run frpc with a single http proxy",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.HttpProxyConf{}
|
||||||
|
var prefix string
|
||||||
|
if user != "" {
|
||||||
|
prefix = user + "."
|
||||||
|
}
|
||||||
|
cfg.ProxyName = prefix + proxyName
|
||||||
|
cfg.ProxyType = consts.HttpProxy
|
||||||
|
cfg.LocalIp = localIp
|
||||||
|
cfg.LocalPort = localPort
|
||||||
|
cfg.CustomDomains = strings.Split(customDomains, ",")
|
||||||
|
cfg.SubDomain = subDomain
|
||||||
|
cfg.Locations = strings.Split(locations, ",")
|
||||||
|
cfg.HttpUser = httpUser
|
||||||
|
cfg.HttpPwd = httpPwd
|
||||||
|
cfg.HostHeaderRewrite = hostHeaderRewrite
|
||||||
|
cfg.UseEncryption = useEncryption
|
||||||
|
cfg.UseCompression = useCompression
|
||||||
|
|
||||||
|
err = cfg.CheckForCli()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(proxyConfs, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
88
cmd/frpc/sub/https.go
Normal file
88
cmd/frpc/sub/https.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/models/consts"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp or kcp")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
|
httpsCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
httpsCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&customDomains, "custom_domain", "d", "", "custom domain")
|
||||||
|
httpsCmd.PersistentFlags().StringVarP(&subDomain, "sd", "", "", "sub domain")
|
||||||
|
httpsCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
|
||||||
|
httpsCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(httpsCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpsCmd = &cobra.Command{
|
||||||
|
Use: "https",
|
||||||
|
Short: "Run frpc with a single https proxy",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.HttpsProxyConf{}
|
||||||
|
var prefix string
|
||||||
|
if user != "" {
|
||||||
|
prefix = user + "."
|
||||||
|
}
|
||||||
|
cfg.ProxyName = prefix + proxyName
|
||||||
|
cfg.ProxyType = consts.HttpsProxy
|
||||||
|
cfg.LocalIp = localIp
|
||||||
|
cfg.LocalPort = localPort
|
||||||
|
cfg.CustomDomains = strings.Split(customDomains, ",")
|
||||||
|
cfg.SubDomain = subDomain
|
||||||
|
cfg.UseEncryption = useEncryption
|
||||||
|
cfg.UseCompression = useCompression
|
||||||
|
|
||||||
|
err = cfg.CheckForCli()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(proxyConfs, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
92
cmd/frpc/sub/reload.go
Normal file
92
cmd/frpc/sub/reload.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/client"
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(reloadCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var reloadCmd = &cobra.Command{
|
||||||
|
Use: "reload",
|
||||||
|
Short: "Hot-Reload frpc configuration",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeIni, cfgFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reload()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("frpc reload error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("reload success\n")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func reload() error {
|
||||||
|
if g.GlbClientCfg.AdminPort == 0 {
|
||||||
|
return fmt.Errorf("admin_port shoud be set if you want to use reload feature")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://"+
|
||||||
|
g.GlbClientCfg.AdminAddr+":"+fmt.Sprintf("%d", g.GlbClientCfg.AdminPort)+"/api/reload", nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
|
||||||
|
g.GlbClientCfg.AdminPwd))
|
||||||
|
|
||||||
|
req.Header.Add("Authorization", authStr)
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return fmt.Errorf("admin api status code [%d]", resp.StatusCode)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res := &client.GeneralResponse{}
|
||||||
|
err = json.Unmarshal(body, &res)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body)))
|
||||||
|
} else if res.Code != 0 {
|
||||||
|
return fmt.Errorf(res.Msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
215
cmd/frpc/sub/root.go
Normal file
215
cmd/frpc/sub/root.go
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
ini "github.com/vaughan0/go-ini"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/client"
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
"github.com/fatedier/frp/utils/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CfgFileTypeIni = iota
|
||||||
|
CfgFileTypeCmd
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cfgFile string
|
||||||
|
showVersion bool
|
||||||
|
|
||||||
|
serverAddr string
|
||||||
|
user string
|
||||||
|
protocol string
|
||||||
|
token string
|
||||||
|
logLevel string
|
||||||
|
logFile string
|
||||||
|
logMaxDays int
|
||||||
|
|
||||||
|
proxyName string
|
||||||
|
localIp string
|
||||||
|
localPort int
|
||||||
|
remotePort int
|
||||||
|
useEncryption bool
|
||||||
|
useCompression bool
|
||||||
|
customDomains string
|
||||||
|
subDomain string
|
||||||
|
httpUser string
|
||||||
|
httpPwd string
|
||||||
|
locations string
|
||||||
|
hostHeaderRewrite string
|
||||||
|
role string
|
||||||
|
sk string
|
||||||
|
serverName string
|
||||||
|
bindAddr string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&cfgFile, "", "c", "./frpc.ini", "config file of frpc")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "frpc",
|
||||||
|
Short: "frpc is the client of frp (https://github.com/fatedier/frp)",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if showVersion {
|
||||||
|
fmt.Println(version.Full())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not show command usage here.
|
||||||
|
err := runClient(cfgFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSignal(svr *client.Service) {
|
||||||
|
ch := make(chan os.Signal)
|
||||||
|
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-ch
|
||||||
|
svr.Close()
|
||||||
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseClientCommonCfg(fileType int, filePath string) (err error) {
|
||||||
|
if fileType == CfgFileTypeIni {
|
||||||
|
err = parseClientCommonCfgFromIni(filePath)
|
||||||
|
} else if fileType == CfgFileTypeCmd {
|
||||||
|
err = parseClientCommonCfgFromCmd()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.GlbClientCfg.CfgFile = cfgFile
|
||||||
|
|
||||||
|
err = g.GlbClientCfg.ClientCommonConf.Check()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseClientCommonCfgFromIni(filePath string) (err error) {
|
||||||
|
b, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content := string(b)
|
||||||
|
|
||||||
|
cfg, err := config.UnmarshalClientConfFromIni(&g.GlbClientCfg.ClientCommonConf, content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.GlbClientCfg.ClientCommonConf = *cfg
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseClientCommonCfgFromCmd() (err error) {
|
||||||
|
strs := strings.Split(serverAddr, ":")
|
||||||
|
if len(strs) < 2 {
|
||||||
|
err = fmt.Errorf("invalid server_addr")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strs[0] != "" {
|
||||||
|
g.GlbClientCfg.ServerAddr = strs[0]
|
||||||
|
}
|
||||||
|
g.GlbClientCfg.ServerPort, err = strconv.Atoi(strs[1])
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("invalid server_addr")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.GlbClientCfg.User = user
|
||||||
|
g.GlbClientCfg.Protocol = protocol
|
||||||
|
g.GlbClientCfg.Token = token
|
||||||
|
g.GlbClientCfg.LogLevel = logLevel
|
||||||
|
g.GlbClientCfg.LogFile = logFile
|
||||||
|
g.GlbClientCfg.LogMaxDays = int64(logMaxDays)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runClient(cfgFilePath string) (err error) {
|
||||||
|
err = parseClientCommonCfg(CfgFileTypeIni, cfgFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conf, err := ini.LoadFile(cfgFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pxyCfgs, visitorCfgs, err := config.LoadProxyConfFromIni(g.GlbClientCfg.User, conf, g.GlbClientCfg.Start)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = startService(pxyCfgs, visitorCfgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.ProxyConf) (err error) {
|
||||||
|
log.InitLog(g.GlbClientCfg.LogWay, g.GlbClientCfg.LogFile, g.GlbClientCfg.LogLevel, g.GlbClientCfg.LogMaxDays)
|
||||||
|
if g.GlbClientCfg.DnsServer != "" {
|
||||||
|
s := g.GlbClientCfg.DnsServer
|
||||||
|
if !strings.Contains(s, ":") {
|
||||||
|
s += ":53"
|
||||||
|
}
|
||||||
|
// Change default dns server for frpc
|
||||||
|
net.DefaultResolver = &net.Resolver{
|
||||||
|
PreferGo: true,
|
||||||
|
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
return net.Dial("udp", s)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
svr := client.NewService(pxyCfgs, visitorCfgs)
|
||||||
|
|
||||||
|
// Capture the exit signal if we use kcp.
|
||||||
|
if g.GlbClientCfg.Protocol == "kcp" {
|
||||||
|
go handleSignal(svr)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = svr.Run()
|
||||||
|
return
|
||||||
|
}
|
||||||
146
cmd/frpc/sub/status.go
Normal file
146
cmd/frpc/sub/status.go
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rodaine/table"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/client"
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(statusCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusCmd = &cobra.Command{
|
||||||
|
Use: "status",
|
||||||
|
Short: "Overview of all proxies status",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeIni, cfgFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = status()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("frpc get status error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func status() error {
|
||||||
|
if g.GlbClientCfg.AdminPort == 0 {
|
||||||
|
return fmt.Errorf("admin_port shoud be set if you want to get proxy status")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", "http://"+
|
||||||
|
g.GlbClientCfg.AdminAddr+":"+fmt.Sprintf("%d", g.GlbClientCfg.AdminPort)+"/api/status", nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
|
||||||
|
g.GlbClientCfg.AdminPwd))
|
||||||
|
|
||||||
|
req.Header.Add("Authorization", authStr)
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return fmt.Errorf("admin api status code [%d]", resp.StatusCode)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res := &client.StatusResp{}
|
||||||
|
err = json.Unmarshal(body, &res)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unmarshal http response error: %s", strings.TrimSpace(string(body)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Proxy Status...")
|
||||||
|
if len(res.Tcp) > 0 {
|
||||||
|
fmt.Printf("TCP")
|
||||||
|
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
||||||
|
for _, ps := range res.Tcp {
|
||||||
|
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
||||||
|
}
|
||||||
|
tbl.Print()
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
if len(res.Udp) > 0 {
|
||||||
|
fmt.Printf("UDP")
|
||||||
|
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
||||||
|
for _, ps := range res.Udp {
|
||||||
|
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
||||||
|
}
|
||||||
|
tbl.Print()
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
if len(res.Http) > 0 {
|
||||||
|
fmt.Printf("HTTP")
|
||||||
|
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
||||||
|
for _, ps := range res.Http {
|
||||||
|
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
||||||
|
}
|
||||||
|
tbl.Print()
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
if len(res.Https) > 0 {
|
||||||
|
fmt.Printf("HTTPS")
|
||||||
|
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
||||||
|
for _, ps := range res.Https {
|
||||||
|
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
||||||
|
}
|
||||||
|
tbl.Print()
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
if len(res.Stcp) > 0 {
|
||||||
|
fmt.Printf("STCP")
|
||||||
|
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
||||||
|
for _, ps := range res.Stcp {
|
||||||
|
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
||||||
|
}
|
||||||
|
tbl.Print()
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
if len(res.Xtcp) > 0 {
|
||||||
|
fmt.Printf("XTCP")
|
||||||
|
tbl := table.New("Name", "Status", "LocalAddr", "Plugin", "RemoteAddr", "Error")
|
||||||
|
for _, ps := range res.Xtcp {
|
||||||
|
tbl.AddRow(ps.Name, ps.Status, ps.LocalAddr, ps.Plugin, ps.RemoteAddr, ps.Err)
|
||||||
|
}
|
||||||
|
tbl.Print()
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
102
cmd/frpc/sub/stcp.go
Normal file
102
cmd/frpc/sub/stcp.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/models/consts"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp or kcp")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
|
stcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&sk, "sk", "", "", "secret key")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&serverName, "server_name", "", "", "server name")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
stcpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
|
||||||
|
stcpCmd.PersistentFlags().StringVarP(&bindAddr, "bind_addr", "", "", "bind addr")
|
||||||
|
stcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
|
||||||
|
stcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(stcpCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stcpCmd = &cobra.Command{
|
||||||
|
Use: "stcp",
|
||||||
|
Short: "Run frpc with a single stcp proxy",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.StcpProxyConf{}
|
||||||
|
var prefix string
|
||||||
|
if user != "" {
|
||||||
|
prefix = user + "."
|
||||||
|
}
|
||||||
|
cfg.ProxyName = prefix + proxyName
|
||||||
|
cfg.ProxyType = consts.StcpProxy
|
||||||
|
cfg.Role = role
|
||||||
|
cfg.Sk = sk
|
||||||
|
cfg.ServerName = serverName
|
||||||
|
cfg.LocalIp = localIp
|
||||||
|
cfg.LocalPort = localPort
|
||||||
|
cfg.BindAddr = bindAddr
|
||||||
|
cfg.UseEncryption = useEncryption
|
||||||
|
cfg.UseCompression = useCompression
|
||||||
|
|
||||||
|
err = cfg.CheckForCli()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Role == "server" {
|
||||||
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(proxyConfs, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
visitorConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(nil, visitorConfs)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
85
cmd/frpc/sub/tcp.go
Normal file
85
cmd/frpc/sub/tcp.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/models/consts"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp or kcp")
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
|
tcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
|
tcpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
tcpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
|
||||||
|
tcpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
|
||||||
|
tcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
|
||||||
|
tcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(tcpCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tcpCmd = &cobra.Command{
|
||||||
|
Use: "tcp",
|
||||||
|
Short: "Run frpc with a single tcp proxy",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.TcpProxyConf{}
|
||||||
|
var prefix string
|
||||||
|
if user != "" {
|
||||||
|
prefix = user + "."
|
||||||
|
}
|
||||||
|
cfg.ProxyName = prefix + proxyName
|
||||||
|
cfg.ProxyType = consts.TcpProxy
|
||||||
|
cfg.LocalIp = localIp
|
||||||
|
cfg.LocalPort = localPort
|
||||||
|
cfg.RemotePort = remotePort
|
||||||
|
cfg.UseEncryption = useEncryption
|
||||||
|
cfg.UseCompression = useCompression
|
||||||
|
|
||||||
|
err = cfg.CheckForCli()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(proxyConfs, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
85
cmd/frpc/sub/udp.go
Normal file
85
cmd/frpc/sub/udp.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/models/consts"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp or kcp")
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
|
udpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
|
udpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
udpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
|
||||||
|
udpCmd.PersistentFlags().IntVarP(&remotePort, "remote_port", "r", 0, "remote port")
|
||||||
|
udpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
|
||||||
|
udpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(udpCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var udpCmd = &cobra.Command{
|
||||||
|
Use: "udp",
|
||||||
|
Short: "Run frpc with a single udp proxy",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.UdpProxyConf{}
|
||||||
|
var prefix string
|
||||||
|
if user != "" {
|
||||||
|
prefix = user + "."
|
||||||
|
}
|
||||||
|
cfg.ProxyName = prefix + proxyName
|
||||||
|
cfg.ProxyType = consts.UdpProxy
|
||||||
|
cfg.LocalIp = localIp
|
||||||
|
cfg.LocalPort = localPort
|
||||||
|
cfg.RemotePort = remotePort
|
||||||
|
cfg.UseEncryption = useEncryption
|
||||||
|
cfg.UseCompression = useCompression
|
||||||
|
|
||||||
|
err = cfg.CheckForCli()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(proxyConfs, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
102
cmd/frpc/sub/xtcp.go
Normal file
102
cmd/frpc/sub/xtcp.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/models/consts"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp or kcp")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
|
xtcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&sk, "sk", "", "", "secret key")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&serverName, "server_name", "", "", "server name")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
xtcpCmd.PersistentFlags().IntVarP(&localPort, "local_port", "l", 0, "local port")
|
||||||
|
xtcpCmd.PersistentFlags().StringVarP(&bindAddr, "bind_addr", "", "", "bind addr")
|
||||||
|
xtcpCmd.PersistentFlags().BoolVarP(&useEncryption, "ue", "", false, "use encryption")
|
||||||
|
xtcpCmd.PersistentFlags().BoolVarP(&useCompression, "uc", "", false, "use compression")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(xtcpCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xtcpCmd = &cobra.Command{
|
||||||
|
Use: "xtcp",
|
||||||
|
Short: "Run frpc with a single xtcp proxy",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.XtcpProxyConf{}
|
||||||
|
var prefix string
|
||||||
|
if user != "" {
|
||||||
|
prefix = user + "."
|
||||||
|
}
|
||||||
|
cfg.ProxyName = prefix + proxyName
|
||||||
|
cfg.ProxyType = consts.XtcpProxy
|
||||||
|
cfg.Role = role
|
||||||
|
cfg.Sk = sk
|
||||||
|
cfg.ServerName = serverName
|
||||||
|
cfg.LocalIp = localIp
|
||||||
|
cfg.LocalPort = localPort
|
||||||
|
cfg.BindAddr = bindAddr
|
||||||
|
cfg.UseEncryption = useEncryption
|
||||||
|
cfg.UseCompression = useCompression
|
||||||
|
|
||||||
|
err = cfg.CheckForCli()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Role == "server" {
|
||||||
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(proxyConfs, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
visitorConfs := map[string]config.ProxyConf{
|
||||||
|
cfg.ProxyName: cfg,
|
||||||
|
}
|
||||||
|
err = startService(nil, visitorConfs)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
103
cmd/frps/main.go
103
cmd/frps/main.go
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2016 fatedier, fatedier@gmail.com
|
// Copyright 2018 fatedier, fatedier@gmail.com
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -14,105 +14,6 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
docopt "github.com/docopt/docopt-go"
|
|
||||||
ini "github.com/vaughan0/go-ini"
|
|
||||||
|
|
||||||
"github.com/fatedier/frp/models/config"
|
|
||||||
"github.com/fatedier/frp/server"
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
"github.com/fatedier/frp/utils/version"
|
|
||||||
)
|
|
||||||
|
|
||||||
var usage string = `frps is the server of frp
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
frps [-c config_file] [-L log_file] [--log-level=<log_level>] [--addr=<bind_addr>]
|
|
||||||
frps -h | --help
|
|
||||||
frps -v | --version
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c config_file set config file
|
|
||||||
-L log_file set output log file, including console
|
|
||||||
--log-level=<log_level> set log level: debug, info, warn, error
|
|
||||||
--addr=<bind_addr> listen addr for client, example: 0.0.0.0:7000
|
|
||||||
-h --help show this screen
|
|
||||||
-v --version show version
|
|
||||||
`
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
Execute()
|
||||||
confFile := "./frps.ini"
|
|
||||||
// the configures parsed from file will be replaced by those from command line if exist
|
|
||||||
args, err := docopt.Parse(usage, nil, true, version.Full(), false)
|
|
||||||
|
|
||||||
if args["-c"] != nil {
|
|
||||||
confFile = args["-c"].(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf, err := ini.LoadFile(confFile)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
config.ServerCommonCfg, err = config.LoadServerCommonConf(conf)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["-L"] != nil {
|
|
||||||
if args["-L"].(string) == "console" {
|
|
||||||
config.ServerCommonCfg.LogWay = "console"
|
|
||||||
} else {
|
|
||||||
config.ServerCommonCfg.LogWay = "file"
|
|
||||||
config.ServerCommonCfg.LogFile = args["-L"].(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["--log-level"] != nil {
|
|
||||||
config.ServerCommonCfg.LogLevel = args["--log-level"].(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["--addr"] != nil {
|
|
||||||
addr := strings.Split(args["--addr"].(string), ":")
|
|
||||||
if len(addr) != 2 {
|
|
||||||
fmt.Println("--addr format error: example 0.0.0.0:7000")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
bindPort, err := strconv.ParseInt(addr[1], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("--addr format error, example 0.0.0.0:7000")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
config.ServerCommonCfg.BindAddr = addr[0]
|
|
||||||
config.ServerCommonCfg.BindPort = int(bindPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args["-v"] != nil {
|
|
||||||
if args["-v"].(bool) {
|
|
||||||
fmt.Println(version.Full())
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.InitLog(config.ServerCommonCfg.LogWay, config.ServerCommonCfg.LogFile,
|
|
||||||
config.ServerCommonCfg.LogLevel, config.ServerCommonCfg.LogMaxDays)
|
|
||||||
|
|
||||||
svr, err := server.NewService()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
log.Info("Start frps success")
|
|
||||||
if config.ServerCommonCfg.PrivilegeMode == true {
|
|
||||||
log.Info("PrivilegeMode is enabled, you should pay more attention to security issues")
|
|
||||||
}
|
|
||||||
server.ServerService = svr
|
|
||||||
svr.Run()
|
|
||||||
}
|
}
|
||||||
|
|||||||
176
cmd/frps/root.go
Normal file
176
cmd/frps/root.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
"github.com/fatedier/frp/server"
|
||||||
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
"github.com/fatedier/frp/utils/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CfgFileTypeIni = iota
|
||||||
|
CfgFileTypeCmd
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cfgFile string
|
||||||
|
showVersion bool
|
||||||
|
|
||||||
|
bindAddr string
|
||||||
|
bindPort int
|
||||||
|
bindUdpPort int
|
||||||
|
kcpBindPort int
|
||||||
|
proxyBindAddr string
|
||||||
|
vhostHttpPort int
|
||||||
|
vhostHttpsPort int
|
||||||
|
dashboardAddr string
|
||||||
|
dashboardPort int
|
||||||
|
dashboardUser string
|
||||||
|
dashboardPwd string
|
||||||
|
assetsDir string
|
||||||
|
logFile string
|
||||||
|
logWay string
|
||||||
|
logLevel string
|
||||||
|
logMaxDays int64
|
||||||
|
token string
|
||||||
|
authTimeout int64
|
||||||
|
subDomainHost string
|
||||||
|
tcpMux bool
|
||||||
|
allowPorts string
|
||||||
|
maxPoolCount int64
|
||||||
|
maxPortsPerClient int64
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&cfgFile, "", "c", "", "config file of frps")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
|
||||||
|
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&bindAddr, "bind_addr", "", "0.0.0.0", "bind address")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&bindPort, "bind_port", "p", 7000, "bind port")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&bindUdpPort, "bind_udp_port", "", 0, "bind udp port")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&kcpBindPort, "kcp_bind_port", "", 0, "kcp bind udp port")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&proxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&vhostHttpPort, "vhost_http_port", "", 0, "vhost http port")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&vhostHttpsPort, "vhost_https_port", "", 0, "vhost https port")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&dashboardAddr, "dashboard_addr", "", "0.0.0.0", "dasboard address")
|
||||||
|
rootCmd.PersistentFlags().IntVarP(&dashboardPort, "dashboard_port", "", 0, "dashboard port")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&dashboardUser, "dashboard_user", "", "admin", "dashboard user")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&dashboardPwd, "dashboard_pwd", "", "admin", "dashboard password")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&logWay, "log_way", "", "console", "log way")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
|
rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log_max_days")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&token, "token", "", "", "auth token")
|
||||||
|
rootCmd.PersistentFlags().Int64VarP(&authTimeout, "auth_timeout", "", 900, "auth timeout")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&subDomainHost, "subdomain_host", "", "", "subdomain host")
|
||||||
|
rootCmd.PersistentFlags().Int64VarP(&maxPortsPerClient, "max_ports_per_client", "", 0, "max ports per client")
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "frps",
|
||||||
|
Short: "frps is the server of frp (https://github.com/fatedier/frp)",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if showVersion {
|
||||||
|
fmt.Println(version.Full())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfgFile != "" {
|
||||||
|
parseServerCommonCfg(CfgFileTypeIni, cfgFile)
|
||||||
|
} else {
|
||||||
|
parseServerCommonCfg(CfgFileTypeCmd, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := runServer()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseServerCommonCfg(fileType int, filePath string) (err error) {
|
||||||
|
if fileType == CfgFileTypeIni {
|
||||||
|
err = parseServerCommonCfgFromIni(filePath)
|
||||||
|
} else if fileType == CfgFileTypeCmd {
|
||||||
|
err = parseServerCommonCfgFromCmd()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.GlbServerCfg.CfgFile = cfgFile
|
||||||
|
|
||||||
|
err = g.GlbServerCfg.ServerCommonConf.Check()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.InitServerCfg(&g.GlbServerCfg.ServerCommonConf)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseServerCommonCfgFromIni(filePath string) (err error) {
|
||||||
|
b, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content := string(b)
|
||||||
|
|
||||||
|
cfg, err := config.UnmarshalServerConfFromIni(&g.GlbServerCfg.ServerCommonConf, content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.GlbServerCfg.ServerCommonConf = *cfg
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseServerCommonCfgFromCmd() (err error) {
|
||||||
|
g.GlbServerCfg.BindAddr = bindAddr
|
||||||
|
g.GlbServerCfg.BindPort = bindPort
|
||||||
|
g.GlbServerCfg.BindUdpPort = bindUdpPort
|
||||||
|
g.GlbServerCfg.KcpBindPort = kcpBindPort
|
||||||
|
g.GlbServerCfg.ProxyBindAddr = proxyBindAddr
|
||||||
|
g.GlbServerCfg.VhostHttpPort = vhostHttpPort
|
||||||
|
g.GlbServerCfg.VhostHttpsPort = vhostHttpsPort
|
||||||
|
g.GlbServerCfg.DashboardAddr = dashboardAddr
|
||||||
|
g.GlbServerCfg.DashboardPort = dashboardPort
|
||||||
|
g.GlbServerCfg.DashboardUser = dashboardUser
|
||||||
|
g.GlbServerCfg.DashboardPwd = dashboardPwd
|
||||||
|
g.GlbServerCfg.LogFile = logFile
|
||||||
|
g.GlbServerCfg.LogWay = logWay
|
||||||
|
g.GlbServerCfg.LogLevel = logLevel
|
||||||
|
g.GlbServerCfg.LogMaxDays = logMaxDays
|
||||||
|
g.GlbServerCfg.Token = token
|
||||||
|
g.GlbServerCfg.AuthTimeout = authTimeout
|
||||||
|
g.GlbServerCfg.SubDomainHost = subDomainHost
|
||||||
|
g.GlbServerCfg.MaxPortsPerClient = maxPortsPerClient
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func runServer() (err error) {
|
||||||
|
log.InitLog(g.GlbServerCfg.LogWay, g.GlbServerCfg.LogFile, g.GlbServerCfg.LogLevel,
|
||||||
|
g.GlbServerCfg.LogMaxDays)
|
||||||
|
svr, err := server.NewService()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Info("Start frps success")
|
||||||
|
server.ServerService = svr
|
||||||
|
svr.Run()
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ server_port = 7000
|
|||||||
|
|
||||||
# if you want to connect frps by http proxy, you can set http_proxy here or in global environment variables
|
# if you want to connect frps by http proxy, you can set http_proxy here or in global environment variables
|
||||||
# it only works when protocol is tcp
|
# it only works when protocol is tcp
|
||||||
# http_proxy = http://user:pwd@192.168.1.128:8080
|
# http_proxy = http://user:passwd@192.168.1.128:8080
|
||||||
|
|
||||||
# console or real logFile path like ./frpc.log
|
# console or real logFile path like ./frpc.log
|
||||||
log_file = ./frpc.log
|
log_file = ./frpc.log
|
||||||
@@ -18,13 +18,13 @@ log_level = info
|
|||||||
log_max_days = 3
|
log_max_days = 3
|
||||||
|
|
||||||
# for authentication
|
# for authentication
|
||||||
privilege_token = 12345678
|
token = 12345678
|
||||||
|
|
||||||
# set admin address for control frpc's action by http api such as reload
|
# set admin address for control frpc's action by http api such as reload
|
||||||
admin_addr = 127.0.0.1
|
admin_addr = 127.0.0.1
|
||||||
admin_port = 7400
|
admin_port = 7400
|
||||||
admin_user = admin
|
admin_user = admin
|
||||||
admin_pwd = admin
|
admin_passwd = admin
|
||||||
|
|
||||||
# connections will be established in advance, default value is zero
|
# connections will be established in advance, default value is zero
|
||||||
pool_count = 5
|
pool_count = 5
|
||||||
@@ -43,6 +43,9 @@ login_fail_exit = true
|
|||||||
# now it supports tcp and kcp, default is tcp
|
# now it supports tcp and kcp, default is tcp
|
||||||
protocol = tcp
|
protocol = tcp
|
||||||
|
|
||||||
|
# specify a dns server, so frpc will use this instead of default one
|
||||||
|
dns_server = 8.8.8.8
|
||||||
|
|
||||||
# proxy names you want to start divided by ','
|
# proxy names you want to start divided by ','
|
||||||
# default is empty, means all proxies
|
# default is empty, means all proxies
|
||||||
# start = ssh,dns
|
# start = ssh,dns
|
||||||
@@ -73,7 +76,7 @@ local_port = 22
|
|||||||
# if remote_port is 0, frps will assgin a random port for you
|
# if remote_port is 0, frps will assgin a random port for you
|
||||||
remote_port = 0
|
remote_port = 0
|
||||||
|
|
||||||
# if you want tp expose multiple ports, add 'range:' prefix to the section name
|
# if you want to expose multiple ports, add 'range:' prefix to the section name
|
||||||
# frpc will generate multiple proxies such as 'tcp_port_6010', 'tcp_port_6011' and so on.
|
# frpc will generate multiple proxies such as 'tcp_port_6010', 'tcp_port_6011' and so on.
|
||||||
[range:tcp_port]
|
[range:tcp_port]
|
||||||
type = tcp
|
type = tcp
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ vhost_https_port = 443
|
|||||||
dashboard_addr = 0.0.0.0
|
dashboard_addr = 0.0.0.0
|
||||||
dashboard_port = 7500
|
dashboard_port = 7500
|
||||||
|
|
||||||
# dashboard user and pwd for basic auth protect, if not set, both default value is admin
|
# dashboard user and passwd for basic auth protect, if not set, both default value is admin
|
||||||
dashboard_user = admin
|
dashboard_user = admin
|
||||||
dashboard_pwd = admin
|
dashboard_passwd = admin
|
||||||
|
|
||||||
# dashboard assets directory(only for debug mode)
|
# dashboard assets directory(only for debug mode)
|
||||||
# assets_dir = ./static
|
# assets_dir = ./static
|
||||||
@@ -39,15 +39,15 @@ log_level = info
|
|||||||
|
|
||||||
log_max_days = 3
|
log_max_days = 3
|
||||||
|
|
||||||
# privilege mode is the only supported mode since v0.10.0
|
# auth token
|
||||||
privilege_token = 12345678
|
token = 12345678
|
||||||
|
|
||||||
# heartbeat configure, it's not recommended to modify the default value
|
# heartbeat configure, it's not recommended to modify the default value
|
||||||
# the default value of heartbeat_timeout is 90
|
# the default value of heartbeat_timeout is 90
|
||||||
# heartbeat_timeout = 90
|
# heartbeat_timeout = 90
|
||||||
|
|
||||||
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
|
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
|
||||||
privilege_allow_ports = 2000-3000,3001,3003,4000-50000
|
allow_ports = 2000-3000,3001,3003,4000-50000
|
||||||
|
|
||||||
# pool_count in each proxy will change to max_pool_count if they exceed the maximum value
|
# pool_count in each proxy will change to max_pool_count if they exceed the maximum value
|
||||||
max_pool_count = 5
|
max_pool_count = 5
|
||||||
|
|||||||
32
g/g.go
Normal file
32
g/g.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package g
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fatedier/frp/models/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
GlbClientCfg *ClientCfg
|
||||||
|
GlbServerCfg *ServerCfg
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
GlbClientCfg = &ClientCfg{
|
||||||
|
ClientCommonConf: *config.GetDefaultClientConf(),
|
||||||
|
}
|
||||||
|
GlbServerCfg = &ServerCfg{
|
||||||
|
ServerCommonConf: *config.GetDefaultServerConf(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientCfg struct {
|
||||||
|
config.ClientCommonConf
|
||||||
|
|
||||||
|
CfgFile string
|
||||||
|
ServerUdpPort int // this is configured by login response from frps
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerCfg struct {
|
||||||
|
config.ServerCommonConf
|
||||||
|
|
||||||
|
CfgFile string
|
||||||
|
}
|
||||||
16
glide.lock
generated
16
glide.lock
generated
@@ -1,5 +1,5 @@
|
|||||||
hash: 4095d78a15bf0e7ffdd63331ce75d7199d663cc8710dcd08b9dcd09ba3183eac
|
hash: 367ad1f2515b51db9d04d5620fd88843fb6faabf303fe3103b896ef7a3f5a126
|
||||||
updated: 2018-01-23T14:48:38.764359+08:00
|
updated: 2018-04-23T02:33:52.913905+08:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/armon/go-socks5
|
- name: github.com/armon/go-socks5
|
||||||
version: e75332964ef517daa070d7c38a9466a0d687e0a5
|
version: e75332964ef517daa070d7c38a9466a0d687e0a5
|
||||||
@@ -7,8 +7,6 @@ imports:
|
|||||||
version: 346938d642f2ec3594ed81d874461961cd0faa76
|
version: 346938d642f2ec3594ed81d874461961cd0faa76
|
||||||
subpackages:
|
subpackages:
|
||||||
- spew
|
- spew
|
||||||
- name: github.com/docopt/docopt-go
|
|
||||||
version: 784ddc588536785e7299f7272f39101f7faccc3f
|
|
||||||
- name: github.com/fatedier/beego
|
- name: github.com/fatedier/beego
|
||||||
version: 6c6a4f5bd5eb5a39f7e289b8f345b55f75e7e3e8
|
version: 6c6a4f5bd5eb5a39f7e289b8f345b55f75e7e3e8
|
||||||
subpackages:
|
subpackages:
|
||||||
@@ -18,7 +16,9 @@ imports:
|
|||||||
- name: github.com/golang/snappy
|
- name: github.com/golang/snappy
|
||||||
version: 5979233c5d6225d4a8e438cdd0b411888449ddab
|
version: 5979233c5d6225d4a8e438cdd0b411888449ddab
|
||||||
- name: github.com/gorilla/websocket
|
- name: github.com/gorilla/websocket
|
||||||
version: 292fd08b2560ad524ee37396253d71570339a821
|
version: ea4d1f681babbce9545c9c5f3d5194a789c89f5b
|
||||||
|
- name: github.com/inconshreveable/mousetrap
|
||||||
|
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||||
- name: github.com/julienschmidt/httprouter
|
- name: github.com/julienschmidt/httprouter
|
||||||
version: 8a45e95fc75cb77048068a62daed98cc22fdac7c
|
version: 8a45e95fc75cb77048068a62daed98cc22fdac7c
|
||||||
- name: github.com/klauspost/cpuid
|
- name: github.com/klauspost/cpuid
|
||||||
@@ -37,6 +37,10 @@ imports:
|
|||||||
- fs
|
- fs
|
||||||
- name: github.com/rodaine/table
|
- name: github.com/rodaine/table
|
||||||
version: 212a2ad1c462ed4d5b5511ea2b480a573281dbbd
|
version: 212a2ad1c462ed4d5b5511ea2b480a573281dbbd
|
||||||
|
- name: github.com/spf13/cobra
|
||||||
|
version: 615425954c3b0d9485a7027d4d451fdcdfdee84e
|
||||||
|
- name: github.com/spf13/pflag
|
||||||
|
version: 583c0c0531f06d5278b7d917446061adc344b5cd
|
||||||
- name: github.com/stretchr/testify
|
- name: github.com/stretchr/testify
|
||||||
version: 2402e8e7a02fc811447d11f881aa9746cdc57983
|
version: 2402e8e7a02fc811447d11f881aa9746cdc57983
|
||||||
subpackages:
|
subpackages:
|
||||||
@@ -53,8 +57,6 @@ imports:
|
|||||||
- sm4
|
- sm4
|
||||||
- name: github.com/vaughan0/go-ini
|
- name: github.com/vaughan0/go-ini
|
||||||
version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
|
version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
|
||||||
- name: github.com/xtaci/kcp-go
|
|
||||||
version: df437e2b8ec365a336200f9d9da53441cf72ed47
|
|
||||||
- name: github.com/xtaci/smux
|
- name: github.com/xtaci/smux
|
||||||
version: 2de5471dfcbc029f5fe1392b83fe784127c4943e
|
version: 2de5471dfcbc029f5fe1392b83fe784127c4943e
|
||||||
- name: golang.org/x/crypto
|
- name: golang.org/x/crypto
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import:
|
|||||||
version: v1.1.0
|
version: v1.1.0
|
||||||
subpackages:
|
subpackages:
|
||||||
- spew
|
- spew
|
||||||
- package: github.com/docopt/docopt-go
|
|
||||||
version: 0.6.2
|
|
||||||
- package: github.com/fatedier/beego
|
- package: github.com/fatedier/beego
|
||||||
version: 6c6a4f5bd5eb5a39f7e289b8f345b55f75e7e3e8
|
version: 6c6a4f5bd5eb5a39f7e289b8f345b55f75e7e3e8
|
||||||
subpackages:
|
subpackages:
|
||||||
@@ -48,8 +46,6 @@ import:
|
|||||||
- sm4
|
- sm4
|
||||||
- package: github.com/vaughan0/go-ini
|
- package: github.com/vaughan0/go-ini
|
||||||
version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
|
version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
|
||||||
- package: github.com/xtaci/kcp-go
|
|
||||||
version: v3.17
|
|
||||||
- package: github.com/xtaci/smux
|
- package: github.com/xtaci/smux
|
||||||
version: 2de5471dfcbc029f5fe1392b83fe784127c4943e
|
version: 2de5471dfcbc029f5fe1392b83fe784127c4943e
|
||||||
- package: golang.org/x/crypto
|
- package: golang.org/x/crypto
|
||||||
@@ -74,3 +70,4 @@ import:
|
|||||||
- package: github.com/rodaine/table
|
- package: github.com/rodaine/table
|
||||||
version: v1.0.0
|
version: v1.0.0
|
||||||
- package: github.com/gorilla/websocket
|
- package: github.com/gorilla/websocket
|
||||||
|
version: v1.2.0
|
||||||
|
|||||||
@@ -23,46 +23,41 @@ import (
|
|||||||
ini "github.com/vaughan0/go-ini"
|
ini "github.com/vaughan0/go-ini"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ClientCommonCfg *ClientCommonConf
|
|
||||||
|
|
||||||
// client common config
|
// client common config
|
||||||
type ClientCommonConf struct {
|
type ClientCommonConf struct {
|
||||||
ConfigFile string
|
ServerAddr string `json:"server_addr"`
|
||||||
ServerAddr string
|
ServerPort int `json:"server_port"`
|
||||||
ServerPort int
|
HttpProxy string `json:"http_proxy"`
|
||||||
ServerUdpPort int // this is specified by login response message from frps
|
LogFile string `json:"log_file"`
|
||||||
HttpProxy string
|
LogWay string `json:"log_way"`
|
||||||
LogFile string
|
LogLevel string `json:"log_level"`
|
||||||
LogWay string
|
LogMaxDays int64 `json:"log_max_days"`
|
||||||
LogLevel string
|
Token string `json:"token"`
|
||||||
LogMaxDays int64
|
AdminAddr string `json:"admin_addr"`
|
||||||
PrivilegeToken string
|
AdminPort int `json:"admin_port"`
|
||||||
AdminAddr string
|
AdminUser string `json:"admin_user"`
|
||||||
AdminPort int
|
AdminPwd string `json:"admin_pwd"`
|
||||||
AdminUser string
|
PoolCount int `json:"pool_count"`
|
||||||
AdminPwd string
|
TcpMux bool `json:"tcp_mux"`
|
||||||
PoolCount int
|
User string `json:"user"`
|
||||||
TcpMux bool
|
DnsServer string `json:"dns_server"`
|
||||||
User string
|
LoginFailExit bool `json:"login_fail_exit"`
|
||||||
LoginFailExit bool
|
Start map[string]struct{} `json:"start"`
|
||||||
Start map[string]struct{}
|
Protocol string `json:"protocol"`
|
||||||
Protocol string
|
HeartBeatInterval int64 `json:"heartbeat_interval"`
|
||||||
HeartBeatInterval int64
|
HeartBeatTimeout int64 `json:"heartbeat_timeout"`
|
||||||
HeartBeatTimeout int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDeaultClientCommonConf() *ClientCommonConf {
|
func GetDefaultClientConf() *ClientCommonConf {
|
||||||
return &ClientCommonConf{
|
return &ClientCommonConf{
|
||||||
ConfigFile: "./frpc.ini",
|
|
||||||
ServerAddr: "0.0.0.0",
|
ServerAddr: "0.0.0.0",
|
||||||
ServerPort: 7000,
|
ServerPort: 7000,
|
||||||
ServerUdpPort: 0,
|
HttpProxy: os.Getenv("http_proxy"),
|
||||||
HttpProxy: "",
|
|
||||||
LogFile: "console",
|
LogFile: "console",
|
||||||
LogWay: "console",
|
LogWay: "console",
|
||||||
LogLevel: "info",
|
LogLevel: "info",
|
||||||
LogMaxDays: 3,
|
LogMaxDays: 3,
|
||||||
PrivilegeToken: "",
|
Token: "",
|
||||||
AdminAddr: "127.0.0.1",
|
AdminAddr: "127.0.0.1",
|
||||||
AdminPort: 0,
|
AdminPort: 0,
|
||||||
AdminUser: "",
|
AdminUser: "",
|
||||||
@@ -70,6 +65,7 @@ func GetDeaultClientCommonConf() *ClientCommonConf {
|
|||||||
PoolCount: 1,
|
PoolCount: 1,
|
||||||
TcpMux: true,
|
TcpMux: true,
|
||||||
User: "",
|
User: "",
|
||||||
|
DnsServer: "",
|
||||||
LoginFailExit: true,
|
LoginFailExit: true,
|
||||||
Start: make(map[string]struct{}),
|
Start: make(map[string]struct{}),
|
||||||
Protocol: "tcp",
|
Protocol: "tcp",
|
||||||
@@ -78,21 +74,28 @@ func GetDeaultClientCommonConf() *ClientCommonConf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadClientCommonConf(conf ini.File) (cfg *ClientCommonConf, err error) {
|
func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (cfg *ClientCommonConf, err error) {
|
||||||
|
cfg = defaultCfg
|
||||||
|
if cfg == nil {
|
||||||
|
cfg = GetDefaultClientConf()
|
||||||
|
}
|
||||||
|
|
||||||
|
conf, err := ini.Load(strings.NewReader(content))
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("parse ini conf file error: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tmpStr string
|
tmpStr string
|
||||||
ok bool
|
ok bool
|
||||||
v int64
|
v int64
|
||||||
)
|
)
|
||||||
cfg = GetDeaultClientCommonConf()
|
if tmpStr, ok = conf.Get("common", "server_addr"); ok {
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "server_addr")
|
|
||||||
if ok {
|
|
||||||
cfg.ServerAddr = tmpStr
|
cfg.ServerAddr = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "server_port")
|
if tmpStr, ok = conf.Get("common", "server_port"); ok {
|
||||||
if ok {
|
|
||||||
v, err = strconv.ParseInt(tmpStr, 10, 64)
|
v, err = strconv.ParseInt(tmpStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid server_port")
|
err = fmt.Errorf("Parse conf error: invalid server_port")
|
||||||
@@ -101,16 +104,11 @@ func LoadClientCommonConf(conf ini.File) (cfg *ClientCommonConf, err error) {
|
|||||||
cfg.ServerPort = int(v)
|
cfg.ServerPort = int(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "http_proxy")
|
if tmpStr, ok = conf.Get("common", "http_proxy"); ok {
|
||||||
if ok {
|
|
||||||
cfg.HttpProxy = tmpStr
|
cfg.HttpProxy = tmpStr
|
||||||
} else {
|
|
||||||
// get http_proxy from env
|
|
||||||
cfg.HttpProxy = os.Getenv("http_proxy")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "log_file")
|
if tmpStr, ok = conf.Get("common", "log_file"); ok {
|
||||||
if ok {
|
|
||||||
cfg.LogFile = tmpStr
|
cfg.LogFile = tmpStr
|
||||||
if cfg.LogFile == "console" {
|
if cfg.LogFile == "console" {
|
||||||
cfg.LogWay = "console"
|
cfg.LogWay = "console"
|
||||||
@@ -119,30 +117,25 @@ func LoadClientCommonConf(conf ini.File) (cfg *ClientCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "log_level")
|
if tmpStr, ok = conf.Get("common", "log_level"); ok {
|
||||||
if ok {
|
|
||||||
cfg.LogLevel = tmpStr
|
cfg.LogLevel = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "log_max_days")
|
if tmpStr, ok = conf.Get("common", "log_max_days"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
|
||||||
cfg.LogMaxDays = v
|
cfg.LogMaxDays = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "privilege_token")
|
if tmpStr, ok = conf.Get("common", "token"); ok {
|
||||||
if ok {
|
cfg.Token = tmpStr
|
||||||
cfg.PrivilegeToken = tmpStr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "admin_addr")
|
if tmpStr, ok = conf.Get("common", "admin_addr"); ok {
|
||||||
if ok {
|
|
||||||
cfg.AdminAddr = tmpStr
|
cfg.AdminAddr = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "admin_port")
|
if tmpStr, ok = conf.Get("common", "admin_port"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
|
||||||
cfg.AdminPort = int(v)
|
cfg.AdminPort = int(v)
|
||||||
} else {
|
} else {
|
||||||
@@ -151,55 +144,48 @@ func LoadClientCommonConf(conf ini.File) (cfg *ClientCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "admin_user")
|
if tmpStr, ok = conf.Get("common", "admin_user"); ok {
|
||||||
if ok {
|
|
||||||
cfg.AdminUser = tmpStr
|
cfg.AdminUser = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "admin_pwd")
|
if tmpStr, ok = conf.Get("common", "admin_pwd"); ok {
|
||||||
if ok {
|
|
||||||
cfg.AdminPwd = tmpStr
|
cfg.AdminPwd = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "pool_count")
|
if tmpStr, ok = conf.Get("common", "pool_count"); ok {
|
||||||
if ok {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
|
||||||
v, err = strconv.ParseInt(tmpStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
cfg.PoolCount = 1
|
|
||||||
} else {
|
|
||||||
cfg.PoolCount = int(v)
|
cfg.PoolCount = int(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "tcp_mux")
|
if tmpStr, ok = conf.Get("common", "tcp_mux"); ok && tmpStr == "false" {
|
||||||
if ok && tmpStr == "false" {
|
|
||||||
cfg.TcpMux = false
|
cfg.TcpMux = false
|
||||||
} else {
|
} else {
|
||||||
cfg.TcpMux = true
|
cfg.TcpMux = true
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "user")
|
if tmpStr, ok = conf.Get("common", "user"); ok {
|
||||||
if ok {
|
|
||||||
cfg.User = tmpStr
|
cfg.User = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "start")
|
if tmpStr, ok = conf.Get("common", "dns_server"); ok {
|
||||||
if ok {
|
cfg.DnsServer = tmpStr
|
||||||
|
}
|
||||||
|
|
||||||
|
if tmpStr, ok = conf.Get("common", "start"); ok {
|
||||||
proxyNames := strings.Split(tmpStr, ",")
|
proxyNames := strings.Split(tmpStr, ",")
|
||||||
for _, name := range proxyNames {
|
for _, name := range proxyNames {
|
||||||
cfg.Start[strings.TrimSpace(name)] = struct{}{}
|
cfg.Start[strings.TrimSpace(name)] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "login_fail_exit")
|
if tmpStr, ok = conf.Get("common", "login_fail_exit"); ok && tmpStr == "false" {
|
||||||
if ok && tmpStr == "false" {
|
|
||||||
cfg.LoginFailExit = false
|
cfg.LoginFailExit = false
|
||||||
} else {
|
} else {
|
||||||
cfg.LoginFailExit = true
|
cfg.LoginFailExit = true
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "protocol")
|
if tmpStr, ok = conf.Get("common", "protocol"); ok {
|
||||||
if ok {
|
|
||||||
// Now it only support tcp and kcp.
|
// Now it only support tcp and kcp.
|
||||||
if tmpStr != "kcp" {
|
if tmpStr != "kcp" {
|
||||||
tmpStr = "tcp"
|
tmpStr = "tcp"
|
||||||
@@ -207,10 +193,8 @@ func LoadClientCommonConf(conf ini.File) (cfg *ClientCommonConf, err error) {
|
|||||||
cfg.Protocol = tmpStr
|
cfg.Protocol = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "heartbeat_timeout")
|
if tmpStr, ok = conf.Get("common", "heartbeat_timeout"); ok {
|
||||||
if ok {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
v, err = strconv.ParseInt(tmpStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout")
|
err = fmt.Errorf("Parse conf error: invalid heartbeat_timeout")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -218,17 +202,18 @@ func LoadClientCommonConf(conf ini.File) (cfg *ClientCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "heartbeat_interval")
|
if tmpStr, ok = conf.Get("common", "heartbeat_interval"); ok {
|
||||||
if ok {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
v, err = strconv.ParseInt(tmpStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
cfg.HeartBeatInterval = v
|
cfg.HeartBeatInterval = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *ClientCommonConf) Check() (err error) {
|
||||||
if cfg.HeartBeatInterval <= 0 {
|
if cfg.HeartBeatInterval <= 0 {
|
||||||
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
err = fmt.Errorf("Parse conf error: invalid heartbeat_interval")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import (
|
|||||||
ini "github.com/vaughan0/go-ini"
|
ini "github.com/vaughan0/go-ini"
|
||||||
)
|
)
|
||||||
|
|
||||||
var proxyConfTypeMap map[string]reflect.Type
|
var (
|
||||||
|
proxyConfTypeMap map[string]reflect.Type
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proxyConfTypeMap = make(map[string]reflect.Type)
|
proxyConfTypeMap = make(map[string]reflect.Type)
|
||||||
@@ -51,17 +53,16 @@ func NewConfByType(proxyType string) ProxyConf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProxyConf interface {
|
type ProxyConf interface {
|
||||||
GetName() string
|
|
||||||
GetType() string
|
|
||||||
GetBaseInfo() *BaseProxyConf
|
GetBaseInfo() *BaseProxyConf
|
||||||
LoadFromMsg(pMsg *msg.NewProxy)
|
UnmarshalFromMsg(pMsg *msg.NewProxy)
|
||||||
LoadFromFile(name string, conf ini.Section) error
|
UnmarshalFromIni(prefix string, name string, conf ini.Section) error
|
||||||
UnMarshalToMsg(pMsg *msg.NewProxy)
|
MarshalToMsg(pMsg *msg.NewProxy)
|
||||||
Check() error
|
CheckForCli() error
|
||||||
|
CheckForSvr() error
|
||||||
Compare(conf ProxyConf) bool
|
Compare(conf ProxyConf) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyConf(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
|
func NewProxyConfFromMsg(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
|
||||||
if pMsg.ProxyType == "" {
|
if pMsg.ProxyType == "" {
|
||||||
pMsg.ProxyType = consts.TcpProxy
|
pMsg.ProxyType = consts.TcpProxy
|
||||||
}
|
}
|
||||||
@@ -71,12 +72,12 @@ func NewProxyConf(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
|
|||||||
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
|
||||||
}
|
}
|
||||||
cfg.LoadFromMsg(pMsg)
|
cfg.UnmarshalFromMsg(pMsg)
|
||||||
err = cfg.Check()
|
err = cfg.CheckForSvr()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyConfFromFile(name string, section ini.Section) (cfg ProxyConf, err error) {
|
func NewProxyConfFromIni(prefix string, name string, section ini.Section) (cfg ProxyConf, err error) {
|
||||||
proxyType := section["type"]
|
proxyType := section["type"]
|
||||||
if proxyType == "" {
|
if proxyType == "" {
|
||||||
proxyType = consts.TcpProxy
|
proxyType = consts.TcpProxy
|
||||||
@@ -87,7 +88,10 @@ func NewProxyConfFromFile(name string, section ini.Section) (cfg ProxyConf, err
|
|||||||
err = fmt.Errorf("proxy [%s] type [%s] error", name, proxyType)
|
err = fmt.Errorf("proxy [%s] type [%s] error", name, proxyType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = cfg.LoadFromFile(name, section)
|
if err = cfg.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = cfg.CheckForCli()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,14 +104,6 @@ type BaseProxyConf struct {
|
|||||||
UseCompression bool `json:"use_compression"`
|
UseCompression bool `json:"use_compression"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BaseProxyConf) GetName() string {
|
|
||||||
return cfg.ProxyName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg *BaseProxyConf) GetType() string {
|
|
||||||
return cfg.ProxyType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg *BaseProxyConf) GetBaseInfo() *BaseProxyConf {
|
func (cfg *BaseProxyConf) GetBaseInfo() *BaseProxyConf {
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
@@ -122,23 +118,19 @@ func (cfg *BaseProxyConf) compare(cmp *BaseProxyConf) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BaseProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *BaseProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.ProxyName = pMsg.ProxyName
|
cfg.ProxyName = pMsg.ProxyName
|
||||||
cfg.ProxyType = pMsg.ProxyType
|
cfg.ProxyType = pMsg.ProxyType
|
||||||
cfg.UseEncryption = pMsg.UseEncryption
|
cfg.UseEncryption = pMsg.UseEncryption
|
||||||
cfg.UseCompression = pMsg.UseCompression
|
cfg.UseCompression = pMsg.UseCompression
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BaseProxyConf) LoadFromFile(name string, section ini.Section) error {
|
func (cfg *BaseProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) error {
|
||||||
var (
|
var (
|
||||||
tmpStr string
|
tmpStr string
|
||||||
ok bool
|
ok bool
|
||||||
)
|
)
|
||||||
if ClientCommonCfg.User != "" {
|
cfg.ProxyName = prefix + name
|
||||||
cfg.ProxyName = ClientCommonCfg.User + "." + name
|
|
||||||
} else {
|
|
||||||
cfg.ProxyName = name
|
|
||||||
}
|
|
||||||
cfg.ProxyType = section["type"]
|
cfg.ProxyType = section["type"]
|
||||||
|
|
||||||
tmpStr, ok = section["use_encryption"]
|
tmpStr, ok = section["use_encryption"]
|
||||||
@@ -153,7 +145,7 @@ func (cfg *BaseProxyConf) LoadFromFile(name string, section ini.Section) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BaseProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *BaseProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
pMsg.ProxyName = cfg.ProxyName
|
pMsg.ProxyName = cfg.ProxyName
|
||||||
pMsg.ProxyType = cfg.ProxyType
|
pMsg.ProxyType = cfg.ProxyType
|
||||||
pMsg.UseEncryption = cfg.UseEncryption
|
pMsg.UseEncryption = cfg.UseEncryption
|
||||||
@@ -162,24 +154,21 @@ func (cfg *BaseProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|||||||
|
|
||||||
// Bind info
|
// Bind info
|
||||||
type BindInfoConf struct {
|
type BindInfoConf struct {
|
||||||
BindAddr string `json:"bind_addr"`
|
RemotePort int `json:"remote_port"`
|
||||||
RemotePort int `json:"remote_port"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BindInfoConf) compare(cmp *BindInfoConf) bool {
|
func (cfg *BindInfoConf) compare(cmp *BindInfoConf) bool {
|
||||||
if cfg.BindAddr != cmp.BindAddr ||
|
if cfg.RemotePort != cmp.RemotePort {
|
||||||
cfg.RemotePort != cmp.RemotePort {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BindInfoConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *BindInfoConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BindAddr = ServerCommonCfg.ProxyBindAddr
|
|
||||||
cfg.RemotePort = pMsg.RemotePort
|
cfg.RemotePort = pMsg.RemotePort
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BindInfoConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *BindInfoConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
var (
|
var (
|
||||||
tmpStr string
|
tmpStr string
|
||||||
ok bool
|
ok bool
|
||||||
@@ -197,14 +186,10 @@ func (cfg *BindInfoConf) LoadFromFile(name string, section ini.Section) (err err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BindInfoConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *BindInfoConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
pMsg.RemotePort = cfg.RemotePort
|
pMsg.RemotePort = cfg.RemotePort
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *BindInfoConf) check() (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Domain info
|
// Domain info
|
||||||
type DomainConf struct {
|
type DomainConf struct {
|
||||||
CustomDomains []string `json:"custom_domains"`
|
CustomDomains []string `json:"custom_domains"`
|
||||||
@@ -219,12 +204,12 @@ func (cfg *DomainConf) compare(cmp *DomainConf) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *DomainConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *DomainConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.CustomDomains = pMsg.CustomDomains
|
cfg.CustomDomains = pMsg.CustomDomains
|
||||||
cfg.SubDomain = pMsg.SubDomain
|
cfg.SubDomain = pMsg.SubDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *DomainConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *DomainConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
var (
|
var (
|
||||||
tmpStr string
|
tmpStr string
|
||||||
ok bool
|
ok bool
|
||||||
@@ -239,42 +224,60 @@ func (cfg *DomainConf) LoadFromFile(name string, section ini.Section) (err error
|
|||||||
if tmpStr, ok = section["subdomain"]; ok {
|
if tmpStr, ok = section["subdomain"]; ok {
|
||||||
cfg.SubDomain = tmpStr
|
cfg.SubDomain = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" {
|
|
||||||
return fmt.Errorf("Parse conf error: proxy [%s] custom_domains and subdomain should set at least one of them", name)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *DomainConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *DomainConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
pMsg.CustomDomains = cfg.CustomDomains
|
pMsg.CustomDomains = cfg.CustomDomains
|
||||||
pMsg.SubDomain = cfg.SubDomain
|
pMsg.SubDomain = cfg.SubDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *DomainConf) check() (err error) {
|
func (cfg *DomainConf) check() (err error) {
|
||||||
|
if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" {
|
||||||
|
err = fmt.Errorf("custom_domains and subdomain should set at least one of them")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *DomainConf) checkForCli() (err error) {
|
||||||
|
if err = cfg.check(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *DomainConf) checkForSvr() (err error) {
|
||||||
|
if err = cfg.check(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, domain := range cfg.CustomDomains {
|
for _, domain := range cfg.CustomDomains {
|
||||||
if ServerCommonCfg.SubDomainHost != "" && len(strings.Split(ServerCommonCfg.SubDomainHost, ".")) < len(strings.Split(domain, ".")) {
|
if subDomainHost != "" && len(strings.Split(subDomainHost, ".")) < len(strings.Split(domain, ".")) {
|
||||||
if strings.Contains(domain, ServerCommonCfg.SubDomainHost) {
|
if strings.Contains(domain, subDomainHost) {
|
||||||
return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, ServerCommonCfg.SubDomainHost)
|
return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, subDomainHost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.SubDomain != "" {
|
if cfg.SubDomain != "" {
|
||||||
if ServerCommonCfg.SubDomainHost == "" {
|
if subDomainHost == "" {
|
||||||
return fmt.Errorf("subdomain is not supported because this feature is not enabled by frps")
|
return fmt.Errorf("subdomain is not supported because this feature is not enabled by frps")
|
||||||
}
|
}
|
||||||
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local service info
|
// Local service info
|
||||||
type LocalSvrConf struct {
|
type LocalSvrConf struct {
|
||||||
LocalIp string `json:"-"`
|
LocalIp string `json:"local_ip"`
|
||||||
LocalPort int `json:"-"`
|
LocalPort int `json:"local_port"`
|
||||||
|
|
||||||
|
Plugin string `json:"plugin"`
|
||||||
|
PluginParams map[string]string `json:"plugin_params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *LocalSvrConf) compare(cmp *LocalSvrConf) bool {
|
func (cfg *LocalSvrConf) compare(cmp *LocalSvrConf) bool {
|
||||||
@@ -282,30 +285,6 @@ func (cfg *LocalSvrConf) compare(cmp *LocalSvrConf) bool {
|
|||||||
cfg.LocalPort != cmp.LocalPort {
|
cfg.LocalPort != cmp.LocalPort {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg *LocalSvrConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
||||||
if cfg.LocalIp = section["local_ip"]; cfg.LocalIp == "" {
|
|
||||||
cfg.LocalIp = "127.0.0.1"
|
|
||||||
}
|
|
||||||
|
|
||||||
if tmpStr, ok := section["local_port"]; ok {
|
|
||||||
if cfg.LocalPort, err = strconv.Atoi(tmpStr); err != nil {
|
|
||||||
return fmt.Errorf("Parse conf error: proxy [%s] local_port error", name)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("Parse conf error: proxy [%s] local_port not found", name)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PluginConf struct {
|
|
||||||
Plugin string `json:"-"`
|
|
||||||
PluginParams map[string]string `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg *PluginConf) compare(cmp *PluginConf) bool {
|
|
||||||
if cfg.Plugin != cmp.Plugin ||
|
if cfg.Plugin != cmp.Plugin ||
|
||||||
len(cfg.PluginParams) != len(cmp.PluginParams) {
|
len(cfg.PluginParams) != len(cmp.PluginParams) {
|
||||||
return false
|
return false
|
||||||
@@ -319,7 +298,7 @@ func (cfg *PluginConf) compare(cmp *PluginConf) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *PluginConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *LocalSvrConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
cfg.Plugin = section["plugin"]
|
cfg.Plugin = section["plugin"]
|
||||||
cfg.PluginParams = make(map[string]string)
|
cfg.PluginParams = make(map[string]string)
|
||||||
if cfg.Plugin != "" {
|
if cfg.Plugin != "" {
|
||||||
@@ -330,7 +309,17 @@ func (cfg *PluginConf) LoadFromFile(name string, section ini.Section) (err error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("Parse conf error: proxy [%s] no plugin info found", name)
|
if cfg.LocalIp = section["local_ip"]; cfg.LocalIp == "" {
|
||||||
|
cfg.LocalIp = "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
if tmpStr, ok := section["local_port"]; ok {
|
||||||
|
if cfg.LocalPort, err = strconv.Atoi(tmpStr); err != nil {
|
||||||
|
return fmt.Errorf("Parse conf error: proxy [%s] local_port error", name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Parse conf error: proxy [%s] local_port not found", name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -341,7 +330,6 @@ type TcpProxyConf struct {
|
|||||||
BindInfoConf
|
BindInfoConf
|
||||||
|
|
||||||
LocalSvrConf
|
LocalSvrConf
|
||||||
PluginConf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *TcpProxyConf) Compare(cmp ProxyConf) bool {
|
func (cfg *TcpProxyConf) Compare(cmp ProxyConf) bool {
|
||||||
@@ -352,43 +340,38 @@ func (cfg *TcpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
|
|
||||||
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
||||||
!cfg.BindInfoConf.compare(&cmpConf.BindInfoConf) ||
|
!cfg.BindInfoConf.compare(&cmpConf.BindInfoConf) ||
|
||||||
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) {
|
||||||
!cfg.PluginConf.compare(&cmpConf.PluginConf) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *TcpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *TcpProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
cfg.BaseProxyConf.UnmarshalFromMsg(pMsg)
|
||||||
cfg.BindInfoConf.LoadFromMsg(pMsg)
|
cfg.BindInfoConf.UnmarshalFromMsg(pMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *TcpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *TcpProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BaseProxyConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = cfg.BindInfoConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BindInfoConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if err = cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
if err = cfg.PluginConf.LoadFromFile(name, section); err != nil {
|
return
|
||||||
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *TcpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *TcpProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
cfg.BaseProxyConf.MarshalToMsg(pMsg)
|
||||||
cfg.BindInfoConf.UnMarshalToMsg(pMsg)
|
cfg.BindInfoConf.MarshalToMsg(pMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *TcpProxyConf) Check() (err error) {
|
func (cfg *TcpProxyConf) CheckForCli() error { return nil }
|
||||||
err = cfg.BindInfoConf.check()
|
|
||||||
return
|
func (cfg *TcpProxyConf) CheckForSvr() error { return nil }
|
||||||
}
|
|
||||||
|
|
||||||
// UDP
|
// UDP
|
||||||
type UdpProxyConf struct {
|
type UdpProxyConf struct {
|
||||||
@@ -412,33 +395,32 @@ func (cfg *UdpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *UdpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *UdpProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
cfg.BaseProxyConf.UnmarshalFromMsg(pMsg)
|
||||||
cfg.BindInfoConf.LoadFromMsg(pMsg)
|
cfg.BindInfoConf.UnmarshalFromMsg(pMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *UdpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *UdpProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BaseProxyConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = cfg.BindInfoConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BindInfoConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *UdpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *UdpProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
cfg.BaseProxyConf.MarshalToMsg(pMsg)
|
||||||
cfg.BindInfoConf.UnMarshalToMsg(pMsg)
|
cfg.BindInfoConf.MarshalToMsg(pMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *UdpProxyConf) Check() (err error) {
|
func (cfg *UdpProxyConf) CheckForCli() error { return nil }
|
||||||
err = cfg.BindInfoConf.check()
|
|
||||||
return
|
func (cfg *UdpProxyConf) CheckForSvr() error { return nil }
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP
|
// HTTP
|
||||||
type HttpProxyConf struct {
|
type HttpProxyConf struct {
|
||||||
@@ -446,12 +428,11 @@ type HttpProxyConf struct {
|
|||||||
DomainConf
|
DomainConf
|
||||||
|
|
||||||
LocalSvrConf
|
LocalSvrConf
|
||||||
PluginConf
|
|
||||||
|
|
||||||
Locations []string `json:"locations"`
|
Locations []string `json:"locations"`
|
||||||
HostHeaderRewrite string `json:"host_header_rewrite"`
|
HostHeaderRewrite string `json:"host_header_rewrite"`
|
||||||
HttpUser string `json:"-"`
|
HttpUser string `json:"http_user"`
|
||||||
HttpPwd string `json:"-"`
|
HttpPwd string `json:"http_pwd"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) Compare(cmp ProxyConf) bool {
|
func (cfg *HttpProxyConf) Compare(cmp ProxyConf) bool {
|
||||||
@@ -463,7 +444,6 @@ func (cfg *HttpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
||||||
!cfg.DomainConf.compare(&cmpConf.DomainConf) ||
|
!cfg.DomainConf.compare(&cmpConf.DomainConf) ||
|
||||||
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
||||||
!cfg.PluginConf.compare(&cmpConf.PluginConf) ||
|
|
||||||
strings.Join(cfg.Locations, " ") != strings.Join(cmpConf.Locations, " ") ||
|
strings.Join(cfg.Locations, " ") != strings.Join(cmpConf.Locations, " ") ||
|
||||||
cfg.HostHeaderRewrite != cmpConf.HostHeaderRewrite ||
|
cfg.HostHeaderRewrite != cmpConf.HostHeaderRewrite ||
|
||||||
cfg.HttpUser != cmpConf.HttpUser ||
|
cfg.HttpUser != cmpConf.HttpUser ||
|
||||||
@@ -473,9 +453,9 @@ func (cfg *HttpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *HttpProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
cfg.BaseProxyConf.UnmarshalFromMsg(pMsg)
|
||||||
cfg.DomainConf.LoadFromMsg(pMsg)
|
cfg.DomainConf.UnmarshalFromMsg(pMsg)
|
||||||
|
|
||||||
cfg.Locations = pMsg.Locations
|
cfg.Locations = pMsg.Locations
|
||||||
cfg.HostHeaderRewrite = pMsg.HostHeaderRewrite
|
cfg.HostHeaderRewrite = pMsg.HostHeaderRewrite
|
||||||
@@ -483,17 +463,15 @@ func (cfg *HttpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|||||||
cfg.HttpPwd = pMsg.HttpPwd
|
cfg.HttpPwd = pMsg.HttpPwd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *HttpProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BaseProxyConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = cfg.DomainConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.DomainConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = cfg.PluginConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -512,9 +490,9 @@ func (cfg *HttpProxyConf) LoadFromFile(name string, section ini.Section) (err er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *HttpProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
cfg.BaseProxyConf.MarshalToMsg(pMsg)
|
||||||
cfg.DomainConf.UnMarshalToMsg(pMsg)
|
cfg.DomainConf.MarshalToMsg(pMsg)
|
||||||
|
|
||||||
pMsg.Locations = cfg.Locations
|
pMsg.Locations = cfg.Locations
|
||||||
pMsg.HostHeaderRewrite = cfg.HostHeaderRewrite
|
pMsg.HostHeaderRewrite = cfg.HostHeaderRewrite
|
||||||
@@ -522,11 +500,20 @@ func (cfg *HttpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|||||||
pMsg.HttpPwd = cfg.HttpPwd
|
pMsg.HttpPwd = cfg.HttpPwd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) Check() (err error) {
|
func (cfg *HttpProxyConf) CheckForCli() (err error) {
|
||||||
if ServerCommonCfg.VhostHttpPort == 0 {
|
if err = cfg.DomainConf.checkForCli(); err != nil {
|
||||||
return fmt.Errorf("type [http] not support when vhost_http_port is not set")
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *HttpProxyConf) CheckForSvr() (err error) {
|
||||||
|
if vhostHttpPort == 0 {
|
||||||
|
err = fmt.Errorf("type [http] not support when vhost_http_port is not set")
|
||||||
|
}
|
||||||
|
if err = cfg.DomainConf.checkForSvr(); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
err = cfg.DomainConf.check()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +523,6 @@ type HttpsProxyConf struct {
|
|||||||
DomainConf
|
DomainConf
|
||||||
|
|
||||||
LocalSvrConf
|
LocalSvrConf
|
||||||
PluginConf
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpsProxyConf) Compare(cmp ProxyConf) bool {
|
func (cfg *HttpsProxyConf) Compare(cmp ProxyConf) bool {
|
||||||
@@ -547,43 +533,49 @@ func (cfg *HttpsProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
|
|
||||||
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
||||||
!cfg.DomainConf.compare(&cmpConf.DomainConf) ||
|
!cfg.DomainConf.compare(&cmpConf.DomainConf) ||
|
||||||
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) {
|
||||||
!cfg.PluginConf.compare(&cmpConf.PluginConf) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpsProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *HttpsProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
cfg.BaseProxyConf.UnmarshalFromMsg(pMsg)
|
||||||
cfg.DomainConf.LoadFromMsg(pMsg)
|
cfg.DomainConf.UnmarshalFromMsg(pMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpsProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *HttpsProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BaseProxyConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = cfg.DomainConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.DomainConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = cfg.PluginConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpsProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *HttpsProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
cfg.BaseProxyConf.MarshalToMsg(pMsg)
|
||||||
cfg.DomainConf.UnMarshalToMsg(pMsg)
|
cfg.DomainConf.MarshalToMsg(pMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpsProxyConf) Check() (err error) {
|
func (cfg *HttpsProxyConf) CheckForCli() (err error) {
|
||||||
if ServerCommonCfg.VhostHttpsPort == 0 {
|
if err = cfg.DomainConf.checkForCli(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *HttpsProxyConf) CheckForSvr() (err error) {
|
||||||
|
if vhostHttpsPort == 0 {
|
||||||
return fmt.Errorf("type [https] not support when vhost_https_port is not set")
|
return fmt.Errorf("type [https] not support when vhost_https_port is not set")
|
||||||
}
|
}
|
||||||
err = cfg.DomainConf.check()
|
if err = cfg.DomainConf.checkForSvr(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,7 +588,6 @@ type StcpProxyConf struct {
|
|||||||
|
|
||||||
// used in role server
|
// used in role server
|
||||||
LocalSvrConf
|
LocalSvrConf
|
||||||
PluginConf
|
|
||||||
|
|
||||||
// used in role visitor
|
// used in role visitor
|
||||||
ServerName string `json:"server_name"`
|
ServerName string `json:"server_name"`
|
||||||
@@ -612,7 +603,6 @@ func (cfg *StcpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
|
|
||||||
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
||||||
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
||||||
!cfg.PluginConf.compare(&cmpConf.PluginConf) ||
|
|
||||||
cfg.Role != cmpConf.Role ||
|
cfg.Role != cmpConf.Role ||
|
||||||
cfg.Sk != cmpConf.Sk ||
|
cfg.Sk != cmpConf.Sk ||
|
||||||
cfg.ServerName != cmpConf.ServerName ||
|
cfg.ServerName != cmpConf.ServerName ||
|
||||||
@@ -624,13 +614,13 @@ func (cfg *StcpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only for role server.
|
// Only for role server.
|
||||||
func (cfg *StcpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *StcpProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
cfg.BaseProxyConf.UnmarshalFromMsg(pMsg)
|
||||||
cfg.Sk = pMsg.Sk
|
cfg.Sk = pMsg.Sk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *StcpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *StcpProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BaseProxyConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,21 +651,33 @@ func (cfg *StcpProxyConf) LoadFromFile(name string, section ini.Section) (err er
|
|||||||
return fmt.Errorf("Parse conf error: proxy [%s] bind_port not found", name)
|
return fmt.Errorf("Parse conf error: proxy [%s] bind_port not found", name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = cfg.PluginConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *StcpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *StcpProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
cfg.BaseProxyConf.MarshalToMsg(pMsg)
|
||||||
pMsg.Sk = cfg.Sk
|
pMsg.Sk = cfg.Sk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *StcpProxyConf) Check() (err error) {
|
func (cfg *StcpProxyConf) CheckForCli() (err error) {
|
||||||
|
if cfg.Role != "server" && cfg.Role != "visitor" {
|
||||||
|
err = fmt.Errorf("role should be 'server' or 'visitor'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cfg.Role == "visitor" {
|
||||||
|
if cfg.BindAddr == "" {
|
||||||
|
err = fmt.Errorf("bind_addr shouldn't be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *StcpProxyConf) CheckForSvr() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,7 +690,6 @@ type XtcpProxyConf struct {
|
|||||||
|
|
||||||
// used in role server
|
// used in role server
|
||||||
LocalSvrConf
|
LocalSvrConf
|
||||||
PluginConf
|
|
||||||
|
|
||||||
// used in role visitor
|
// used in role visitor
|
||||||
ServerName string `json:"server_name"`
|
ServerName string `json:"server_name"`
|
||||||
@@ -704,7 +705,6 @@ func (cfg *XtcpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
|
|
||||||
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) ||
|
||||||
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
!cfg.LocalSvrConf.compare(&cmpConf.LocalSvrConf) ||
|
||||||
!cfg.PluginConf.compare(&cmpConf.PluginConf) ||
|
|
||||||
cfg.Role != cmpConf.Role ||
|
cfg.Role != cmpConf.Role ||
|
||||||
cfg.Sk != cmpConf.Sk ||
|
cfg.Sk != cmpConf.Sk ||
|
||||||
cfg.ServerName != cmpConf.ServerName ||
|
cfg.ServerName != cmpConf.ServerName ||
|
||||||
@@ -716,13 +716,13 @@ func (cfg *XtcpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only for role server.
|
// Only for role server.
|
||||||
func (cfg *XtcpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
func (cfg *XtcpProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
cfg.BaseProxyConf.UnmarshalFromMsg(pMsg)
|
||||||
cfg.Sk = pMsg.Sk
|
cfg.Sk = pMsg.Sk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *XtcpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
func (cfg *XtcpProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.BaseProxyConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,21 +753,33 @@ func (cfg *XtcpProxyConf) LoadFromFile(name string, section ini.Section) (err er
|
|||||||
return fmt.Errorf("Parse conf error: proxy [%s] bind_port not found", name)
|
return fmt.Errorf("Parse conf error: proxy [%s] bind_port not found", name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = cfg.PluginConf.LoadFromFile(name, section); err != nil {
|
if err = cfg.LocalSvrConf.UnmarshalFromIni(prefix, name, section); err != nil {
|
||||||
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *XtcpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
func (cfg *XtcpProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
||||||
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
cfg.BaseProxyConf.MarshalToMsg(pMsg)
|
||||||
pMsg.Sk = cfg.Sk
|
pMsg.Sk = cfg.Sk
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *XtcpProxyConf) Check() (err error) {
|
func (cfg *XtcpProxyConf) CheckForCli() (err error) {
|
||||||
|
if cfg.Role != "server" && cfg.Role != "visitor" {
|
||||||
|
err = fmt.Errorf("role should be 'server' or 'visitor'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cfg.Role == "visitor" {
|
||||||
|
if cfg.BindAddr == "" {
|
||||||
|
err = fmt.Errorf("bind_addr shouldn't be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *XtcpProxyConf) CheckForSvr() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,7 +800,7 @@ func ParseRangeSection(name string, section ini.Section) (sections map[string]in
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(localPorts) == 0 {
|
if len(localPorts) == 0 {
|
||||||
err = fmt.Errorf("Parse conf error: range section [%s] local_port and remote_port is necessary")
|
err = fmt.Errorf("Parse conf error: range section [%s] local_port and remote_port is necessary", name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,7 +817,7 @@ func ParseRangeSection(name string, section ini.Section) (sections map[string]in
|
|||||||
|
|
||||||
// if len(startProxy) is 0, start all
|
// if len(startProxy) is 0, start all
|
||||||
// otherwise just start proxies in startProxy map
|
// otherwise just start proxies in startProxy map
|
||||||
func LoadProxyConfFromFile(prefix string, conf ini.File, startProxy map[string]struct{}) (
|
func LoadProxyConfFromIni(prefix string, conf ini.File, startProxy map[string]struct{}) (
|
||||||
proxyConfs map[string]ProxyConf, visitorConfs map[string]ProxyConf, err error) {
|
proxyConfs map[string]ProxyConf, visitorConfs map[string]ProxyConf, err error) {
|
||||||
|
|
||||||
if prefix != "" {
|
if prefix != "" {
|
||||||
@@ -842,9 +854,7 @@ func LoadProxyConfFromFile(prefix string, conf ini.File, startProxy map[string]s
|
|||||||
}
|
}
|
||||||
|
|
||||||
for subName, subSection := range subSections {
|
for subName, subSection := range subSections {
|
||||||
// some proxy or visotr configure may be used this prefix
|
cfg, err := NewProxyConfFromIni(prefix, subName, subSection)
|
||||||
subSection["prefix"] = prefix
|
|
||||||
cfg, err := NewProxyConfFromFile(subName, subSection)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return proxyConfs, visitorConfs, err
|
return proxyConfs, visitorConfs, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,94 +24,109 @@ import (
|
|||||||
"github.com/fatedier/frp/utils/util"
|
"github.com/fatedier/frp/utils/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ServerCommonCfg *ServerCommonConf
|
var (
|
||||||
|
// server global configure used for generate proxy conf used in frps
|
||||||
|
proxyBindAddr string
|
||||||
|
subDomainHost string
|
||||||
|
vhostHttpPort int
|
||||||
|
vhostHttpsPort int
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitServerCfg(cfg *ServerCommonConf) {
|
||||||
|
proxyBindAddr = cfg.ProxyBindAddr
|
||||||
|
subDomainHost = cfg.SubDomainHost
|
||||||
|
vhostHttpPort = cfg.VhostHttpPort
|
||||||
|
vhostHttpsPort = cfg.VhostHttpsPort
|
||||||
|
}
|
||||||
|
|
||||||
// common config
|
// common config
|
||||||
type ServerCommonConf struct {
|
type ServerCommonConf struct {
|
||||||
ConfigFile string
|
BindAddr string `json:"bind_addr"`
|
||||||
BindAddr string
|
BindPort int `json:"bind_port"`
|
||||||
BindPort int
|
BindUdpPort int `json:"bind_udp_port"`
|
||||||
BindUdpPort int
|
KcpBindPort int `json:"kcp_bind_port"`
|
||||||
KcpBindPort int
|
ProxyBindAddr string `json:"proxy_bind_addr"`
|
||||||
ProxyBindAddr string
|
|
||||||
|
|
||||||
// If VhostHttpPort equals 0, don't listen a public port for http protocol.
|
// If VhostHttpPort equals 0, don't listen a public port for http protocol.
|
||||||
VhostHttpPort int
|
VhostHttpPort int `json:"vhost_http_port"`
|
||||||
|
|
||||||
// if VhostHttpsPort equals 0, don't listen a public port for https protocol
|
// if VhostHttpsPort equals 0, don't listen a public port for https protocol
|
||||||
VhostHttpsPort int
|
VhostHttpsPort int `json:"vhost_http_port"`
|
||||||
DashboardAddr string
|
DashboardAddr string `json:"dashboard_addr"`
|
||||||
|
|
||||||
// if DashboardPort equals 0, dashboard is not available
|
// if DashboardPort equals 0, dashboard is not available
|
||||||
DashboardPort int
|
DashboardPort int `json:"dashboard_port"`
|
||||||
DashboardUser string
|
DashboardUser string `json:"dashboard_user"`
|
||||||
DashboardPwd string
|
DashboardPwd string `json:"dashboard_pwd"`
|
||||||
AssetsDir string
|
AssetsDir string `json:"asserts_dir"`
|
||||||
LogFile string
|
LogFile string `json:"log_file"`
|
||||||
LogWay string // console or file
|
LogWay string `json:"log_way"` // console or file
|
||||||
LogLevel string
|
LogLevel string `json:"log_level"`
|
||||||
LogMaxDays int64
|
LogMaxDays int64 `json:"log_max_days"`
|
||||||
PrivilegeMode bool
|
Token string `json:"token"`
|
||||||
PrivilegeToken string
|
AuthTimeout int64 `json:"auth_timeout"`
|
||||||
AuthTimeout int64
|
SubDomainHost string `json:"subdomain_host"`
|
||||||
SubDomainHost string
|
TcpMux bool `json:"tcp_mux"`
|
||||||
TcpMux bool
|
|
||||||
|
|
||||||
PrivilegeAllowPorts map[int]struct{}
|
AllowPorts map[int]struct{}
|
||||||
MaxPoolCount int64
|
MaxPoolCount int64 `json:"max_pool_count"`
|
||||||
MaxPortsPerClient int64
|
MaxPortsPerClient int64 `json:"max_ports_per_client"`
|
||||||
HeartBeatTimeout int64
|
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
|
||||||
UserConnTimeout int64
|
UserConnTimeout int64 `json:"user_conn_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultServerCommonConf() *ServerCommonConf {
|
func GetDefaultServerConf() *ServerCommonConf {
|
||||||
return &ServerCommonConf{
|
return &ServerCommonConf{
|
||||||
ConfigFile: "./frps.ini",
|
BindAddr: "0.0.0.0",
|
||||||
BindAddr: "0.0.0.0",
|
BindPort: 7000,
|
||||||
BindPort: 7000,
|
BindUdpPort: 0,
|
||||||
BindUdpPort: 0,
|
KcpBindPort: 0,
|
||||||
KcpBindPort: 0,
|
ProxyBindAddr: "0.0.0.0",
|
||||||
ProxyBindAddr: "0.0.0.0",
|
VhostHttpPort: 0,
|
||||||
VhostHttpPort: 0,
|
VhostHttpsPort: 0,
|
||||||
VhostHttpsPort: 0,
|
DashboardAddr: "0.0.0.0",
|
||||||
DashboardAddr: "0.0.0.0",
|
DashboardPort: 0,
|
||||||
DashboardPort: 0,
|
DashboardUser: "admin",
|
||||||
DashboardUser: "admin",
|
DashboardPwd: "admin",
|
||||||
DashboardPwd: "admin",
|
AssetsDir: "",
|
||||||
AssetsDir: "",
|
LogFile: "console",
|
||||||
LogFile: "console",
|
LogWay: "console",
|
||||||
LogWay: "console",
|
LogLevel: "info",
|
||||||
LogLevel: "info",
|
LogMaxDays: 3,
|
||||||
LogMaxDays: 3,
|
Token: "",
|
||||||
PrivilegeMode: true,
|
AuthTimeout: 900,
|
||||||
PrivilegeToken: "",
|
SubDomainHost: "",
|
||||||
AuthTimeout: 900,
|
TcpMux: true,
|
||||||
SubDomainHost: "",
|
AllowPorts: make(map[int]struct{}),
|
||||||
TcpMux: true,
|
MaxPoolCount: 5,
|
||||||
PrivilegeAllowPorts: make(map[int]struct{}),
|
MaxPortsPerClient: 0,
|
||||||
MaxPoolCount: 5,
|
HeartBeatTimeout: 90,
|
||||||
MaxPortsPerClient: 0,
|
UserConnTimeout: 10,
|
||||||
HeartBeatTimeout: 90,
|
|
||||||
UserConnTimeout: 10,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load server common configure.
|
func UnmarshalServerConfFromIni(defaultCfg *ServerCommonConf, content string) (cfg *ServerCommonConf, err error) {
|
||||||
func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
cfg = defaultCfg
|
||||||
|
if cfg == nil {
|
||||||
|
cfg = GetDefaultServerConf()
|
||||||
|
}
|
||||||
|
|
||||||
|
conf, err := ini.Load(strings.NewReader(content))
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("parse ini conf file error: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tmpStr string
|
tmpStr string
|
||||||
ok bool
|
ok bool
|
||||||
v int64
|
v int64
|
||||||
)
|
)
|
||||||
cfg = GetDefaultServerCommonConf()
|
if tmpStr, ok = conf.Get("common", "bind_addr"); ok {
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "bind_addr")
|
|
||||||
if ok {
|
|
||||||
cfg.BindAddr = tmpStr
|
cfg.BindAddr = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "bind_port")
|
if tmpStr, ok = conf.Get("common", "bind_port"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid bind_port")
|
err = fmt.Errorf("Parse conf error: invalid bind_port")
|
||||||
return
|
return
|
||||||
@@ -120,8 +135,7 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "bind_udp_port")
|
if tmpStr, ok = conf.Get("common", "bind_udp_port"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid bind_udp_port")
|
err = fmt.Errorf("Parse conf error: invalid bind_udp_port")
|
||||||
return
|
return
|
||||||
@@ -130,8 +144,7 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "kcp_bind_port")
|
if tmpStr, ok = conf.Get("common", "kcp_bind_port"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid kcp_bind_port")
|
err = fmt.Errorf("Parse conf error: invalid kcp_bind_port")
|
||||||
return
|
return
|
||||||
@@ -140,15 +153,13 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "proxy_bind_addr")
|
if tmpStr, ok = conf.Get("common", "proxy_bind_addr"); ok {
|
||||||
if ok {
|
|
||||||
cfg.ProxyBindAddr = tmpStr
|
cfg.ProxyBindAddr = tmpStr
|
||||||
} else {
|
} else {
|
||||||
cfg.ProxyBindAddr = cfg.BindAddr
|
cfg.ProxyBindAddr = cfg.BindAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "vhost_http_port")
|
if tmpStr, ok = conf.Get("common", "vhost_http_port"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid vhost_http_port")
|
err = fmt.Errorf("Parse conf error: invalid vhost_http_port")
|
||||||
return
|
return
|
||||||
@@ -159,8 +170,7 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
cfg.VhostHttpPort = 0
|
cfg.VhostHttpPort = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "vhost_https_port")
|
if tmpStr, ok = conf.Get("common", "vhost_https_port"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid vhost_https_port")
|
err = fmt.Errorf("Parse conf error: invalid vhost_https_port")
|
||||||
return
|
return
|
||||||
@@ -171,15 +181,13 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
cfg.VhostHttpsPort = 0
|
cfg.VhostHttpsPort = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "dashboard_addr")
|
if tmpStr, ok = conf.Get("common", "dashboard_addr"); ok {
|
||||||
if ok {
|
|
||||||
cfg.DashboardAddr = tmpStr
|
cfg.DashboardAddr = tmpStr
|
||||||
} else {
|
} else {
|
||||||
cfg.DashboardAddr = cfg.BindAddr
|
cfg.DashboardAddr = cfg.BindAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "dashboard_port")
|
if tmpStr, ok = conf.Get("common", "dashboard_port"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid dashboard_port")
|
err = fmt.Errorf("Parse conf error: invalid dashboard_port")
|
||||||
return
|
return
|
||||||
@@ -190,23 +198,19 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
cfg.DashboardPort = 0
|
cfg.DashboardPort = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "dashboard_user")
|
if tmpStr, ok = conf.Get("common", "dashboard_user"); ok {
|
||||||
if ok {
|
|
||||||
cfg.DashboardUser = tmpStr
|
cfg.DashboardUser = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "dashboard_pwd")
|
if tmpStr, ok = conf.Get("common", "dashboard_pwd"); ok {
|
||||||
if ok {
|
|
||||||
cfg.DashboardPwd = tmpStr
|
cfg.DashboardPwd = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "assets_dir")
|
if tmpStr, ok = conf.Get("common", "assets_dir"); ok {
|
||||||
if ok {
|
|
||||||
cfg.AssetsDir = tmpStr
|
cfg.AssetsDir = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "log_file")
|
if tmpStr, ok = conf.Get("common", "log_file"); ok {
|
||||||
if ok {
|
|
||||||
cfg.LogFile = tmpStr
|
cfg.LogFile = tmpStr
|
||||||
if cfg.LogFile == "console" {
|
if cfg.LogFile == "console" {
|
||||||
cfg.LogWay = "console"
|
cfg.LogWay = "console"
|
||||||
@@ -215,47 +219,33 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "log_level")
|
if tmpStr, ok = conf.Get("common", "log_level"); ok {
|
||||||
if ok {
|
|
||||||
cfg.LogLevel = tmpStr
|
cfg.LogLevel = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "log_max_days")
|
if tmpStr, ok = conf.Get("common", "log_max_days"); ok {
|
||||||
if ok {
|
|
||||||
v, err = strconv.ParseInt(tmpStr, 10, 64)
|
v, err = strconv.ParseInt(tmpStr, 10, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
cfg.LogMaxDays = v
|
cfg.LogMaxDays = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "privilege_mode")
|
cfg.Token, _ = conf.Get("common", "token")
|
||||||
if ok {
|
|
||||||
if tmpStr == "true" {
|
if allowPortsStr, ok := conf.Get("common", "allow_ports"); ok {
|
||||||
cfg.PrivilegeMode = true
|
// e.g. 1000-2000,2001,2002,3000-4000
|
||||||
|
ports, errRet := util.ParseRangeNumbers(allowPortsStr)
|
||||||
|
if errRet != nil {
|
||||||
|
err = fmt.Errorf("Parse conf error: allow_ports: %v", errRet)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, port := range ports {
|
||||||
|
cfg.AllowPorts[int(port)] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivilegeMode configure
|
if tmpStr, ok = conf.Get("common", "max_pool_count"); ok {
|
||||||
if cfg.PrivilegeMode == true {
|
|
||||||
cfg.PrivilegeToken, _ = conf.Get("common", "privilege_token")
|
|
||||||
|
|
||||||
allowPortsStr, ok := conf.Get("common", "privilege_allow_ports")
|
|
||||||
if ok {
|
|
||||||
// e.g. 1000-2000,2001,2002,3000-4000
|
|
||||||
ports, errRet := util.ParseRangeNumbers(allowPortsStr)
|
|
||||||
if errRet != nil {
|
|
||||||
err = fmt.Errorf("Parse conf error: privilege_allow_ports: %v", errRet)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, port := range ports {
|
|
||||||
cfg.PrivilegeAllowPorts[int(port)] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "max_pool_count")
|
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid max_pool_count")
|
err = fmt.Errorf("Parse conf error: invalid max_pool_count")
|
||||||
return
|
return
|
||||||
@@ -268,8 +258,7 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "max_ports_per_client")
|
if tmpStr, ok = conf.Get("common", "max_ports_per_client"); ok {
|
||||||
if ok {
|
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
||||||
err = fmt.Errorf("Parse conf error: invalid max_ports_per_client")
|
err = fmt.Errorf("Parse conf error: invalid max_ports_per_client")
|
||||||
return
|
return
|
||||||
@@ -282,8 +271,7 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "authentication_timeout")
|
if tmpStr, ok = conf.Get("common", "authentication_timeout"); ok {
|
||||||
if ok {
|
|
||||||
v, errRet := strconv.ParseInt(tmpStr, 10, 64)
|
v, errRet := strconv.ParseInt(tmpStr, 10, 64)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = fmt.Errorf("Parse conf error: authentication_timeout is incorrect")
|
err = fmt.Errorf("Parse conf error: authentication_timeout is incorrect")
|
||||||
@@ -293,20 +281,17 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "subdomain_host")
|
if tmpStr, ok = conf.Get("common", "subdomain_host"); ok {
|
||||||
if ok {
|
|
||||||
cfg.SubDomainHost = strings.ToLower(strings.TrimSpace(tmpStr))
|
cfg.SubDomainHost = strings.ToLower(strings.TrimSpace(tmpStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "tcp_mux")
|
if tmpStr, ok = conf.Get("common", "tcp_mux"); ok && tmpStr == "false" {
|
||||||
if ok && tmpStr == "false" {
|
|
||||||
cfg.TcpMux = false
|
cfg.TcpMux = false
|
||||||
} else {
|
} else {
|
||||||
cfg.TcpMux = true
|
cfg.TcpMux = true
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpStr, ok = conf.Get("common", "heartbeat_timeout")
|
if tmpStr, ok = conf.Get("common", "heartbeat_timeout"); ok {
|
||||||
if ok {
|
|
||||||
v, errRet := strconv.ParseInt(tmpStr, 10, 64)
|
v, errRet := strconv.ParseInt(tmpStr, 10, 64)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
err = fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
||||||
@@ -317,3 +302,7 @@ func LoadServerCommonConf(conf ini.File) (cfg *ServerCommonConf, err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg *ServerCommonConf) Check() (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ func Forwarder(dstAddr *net.UDPAddr, readCh <-chan *msg.UdpPacket, sendCh chan<-
|
|||||||
mu.Lock()
|
mu.Lock()
|
||||||
delete(udpConnMap, addr)
|
delete(udpConnMap, addr)
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
|
udpConn.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
buf := pool.GetBuf(1500)
|
buf := pool.GetBuf(1500)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ make -f ./Makefile.cross-compiles
|
|||||||
rm -rf ./packages
|
rm -rf ./packages
|
||||||
mkdir ./packages
|
mkdir ./packages
|
||||||
|
|
||||||
os_all='linux windows darwin'
|
os_all='linux windows darwin freebsd'
|
||||||
arch_all='386 amd64 arm mips64 mips64le mips mipsle'
|
arch_all='386 amd64 arm mips64 mips64le mips mipsle'
|
||||||
|
|
||||||
for os in $os_all; do
|
for os in $os_all; do
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/consts"
|
"github.com/fatedier/frp/models/consts"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
@@ -103,7 +104,7 @@ func (ctl *Control) Start() {
|
|||||||
loginRespMsg := &msg.LoginResp{
|
loginRespMsg := &msg.LoginResp{
|
||||||
Version: version.Full(),
|
Version: version.Full(),
|
||||||
RunId: ctl.runId,
|
RunId: ctl.runId,
|
||||||
ServerUdpPort: config.ServerCommonCfg.BindUdpPort,
|
ServerUdpPort: g.GlbServerCfg.BindUdpPort,
|
||||||
Error: "",
|
Error: "",
|
||||||
}
|
}
|
||||||
msg.WriteMsg(ctl.conn, loginRespMsg)
|
msg.WriteMsg(ctl.conn, loginRespMsg)
|
||||||
@@ -172,7 +173,7 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-time.After(time.Duration(config.ServerCommonCfg.UserConnTimeout) * time.Second):
|
case <-time.After(time.Duration(g.GlbServerCfg.UserConnTimeout) * time.Second):
|
||||||
err = fmt.Errorf("timeout trying to get work connection")
|
err = fmt.Errorf("timeout trying to get work connection")
|
||||||
ctl.conn.Warn("%v", err)
|
ctl.conn.Warn("%v", err)
|
||||||
return
|
return
|
||||||
@@ -202,7 +203,7 @@ func (ctl *Control) writer() {
|
|||||||
defer ctl.allShutdown.Start()
|
defer ctl.allShutdown.Start()
|
||||||
defer ctl.writerShutdown.Done()
|
defer ctl.writerShutdown.Done()
|
||||||
|
|
||||||
encWriter, err := crypto.NewWriter(ctl.conn, []byte(config.ServerCommonCfg.PrivilegeToken))
|
encWriter, err := crypto.NewWriter(ctl.conn, []byte(g.GlbServerCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.conn.Error("crypto new writer error: %v", err)
|
ctl.conn.Error("crypto new writer error: %v", err)
|
||||||
ctl.allShutdown.Start()
|
ctl.allShutdown.Start()
|
||||||
@@ -231,7 +232,7 @@ func (ctl *Control) reader() {
|
|||||||
defer ctl.allShutdown.Start()
|
defer ctl.allShutdown.Start()
|
||||||
defer ctl.readerShutdown.Done()
|
defer ctl.readerShutdown.Done()
|
||||||
|
|
||||||
encReader := crypto.NewReader(ctl.conn, []byte(config.ServerCommonCfg.PrivilegeToken))
|
encReader := crypto.NewReader(ctl.conn, []byte(g.GlbServerCfg.Token))
|
||||||
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 {
|
||||||
@@ -265,13 +266,14 @@ func (ctl *Control) stoper() {
|
|||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
ctl.readerShutdown.WaitDone()
|
ctl.readerShutdown.WaitDone()
|
||||||
|
|
||||||
|
ctl.mu.Lock()
|
||||||
|
defer ctl.mu.Unlock()
|
||||||
|
|
||||||
close(ctl.workConnCh)
|
close(ctl.workConnCh)
|
||||||
for workConn := range ctl.workConnCh {
|
for workConn := range ctl.workConnCh {
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctl.mu.Lock()
|
|
||||||
defer ctl.mu.Unlock()
|
|
||||||
for _, pxy := range ctl.proxies {
|
for _, pxy := range ctl.proxies {
|
||||||
pxy.Close()
|
pxy.Close()
|
||||||
ctl.svr.DelProxy(pxy.GetName())
|
ctl.svr.DelProxy(pxy.GetName())
|
||||||
@@ -300,9 +302,10 @@ func (ctl *Control) manager() {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-heartbeat.C:
|
case <-heartbeat.C:
|
||||||
if time.Since(ctl.lastPing) > time.Duration(config.ServerCommonCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPing) > time.Duration(g.GlbServerCfg.HeartBeatTimeout)*time.Second {
|
||||||
ctl.conn.Warn("heartbeat timeout")
|
ctl.conn.Warn("heartbeat timeout")
|
||||||
ctl.allShutdown.Start()
|
ctl.allShutdown.Start()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
case rawMsg, ok := <-ctl.readCh:
|
case rawMsg, ok := <-ctl.readCh:
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -340,7 +343,7 @@ func (ctl *Control) manager() {
|
|||||||
func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) {
|
func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) {
|
||||||
var pxyConf config.ProxyConf
|
var pxyConf config.ProxyConf
|
||||||
// Load configures from NewProxy message and check.
|
// Load configures from NewProxy message and check.
|
||||||
pxyConf, err = config.NewProxyConf(pxyMsg)
|
pxyConf, err = config.NewProxyConfFromMsg(pxyMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -353,9 +356,9 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check ports used number in each client
|
// Check ports used number in each client
|
||||||
if config.ServerCommonCfg.MaxPortsPerClient > 0 {
|
if g.GlbServerCfg.MaxPortsPerClient > 0 {
|
||||||
ctl.mu.Lock()
|
ctl.mu.Lock()
|
||||||
if ctl.portsUsedNum+pxy.GetUsedPortsNum() > int(config.ServerCommonCfg.MaxPortsPerClient) {
|
if ctl.portsUsedNum+pxy.GetUsedPortsNum() > int(g.GlbServerCfg.MaxPortsPerClient) {
|
||||||
ctl.mu.Unlock()
|
ctl.mu.Unlock()
|
||||||
err = fmt.Errorf("exceed the max_ports_per_client")
|
err = fmt.Errorf("exceed the max_ports_per_client")
|
||||||
return
|
return
|
||||||
@@ -402,7 +405,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ServerCommonCfg.MaxPortsPerClient > 0 {
|
if g.GlbServerCfg.MaxPortsPerClient > 0 {
|
||||||
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
|
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
|
||||||
}
|
}
|
||||||
pxy.Close()
|
pxy.Close()
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/assets"
|
"github.com/fatedier/frp/assets"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/g"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
@@ -36,10 +36,14 @@ func RunDashboardServer(addr string, port int) (err error) {
|
|||||||
// url router
|
// url router
|
||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
|
|
||||||
user, passwd := config.ServerCommonCfg.DashboardUser, config.ServerCommonCfg.DashboardPwd
|
user, passwd := g.GlbServerCfg.DashboardUser, g.GlbServerCfg.DashboardPwd
|
||||||
|
|
||||||
// api, see dashboard_api.go
|
// api, see dashboard_api.go
|
||||||
router.GET("/api/serverinfo", frpNet.HttprouterBasicAuth(apiServerInfo, user, passwd))
|
router.GET("/api/serverinfo", frpNet.HttprouterBasicAuth(apiServerInfo, user, passwd))
|
||||||
|
router.GET("/api/proxy/tcp/:name", frpNet.HttprouterBasicAuth(apiProxyTcpByName, user, passwd))
|
||||||
|
router.GET("/api/proxy/udp/:name", frpNet.HttprouterBasicAuth(apiProxyUdpByName, user, passwd))
|
||||||
|
router.GET("/api/proxy/http/:name", frpNet.HttprouterBasicAuth(apiProxyHttpByName, user, passwd))
|
||||||
|
router.GET("/api/proxy/https/:name", frpNet.HttprouterBasicAuth(apiProxyHttpsByName, user, passwd))
|
||||||
router.GET("/api/proxy/tcp", frpNet.HttprouterBasicAuth(apiProxyTcp, user, passwd))
|
router.GET("/api/proxy/tcp", frpNet.HttprouterBasicAuth(apiProxyTcp, user, passwd))
|
||||||
router.GET("/api/proxy/udp", frpNet.HttprouterBasicAuth(apiProxyUdp, user, passwd))
|
router.GET("/api/proxy/udp", frpNet.HttprouterBasicAuth(apiProxyUdp, user, passwd))
|
||||||
router.GET("/api/proxy/http", frpNet.HttprouterBasicAuth(apiProxyHttp, user, passwd))
|
router.GET("/api/proxy/http", frpNet.HttprouterBasicAuth(apiProxyHttp, user, passwd))
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/consts"
|
"github.com/fatedier/frp/models/consts"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
@@ -60,7 +61,7 @@ func apiServerInfo(w http.ResponseWriter, r *http.Request, _ httprouter.Params)
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
log.Info("Http request: [/api/serverinfo]")
|
log.Info("Http request: [/api/serverinfo]")
|
||||||
cfg := config.ServerCommonCfg
|
cfg := &g.GlbServerCfg.ServerCommonConf
|
||||||
serverStats := StatsGetServer()
|
serverStats := StatsGetServer()
|
||||||
res = ServerInfoResp{
|
res = ServerInfoResp{
|
||||||
Version: version.Full(),
|
Version: version.Full(),
|
||||||
@@ -189,6 +190,119 @@ func getProxyStatsByType(proxyType string) (proxyInfos []*ProxyStatsInfo) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get proxy info by name.
|
||||||
|
type GetProxyStatsResp struct {
|
||||||
|
GeneralResponse
|
||||||
|
|
||||||
|
Name string `json:"name"`
|
||||||
|
Conf config.ProxyConf `json:"conf"`
|
||||||
|
TodayTrafficIn int64 `json:"today_traffic_in"`
|
||||||
|
TodayTrafficOut int64 `json:"today_traffic_out"`
|
||||||
|
CurConns int64 `json:"cur_conns"`
|
||||||
|
LastStartTime string `json:"last_start_time"`
|
||||||
|
LastCloseTime string `json:"last_close_time"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// api/proxy/tcp/:name
|
||||||
|
func apiProxyTcpByName(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
var (
|
||||||
|
buf []byte
|
||||||
|
res GetProxyStatsResp
|
||||||
|
)
|
||||||
|
name := params.ByName("name")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
log.Info("Http response [/api/proxy/tcp/:name]: code [%d]", res.Code)
|
||||||
|
}()
|
||||||
|
log.Info("Http request: [/api/proxy/tcp/:name]")
|
||||||
|
|
||||||
|
res = getProxyStatsByTypeAndName(consts.TcpProxy, name)
|
||||||
|
|
||||||
|
buf, _ = json.Marshal(&res)
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// api/proxy/udp/:name
|
||||||
|
func apiProxyUdpByName(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
var (
|
||||||
|
buf []byte
|
||||||
|
res GetProxyStatsResp
|
||||||
|
)
|
||||||
|
name := params.ByName("name")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
log.Info("Http response [/api/proxy/udp/:name]: code [%d]", res.Code)
|
||||||
|
}()
|
||||||
|
log.Info("Http request: [/api/proxy/udp/:name]")
|
||||||
|
|
||||||
|
res = getProxyStatsByTypeAndName(consts.UdpProxy, name)
|
||||||
|
|
||||||
|
buf, _ = json.Marshal(&res)
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// api/proxy/http/:name
|
||||||
|
func apiProxyHttpByName(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
var (
|
||||||
|
buf []byte
|
||||||
|
res GetProxyStatsResp
|
||||||
|
)
|
||||||
|
name := params.ByName("name")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
log.Info("Http response [/api/proxy/http/:name]: code [%d]", res.Code)
|
||||||
|
}()
|
||||||
|
log.Info("Http request: [/api/proxy/http/:name]")
|
||||||
|
|
||||||
|
res = getProxyStatsByTypeAndName(consts.HttpProxy, name)
|
||||||
|
|
||||||
|
buf, _ = json.Marshal(&res)
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// api/proxy/https/:name
|
||||||
|
func apiProxyHttpsByName(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
|
var (
|
||||||
|
buf []byte
|
||||||
|
res GetProxyStatsResp
|
||||||
|
)
|
||||||
|
name := params.ByName("name")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
log.Info("Http response [/api/proxy/https/:name]: code [%d]", res.Code)
|
||||||
|
}()
|
||||||
|
log.Info("Http request: [/api/proxy/https/:name]")
|
||||||
|
|
||||||
|
res = getProxyStatsByTypeAndName(consts.HttpsProxy, name)
|
||||||
|
|
||||||
|
buf, _ = json.Marshal(&res)
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProxyStatsByTypeAndName(proxyType string, proxyName string) (proxyInfo GetProxyStatsResp) {
|
||||||
|
proxyInfo.Name = proxyName
|
||||||
|
ps := StatsGetProxiesByTypeAndName(proxyType, proxyName)
|
||||||
|
if ps == nil {
|
||||||
|
proxyInfo.Code = 1
|
||||||
|
proxyInfo.Msg = "no proxy info found"
|
||||||
|
} else {
|
||||||
|
if pxy, ok := ServerService.pxyManager.GetByName(proxyName); ok {
|
||||||
|
proxyInfo.Conf = pxy.GetConf()
|
||||||
|
proxyInfo.Status = consts.Online
|
||||||
|
} else {
|
||||||
|
proxyInfo.Status = consts.Offline
|
||||||
|
}
|
||||||
|
proxyInfo.TodayTrafficIn = ps.TodayTrafficIn
|
||||||
|
proxyInfo.TodayTrafficOut = ps.TodayTrafficOut
|
||||||
|
proxyInfo.CurConns = ps.CurConns
|
||||||
|
proxyInfo.LastStartTime = ps.LastStartTime
|
||||||
|
proxyInfo.LastCloseTime = ps.LastCloseTime
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// api/proxy/traffic/:name
|
// api/proxy/traffic/:name
|
||||||
type GetProxyTrafficResp struct {
|
type GetProxyTrafficResp struct {
|
||||||
GeneralResponse
|
GeneralResponse
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
"github.com/fatedier/frp/utils/metric"
|
"github.com/fatedier/frp/utils/metric"
|
||||||
)
|
)
|
||||||
@@ -92,19 +92,19 @@ func StatsClearUselessInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StatsNewClient() {
|
func StatsNewClient() {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.ClientCounts.Inc(1)
|
globalStats.ClientCounts.Inc(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatsCloseClient() {
|
func StatsCloseClient() {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.ClientCounts.Dec(1)
|
globalStats.ClientCounts.Dec(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func StatsNewProxy(name string, proxyType string) {
|
func StatsNewProxy(name string, proxyType string) {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.mu.Lock()
|
globalStats.mu.Lock()
|
||||||
defer globalStats.mu.Unlock()
|
defer globalStats.mu.Unlock()
|
||||||
counter, ok := globalStats.ProxyTypeCounts[proxyType]
|
counter, ok := globalStats.ProxyTypeCounts[proxyType]
|
||||||
@@ -130,7 +130,7 @@ func StatsNewProxy(name string, proxyType string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StatsCloseProxy(proxyName string, proxyType string) {
|
func StatsCloseProxy(proxyName string, proxyType string) {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.mu.Lock()
|
globalStats.mu.Lock()
|
||||||
defer globalStats.mu.Unlock()
|
defer globalStats.mu.Unlock()
|
||||||
if counter, ok := globalStats.ProxyTypeCounts[proxyType]; ok {
|
if counter, ok := globalStats.ProxyTypeCounts[proxyType]; ok {
|
||||||
@@ -143,7 +143,7 @@ func StatsCloseProxy(proxyName string, proxyType string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StatsOpenConnection(name string) {
|
func StatsOpenConnection(name string) {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.CurConns.Inc(1)
|
globalStats.CurConns.Inc(1)
|
||||||
|
|
||||||
globalStats.mu.Lock()
|
globalStats.mu.Lock()
|
||||||
@@ -157,7 +157,7 @@ func StatsOpenConnection(name string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StatsCloseConnection(name string) {
|
func StatsCloseConnection(name string) {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.CurConns.Dec(1)
|
globalStats.CurConns.Dec(1)
|
||||||
|
|
||||||
globalStats.mu.Lock()
|
globalStats.mu.Lock()
|
||||||
@@ -171,7 +171,7 @@ func StatsCloseConnection(name string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StatsAddTrafficIn(name string, trafficIn int64) {
|
func StatsAddTrafficIn(name string, trafficIn int64) {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.TotalTrafficIn.Inc(trafficIn)
|
globalStats.TotalTrafficIn.Inc(trafficIn)
|
||||||
|
|
||||||
globalStats.mu.Lock()
|
globalStats.mu.Lock()
|
||||||
@@ -186,7 +186,7 @@ func StatsAddTrafficIn(name string, trafficIn int64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StatsAddTrafficOut(name string, trafficOut int64) {
|
func StatsAddTrafficOut(name string, trafficOut int64) {
|
||||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
if g.GlbServerCfg.DashboardPort != 0 {
|
||||||
globalStats.TotalTrafficOut.Inc(trafficOut)
|
globalStats.TotalTrafficOut.Inc(trafficOut)
|
||||||
|
|
||||||
globalStats.mu.Lock()
|
globalStats.mu.Lock()
|
||||||
@@ -263,6 +263,37 @@ func StatsGetProxiesByType(proxyType string) []*ProxyStats {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StatsGetProxiesByTypeAndName(proxyType string, proxyName string) (res *ProxyStats) {
|
||||||
|
globalStats.mu.Lock()
|
||||||
|
defer globalStats.mu.Unlock()
|
||||||
|
|
||||||
|
for name, proxyStats := range globalStats.ProxyStatistics {
|
||||||
|
if proxyStats.ProxyType != proxyType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if name != proxyName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &ProxyStats{
|
||||||
|
Name: name,
|
||||||
|
Type: proxyStats.ProxyType,
|
||||||
|
TodayTrafficIn: proxyStats.TrafficIn.TodayCount(),
|
||||||
|
TodayTrafficOut: proxyStats.TrafficOut.TodayCount(),
|
||||||
|
CurConns: proxyStats.CurConns.Count(),
|
||||||
|
}
|
||||||
|
if !proxyStats.LastStartTime.IsZero() {
|
||||||
|
res.LastStartTime = proxyStats.LastStartTime.Format("01-02 15:04:05")
|
||||||
|
}
|
||||||
|
if !proxyStats.LastCloseTime.IsZero() {
|
||||||
|
res.LastCloseTime = proxyStats.LastCloseTime.Format("01-02 15:04:05")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type ProxyTrafficInfo struct {
|
type ProxyTrafficInfo struct {
|
||||||
Name string
|
Name string
|
||||||
TrafficIn []int64
|
TrafficIn []int64
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/models/proto/udp"
|
"github.com/fatedier/frp/models/proto/udp"
|
||||||
@@ -126,7 +127,7 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, frpNet.Con
|
|||||||
|
|
||||||
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.GetBaseInfo().ProxyName,
|
||||||
ctl: ctl,
|
ctl: ctl,
|
||||||
listeners: make([]frpNet.Listener, 0),
|
listeners: make([]frpNet.Listener, 0),
|
||||||
Logger: log.NewPrefixLogger(ctl.runId),
|
Logger: log.NewPrefixLogger(ctl.runId),
|
||||||
@@ -191,7 +192,7 @@ func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
|||||||
|
|
||||||
remoteAddr = fmt.Sprintf(":%d", pxy.realPort)
|
remoteAddr = fmt.Sprintf(":%d", pxy.realPort)
|
||||||
pxy.cfg.RemotePort = pxy.realPort
|
pxy.cfg.RemotePort = pxy.realPort
|
||||||
listener, errRet := frpNet.ListenTcp(config.ServerCommonCfg.ProxyBindAddr, pxy.realPort)
|
listener, errRet := frpNet.ListenTcp(g.GlbServerCfg.ProxyBindAddr, pxy.realPort)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
@@ -244,7 +245,7 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
tmpDomain := routeConfig.Domain
|
tmpDomain := routeConfig.Domain
|
||||||
tmpLocation := routeConfig.Location
|
tmpLocation := routeConfig.Location
|
||||||
addrs = append(addrs, util.CanonicalAddr(tmpDomain, int(config.ServerCommonCfg.VhostHttpPort)))
|
addrs = append(addrs, util.CanonicalAddr(tmpDomain, int(g.GlbServerCfg.VhostHttpPort)))
|
||||||
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
||||||
pxy.ctl.svr.httpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
pxy.ctl.svr.httpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
||||||
})
|
})
|
||||||
@@ -253,7 +254,7 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
if pxy.cfg.SubDomain != "" {
|
||||||
routeConfig.Domain = pxy.cfg.SubDomain + "." + config.ServerCommonCfg.SubDomainHost
|
routeConfig.Domain = pxy.cfg.SubDomain + "." + g.GlbServerCfg.SubDomainHost
|
||||||
for _, location := range locations {
|
for _, location := range locations {
|
||||||
routeConfig.Location = location
|
routeConfig.Location = location
|
||||||
err = pxy.ctl.svr.httpReverseProxy.Register(routeConfig)
|
err = pxy.ctl.svr.httpReverseProxy.Register(routeConfig)
|
||||||
@@ -262,7 +263,7 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
tmpDomain := routeConfig.Domain
|
tmpDomain := routeConfig.Domain
|
||||||
tmpLocation := routeConfig.Location
|
tmpLocation := routeConfig.Location
|
||||||
addrs = append(addrs, util.CanonicalAddr(tmpDomain, int(config.ServerCommonCfg.VhostHttpPort)))
|
addrs = append(addrs, util.CanonicalAddr(tmpDomain, g.GlbServerCfg.VhostHttpPort))
|
||||||
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
pxy.closeFuncs = append(pxy.closeFuncs, func() {
|
||||||
pxy.ctl.svr.httpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
pxy.ctl.svr.httpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
||||||
})
|
})
|
||||||
@@ -286,7 +287,7 @@ func (pxy *HttpProxy) GetRealConn() (workConn frpNet.Conn, err error) {
|
|||||||
|
|
||||||
var rwc io.ReadWriteCloser = tmpConn
|
var rwc io.ReadWriteCloser = tmpConn
|
||||||
if pxy.cfg.UseEncryption {
|
if pxy.cfg.UseEncryption {
|
||||||
rwc, err = frpIo.WithEncryption(rwc, []byte(config.ServerCommonCfg.PrivilegeToken))
|
rwc, err = frpIo.WithEncryption(rwc, []byte(g.GlbServerCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create encryption stream error: %v", err)
|
pxy.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
@@ -334,11 +335,11 @@ func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
|
|||||||
l.AddLogPrefix(pxy.name)
|
l.AddLogPrefix(pxy.name)
|
||||||
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
||||||
pxy.listeners = append(pxy.listeners, l)
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(config.ServerCommonCfg.VhostHttpsPort)))
|
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, g.GlbServerCfg.VhostHttpsPort))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
if pxy.cfg.SubDomain != "" {
|
||||||
routeConfig.Domain = pxy.cfg.SubDomain + "." + config.ServerCommonCfg.SubDomainHost
|
routeConfig.Domain = pxy.cfg.SubDomain + "." + g.GlbServerCfg.SubDomainHost
|
||||||
l, errRet := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig)
|
l, errRet := pxy.ctl.svr.VhostHttpsMuxer.Listen(routeConfig)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
@@ -347,7 +348,7 @@ func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
|
|||||||
l.AddLogPrefix(pxy.name)
|
l.AddLogPrefix(pxy.name)
|
||||||
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
||||||
pxy.listeners = append(pxy.listeners, l)
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(config.ServerCommonCfg.VhostHttpsPort)))
|
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(g.GlbServerCfg.VhostHttpsPort)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
||||||
@@ -478,7 +479,7 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
|||||||
|
|
||||||
remoteAddr = fmt.Sprintf(":%d", pxy.realPort)
|
remoteAddr = fmt.Sprintf(":%d", pxy.realPort)
|
||||||
pxy.cfg.RemotePort = pxy.realPort
|
pxy.cfg.RemotePort = pxy.realPort
|
||||||
addr, errRet := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", config.ServerCommonCfg.ProxyBindAddr, pxy.realPort))
|
addr, errRet := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", g.GlbServerCfg.ProxyBindAddr, pxy.realPort))
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
@@ -644,7 +645,7 @@ func HandleUserTcpConnection(pxy Proxy, userConn frpNet.Conn) {
|
|||||||
var local io.ReadWriteCloser = workConn
|
var local io.ReadWriteCloser = workConn
|
||||||
cfg := pxy.GetConf().GetBaseInfo()
|
cfg := pxy.GetConf().GetBaseInfo()
|
||||||
if cfg.UseEncryption {
|
if cfg.UseEncryption {
|
||||||
local, err = frpIo.WithEncryption(local, []byte(config.ServerCommonCfg.PrivilegeToken))
|
local, err = frpIo.WithEncryption(local, []byte(g.GlbServerCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create encryption stream error: %v", err)
|
pxy.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/assets"
|
"github.com/fatedier/frp/assets"
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/g"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
@@ -71,13 +71,13 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewService() (svr *Service, err error) {
|
func NewService() (svr *Service, err error) {
|
||||||
cfg := config.ServerCommonCfg
|
cfg := &g.GlbServerCfg.ServerCommonConf
|
||||||
svr = &Service{
|
svr = &Service{
|
||||||
ctlManager: NewControlManager(),
|
ctlManager: NewControlManager(),
|
||||||
pxyManager: NewProxyManager(),
|
pxyManager: NewProxyManager(),
|
||||||
visitorManager: NewVisitorManager(),
|
visitorManager: NewVisitorManager(),
|
||||||
tcpPortManager: NewPortManager("tcp", cfg.ProxyBindAddr, cfg.PrivilegeAllowPorts),
|
tcpPortManager: NewPortManager("tcp", cfg.ProxyBindAddr, cfg.AllowPorts),
|
||||||
udpPortManager: NewPortManager("udp", cfg.ProxyBindAddr, cfg.PrivilegeAllowPorts),
|
udpPortManager: NewPortManager("udp", cfg.ProxyBindAddr, cfg.AllowPorts),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init assets.
|
// Init assets.
|
||||||
@@ -170,7 +170,7 @@ func (svr *Service) Run() {
|
|||||||
if svr.natHoleController != nil {
|
if svr.natHoleController != nil {
|
||||||
go svr.natHoleController.Run()
|
go svr.natHoleController.Run()
|
||||||
}
|
}
|
||||||
if config.ServerCommonCfg.KcpBindPort > 0 {
|
if g.GlbServerCfg.KcpBindPort > 0 {
|
||||||
go svr.HandleListener(svr.kcpListener)
|
go svr.HandleListener(svr.kcpListener)
|
||||||
}
|
}
|
||||||
svr.HandleListener(svr.listener)
|
svr.HandleListener(svr.listener)
|
||||||
@@ -233,7 +233,7 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ServerCommonCfg.TcpMux {
|
if g.GlbServerCfg.TcpMux {
|
||||||
session, err := smux.Server(frpConn, nil)
|
session, err := smux.Server(frpConn, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Failed to create mux connection: %v", err)
|
log.Warn("Failed to create mux connection: %v", err)
|
||||||
@@ -270,11 +270,11 @@ func (svr *Service) RegisterControl(ctlConn frpNet.Conn, loginMsg *msg.Login) (e
|
|||||||
|
|
||||||
// Check auth.
|
// Check auth.
|
||||||
nowTime := time.Now().Unix()
|
nowTime := time.Now().Unix()
|
||||||
if config.ServerCommonCfg.AuthTimeout != 0 && nowTime-loginMsg.Timestamp > config.ServerCommonCfg.AuthTimeout {
|
if g.GlbServerCfg.AuthTimeout != 0 && nowTime-loginMsg.Timestamp > g.GlbServerCfg.AuthTimeout {
|
||||||
err = fmt.Errorf("authorization timeout")
|
err = fmt.Errorf("authorization timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if util.GetAuthKey(config.ServerCommonCfg.PrivilegeToken, loginMsg.Timestamp) != loginMsg.PrivilegeKey {
|
if util.GetAuthKey(g.GlbServerCfg.Token, loginMsg.Timestamp) != loginMsg.PrivilegeKey {
|
||||||
err = fmt.Errorf("authorization failed")
|
err = fmt.Errorf("authorization failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ server_port = 10700
|
|||||||
log_file = ./frpc.log
|
log_file = ./frpc.log
|
||||||
# debug, info, warn, error
|
# debug, info, warn, error
|
||||||
log_level = debug
|
log_level = debug
|
||||||
privilege_token = 123456
|
token = 123456
|
||||||
admin_port = 10600
|
admin_port = 10600
|
||||||
admin_user = abc
|
admin_user = abc
|
||||||
admin_pwd = abc
|
admin_pwd = abc
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ server_port = 10700
|
|||||||
log_file = ./frpc_visitor.log
|
log_file = ./frpc_visitor.log
|
||||||
# debug, info, warn, error
|
# debug, info, warn, error
|
||||||
log_level = debug
|
log_level = debug
|
||||||
privilege_token = 123456
|
token = 123456
|
||||||
|
|
||||||
[stcp_visitor]
|
[stcp_visitor]
|
||||||
type = stcp
|
type = stcp
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ bind_port = 10700
|
|||||||
vhost_http_port = 10804
|
vhost_http_port = 10804
|
||||||
log_file = ./frps.log
|
log_file = ./frps.log
|
||||||
log_level = debug
|
log_level = debug
|
||||||
privilege_token = 123456
|
token = 123456
|
||||||
privilege_allow_ports = 10000-20000,20002,30000-50000
|
allow_ports = 10000-20000,20002,30000-50000
|
||||||
subdomain_host = sub.com
|
subdomain_host = sub.com
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ func TestWebSocket(t *testing.T) {
|
|||||||
assert.Equal(TEST_HTTP_NORMAL_STR, string(msg))
|
assert.Equal(TEST_HTTP_NORMAL_STR, string(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrivilegeAllowPorts(t *testing.T) {
|
func TestAllowPorts(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
// Port not allowed
|
// Port not allowed
|
||||||
status, err := getProxyStatus(ProxyTcpPortNotAllowed)
|
status, err := getProxyStatus(ProxyTcpPortNotAllowed)
|
||||||
|
|||||||
@@ -21,11 +21,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
|
||||||
kcp "github.com/xtaci/kcp-go"
|
kcp "github.com/fatedier/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conn is the interface of connections used in frp.
|
// Conn is the interface of connections used in frp.
|
||||||
@@ -178,6 +179,7 @@ func (sc *SharedConn) WriteBuff(buffer []byte) (err error) {
|
|||||||
type StatsConn struct {
|
type StatsConn struct {
|
||||||
Conn
|
Conn
|
||||||
|
|
||||||
|
closed int64 // 1 means closed
|
||||||
totalRead int64
|
totalRead int64
|
||||||
totalWrite int64
|
totalWrite int64
|
||||||
statsFunc func(totalRead, totalWrite int64)
|
statsFunc func(totalRead, totalWrite int64)
|
||||||
@@ -203,9 +205,12 @@ func (statsConn *StatsConn) Write(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (statsConn *StatsConn) Close() (err error) {
|
func (statsConn *StatsConn) Close() (err error) {
|
||||||
err = statsConn.Conn.Close()
|
old := atomic.SwapInt64(&statsConn.closed, 1)
|
||||||
if statsConn.statsFunc != nil {
|
if old != 1 {
|
||||||
statsConn.statsFunc(statsConn.totalRead, statsConn.totalWrite)
|
err = statsConn.Conn.Close()
|
||||||
|
if statsConn.statsFunc != nil {
|
||||||
|
statsConn.statsFunc(statsConn.totalRead, statsConn.totalWrite)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version string = "0.16.0"
|
var version string = "0.17.0"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ func readHandshake(rd io.Reader) (host string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(data) < 2 {
|
if len(data) < 2 {
|
||||||
err = fmt.Errorf("readHandshake: extension dataLen[%d] is too short")
|
err = fmt.Errorf("readHandshake: extension dataLen[%d] is too short", len(data))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
31
vendor/github.com/docopt/docopt-go/.travis.yml
generated
vendored
31
vendor/github.com/docopt/docopt-go/.travis.yml
generated
vendored
@@ -1,31 +0,0 @@
|
|||||||
# Travis CI (http://travis-ci.org/) is a continuous integration
|
|
||||||
# service for open source projects. This file configures it
|
|
||||||
# to run unit tests for docopt-go.
|
|
||||||
|
|
||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.4
|
|
||||||
- 1.5
|
|
||||||
- tip
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- go get golang.org/x/tools/cmd/vet
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
- go get github.com/golang/lint/golint
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
|
|
||||||
install:
|
|
||||||
- go get -d -v ./... && go build -v ./...
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go vet -x ./...
|
|
||||||
- $HOME/gopath/bin/golint ./...
|
|
||||||
- go test -v ./...
|
|
||||||
- go test -covermode=count -coverprofile=profile.cov .
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci
|
|
||||||
20
vendor/github.com/docopt/docopt-go/LICENSE
generated
vendored
20
vendor/github.com/docopt/docopt-go/LICENSE
generated
vendored
@@ -1,20 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 Keith Batten
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
88
vendor/github.com/docopt/docopt-go/README.md
generated
vendored
88
vendor/github.com/docopt/docopt-go/README.md
generated
vendored
@@ -1,88 +0,0 @@
|
|||||||
docopt-go
|
|
||||||
=========
|
|
||||||
|
|
||||||
[](https://travis-ci.org/docopt/docopt.go)
|
|
||||||
[](https://coveralls.io/r/docopt/docopt.go)
|
|
||||||
[](https://godoc.org/github.com/docopt/docopt.go)
|
|
||||||
|
|
||||||
An implementation of [docopt](http://docopt.org/) in the
|
|
||||||
[Go](http://golang.org/) programming language.
|
|
||||||
|
|
||||||
**docopt** helps you create *beautiful* command-line interfaces easily:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Naval Fate.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
naval_fate ship new <name>...
|
|
||||||
naval_fate ship <name> move <x> <y> [--speed=<kn>]
|
|
||||||
naval_fate ship shoot <x> <y>
|
|
||||||
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
|
|
||||||
naval_fate -h | --help
|
|
||||||
naval_fate --version
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help Show this screen.
|
|
||||||
--version Show version.
|
|
||||||
--speed=<kn> Speed in knots [default: 10].
|
|
||||||
--moored Moored (anchored) mine.
|
|
||||||
--drifting Drifting mine.`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "Naval Fate 2.0", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**docopt** parses command-line arguments based on a help message. Don't
|
|
||||||
write parser code: a good help message already has all the necessary
|
|
||||||
information in it.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
⚠ Use the alias “docopt-go”. To use docopt in your Go code:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/docopt/docopt-go"
|
|
||||||
```
|
|
||||||
|
|
||||||
To install docopt according to your `$GOPATH`:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ go get github.com/docopt/docopt-go
|
|
||||||
```
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
```go
|
|
||||||
func Parse(doc string, argv []string, help bool, version string,
|
|
||||||
optionsFirst bool, exit ...bool) (map[string]interface{}, error)
|
|
||||||
```
|
|
||||||
Parse `argv` based on the command-line interface described in `doc`.
|
|
||||||
|
|
||||||
Given a conventional command-line help message, docopt creates a parser and
|
|
||||||
processes the arguments. See
|
|
||||||
https://github.com/docopt/docopt#help-message-format for a description of the
|
|
||||||
help message format. If `argv` is `nil`, `os.Args[1:]` is used.
|
|
||||||
|
|
||||||
docopt returns a map of option names to the values parsed from `argv`, and an
|
|
||||||
error or `nil`.
|
|
||||||
|
|
||||||
More documentation for docopt is available at
|
|
||||||
[GoDoc.org](https://godoc.org/github.com/docopt/docopt.go).
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
All tests from the Python version are implemented and passing
|
|
||||||
at [Travis CI](https://travis-ci.org/docopt/docopt.go). New
|
|
||||||
language-agnostic tests have been added
|
|
||||||
to [test_golang.docopt](test_golang.docopt).
|
|
||||||
|
|
||||||
To run tests for docopt-go, use `go test`.
|
|
||||||
1239
vendor/github.com/docopt/docopt-go/docopt.go
generated
vendored
1239
vendor/github.com/docopt/docopt-go/docopt.go
generated
vendored
File diff suppressed because it is too large
Load Diff
1536
vendor/github.com/docopt/docopt-go/docopt_test.go
generated
vendored
1536
vendor/github.com/docopt/docopt-go/docopt_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
37
vendor/github.com/docopt/docopt-go/example_test.go
generated
vendored
37
vendor/github.com/docopt/docopt-go/example_test.go
generated
vendored
@@ -1,37 +0,0 @@
|
|||||||
package docopt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleParse() {
|
|
||||||
usage := `Usage:
|
|
||||||
config_example tcp [<host>] [--force] [--timeout=<seconds>]
|
|
||||||
config_example serial <port> [--baud=<rate>] [--timeout=<seconds>]
|
|
||||||
config_example -h | --help | --version`
|
|
||||||
// parse the command line `comfig_example tcp 127.0.0.1 --force`
|
|
||||||
argv := []string{"tcp", "127.0.0.1", "--force"}
|
|
||||||
arguments, _ := Parse(usage, argv, true, "0.1.1rc", false)
|
|
||||||
// sort the keys of the arguments map
|
|
||||||
var keys []string
|
|
||||||
for k := range arguments {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
// print the argument keys and values
|
|
||||||
for _, k := range keys {
|
|
||||||
fmt.Printf("%9s %v\n", k, arguments[k])
|
|
||||||
}
|
|
||||||
// output:
|
|
||||||
// --baud <nil>
|
|
||||||
// --force true
|
|
||||||
// --help false
|
|
||||||
// --timeout <nil>
|
|
||||||
// --version false
|
|
||||||
// -h false
|
|
||||||
// <host> 127.0.0.1
|
|
||||||
// <port> <nil>
|
|
||||||
// serial false
|
|
||||||
// tcp true
|
|
||||||
}
|
|
||||||
29
vendor/github.com/docopt/docopt-go/examples/arguments/arguments_example.go
generated
vendored
29
vendor/github.com/docopt/docopt-go/examples/arguments/arguments_example.go
generated
vendored
@@ -1,29 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Usage: arguments_example [-vqrh] [FILE] ...
|
|
||||||
arguments_example (--left | --right) CORRECTION FILE
|
|
||||||
|
|
||||||
Process FILE and optionally apply correction to either left-hand side or
|
|
||||||
right-hand side.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
FILE optional input file
|
|
||||||
CORRECTION correction angle, needs FILE, --left or --right to be present
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help
|
|
||||||
-v verbose mode
|
|
||||||
-q quiet mode
|
|
||||||
-r make report
|
|
||||||
--left use left-hand side
|
|
||||||
--right use right-hand side`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
26
vendor/github.com/docopt/docopt-go/examples/calculator/calculator_example.go
generated
vendored
26
vendor/github.com/docopt/docopt-go/examples/calculator/calculator_example.go
generated
vendored
@@ -1,26 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Not a serious example.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
calculator_example <value> ( ( + | - | * | / ) <value> )...
|
|
||||||
calculator_example <function> <value> [( , <value> )]...
|
|
||||||
calculator_example (-h | --help)
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
calculator_example 1 + 2 + 3 + 4 + 5
|
|
||||||
calculator_example 1 + 2 '*' 3 / 4 - 5 # note quotes around '*'
|
|
||||||
calculator_example sum 10 , 20 , 30 , 40
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h, --help
|
|
||||||
`
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
76
vendor/github.com/docopt/docopt-go/examples/config_file/config_file_example.go
generated
vendored
76
vendor/github.com/docopt/docopt-go/examples/config_file/config_file_example.go
generated
vendored
@@ -1,76 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func loadJSONConfig() map[string]interface{} {
|
|
||||||
var result map[string]interface{}
|
|
||||||
jsonData := []byte(`{"--force": true, "--timeout": "10", "--baud": "9600"}`)
|
|
||||||
json.Unmarshal(jsonData, &result)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadIniConfig() map[string]interface{} {
|
|
||||||
iniData := `
|
|
||||||
[default-arguments]
|
|
||||||
--force
|
|
||||||
--baud=19200
|
|
||||||
<host>=localhost`
|
|
||||||
// trivial ini parser
|
|
||||||
// default value for an item is bool: true (for --force)
|
|
||||||
// otherwise the value is a string
|
|
||||||
iniParsed := make(map[string]map[string]interface{})
|
|
||||||
var section string
|
|
||||||
for _, line := range strings.Split(iniData, "\n") {
|
|
||||||
if strings.HasPrefix(line, "[") {
|
|
||||||
section = line
|
|
||||||
iniParsed[section] = make(map[string]interface{})
|
|
||||||
} else if section != "" {
|
|
||||||
kv := strings.SplitN(line, "=", 2)
|
|
||||||
if len(kv) == 1 {
|
|
||||||
iniParsed[section][kv[0]] = true
|
|
||||||
} else if len(kv) == 2 {
|
|
||||||
iniParsed[section][kv[0]] = kv[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return iniParsed["[default-arguments]"]
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge combines two maps.
|
|
||||||
// truthiness takes priority over falsiness
|
|
||||||
// mapA takes priority over mapB
|
|
||||||
func merge(mapA, mapB map[string]interface{}) map[string]interface{} {
|
|
||||||
result := make(map[string]interface{})
|
|
||||||
for k, v := range mapA {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
for k, v := range mapB {
|
|
||||||
if _, ok := result[k]; !ok || result[k] == nil || result[k] == false {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Usage:
|
|
||||||
config_file_example tcp [<host>] [--force] [--timeout=<seconds>]
|
|
||||||
config_file_example serial <port> [--baud=<rate>] [--timeout=<seconds>]
|
|
||||||
config_file_example -h | --help | --version`
|
|
||||||
|
|
||||||
jsonConfig := loadJSONConfig()
|
|
||||||
iniConfig := loadIniConfig()
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "0.1.1rc", false)
|
|
||||||
|
|
||||||
// Arguments take priority over INI, INI takes priority over JSON
|
|
||||||
result := merge(arguments, merge(iniConfig, jsonConfig))
|
|
||||||
|
|
||||||
fmt.Println("JSON config: ", jsonConfig)
|
|
||||||
fmt.Println("INI config: ", iniConfig)
|
|
||||||
fmt.Println("Result: ", result)
|
|
||||||
}
|
|
||||||
22
vendor/github.com/docopt/docopt-go/examples/counted/counted_example.go
generated
vendored
22
vendor/github.com/docopt/docopt-go/examples/counted/counted_example.go
generated
vendored
@@ -1,22 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Usage: counted_example --help
|
|
||||||
counted_example -v...
|
|
||||||
counted_example go [go]
|
|
||||||
counted_example (--path=<path>)...
|
|
||||||
counted_example <file> <file>
|
|
||||||
|
|
||||||
Try: counted_example -vvvvvvvvvv
|
|
||||||
counted_example go go
|
|
||||||
counted_example --path ./here --path ./there
|
|
||||||
counted_example this.txt that.txt`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
38
vendor/github.com/docopt/docopt-go/examples/git/branch/git_branch.go
generated
vendored
38
vendor/github.com/docopt/docopt-go/examples/git/branch/git_branch.go
generated
vendored
@@ -1,38 +0,0 @@
|
|||||||
package git
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `usage: git branch [options] [-r | -a] [--merged=<commit> | --no-merged=<commit>]
|
|
||||||
git branch [options] [-l] [-f] <branchname> [<start-point>]
|
|
||||||
git branch [options] [-r] (-d | -D) <branchname>
|
|
||||||
git branch [options] (-m | -M) [<oldbranch>] <newbranch>
|
|
||||||
|
|
||||||
Generic options:
|
|
||||||
-h, --help
|
|
||||||
-v, --verbose show hash and subject, give twice for upstream branch
|
|
||||||
-t, --track set up tracking mode (see git-pull(1))
|
|
||||||
--set-upstream change upstream info
|
|
||||||
--color=<when> use colored output
|
|
||||||
-r act on remote-tracking branches
|
|
||||||
--contains=<commit> print only branches that contain the commit
|
|
||||||
--abbrev=<n> use <n> digits to display SHA-1s
|
|
||||||
|
|
||||||
Specific git-branch actions:
|
|
||||||
-a list both remote-tracking and local branches
|
|
||||||
-d delete fully merged branch
|
|
||||||
-D delete branch (even if not merged)
|
|
||||||
-m move/rename a branch and its reflog
|
|
||||||
-M move/rename a branch, even if target exists
|
|
||||||
-l create the branch's reflog
|
|
||||||
-f, --force force creation (when already exists)
|
|
||||||
--no-merged=<commit> print only not merged branches
|
|
||||||
--merged=<commit> print only merged branches
|
|
||||||
`
|
|
||||||
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(args)
|
|
||||||
}
|
|
||||||
30
vendor/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go
generated
vendored
30
vendor/github.com/docopt/docopt-go/examples/git/checkout/git_checkout.go
generated
vendored
@@ -1,30 +0,0 @@
|
|||||||
package git
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `usage: git checkout [options] <branch>
|
|
||||||
git checkout [options] <branch> -- <file>...
|
|
||||||
|
|
||||||
options:
|
|
||||||
-q, --quiet suppress progress reporting
|
|
||||||
-b <branch> create and checkout a new branch
|
|
||||||
-B <branch> create/reset and checkout a branch
|
|
||||||
-l create reflog for new branch
|
|
||||||
-t, --track set upstream info for new branch
|
|
||||||
--orphan <new branch>
|
|
||||||
new unparented branch
|
|
||||||
-2, --ours checkout our version for unmerged files
|
|
||||||
-3, --theirs checkout their version for unmerged files
|
|
||||||
-f, --force force checkout (throw away local modifications)
|
|
||||||
-m, --merge perform a 3-way merge with the new branch
|
|
||||||
--conflict <style> conflict style (merge or diff3)
|
|
||||||
-p, --patch select hunks interactively
|
|
||||||
`
|
|
||||||
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(args)
|
|
||||||
}
|
|
||||||
37
vendor/github.com/docopt/docopt-go/examples/git/clone/git_clone.go
generated
vendored
37
vendor/github.com/docopt/docopt-go/examples/git/clone/git_clone.go
generated
vendored
@@ -1,37 +0,0 @@
|
|||||||
package git
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `usage: git clone [options] [--] <repo> [<dir>]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-v, --verbose be more verbose
|
|
||||||
-q, --quiet be more quiet
|
|
||||||
--progress force progress reporting
|
|
||||||
-n, --no-checkout don't create a checkout
|
|
||||||
--bare create a bare repository
|
|
||||||
--mirror create a mirror repository (implies bare)
|
|
||||||
-l, --local to clone from a local repository
|
|
||||||
--no-hardlinks don't use local hardlinks, always copy
|
|
||||||
-s, --shared setup as shared repository
|
|
||||||
--recursive initialize submodules in the clone
|
|
||||||
--recurse-submodules initialize submodules in the clone
|
|
||||||
--template <template-directory>
|
|
||||||
directory from which templates will be used
|
|
||||||
--reference <repo> reference repository
|
|
||||||
-o, --origin <branch>
|
|
||||||
use <branch> instead of 'origin' to track upstream
|
|
||||||
-b, --branch <branch>
|
|
||||||
checkout <branch> instead of the remote's HEAD
|
|
||||||
-u, --upload-pack <path>
|
|
||||||
path to git-upload-pack on the remote
|
|
||||||
--depth <depth> create a shallow clone of that depth
|
|
||||||
`
|
|
||||||
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(args)
|
|
||||||
}
|
|
||||||
108
vendor/github.com/docopt/docopt-go/examples/git/git.go
generated
vendored
108
vendor/github.com/docopt/docopt-go/examples/git/git.go
generated
vendored
@@ -1,108 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `usage: git [--version] [--exec-path=<path>] [--html-path]
|
|
||||||
[-p|--paginate|--no-pager] [--no-replace-objects]
|
|
||||||
[--bare] [--git-dir=<path>] [--work-tree=<path>]
|
|
||||||
[-c <name>=<value>] [--help]
|
|
||||||
<command> [<args>...]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-c <name=value>
|
|
||||||
-h, --help
|
|
||||||
-p, --paginate
|
|
||||||
|
|
||||||
The most commonly used git commands are:
|
|
||||||
add Add file contents to the index
|
|
||||||
branch List, create, or delete branches
|
|
||||||
checkout Checkout a branch or paths to the working tree
|
|
||||||
clone Clone a repository into a new directory
|
|
||||||
commit Record changes to the repository
|
|
||||||
push Update remote refs along with associated objects
|
|
||||||
remote Manage set of tracked repositories
|
|
||||||
|
|
||||||
See 'git help <command>' for more information on a specific command.
|
|
||||||
`
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "git version 1.7.4.4", true)
|
|
||||||
|
|
||||||
fmt.Println("global arguments:")
|
|
||||||
fmt.Println(args)
|
|
||||||
|
|
||||||
fmt.Println("command arguments:")
|
|
||||||
cmd := args["<command>"].(string)
|
|
||||||
cmdArgs := args["<args>"].([]string)
|
|
||||||
|
|
||||||
err := runCommand(cmd, cmdArgs)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func goRun(scriptName string, args []string) (err error) {
|
|
||||||
cmdArgs := make([]string, 2)
|
|
||||||
cmdArgs[0] = "run"
|
|
||||||
cmdArgs[1] = scriptName
|
|
||||||
cmdArgs = append(cmdArgs, args...)
|
|
||||||
osCmd := exec.Command("go", cmdArgs...)
|
|
||||||
var out []byte
|
|
||||||
out, err = osCmd.Output()
|
|
||||||
fmt.Println(string(out))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCommand(cmd string, args []string) (err error) {
|
|
||||||
argv := make([]string, 1)
|
|
||||||
argv[0] = cmd
|
|
||||||
argv = append(argv, args...)
|
|
||||||
switch cmd {
|
|
||||||
case "add":
|
|
||||||
// subcommand is a function call
|
|
||||||
return cmdAdd(argv)
|
|
||||||
case "branch":
|
|
||||||
// subcommand is a script
|
|
||||||
return goRun("branch/git_branch.go", argv)
|
|
||||||
case "checkout", "clone", "commit", "push", "remote":
|
|
||||||
// subcommand is a script
|
|
||||||
scriptName := fmt.Sprintf("%s/git_%s.go", cmd, cmd)
|
|
||||||
return goRun(scriptName, argv)
|
|
||||||
case "help", "":
|
|
||||||
return goRun("git.go", []string{"git_add.go", "--help"})
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("%s is not a git command. See 'git help'", cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdAdd(argv []string) (err error) {
|
|
||||||
usage := `usage: git add [options] [--] [<filepattern>...]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-h, --help
|
|
||||||
-n, --dry-run dry run
|
|
||||||
-v, --verbose be verbose
|
|
||||||
-i, --interactive interactive picking
|
|
||||||
-p, --patch select hunks interactively
|
|
||||||
-e, --edit edit current diff and apply
|
|
||||||
-f, --force allow adding otherwise ignored files
|
|
||||||
-u, --update update tracked files
|
|
||||||
-N, --intent-to-add record only the fact that the path will be added later
|
|
||||||
-A, --all add all, noticing removal of tracked files
|
|
||||||
--refresh don't add, only refresh the index
|
|
||||||
--ignore-errors just skip files which cannot be added because of errors
|
|
||||||
--ignore-missing check if - even missing - files are ignored in dry run
|
|
||||||
`
|
|
||||||
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(args)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
34
vendor/github.com/docopt/docopt-go/examples/git/push/git_push.go
generated
vendored
34
vendor/github.com/docopt/docopt-go/examples/git/push/git_push.go
generated
vendored
@@ -1,34 +0,0 @@
|
|||||||
package git
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `usage: git push [options] [<repository> [<refspec>...]]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-h, --help
|
|
||||||
-v, --verbose be more verbose
|
|
||||||
-q, --quiet be more quiet
|
|
||||||
--repo <repository> repository
|
|
||||||
--all push all refs
|
|
||||||
--mirror mirror all refs
|
|
||||||
--delete delete refs
|
|
||||||
--tags push tags (can't be used with --all or --mirror)
|
|
||||||
-n, --dry-run dry run
|
|
||||||
--porcelain machine-readable output
|
|
||||||
-f, --force force updates
|
|
||||||
--thin use thin pack
|
|
||||||
--receive-pack <receive-pack>
|
|
||||||
receive pack program
|
|
||||||
--exec <receive-pack>
|
|
||||||
receive pack program
|
|
||||||
-u, --set-upstream set upstream for git pull/status
|
|
||||||
--progress force progress reporting
|
|
||||||
`
|
|
||||||
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(args)
|
|
||||||
}
|
|
||||||
28
vendor/github.com/docopt/docopt-go/examples/git/remote/git_remote.go
generated
vendored
28
vendor/github.com/docopt/docopt-go/examples/git/remote/git_remote.go
generated
vendored
@@ -1,28 +0,0 @@
|
|||||||
package git
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `usage: git remote [-v | --verbose]
|
|
||||||
git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
|
||||||
git remote rename <old> <new>
|
|
||||||
git remote rm <name>
|
|
||||||
git remote set-head <name> (-a | -d | <branch>)
|
|
||||||
git remote [-v | --verbose] show [-n] <name>
|
|
||||||
git remote prune [-n | --dry-run] <name>
|
|
||||||
git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]
|
|
||||||
git remote set-branches <name> [--add] <branch>...
|
|
||||||
git remote set-url <name> <newurl> [<oldurl>]
|
|
||||||
git remote set-url --add <name> <newurl>
|
|
||||||
git remote set-url --delete <name> <url>
|
|
||||||
|
|
||||||
options:
|
|
||||||
-v, --verbose be verbose; must be placed before a subcommand
|
|
||||||
`
|
|
||||||
|
|
||||||
args, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(args)
|
|
||||||
}
|
|
||||||
28
vendor/github.com/docopt/docopt-go/examples/naval_fate/naval_fate.go
generated
vendored
28
vendor/github.com/docopt/docopt-go/examples/naval_fate/naval_fate.go
generated
vendored
@@ -1,28 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Naval Fate.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
naval_fate ship new <name>...
|
|
||||||
naval_fate ship <name> move <x> <y> [--speed=<kn>]
|
|
||||||
naval_fate ship shoot <x> <y>
|
|
||||||
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
|
|
||||||
naval_fate -h | --help
|
|
||||||
naval_fate --version
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help Show this screen.
|
|
||||||
--version Show version.
|
|
||||||
--speed=<kn> Speed in knots [default: 10].
|
|
||||||
--moored Moored (anchored) mine.
|
|
||||||
--drifting Drifting mine.`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "Naval Fate 2.0", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
19
vendor/github.com/docopt/docopt-go/examples/odd_even/odd_even_example.go
generated
vendored
19
vendor/github.com/docopt/docopt-go/examples/odd_even/odd_even_example.go
generated
vendored
@@ -1,19 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Usage: odd_even_example [-h | --help] (ODD EVEN)...
|
|
||||||
|
|
||||||
Example, try:
|
|
||||||
odd_even_example 1 2 3 4
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h, --help`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
43
vendor/github.com/docopt/docopt-go/examples/options/options_example.go
generated
vendored
43
vendor/github.com/docopt/docopt-go/examples/options/options_example.go
generated
vendored
@@ -1,43 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Example of program with many options using docopt.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
options_example [-hvqrf NAME] [--exclude=PATTERNS]
|
|
||||||
[--select=ERRORS | --ignore=ERRORS] [--show-source]
|
|
||||||
[--statistics] [--count] [--benchmark] PATH...
|
|
||||||
options_example (--doctest | --testsuite=DIR)
|
|
||||||
options_example --version
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
PATH destination path
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help show this help message and exit
|
|
||||||
--version show version and exit
|
|
||||||
-v --verbose print status messages
|
|
||||||
-q --quiet report only file names
|
|
||||||
-r --repeat show all occurrences of the same error
|
|
||||||
--exclude=PATTERNS exclude files or directories which match these comma
|
|
||||||
separated patterns [default: .svn,CVS,.bzr,.hg,.git]
|
|
||||||
-f NAME --file=NAME when parsing directories, only check filenames matching
|
|
||||||
these comma separated patterns [default: *.go]
|
|
||||||
--select=ERRORS select errors and warnings (e.g. E,W6)
|
|
||||||
--ignore=ERRORS skip errors and warnings (e.g. E4,W)
|
|
||||||
--show-source show source code for each error
|
|
||||||
--statistics count errors and warnings
|
|
||||||
--count print total number of errors and warnings to standard
|
|
||||||
error and set exit code to 1 if total is not null
|
|
||||||
--benchmark measure processing speed
|
|
||||||
--testsuite=DIR run regression tests from dir
|
|
||||||
--doctest run doctest on myself`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "1.0.0rc2", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
24
vendor/github.com/docopt/docopt-go/examples/options_shortcut/options_shortcut_example.go
generated
vendored
24
vendor/github.com/docopt/docopt-go/examples/options_shortcut/options_shortcut_example.go
generated
vendored
@@ -1,24 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Example of program which uses [options] shortcut in pattern.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
options_shortcut_example [options] <port>
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help show this help message and exit
|
|
||||||
--version show version and exit
|
|
||||||
-n, --number N use N as a number
|
|
||||||
-t, --timeout TIMEOUT set timeout TIMEOUT seconds
|
|
||||||
--apply apply changes to database
|
|
||||||
-q operate in quiet mode`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "1.0.0rc2", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
16
vendor/github.com/docopt/docopt-go/examples/quick/quick_example.go
generated
vendored
16
vendor/github.com/docopt/docopt-go/examples/quick/quick_example.go
generated
vendored
@@ -1,16 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `Usage:
|
|
||||||
quick_example tcp <host> <port> [--timeout=<seconds>]
|
|
||||||
quick_example serial <port> [--baud=9600] [--timeout=<seconds>]
|
|
||||||
quick_example -h | --help | --version`
|
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "0.1.1rc", false)
|
|
||||||
fmt.Println(arguments)
|
|
||||||
}
|
|
||||||
31
vendor/github.com/docopt/docopt-go/examples/type_assert/type_assert_example.go
generated
vendored
31
vendor/github.com/docopt/docopt-go/examples/type_assert/type_assert_example.go
generated
vendored
@@ -1,31 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/docopt/docopt-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
usage := `usage: foo [-x] [-y]`
|
|
||||||
|
|
||||||
arguments, err := docopt.Parse(usage, nil, true, "", false)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(arguments)
|
|
||||||
|
|
||||||
var x = arguments["-x"].(bool) // type assertion required
|
|
||||||
if x == true {
|
|
||||||
fmt.Println("x is true")
|
|
||||||
}
|
|
||||||
|
|
||||||
y := arguments["-y"] // no type assertion needed
|
|
||||||
if y == true {
|
|
||||||
fmt.Println("y is true")
|
|
||||||
}
|
|
||||||
y2 := arguments["-y"]
|
|
||||||
if y2 == 10 { // this will never be true, a type assertion would have produced a build error
|
|
||||||
fmt.Println("y is 10")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9
vendor/github.com/docopt/docopt-go/test_golang.docopt
generated
vendored
9
vendor/github.com/docopt/docopt-go/test_golang.docopt
generated
vendored
@@ -1,9 +0,0 @@
|
|||||||
r"""usage: prog [NAME_-2]..."""
|
|
||||||
$ prog 10 20
|
|
||||||
{"NAME_-2": ["10", "20"]}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
{"NAME_-2": ["10"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"NAME_-2": []}
|
|
||||||
957
vendor/github.com/docopt/docopt-go/testcases.docopt
generated
vendored
957
vendor/github.com/docopt/docopt-go/testcases.docopt
generated
vendored
@@ -1,957 +0,0 @@
|
|||||||
r"""Usage: prog
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{}
|
|
||||||
|
|
||||||
$ prog --xxx
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: -a All.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"-a": false}
|
|
||||||
|
|
||||||
$ prog -a
|
|
||||||
{"-a": true}
|
|
||||||
|
|
||||||
$ prog -x
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: --all All.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"--all": false}
|
|
||||||
|
|
||||||
$ prog --all
|
|
||||||
{"--all": true}
|
|
||||||
|
|
||||||
$ prog --xxx
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: -v, --verbose Verbose.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog --verbose
|
|
||||||
{"--verbose": true}
|
|
||||||
|
|
||||||
$ prog --ver
|
|
||||||
{"--verbose": true}
|
|
||||||
|
|
||||||
$ prog -v
|
|
||||||
{"--verbose": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: -p PATH
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -p home/
|
|
||||||
{"-p": "home/"}
|
|
||||||
|
|
||||||
$ prog -phome/
|
|
||||||
{"-p": "home/"}
|
|
||||||
|
|
||||||
$ prog -p
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: --path <path>
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog --path home/
|
|
||||||
{"--path": "home/"}
|
|
||||||
|
|
||||||
$ prog --path=home/
|
|
||||||
{"--path": "home/"}
|
|
||||||
|
|
||||||
$ prog --pa home/
|
|
||||||
{"--path": "home/"}
|
|
||||||
|
|
||||||
$ prog --pa=home/
|
|
||||||
{"--path": "home/"}
|
|
||||||
|
|
||||||
$ prog --path
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: -p PATH, --path=<path> Path to files.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -proot
|
|
||||||
{"--path": "root"}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: -p --path PATH Path to files.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -p root
|
|
||||||
{"--path": "root"}
|
|
||||||
|
|
||||||
$ prog --path root
|
|
||||||
{"--path": "root"}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-p PATH Path to files [default: ./]
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"-p": "./"}
|
|
||||||
|
|
||||||
$ prog -phome
|
|
||||||
{"-p": "home"}
|
|
||||||
|
|
||||||
|
|
||||||
r"""UsAgE: prog [options]
|
|
||||||
|
|
||||||
OpTiOnS: --path=<files> Path to files
|
|
||||||
[dEfAuLt: /root]
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"--path": "/root"}
|
|
||||||
|
|
||||||
$ prog --path=home
|
|
||||||
{"--path": "home"}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [options]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-a Add
|
|
||||||
-r Remote
|
|
||||||
-m <msg> Message
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -r -m Hello
|
|
||||||
{"-a": true,
|
|
||||||
"-r": true,
|
|
||||||
"-m": "Hello"}
|
|
||||||
|
|
||||||
$ prog -armyourass
|
|
||||||
{"-a": true,
|
|
||||||
"-r": true,
|
|
||||||
"-m": "yourass"}
|
|
||||||
|
|
||||||
$ prog -a -r
|
|
||||||
{"-a": true,
|
|
||||||
"-r": true,
|
|
||||||
"-m": null}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
Options: --version
|
|
||||||
--verbose
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog --version
|
|
||||||
{"--version": true,
|
|
||||||
"--verbose": false}
|
|
||||||
|
|
||||||
$ prog --verbose
|
|
||||||
{"--version": false,
|
|
||||||
"--verbose": true}
|
|
||||||
|
|
||||||
$ prog --ver
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog --verb
|
|
||||||
{"--version": false,
|
|
||||||
"--verbose": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [-a -r -m <msg>]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-a Add
|
|
||||||
-r Remote
|
|
||||||
-m <msg> Message
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -armyourass
|
|
||||||
{"-a": true,
|
|
||||||
"-r": true,
|
|
||||||
"-m": "yourass"}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [-armmsg]
|
|
||||||
|
|
||||||
options: -a Add
|
|
||||||
-r Remote
|
|
||||||
-m <msg> Message
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -r -m Hello
|
|
||||||
{"-a": true,
|
|
||||||
"-r": true,
|
|
||||||
"-m": "Hello"}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog -a -b
|
|
||||||
|
|
||||||
options:
|
|
||||||
-a
|
|
||||||
-b
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -b
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -b -a
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -a
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog (-a -b)
|
|
||||||
|
|
||||||
options: -a
|
|
||||||
-b
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -b
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -b -a
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -a
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [-a] -b
|
|
||||||
|
|
||||||
options: -a
|
|
||||||
-b
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -b
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -b -a
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -a
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog -b
|
|
||||||
{"-a": false, "-b": true}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [(-a -b)]
|
|
||||||
|
|
||||||
options: -a
|
|
||||||
-b
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -b
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -b -a
|
|
||||||
{"-a": true, "-b": true}
|
|
||||||
|
|
||||||
$ prog -a
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog -b
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"-a": false, "-b": false}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog (-a|-b)
|
|
||||||
|
|
||||||
options: -a
|
|
||||||
-b
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -b
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog -a
|
|
||||||
{"-a": true, "-b": false}
|
|
||||||
|
|
||||||
$ prog -b
|
|
||||||
{"-a": false, "-b": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [ -a | -b ]
|
|
||||||
|
|
||||||
options: -a
|
|
||||||
-b
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a -b
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"-a": false, "-b": false}
|
|
||||||
|
|
||||||
$ prog -a
|
|
||||||
{"-a": true, "-b": false}
|
|
||||||
|
|
||||||
$ prog -b
|
|
||||||
{"-a": false, "-b": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog <arg>"""
|
|
||||||
$ prog 10
|
|
||||||
{"<arg>": "10"}
|
|
||||||
|
|
||||||
$ prog 10 20
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [<arg>]"""
|
|
||||||
$ prog 10
|
|
||||||
{"<arg>": "10"}
|
|
||||||
|
|
||||||
$ prog 10 20
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"<arg>": null}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog <kind> <name> <type>"""
|
|
||||||
$ prog 10 20 40
|
|
||||||
{"<kind>": "10", "<name>": "20", "<type>": "40"}
|
|
||||||
|
|
||||||
$ prog 10 20
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog <kind> [<name> <type>]"""
|
|
||||||
$ prog 10 20 40
|
|
||||||
{"<kind>": "10", "<name>": "20", "<type>": "40"}
|
|
||||||
|
|
||||||
$ prog 10 20
|
|
||||||
{"<kind>": "10", "<name>": "20", "<type>": null}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [<kind> | <name> <type>]"""
|
|
||||||
$ prog 10 20 40
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog 20 40
|
|
||||||
{"<kind>": null, "<name>": "20", "<type>": "40"}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"<kind>": null, "<name>": null, "<type>": null}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog (<kind> --all | <name>)
|
|
||||||
|
|
||||||
options:
|
|
||||||
--all
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog 10 --all
|
|
||||||
{"<kind>": "10", "--all": true, "<name>": null}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
{"<kind>": null, "--all": false, "<name>": "10"}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [<name> <name>]"""
|
|
||||||
$ prog 10 20
|
|
||||||
{"<name>": ["10", "20"]}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
{"<name>": ["10"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"<name>": []}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [(<name> <name>)]"""
|
|
||||||
$ prog 10 20
|
|
||||||
{"<name>": ["10", "20"]}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"<name>": []}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog NAME..."""
|
|
||||||
$ prog 10 20
|
|
||||||
{"NAME": ["10", "20"]}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
{"NAME": ["10"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [NAME]..."""
|
|
||||||
$ prog 10 20
|
|
||||||
{"NAME": ["10", "20"]}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
{"NAME": ["10"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"NAME": []}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [NAME...]"""
|
|
||||||
$ prog 10 20
|
|
||||||
{"NAME": ["10", "20"]}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
{"NAME": ["10"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"NAME": []}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [NAME [NAME ...]]"""
|
|
||||||
$ prog 10 20
|
|
||||||
{"NAME": ["10", "20"]}
|
|
||||||
|
|
||||||
$ prog 10
|
|
||||||
{"NAME": ["10"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"NAME": []}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog (NAME | --foo NAME)
|
|
||||||
|
|
||||||
options: --foo
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog 10
|
|
||||||
{"NAME": "10", "--foo": false}
|
|
||||||
|
|
||||||
$ prog --foo 10
|
|
||||||
{"NAME": "10", "--foo": true}
|
|
||||||
|
|
||||||
$ prog --foo=10
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog (NAME | --foo) [--bar | NAME]
|
|
||||||
|
|
||||||
options: --foo
|
|
||||||
options: --bar
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog 10
|
|
||||||
{"NAME": ["10"], "--foo": false, "--bar": false}
|
|
||||||
|
|
||||||
$ prog 10 20
|
|
||||||
{"NAME": ["10", "20"], "--foo": false, "--bar": false}
|
|
||||||
|
|
||||||
$ prog --foo --bar
|
|
||||||
{"NAME": [], "--foo": true, "--bar": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Naval Fate.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
prog ship new <name>...
|
|
||||||
prog ship [<name>] move <x> <y> [--speed=<kn>]
|
|
||||||
prog ship shoot <x> <y>
|
|
||||||
prog mine (set|remove) <x> <y> [--moored|--drifting]
|
|
||||||
prog -h | --help
|
|
||||||
prog --version
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-h --help Show this screen.
|
|
||||||
--version Show version.
|
|
||||||
--speed=<kn> Speed in knots [default: 10].
|
|
||||||
--moored Mored (anchored) mine.
|
|
||||||
--drifting Drifting mine.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog ship Guardian move 150 300 --speed=20
|
|
||||||
{"--drifting": false,
|
|
||||||
"--help": false,
|
|
||||||
"--moored": false,
|
|
||||||
"--speed": "20",
|
|
||||||
"--version": false,
|
|
||||||
"<name>": ["Guardian"],
|
|
||||||
"<x>": "150",
|
|
||||||
"<y>": "300",
|
|
||||||
"mine": false,
|
|
||||||
"move": true,
|
|
||||||
"new": false,
|
|
||||||
"remove": false,
|
|
||||||
"set": false,
|
|
||||||
"ship": true,
|
|
||||||
"shoot": false}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog --hello"""
|
|
||||||
$ prog --hello
|
|
||||||
{"--hello": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [--hello=<world>]"""
|
|
||||||
$ prog
|
|
||||||
{"--hello": null}
|
|
||||||
|
|
||||||
$ prog --hello wrld
|
|
||||||
{"--hello": "wrld"}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [-o]"""
|
|
||||||
$ prog
|
|
||||||
{"-o": false}
|
|
||||||
|
|
||||||
$ prog -o
|
|
||||||
{"-o": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [-opr]"""
|
|
||||||
$ prog -op
|
|
||||||
{"-o": true, "-p": true, "-r": false}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog --aabb | --aa"""
|
|
||||||
$ prog --aa
|
|
||||||
{"--aabb": false, "--aa": true}
|
|
||||||
|
|
||||||
$ prog --a
|
|
||||||
"user-error" # not a unique prefix
|
|
||||||
|
|
||||||
#
|
|
||||||
# Counting number of flags
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""Usage: prog -v"""
|
|
||||||
$ prog -v
|
|
||||||
{"-v": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [-v -v]"""
|
|
||||||
$ prog
|
|
||||||
{"-v": 0}
|
|
||||||
|
|
||||||
$ prog -v
|
|
||||||
{"-v": 1}
|
|
||||||
|
|
||||||
$ prog -vv
|
|
||||||
{"-v": 2}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog -v ..."""
|
|
||||||
$ prog
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
$ prog -v
|
|
||||||
{"-v": 1}
|
|
||||||
|
|
||||||
$ prog -vv
|
|
||||||
{"-v": 2}
|
|
||||||
|
|
||||||
$ prog -vvvvvv
|
|
||||||
{"-v": 6}
|
|
||||||
|
|
||||||
|
|
||||||
r"""Usage: prog [-v | -vv | -vvv]
|
|
||||||
|
|
||||||
This one is probably most readable user-friednly variant.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"-v": 0}
|
|
||||||
|
|
||||||
$ prog -v
|
|
||||||
{"-v": 1}
|
|
||||||
|
|
||||||
$ prog -vv
|
|
||||||
{"-v": 2}
|
|
||||||
|
|
||||||
$ prog -vvvv
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [--ver --ver]"""
|
|
||||||
$ prog --ver --ver
|
|
||||||
{"--ver": 2}
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Counting commands
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [go]"""
|
|
||||||
$ prog go
|
|
||||||
{"go": true}
|
|
||||||
|
|
||||||
|
|
||||||
r"""usage: prog [go go]"""
|
|
||||||
$ prog
|
|
||||||
{"go": 0}
|
|
||||||
|
|
||||||
$ prog go
|
|
||||||
{"go": 1}
|
|
||||||
|
|
||||||
$ prog go go
|
|
||||||
{"go": 2}
|
|
||||||
|
|
||||||
$ prog go go go
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
r"""usage: prog go..."""
|
|
||||||
$ prog go go go go go
|
|
||||||
{"go": 5}
|
|
||||||
|
|
||||||
#
|
|
||||||
# [options] does not include options from usage-pattern
|
|
||||||
#
|
|
||||||
r"""usage: prog [options] [-a]
|
|
||||||
|
|
||||||
options: -a
|
|
||||||
-b
|
|
||||||
"""
|
|
||||||
$ prog -a
|
|
||||||
{"-a": true, "-b": false}
|
|
||||||
|
|
||||||
$ prog -aa
|
|
||||||
"user-error"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test [options] shourtcut
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""Usage: prog [options] A
|
|
||||||
Options:
|
|
||||||
-q Be quiet
|
|
||||||
-v Be verbose.
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog arg
|
|
||||||
{"A": "arg", "-v": false, "-q": false}
|
|
||||||
|
|
||||||
$ prog -v arg
|
|
||||||
{"A": "arg", "-v": true, "-q": false}
|
|
||||||
|
|
||||||
$ prog -q arg
|
|
||||||
{"A": "arg", "-v": false, "-q": true}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test single dash
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [-]"""
|
|
||||||
|
|
||||||
$ prog -
|
|
||||||
{"-": true}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"-": false}
|
|
||||||
|
|
||||||
#
|
|
||||||
# If argument is repeated, its value should always be a list
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [NAME [NAME ...]]"""
|
|
||||||
|
|
||||||
$ prog a b
|
|
||||||
{"NAME": ["a", "b"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"NAME": []}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Option's argument defaults to null/None
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [options]
|
|
||||||
options:
|
|
||||||
-a Add
|
|
||||||
-m <msg> Message
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a
|
|
||||||
{"-m": null, "-a": true}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test options without description
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog --hello"""
|
|
||||||
$ prog --hello
|
|
||||||
{"--hello": true}
|
|
||||||
|
|
||||||
r"""usage: prog [--hello=<world>]"""
|
|
||||||
$ prog
|
|
||||||
{"--hello": null}
|
|
||||||
|
|
||||||
$ prog --hello wrld
|
|
||||||
{"--hello": "wrld"}
|
|
||||||
|
|
||||||
r"""usage: prog [-o]"""
|
|
||||||
$ prog
|
|
||||||
{"-o": false}
|
|
||||||
|
|
||||||
$ prog -o
|
|
||||||
{"-o": true}
|
|
||||||
|
|
||||||
r"""usage: prog [-opr]"""
|
|
||||||
$ prog -op
|
|
||||||
{"-o": true, "-p": true, "-r": false}
|
|
||||||
|
|
||||||
r"""usage: git [-v | --verbose]"""
|
|
||||||
$ prog -v
|
|
||||||
{"-v": true, "--verbose": false}
|
|
||||||
|
|
||||||
r"""usage: git remote [-v | --verbose]"""
|
|
||||||
$ prog remote -v
|
|
||||||
{"remote": true, "-v": true, "--verbose": false}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test empty usage pattern
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog"""
|
|
||||||
$ prog
|
|
||||||
{}
|
|
||||||
|
|
||||||
r"""usage: prog
|
|
||||||
prog <a> <b>
|
|
||||||
"""
|
|
||||||
$ prog 1 2
|
|
||||||
{"<a>": "1", "<b>": "2"}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"<a>": null, "<b>": null}
|
|
||||||
|
|
||||||
r"""usage: prog <a> <b>
|
|
||||||
prog
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"<a>": null, "<b>": null}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Option's argument should not capture default value from usage pattern
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [--file=<f>]"""
|
|
||||||
$ prog
|
|
||||||
{"--file": null}
|
|
||||||
|
|
||||||
r"""usage: prog [--file=<f>]
|
|
||||||
|
|
||||||
options: --file <a>
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"--file": null}
|
|
||||||
|
|
||||||
r"""Usage: prog [-a <host:port>]
|
|
||||||
|
|
||||||
Options: -a, --address <host:port> TCP address [default: localhost:6283].
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog
|
|
||||||
{"--address": "localhost:6283"}
|
|
||||||
|
|
||||||
#
|
|
||||||
# If option with argument could be repeated,
|
|
||||||
# its arguments should be accumulated into a list
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog --long=<arg> ..."""
|
|
||||||
|
|
||||||
$ prog --long one
|
|
||||||
{"--long": ["one"]}
|
|
||||||
|
|
||||||
$ prog --long one --long two
|
|
||||||
{"--long": ["one", "two"]}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test multiple elements repeated at once
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog (go <direction> --speed=<km/h>)..."""
|
|
||||||
$ prog go left --speed=5 go right --speed=9
|
|
||||||
{"go": 2, "<direction>": ["left", "right"], "--speed": ["5", "9"]}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Required options should work with option shortcut
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [options] -a
|
|
||||||
|
|
||||||
options: -a
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -a
|
|
||||||
{"-a": true}
|
|
||||||
|
|
||||||
#
|
|
||||||
# If option could be repeated its defaults should be split into a list
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [-o <o>]...
|
|
||||||
|
|
||||||
options: -o <o> [default: x]
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -o this -o that
|
|
||||||
{"-o": ["this", "that"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"-o": ["x"]}
|
|
||||||
|
|
||||||
r"""usage: prog [-o <o>]...
|
|
||||||
|
|
||||||
options: -o <o> [default: x y]
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -o this
|
|
||||||
{"-o": ["this"]}
|
|
||||||
|
|
||||||
$ prog
|
|
||||||
{"-o": ["x", "y"]}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test stacked option's argument
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog -pPATH
|
|
||||||
|
|
||||||
options: -p PATH
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog -pHOME
|
|
||||||
{"-p": "HOME"}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Issue 56: Repeated mutually exclusive args give nested lists sometimes
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""Usage: foo (--xx=x|--yy=y)..."""
|
|
||||||
$ prog --xx=1 --yy=2
|
|
||||||
{"--xx": ["1"], "--yy": ["2"]}
|
|
||||||
|
|
||||||
#
|
|
||||||
# POSIXly correct tokenization
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog [<input file>]"""
|
|
||||||
$ prog f.txt
|
|
||||||
{"<input file>": "f.txt"}
|
|
||||||
|
|
||||||
r"""usage: prog [--input=<file name>]..."""
|
|
||||||
$ prog --input a.txt --input=b.txt
|
|
||||||
{"--input": ["a.txt", "b.txt"]}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Issue 85: `[options]` shourtcut with multiple subcommands
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage: prog good [options]
|
|
||||||
prog fail [options]
|
|
||||||
|
|
||||||
options: --loglevel=N
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog fail --loglevel 5
|
|
||||||
{"--loglevel": "5", "fail": true, "good": false}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Usage-section syntax
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""usage:prog --foo"""
|
|
||||||
$ prog --foo
|
|
||||||
{"--foo": true}
|
|
||||||
|
|
||||||
r"""PROGRAM USAGE: prog --foo"""
|
|
||||||
$ prog --foo
|
|
||||||
{"--foo": true}
|
|
||||||
|
|
||||||
r"""Usage: prog --foo
|
|
||||||
prog --bar
|
|
||||||
NOT PART OF SECTION"""
|
|
||||||
$ prog --foo
|
|
||||||
{"--foo": true, "--bar": false}
|
|
||||||
|
|
||||||
r"""Usage:
|
|
||||||
prog --foo
|
|
||||||
prog --bar
|
|
||||||
|
|
||||||
NOT PART OF SECTION"""
|
|
||||||
$ prog --foo
|
|
||||||
{"--foo": true, "--bar": false}
|
|
||||||
|
|
||||||
r"""Usage:
|
|
||||||
prog --foo
|
|
||||||
prog --bar
|
|
||||||
NOT PART OF SECTION"""
|
|
||||||
$ prog --foo
|
|
||||||
{"--foo": true, "--bar": false}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options-section syntax
|
|
||||||
#
|
|
||||||
|
|
||||||
r"""Usage: prog [options]
|
|
||||||
|
|
||||||
global options: --foo
|
|
||||||
local options: --baz
|
|
||||||
--bar
|
|
||||||
other options:
|
|
||||||
--egg
|
|
||||||
--spam
|
|
||||||
-not-an-option-
|
|
||||||
|
|
||||||
"""
|
|
||||||
$ prog --baz --egg
|
|
||||||
{"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}
|
|
||||||
1
vendor/github.com/gorilla/websocket/.travis.yml
generated
vendored
1
vendor/github.com/gorilla/websocket/.travis.yml
generated
vendored
@@ -8,7 +8,6 @@ matrix:
|
|||||||
- go: 1.6
|
- go: 1.6
|
||||||
- go: 1.7
|
- go: 1.7
|
||||||
- go: 1.8
|
- go: 1.8
|
||||||
- go: 1.9
|
|
||||||
- go: tip
|
- go: tip
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- go: tip
|
- go: tip
|
||||||
|
|||||||
140
vendor/github.com/gorilla/websocket/client.go
generated
vendored
140
vendor/github.com/gorilla/websocket/client.go
generated
vendored
@@ -5,8 +5,10 @@
|
|||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -86,6 +88,50 @@ type Dialer struct {
|
|||||||
|
|
||||||
var errMalformedURL = errors.New("malformed ws or wss URL")
|
var errMalformedURL = errors.New("malformed ws or wss URL")
|
||||||
|
|
||||||
|
// parseURL parses the URL.
|
||||||
|
//
|
||||||
|
// This function is a replacement for the standard library url.Parse function.
|
||||||
|
// In Go 1.4 and earlier, url.Parse loses information from the path.
|
||||||
|
func parseURL(s string) (*url.URL, error) {
|
||||||
|
// From the RFC:
|
||||||
|
//
|
||||||
|
// ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
|
||||||
|
// wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
|
||||||
|
var u url.URL
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(s, "ws://"):
|
||||||
|
u.Scheme = "ws"
|
||||||
|
s = s[len("ws://"):]
|
||||||
|
case strings.HasPrefix(s, "wss://"):
|
||||||
|
u.Scheme = "wss"
|
||||||
|
s = s[len("wss://"):]
|
||||||
|
default:
|
||||||
|
return nil, errMalformedURL
|
||||||
|
}
|
||||||
|
|
||||||
|
if i := strings.Index(s, "?"); i >= 0 {
|
||||||
|
u.RawQuery = s[i+1:]
|
||||||
|
s = s[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
if i := strings.Index(s, "/"); i >= 0 {
|
||||||
|
u.Opaque = s[i:]
|
||||||
|
s = s[:i]
|
||||||
|
} else {
|
||||||
|
u.Opaque = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Host = s
|
||||||
|
|
||||||
|
if strings.Contains(u.Host, "@") {
|
||||||
|
// Don't bother parsing user information because user information is
|
||||||
|
// not allowed in websocket URIs.
|
||||||
|
return nil, errMalformedURL
|
||||||
|
}
|
||||||
|
|
||||||
|
return &u, nil
|
||||||
|
}
|
||||||
|
|
||||||
func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
|
func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
|
||||||
hostPort = u.Host
|
hostPort = u.Host
|
||||||
hostNoPort = u.Host
|
hostNoPort = u.Host
|
||||||
@@ -104,7 +150,7 @@ func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
|
|||||||
return hostPort, hostNoPort
|
return hostPort, hostNoPort
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultDialer is a dialer with all fields set to the default values.
|
// DefaultDialer is a dialer with all fields set to the default zero values.
|
||||||
var DefaultDialer = &Dialer{
|
var DefaultDialer = &Dialer{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
}
|
}
|
||||||
@@ -131,7 +177,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.Parse(urlStr)
|
u, err := parseURL(urlStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -200,52 +246,36 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
|||||||
req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
|
req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostPort, hostNoPort := hostPortNoPort(u)
|
||||||
|
|
||||||
|
var proxyURL *url.URL
|
||||||
|
// Check wether the proxy method has been configured
|
||||||
|
if d.Proxy != nil {
|
||||||
|
proxyURL, err = d.Proxy(req)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetHostPort string
|
||||||
|
if proxyURL != nil {
|
||||||
|
targetHostPort, _ = hostPortNoPort(proxyURL)
|
||||||
|
} else {
|
||||||
|
targetHostPort = hostPort
|
||||||
|
}
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d.HandshakeTimeout != 0 {
|
if d.HandshakeTimeout != 0 {
|
||||||
deadline = time.Now().Add(d.HandshakeTimeout)
|
deadline = time.Now().Add(d.HandshakeTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get network dial function.
|
|
||||||
netDial := d.NetDial
|
netDial := d.NetDial
|
||||||
if netDial == nil {
|
if netDial == nil {
|
||||||
netDialer := &net.Dialer{Deadline: deadline}
|
netDialer := &net.Dialer{Deadline: deadline}
|
||||||
netDial = netDialer.Dial
|
netDial = netDialer.Dial
|
||||||
}
|
}
|
||||||
|
|
||||||
// If needed, wrap the dial function to set the connection deadline.
|
netConn, err := netDial("tcp", targetHostPort)
|
||||||
if !deadline.Equal(time.Time{}) {
|
|
||||||
forwardDial := netDial
|
|
||||||
netDial = func(network, addr string) (net.Conn, error) {
|
|
||||||
c, err := forwardDial(network, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = c.SetDeadline(deadline)
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If needed, wrap the dial function to connect through a proxy.
|
|
||||||
if d.Proxy != nil {
|
|
||||||
proxyURL, err := d.Proxy(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if proxyURL != nil {
|
|
||||||
dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial))
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
netDial = dialer.Dial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hostPort, hostNoPort := hostPortNoPort(u)
|
|
||||||
netConn, err := netDial("tcp", hostPort)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -256,6 +286,42 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if err := netConn.SetDeadline(deadline); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if proxyURL != nil {
|
||||||
|
connectHeader := make(http.Header)
|
||||||
|
if user := proxyURL.User; user != nil {
|
||||||
|
proxyUser := user.Username()
|
||||||
|
if proxyPassword, passwordSet := user.Password(); passwordSet {
|
||||||
|
credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
|
||||||
|
connectHeader.Set("Proxy-Authorization", "Basic "+credential)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connectReq := &http.Request{
|
||||||
|
Method: "CONNECT",
|
||||||
|
URL: &url.URL{Opaque: hostPort},
|
||||||
|
Host: hostPort,
|
||||||
|
Header: connectHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
connectReq.Write(netConn)
|
||||||
|
|
||||||
|
// Read response.
|
||||||
|
// Okay to use and discard buffered reader here, because
|
||||||
|
// TLS server will not speak until spoken to.
|
||||||
|
br := bufio.NewReader(netConn)
|
||||||
|
resp, err := http.ReadResponse(br, connectReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
f := strings.SplitN(resp.Status, " ", 2)
|
||||||
|
return nil, nil, errors.New(f[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if u.Scheme == "https" {
|
if u.Scheme == "https" {
|
||||||
cfg := cloneTLSConfig(d.TLSClientConfig)
|
cfg := cloneTLSConfig(d.TLSClientConfig)
|
||||||
if cfg.ServerName == "" {
|
if cfg.ServerName == "" {
|
||||||
|
|||||||
124
vendor/github.com/gorilla/websocket/client_server_test.go
generated
vendored
124
vendor/github.com/gorilla/websocket/client_server_test.go
generated
vendored
@@ -5,14 +5,11 @@
|
|||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/cookiejar"
|
"net/http/cookiejar"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@@ -34,10 +31,9 @@ var cstUpgrader = Upgrader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cstDialer = Dialer{
|
var cstDialer = Dialer{
|
||||||
Subprotocols: []string{"p1", "p2"},
|
Subprotocols: []string{"p1", "p2"},
|
||||||
ReadBufferSize: 1024,
|
ReadBufferSize: 1024,
|
||||||
WriteBufferSize: 1024,
|
WriteBufferSize: 1024,
|
||||||
HandshakeTimeout: 30 * time.Second,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type cstHandler struct{ *testing.T }
|
type cstHandler struct{ *testing.T }
|
||||||
@@ -147,9 +143,8 @@ func TestProxyDial(t *testing.T) {
|
|||||||
s := newServer(t)
|
s := newServer(t)
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
surl, _ := url.Parse(s.Server.URL)
|
surl, _ := url.Parse(s.URL)
|
||||||
|
|
||||||
cstDialer := cstDialer // make local copy for modification on next line.
|
|
||||||
cstDialer.Proxy = http.ProxyURL(surl)
|
cstDialer.Proxy = http.ProxyURL(surl)
|
||||||
|
|
||||||
connect := false
|
connect := false
|
||||||
@@ -165,8 +160,8 @@ func TestProxyDial(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !connect {
|
if !connect {
|
||||||
t.Log("connect not received")
|
t.Log("connect not recieved")
|
||||||
http.Error(w, "connect not received", 405)
|
http.Error(w, "connect not recieved", 405)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
origHandler.ServeHTTP(w, r)
|
origHandler.ServeHTTP(w, r)
|
||||||
@@ -178,16 +173,16 @@ func TestProxyDial(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer ws.Close()
|
defer ws.Close()
|
||||||
sendRecv(t, ws)
|
sendRecv(t, ws)
|
||||||
|
|
||||||
|
cstDialer.Proxy = http.ProxyFromEnvironment
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProxyAuthorizationDial(t *testing.T) {
|
func TestProxyAuthorizationDial(t *testing.T) {
|
||||||
s := newServer(t)
|
s := newServer(t)
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
surl, _ := url.Parse(s.Server.URL)
|
surl, _ := url.Parse(s.URL)
|
||||||
surl.User = url.UserPassword("username", "password")
|
surl.User = url.UserPassword("username", "password")
|
||||||
|
|
||||||
cstDialer := cstDialer // make local copy for modification on next line.
|
|
||||||
cstDialer.Proxy = http.ProxyURL(surl)
|
cstDialer.Proxy = http.ProxyURL(surl)
|
||||||
|
|
||||||
connect := false
|
connect := false
|
||||||
@@ -205,8 +200,8 @@ func TestProxyAuthorizationDial(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !connect {
|
if !connect {
|
||||||
t.Log("connect with proxy authorization not received")
|
t.Log("connect with proxy authorization not recieved")
|
||||||
http.Error(w, "connect with proxy authorization not received", 405)
|
http.Error(w, "connect with proxy authorization not recieved", 405)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
origHandler.ServeHTTP(w, r)
|
origHandler.ServeHTTP(w, r)
|
||||||
@@ -218,6 +213,8 @@ func TestProxyAuthorizationDial(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer ws.Close()
|
defer ws.Close()
|
||||||
sendRecv(t, ws)
|
sendRecv(t, ws)
|
||||||
|
|
||||||
|
cstDialer.Proxy = http.ProxyFromEnvironment
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDial(t *testing.T) {
|
func TestDial(t *testing.T) {
|
||||||
@@ -240,7 +237,7 @@ func TestDialCookieJar(t *testing.T) {
|
|||||||
d := cstDialer
|
d := cstDialer
|
||||||
d.Jar = jar
|
d.Jar = jar
|
||||||
|
|
||||||
u, _ := url.Parse(s.URL)
|
u, _ := parseURL(s.URL)
|
||||||
|
|
||||||
switch u.Scheme {
|
switch u.Scheme {
|
||||||
case "ws":
|
case "ws":
|
||||||
@@ -249,7 +246,7 @@ func TestDialCookieJar(t *testing.T) {
|
|||||||
u.Scheme = "https"
|
u.Scheme = "https"
|
||||||
}
|
}
|
||||||
|
|
||||||
cookies := []*http.Cookie{{Name: "gorilla", Value: "ws", Path: "/"}}
|
cookies := []*http.Cookie{&http.Cookie{Name: "gorilla", Value: "ws", Path: "/"}}
|
||||||
d.Jar.SetCookies(u, cookies)
|
d.Jar.SetCookies(u, cookies)
|
||||||
|
|
||||||
ws, _, err := d.Dial(s.URL, nil)
|
ws, _, err := d.Dial(s.URL, nil)
|
||||||
@@ -401,17 +398,9 @@ func TestBadMethod(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", s.URL, strings.NewReader(""))
|
resp, err := http.PostForm(s.URL, url.Values{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewRequest returned error %v", err)
|
t.Fatalf("PostForm returned error %v", err)
|
||||||
}
|
|
||||||
req.Header.Set("Connection", "upgrade")
|
|
||||||
req.Header.Set("Upgrade", "websocket")
|
|
||||||
req.Header.Set("Sec-Websocket-Version", "13")
|
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Do returned error %v", err)
|
|
||||||
}
|
}
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusMethodNotAllowed {
|
if resp.StatusCode != http.StatusMethodNotAllowed {
|
||||||
@@ -521,82 +510,3 @@ func TestDialCompression(t *testing.T) {
|
|||||||
defer ws.Close()
|
defer ws.Close()
|
||||||
sendRecv(t, ws)
|
sendRecv(t, ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSocksProxyDial(t *testing.T) {
|
|
||||||
s := newServer(t)
|
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
proxyListener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("listen failed: %v", err)
|
|
||||||
}
|
|
||||||
defer proxyListener.Close()
|
|
||||||
go func() {
|
|
||||||
c1, err := proxyListener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("proxy accept failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer c1.Close()
|
|
||||||
|
|
||||||
c1.SetDeadline(time.Now().Add(30 * time.Second))
|
|
||||||
|
|
||||||
buf := make([]byte, 32)
|
|
||||||
if _, err := io.ReadFull(c1, buf[:3]); err != nil {
|
|
||||||
t.Errorf("read failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if want := []byte{5, 1, 0}; !bytes.Equal(want, buf[:len(want)]) {
|
|
||||||
t.Errorf("read %x, want %x", buf[:len(want)], want)
|
|
||||||
}
|
|
||||||
if _, err := c1.Write([]byte{5, 0}); err != nil {
|
|
||||||
t.Errorf("write failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := io.ReadFull(c1, buf[:10]); err != nil {
|
|
||||||
t.Errorf("read failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if want := []byte{5, 1, 0, 1}; !bytes.Equal(want, buf[:len(want)]) {
|
|
||||||
t.Errorf("read %x, want %x", buf[:len(want)], want)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
buf[1] = 0
|
|
||||||
if _, err := c1.Write(buf[:10]); err != nil {
|
|
||||||
t.Errorf("write failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ip := net.IP(buf[4:8])
|
|
||||||
port := binary.BigEndian.Uint16(buf[8:10])
|
|
||||||
|
|
||||||
c2, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: int(port)})
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("dial failed; %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer c2.Close()
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
io.Copy(c1, c2)
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
io.Copy(c2, c1)
|
|
||||||
<-done
|
|
||||||
}()
|
|
||||||
|
|
||||||
purl, err := url.Parse("socks5://" + proxyListener.Addr().String())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("parse failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cstDialer := cstDialer // make local copy for modification on next line.
|
|
||||||
cstDialer.Proxy = http.ProxyURL(purl)
|
|
||||||
|
|
||||||
ws, _, err := cstDialer.Dial(s.URL, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Dial: %v", err)
|
|
||||||
}
|
|
||||||
defer ws.Close()
|
|
||||||
sendRecv(t, ws)
|
|
||||||
}
|
|
||||||
|
|||||||
40
vendor/github.com/gorilla/websocket/client_test.go
generated
vendored
40
vendor/github.com/gorilla/websocket/client_test.go
generated
vendored
@@ -6,9 +6,49 @@ package websocket
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var parseURLTests = []struct {
|
||||||
|
s string
|
||||||
|
u *url.URL
|
||||||
|
rui string
|
||||||
|
}{
|
||||||
|
{"ws://example.com/", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}, "/"},
|
||||||
|
{"ws://example.com", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}, "/"},
|
||||||
|
{"ws://example.com:7777/", &url.URL{Scheme: "ws", Host: "example.com:7777", Opaque: "/"}, "/"},
|
||||||
|
{"wss://example.com/", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/"}, "/"},
|
||||||
|
{"wss://example.com/a/b", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b"}, "/a/b"},
|
||||||
|
{"ss://example.com/a/b", nil, ""},
|
||||||
|
{"ws://webmaster@example.com/", nil, ""},
|
||||||
|
{"wss://example.com/a/b?x=y", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b", RawQuery: "x=y"}, "/a/b?x=y"},
|
||||||
|
{"wss://example.com?x=y", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/", RawQuery: "x=y"}, "/?x=y"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseURL(t *testing.T) {
|
||||||
|
for _, tt := range parseURLTests {
|
||||||
|
u, err := parseURL(tt.s)
|
||||||
|
if tt.u != nil && err != nil {
|
||||||
|
t.Errorf("parseURL(%q) returned error %v", tt.s, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tt.u == nil {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("parseURL(%q) did not return error", tt.s)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(u, tt.u) {
|
||||||
|
t.Errorf("parseURL(%q) = %v, want %v", tt.s, u, tt.u)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if u.RequestURI() != tt.rui {
|
||||||
|
t.Errorf("parseURL(%q).RequestURI() = %v, want %v", tt.s, u.RequestURI(), tt.rui)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var hostPortNoPortTests = []struct {
|
var hostPortNoPortTests = []struct {
|
||||||
u *url.URL
|
u *url.URL
|
||||||
hostPort, hostNoPort string
|
hostPort, hostNoPort string
|
||||||
|
|||||||
44
vendor/github.com/gorilla/websocket/conn.go
generated
vendored
44
vendor/github.com/gorilla/websocket/conn.go
generated
vendored
@@ -76,7 +76,7 @@ const (
|
|||||||
// is UTF-8 encoded text.
|
// is UTF-8 encoded text.
|
||||||
PingMessage = 9
|
PingMessage = 9
|
||||||
|
|
||||||
// PongMessage denotes a pong control message. The optional message payload
|
// PongMessage denotes a ping control message. The optional message payload
|
||||||
// is UTF-8 encoded text.
|
// is UTF-8 encoded text.
|
||||||
PongMessage = 10
|
PongMessage = 10
|
||||||
)
|
)
|
||||||
@@ -100,8 +100,9 @@ func (e *netError) Error() string { return e.msg }
|
|||||||
func (e *netError) Temporary() bool { return e.temporary }
|
func (e *netError) Temporary() bool { return e.temporary }
|
||||||
func (e *netError) Timeout() bool { return e.timeout }
|
func (e *netError) Timeout() bool { return e.timeout }
|
||||||
|
|
||||||
// CloseError represents a close message.
|
// CloseError represents close frame.
|
||||||
type CloseError struct {
|
type CloseError struct {
|
||||||
|
|
||||||
// Code is defined in RFC 6455, section 11.7.
|
// Code is defined in RFC 6455, section 11.7.
|
||||||
Code int
|
Code int
|
||||||
|
|
||||||
@@ -342,8 +343,7 @@ func (c *Conn) Subprotocol() string {
|
|||||||
return c.subprotocol
|
return c.subprotocol
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the underlying network connection without sending or waiting
|
// Close closes the underlying network connection without sending or waiting for a close frame.
|
||||||
// for a close message.
|
|
||||||
func (c *Conn) Close() error {
|
func (c *Conn) Close() error {
|
||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
}
|
}
|
||||||
@@ -484,9 +484,6 @@ func (c *Conn) prepWrite(messageType int) error {
|
|||||||
//
|
//
|
||||||
// There can be at most one open writer on a connection. NextWriter closes the
|
// There can be at most one open writer on a connection. NextWriter closes the
|
||||||
// previous writer if the application has not already done so.
|
// previous writer if the application has not already done so.
|
||||||
//
|
|
||||||
// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and
|
|
||||||
// PongMessage) are supported.
|
|
||||||
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
|
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
|
||||||
if err := c.prepWrite(messageType); err != nil {
|
if err := c.prepWrite(messageType); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -767,6 +764,7 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
|
|||||||
// Read methods
|
// Read methods
|
||||||
|
|
||||||
func (c *Conn) advanceFrame() (int, error) {
|
func (c *Conn) advanceFrame() (int, error) {
|
||||||
|
|
||||||
// 1. Skip remainder of previous frame.
|
// 1. Skip remainder of previous frame.
|
||||||
|
|
||||||
if c.readRemaining > 0 {
|
if c.readRemaining > 0 {
|
||||||
@@ -1035,7 +1033,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetReadLimit sets the maximum size for a message read from the peer. If a
|
// SetReadLimit sets the maximum size for a message read from the peer. If a
|
||||||
// message exceeds the limit, the connection sends a close message to the peer
|
// message exceeds the limit, the connection sends a close frame to the peer
|
||||||
// and returns ErrReadLimit to the application.
|
// and returns ErrReadLimit to the application.
|
||||||
func (c *Conn) SetReadLimit(limit int64) {
|
func (c *Conn) SetReadLimit(limit int64) {
|
||||||
c.readLimit = limit
|
c.readLimit = limit
|
||||||
@@ -1048,21 +1046,24 @@ func (c *Conn) CloseHandler() func(code int, text string) error {
|
|||||||
|
|
||||||
// SetCloseHandler sets the handler for close messages received from the peer.
|
// SetCloseHandler sets the handler for close messages received from the peer.
|
||||||
// The code argument to h is the received close code or CloseNoStatusReceived
|
// The code argument to h is the received close code or CloseNoStatusReceived
|
||||||
// if the close message is empty. The default close handler sends a close
|
// if the close message is empty. The default close handler sends a close frame
|
||||||
// message back to the peer.
|
// back to the peer.
|
||||||
//
|
//
|
||||||
// The application must read the connection to process close messages as
|
// The application must read the connection to process close messages as
|
||||||
// described in the section on Control Messages above.
|
// described in the section on Control Frames above.
|
||||||
//
|
//
|
||||||
// The connection read methods return a CloseError when a close message is
|
// The connection read methods return a CloseError when a close frame is
|
||||||
// received. Most applications should handle close messages as part of their
|
// received. Most applications should handle close messages as part of their
|
||||||
// normal error handling. Applications should only set a close handler when the
|
// normal error handling. Applications should only set a close handler when the
|
||||||
// application must perform some action before sending a close message back to
|
// application must perform some action before sending a close frame back to
|
||||||
// the peer.
|
// the peer.
|
||||||
func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
|
func (c *Conn) SetCloseHandler(h func(code int, text string) error) {
|
||||||
if h == nil {
|
if h == nil {
|
||||||
h = func(code int, text string) error {
|
h = func(code int, text string) error {
|
||||||
message := FormatCloseMessage(code, "")
|
message := []byte{}
|
||||||
|
if code != CloseNoStatusReceived {
|
||||||
|
message = FormatCloseMessage(code, "")
|
||||||
|
}
|
||||||
c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
|
c.WriteControl(CloseMessage, message, time.Now().Add(writeWait))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1076,11 +1077,11 @@ func (c *Conn) PingHandler() func(appData string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetPingHandler sets the handler for ping messages received from the peer.
|
// SetPingHandler sets the handler for ping messages received from the peer.
|
||||||
// The appData argument to h is the PING message application data. The default
|
// The appData argument to h is the PING frame application data. The default
|
||||||
// ping handler sends a pong to the peer.
|
// ping handler sends a pong to the peer.
|
||||||
//
|
//
|
||||||
// The application must read the connection to process ping messages as
|
// The application must read the connection to process ping messages as
|
||||||
// described in the section on Control Messages above.
|
// described in the section on Control Frames above.
|
||||||
func (c *Conn) SetPingHandler(h func(appData string) error) {
|
func (c *Conn) SetPingHandler(h func(appData string) error) {
|
||||||
if h == nil {
|
if h == nil {
|
||||||
h = func(message string) error {
|
h = func(message string) error {
|
||||||
@@ -1102,11 +1103,11 @@ func (c *Conn) PongHandler() func(appData string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetPongHandler sets the handler for pong messages received from the peer.
|
// SetPongHandler sets the handler for pong messages received from the peer.
|
||||||
// The appData argument to h is the PONG message application data. The default
|
// The appData argument to h is the PONG frame application data. The default
|
||||||
// pong handler does nothing.
|
// pong handler does nothing.
|
||||||
//
|
//
|
||||||
// The application must read the connection to process ping messages as
|
// The application must read the connection to process ping messages as
|
||||||
// described in the section on Control Messages above.
|
// described in the section on Control Frames above.
|
||||||
func (c *Conn) SetPongHandler(h func(appData string) error) {
|
func (c *Conn) SetPongHandler(h func(appData string) error) {
|
||||||
if h == nil {
|
if h == nil {
|
||||||
h = func(string) error { return nil }
|
h = func(string) error { return nil }
|
||||||
@@ -1140,14 +1141,7 @@ func (c *Conn) SetCompressionLevel(level int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
|
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
|
||||||
// An empty message is returned for code CloseNoStatusReceived.
|
|
||||||
func FormatCloseMessage(closeCode int, text string) []byte {
|
func FormatCloseMessage(closeCode int, text string) []byte {
|
||||||
if closeCode == CloseNoStatusReceived {
|
|
||||||
// Return empty message because it's illegal to send
|
|
||||||
// CloseNoStatusReceived. Return non-nil value in case application
|
|
||||||
// checks for nil.
|
|
||||||
return []byte{}
|
|
||||||
}
|
|
||||||
buf := make([]byte, 2+len(text))
|
buf := make([]byte, 2+len(text))
|
||||||
binary.BigEndian.PutUint16(buf, uint16(closeCode))
|
binary.BigEndian.PutUint16(buf, uint16(closeCode))
|
||||||
copy(buf[2:], text)
|
copy(buf[2:], text)
|
||||||
|
|||||||
3
vendor/github.com/gorilla/websocket/conn_test.go
generated
vendored
3
vendor/github.com/gorilla/websocket/conn_test.go
generated
vendored
@@ -341,6 +341,7 @@ func TestUnderlyingConn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBufioReadBytes(t *testing.T) {
|
func TestBufioReadBytes(t *testing.T) {
|
||||||
|
|
||||||
// Test calling bufio.ReadBytes for value longer than read buffer size.
|
// Test calling bufio.ReadBytes for value longer than read buffer size.
|
||||||
|
|
||||||
m := make([]byte, 512)
|
m := make([]byte, 512)
|
||||||
@@ -365,7 +366,7 @@ func TestBufioReadBytes(t *testing.T) {
|
|||||||
t.Fatalf("ReadBytes() returned %v", err)
|
t.Fatalf("ReadBytes() returned %v", err)
|
||||||
}
|
}
|
||||||
if len(p) != len(m) {
|
if len(p) != len(m) {
|
||||||
t.Fatalf("read returned %d bytes, want %d bytes", len(p), len(m))
|
t.Fatalf("read returnd %d bytes, want %d bytes", len(p), len(m))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
45
vendor/github.com/gorilla/websocket/doc.go
generated
vendored
45
vendor/github.com/gorilla/websocket/doc.go
generated
vendored
@@ -6,8 +6,9 @@
|
|||||||
//
|
//
|
||||||
// Overview
|
// Overview
|
||||||
//
|
//
|
||||||
// The Conn type represents a WebSocket connection. A server application calls
|
// The Conn type represents a WebSocket connection. A server application uses
|
||||||
// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn:
|
// the Upgrade function from an Upgrader object with a HTTP request handler
|
||||||
|
// to get a pointer to a Conn:
|
||||||
//
|
//
|
||||||
// var upgrader = websocket.Upgrader{
|
// var upgrader = websocket.Upgrader{
|
||||||
// ReadBufferSize: 1024,
|
// ReadBufferSize: 1024,
|
||||||
@@ -30,12 +31,10 @@
|
|||||||
// for {
|
// for {
|
||||||
// messageType, p, err := conn.ReadMessage()
|
// messageType, p, err := conn.ReadMessage()
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// log.Println(err)
|
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
// if err := conn.WriteMessage(messageType, p); err != nil {
|
// if err = conn.WriteMessage(messageType, p); err != nil {
|
||||||
// log.Println(err)
|
// return err
|
||||||
// return
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
@@ -86,26 +85,20 @@
|
|||||||
// and pong. Call the connection WriteControl, WriteMessage or NextWriter
|
// and pong. Call the connection WriteControl, WriteMessage or NextWriter
|
||||||
// methods to send a control message to the peer.
|
// methods to send a control message to the peer.
|
||||||
//
|
//
|
||||||
// Connections handle received close messages by calling the handler function
|
// Connections handle received close messages by sending a close message to the
|
||||||
// set with the SetCloseHandler method and by returning a *CloseError from the
|
// peer and returning a *CloseError from the the NextReader, ReadMessage or the
|
||||||
// NextReader, ReadMessage or the message Read method. The default close
|
// message Read method.
|
||||||
// handler sends a close message to the peer.
|
|
||||||
//
|
//
|
||||||
// Connections handle received ping messages by calling the handler function
|
// Connections handle received ping and pong messages by invoking callback
|
||||||
// set with the SetPingHandler method. The default ping handler sends a pong
|
// functions set with SetPingHandler and SetPongHandler methods. The callback
|
||||||
// message to the peer.
|
// functions are called from the NextReader, ReadMessage and the message Read
|
||||||
|
// methods.
|
||||||
//
|
//
|
||||||
// Connections handle received pong messages by calling the handler function
|
// The default ping handler sends a pong to the peer. The application's reading
|
||||||
// set with the SetPongHandler method. The default pong handler does nothing.
|
// goroutine can block for a short time while the handler writes the pong data
|
||||||
// If an application sends ping messages, then the application should set a
|
// to the connection.
|
||||||
// pong handler to receive the corresponding pong.
|
|
||||||
//
|
//
|
||||||
// The control message handler functions are called from the NextReader,
|
// The application must read the connection to process ping, pong and close
|
||||||
// ReadMessage and message reader Read methods. The default close and ping
|
|
||||||
// handlers can block these methods for a short time when the handler writes to
|
|
||||||
// the connection.
|
|
||||||
//
|
|
||||||
// The application must read the connection to process close, ping and pong
|
|
||||||
// messages sent from the peer. If the application is not otherwise interested
|
// messages sent from the peer. If the application is not otherwise interested
|
||||||
// in messages from the peer, then the application should start a goroutine to
|
// in messages from the peer, then the application should start a goroutine to
|
||||||
// read and discard messages from the peer. A simple example is:
|
// read and discard messages from the peer. A simple example is:
|
||||||
@@ -154,9 +147,9 @@
|
|||||||
// CheckOrigin: func(r *http.Request) bool { return true },
|
// CheckOrigin: func(r *http.Request) bool { return true },
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The deprecated package-level Upgrade function does not perform origin
|
// The deprecated Upgrade function does not enforce an origin policy. It's the
|
||||||
// checking. The application is responsible for checking the Origin header
|
// application's responsibility to check the Origin header before calling
|
||||||
// before calling the Upgrade function.
|
// Upgrade.
|
||||||
//
|
//
|
||||||
// Compression EXPERIMENTAL
|
// Compression EXPERIMENTAL
|
||||||
//
|
//
|
||||||
|
|||||||
2
vendor/github.com/gorilla/websocket/examples/chat/README.md
generated
vendored
2
vendor/github.com/gorilla/websocket/examples/chat/README.md
generated
vendored
@@ -1,6 +1,6 @@
|
|||||||
# Chat Example
|
# Chat Example
|
||||||
|
|
||||||
This application shows how to use the
|
This application shows how to use use the
|
||||||
[websocket](https://github.com/gorilla/websocket) package to implement a simple
|
[websocket](https://github.com/gorilla/websocket) package to implement a simple
|
||||||
web chat application.
|
web chat application.
|
||||||
|
|
||||||
|
|||||||
4
vendor/github.com/gorilla/websocket/examples/chat/client.go
generated
vendored
4
vendor/github.com/gorilla/websocket/examples/chat/client.go
generated
vendored
@@ -64,7 +64,7 @@ func (c *Client) readPump() {
|
|||||||
for {
|
for {
|
||||||
_, message, err := c.conn.ReadMessage()
|
_, message, err := c.conn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
|
||||||
log.Printf("error: %v", err)
|
log.Printf("error: %v", err)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@@ -113,7 +113,7 @@ func (c *Client) writePump() {
|
|||||||
}
|
}
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
||||||
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
if err := c.conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
vendor/github.com/gorilla/websocket/examples/echo/server.go
generated
vendored
1
vendor/github.com/gorilla/websocket/examples/echo/server.go
generated
vendored
@@ -55,7 +55,6 @@ func main() {
|
|||||||
|
|
||||||
var homeTemplate = template.Must(template.New("").Parse(`
|
var homeTemplate = template.Must(template.New("").Parse(`
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
11
vendor/github.com/gorilla/websocket/json.go
generated
vendored
11
vendor/github.com/gorilla/websocket/json.go
generated
vendored
@@ -9,14 +9,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteJSON writes the JSON encoding of v as a message.
|
// WriteJSON is deprecated, use c.WriteJSON instead.
|
||||||
//
|
|
||||||
// Deprecated: Use c.WriteJSON instead.
|
|
||||||
func WriteJSON(c *Conn, v interface{}) error {
|
func WriteJSON(c *Conn, v interface{}) error {
|
||||||
return c.WriteJSON(v)
|
return c.WriteJSON(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteJSON writes the JSON encoding of v as a message.
|
// WriteJSON writes the JSON encoding of v to the connection.
|
||||||
//
|
//
|
||||||
// See the documentation for encoding/json Marshal for details about the
|
// See the documentation for encoding/json Marshal for details about the
|
||||||
// conversion of Go values to JSON.
|
// conversion of Go values to JSON.
|
||||||
@@ -33,10 +31,7 @@ func (c *Conn) WriteJSON(v interface{}) error {
|
|||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadJSON reads the next JSON-encoded message from the connection and stores
|
// ReadJSON is deprecated, use c.ReadJSON instead.
|
||||||
// it in the value pointed to by v.
|
|
||||||
//
|
|
||||||
// Deprecated: Use c.ReadJSON instead.
|
|
||||||
func ReadJSON(c *Conn, v interface{}) error {
|
func ReadJSON(c *Conn, v interface{}) error {
|
||||||
return c.ReadJSON(v)
|
return c.ReadJSON(v)
|
||||||
}
|
}
|
||||||
|
|||||||
1
vendor/github.com/gorilla/websocket/mask.go
generated
vendored
1
vendor/github.com/gorilla/websocket/mask.go
generated
vendored
@@ -11,6 +11,7 @@ import "unsafe"
|
|||||||
const wordSize = int(unsafe.Sizeof(uintptr(0)))
|
const wordSize = int(unsafe.Sizeof(uintptr(0)))
|
||||||
|
|
||||||
func maskBytes(key [4]byte, pos int, b []byte) int {
|
func maskBytes(key [4]byte, pos int, b []byte) int {
|
||||||
|
|
||||||
// Mask one byte at a time for small buffers.
|
// Mask one byte at a time for small buffers.
|
||||||
if len(b) < 2*wordSize {
|
if len(b) < 2*wordSize {
|
||||||
for i := range b {
|
for i := range b {
|
||||||
|
|||||||
77
vendor/github.com/gorilla/websocket/proxy.go
generated
vendored
77
vendor/github.com/gorilla/websocket/proxy.go
generated
vendored
@@ -1,77 +0,0 @@
|
|||||||
// Copyright 2017 The Gorilla WebSocket Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package websocket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type netDialerFunc func(netowrk, addr string) (net.Conn, error)
|
|
||||||
|
|
||||||
func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
|
|
||||||
return fn(network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
|
|
||||||
return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpProxyDialer struct {
|
|
||||||
proxyURL *url.URL
|
|
||||||
fowardDial func(network, addr string) (net.Conn, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
|
|
||||||
hostPort, _ := hostPortNoPort(hpd.proxyURL)
|
|
||||||
conn, err := hpd.fowardDial(network, hostPort)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
connectHeader := make(http.Header)
|
|
||||||
if user := hpd.proxyURL.User; user != nil {
|
|
||||||
proxyUser := user.Username()
|
|
||||||
if proxyPassword, passwordSet := user.Password(); passwordSet {
|
|
||||||
credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
|
|
||||||
connectHeader.Set("Proxy-Authorization", "Basic "+credential)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connectReq := &http.Request{
|
|
||||||
Method: "CONNECT",
|
|
||||||
URL: &url.URL{Opaque: addr},
|
|
||||||
Host: addr,
|
|
||||||
Header: connectHeader,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := connectReq.Write(conn); err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read response. It's OK to use and discard buffered reader here becaue
|
|
||||||
// the remote server does not speak until spoken to.
|
|
||||||
br := bufio.NewReader(conn)
|
|
||||||
resp, err := http.ReadResponse(br, connectReq)
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
conn.Close()
|
|
||||||
f := strings.SplitN(resp.Status, " ", 2)
|
|
||||||
return nil, errors.New(f[1])
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
37
vendor/github.com/gorilla/websocket/server.go
generated
vendored
37
vendor/github.com/gorilla/websocket/server.go
generated
vendored
@@ -76,7 +76,7 @@ func checkSameOrigin(r *http.Request) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return equalASCIIFold(u.Host, r.Host)
|
return u.Host == r.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
|
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
|
||||||
@@ -104,28 +104,26 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header
|
|||||||
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
|
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
|
||||||
// response.
|
// response.
|
||||||
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
|
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
|
||||||
const badHandshake = "websocket: the client is not using the websocket protocol: "
|
|
||||||
|
|
||||||
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
|
|
||||||
return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
|
|
||||||
return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Method != "GET" {
|
if r.Method != "GET" {
|
||||||
return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET")
|
return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET")
|
||||||
}
|
|
||||||
|
|
||||||
if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
|
|
||||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
|
if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok {
|
||||||
return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported")
|
return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
|
||||||
|
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
|
||||||
|
return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") {
|
||||||
|
return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header")
|
||||||
|
}
|
||||||
|
|
||||||
checkOrigin := u.CheckOrigin
|
checkOrigin := u.CheckOrigin
|
||||||
if checkOrigin == nil {
|
if checkOrigin == nil {
|
||||||
checkOrigin = checkSameOrigin
|
checkOrigin = checkSameOrigin
|
||||||
@@ -232,11 +230,10 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade
|
|||||||
|
|
||||||
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
|
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
|
||||||
//
|
//
|
||||||
// Deprecated: Use websocket.Upgrader instead.
|
// This function is deprecated, use websocket.Upgrader instead.
|
||||||
//
|
//
|
||||||
// Upgrade does not perform origin checking. The application is responsible for
|
// The application is responsible for checking the request origin before
|
||||||
// checking the Origin header before calling Upgrade. An example implementation
|
// calling Upgrade. An example implementation of the same origin policy is:
|
||||||
// of the same origin policy check is:
|
|
||||||
//
|
//
|
||||||
// if req.Header.Get("Origin") != "http://"+req.Host {
|
// if req.Header.Get("Origin") != "http://"+req.Host {
|
||||||
// http.Error(w, "Origin not allowed", 403)
|
// http.Error(w, "Origin not allowed", 403)
|
||||||
|
|||||||
18
vendor/github.com/gorilla/websocket/server_test.go
generated
vendored
18
vendor/github.com/gorilla/websocket/server_test.go
generated
vendored
@@ -49,21 +49,3 @@ func TestIsWebSocketUpgrade(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkSameOriginTests = []struct {
|
|
||||||
ok bool
|
|
||||||
r *http.Request
|
|
||||||
}{
|
|
||||||
{false, &http.Request{Host: "example.org", Header: map[string][]string{"Origin": []string{"https://other.org"}}}},
|
|
||||||
{true, &http.Request{Host: "example.org", Header: map[string][]string{"Origin": []string{"https://example.org"}}}},
|
|
||||||
{true, &http.Request{Host: "Example.org", Header: map[string][]string{"Origin": []string{"https://example.org"}}}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckSameOrigin(t *testing.T) {
|
|
||||||
for _, tt := range checkSameOriginTests {
|
|
||||||
ok := checkSameOrigin(tt.r)
|
|
||||||
if tt.ok != ok {
|
|
||||||
t.Errorf("checkSameOrigin(%+v) returned %v, want %v", tt.r, ok, tt.ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
33
vendor/github.com/gorilla/websocket/util.go
generated
vendored
33
vendor/github.com/gorilla/websocket/util.go
generated
vendored
@@ -11,7 +11,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
|
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
|
||||||
@@ -112,14 +111,14 @@ func nextTokenOrQuoted(s string) (value string, rest string) {
|
|||||||
case escape:
|
case escape:
|
||||||
escape = false
|
escape = false
|
||||||
p[j] = b
|
p[j] = b
|
||||||
j++
|
j += 1
|
||||||
case b == '\\':
|
case b == '\\':
|
||||||
escape = true
|
escape = true
|
||||||
case b == '"':
|
case b == '"':
|
||||||
return string(p[:j]), s[i+1:]
|
return string(p[:j]), s[i+1:]
|
||||||
default:
|
default:
|
||||||
p[j] = b
|
p[j] = b
|
||||||
j++
|
j += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", ""
|
return "", ""
|
||||||
@@ -128,31 +127,8 @@ func nextTokenOrQuoted(s string) (value string, rest string) {
|
|||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// equalASCIIFold returns true if s is equal to t with ASCII case folding.
|
|
||||||
func equalASCIIFold(s, t string) bool {
|
|
||||||
for s != "" && t != "" {
|
|
||||||
sr, size := utf8.DecodeRuneInString(s)
|
|
||||||
s = s[size:]
|
|
||||||
tr, size := utf8.DecodeRuneInString(t)
|
|
||||||
t = t[size:]
|
|
||||||
if sr == tr {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if 'A' <= sr && sr <= 'Z' {
|
|
||||||
sr = sr + 'a' - 'A'
|
|
||||||
}
|
|
||||||
if 'A' <= tr && tr <= 'Z' {
|
|
||||||
tr = tr + 'a' - 'A'
|
|
||||||
}
|
|
||||||
if sr != tr {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s == t
|
|
||||||
}
|
|
||||||
|
|
||||||
// tokenListContainsValue returns true if the 1#token header with the given
|
// tokenListContainsValue returns true if the 1#token header with the given
|
||||||
// name contains a token equal to value with ASCII case folding.
|
// name contains token.
|
||||||
func tokenListContainsValue(header http.Header, name string, value string) bool {
|
func tokenListContainsValue(header http.Header, name string, value string) bool {
|
||||||
headers:
|
headers:
|
||||||
for _, s := range header[name] {
|
for _, s := range header[name] {
|
||||||
@@ -166,7 +142,7 @@ headers:
|
|||||||
if s != "" && s[0] != ',' {
|
if s != "" && s[0] != ',' {
|
||||||
continue headers
|
continue headers
|
||||||
}
|
}
|
||||||
if equalASCIIFold(t, value) {
|
if strings.EqualFold(t, value) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if s == "" {
|
if s == "" {
|
||||||
@@ -180,6 +156,7 @@ headers:
|
|||||||
|
|
||||||
// parseExtensiosn parses WebSocket extensions from a header.
|
// parseExtensiosn parses WebSocket extensions from a header.
|
||||||
func parseExtensions(header http.Header) []map[string]string {
|
func parseExtensions(header http.Header) []map[string]string {
|
||||||
|
|
||||||
// From RFC 6455:
|
// From RFC 6455:
|
||||||
//
|
//
|
||||||
// Sec-WebSocket-Extensions = extension-list
|
// Sec-WebSocket-Extensions = extension-list
|
||||||
|
|||||||
49
vendor/github.com/gorilla/websocket/util_test.go
generated
vendored
49
vendor/github.com/gorilla/websocket/util_test.go
generated
vendored
@@ -10,24 +10,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var equalASCIIFoldTests = []struct {
|
|
||||||
t, s string
|
|
||||||
eq bool
|
|
||||||
}{
|
|
||||||
{"WebSocket", "websocket", true},
|
|
||||||
{"websocket", "WebSocket", true},
|
|
||||||
{"Öyster", "öyster", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEqualASCIIFold(t *testing.T) {
|
|
||||||
for _, tt := range equalASCIIFoldTests {
|
|
||||||
eq := equalASCIIFold(tt.s, tt.t)
|
|
||||||
if eq != tt.eq {
|
|
||||||
t.Errorf("equalASCIIFold(%q, %q) = %v, want %v", tt.s, tt.t, eq, tt.eq)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenListContainsValueTests = []struct {
|
var tokenListContainsValueTests = []struct {
|
||||||
value string
|
value string
|
||||||
ok bool
|
ok bool
|
||||||
@@ -56,32 +38,29 @@ var parseExtensionTests = []struct {
|
|||||||
value string
|
value string
|
||||||
extensions []map[string]string
|
extensions []map[string]string
|
||||||
}{
|
}{
|
||||||
{`foo`, []map[string]string{{"": "foo"}}},
|
{`foo`, []map[string]string{map[string]string{"": "foo"}}},
|
||||||
{`foo, bar; baz=2`, []map[string]string{
|
{`foo, bar; baz=2`, []map[string]string{
|
||||||
{"": "foo"},
|
map[string]string{"": "foo"},
|
||||||
{"": "bar", "baz": "2"}}},
|
map[string]string{"": "bar", "baz": "2"}}},
|
||||||
{`foo; bar="b,a;z"`, []map[string]string{
|
{`foo; bar="b,a;z"`, []map[string]string{
|
||||||
{"": "foo", "bar": "b,a;z"}}},
|
map[string]string{"": "foo", "bar": "b,a;z"}}},
|
||||||
{`foo , bar; baz = 2`, []map[string]string{
|
{`foo , bar; baz = 2`, []map[string]string{
|
||||||
{"": "foo"},
|
map[string]string{"": "foo"},
|
||||||
{"": "bar", "baz": "2"}}},
|
map[string]string{"": "bar", "baz": "2"}}},
|
||||||
{`foo, bar; baz=2 junk`, []map[string]string{
|
{`foo, bar; baz=2 junk`, []map[string]string{
|
||||||
{"": "foo"}}},
|
map[string]string{"": "foo"}}},
|
||||||
{`foo junk, bar; baz=2 junk`, nil},
|
{`foo junk, bar; baz=2 junk`, nil},
|
||||||
{`mux; max-channels=4; flow-control, deflate-stream`, []map[string]string{
|
{`mux; max-channels=4; flow-control, deflate-stream`, []map[string]string{
|
||||||
{"": "mux", "max-channels": "4", "flow-control": ""},
|
map[string]string{"": "mux", "max-channels": "4", "flow-control": ""},
|
||||||
{"": "deflate-stream"}}},
|
map[string]string{"": "deflate-stream"}}},
|
||||||
{`permessage-foo; x="10"`, []map[string]string{
|
{`permessage-foo; x="10"`, []map[string]string{
|
||||||
{"": "permessage-foo", "x": "10"}}},
|
map[string]string{"": "permessage-foo", "x": "10"}}},
|
||||||
{`permessage-foo; use_y, permessage-foo`, []map[string]string{
|
{`permessage-foo; use_y, permessage-foo`, []map[string]string{
|
||||||
{"": "permessage-foo", "use_y": ""},
|
map[string]string{"": "permessage-foo", "use_y": ""},
|
||||||
{"": "permessage-foo"}}},
|
map[string]string{"": "permessage-foo"}}},
|
||||||
{`permessage-deflate; client_max_window_bits; server_max_window_bits=10 , permessage-deflate; client_max_window_bits`, []map[string]string{
|
{`permessage-deflate; client_max_window_bits; server_max_window_bits=10 , permessage-deflate; client_max_window_bits`, []map[string]string{
|
||||||
{"": "permessage-deflate", "client_max_window_bits": "", "server_max_window_bits": "10"},
|
map[string]string{"": "permessage-deflate", "client_max_window_bits": "", "server_max_window_bits": "10"},
|
||||||
{"": "permessage-deflate", "client_max_window_bits": ""}}},
|
map[string]string{"": "permessage-deflate", "client_max_window_bits": ""}}},
|
||||||
{"permessage-deflate; server_no_context_takeover; client_max_window_bits=15", []map[string]string{
|
|
||||||
{"": "permessage-deflate", "server_no_context_takeover": "", "client_max_window_bits": "15"},
|
|
||||||
}},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseExtensions(t *testing.T) {
|
func TestParseExtensions(t *testing.T) {
|
||||||
|
|||||||
473
vendor/github.com/gorilla/websocket/x_net_proxy.go
generated
vendored
473
vendor/github.com/gorilla/websocket/x_net_proxy.go
generated
vendored
@@ -1,473 +0,0 @@
|
|||||||
// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
|
|
||||||
//go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy
|
|
||||||
|
|
||||||
// Package proxy provides support for a variety of protocols to proxy network
|
|
||||||
// data.
|
|
||||||
//
|
|
||||||
|
|
||||||
package websocket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type proxy_direct struct{}
|
|
||||||
|
|
||||||
// Direct is a direct proxy: one that makes network connections directly.
|
|
||||||
var proxy_Direct = proxy_direct{}
|
|
||||||
|
|
||||||
func (proxy_direct) Dial(network, addr string) (net.Conn, error) {
|
|
||||||
return net.Dial(network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A PerHost directs connections to a default Dialer unless the host name
|
|
||||||
// requested matches one of a number of exceptions.
|
|
||||||
type proxy_PerHost struct {
|
|
||||||
def, bypass proxy_Dialer
|
|
||||||
|
|
||||||
bypassNetworks []*net.IPNet
|
|
||||||
bypassIPs []net.IP
|
|
||||||
bypassZones []string
|
|
||||||
bypassHosts []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPerHost returns a PerHost Dialer that directs connections to either
|
|
||||||
// defaultDialer or bypass, depending on whether the connection matches one of
|
|
||||||
// the configured rules.
|
|
||||||
func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost {
|
|
||||||
return &proxy_PerHost{
|
|
||||||
def: defaultDialer,
|
|
||||||
bypass: bypass,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial connects to the address addr on the given network through either
|
|
||||||
// defaultDialer or bypass.
|
|
||||||
func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) {
|
|
||||||
host, _, err := net.SplitHostPort(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.dialerForRequest(host).Dial(network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer {
|
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
|
||||||
for _, net := range p.bypassNetworks {
|
|
||||||
if net.Contains(ip) {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, bypassIP := range p.bypassIPs {
|
|
||||||
if bypassIP.Equal(ip) {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p.def
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, zone := range p.bypassZones {
|
|
||||||
if strings.HasSuffix(host, zone) {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
if host == zone[1:] {
|
|
||||||
// For a zone ".example.com", we match "example.com"
|
|
||||||
// too.
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, bypassHost := range p.bypassHosts {
|
|
||||||
if bypassHost == host {
|
|
||||||
return p.bypass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p.def
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFromString parses a string that contains comma-separated values
|
|
||||||
// specifying hosts that should use the bypass proxy. Each value is either an
|
|
||||||
// IP address, a CIDR range, a zone (*.example.com) or a host name
|
|
||||||
// (localhost). A best effort is made to parse the string and errors are
|
|
||||||
// ignored.
|
|
||||||
func (p *proxy_PerHost) AddFromString(s string) {
|
|
||||||
hosts := strings.Split(s, ",")
|
|
||||||
for _, host := range hosts {
|
|
||||||
host = strings.TrimSpace(host)
|
|
||||||
if len(host) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.Contains(host, "/") {
|
|
||||||
// We assume that it's a CIDR address like 127.0.0.0/8
|
|
||||||
if _, net, err := net.ParseCIDR(host); err == nil {
|
|
||||||
p.AddNetwork(net)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
|
||||||
p.AddIP(ip)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(host, "*.") {
|
|
||||||
p.AddZone(host[1:])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
p.AddHost(host)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddIP specifies an IP address that will use the bypass proxy. Note that
|
|
||||||
// this will only take effect if a literal IP address is dialed. A connection
|
|
||||||
// to a named host will never match an IP.
|
|
||||||
func (p *proxy_PerHost) AddIP(ip net.IP) {
|
|
||||||
p.bypassIPs = append(p.bypassIPs, ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddNetwork specifies an IP range that will use the bypass proxy. Note that
|
|
||||||
// this will only take effect if a literal IP address is dialed. A connection
|
|
||||||
// to a named host will never match.
|
|
||||||
func (p *proxy_PerHost) AddNetwork(net *net.IPNet) {
|
|
||||||
p.bypassNetworks = append(p.bypassNetworks, net)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
|
|
||||||
// "example.com" matches "example.com" and all of its subdomains.
|
|
||||||
func (p *proxy_PerHost) AddZone(zone string) {
|
|
||||||
if strings.HasSuffix(zone, ".") {
|
|
||||||
zone = zone[:len(zone)-1]
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(zone, ".") {
|
|
||||||
zone = "." + zone
|
|
||||||
}
|
|
||||||
p.bypassZones = append(p.bypassZones, zone)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHost specifies a host name that will use the bypass proxy.
|
|
||||||
func (p *proxy_PerHost) AddHost(host string) {
|
|
||||||
if strings.HasSuffix(host, ".") {
|
|
||||||
host = host[:len(host)-1]
|
|
||||||
}
|
|
||||||
p.bypassHosts = append(p.bypassHosts, host)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Dialer is a means to establish a connection.
|
|
||||||
type proxy_Dialer interface {
|
|
||||||
// Dial connects to the given address via the proxy.
|
|
||||||
Dial(network, addr string) (c net.Conn, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auth contains authentication parameters that specific Dialers may require.
|
|
||||||
type proxy_Auth struct {
|
|
||||||
User, Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromEnvironment returns the dialer specified by the proxy related variables in
|
|
||||||
// the environment.
|
|
||||||
func proxy_FromEnvironment() proxy_Dialer {
|
|
||||||
allProxy := proxy_allProxyEnv.Get()
|
|
||||||
if len(allProxy) == 0 {
|
|
||||||
return proxy_Direct
|
|
||||||
}
|
|
||||||
|
|
||||||
proxyURL, err := url.Parse(allProxy)
|
|
||||||
if err != nil {
|
|
||||||
return proxy_Direct
|
|
||||||
}
|
|
||||||
proxy, err := proxy_FromURL(proxyURL, proxy_Direct)
|
|
||||||
if err != nil {
|
|
||||||
return proxy_Direct
|
|
||||||
}
|
|
||||||
|
|
||||||
noProxy := proxy_noProxyEnv.Get()
|
|
||||||
if len(noProxy) == 0 {
|
|
||||||
return proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
perHost := proxy_NewPerHost(proxy, proxy_Direct)
|
|
||||||
perHost.AddFromString(noProxy)
|
|
||||||
return perHost
|
|
||||||
}
|
|
||||||
|
|
||||||
// proxySchemes is a map from URL schemes to a function that creates a Dialer
|
|
||||||
// from a URL with such a scheme.
|
|
||||||
var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)
|
|
||||||
|
|
||||||
// RegisterDialerType takes a URL scheme and a function to generate Dialers from
|
|
||||||
// a URL with that scheme and a forwarding Dialer. Registered schemes are used
|
|
||||||
// by FromURL.
|
|
||||||
func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) {
|
|
||||||
if proxy_proxySchemes == nil {
|
|
||||||
proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error))
|
|
||||||
}
|
|
||||||
proxy_proxySchemes[scheme] = f
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromURL returns a Dialer given a URL specification and an underlying
|
|
||||||
// Dialer for it to make network requests.
|
|
||||||
func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) {
|
|
||||||
var auth *proxy_Auth
|
|
||||||
if u.User != nil {
|
|
||||||
auth = new(proxy_Auth)
|
|
||||||
auth.User = u.User.Username()
|
|
||||||
if p, ok := u.User.Password(); ok {
|
|
||||||
auth.Password = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch u.Scheme {
|
|
||||||
case "socks5":
|
|
||||||
return proxy_SOCKS5("tcp", u.Host, auth, forward)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the scheme doesn't match any of the built-in schemes, see if it
|
|
||||||
// was registered by another package.
|
|
||||||
if proxy_proxySchemes != nil {
|
|
||||||
if f, ok := proxy_proxySchemes[u.Scheme]; ok {
|
|
||||||
return f(u, forward)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
proxy_allProxyEnv = &proxy_envOnce{
|
|
||||||
names: []string{"ALL_PROXY", "all_proxy"},
|
|
||||||
}
|
|
||||||
proxy_noProxyEnv = &proxy_envOnce{
|
|
||||||
names: []string{"NO_PROXY", "no_proxy"},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// envOnce looks up an environment variable (optionally by multiple
|
|
||||||
// names) once. It mitigates expensive lookups on some platforms
|
|
||||||
// (e.g. Windows).
|
|
||||||
// (Borrowed from net/http/transport.go)
|
|
||||||
type proxy_envOnce struct {
|
|
||||||
names []string
|
|
||||||
once sync.Once
|
|
||||||
val string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *proxy_envOnce) Get() string {
|
|
||||||
e.once.Do(e.init)
|
|
||||||
return e.val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *proxy_envOnce) init() {
|
|
||||||
for _, n := range e.names {
|
|
||||||
e.val = os.Getenv(n)
|
|
||||||
if e.val != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
|
|
||||||
// with an optional username and password. See RFC 1928 and RFC 1929.
|
|
||||||
func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) {
|
|
||||||
s := &proxy_socks5{
|
|
||||||
network: network,
|
|
||||||
addr: addr,
|
|
||||||
forward: forward,
|
|
||||||
}
|
|
||||||
if auth != nil {
|
|
||||||
s.user = auth.User
|
|
||||||
s.password = auth.Password
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type proxy_socks5 struct {
|
|
||||||
user, password string
|
|
||||||
network, addr string
|
|
||||||
forward proxy_Dialer
|
|
||||||
}
|
|
||||||
|
|
||||||
const proxy_socks5Version = 5
|
|
||||||
|
|
||||||
const (
|
|
||||||
proxy_socks5AuthNone = 0
|
|
||||||
proxy_socks5AuthPassword = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
const proxy_socks5Connect = 1
|
|
||||||
|
|
||||||
const (
|
|
||||||
proxy_socks5IP4 = 1
|
|
||||||
proxy_socks5Domain = 3
|
|
||||||
proxy_socks5IP6 = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
var proxy_socks5Errors = []string{
|
|
||||||
"",
|
|
||||||
"general failure",
|
|
||||||
"connection forbidden",
|
|
||||||
"network unreachable",
|
|
||||||
"host unreachable",
|
|
||||||
"connection refused",
|
|
||||||
"TTL expired",
|
|
||||||
"command not supported",
|
|
||||||
"address type not supported",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dial connects to the address addr on the given network via the SOCKS5 proxy.
|
|
||||||
func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) {
|
|
||||||
switch network {
|
|
||||||
case "tcp", "tcp6", "tcp4":
|
|
||||||
default:
|
|
||||||
return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := s.forward.Dial(s.network, s.addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := s.connect(conn, addr); err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect takes an existing connection to a socks5 proxy server,
|
|
||||||
// and commands the server to extend that connection to target,
|
|
||||||
// which must be a canonical address with a host and port.
|
|
||||||
func (s *proxy_socks5) connect(conn net.Conn, target string) error {
|
|
||||||
host, portStr, err := net.SplitHostPort(target)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
port, err := strconv.Atoi(portStr)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("proxy: failed to parse port number: " + portStr)
|
|
||||||
}
|
|
||||||
if port < 1 || port > 0xffff {
|
|
||||||
return errors.New("proxy: port number out of range: " + portStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the size here is just an estimate
|
|
||||||
buf := make([]byte, 0, 6+len(host))
|
|
||||||
|
|
||||||
buf = append(buf, proxy_socks5Version)
|
|
||||||
if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
|
|
||||||
buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword)
|
|
||||||
} else {
|
|
||||||
buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := conn.Write(buf); err != nil {
|
|
||||||
return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
|
||||||
return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
if buf[0] != 5 {
|
|
||||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
|
|
||||||
}
|
|
||||||
if buf[1] == 0xff {
|
|
||||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
|
|
||||||
}
|
|
||||||
|
|
||||||
// See RFC 1929
|
|
||||||
if buf[1] == proxy_socks5AuthPassword {
|
|
||||||
buf = buf[:0]
|
|
||||||
buf = append(buf, 1 /* password protocol version */)
|
|
||||||
buf = append(buf, uint8(len(s.user)))
|
|
||||||
buf = append(buf, s.user...)
|
|
||||||
buf = append(buf, uint8(len(s.password)))
|
|
||||||
buf = append(buf, s.password...)
|
|
||||||
|
|
||||||
if _, err := conn.Write(buf); err != nil {
|
|
||||||
return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
|
||||||
return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if buf[1] != 0 {
|
|
||||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = buf[:0]
|
|
||||||
buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */)
|
|
||||||
|
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
|
||||||
buf = append(buf, proxy_socks5IP4)
|
|
||||||
ip = ip4
|
|
||||||
} else {
|
|
||||||
buf = append(buf, proxy_socks5IP6)
|
|
||||||
}
|
|
||||||
buf = append(buf, ip...)
|
|
||||||
} else {
|
|
||||||
if len(host) > 255 {
|
|
||||||
return errors.New("proxy: destination host name too long: " + host)
|
|
||||||
}
|
|
||||||
buf = append(buf, proxy_socks5Domain)
|
|
||||||
buf = append(buf, byte(len(host)))
|
|
||||||
buf = append(buf, host...)
|
|
||||||
}
|
|
||||||
buf = append(buf, byte(port>>8), byte(port))
|
|
||||||
|
|
||||||
if _, err := conn.Write(buf); err != nil {
|
|
||||||
return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(conn, buf[:4]); err != nil {
|
|
||||||
return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
failure := "unknown error"
|
|
||||||
if int(buf[1]) < len(proxy_socks5Errors) {
|
|
||||||
failure = proxy_socks5Errors[buf[1]]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(failure) > 0 {
|
|
||||||
return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesToDiscard := 0
|
|
||||||
switch buf[3] {
|
|
||||||
case proxy_socks5IP4:
|
|
||||||
bytesToDiscard = net.IPv4len
|
|
||||||
case proxy_socks5IP6:
|
|
||||||
bytesToDiscard = net.IPv6len
|
|
||||||
case proxy_socks5Domain:
|
|
||||||
_, err := io.ReadFull(conn, buf[:1])
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
bytesToDiscard = int(buf[0])
|
|
||||||
default:
|
|
||||||
return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cap(buf) < bytesToDiscard {
|
|
||||||
buf = make([]byte, bytesToDiscard)
|
|
||||||
} else {
|
|
||||||
buf = buf[:bytesToDiscard]
|
|
||||||
}
|
|
||||||
if _, err := io.ReadFull(conn, buf); err != nil {
|
|
||||||
return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also need to discard the port number
|
|
||||||
if _, err := io.ReadFull(conn, buf[:2]); err != nil {
|
|
||||||
return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
13
vendor/github.com/inconshreveable/mousetrap/LICENSE
generated
vendored
Normal file
13
vendor/github.com/inconshreveable/mousetrap/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2014 Alan Shreve
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
23
vendor/github.com/inconshreveable/mousetrap/README.md
generated
vendored
Normal file
23
vendor/github.com/inconshreveable/mousetrap/README.md
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# mousetrap
|
||||||
|
|
||||||
|
mousetrap is a tiny library that answers a single question.
|
||||||
|
|
||||||
|
On a Windows machine, was the process invoked by someone double clicking on
|
||||||
|
the executable file while browsing in explorer?
|
||||||
|
|
||||||
|
### Motivation
|
||||||
|
|
||||||
|
Windows developers unfamiliar with command line tools will often "double-click"
|
||||||
|
the executable for a tool. Because most CLI tools print the help and then exit
|
||||||
|
when invoked without arguments, this is often very frustrating for those users.
|
||||||
|
|
||||||
|
mousetrap provides a way to detect these invocations so that you can provide
|
||||||
|
more helpful behavior and instructions on how to run the CLI tool. To see what
|
||||||
|
this looks like, both from an organizational and a technical perspective, see
|
||||||
|
https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/
|
||||||
|
|
||||||
|
### The interface
|
||||||
|
|
||||||
|
The library exposes a single interface:
|
||||||
|
|
||||||
|
func StartedByExplorer() (bool)
|
||||||
15
vendor/github.com/inconshreveable/mousetrap/trap_others.go
generated
vendored
Normal file
15
vendor/github.com/inconshreveable/mousetrap/trap_others.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package mousetrap
|
||||||
|
|
||||||
|
// StartedByExplorer returns true if the program was invoked by the user
|
||||||
|
// double-clicking on the executable from explorer.exe
|
||||||
|
//
|
||||||
|
// It is conservative and returns false if any of the internal calls fail.
|
||||||
|
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||||
|
// whether it was launched from explorer.exe
|
||||||
|
//
|
||||||
|
// On non-Windows platforms, it always returns false.
|
||||||
|
func StartedByExplorer() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
98
vendor/github.com/inconshreveable/mousetrap/trap_windows.go
generated
vendored
Normal file
98
vendor/github.com/inconshreveable/mousetrap/trap_windows.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// +build windows
|
||||||
|
// +build !go1.4
|
||||||
|
|
||||||
|
package mousetrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// defined by the Win32 API
|
||||||
|
th32cs_snapprocess uintptr = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||||
|
CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot")
|
||||||
|
Process32First = kernel.MustFindProc("Process32FirstW")
|
||||||
|
Process32Next = kernel.MustFindProc("Process32NextW")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessEntry32 structure defined by the Win32 API
|
||||||
|
type processEntry32 struct {
|
||||||
|
dwSize uint32
|
||||||
|
cntUsage uint32
|
||||||
|
th32ProcessID uint32
|
||||||
|
th32DefaultHeapID int
|
||||||
|
th32ModuleID uint32
|
||||||
|
cntThreads uint32
|
||||||
|
th32ParentProcessID uint32
|
||||||
|
pcPriClassBase int32
|
||||||
|
dwFlags uint32
|
||||||
|
szExeFile [syscall.MAX_PATH]uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProcessEntry(pid int) (pe *processEntry32, err error) {
|
||||||
|
snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0))
|
||||||
|
if snapshot == uintptr(syscall.InvalidHandle) {
|
||||||
|
err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer syscall.CloseHandle(syscall.Handle(snapshot))
|
||||||
|
|
||||||
|
var processEntry processEntry32
|
||||||
|
processEntry.dwSize = uint32(unsafe.Sizeof(processEntry))
|
||||||
|
ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
||||||
|
if ok == 0 {
|
||||||
|
err = fmt.Errorf("Process32First: %v", e1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if processEntry.th32ProcessID == uint32(pid) {
|
||||||
|
pe = &processEntry
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
||||||
|
if ok == 0 {
|
||||||
|
err = fmt.Errorf("Process32Next: %v", e1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getppid() (pid int, err error) {
|
||||||
|
pe, err := getProcessEntry(os.Getpid())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = int(pe.th32ParentProcessID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
||||||
|
// on the executable from explorer.exe
|
||||||
|
//
|
||||||
|
// It is conservative and returns false if any of the internal calls fail.
|
||||||
|
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||||
|
// whether it was launched from explorer.exe
|
||||||
|
func StartedByExplorer() bool {
|
||||||
|
ppid, err := getppid()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
pe, err := getProcessEntry(ppid)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
name := syscall.UTF16ToString(pe.szExeFile[:])
|
||||||
|
return name == "explorer.exe"
|
||||||
|
}
|
||||||
46
vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
generated
vendored
Normal file
46
vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// +build windows
|
||||||
|
// +build go1.4
|
||||||
|
|
||||||
|
package mousetrap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
|
||||||
|
snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer syscall.CloseHandle(snapshot)
|
||||||
|
var procEntry syscall.ProcessEntry32
|
||||||
|
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
|
||||||
|
if err = syscall.Process32First(snapshot, &procEntry); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if procEntry.ProcessID == uint32(pid) {
|
||||||
|
return &procEntry, nil
|
||||||
|
}
|
||||||
|
err = syscall.Process32Next(snapshot, &procEntry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
||||||
|
// on the executable from explorer.exe
|
||||||
|
//
|
||||||
|
// It is conservative and returns false if any of the internal calls fail.
|
||||||
|
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||||
|
// whether it was launched from explorer.exe
|
||||||
|
func StartedByExplorer() bool {
|
||||||
|
pe, err := getProcessEntry(os.Getppid())
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:])
|
||||||
|
}
|
||||||
38
vendor/github.com/spf13/cobra/.circleci/config.yml
generated
vendored
Normal file
38
vendor/github.com/spf13/cobra/.circleci/config.yml
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
main:
|
||||||
|
jobs:
|
||||||
|
- go-current
|
||||||
|
- go-previous
|
||||||
|
- go-latest
|
||||||
|
base: &base
|
||||||
|
working_directory: /go/src/github.com/spf13/cobra
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: "All Commands"
|
||||||
|
command: |
|
||||||
|
mkdir -p bin
|
||||||
|
curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck
|
||||||
|
chmod +x bin/shellcheck
|
||||||
|
go get -t -v ./...
|
||||||
|
PATH=$PATH:$PWD/bin go test -v ./...
|
||||||
|
go build
|
||||||
|
diff -u <(echo -n) <(gofmt -d -s .)
|
||||||
|
if [ -z $NOVET ]; then
|
||||||
|
diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint');
|
||||||
|
fi
|
||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
go-current:
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.10.0
|
||||||
|
<<: *base
|
||||||
|
go-previous:
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:1.9.4
|
||||||
|
<<: *base
|
||||||
|
go-latest:
|
||||||
|
docker:
|
||||||
|
- image: circleci/golang:latest
|
||||||
|
<<: *base
|
||||||
15
vendor/github.com/docopt/docopt-go/.gitignore → vendor/github.com/spf13/cobra/.gitignore
generated
vendored
15
vendor/github.com/docopt/docopt-go/.gitignore → vendor/github.com/spf13/cobra/.gitignore
generated
vendored
@@ -19,7 +19,18 @@ _cgo_export.*
|
|||||||
|
|
||||||
_testmain.go
|
_testmain.go
|
||||||
|
|
||||||
|
# Vim files https://github.com/github/gitignore/blob/master/Global/Vim.gitignore
|
||||||
|
# swap
|
||||||
|
[._]*.s[a-w][a-z]
|
||||||
|
[._]s[a-w][a-z]
|
||||||
|
# session
|
||||||
|
Session.vim
|
||||||
|
# temporary
|
||||||
|
.netrwhist
|
||||||
|
*~
|
||||||
|
# auto-generated tag files
|
||||||
|
tags
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
# coverage droppings
|
cobra.test
|
||||||
profile.cov
|
|
||||||
3
vendor/github.com/spf13/cobra/.mailmap
generated
vendored
Normal file
3
vendor/github.com/spf13/cobra/.mailmap
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Steve Francia <steve.francia@gmail.com>
|
||||||
|
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
||||||
|
Fabiano Franz <ffranz@redhat.com> <contact@fabianofranz.com>
|
||||||
21
vendor/github.com/spf13/cobra/.travis.yml
generated
vendored
Normal file
21
vendor/github.com/spf13/cobra/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- go: 1.9.4
|
||||||
|
- go: 1.10.0
|
||||||
|
- go: tip
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- mkdir -p bin
|
||||||
|
- curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.3/shellcheck
|
||||||
|
- chmod +x bin/shellcheck
|
||||||
|
script:
|
||||||
|
- PATH=$PATH:$PWD/bin go test -v ./...
|
||||||
|
- go build
|
||||||
|
- diff -u <(echo -n) <(gofmt -d -s .)
|
||||||
|
- if [ -z $NOVET ]; then
|
||||||
|
diff -u <(echo -n) <(go tool vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint');
|
||||||
|
fi
|
||||||
174
vendor/github.com/spf13/cobra/LICENSE.txt
generated
vendored
Normal file
174
vendor/github.com/spf13/cobra/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user