浏览代码

Fix conflicts

Conflicts:
	README_zh.md
	src/utils/version/version.go
fatedier 8 年之前
父节点
当前提交
b65e037b5e

+ 5 - 0
.dockerignore

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

+ 1 - 1
.travis.yml

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

+ 17 - 0
Dockerfile

@@ -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 - 0
Dockerfile_alpine

@@ -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"]

+ 7 - 1
Makefile.cross-compiles

@@ -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

+ 12 - 4
README.md

@@ -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 optional,if 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)

+ 18 - 8
README_zh.md

@@ -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)

+ 2 - 0
conf/frpc.ini

@@ -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 - 0
conf/frpc_min.ini

@@ -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

+ 3 - 0
conf/frps.ini

@@ -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 - 0
conf/frps_min.ini

@@ -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

+ 1 - 1
cross_compiles_package.sh → package.sh

@@ -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

+ 6 - 1
src/cmd/frpc/control.go

@@ -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,
 	}

+ 6 - 2
src/models/client/client.go

@@ -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

+ 10 - 0
src/models/client/config.go

@@ -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

+ 25 - 13
src/models/server/config.go

@@ -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

+ 43 - 1
src/models/server/dashboard.go

@@ -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)
+	}
+}

+ 48 - 2
src/utils/conn/conn.go

@@ -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) {

+ 1 - 1
src/utils/version/version.go

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

+ 17 - 0
src/utils/vhost/vhost.go

@@ -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)

+ 1 - 1
test/func_test.go

@@ -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)
 	}