forked from fatedier/frp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
3 changed files
with
236 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"port":":8080" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package proxy | ||
|
||
import ( | ||
"bufio" | ||
"encoding/json" | ||
"os" | ||
) | ||
|
||
// Config 保存代理服务器的配置 | ||
type Config struct { | ||
Port string `json:"port"` | ||
Auth bool `json:"auth"` | ||
|
||
User map[string]string `json:"user"` | ||
} | ||
|
||
// 从指定json文件读取config配置 | ||
func (c *Config) GetConfig(filename string) error { | ||
|
||
configFile, err := os.Open(filename) | ||
if err != nil { | ||
return err | ||
} | ||
defer configFile.Close() | ||
|
||
br := bufio.NewReader(configFile) | ||
err = json.NewDecoder(br).Decode(c) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
package proxy | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"net" | ||
"net/http" | ||
"os" | ||
"time" | ||
|
||
"github.com/fatedier/frp/models/plugin" | ||
"github.com/fatedier/frp/utils/log" | ||
wrap "github.com/fatedier/frp/utils/net" | ||
) | ||
|
||
var ( | ||
HTTP_200 = []byte("HTTP/1.1 200 Connection Established\r\n\r\n") | ||
ProxyName = "default-proxy" | ||
cnfg Config | ||
) | ||
|
||
func init() { | ||
// 加载配置文件 | ||
err := cnfg.GetConfig("../config/config.json") | ||
if err != nil { | ||
log.Error("can not load config file:%v\n", err) | ||
os.Exit(-1) | ||
} | ||
plugin.Register(ProxyName, NewProxyPlugin) | ||
} | ||
|
||
type ProxyServer struct { | ||
Tr *http.Transport | ||
} | ||
|
||
type Proxy struct { | ||
Server *http.Server | ||
Ln net.Listener | ||
} | ||
|
||
func NewProxyPlugin(params map[string]string) (p plugin.Plugin, err error) { | ||
|
||
listen, err := net.Listen("tcp", cnfg.Port) | ||
if err != nil { | ||
log.Error("can not listen %v port", cnfg.Port) | ||
return | ||
} | ||
|
||
p = &Proxy{ | ||
Server: NewProxyServer(), | ||
Ln: listen, | ||
} | ||
return | ||
} | ||
|
||
func (proxy *Proxy) Name() string { | ||
return ProxyName | ||
} | ||
|
||
// right?? | ||
func (proxy *Proxy) Handle(conn io.ReadWriteCloser) { | ||
wrapConn := wrap.WrapReadWriteCloserToConn(conn) | ||
|
||
remote, err := net.Dial("tcp", cnfg.Port) | ||
if err != nil { | ||
log.Error("dial tcp error:%v", err) | ||
return | ||
} | ||
|
||
// or tcp.Join(remote,wrapConn) | ||
_, err = io.Copy(remote, wrapConn) | ||
if err != nil && err != io.EOF { | ||
log.Error("io copy data error:%v", err) | ||
return | ||
} | ||
return | ||
} | ||
|
||
func (proxy *Proxy) Close() error { | ||
return proxy.Server.Close() | ||
} | ||
|
||
func NewProxyServer() *http.Server { | ||
|
||
return &http.Server{ | ||
Addr: cnfg.Port, | ||
Handler: &ProxyServer{Tr: http.DefaultTransport.(*http.Transport)}, | ||
ReadTimeout: 10 * time.Second, | ||
WriteTimeout: 10 * time.Second, | ||
MaxHeaderBytes: 1 << 20, | ||
} | ||
} | ||
|
||
func (proxy *ProxyServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { | ||
defer func() { | ||
if err := recover(); err != nil { | ||
rw.WriteHeader(http.StatusInternalServerError) | ||
log.Error("Panic: %v", err) | ||
fmt.Fprintf(rw, fmt.Sprintln(err)) | ||
} | ||
}() | ||
|
||
if req.Method == "CONNECT" { // 是connect连接 | ||
proxy.HttpsHandler(rw, req) | ||
} else { | ||
proxy.HttpHandler(rw, req) | ||
} | ||
} | ||
|
||
// 处理普通的http请求 | ||
func (proxy *ProxyServer) HttpHandler(rw http.ResponseWriter, req *http.Request) { | ||
log.Info("is sending request %v %v ", req.Method, req.URL.Host) | ||
removeProxyHeaders(req) // 去除不必要的头 | ||
|
||
resp, err := proxy.Tr.RoundTrip(req) | ||
if err != nil { | ||
log.Error("transport RoundTrip error: %v", err) | ||
http.Error(rw, err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
defer resp.Body.Close() | ||
|
||
clearHeaders(rw.Header()) // 得到一个空的Header | ||
copyHeaders(rw.Header(), resp.Header) | ||
rw.WriteHeader(resp.StatusCode) | ||
|
||
nr, err := io.Copy(rw, resp.Body) | ||
if err != nil && err != io.EOF { | ||
log.Error("got an error when copy remote response to client.%v", err) | ||
return | ||
} | ||
log.Info("copied %v bytes from remote host %v.", nr, req.URL.Host) | ||
} | ||
|
||
// 处理https连接,主要用于CONNECT方法 | ||
func (proxy *ProxyServer) HttpsHandler(rw http.ResponseWriter, req *http.Request) { | ||
log.Info("[CONNECT] tried to connect to remote host %v", req.URL.Host) | ||
|
||
hj, _ := rw.(http.Hijacker) | ||
client, _, err := hj.Hijack() //获取客户端与代理服务器的tcp连接 | ||
if err != nil { | ||
log.Error("failed to get Tcp connection of", req.RequestURI) | ||
http.Error(rw, "Failed", http.StatusBadRequest) | ||
return | ||
} | ||
|
||
remote, err := net.Dial("tcp", req.URL.Host) //建立服务端和代理服务器的tcp连接 | ||
if err != nil { | ||
log.Error("failed to connect %v", req.RequestURI) | ||
http.Error(rw, "Failed", http.StatusBadRequest) | ||
client.Close() | ||
return | ||
} | ||
|
||
client.Write(HTTP_200) | ||
|
||
go copyRemoteToClient(remote, client) | ||
go copyRemoteToClient(client, remote) | ||
} | ||
|
||
// data copy between two socket | ||
func copyRemoteToClient(remote, client net.Conn) { | ||
defer func() { | ||
remote.Close() | ||
client.Close() | ||
}() | ||
|
||
nr, err := io.Copy(remote, client) | ||
if err != nil && err != io.EOF { | ||
log.Error("got an error when handles CONNECT %v", err) | ||
return | ||
} | ||
log.Info("[CONNECT] transported %v bytes betwwen %v and %v", nr, remote.RemoteAddr(), client.RemoteAddr()) | ||
} | ||
|
||
func copyHeaders(dst, src http.Header) { | ||
for key, values := range src { | ||
for _, value := range values { | ||
dst.Add(key, value) | ||
} | ||
} | ||
} | ||
|
||
func clearHeaders(headers http.Header) { | ||
for key, _ := range headers { | ||
headers.Del(key) | ||
} | ||
} | ||
|
||
func removeProxyHeaders(req *http.Request) { | ||
req.RequestURI = "" | ||
req.Header.Del("Proxy-Connection") | ||
req.Header.Del("Connection") | ||
req.Header.Del("Keep-Alive") | ||
req.Header.Del("Proxy-Authenticate") | ||
req.Header.Del("Proxy-Authorization") | ||
req.Header.Del("TE") | ||
req.Header.Del("Trailers") | ||
req.Header.Del("Transfer-Encoding") | ||
req.Header.Del("Upgrade") | ||
} |