diff --git a/emitter.go b/emitter.go index 174cfc8..3fdbac4 100644 --- a/emitter.go +++ b/emitter.go @@ -31,6 +31,8 @@ func CopyMulty(src io.Reader, writers ...io.Writer) (err error) { if nr > 0 && len(buf) > nr { payload := buf[0:nr] + Debug("[EMITTER] Received payload:", string(payload)) + if modifier != nil { payload = modifier.Rewrite(payload) diff --git a/http_client.go b/http_client.go index 4e44f77..d142e21 100644 --- a/http_client.go +++ b/http_client.go @@ -72,7 +72,7 @@ func (c *HTTPClient) Disconnect() { if c.conn != nil { c.conn.Close() c.conn = nil - Debug("Disconnected: ", c.baseURL) + Debug("[HTTP] Disconnected: ", c.baseURL) } } @@ -90,7 +90,7 @@ func (c *HTTPClient) isAlive() bool { func (c *HTTPClient) Send(data []byte) (response []byte, err error) { if c.conn == nil || !c.isAlive() { - Debug("Connecting:", c.baseURL) + Debug("[HTTP] Connecting:", c.baseURL) c.Connect() } @@ -101,11 +101,11 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) { data = proto.SetHost(data, []byte(c.baseURL), []byte(c.host)) if c.config.Debug { - Debug("Sending:", string(data)) + Debug("[HTTP] Sending:", string(data)) } if _, err = c.conn.Write(data); err != nil { - Debug("Write error:", err, c.baseURL) + Debug("[HTTP] Write error:", err, c.baseURL) return } @@ -113,14 +113,14 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) { n, err := c.conn.Read(c.respBuf) if err != nil { - Debug("READ ERRORR!", err, c.conn) + Debug("[HTTP] READ ERRORR!", err, c.conn) return } payload := c.respBuf[:n] if c.config.Debug { - Debug("Received:", string(payload)) + Debug("[HTTP] Received:", string(payload)) } if c.config.FollowRedirects > 0 && c.redirectsCount < c.config.FollowRedirects { @@ -134,7 +134,7 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) { redirectPayload := []byte("GET " + string(location) + " HTTP/1.1\r\n\r\n") if c.config.Debug { - Debug("Redirecting to: " + string(location)) + Debug("[HTTP] Redirecting to: " + string(location)) } return c.Send(redirectPayload) @@ -145,3 +145,9 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) { return payload, err } + +func (c *HTTPClient) Get(path string) (response []byte, err error) { + payload := "GET " + path + " HTTP/1.1\r\n\r\n" + + return c.Send([]byte(payload)) +} \ No newline at end of file diff --git a/middleware_test.go b/middleware_test.go index 347453c..7ce251a 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -1,22 +1,20 @@ package main import ( - _ "bufio" "bytes" "crypto/rand" "io" - "io/ioutil" - _ "log" - _ "net" "net/http" "sync" "testing" "strings" + "github.com/buger/gor/proto" + "encoding/hex" ) // Simple service that generate token on request, and require this token for accesing to secure area func NewFakeSecureService(wg *sync.WaitGroup) string { - active_tokens := make([][]byte, 0) + active_tokens := make([]string, 0) listener := startHTTP(func(w http.ResponseWriter, req *http.Request) { Debug("Received request: " + req.URL.String()) @@ -25,17 +23,18 @@ func NewFakeSecureService(wg *sync.WaitGroup) string { case "/token": // Generate random token token_length := 10 - token := make([]byte, token_length) - rand.Read(token) + buf := make([]byte, token_length) + rand.Read(buf) + token := hex.EncodeToString(buf) active_tokens = append(active_tokens, token) - w.Write(token) + w.Write([]byte(token)) case "/secure": - token := []byte(req.URL.Query().Get("token")) + token := req.URL.Query().Get("token") token_found := false for _, t := range active_tokens { - if bytes.Equal(t, token) { + if t == token { token_found = true break } @@ -56,7 +55,7 @@ func NewFakeSecureService(wg *sync.WaitGroup) string { } func TestFakeSecureService(t *testing.T) { - var resp *http.Response + var resp, token []byte wg := new(sync.WaitGroup) @@ -64,26 +63,27 @@ func TestFakeSecureService(t *testing.T) { wg.Add(3) - resp, _ = http.Get("http://" + addr + "/token") - token, _ := ioutil.ReadAll(resp.Body) + client := NewHTTPClient("http://" + addr, &HTTPClientConfig{Debug: true}) + resp, _ = client.Get("/token") + token = proto.Body(resp) - // Right token - resp, _ = http.Get("http://" + addr + "/secure?token=" + string(token)) - if resp.StatusCode != http.StatusAccepted { - t.Error("Valid token should returns wrong status:", resp.StatusCode) - } + // Right token + resp, _ = client.Get("/secure?token=" + string(token)) + if !bytes.Equal(proto.Status(resp), []byte("202")) { + t.Error("Valid token should return status 202:", string(proto.Status(resp))) + } - // Wrong tokens forbidden - resp, _ = http.Get("http://" + addr + "/secure?token=wrong") - if resp.StatusCode != http.StatusForbidden { - t.Error("Wrong tokens should be forbidden, instead:", resp.StatusCode) + // Wrong tokens forbidden + resp, _ = client.Get("/secure?token=wrong") + if !bytes.Equal(proto.Status(resp), []byte("403")) { + t.Error("Wrong token should returns status 403:", string(proto.Status(resp))) } wg.Wait() } func TestMiddleware(t *testing.T) { - var resp *http.Response + var resp, token []byte wg := new(sync.WaitGroup) @@ -107,13 +107,15 @@ func TestMiddleware(t *testing.T) { // Should receive 2 requests from original + 2 from replayed wg.Add(4) - // Sending traffic to original service - resp, _ = http.Get("http://" + from + "/token") - token, _ := ioutil.ReadAll(resp.Body) + client := NewHTTPClient("http://" + from, &HTTPClientConfig{Debug: true}) - resp, _ = http.Get("http://" + from + "/secure?token=" + string(token)) - if resp.StatusCode != http.StatusAccepted { - t.Error("Valid token should returns wrong status:", resp.StatusCode) + // Sending traffic to original service + resp, _ = client.Get("/token") + token = proto.Body(resp) + + resp, _ = client.Get("/secure?token=" + string(token)) + if !bytes.Equal(proto.Status(resp), []byte("202")) { + t.Error("Valid token should return 202:", proto.Status(resp)) } wg.Wait() diff --git a/plugins.go b/plugins.go index e83a7f2..adfc242 100644 --- a/plugins.go +++ b/plugins.go @@ -56,8 +56,8 @@ func registerPlugin(constructor interface{}, options ...interface{}) { } if _, ok := plugin.(io.Reader); ok { - for _, options := range Settings.middleware { - plugin_wrapper = NewMiddleware(plugin_wrapper, options) + if len(Settings.middleware) > 0 { + plugin_wrapper = NewMiddleware(plugin_wrapper, Settings.middleware) } Plugins.Inputs = append(Plugins.Inputs, plugin_wrapper.(io.Reader)) } diff --git a/proto/proto.go b/proto/proto.go index 626d289..9ca60e5 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -68,6 +68,11 @@ func AddHeader(payload, name, value []byte) []byte { return byteutils.Insert(payload, mimeStart, header) } +func Body(payload []byte) []byte { + // 4 -> len(EMPTY_LINE) + return payload[MIMEHeadersEndPos(payload) + 4:] +} + func Path(payload []byte) []byte { start := bytes.IndexByte(payload, ' ') start += 1 diff --git a/settings.go b/settings.go index 537b97a..5c34f46 100644 --- a/settings.go +++ b/settings.go @@ -41,7 +41,7 @@ type AppSettings struct { inputRAW MultiOption - middleware MultiOption + middleware string inputHTTP MultiOption outputHTTP MultiOption @@ -78,7 +78,7 @@ func init() { flag.Var(&Settings.inputRAW, "input-raw", "Capture traffic from given port (use RAW sockets and require *sudo* access):\n\t# Capture traffic from 8080 port\n\tgor --input-raw :8080 --output-http staging.com") - flag.Var(&Settings.middleware, "middleware", "Used for modifying input traffic using external command") + flag.StringVar(&Settings.middleware, "middleware", "", "Used for modifying traffic using external command") flag.Var(&Settings.inputHTTP, "input-http", "Read requests from HTTP, should be explicitly sent from your application:\n\t# Listen for http on 9000\n\tgor --input-http :9000 --output-http staging.com") @@ -117,7 +117,7 @@ func init() { func Debug(args ...interface{}) { if Settings.verbose { - log.Print("[DEBUG] ") + fmt.Print("[DEBUG] ") log.Println(args...) } }