Skip to content

Commit

Permalink
Support Caddy
Browse files Browse the repository at this point in the history
  • Loading branch information
coyove committed Oct 25, 2018
1 parent 4f4faea commit f59078b
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 36 deletions.
23 changes: 23 additions & 0 deletions cmd/gocaddyway/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Use goflyway in Caddy [beta]

1. Follow the [official guide](https://github.com/mholt/caddy#build) to run a working caddy server from source
2. In `caddy/caddymain/run.go`, add `_ "github.com/coyove/goflyway/cmd/gocaddyway"`
2. In `caddyhttp/httpserver/plugin.go`, add `goflyway` to `directives` at about line 600. (Don't add to the bottom, it should be in front of `locale`, the order is important)
2. Build caddy
2. Prepare a Caddyfile and start the server, e.g.:
```
http://:8100 {
goflyway password
proxy / http://example.com
}
```
2. At local:
```
./goflyway -up xxx:8100 -k password
```
2. Done!
## Note
1. TCP multiplexer is not supported
2. Caddyfile hot reload is not supported, stop all and restart all
58 changes: 58 additions & 0 deletions cmd/gocaddyway/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package gocaddyway

import (
"net/http"

"github.com/coyove/common/logg"
"github.com/coyove/goflyway/proxy"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
)

type gofwHandler struct {
Next httpserver.Handler
gofw *proxy.ProxyServer
}

func init() {
caddy.RegisterPlugin("goflyway", caddy.Plugin{
ServerType: "http",
Action: setup,
})
}

func setup(c *caddy.Controller) error {

c.Next()
if !c.NextArg() {
return c.ArgErr()
}

cipher := proxy.NewCipher(c.Val(), proxy.FullCipher)
cipher.IO.StartPurgeConns(20)
cipher.IO.Logger = logg.NewLogger("off")
sc := &proxy.ServerConfig{
Cipher: cipher,
LBindTimeout: 10,
LBindCap: 256,
Logger: cipher.IO.Logger,
}

cfg := httpserver.GetConfig(c)
mid := func(next httpserver.Handler) httpserver.Handler {
server, _ := proxy.NewServer("0.0.0.0:0", sc)
return gofwHandler{
Next: next,
gofw: server,
}
}
cfg.AddMiddleware(mid)
return nil
}

func (h gofwHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
if h.gofw.ServeHTTPImpl(w, r) {
return 0, nil
}
return h.Next.ServeHTTP(w, r)
}
74 changes: 38 additions & 36 deletions proxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,27 +148,13 @@ func (proxy *ProxyServer) replyGood(downstreamConn net.Conn, cr *clientRequest,
downstreamConn.Write(p.Bytes())
}

func (proxy *ProxyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
replySomething := func() {
if proxy.rp == nil {
w.WriteHeader(404)
w.Write([]byte(`<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>`))
} else {
proxy.rp.ServeHTTP(w, r)
}
}

// ServeHTTPImpl returns true if it successfully handled the goflyway request, false if any error occurred.
// When succeed, ServeHTTPImpl will take over all controls of w and r, caller shall not alter them ever after.
func (proxy *ProxyServer) ServeHTTPImpl(w http.ResponseWriter, r *http.Request) bool {
addr, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
proxy.Logger.Warnf("Unknown address: %s", r.RemoteAddr)
replySomething()
return
return false
}

var rawReq []byte
Expand Down Expand Up @@ -200,7 +186,7 @@ DE_AGAIN:
case resp := <-cb:
if resp.err != nil {
userConn.Write([]byte("HTTP/1.1 400 Bad Request\r\n\r\nError: " + resp.err.Error()))
return
return true
}
case <-time.After(time.Duration(proxy.LBindTimeout) * time.Second):
proxy.Logger.Errorf("RP client didn't response")
Expand All @@ -216,7 +202,7 @@ DE_AGAIN:
}
}
proxy.localRP.Unlock()
return
return true
}

if fu := r.Header.Get(fwdURLHeader); fu != "" {
Expand All @@ -227,14 +213,13 @@ DE_AGAIN:

proxy.Logger.Dbgf("Invalid request from %s: %s", addr, proxy.stripURI(r.RequestURI))
proxy.blacklist.Add(addr, nil)
replySomething()
return
return false
}

if proxy.Users != nil {
if !proxy.auth(cr.Auth) {
proxy.Logger.Warnf("User auth failed from %s", addr)
return
return true
}
}

Expand All @@ -255,7 +240,7 @@ DE_AGAIN:
proxy.Logger.Dbgf("DNS answer of %s: %s", host, ip.String())
w.Header().Add(dnsRespHeader, base64.StdEncoding.EncodeToString([]byte(ip.IP.To4())))
w.WriteHeader(200)
return
return true
}

if cr.Opt.IsSet(doLocalRP) {
Expand All @@ -268,36 +253,35 @@ DE_AGAIN:
resp, ok := proxy.localRP.waiting[dst]
if !ok {
proxy.localRP.Unlock()
return
return true
}
proxy.localRP.Unlock()

downstreamConn := proxy.hijack(w)
proxy.replyGood(downstreamConn, cr, &ioc, r)
go proxy.Cipher.IO.Bridge(downstreamConn, resp.req.conn, cr.IV, ioc)
resp.req.callback <- resp
return
return true
}
}

if proxy.isBlocked(dst) {
w.WriteHeader(http.StatusForbidden)
proxy.Logger.Logf("%s is blocked", dst)
return
return true
}

if cr.Opt.IsSet(doConnect) {
host := dst
if host == "" {
proxy.Logger.Warnf("Valid rkey invalid host from %s", addr)
replySomething()
return
return false
}

proxy.Logger.Logf("Dial real host: %s", host)
downstreamConn := proxy.hijack(w)
if downstreamConn == nil {
return
return false
}

ioc := proxy.getIOConfig(cr)
Expand All @@ -309,7 +293,7 @@ DE_AGAIN:
if proxy.Policy.IsSet(PolicyDisableUDP) {
proxy.Logger.Warnf("Client UDP relay request rejected")
downstreamConn.Close()
return
return false
}

uaddr, _ := net.ResolveUDPAddr("udp", host)
Expand All @@ -329,7 +313,7 @@ DE_AGAIN:
if err != nil {
proxy.Logger.Errorf("Dial real host failed: %v", err)
downstreamConn.Close()
return
return false
}

proxy.replyGood(downstreamConn, cr, &ioc, r)
Expand All @@ -341,13 +325,13 @@ DE_AGAIN:
} else {
go proxy.Cipher.IO.Bridge(downstreamConn, targetSiteConn, cr.IV, ioc)
}
return true
} else if cr.Opt.IsSet(doHTTPReq) {
var err error

r.URL, err = url.Parse(dst)
if err != nil {
replySomething()
return
return false
}

r.Host = r.URL.Host
Expand All @@ -359,7 +343,7 @@ DE_AGAIN:
if err != nil {
proxy.Logger.Errorf("Round trip %s: %v", r.URL, err)
proxy.Write(w, cr.IV, []byte(err.Error()), http.StatusInternalServerError)
return
return true
}

copyHeaders(w.Header(), resp.Header, proxy.Cipher, true, cr.IV)
Expand All @@ -375,9 +359,27 @@ DE_AGAIN:
}

tryClose(resp.Body)
return true
} else {
proxy.blacklist.Add(addr, nil)
replySomething()
return false
}
}

func (proxy *ProxyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !proxy.ServeHTTPImpl(w, r) {
if proxy.rp == nil {
w.WriteHeader(404)
w.Write([]byte(`<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>`))
} else {
proxy.rp.ServeHTTP(w, r)
}
}
}

Expand Down

0 comments on commit f59078b

Please sign in to comment.