mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
Use latest libpcap and ensure to close sockets
This commit is contained in:
@@ -1 +1,3 @@
|
|||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
gor
|
||||||
|
gor.test
|
||||||
|
|||||||
+2
-1
@@ -10,7 +10,8 @@ RUN apt-get update -y
|
|||||||
RUN echo oracle-java7-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections
|
RUN echo oracle-java7-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections
|
||||||
RUN apt-get install oracle-java8-installer -y
|
RUN apt-get install oracle-java8-installer -y
|
||||||
|
|
||||||
RUN apt-get install libpcap-dev -y
|
RUN apt-get install flex bison -y
|
||||||
|
RUN wget http://www.tcpdump.org/release/libpcap-1.7.4.tar.gz && tar xzf libpcap-1.7.4.tar.gz && cd libpcap-1.7.4 && ./configure && make install
|
||||||
RUN go get github.com/google/gopacket
|
RUN go get github.com/google/gopacket
|
||||||
RUN go get -u github.com/golang/lint/golint
|
RUN go get -u github.com/golang/lint/golint
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ RUN = docker run -v `pwd`:$(SOURCE_PATH) -p 0.0.0.0:8000:8000 -t -i gor
|
|||||||
BENCHMARK = BenchmarkRAWInput
|
BENCHMARK = BenchmarkRAWInput
|
||||||
TEST = TestRawListenerBench
|
TEST = TestRawListenerBench
|
||||||
VERSION = DEV-$(shell date +%s)
|
VERSION = DEV-$(shell date +%s)
|
||||||
|
LDFLAGS = -ldflags "-X main.VERSION=$(VERSION) -extldflags \"-static\""
|
||||||
|
|
||||||
release: release-x64
|
release: release-x64
|
||||||
|
|
||||||
release-x64:
|
release-x64:
|
||||||
docker run -v `pwd`:$(SOURCE_PATH) -t --env GOOS=linux --env GOARCH=amd64 -i gor go build -ldflags "-X main.VERSION=$(VERSION) -extldflags \"-static\"" && tar -czf gor_$(VERSION)_x64.tar.gz gor && rm gor
|
docker run -v `pwd`:$(SOURCE_PATH) -t --env GOOS=linux --env GOARCH=amd64 -i gor go build $(LDFLAGS) && tar -czf gor_$(VERSION)_x64.tar.gz gor && rm gor
|
||||||
|
|
||||||
release-x86:
|
release-x86:
|
||||||
docker run -v `pwd`:$(SOURCE_PATH) -t --env GOOS=linux --env GOARCH=386 -i gor go build -ldflags "-X main.VERSION=$(VERSION)" && tar -czf gor_$(VERSION)_x86.tar.gz gor && rm gor
|
docker run -v `pwd`:$(SOURCE_PATH) -t --env GOOS=linux --env GOARCH=386 -i gor go build $(LDFLAGS) && tar -czf gor_$(VERSION)_x86.tar.gz gor && rm gor
|
||||||
|
|
||||||
build:
|
build:
|
||||||
docker build -t gor .
|
docker build -t gor .
|
||||||
@@ -27,13 +28,13 @@ race:
|
|||||||
$(RUN) go test ./... $(ARGS) -v -race -timeout 15s
|
$(RUN) go test ./... $(ARGS) -v -race -timeout 15s
|
||||||
|
|
||||||
test:
|
test:
|
||||||
$(RUN) go test ./. -timeout 30s $(ARGS) -v
|
$(RUN) go test ./. -race -timeout 30s $(LDFLAGS) $(ARGS) -v
|
||||||
|
|
||||||
test_all:
|
test_all:
|
||||||
$(RUN) go test ./... -timeout 60s $(ARGS) -v
|
$(RUN) go test ./... -timeout 60s $(LDFLAGS) $(ARGS) -v
|
||||||
|
|
||||||
testone:
|
testone:
|
||||||
$(RUN) go test ./... -timeout 4s -run $(TEST) $(ARGS) -v
|
$(RUN) go test ./... -timeout 4s $(LDFLAGS) -run $(TEST) $(ARGS) -v
|
||||||
|
|
||||||
cover:
|
cover:
|
||||||
$(RUN) go test $(ARGS) -race -v -timeout 15s -coverprofile=coverage.out
|
$(RUN) go test $(ARGS) -race -v -timeout 15s -coverprofile=coverage.out
|
||||||
@@ -46,7 +47,7 @@ vet:
|
|||||||
$(RUN) go vet
|
$(RUN) go vet
|
||||||
|
|
||||||
bench:
|
bench:
|
||||||
$(RUN) go test -v -run NOT_EXISTING -bench $(BENCHMARK) -benchtime 5s
|
$(RUN) go test $(LDFLAGS) -v -run NOT_EXISTING -bench $(BENCHMARK) -benchtime 5s
|
||||||
|
|
||||||
profile_test:
|
profile_test:
|
||||||
$(RUN) go test $(LDFLAGS) -run $(TEST) ./raw_socket_listener/. $(ARGS) -memprofile mem.mprof -cpuprofile cpu.out
|
$(RUN) go test $(LDFLAGS) -run $(TEST) ./raw_socket_listener/. $(ARGS) -memprofile mem.mprof -cpuprofile cpu.out
|
||||||
@@ -54,7 +55,7 @@ profile_test:
|
|||||||
|
|
||||||
# Used mainly for debugging, because docker container do not have access to parent machine ports
|
# Used mainly for debugging, because docker container do not have access to parent machine ports
|
||||||
run:
|
run:
|
||||||
$(RUN) go run $(SOURCE) --input-dummy=0 --output-http="http://localhost:9000" --input-raw 127.0.0.1:9000 --input-http 127.0.0.1:9000 --verbose --debug --middleware "./examples/middleware/echo.sh"
|
$(RUN) go run $(LDFLAGS) $(SOURCE) --input-dummy=0 --output-http="http://localhost:9000" --input-raw 127.0.0.1:9000 --input-http 127.0.0.1:9000 --verbose --debug --middleware "./examples/middleware/echo.sh"
|
||||||
|
|
||||||
run-2:
|
run-2:
|
||||||
$(RUN) go run $(SOURCE) --input-file ./fixtures/requests.gor --output-dummy=0
|
$(RUN) go run $(SOURCE) --input-file ./fixtures/requests.gor --output-dummy=0
|
||||||
|
|||||||
+8
-1
@@ -32,8 +32,15 @@ func Start(stop chan int) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-stop:
|
case <-stop:
|
||||||
|
pluginMu.Lock()
|
||||||
|
for _, p := range Plugins.All {
|
||||||
|
if cp, ok := p.(io.Closer); ok {
|
||||||
|
cp.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pluginMu.Unlock()
|
||||||
return
|
return
|
||||||
case <-time.After(time.Second):
|
case <-time.After(100 * time.Millisecond):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"io"
|
||||||
"runtime"
|
"runtime"
|
||||||
_ "runtime/debug"
|
_ "runtime/debug"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
@@ -50,6 +53,20 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Start(nil)
|
Start(nil)
|
||||||
|
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
go func(){
|
||||||
|
<- c
|
||||||
|
|
||||||
|
for _, p := range Plugins.All {
|
||||||
|
if cp, ok := p.(io.Closer); ok {
|
||||||
|
cp.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(1)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func profileCPU(cpuprofile string) {
|
func profileCPU(cpuprofile string) {
|
||||||
|
|||||||
+5
-1
@@ -12,8 +12,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var httpMu sync.Mutex
|
||||||
|
|
||||||
var defaultPorts = map[string]string{
|
var defaultPorts = map[string]string{
|
||||||
"http": "80",
|
"http": "80",
|
||||||
"https": "443",
|
"https": "443",
|
||||||
@@ -176,7 +179,8 @@ func (c *HTTPClient) Send(data []byte) (response []byte, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
payload := c.respBuf[:n]
|
payload := make([]byte, n)
|
||||||
|
copy(payload, c.respBuf[:n])
|
||||||
|
|
||||||
if c.config.Debug {
|
if c.config.Debug {
|
||||||
Debug("[HTTPClient] Received:", string(payload))
|
Debug("[HTTPClient] Received:", string(payload))
|
||||||
|
|||||||
+14
-16
@@ -32,11 +32,7 @@ func NewRAWInput(address string, engine int, expire time.Duration) (i *RAWInput)
|
|||||||
i.engine = engine
|
i.engine = engine
|
||||||
i.quit = make(chan bool)
|
i.quit = make(chan bool)
|
||||||
|
|
||||||
go i.listen(address)
|
i.listen(address)
|
||||||
|
|
||||||
for i.listener == nil {
|
|
||||||
time.Sleep(time.Millisecond)
|
|
||||||
}
|
|
||||||
i.listener.IsReady()
|
i.listener.IsReady()
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -73,18 +69,20 @@ func (i *RAWInput) listen(address string) {
|
|||||||
|
|
||||||
ch := i.listener.Receiver()
|
ch := i.listener.Receiver()
|
||||||
|
|
||||||
for {
|
go func(){
|
||||||
select {
|
for {
|
||||||
case <-i.quit:
|
select {
|
||||||
return
|
case <-i.quit:
|
||||||
default:
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receiving TCPMessage object
|
||||||
|
m := <-ch
|
||||||
|
|
||||||
|
i.data <- m
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
// Receiving TCPMessage object
|
|
||||||
m := <-ch
|
|
||||||
|
|
||||||
i.data <- m
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *RAWInput) String() string {
|
func (i *RAWInput) String() string {
|
||||||
|
|||||||
@@ -5,14 +5,18 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InOutPlugins struct for holding references to plugins
|
// InOutPlugins struct for holding references to plugins
|
||||||
type InOutPlugins struct {
|
type InOutPlugins struct {
|
||||||
Inputs []io.Reader
|
Inputs []io.Reader
|
||||||
Outputs []io.Writer
|
Outputs []io.Writer
|
||||||
|
All []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var pluginMu sync.Mutex
|
||||||
// Plugins holds all the plugin objects
|
// Plugins holds all the plugin objects
|
||||||
var Plugins *InOutPlugins = new(InOutPlugins)
|
var Plugins *InOutPlugins = new(InOutPlugins)
|
||||||
|
|
||||||
@@ -67,10 +71,15 @@ func registerPlugin(constructor interface{}, options ...interface{}) {
|
|||||||
if isW {
|
if isW {
|
||||||
Plugins.Outputs = append(Plugins.Outputs, pluginWrapper.(io.Writer))
|
Plugins.Outputs = append(Plugins.Outputs, pluginWrapper.(io.Writer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Plugins.All = append(Plugins.All, plugin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitPlugins specify and initialize all available plugins
|
// InitPlugins specify and initialize all available plugins
|
||||||
func InitPlugins() {
|
func InitPlugins() {
|
||||||
|
pluginMu.Lock()
|
||||||
|
defer pluginMu.Unlock()
|
||||||
|
|
||||||
for _, options := range Settings.inputDummy {
|
for _, options := range Settings.inputDummy {
|
||||||
registerPlugin(NewDummyInput, options)
|
registerPlugin(NewDummyInput, options)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ type Listener struct {
|
|||||||
messageExpire time.Duration
|
messageExpire time.Duration
|
||||||
|
|
||||||
conn net.PacketConn
|
conn net.PacketConn
|
||||||
|
pcapHandles []*pcap.Handle
|
||||||
|
|
||||||
quit chan bool
|
quit chan bool
|
||||||
readyCh chan bool
|
readyCh chan bool
|
||||||
}
|
}
|
||||||
@@ -279,7 +281,11 @@ func (t *Listener) readPcap() {
|
|||||||
}
|
}
|
||||||
defer handle.Close()
|
defer handle.Close()
|
||||||
|
|
||||||
bpf := "port " + strconv.Itoa(int(t.port))
|
t.mu.Lock()
|
||||||
|
t.pcapHandles = append(t.pcapHandles, handle)
|
||||||
|
t.mu.Unlock()
|
||||||
|
|
||||||
|
bpf := "tcp port " + strconv.Itoa(int(t.port))
|
||||||
|
|
||||||
// log.Println("Applying bpf programm:", bpf, " Device:", device.Name)
|
// log.Println("Applying bpf programm:", bpf, " Device:", device.Name)
|
||||||
if err := handle.SetBPFFilter(bpf); err != nil {
|
if err := handle.SetBPFFilter(bpf); err != nil {
|
||||||
@@ -287,6 +293,7 @@ func (t *Listener) readPcap() {
|
|||||||
wg.Done()
|
wg.Done()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// log.Println("BPF appplied", device.Name)
|
||||||
|
|
||||||
source := gopacket.NewPacketSource(handle, handle.LinkType())
|
source := gopacket.NewPacketSource(handle, handle.LinkType())
|
||||||
source.Lazy = true
|
source.Lazy = true
|
||||||
@@ -574,5 +581,10 @@ func (t *Listener) Close() {
|
|||||||
if t.conn != nil {
|
if t.conn != nil {
|
||||||
t.conn.Close()
|
t.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, h := range t.pcapHandles {
|
||||||
|
h.Close()
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ func TestRawListenerInput(t *testing.T) {
|
|||||||
respAck := reqPacket.Seq + uint32(len(reqPacket.Data))
|
respAck := reqPacket.Seq + uint32(len(reqPacket.Data))
|
||||||
respPacket := buildPacket(false, respAck, reqPacket.Seq+1, []byte("HTTP/1.1 200 OK\r\n\r\n"))
|
respPacket := buildPacket(false, respAck, reqPacket.Seq+1, []byte("HTTP/1.1 200 OK\r\n\r\n"))
|
||||||
|
|
||||||
listener.processTCPPacket(reqPacket)
|
listener.packetsChan <- reqPacket.Dump()
|
||||||
listener.processTCPPacket(respPacket)
|
listener.packetsChan <- respPacket.Dump()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case req = <-listener.messagesChan:
|
case req = <-listener.messagesChan:
|
||||||
@@ -56,8 +56,8 @@ func TestRawListenerResponse(t *testing.T) {
|
|||||||
respPacket := buildPacket(false, 1+uint32(len(reqPacket.Data)), 2, []byte("HTTP/1.1 200 OK\r\n\r\n"))
|
respPacket := buildPacket(false, 1+uint32(len(reqPacket.Data)), 2, []byte("HTTP/1.1 200 OK\r\n\r\n"))
|
||||||
|
|
||||||
// If response packet comes before request
|
// If response packet comes before request
|
||||||
listener.processTCPPacket(respPacket)
|
listener.packetsChan <- respPacket.Dump()
|
||||||
listener.processTCPPacket(reqPacket)
|
listener.packetsChan <- reqPacket.Dump()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case req = <-listener.messagesChan:
|
case req = <-listener.messagesChan:
|
||||||
@@ -102,12 +102,12 @@ func TestRawListener100Continue(t *testing.T) {
|
|||||||
// panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data))))
|
// panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data))))
|
||||||
respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n"))
|
respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n"))
|
||||||
|
|
||||||
listener.processTCPPacket(reqPacket1)
|
listener.packetsChan <- reqPacket1.Dump()
|
||||||
listener.processTCPPacket(reqPacket2)
|
listener.packetsChan <- reqPacket2.Dump()
|
||||||
listener.processTCPPacket(reqPacket3)
|
listener.packetsChan <- reqPacket3.Dump()
|
||||||
|
|
||||||
listener.processTCPPacket(respPacket1)
|
listener.packetsChan <- respPacket1.Dump()
|
||||||
listener.processTCPPacket(respPacket2)
|
listener.packetsChan <- respPacket2.Dump()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case req = <-listener.messagesChan:
|
case req = <-listener.messagesChan:
|
||||||
@@ -159,12 +159,12 @@ func TestRawListener100ContinueWrongOrder(t *testing.T) {
|
|||||||
// panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data))))
|
// panic(int(uint32(len(reqPacket1.Data)) + uint32(len(reqPacket2.Data)) + uint32(len(reqPacket3.Data))))
|
||||||
respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n"))
|
respPacket2 := buildPacket(false, reqPacket3.Seq+1 /* len of data */, 2, []byte("HTTP/1.1 200 OK\r\n"))
|
||||||
|
|
||||||
listener.processTCPPacket(respPacket1)
|
listener.packetsChan <- respPacket1.Dump()
|
||||||
listener.processTCPPacket(respPacket2)
|
listener.packetsChan <- respPacket2.Dump()
|
||||||
|
|
||||||
listener.processTCPPacket(reqPacket1)
|
listener.packetsChan <- reqPacket1.Dump()
|
||||||
listener.processTCPPacket(reqPacket2)
|
listener.packetsChan <- reqPacket2.Dump()
|
||||||
listener.processTCPPacket(reqPacket3)
|
listener.packetsChan <- reqPacket3.Dump()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case req = <-listener.messagesChan:
|
case req = <-listener.messagesChan:
|
||||||
@@ -386,7 +386,7 @@ func TestRawListenerBench(t *testing.T) {
|
|||||||
|
|
||||||
// Should re-construct message from all possible combinations
|
// Should re-construct message from all possible combinations
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
go func() {
|
go func(i int) {
|
||||||
for j := 0; j < 100; j++ {
|
for j := 0; j < 100; j++ {
|
||||||
var packets []*TCPPacket
|
var packets []*TCPPacket
|
||||||
|
|
||||||
@@ -412,7 +412,7 @@ func TestRawListenerBench(t *testing.T) {
|
|||||||
|
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}()
|
}(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := l.Receiver()
|
ch := l.Receiver()
|
||||||
|
|||||||
@@ -74,16 +74,18 @@ func (t *TCPPacket) ParseBasic() {
|
|||||||
|
|
||||||
func (t *TCPPacket) Dump() []byte {
|
func (t *TCPPacket) Dump() []byte {
|
||||||
buf := make([]byte, len(t.Data)+16+16)
|
buf := make([]byte, len(t.Data)+16+16)
|
||||||
|
copy(buf[:16], t.Addr)
|
||||||
|
|
||||||
tcpBuf := buf[16:]
|
tcpBuf := buf[16:]
|
||||||
|
|
||||||
binary.BigEndian.PutUint16(tcpBuf[2:4], t.DestPort)
|
binary.BigEndian.PutUint16(tcpBuf[2:4], t.DestPort)
|
||||||
binary.BigEndian.PutUint16(buf[0:2], t.SrcPort)
|
binary.BigEndian.PutUint16(tcpBuf[0:2], t.SrcPort)
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(buf[4:8], t.Seq)
|
binary.BigEndian.PutUint32(tcpBuf[4:8], t.Seq)
|
||||||
binary.BigEndian.PutUint32(buf[8:12], t.Ack)
|
binary.BigEndian.PutUint32(tcpBuf[8:12], t.Ack)
|
||||||
|
|
||||||
tcpBuf[16] = 64
|
tcpBuf[12] = 64
|
||||||
copy(tcpBuf[20:], t.Data)
|
copy(tcpBuf[16:], t.Data)
|
||||||
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user