mirror of https://github.com/fatedier/frp
fatedier
8 years ago
8 changed files with 237 additions and 246 deletions
@ -1,32 +0,0 @@
|
||||
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 |
||||
} |
@ -1,203 +0,0 @@
|
||||
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 |
||||
} |
||||
|
||||
proxy := &Proxy{ |
||||
Server: NewProxyServer(), |
||||
Ln: listen, |
||||
} |
||||
go proxy.Server.Serve(proxy.Ln) |
||||
|
||||
return proxy, nil |
||||
} |
||||
|
||||
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") |
||||
} |
@ -0,0 +1,226 @@
|
||||
// Copyright 2017 frp team
|
||||
//
|
||||
// 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 plugin |
||||
|
||||
import ( |
||||
"encoding/base64" |
||||
"fmt" |
||||
"io" |
||||
"net" |
||||
"net/http" |
||||
"strings" |
||||
"sync" |
||||
|
||||
"github.com/fatedier/frp/models/proto/tcp" |
||||
"github.com/fatedier/frp/utils/errors" |
||||
frpNet "github.com/fatedier/frp/utils/net" |
||||
) |
||||
|
||||
const PluginHttpProxy = "http_proxy" |
||||
|
||||
func init() { |
||||
Register(PluginHttpProxy, NewHttpProxyPlugin) |
||||
} |
||||
|
||||
type Listener struct { |
||||
conns chan net.Conn |
||||
closed bool |
||||
mu sync.Mutex |
||||
} |
||||
|
||||
func NewProxyListener() *Listener { |
||||
return &Listener{ |
||||
conns: make(chan net.Conn, 64), |
||||
} |
||||
} |
||||
|
||||
func (l *Listener) Accept() (net.Conn, error) { |
||||
conn, ok := <-l.conns |
||||
if !ok { |
||||
return nil, fmt.Errorf("listener closed") |
||||
} |
||||
return conn, nil |
||||
} |
||||
|
||||
func (l *Listener) PutConn(conn net.Conn) error { |
||||
err := errors.PanicToError(func() { |
||||
l.conns <- conn |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
func (l *Listener) Close() error { |
||||
l.mu.Lock() |
||||
defer l.mu.Unlock() |
||||
if !l.closed { |
||||
close(l.conns) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (l *Listener) Addr() net.Addr { |
||||
return (*net.TCPAddr)(nil) |
||||
} |
||||
|
||||
type HttpProxy struct { |
||||
l *Listener |
||||
s *http.Server |
||||
AuthUser string |
||||
AuthPasswd string |
||||
} |
||||
|
||||
func NewHttpProxyPlugin(params map[string]string) (Plugin, error) { |
||||
user := params["plugin_http_user"] |
||||
passwd := params["plugin_http_passwd"] |
||||
listener := NewProxyListener() |
||||
|
||||
hp := &HttpProxy{ |
||||
l: listener, |
||||
AuthUser: user, |
||||
AuthPasswd: passwd, |
||||
} |
||||
|
||||
hp.s = &http.Server{ |
||||
Handler: hp, |
||||
} |
||||
|
||||
go hp.s.Serve(listener) |
||||
return hp, nil |
||||
} |
||||
|
||||
func (hp *HttpProxy) Name() string { |
||||
return PluginHttpProxy |
||||
} |
||||
|
||||
func (hp *HttpProxy) Handle(conn io.ReadWriteCloser) { |
||||
var wrapConn net.Conn |
||||
if realConn, ok := conn.(net.Conn); ok { |
||||
wrapConn = realConn |
||||
} else { |
||||
wrapConn = frpNet.WrapReadWriteCloserToConn(conn) |
||||
} |
||||
|
||||
hp.l.PutConn(wrapConn) |
||||
return |
||||
} |
||||
|
||||
func (hp *HttpProxy) Close() error { |
||||
hp.s.Close() |
||||
hp.l.Close() |
||||
return nil |
||||
} |
||||
|
||||
func (hp *HttpProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { |
||||
if ok := hp.Auth(rw, req); !ok { |
||||
rw.Header().Set("Proxy-Authenticate", "Basic") |
||||
rw.WriteHeader(http.StatusProxyAuthRequired) |
||||
return |
||||
} |
||||
|
||||
if req.Method == "CONNECT" { |
||||
hp.ConnectHandler(rw, req) |
||||
} else { |
||||
hp.HttpHandler(rw, req) |
||||
} |
||||
} |
||||
|
||||
func (hp *HttpProxy) HttpHandler(rw http.ResponseWriter, req *http.Request) { |
||||
removeProxyHeaders(req) |
||||
|
||||
resp, err := http.DefaultTransport.RoundTrip(req) |
||||
if err != nil { |
||||
http.Error(rw, err.Error(), http.StatusInternalServerError) |
||||
return |
||||
} |
||||
defer resp.Body.Close() |
||||
|
||||
copyHeaders(rw.Header(), resp.Header) |
||||
rw.WriteHeader(resp.StatusCode) |
||||
|
||||
_, err = io.Copy(rw, resp.Body) |
||||
if err != nil && err != io.EOF { |
||||
return |
||||
} |
||||
} |
||||
|
||||
func (hp *HttpProxy) ConnectHandler(rw http.ResponseWriter, req *http.Request) { |
||||
hj, ok := rw.(http.Hijacker) |
||||
if !ok { |
||||
rw.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
client, _, err := hj.Hijack() |
||||
if err != nil { |
||||
rw.WriteHeader(http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
remote, err := net.Dial("tcp", req.URL.Host) |
||||
if err != nil { |
||||
http.Error(rw, "Failed", http.StatusBadRequest) |
||||
client.Close() |
||||
return |
||||
} |
||||
client.Write([]byte("HTTP/1.0 200 OK\r\n\r\n")) |
||||
|
||||
go tcp.Join(remote, client) |
||||
} |
||||
|
||||
func (hp *HttpProxy) Auth(rw http.ResponseWriter, req *http.Request) bool { |
||||
if hp.AuthUser == "" && hp.AuthPasswd == "" { |
||||
return true |
||||
} |
||||
|
||||
s := strings.SplitN(req.Header.Get("Proxy-Authorization"), " ", 2) |
||||
if len(s) != 2 { |
||||
return false |
||||
} |
||||
|
||||
b, err := base64.StdEncoding.DecodeString(s[1]) |
||||
if err != nil { |
||||
return false |
||||
} |
||||
|
||||
pair := strings.SplitN(string(b), ":", 2) |
||||
if len(pair) != 2 { |
||||
return false |
||||
} |
||||
|
||||
if pair[0] != hp.AuthUser || pair[1] != hp.AuthPasswd { |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
func copyHeaders(dst, src http.Header) { |
||||
for key, values := range src { |
||||
for _, value := range values { |
||||
dst.Add(key, value) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func removeProxyHeaders(req *http.Request) { |
||||
req.RequestURI = "" |
||||
req.Header.Del("Proxy-Connection") |
||||
req.Header.Del("Connection") |
||||
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") |
||||
} |
Loading…
Reference in new issue