|
@@ -2,8 +2,10 @@ package main
|
|
|
|
|
|
import (
|
|
import (
|
|
"bufio"
|
|
"bufio"
|
|
|
|
+ "bytes"
|
|
"crypto/sha1"
|
|
"crypto/sha1"
|
|
"encoding/csv"
|
|
"encoding/csv"
|
|
|
|
+ "encoding/json"
|
|
"flag"
|
|
"flag"
|
|
"fmt"
|
|
"fmt"
|
|
"io"
|
|
"io"
|
|
@@ -51,6 +53,7 @@ var (
|
|
nginxLog = flag.String("nginx-log", "", "Nginx log file to tail")
|
|
nginxLog = flag.String("nginx-log", "", "Nginx log file to tail")
|
|
nginxFormat = flag.String("nginx-format", "", "The nginx log file format")
|
|
nginxFormat = flag.String("nginx-format", "", "The nginx log file format")
|
|
hostName = flag.String("hostname", "", "Override the captured hostname with this one")
|
|
hostName = flag.String("hostname", "", "Override the captured hostname with this one")
|
|
|
|
+ accessWatchKey = flag.String("access-watch-key", "", "access.watch API key")
|
|
configFile = flag.String("config", "", "The location of the TOML config file")
|
|
configFile = flag.String("config", "", "The location of the TOML config file")
|
|
|
|
|
|
beQuiet = flag.Bool("quiet", true, "Be quiet")
|
|
beQuiet = flag.Bool("quiet", true, "Be quiet")
|
|
@@ -94,6 +97,7 @@ type Config struct {
|
|
NginxLog string
|
|
NginxLog string
|
|
NginxLogFormat string
|
|
NginxLogFormat string
|
|
HostName string
|
|
HostName string
|
|
|
|
+ AccessWatchKey string
|
|
}
|
|
}
|
|
|
|
|
|
type duration struct {
|
|
type duration struct {
|
|
@@ -122,7 +126,8 @@ func (c Config) print() {
|
|
fmt.Printf("Apache Log: %s\n", c.ApacheLog)
|
|
fmt.Printf("Apache Log: %s\n", c.ApacheLog)
|
|
fmt.Printf("Nginx Log: %s\n", c.NginxLog)
|
|
fmt.Printf("Nginx Log: %s\n", c.NginxLog)
|
|
fmt.Printf("Nginx Log Format: %s\n", c.NginxLogFormat)
|
|
fmt.Printf("Nginx Log Format: %s\n", c.NginxLogFormat)
|
|
- fmt.Printf("HostName: %s\n", c.HostName)
|
|
|
|
|
|
+ fmt.Printf("HostName: %s\n", c.HostName)
|
|
|
|
+ fmt.Printf("AccessWatchKey: %s\n", c.AccessWatchKey)
|
|
fmt.Printf("UseXForwardedAsSource: %t\n", c.UseXForwardedAsSource)
|
|
fmt.Printf("UseXForwardedAsSource: %t\n", c.UseXForwardedAsSource)
|
|
fmt.Printf("Protocol: %s\n", c.Protocol)
|
|
fmt.Printf("Protocol: %s\n", c.Protocol)
|
|
fmt.Printf("Quiet: %t\n", c.Quiet)
|
|
fmt.Printf("Quiet: %t\n", c.Quiet)
|
|
@@ -156,7 +161,7 @@ func main() {
|
|
|
|
|
|
// NATS
|
|
// NATS
|
|
//
|
|
//
|
|
- if config.NatsURL == "" {
|
|
|
|
|
|
+ if config.NatsURL == "" && config.AccessWatchKey == "" {
|
|
log.Fatal("No NATS URL specified (-nats-url)!")
|
|
log.Fatal("No NATS URL specified (-nats-url)!")
|
|
}
|
|
}
|
|
|
|
|
|
@@ -164,7 +169,7 @@ func main() {
|
|
natsErrorChan = make(chan error, 1)
|
|
natsErrorChan = make(chan error, 1)
|
|
|
|
|
|
err := connectToNATS()
|
|
err := connectToNATS()
|
|
- if err != nil {
|
|
|
|
|
|
+ if err != nil && config.AccessWatchKey == "" {
|
|
log.Fatal(err)
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -443,7 +448,84 @@ func liveCapture() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func writeLogToWatch(r *data.Request) {
|
|
|
|
+ h := map[string]string{}
|
|
|
|
+
|
|
|
|
+ if r.AcceptEncoding != "" {
|
|
|
|
+ h["Accept-Encoding"] = r.AcceptEncoding
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.Accept != "" {
|
|
|
|
+ h["Accept"] = r.Accept
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.AcceptLanguage != "" {
|
|
|
|
+ h["Accept-Language"] = r.AcceptLanguage
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.Cookie != "" {
|
|
|
|
+ h["Cookie"] = r.Cookie
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.Host != "" {
|
|
|
|
+ h["Host"] = r.Host
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.Referer != "" {
|
|
|
|
+ h["Referer"] = r.Referer
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.UserAgent != "" {
|
|
|
|
+ h["User-Agent"] = r.UserAgent
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.Via != "" {
|
|
|
|
+ h["Via"] = r.Via
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.XForwardedFor != "" {
|
|
|
|
+ h["X-Forwarded-For"] = r.XForwardedFor
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if r.XRequestedWith != "" {
|
|
|
|
+ h["X-Requested-With"] = r.XRequestedWith
|
|
|
|
+ }
|
|
|
|
+ if r.XRequestedWith != "" {
|
|
|
|
+ h["X-Requested-With"] = r.XRequestedWith
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ data := map[string]interface{}{
|
|
|
|
+ "request": map[string]interface{}{
|
|
|
|
+ "time": time.Unix(0, r.CreatedAt),
|
|
|
|
+ "address": r.Source,
|
|
|
|
+ // "scheme": r.Protocol,
|
|
|
|
+ "method": r.Method,
|
|
|
|
+ "url": r.Url,
|
|
|
|
+ "headers": h,
|
|
|
|
+ },
|
|
|
|
+ "response": map[string]interface{}{"status": 200},
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ jdata, err := json.Marshal(data)
|
|
|
|
+
|
|
|
|
+ client := &http.Client{}
|
|
|
|
+
|
|
|
|
+ buf := bytes.NewBuffer(jdata)
|
|
|
|
+ req, err := http.NewRequest("POST", "https://log.access.watch/1.1/log", buf)
|
|
|
|
+ req.Header.Add("Api-Key", *accessWatchKey)
|
|
|
|
+ resp, err := client.Do(req)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println(err)
|
|
|
|
+ }
|
|
|
|
+ resp.Body.Close()
|
|
|
|
+}
|
|
|
|
+
|
|
func publishRequest(queue string, request *data.Request) {
|
|
func publishRequest(queue string, request *data.Request) {
|
|
|
|
+ if config.AccessWatchKey != "" {
|
|
|
|
+ writeLogToWatch(request)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
if !natsIsAvailable {
|
|
if !natsIsAvailable {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
@@ -454,6 +536,7 @@ func publishRequest(queue string, request *data.Request) {
|
|
natsIsAvailable = false
|
|
natsIsAvailable = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
// processPacket receives a raw packet from pcap, builds a Request item from it and sends it to the queue
|
|
// processPacket receives a raw packet from pcap, builds a Request item from it and sends it to the queue
|
|
@@ -772,6 +855,7 @@ func loadConfig() {
|
|
config.HostName = *hostName
|
|
config.HostName = *hostName
|
|
config.Quiet = *beQuiet
|
|
config.Quiet = *beQuiet
|
|
config.Trace = *trace
|
|
config.Trace = *trace
|
|
|
|
+ config.AccessWatchKey = *accessWatchKey
|
|
|
|
|
|
if *configFile == "" {
|
|
if *configFile == "" {
|
|
return
|
|
return
|