Skip to content

Commit

Permalink
Merge pull request #76 from fatedier/fatedier/support_http_proxy
Browse files Browse the repository at this point in the history
frpc: add support for connecting server through http proxies, see #67
  • Loading branch information
fatedier authored Aug 14, 2016
2 parents 47c1a3e + e262ac6 commit 09624b5
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 6 deletions.
2 changes: 2 additions & 0 deletions conf/frpc.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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:[email protected]:8080
# console or real logFile path like ./frpc.log
log_file = ./frpc.log
# debug, info, warn, error
Expand Down
6 changes: 5 additions & 1 deletion src/cmd/frpc/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions src/models/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
Expand Down
10 changes: 10 additions & 0 deletions src/models/client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package client

import (
"fmt"
"os"
"strconv"
"strings"

Expand All @@ -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"
Expand Down Expand Up @@ -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
Expand Down
50 changes: 48 additions & 2 deletions src/utils/conn/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ package conn

import (
"bufio"
"encoding/base64"
"fmt"
"io"
"net"
"net/http"
"net/url"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -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
}
Expand All @@ -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", "https://"+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) {
Expand Down
2 changes: 1 addition & 1 deletion test/func_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down

0 comments on commit 09624b5

Please sign in to comment.