commit ceefc45622887bbe3425d65d24e893af1ea60ab2 Author: stephen mcquay Date: Tue Aug 11 19:03:37 2015 -0700 init diff --git a/license b/license new file mode 100644 index 0000000..c3ca89b --- /dev/null +++ b/license @@ -0,0 +1,27 @@ +Copyright (c) 2015, stephen mcquay + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of authpixious nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/main.go b/main.go new file mode 100644 index 0000000..79663a4 --- /dev/null +++ b/main.go @@ -0,0 +1,129 @@ +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) + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..61a5404 --- /dev/null +++ b/readme.md @@ -0,0 +1,13 @@ +# authpixious + +feed `authpicious` `/var/log/auth.log` on stdin and watch it rank offenders by +offense. + +## installation + + $ go get mcquay.me/authpixious + + +## usage + + $ cat /var/log/auth.log | authpixious -max 10