mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
Can be useful in case of non standard network interfaces when like tunnels or SPAN ports, when IP of interface does not match with IP of packet. Can be used to read traffic from multiple ports and interfaces at once as well.
221 lines
5.3 KiB
Go
221 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"github.com/buger/goreplay/proto"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type fakeServiceCb func(string, int, []byte)
|
|
|
|
// Simple service that generate token on request, and require this token for accesing to secure area
|
|
func NewFakeSecureService(wg *sync.WaitGroup, cb fakeServiceCb) *httptest.Server {
|
|
active_tokens := make([]string, 0)
|
|
var mu sync.Mutex
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
Debug("Received request: " + req.URL.String())
|
|
|
|
switch req.URL.Path {
|
|
case "/token":
|
|
// Generate random token
|
|
token_length := 10
|
|
buf := make([]byte, token_length)
|
|
rand.Read(buf)
|
|
token := hex.EncodeToString(buf)
|
|
active_tokens = append(active_tokens, token)
|
|
|
|
w.Write([]byte(token))
|
|
|
|
cb(req.URL.Path, 200, []byte(token))
|
|
case "/secure":
|
|
token := req.URL.Query().Get("token")
|
|
token_found := false
|
|
|
|
for _, t := range active_tokens {
|
|
if t == token {
|
|
token_found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if token_found {
|
|
w.WriteHeader(http.StatusAccepted)
|
|
cb(req.URL.Path, 202, []byte(nil))
|
|
} else {
|
|
w.WriteHeader(http.StatusForbidden)
|
|
cb(req.URL.Path, 403, []byte(nil))
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
}))
|
|
|
|
return server
|
|
}
|
|
|
|
func TestFakeSecureService(t *testing.T) {
|
|
var resp, token []byte
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
server := NewFakeSecureService(wg, func(path string, status int, resp []byte) {
|
|
})
|
|
defer server.Close()
|
|
|
|
wg.Add(3)
|
|
|
|
client := NewHTTPClient(server.URL, &HTTPClientConfig{Debug: true})
|
|
resp, _ = client.Get("/token")
|
|
token = proto.Body(resp)
|
|
|
|
// 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, _ = 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 TestEchoMiddleware(t *testing.T) {
|
|
wg := new(sync.WaitGroup)
|
|
|
|
from := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Env", "prod")
|
|
w.Header().Set("RequestPath", r.URL.Path)
|
|
wg.Done()
|
|
}))
|
|
defer from.Close()
|
|
|
|
to := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Env", "test")
|
|
w.Header().Set("RequestPath", r.URL.Path)
|
|
wg.Done()
|
|
}))
|
|
defer to.Close()
|
|
|
|
quit := make(chan int)
|
|
|
|
Settings.middleware = "./examples/middleware/echo.sh"
|
|
|
|
// Catch traffic from one service
|
|
fromAddr := strings.Replace(from.Listener.Addr().String(), "[::]", "127.0.0.1", -1)
|
|
input := NewRAWInput(fromAddr, EnginePcap, true, testRawExpire, "", "")
|
|
defer input.Close()
|
|
|
|
// And redirect to another
|
|
output := NewHTTPOutput(to.URL, &HTTPOutputConfig{Debug: false})
|
|
|
|
Plugins.Inputs = []io.Reader{input}
|
|
Plugins.Outputs = []io.Writer{output}
|
|
|
|
// Start Gor
|
|
go Start(quit)
|
|
|
|
// Wait till middleware initialization
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Should receive 2 requests from original + 2 from replayed
|
|
client := NewHTTPClient(from.URL, &HTTPClientConfig{Debug: false})
|
|
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(4)
|
|
// Request should be echoed
|
|
client.Get("/a")
|
|
time.Sleep(5 * time.Millisecond)
|
|
client.Get("/b")
|
|
time.Sleep(5 * time.Millisecond)
|
|
}
|
|
|
|
wg.Wait()
|
|
close(quit)
|
|
time.Sleep(200 * time.Millisecond)
|
|
|
|
Settings.middleware = ""
|
|
}
|
|
|
|
func TestTokenMiddleware(t *testing.T) {
|
|
var resp, token []byte
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
from := NewFakeSecureService(wg, func(path string, status int, tok []byte) {
|
|
time.Sleep(10 * time.Millisecond)
|
|
})
|
|
defer from.Close()
|
|
|
|
to := NewFakeSecureService(wg, func(path string, status int, tok []byte) {
|
|
switch path {
|
|
case "/secure":
|
|
if status != 202 {
|
|
t.Error("Server should receive valid rewritten token")
|
|
}
|
|
}
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
})
|
|
defer to.Close()
|
|
|
|
quit := make(chan int)
|
|
|
|
Settings.middleware = "go run ./examples/middleware/token_modifier.go"
|
|
|
|
fromAddr := strings.Replace(from.Listener.Addr().String(), "[::]", "127.0.0.1", -1)
|
|
// Catch traffic from one service
|
|
input := NewRAWInput(fromAddr, EnginePcap, true, testRawExpire, "", "")
|
|
defer input.Close()
|
|
|
|
// And redirect to another
|
|
output := NewHTTPOutput(to.URL, &HTTPOutputConfig{Debug: true})
|
|
|
|
Plugins.Inputs = []io.Reader{input}
|
|
Plugins.Outputs = []io.Writer{output}
|
|
|
|
// Start Gor
|
|
go Start(quit)
|
|
|
|
// Wait for middleware to initialize
|
|
// Give go compiller time to build programm
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
// Should receive 2 requests from original + 2 from replayed
|
|
wg.Add(4)
|
|
|
|
client := NewHTTPClient(from.URL, &HTTPClientConfig{Debug: true})
|
|
|
|
// Sending traffic to original service
|
|
resp, _ = client.Get("/token")
|
|
token = proto.Body(resp)
|
|
|
|
// When delay is too smal, middleware does not always rewrite requests in time
|
|
// Hopefuly client will have delay more then 100ms :)
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
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()
|
|
close(quit)
|
|
time.Sleep(100 * time.Millisecond)
|
|
Settings.middleware = ""
|
|
}
|