/
sot.go
150 lines (125 loc) · 3.15 KB
/
sot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package main
// Sound of Traffic (2) server
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
es "github.com/antage/eventsource"
pcap "github.com/miekg/pcap"
)
func main() {
device := flag.String("i", "", "network device")
port := flag.String("p", "8000", "http server port (default 8000)")
flag.Parse()
if *device == "" {
flag.PrintDefaults()
printDevices()
} else {
startServer(device, port)
}
}
// Prints a list of available network devices to console
func printDevices() {
devs, err := pcap.FindAllDevs()
if len(devs) == 0 {
fmt.Printf("Error: no network devices found. %s\n", err)
} else {
fmt.Println("Available network devices")
for _, dev := range devs {
fmt.Printf(" %s \n", dev.Name)
}
}
}
func startServer(device *string, port *string) {
sm := make(SourceMap)
for _, t := range []string{"tcp", "udp"} {
defer sm.Add(t).Close()
http.Handle(sm[t].url, sm[t].es)
}
http.Handle("/sources", sm)
http.Handle("/", http.FileServer(http.Dir("./pub")))
go openDevice(device, port, sm)
log.Printf("Opening server at localhost:%s and listening for %s\n", *port, *device)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}
// Source is is
type Source struct {
es es.EventSource
label string
url string
}
// SourceMap Maps the type (TCP, UDP, ARP, etc) to an event source
type SourceMap map[string]Source
// Add binds an event source to a packet type (ie TCP)
// creates an http handler to allow subscription to the packet type
func (sm SourceMap) Add(label string) es.EventSource {
c := Source{
es: es.New(nil, nil),
label: label,
url: "/pcap/" + label + "/"}
sm[label] = c
return c.es
}
// ServeHTTP display the available sources as json
func (sm SourceMap) ServeHTTP(w http.ResponseWriter, r *http.Request) {
o := make(map[string]string)
for k := range sm {
o[k] = sm[k].url
}
m, _ := json.Marshal(o)
fmt.Fprintf(w, "%s", m)
}
func openDevice(device *string, port *string, sm SourceMap) {
h, err := pcap.OpenLive(*device, 65535, true, 100)
if h == nil {
fmt.Printf("Failed to open %s : %s\n", *device, err)
} else {
h.SetFilter("not port " + *port)
for pkt := h.Next(); ; pkt = h.Next() {
if pkt != nil {
sm.process(pkt)
}
}
log.Println("timeout")
}
}
type ports struct {
SrcPort uint16
DestPort uint16
}
type addrHdr interface {
SrcAddr() string
DestAddr() string
Len() int
}
func (sm SourceMap) process(pkt *pcap.Packet) {
pkt.Decode()
if len(pkt.Headers) >= 2 {
if addr, ok := pkt.Headers[0].(addrHdr); ok {
sm.route(pkt, &addr)
}
}
}
func (sm SourceMap) route(pkt *pcap.Packet, addr *addrHdr) {
switch k := pkt.Headers[1].(type) {
case *pcap.Tcphdr:
f := &ports{k.SrcPort, k.DestPort}
sm["tcp"].send(addr, f)
case *pcap.Udphdr:
f := &ports{k.SrcPort, k.DestPort}
sm["udp"].send(addr, f)
default:
log.Printf("%T", k)
}
}
func (s Source) send(addr *addrHdr, port *ports) {
m := msg(*addr, port)
s.es.SendEventMessage(m, "", "")
}
// Create the string representing the packet
// this is what gets sent to the browser
func msg(addr addrHdr, k *ports) string {
return fmt.Sprintf("%s:%d %s:%d", addr.SrcAddr(), int(k.SrcPort), addr.DestAddr(), int(k.DestPort))
}