diff --git a/.gitignore b/.gitignore index 66fd13c..a756998 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,5 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib +# Log files +*.log -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ +# Binary +analyzer-d4-log diff --git a/conf.sample/http_server b/conf.sample/http_server new file mode 100644 index 0000000..f14f35d --- /dev/null +++ b/conf.sample/http_server @@ -0,0 +1 @@ +127.0.0.1:8080 diff --git a/conf.sample/redis b/conf.sample/redis new file mode 100644 index 0000000..5d6f103 --- /dev/null +++ b/conf.sample/redis @@ -0,0 +1 @@ +localhost:6380/2 diff --git a/conf.sample/redis_queue b/conf.sample/redis_queue new file mode 100644 index 0000000..998486e --- /dev/null +++ b/conf.sample/redis_queue @@ -0,0 +1 @@ +0894517855f047d2a77b4473d3a9cc5b diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..134cdf0 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/D4-project/analyzer-d4-log + +go 1.13 + +require ( + github.com/D4-project/d4-golang-utils v0.0.0-20200108150548-740f16240125 + github.com/gomodule/redigo v2.0.0+incompatible +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5a928c3 --- /dev/null +++ b/go.sum @@ -0,0 +1,5 @@ +github.com/D4-project/d4-golang-utils v0.0.0-20200108150548-740f16240125 h1:iv+hcdT+M0XJIDEoCtvk9HVvI8PgvbQNBtbEfCczCRI= +github.com/D4-project/d4-golang-utils v0.0.0-20200108150548-740f16240125/go.mod h1:2rq8KBQnNNDocwc/49cnpaqoQA/komoSHKom7ynvqJc= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= diff --git a/logparser/parser.go b/logparser/parser.go new file mode 100644 index 0000000..cc77ae1 --- /dev/null +++ b/logparser/parser.go @@ -0,0 +1 @@ +package logparser diff --git a/logparser/parser_test.go b/logparser/parser_test.go new file mode 100644 index 0000000..62556e2 --- /dev/null +++ b/logparser/parser_test.go @@ -0,0 +1,77 @@ +package logparser + +import ( + "bufio" + "fmt" + "log" + "os" + "regexp" + "testing" +) + +var expected = map[int]map[string]string{ + 0: map[string]string{ + "date": "Jan 22 11:59:37", + "host": "sigmund", + "username": "git", + "src": "106.12.14.144", + }, + 1: map[string]string{ + "date": "Jan 22 11:37:19", + "host": "sigmund", + "username": "gestion", + "src": "159.89.153.54", + }, + 2: map[string]string{ + "date": "Jan 22 11:34:46", + "host": "sigmund", + "username": "atpco", + "src": "177.152.124.21", + }, + 3: map[string]string{ + "date": "Jan 22 11:33:07", + "host": "sigmund", + "username": "ki", + "src": "49.233.183.158", + }, + 4: map[string]string{ + "date": "Jan 22 11:29:16", + "host": "sigmund", + "username": "admin", + "src": "185.56.8.191", + }, +} + +func TestSshdParser(t *testing.T) { + // Opening sshd test file + fmt.Println("[+] Testing the sshd log parser") + f, err := os.Open("./test.log") + if err != nil { + log.Fatalf("Error opening test file: %v", err) + } + defer f.Close() + scanner := bufio.NewScanner(f) + c := 0 + for scanner.Scan() { + re := regexp.MustCompile(`^(?P[[:alpha:]]{3}\s\d{2}\s\d{2}:\d{2}:\d{2}) (?P[[:word:]]+) sshd\[[[:alnum:]]+\]: Invalid user (?P[[:word:]]+) from (?P.*$)`) + n1 := re.SubexpNames() + r2 := re.FindAllStringSubmatch(scanner.Text(), -1)[0] + + // Build the group map for the line + md := map[string]string{} + for i, n := range r2 { + // fmt.Printf("%d. match='%s'\tname='%s'\n", i, n, n1[i]) + md[n1[i]] = n + } + + // Check against the expected map + for _, n := range n1 { + if n != "" { + if md[n] != expected[c][n] { + t.Errorf("%v = '%v'; want '%v'", n, md[n], expected[c][n]) + } + } + } + c++ + } +} diff --git a/logparser/test.log b/logparser/test.log new file mode 100644 index 0000000..bc9bcf4 --- /dev/null +++ b/logparser/test.log @@ -0,0 +1,5 @@ +Jan 22 11:59:37 sigmund sshd[26514]: Invalid user git from 106.12.14.144 +Jan 22 11:37:19 sigmund sshd[26143]: Invalid user gestion from 159.89.153.54 +Jan 22 11:34:46 sigmund sshd[26125]: Invalid user atpco from 177.152.124.21 +Jan 22 11:33:07 sigmund sshd[26109]: Invalid user ki from 49.233.183.158 +Jan 22 11:29:16 sigmund sshd[26091]: Invalid user admin from 185.56.8.191 diff --git a/main.go b/main.go new file mode 100644 index 0000000..bbec9e2 --- /dev/null +++ b/main.go @@ -0,0 +1,108 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "log" + "os" + "os/signal" + "strconv" + "strings" + + config "github.com/D4-project/d4-golang-utils/config" + "github.com/gomodule/redigo/redis" +) + +type ( + conf struct { + redisHost string + redisPort string + redisDB int + redisQueue string + httpHost string + httpPort string + } +) + +// Setting up flags +var ( + confdir = flag.String("c", "conf.sample", "configuration directory") + cr redis.Conn +) + +func main() { + sortie := make(chan os.Signal, 1) + signal.Notify(sortie, os.Interrupt, os.Kill) + // Signal goroutine + go func() { + <-sortie + fmt.Println("Exiting.") + log.Println("Exit") + os.Exit(0) + }() + + // Setting up log file + f, err := os.OpenFile("analyzer-d4-log.log", 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) + log.Println("Init") + + // Usage and flags + flag.Usage = func() { + fmt.Printf("analyzer-d4-log:\n\n") + fmt.Printf(" Generate statistics about logs collected through d4 in\n") + fmt.Printf(" HTML format. Optionally serves the results over HTTP.\n") + fmt.Printf("\n") + flag.PrintDefaults() + fmt.Printf("\n") + fmt.Printf("The configuration directory should hold the following files\n") + fmt.Printf("to specify the settings to use:\n\n") + fmt.Printf(" mandatory: redis - host:port/db\n") + fmt.Printf(" mandatory: redis_queue - uuid\n") + fmt.Printf(" optional: http_server - host:port\n\n") + fmt.Printf("See conf.sample for an example.\n") + } + + // Config + c := conf{} + flag.Parse() + if flag.NFlag() == 0 || *confdir == "" { + flag.Usage() + os.Exit(1) + } else { + *confdir = strings.TrimSuffix(*confdir, "/") + *confdir = strings.TrimSuffix(*confdir, "\\") + } + + // Parse Redis Config + tmp := config.ReadConfigFile(*confdir, "redis") + ss := strings.Split(string(tmp), "/") + if len(ss) <= 1 { + log.Fatal("Missing Database in Redis config: should be host:port/database_name") + } + c.redisDB, _ = strconv.Atoi(ss[1]) + var ret bool + ret, ss[0] = config.IsNet(ss[0]) + if !ret { + sss := strings.Split(string(ss[0]), ":") + c.redisHost = sss[0] + c.redisPort = sss[1] + } + c.redisQueue = string(config.ReadConfigFile(*confdir, "redis_queue")) + initRedis(c.redisHost, c.redisPort, c.redisDB) + defer cr.Close() + + log.Println("Exit") +} + +func initRedis(host string, port string, d int) { + err := errors.New("") + cr, err = redis.Dial("tcp", host+":"+port, redis.DialDatabase(d)) + if err != nil { + log.Fatal(err) + } +}