Skip to content

Commit 12c8535

Browse files
committed
Better logging.
1 parent cedec4b commit 12c8535

9 files changed

Lines changed: 333 additions & 188 deletions

File tree

decoders.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,13 @@ type Event struct {
5858
SourcePort uint16
5959
DestAddr string
6060
DestPort uint16
61+
62+
// The original event.
63+
Original string
6164
}
6265

6366
func (e *Event) ToPcapFilter() string {
67+
6468
return fmt.Sprintf(
6569
"proto %s and ((host %s and port %d) and (host %s and port %d))",
6670
e.Protocol,
@@ -69,6 +73,7 @@ func (e *Event) ToPcapFilter() string {
6973
}
7074

7175
func DecodeSnortFastEventTimestamp(buf string) string {
76+
7277
matches := snortFastTimestampPattern.FindStringSubmatch(buf)
7378
if matches == nil {
7479
return ""
@@ -85,6 +90,7 @@ func DecodeSnortFastEventTimestamp(buf string) string {
8590
// DecodeSnortFastEvent will decode Snort and Suricata "fast" style
8691
// events.
8792
func DecodeSnortFastEvent(buf string) *Event {
93+
8894
eventMatches := snortFastEventRegexp.FindStringSubmatch(buf)
8995
if eventMatches == nil {
9096
if parsers_debug {
@@ -120,11 +126,13 @@ func DecodeSnortFastEvent(buf string) *Event {
120126
SourcePort: (uint16)(sourcePort),
121127
DestAddr: eventMatches[4],
122128
DestPort: (uint16)(destPort),
129+
Original: buf,
123130
}
124131
}
125132

126133
// DecodeSuricataJsonEvent decodes a Suricata style JSON event.
127134
func DecodeSuricataJsonEvent(buf string) *Event {
135+
128136
suricataJsonEvent := SuricataJsonEvent{}
129137

130138
if err := json.Unmarshal(([]byte)(buf), &suricataJsonEvent); err != nil {
@@ -134,15 +142,14 @@ func DecodeSuricataJsonEvent(buf string) *Event {
134142
return nil
135143
}
136144

137-
log.Println(suricataJsonEvent)
138-
139145
return &Event{
140146
Timestamp: suricataJsonEvent.Timestamp,
141147
Protocol: suricataJsonEvent.Protocol,
142148
SourceAddr: suricataJsonEvent.SourceAddr,
143149
SourcePort: suricataJsonEvent.SourcePort,
144150
DestAddr: suricataJsonEvent.DestAddr,
145151
DestPort: suricataJsonEvent.DestPort,
152+
Original: buf,
146153
}
147154
}
148155

@@ -153,5 +160,5 @@ func DecodeEvent(buf string) (*Event, error) {
153160
if event := DecodeSnortFastEvent(buf); event != nil {
154161
return event, nil
155162
}
156-
return nil, fmt.Errorf("unable to decode event")
163+
return nil, fmt.Errorf("error: event not recognized by any decoders")
157164
}

dumper.go renamed to dumper/dumper.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
2525
// OF THE POSSIBILITY OF SUCH DAMAGE.
2626

27-
package main
27+
package dumper
2828

2929
import (
3030
"flag"
@@ -37,6 +37,8 @@ import (
3737
"dumpy/libpcap"
3838
)
3939

40+
var verbose bool = false
41+
4042
func getStartSeconds(filename string) (int64, error) {
4143
var seconds int64
4244
pcap, err := libpcap.OpenOffline(filename)
@@ -117,6 +119,7 @@ func DumperMain(args []string) {
117119
"start time in unix time (seconds)")
118120
flagset.Int64Var(&duration, "duration", 0, "duration of capture (seconds)")
119121
flagset.StringVar(&filter, "filter", "", "bpf filter expression")
122+
flagset.BoolVar(&verbose, "verbose", false, "be more verbose")
120123
flagset.Parse(args)
121124

122125
if directory == "" || prefix == "" {
@@ -135,7 +138,9 @@ func DumperMain(args []string) {
135138
var dumper *libpcap.Dumper
136139

137140
for _, file := range files {
138-
log.Printf("opening file %s", file.Name())
141+
if verbose {
142+
log.Printf("opening file %s", file.Name())
143+
}
139144
pcap, err := libpcap.OpenOffline(path.Join(directory, file.Name()))
140145
if err != nil {
141146
log.Fatal(err)

logger.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright (c) 2014 Jason Ish. All rights reserved.
2+
//
3+
// Redistribution and use in source and binary forms, with or without
4+
// modification, are permitted provided that the following conditions
5+
// are met:
6+
//
7+
// 1. Redistributions of source code must retain the above copyright
8+
// notice, this list of conditions and the following disclaimer.
9+
//
10+
// 2. Redistributions in binary form must reproduce the above
11+
// copyright notice, this list of conditions and the following
12+
// disclaimer in the documentation and/or other materials provided
13+
// with the distribution.
14+
//
15+
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
16+
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17+
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18+
// DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19+
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22+
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23+
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
25+
// OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
package main
28+
29+
import (
30+
"fmt"
31+
"log"
32+
"net/http"
33+
"os"
34+
"strings"
35+
36+
"github.com/gorilla/context"
37+
)
38+
39+
// Logger is a wrapper around the standard logger that implements some
40+
// http.Request aware functions.
41+
type Logger struct {
42+
*log.Logger
43+
}
44+
45+
func NewLogger(prefix string) *Logger {
46+
return &Logger{log.New(os.Stderr, prefix, log.Ldate|log.Ltime)}
47+
}
48+
49+
func (l *Logger) PrintfWithRequest(r *http.Request, format string, v ...interface{}) {
50+
l.Printf("[%s@%s] %s",
51+
context.Get(r, "username"),
52+
l.getRemoteAddr(r),
53+
fmt.Sprintf(format, v...))
54+
}
55+
56+
func (l *Logger) PrintWithRequest(r *http.Request, v ...interface{}) {
57+
l.Printf("[%s@%s] %s",
58+
context.Get(r, "username"),
59+
l.getRemoteAddr(r),
60+
fmt.Sprint(v...))
61+
}
62+
63+
// getRemoteAddr gets the remote address of the request without the
64+
// port information.
65+
func (l *Logger) getRemoteAddr(r *http.Request) string {
66+
return strings.Split(r.RemoteAddr, ":")[0]
67+
}

main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@
2727
package main
2828

2929
import (
30+
"dumpy/dumper"
3031
"flag"
3132
"fmt"
3233
"os"
3334
)
3435

36+
// Global logger.
37+
var logger = NewLogger("")
38+
3539
func Usage() {
3640
fmt.Printf(`
3741
Usage: dumpy [options] <command>
@@ -64,7 +68,7 @@ func main() {
6468
case "version":
6569
fmt.Println(VERSION)
6670
case "dump":
67-
DumperMain(os.Args[2:])
71+
dumper.DumperMain(os.Args[2:])
6872
case "config":
6973
ConfigMain(NewConfig(configFilename), os.Args[2:])
7074
case "start":

web-authenticator.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"log"
3232
"net/http"
3333
"strings"
34+
"github.com/gorilla/context"
3435

3536
"code.google.com/p/go.crypto/bcrypt"
3637
)
@@ -54,6 +55,13 @@ type Authenticator struct {
5455
users map[string]string
5556
}
5657

58+
func NewAuthenticator(config *Config) *Authenticator {
59+
if len(config.Users) == 0 {
60+
logger.Printf("WARNING: No users configuration. Authentication disabled.")
61+
}
62+
return &Authenticator{config.Users}
63+
}
64+
5765
func (a *Authenticator) GetUsernameAndPassword(authHeader string) (string, string) {
5866
parts := strings.SplitN(authHeader, " ", 2)
5967
if len(parts) == 2 {
@@ -85,11 +93,16 @@ func (a *Authenticator) CheckUsernameAndPassword(username string, password strin
8593
}
8694

8795
func (a *Authenticator) authenticate(request *http.Request) bool {
96+
if len(a.users) == 0 {
97+
context.Set(request, "username", "<anonymous>")
98+
return true
99+
}
88100
authHeader := request.Header.Get("authorization")
89101
if authHeader != "" {
90102
username, password := a.GetUsernameAndPassword(authHeader)
91103
if username != "" {
92104
if a.CheckUsernameAndPassword(username, password) {
105+
context.Set(request, "username", username)
93106
return true
94107
}
95108
}

web-fetch-handler.go

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ package main
2929
import (
3030
"bufio"
3131
"fmt"
32-
"log"
32+
"io"
3333
"net/http"
3434
"os"
3535
"os/exec"
@@ -66,20 +66,26 @@ type FetchHandler struct {
6666
}
6767

6868
func (h *FetchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
69-
if r.FormValue("event") != "" {
70-
h.HandleEventRequest(w, r)
71-
} else if r.FormValue("filter") != "" {
69+
70+
queryType := r.FormValue("query-type")
71+
72+
switch queryType {
73+
case "pcap-filter":
7274
h.HandleFilterRequest(w, r)
73-
} else {
74-
http.Error(w, "Missing fetch request type (filter or event)",
75-
http.StatusBadRequest)
75+
case "event":
76+
h.HandleEventRequest(w, r)
77+
case "":
78+
HttpErrorAndLog(w, r, http.StatusBadRequest,
79+
"Missing query-type parameter.")
80+
default:
81+
HttpErrorAndLog(w, r, http.StatusBadRequest,
82+
"Unknown query-type: %s", queryType)
7683
}
7784
}
7885

7986
func (h *FetchHandler) HandleFilterRequest(w http.ResponseWriter, r *http.Request) {
8087

8188
filter := r.FormValue("filter")
82-
8389
argStartTime := r.FormValue("start-time")
8490
argDuration := r.FormValue("duration")
8591
argSpool := r.FormValue("spool")
@@ -115,6 +121,13 @@ func (h *FetchHandler) HandleFilterRequest(w http.ResponseWriter, r *http.Reques
115121
return
116122
}
117123

124+
logger.PrintfWithRequest(r, "Preparing dumper request: %s",
125+
map[string]string{
126+
"start-time": startTime.String(),
127+
"duration": duration.String(),
128+
"pcap-filter": filter,
129+
})
130+
118131
dumperArgs := []string{
119132
"-directory", spool.Directory,
120133
"-prefix", spool.Prefix,
@@ -127,9 +140,9 @@ func (h *FetchHandler) HandleFilterRequest(w http.ResponseWriter, r *http.Reques
127140

128141
func (h *FetchHandler) HandleEventRequest(w http.ResponseWriter, r *http.Request) {
129142

130-
event, _ := DecodeEvent(r.FormValue("event"))
131-
if event == nil {
132-
http.Error(w, "failed to decode event", http.StatusBadRequest)
143+
event, err := DecodeEvent(r.FormValue("event"))
144+
if err != nil {
145+
HttpErrorAndLog(w, r, http.StatusBadRequest, err.Error())
133146
return
134147
}
135148

@@ -168,6 +181,14 @@ func (h *FetchHandler) HandleEventRequest(w http.ResponseWriter, r *http.Request
168181
return
169182
}
170183

184+
logger.PrintfWithRequest(r, "Preparing dumper request: %s",
185+
map[string]string{
186+
"start-time": startTime.String(),
187+
"duration": duration.String(),
188+
"pcap-filter": event.ToPcapFilter(),
189+
"event": event.Original,
190+
})
191+
171192
dumperArgs := []string{
172193
"-directory", spool.Directory,
173194
"-prefix", spool.Prefix,
@@ -204,23 +225,27 @@ func (h *FetchHandler) RunDumper(w http.ResponseWriter, r *http.Request, args []
204225
if err != nil {
205226
break
206227
}
207-
log.Printf("dumpy dumper (stderr): %s", line)
228+
logger.Printf("dumpy dumper [%d] (stderr) %s", dumper.Process.Pid, line)
208229
}
209230
}()
210231

211232
err = dumper.Start()
212233
if err != nil {
213-
http.Error(w, "failed to execute dumper: "+err.Error(),
214-
http.StatusInternalServerError)
234+
HttpErrorAndLog(w, r, http.StatusInternalServerError,
235+
"failed to execute dumper: %s", err)
215236
return
216237
}
238+
logger.PrintfWithRequest(r, "dumper with pid %d started: %s",
239+
dumper.Process.Pid, dumper.Args)
217240

218241
bytesWritten := 0
219242
for {
220243
buf := make([]byte, 8192)
221244
n, err := stdout.Read(buf)
222245
if err != nil {
223-
log.Print(err)
246+
if err != io.EOF {
247+
logger.PrintfWithRequest(r, "unexpected dump error: %s", err)
248+
}
224249
break
225250
}
226251

@@ -231,13 +256,17 @@ func (h *FetchHandler) RunDumper(w http.ResponseWriter, r *http.Request, args []
231256
}
232257
n, err = w.Write(buf[0:n])
233258
if err != nil {
234-
log.Printf("write to client failed: %s", err)
259+
logger.PrintfWithRequest(r,
260+
"Write failed; client may have disconnected: %s", err)
235261
break
236262
}
237263
bytesWritten += n
238264
}
239265

240266
if bytesWritten == 0 {
241267
http.Error(w, "No packets found.", http.StatusNotFound)
268+
} else {
269+
logger.PrintfWithRequest(r, "Wrote %d bytes of packet data",
270+
bytesWritten)
242271
}
243272
}

0 commit comments

Comments
 (0)