You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
2.5 KiB
Go
130 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"sort"
|
|
"strconv"
|
|
)
|
|
|
|
var max = flag.Int64("max", 5, "limit output, if negative print all")
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
// Failed password for root from 43.229.53.57 port 62954 ssh2
|
|
// message repeated 2 times: [ Failed password for root from 43.229.53.57 port 32871 ssh2]
|
|
p, err := regexp.Compile(`(message repeated (\d+) times: \[)? Failed password for (invalid user )?(.*?) from (.*) port`)
|
|
if err != nil {
|
|
fail("failed to compile regex", err)
|
|
}
|
|
|
|
unames := counter{}
|
|
ips := counter{}
|
|
|
|
s := bufio.NewScanner(os.Stdin)
|
|
for s.Scan() {
|
|
if m := p.FindSubmatch(s.Bytes()); m == nil {
|
|
continue
|
|
} else {
|
|
if len(m) != 6 {
|
|
fail("failure to capture correct number of tokens", nil)
|
|
}
|
|
|
|
multstr := string(m[2])
|
|
uname, ip := m[4], m[5]
|
|
|
|
multiplier := 1
|
|
if multstr != "" {
|
|
i, err := strconv.Atoi(multstr)
|
|
if err != nil {
|
|
fail("problem parsing int", err)
|
|
}
|
|
multiplier = i
|
|
}
|
|
|
|
unames[string(uname)] += multiplier
|
|
ips[string(ip)] += multiplier
|
|
}
|
|
}
|
|
if err := s.Err(); err != nil {
|
|
fail("failure reading from stdin", err)
|
|
}
|
|
|
|
display(unames, ips)
|
|
}
|
|
|
|
// fail constructs an error message, sends to stderr, and exists 1
|
|
func fail(msg string, err error) {
|
|
fmt.Fprintf(os.Stderr, "%s; %v\n", msg, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
type counter map[string]int
|
|
|
|
// top sorts the map by value and returns max pairs, unless max is negative in
|
|
// which case it returns all pairs
|
|
func top(m counter, max int64) pairList {
|
|
p := make(pairList, len(m))
|
|
i := 0
|
|
for k, v := range m {
|
|
p[i] = pair{k, v}
|
|
i++
|
|
}
|
|
sort.Sort(p)
|
|
|
|
if max < 0 {
|
|
return p
|
|
}
|
|
if int64(len(p)) > max {
|
|
p = p[:max]
|
|
}
|
|
return p
|
|
}
|
|
|
|
// How I sort a counter by value
|
|
type pair struct {
|
|
key string
|
|
value int
|
|
}
|
|
|
|
type pairList []pair
|
|
|
|
func (p pairList) Swap(i, j int) {
|
|
p[i], p[j] = p[j], p[i]
|
|
}
|
|
|
|
func (p pairList) Len() int {
|
|
return len(p)
|
|
}
|
|
|
|
// Less sorts in descending order
|
|
func (p pairList) Less(i, j int) bool {
|
|
return p[i].value > p[j].value
|
|
}
|
|
|
|
func display(unames, ips map[string]int) {
|
|
var title string
|
|
title = fmt.Sprintf("%-20s %s", "unames", "count")
|
|
fmt.Printf("%s\n", title)
|
|
for _ = range title {
|
|
fmt.Print("-")
|
|
}
|
|
fmt.Println()
|
|
for _, v := range top(unames, *max) {
|
|
fmt.Printf("%-20s %d\n", v.key, v.value)
|
|
}
|
|
title = fmt.Sprintf("%-20s %s", "ips", "count")
|
|
fmt.Printf("\n%s\n", title)
|
|
for _ = range title {
|
|
fmt.Print("-")
|
|
}
|
|
fmt.Println()
|
|
for _, v := range top(ips, *max) {
|
|
fmt.Printf("%-20s %d\n", v.key, v.value)
|
|
}
|
|
}
|