2015-07-20 14:08:22 +02:00
|
|
|
// lastlogin_consolidate
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"gopkg.in/mgo.v2"
|
|
|
|
"gopkg.in/mgo.v2/bson"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2015-11-09 15:54:05 +01:00
|
|
|
_VERSION = "v1.0.6"
|
2015-07-20 14:08:22 +02:00
|
|
|
_tformat = "2006-01-02"
|
2015-07-21 12:04:07 +02:00
|
|
|
_24h = (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59)
|
|
|
|
_10m = (time.Minute * 10)
|
2015-07-21 15:00:46 +02:00
|
|
|
_15m = (time.Minute * 15)
|
2015-07-20 14:08:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
opts = Options{
|
2015-07-21 12:30:28 +02:00
|
|
|
MongoSrc: "mongodb://127.0.0.1:27018",
|
|
|
|
LogFile: "log/llconsolidate.log",
|
2015-07-20 14:08:22 +02:00
|
|
|
StartDate: time.Now().Add(-24 * time.Hour).Format(_tformat),
|
2015-07-21 12:04:07 +02:00
|
|
|
Duration: _24h,
|
2015-07-21 15:00:46 +02:00
|
|
|
Interval: _15m,
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
type Options struct {
|
2015-07-20 16:58:00 +02:00
|
|
|
MongoSrc string
|
|
|
|
MongoDst string
|
|
|
|
mdbSrc *mgo.Session
|
|
|
|
mdbDst *mgo.Session
|
2015-07-20 14:08:22 +02:00
|
|
|
ll *mgo.Collection
|
|
|
|
lc *mgo.Collection
|
|
|
|
StartDate string
|
2015-07-20 16:58:00 +02:00
|
|
|
Duration time.Duration
|
2015-07-21 12:04:07 +02:00
|
|
|
Interval time.Duration
|
2015-07-20 14:08:22 +02:00
|
|
|
LogFile string
|
|
|
|
Version bool
|
2015-11-09 15:54:05 +01:00
|
|
|
Debug bool
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type LastLogin struct {
|
|
|
|
User string `json: "user"`
|
|
|
|
Protocol string `json: "protocol"`
|
|
|
|
IP string `json: "ip"`
|
|
|
|
Date time.Time `json: "date"`
|
|
|
|
ID string `json: "_id"`
|
|
|
|
}
|
|
|
|
|
2015-07-20 16:58:00 +02:00
|
|
|
type LastLoginDay struct {
|
2015-07-20 14:08:22 +02:00
|
|
|
User string `json:"user"`
|
|
|
|
Date time.Time `json:"date"`
|
|
|
|
Protocols Protocols `json:"protocols"`
|
|
|
|
IPs []IPs `json:"ips"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type IPs struct {
|
2015-07-21 15:00:46 +02:00
|
|
|
IP string `json:"ip"`
|
|
|
|
Date time.Time `json:"date"`
|
|
|
|
Protocol string `json:"protocol"`
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type Protocols struct {
|
|
|
|
Pop int `json:"pop"`
|
|
|
|
Imap int `json:"imap"`
|
|
|
|
Web int `json:"web"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Index struct {
|
|
|
|
User string `json:"user"`
|
|
|
|
Date time.Time `json:"date"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func usage() {
|
2015-11-09 15:54:05 +01:00
|
|
|
fmt.Println("Usage: lastlogin_consolidate -ms <mongo source mongodb://IP:PORT> -md <mongo destination mongodb://IP:PORT> -l <logfile> -d <date> -dd <duration> -i <interval> -v\n")
|
2015-07-20 14:08:22 +02:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
current, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
opts.LogFile = path.Join(current, opts.LogFile)
|
|
|
|
|
2015-07-21 12:33:05 +02:00
|
|
|
flag.StringVar(&opts.MongoSrc, "ms", opts.MongoSrc, "Mongodb Source")
|
2015-07-20 16:58:00 +02:00
|
|
|
flag.StringVar(&opts.MongoDst, "md", "", "Mongodb Destination")
|
2015-07-20 14:08:22 +02:00
|
|
|
flag.StringVar(&opts.LogFile, "l", opts.LogFile, "Logs filename")
|
|
|
|
flag.StringVar(&opts.StartDate, "d", opts.StartDate, "Date")
|
2015-07-20 16:58:00 +02:00
|
|
|
flag.DurationVar(&opts.Duration, "dd", opts.Duration, "Duration")
|
2015-07-21 12:04:07 +02:00
|
|
|
flag.DurationVar(&opts.Interval, "i", opts.Interval, "Duration")
|
2015-07-20 14:08:22 +02:00
|
|
|
flag.BoolVar(&opts.Version, "v", false, "Version")
|
2015-11-09 15:54:05 +01:00
|
|
|
flag.BoolVar(&opts.Debug, "debug", false, "Debug")
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func connectMongo() {
|
2015-07-20 16:58:00 +02:00
|
|
|
|
|
|
|
if opts.MongoSrc == "" {
|
|
|
|
log.Fatalf("Mongodb URI invalid: '%s'\n", opts.MongoSrc)
|
|
|
|
}
|
2015-07-20 14:08:22 +02:00
|
|
|
var err error
|
2015-07-20 16:58:00 +02:00
|
|
|
opts.mdbSrc, err = mgo.Dial(opts.MongoSrc)
|
2015-07-20 14:08:22 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Println("Mongodb connect Error: ", err.Error())
|
|
|
|
os.Exit(-3)
|
|
|
|
}
|
2015-07-20 16:58:00 +02:00
|
|
|
opts.ll = opts.mdbSrc.DB("dovecot").C("lastlogin")
|
|
|
|
|
|
|
|
if opts.MongoDst == "" {
|
|
|
|
opts.mdbDst = opts.mdbSrc
|
|
|
|
opts.lc = opts.mdbSrc.DB("dovecot").C("lastlogin_day")
|
|
|
|
} else {
|
|
|
|
opts.mdbDst, err = mgo.Dial(opts.MongoDst)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Mongodb connect Error: ", err.Error())
|
|
|
|
os.Exit(-3)
|
|
|
|
}
|
2015-07-21 12:04:07 +02:00
|
|
|
opts.lc = opts.mdbDst.DB("dovecot").C("lastlogin_day")
|
2015-07-20 16:58:00 +02:00
|
|
|
}
|
|
|
|
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
|
|
|
flag.Usage = usage
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
if opts.Version {
|
|
|
|
fmt.Println(os.Args[0], _VERSION)
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
fs, err := os.OpenFile(opts.LogFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Log file error: ", err.Error())
|
|
|
|
os.Exit(-4)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.SetOutput(fs)
|
|
|
|
|
|
|
|
start := time.Now()
|
|
|
|
fmt.Printf("Start: %+v\n", opts)
|
|
|
|
log.Printf("Start: %+v\n", opts)
|
|
|
|
|
|
|
|
connectMongo()
|
2015-07-20 16:58:00 +02:00
|
|
|
defer opts.mdbSrc.Close()
|
|
|
|
defer opts.mdbDst.Clone()
|
2015-07-20 14:08:22 +02:00
|
|
|
|
|
|
|
y, err := time.Parse(_tformat, opts.StartDate)
|
|
|
|
if err != nil {
|
2015-07-21 12:30:28 +02:00
|
|
|
log.Println("Date Error: ", err)
|
2015-07-20 14:08:22 +02:00
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
|
2015-11-09 15:54:05 +01:00
|
|
|
// DEBUG
|
|
|
|
//fmt.Printf("Start %+v\n\r", y)
|
2015-07-20 14:08:22 +02:00
|
|
|
|
2015-07-21 12:04:07 +02:00
|
|
|
var ys []time.Time
|
|
|
|
var ye []time.Time
|
|
|
|
|
|
|
|
if opts.Duration <= (time.Hour * 24) {
|
|
|
|
ys = append(ys, time.Date(y.Year(), y.Month(), y.Day(), 0, 0, 0, 0, time.UTC))
|
|
|
|
ye = append(ye, ys[0].Add(opts.Duration))
|
|
|
|
} else {
|
|
|
|
for i := 0; i < int(opts.Duration/(time.Hour*24)); i++ {
|
2015-07-21 12:30:28 +02:00
|
|
|
// fmt.Println(i)
|
2015-07-21 12:04:07 +02:00
|
|
|
yt := y.Add(time.Hour * time.Duration(24*i))
|
2015-11-09 15:54:05 +01:00
|
|
|
// fmt.Println(yt)
|
2015-07-21 12:04:07 +02:00
|
|
|
ys = append(ys, time.Date(yt.Year(), yt.Month(), yt.Day(), 0, 0, 0, 0, time.UTC))
|
|
|
|
ye = append(ye, ys[i].Add(_24h))
|
|
|
|
}
|
|
|
|
}
|
2015-07-20 14:08:22 +02:00
|
|
|
|
2015-11-09 15:54:05 +01:00
|
|
|
// DEBUG
|
|
|
|
if opts.Debug {
|
|
|
|
fmt.Printf("Start: %+v, Stop: %+v\n\r", ys, ye)
|
|
|
|
}
|
2015-07-20 14:08:22 +02:00
|
|
|
|
2015-07-21 12:04:07 +02:00
|
|
|
for i := range ys {
|
2015-07-21 15:45:06 +02:00
|
|
|
|
|
|
|
pStart := time.Now()
|
|
|
|
|
2015-11-09 15:54:05 +01:00
|
|
|
qStart := time.Now()
|
|
|
|
|
2015-07-21 12:04:07 +02:00
|
|
|
q := opts.ll.Find(bson.M{"date": bson.M{"$gte": ys[i], "$lte": ye[i]}}).Sort("user")
|
|
|
|
|
2015-11-09 15:54:05 +01:00
|
|
|
if opts.Debug {
|
|
|
|
fmt.Printf("Find from date: %s\n\r", time.Since(qStart))
|
|
|
|
}
|
|
|
|
|
|
|
|
qStart = time.Now()
|
|
|
|
|
2015-07-21 12:04:07 +02:00
|
|
|
ar := []string{}
|
|
|
|
q.Distinct("user", &ar)
|
|
|
|
|
2015-11-09 15:54:05 +01:00
|
|
|
if opts.Debug {
|
|
|
|
fmt.Printf("Distinct: %s\n\r", time.Since(qStart))
|
|
|
|
}
|
|
|
|
|
2015-07-21 12:04:07 +02:00
|
|
|
fmt.Printf("Date: %s - %s\n", ys[i], ye[i])
|
2015-07-21 12:30:28 +02:00
|
|
|
log.Printf("Date: %s - %s\n", ys[i], ye[i])
|
2015-07-21 12:04:07 +02:00
|
|
|
|
|
|
|
for u := range ar {
|
|
|
|
ll := LastLoginDay{}
|
|
|
|
ll.User = ar[u]
|
|
|
|
ll.Date = ys[i]
|
2015-11-09 15:54:05 +01:00
|
|
|
|
|
|
|
// DEBUG
|
|
|
|
if opts.Debug {
|
|
|
|
fmt.Printf("User: %s\n\r", ar[u])
|
|
|
|
}
|
|
|
|
|
|
|
|
qStart = time.Now()
|
2015-07-21 12:04:07 +02:00
|
|
|
nq := opts.ll.Find(bson.M{"date": bson.M{"$gte": ys[i], "$lte": ye[i]}, "user": ar[u]}).Sort("date")
|
2015-11-09 15:54:05 +01:00
|
|
|
//fmt.Printf("User: %s -> %s\n\r", ar[u], time.Since(qStart) )
|
2015-07-21 12:04:07 +02:00
|
|
|
iter := nq.Iter()
|
|
|
|
result := LastLogin{}
|
|
|
|
ips := []IPs{}
|
|
|
|
lastip := IPs{}
|
|
|
|
for iter.Next(&result) {
|
|
|
|
if result.IP == lastip.IP && result.Date.Sub(lastip.Date) < opts.Interval {
|
|
|
|
//fmt.Println("IPs: ", result.IP, result.Date, result.Date.Sub(lastip.Date))
|
|
|
|
} else {
|
2015-07-21 15:00:46 +02:00
|
|
|
ips = append(ips, IPs{IP: result.IP, Date: result.Date, Protocol: result.Protocol})
|
2015-07-21 12:04:07 +02:00
|
|
|
lastip.Date = result.Date
|
|
|
|
lastip.IP = result.IP
|
|
|
|
}
|
|
|
|
switch result.Protocol {
|
|
|
|
case "pop3", "pop":
|
|
|
|
ll.Protocols.Pop += 1
|
|
|
|
case "imap":
|
|
|
|
ll.Protocols.Imap += 1
|
|
|
|
case "web":
|
|
|
|
ll.Protocols.Web += 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := iter.Close(); err != nil {
|
2015-07-21 12:30:28 +02:00
|
|
|
log.Println("Iter: ", err)
|
2015-07-21 12:04:07 +02:00
|
|
|
}
|
|
|
|
ll.IPs = ips
|
2015-11-09 15:54:05 +01:00
|
|
|
//fmt.Printf("Upsert %+v\n\r", ll)
|
2015-07-21 12:04:07 +02:00
|
|
|
_, err := opts.lc.Upsert(Index{User: ll.User, Date: ll.Date}, ll)
|
|
|
|
if err != nil {
|
2015-07-21 12:30:28 +02:00
|
|
|
log.Println("Insert error: ", err)
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-21 15:45:06 +02:00
|
|
|
fmt.Printf("Stop %s: %s\n", ys[i], time.Since(pStart))
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("Stop: ", time.Since(start))
|
2015-07-21 12:30:28 +02:00
|
|
|
log.Println("Stop: ", time.Since(start))
|
2015-07-20 14:08:22 +02:00
|
|
|
}
|