Skip to content

Commit

Permalink
Add source code
Browse files Browse the repository at this point in the history
  • Loading branch information
raypereda committed May 3, 2019
1 parent 35c3df0 commit 98553f9
Show file tree
Hide file tree
Showing 18 changed files with 1,257 additions and 1 deletion.
77 changes: 76 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,77 @@
# wiredog
a terminal-based monitor of local HTTP traffic

Wiredog monitors the local HTTP traffic by scanning the
network packets. All network interfaces are monitored.
At least one active interface is needed.

When the requests rate for a given period exceeds a
threshold, an alert message is displayed. The top 10
website sections ordered by number of requests are displayed.

Working and tested on Linux. OSX and Windows support is planned.

<p align="center">
<img src="wiredog-demo.gif" width="800">
</p>

```
$ wiredog -help
Wiredog is a tool for monitoring network traffic.
Only local HTTP requests are studied.
Administrator permission is required to access network devices.
Consider using sudo on Linux or get admin rights on Windows.
Usage: sudo \path\to\wiredog [flags]
-assembly_debug_log
If true, the github.com/google/gopacket/tcpassembly library will log verbose debugging information (at least one line per packet)
-assembly_memuse_log
If true, the github.com/google/gopacket/tcpassembly library will log information regarding its memory use every once in a while.
-d string
network device name (default "wlp2s0")
-h int
threshold of HTTP request hits (default 2)
-log string
log directory (default ".")
-p duration
time period between traffic checks (default 2m0s)
-t generates test HTTP requests; sets h=2 and p=2s
```

## Built With (from go.mod file)
```
Go 1.12
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c
github.com/gizak/termui v2.3.0+incompatible // indirect
github.com/gizak/termui/v3 v3.0.0
github.com/google/gopacket v1.1.16
github.com/maruel/panicparse v1.1.1 // indirect
github.com/mattn/go-runewidth v0.0.4 // indirect
github.com/mdlayher/raw v0.0.0-20190419142535-64193704e472 // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/nsf/termbox-go v0.0.0-20190325093121-288510b9734e // indirect
github.com/onsi/ginkgo v1.8.0 // indirect
github.com/onsi/gomega v1.5.0 // indirect
github.com/pkg/errors v0.8.1
github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc // indirect
```

## Thanks

gopacket and termui are cool Go packages. And of course, the Go programming language is beautiful.

## Useful links

https://www.devdungeon.com/content/packet-capture-injection-and-analysis-gopacket

https://medium.com/@cjoudrey/capturing-http-packets-the-hard-way-b9c799bfb6

https://stackoverflow.com/questions/21145781/how-do-you-use-the-tcp-assembly-package-in-gopacket



159 changes: 159 additions & 0 deletions cmd/wiredog/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Wiredog is a command for network monitoring.
package main

import (
"flag"
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"

"code.cloudfoundry.org/clock"
ui "github.com/gizak/termui/v3"
"github.com/raypereda/wiredog/pkg/alerts"
asm "github.com/raypereda/wiredog/pkg/httpassembler"
"github.com/raypereda/wiredog/pkg/screens"
"github.com/raypereda/wiredog/pkg/stats"
)

var (
device string
hitThreshold int
logDirectory string
alertInterval time.Duration
testRequests bool
)

func settings() string {
var sb strings.Builder
fmt.Fprintf(&sb, "Alert Interval : %s\n", alertInterval)
fmt.Fprintf(&sb, "Hit Threshold : %d\n", hitThreshold)
fmt.Fprintf(&sb, "Network Interface : %s\n", device)
absDirectory, err := filepath.Abs(logDirectory)
if err != nil {
log.Fatalf("error getting absolute path for %s: %v", logDirectory, err)
}
logDirectory = absDirectory
fmt.Fprintf(&sb, "Log Directory : %8s\n", logDirectory)
return sb.String()
}

// Usage prints usage, overwrites default
var Usage = func() {
fmt.Fprintln(flag.CommandLine.Output(), "Wiredog is a tool for monitoring network traffic.")
fmt.Fprintln(flag.CommandLine.Output())
fmt.Fprintln(flag.CommandLine.Output(), "Only local HTTP requests are studied.")
fmt.Fprintln(flag.CommandLine.Output(), "Administrator permission is required to access network devices.")
fmt.Fprintln(flag.CommandLine.Output(), "Consider using sudo on Linux or get admin rights on Windows.")
fmt.Fprintln(flag.CommandLine.Output())
fmt.Fprintln(flag.CommandLine.Output(), "Usage: sudo \\path\\to\\wiredog [flags]")
fmt.Fprintln(flag.CommandLine.Output())
flag.PrintDefaults()
}

func main() {
// other network devices on my laptop: lo, enp0s31f6, but they don't work in promiscuous mode
flag.StringVar(&device, "d", "wlp2s0", "network device name")
flag.IntVar(&hitThreshold, "h", 2, "threshold of HTTP request hits")
flag.StringVar(&logDirectory, "log", ".", "log directory")
flag.DurationVar(&alertInterval, "p", 2*time.Minute, "time period between traffic checks")
flag.BoolVar(&testRequests, "t", false, "generates test HTTP requests; sets h=2 and p=2s")
flag.Usage = Usage
flag.Parse()

logFile := logDirectory + "/wiredog.log"
f, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer f.Close()
log.SetOutput(f)

if err := ui.Init(); err != nil {
log.Fatalf("failed to initialize termui: %v", err)
}
defer ui.Close()

if testRequests {
hitThreshold = 5
alertInterval = 2 * time.Second
go makeTestRequests()
}

requests := make(chan *http.Request) // receiver of requests
asm, err := asm.NewHTTPAssembler(device, requests)
if err != nil {
log.Fatalln("error connecting to network devices", err)
}
go asm.Run()

s := screens.New(settings())

clock := clock.NewClock()
hist := alerts.NewHistory(clock, alertInterval)
// BUGFIX: avoid sharing screen state with alert, need to rethink
alert := alerts.New(clock, hist, alertInterval, hitThreshold, s)
go alert.Run()

metrics := stats.New()
go func() {
for {
r := <-requests
metrics.Tally(r) // collects statistics
hist.Record(r) // keep history for alerter
}
}()

go func() {
ticker := time.NewTicker(time.Second)
for {
<-ticker.C
s.UpdateTopN(metrics.GetTopSections())
s.Render()
}
}()

go func() {
ticker := time.NewTicker(alertInterval)
for {
<-ticker.C
count := float64(hist.RecentRequestCount())
s.AddRequestCount(count)
s.Render()
}
}()

s.Start()
log.Println("Stopped monitoring.")
}

func get(url string) {
_, _ = http.Get(url)
}

func makeTestRequests() {
time.Sleep(1 * time.Second) // allow alerts to setup
get("http://example1.com")
get("http://example2.com/sectionA/")
get("http://example2.com/sectionA/")
get("http://example3.com")
get("http://example3.com")
get("http://example3.com")

for {
time.Sleep(time.Second)
get("http://example4.com")
get("http://example4.com")
get("http://example4.com")
get("http://example4.com")
time.Sleep(time.Second)
get("http://example5.com")
get("http://example5.com")
get("http://example5.com")
get("http://example5.com")
get("http://example5.com")
}
}
Binary file added cmd/wiredog/wiredog
Binary file not shown.
Loading

0 comments on commit 98553f9

Please sign in to comment.