Fix conflicts

Conflicts:
	README_zh.md
	src/utils/version/version.go
This commit is contained in:
fatedier 2016-08-24 13:49:13 +08:00
commit b65e037b5e
21 changed files with 259 additions and 36 deletions

5
.dockerignore Normal file
View File

@ -0,0 +1,5 @@
Dockerfile
.git
*~
*#
.#*

View File

@ -4,7 +4,7 @@ language: go
go:
- 1.5.4
- 1.6.3
- 1.7rc6
- 1.7
install:
- make

17
Dockerfile Normal file
View File

@ -0,0 +1,17 @@
FROM golang:1.6
COPY . /go/src/github.com/fatedier/frp
RUN cd /go/src/github.com/fatedier/frp \
&& make \
&& mv bin/frpc /frpc \
&& mv bin/frps /frps \
&& mv conf/frpc_min.ini /frpc.ini \
&& mv conf/frps_min.ini /frps.ini \
&& make clean
WORKDIR /
EXPOSE 80 443 6000 7000 7500
ENTRYPOINT ["/frps"]

12
Dockerfile_alpine Normal file
View File

@ -0,0 +1,12 @@
FROM alpine:3.4
COPY bin/frpc /frpc
COPY bin/frps /frps
COPY conf/frpc_min.ini /frpc.ini
COPY conf/frps_min.ini /frps.ini
WORKDIR /
EXPOSE 80 443 6000 7000 7500
ENTRYPOINT ["/frps"]

View File

@ -3,10 +3,16 @@ export GO15VENDOREXPERIMENT := 1
all: build
build: gox app
build: gox app more
gox:
go get github.com/mitchellh/gox
app:
gox -osarch "darwin/386 darwin/amd64 linux/386 linux/amd64 linux/arm windows/386 windows/amd64" ./src/...
more:
env GOOS=linux GOARCH=mips64 go build -o ./frpc_linux_mips64 ./src/cmd/frpc
env GOOS=linux GOARCH=mips64 go build -o ./frps_linux_mips64 ./src/cmd/frps
env GOOS=linux GOARCH=mips64le go build -o ./frpc_linux_mips64le ./src/cmd/frpc
env GOOS=linux GOARCH=mips64le go build -o ./frps_linux_mips64le ./src/cmd/frps

View File

@ -150,9 +150,12 @@ Configure a port for dashboard to enable this feature:
```ini
[common]
dashboard_port = 7500
# dashboard's username and password are both optionalif not set, default is admin.
dashboard_username = abc
dashboard_password = abc
```
Then visit `http://[server_addr]:7500` to see dashboard.
Then visit `http://[server_addr]:7500` to see dashboard, default username and password are both `admin`.
![dashboard](/doc/pic/dashboard.png)
@ -327,7 +330,9 @@ If `host_header_rewrite` is specified, the Host header will be rewritten to matc
Interested in getting involved? We would like to help you!
* Take a look at our [issues list](https://github.com/fatedier/frp/issues) and consider submitting a patch
* Take a look at our [issues list](https://github.com/fatedier/frp/issues) and consider sending a Pull Request to **dev branch**.
* If you want to add a new feature, please create an issue first to describe the new feature, as well as the implementation approach. Once a proposal is accepted, create an implementation of the new features and submit it as a pull request.
* Sorry for my poor english and improvement for this document is welcome even some typo fix.
* If you have some wanderful ideas, send email to fatedier@gmail.com.
**Note: We prefer you to give your advise in [issues](https://github.com/fatedier/frp/issues), so others with a same question can search it quickly and we don't need to answer them repeatly.**
@ -348,5 +353,8 @@ Donate money by [paypal](https://www.paypal.me/fatedier) to my account **fatedie
* [fatedier](https://github.com/fatedier)
* [Hurricanezwf](https://github.com/Hurricanezwf)
* [vashstorm](https://github.com/vashstorm)
* [maodanp](https://github.com/maodanp)
* [Pan Hao](https://github.com/vashstorm)
* [Danping Mao](https://github.com/maodanp)
* [Eric Larssen](https://github.com/ericlarssen)
* [Damon Zhao](https://github.com/se77en)
* [Manfred Touron](https://github.com/moul)

View File

@ -24,7 +24,7 @@ frp 是一个高性能的反向代理应用,可以帮助您轻松地进行内
* [连接池](#连接池)
* [修改 Host Header](#修改-host-header)
* [开发计划](#开发计划)
* [贡献代码](#贡献代码)
* [为 frp 做贡献](#为-frp-做贡献)
* [捐助](#捐助)
* [贡献者](#贡献者)
@ -147,9 +147,12 @@ frp 目前正在前期开发阶段master 分支用于发布稳定版本dev
```ini
[common]
dashboard_port = 7500
# dashboard 用户名密码可选,默认都为 admin
dashboard_username = abc
dashboard_password = abc
```
打开浏览器通过 `http://[server_addr]:7500` 访问 dashboard 界面。
打开浏览器通过 `http://[server_addr]:7500` 访问 dashboard 界面,用户名密码默认为 `admin`
![dashboard](/doc/pic/dashboard.png)
@ -330,12 +333,16 @@ host_header_rewrite = dev.yourdomain.com
* frpc 完全控制模式,通过 dashboard 对 frpc 进行在线操作。
* 支持 udp 打洞的方式,提供两边内网机器直接通信,流量不经过服务器转发。
## 贡献代码
## 为 frp 做贡献
如果您对这个项目感兴趣,我们非常欢迎您参与其中!
frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进步贡献力量。
* 如果您需要提交问题,可以通过 [issues](https://github.com/fatedier/frp/issues) 来完成。
* 如果您有新的功能需求,可以反馈至 fatedier@gmail.com 共同讨论。
* 在使用过程中出现任何问题,可以通过 [issues](https://github.com/fatedier/frp/issues) 来反馈。
* Bug 的修复可以直接提交 Pull Request 到 dev 分支。
* 如果是增加新的功能特性,请先创建一个 issue 并做简单描述以及大致的实现方法,提议被采纳后,就可以创建一个实现新特性的 Pull Request。
* 欢迎对说明文档做出改善,帮助更多的人使用 frp特别是英文文档。
* 贡献代码请提交 PR 至 dev 分支master 分支仅用于发布稳定可用版本。
* 如果你有任何其他方面的问题,欢迎反馈至 fatedier@gmail.com 共同交流。
**提醒:和项目相关的问题最好在 [issues](https://github.com/fatedier/frp/issues) 中反馈,这样方便其他有类似问题的人可以快速查找解决方法,并且也避免了我们重复回答一些问题。**
@ -355,5 +362,8 @@ host_header_rewrite = dev.yourdomain.com
* [fatedier](https://github.com/fatedier)
* [Hurricanezwf](https://github.com/Hurricanezwf)
* [vashstorm](https://github.com/vashstorm)
* [maodanp](https://github.com/maodanp)
* [Pan Hao](https://github.com/vashstorm)
* [Danping Mao](https://github.com/maodanp)
* [Eric Larssen](https://github.com/ericlarssen)
* [Damon Zhao](https://github.com/se77en)
* [Manfred Touron](https://github.com/moul)

View File

@ -4,6 +4,8 @@
# in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
server_addr = 0.0.0.0
server_port = 7000
# if you want to connect frps by http proxy, you can set http_proxy here or in global environment variables
# http_proxy = http://user:pwd@192.168.1.128:8080
# console or real logFile path like ./frpc.log
log_file = ./frpc.log
# debug, info, warn, error

10
conf/frpc_min.ini Normal file
View File

@ -0,0 +1,10 @@
[common]
server_addr = 0.0.0.0
server_port = 7000
auth_token = 123
privilege_token = 12345678
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22

View File

@ -9,6 +9,9 @@ vhost_http_port = 80
vhost_https_port = 443
# if you want to configure or reload frps by dashboard, dashboard_port must be set
dashboard_port = 7500
# dashboard username and password for basic protect, if not set, both default value is admin
dashboard_username = abc
dashboard_password = abc
# dashboard assets directory(only for debug mode)
# assets_dir = ./static
# console or real logFile path like ./frps.log

14
conf/frps_min.ini Normal file
View File

@ -0,0 +1,14 @@
[common]
bind_addr = 0.0.0.0
bind_port = 7000
vhost_http_port = 80
vhost_https_port = 443
dashboard_port = 7500
privilege_mode = true
privilege_token = 12345678
[ssh]
type = tcp
auth_token = 123
bind_addr = 0.0.0.0
listen_port = 6000

View File

@ -15,7 +15,7 @@ rm -rf ./packages
mkdir ./packages
os_all='linux windows darwin'
arch_all='386 amd64 arm'
arch_all='386 amd64 arm mips64 mips64le'
for os in $os_all; do
for arch in $arch_all; do

View File

@ -130,7 +130,11 @@ func msgSender(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface
}
func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) {
c, err = conn.ConnectServer(client.ServerAddr, client.ServerPort)
if client.HttpProxy == "" {
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", client.ServerAddr, client.ServerPort))
} else {
c, err = conn.ConnectServerByHttpProxy(client.HttpProxy, fmt.Sprintf("%s:%d", client.ServerAddr, client.ServerPort))
}
if err != nil {
log.Error("ProxyName [%s], connect to server [%s:%d] error, %v", cli.Name, client.ServerAddr, client.ServerPort, err)
return
@ -144,6 +148,7 @@ func loginToServer(cli *client.ProxyClient) (c *conn.Conn, err error) {
UseGzip: cli.UseGzip,
PrivilegeMode: cli.PrivilegeMode,
ProxyType: cli.Type,
PoolCount: cli.PoolCount,
HostHeaderRewrite: cli.HostHeaderRewrite,
Timestamp: nowTime,
}

View File

@ -37,7 +37,7 @@ type ProxyClient struct {
}
func (p *ProxyClient) GetLocalConn() (c *conn.Conn, err error) {
c, err = conn.ConnectServer(p.LocalIp, p.LocalPort)
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", p.LocalIp, p.LocalPort))
if err != nil {
log.Error("ProxyName [%s], connect to local port error, %v", p.Name, err)
}
@ -51,7 +51,11 @@ func (p *ProxyClient) GetRemoteConn(addr string, port int64) (c *conn.Conn, err
}
}()
c, err = conn.ConnectServer(addr, port)
if HttpProxy == "" {
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", addr, port))
} else {
c, err = conn.ConnectServerByHttpProxy(HttpProxy, fmt.Sprintf("%s:%d", addr, port))
}
if err != nil {
log.Error("ProxyName [%s], connect to server [%s:%d] error, %v", p.Name, addr, port, err)
return

View File

@ -16,6 +16,7 @@ package client
import (
"fmt"
"os"
"strconv"
"strings"
@ -26,6 +27,7 @@ import (
var (
ServerAddr string = "0.0.0.0"
ServerPort int64 = 7000
HttpProxy string = ""
LogFile string = "console"
LogWay string = "console"
LogLevel string = "info"
@ -57,6 +59,14 @@ func LoadConf(confFile string) (err error) {
ServerPort, _ = strconv.ParseInt(tmpStr, 10, 64)
}
tmpStr, ok = conf.Get("common", "http_proxy")
if ok {
HttpProxy = tmpStr
} else {
// get http_proxy from env
HttpProxy = os.Getenv("http_proxy")
}
tmpStr, ok = conf.Get("common", "log_file")
if ok {
LogFile = tmpStr

View File

@ -30,19 +30,21 @@ import (
// common config
var (
ConfigFile string = "./frps.ini"
BindAddr string = "0.0.0.0"
BindPort int64 = 7000
VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol
VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol
DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available
AssetsDir string = ""
LogFile string = "console"
LogWay string = "console" // console or file
LogLevel string = "info"
LogMaxDays int64 = 3
PrivilegeMode bool = false
PrivilegeToken string = ""
ConfigFile string = "./frps.ini"
BindAddr string = "0.0.0.0"
BindPort int64 = 7000
VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol
VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol
DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available
DashboardUsername string = "admin"
DashboardPassword string = "admin"
AssetsDir string = ""
LogFile string = "console"
LogWay string = "console" // console or file
LogLevel string = "info"
LogMaxDays int64 = 3
PrivilegeMode bool = false
PrivilegeToken string = ""
// if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected
PrivilegeAllowPorts map[int64]struct{}
@ -119,6 +121,16 @@ func loadCommonConf(confFile string) error {
DashboardPort = 0
}
tmpStr, ok = conf.Get("common", "dashboard_username")
if ok {
DashboardUsername = tmpStr
}
tmpStr, ok = conf.Get("common", "dashboard_password")
if ok {
DashboardPassword = tmpStr
}
tmpStr, ok = conf.Get("common", "assets_dir")
if ok {
AssetsDir = tmpStr

View File

@ -15,9 +15,11 @@
package server
import (
"encoding/base64"
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/fatedier/frp/src/assets"
@ -38,7 +40,7 @@ func RunDashboardServer(addr string, port int64) (err error) {
// view, see dashboard_view.go
mux.Handle("/favicon.ico", http.FileServer(assets.FileSystem))
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(assets.FileSystem)))
mux.HandleFunc("/", viewDashboard)
mux.HandleFunc("/", use(viewDashboard, basicAuth))
address := fmt.Sprintf("%s:%d", addr, port)
server := &http.Server{
@ -58,3 +60,43 @@ func RunDashboardServer(addr string, port int64) (err error) {
go server.Serve(ln)
return
}
func use(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFunc) http.HandlerFunc {
for _, m := range middleware {
h = m(h)
}
return h
}
func basicAuth(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
if len(s) != 2 {
http.Error(w, "Not authorized", 401)
return
}
b, err := base64.StdEncoding.DecodeString(s[1])
if err != nil {
http.Error(w, err.Error(), 401)
return
}
pair := strings.SplitN(string(b), ":", 2)
if len(pair) != 2 {
http.Error(w, "Not authorized", 401)
return
}
if pair[0] != DashboardUsername || pair[1] != DashboardPassword {
http.Error(w, "Not authorized", 401)
return
}
h.ServeHTTP(w, r)
}
}

View File

@ -16,9 +16,12 @@ package conn
import (
"bufio"
"encoding/base64"
"fmt"
"io"
"net"
"net/http"
"net/url"
"strings"
"sync"
"time"
@ -104,9 +107,9 @@ func NewConn(conn net.Conn) (c *Conn) {
return c
}
func ConnectServer(host string, port int64) (c *Conn, err error) {
func ConnectServer(addr string) (c *Conn, err error) {
c = &Conn{}
servertAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
servertAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return
}
@ -120,6 +123,49 @@ func ConnectServer(host string, port int64) (c *Conn, err error) {
return c, nil
}
func ConnectServerByHttpProxy(httpProxy string, serverAddr string) (c *Conn, err error) {
var proxyUrl *url.URL
if proxyUrl, err = url.Parse(httpProxy); err != nil {
return
}
var proxyAuth string
if proxyUrl.User != nil {
proxyAuth = "Basic " + base64.StdEncoding.EncodeToString([]byte(proxyUrl.User.String()))
}
if proxyUrl.Scheme != "http" {
err = fmt.Errorf("Proxy URL scheme must be http, not [%s]", proxyUrl.Scheme)
return
}
if c, err = ConnectServer(proxyUrl.Host); err != nil {
return
}
req, err := http.NewRequest("CONNECT", "http://"+serverAddr, nil)
if err != nil {
return
}
if proxyAuth != "" {
req.Header.Set("Proxy-Authorization", proxyAuth)
}
req.Header.Set("User-Agent", "Mozilla/5.0")
req.Write(c.TcpConn)
resp, err := http.ReadResponse(bufio.NewReader(c), req)
if err != nil {
return
}
resp.Body.Close()
if resp.StatusCode != 200 {
err = fmt.Errorf("ConnectServer using proxy error, StatusCode [%d]", resp.StatusCode)
return
}
return
}
// if the tcpConn is different with c.TcpConn
// you should call c.Close() first
func (c *Conn) SetTcpConn(tcpConn net.Conn) {

View File

@ -19,7 +19,7 @@ import (
"strings"
)
var version string = "0.8.1"
var version string = "0.9.0"
func Full() string {
return version

View File

@ -71,6 +71,18 @@ func (v *VhostMuxer) Listen(name string, rewriteHost string) (l *Listener, err e
func (v *VhostMuxer) getListener(name string) (l *Listener, exist bool) {
v.mutex.RLock()
defer v.mutex.RUnlock()
// first we check the full hostname
// if not exist, then check the wildcard_domain such as *.example.com
l, exist = v.registryMap[name]
if exist {
return l, exist
}
domainSplit := strings.Split(name, ".")
if len(domainSplit) < 3 {
return l, false
}
domainSplit[0] = "*"
name = strings.Join(domainSplit, ".")
l, exist = v.registryMap[name]
return l, exist
}
@ -93,21 +105,26 @@ func (v *VhostMuxer) run() {
func (v *VhostMuxer) handle(c *conn.Conn) {
if err := c.SetDeadline(time.Now().Add(v.timeout)); err != nil {
c.Close()
return
}
sConn, name, err := v.vhostFunc(c)
if err != nil {
c.Close()
return
}
name = strings.ToLower(name)
// get listener by hostname
l, ok := v.getListener(name)
if !ok {
c.Close()
return
}
if err = sConn.SetDeadline(time.Time{}); err != nil {
c.Close()
return
}
c.SetTcpConn(sConn)

View File

@ -19,7 +19,7 @@ var (
)
func TestEchoServer(t *testing.T) {
c, err := conn.ConnectServer("0.0.0.0", ECHO_PORT)
c, err := conn.ConnectServer(fmt.Sprintf("0.0.0.0:%d", ECHO_PORT))
if err != nil {
t.Fatalf("connect to echo server error: %v", err)
}