Andrew Khozhempo 3 лет назад
Сommit
5e10c73767
7 измененных файлов с 409 добавлено и 0 удалено
  1. 2 0
      .gitattributes
  2. 24 0
      LICENSE
  3. 28 0
      README.md
  4. 282 0
      ab_analyzer.go
  5. 12 0
      config.json
  6. 9 0
      go.mod
  7. 52 0
      go.sum

+ 2 - 0
.gitattributes

@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto

+ 24 - 0
LICENSE

@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>

+ 28 - 0
README.md

@@ -0,0 +1,28 @@
+# Autoban analyzer
+Additional utility for Autoban service. Do analyze of cumulative user behavior statistics. 
+
+
+INSTALLATION
+------------
+
+Download and run periodically to search suspicious activity. Correct config.json with you mySQL base configuration and allow access to autoban base.
+
+Depenging of period use one key on command line:
+  -10m
+    	process every 10 minutes analyze
+  -daily
+    	process daily analyze
+  -hourly
+    	process hourly analyze
+
+
+REQUIREMENTS
+------------
+
+Every system supported with golang complator.
+
+
+QUICK START
+-----------
+
+Not so easy as you think. Gotta try a little.

+ 282 - 0
ab_analyzer.go

@@ -0,0 +1,282 @@
+// ab_analyzer
+
+package main
+
+import (
+	"database/sql"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"math/big"
+	"net"
+	"os"
+	"strconv"
+	"time"
+
+	_ "github.com/go-sql-driver/mysql"
+	"github.com/hjson/hjson-go"
+	"github.com/kpango/glg"
+)
+
+type listToBanStruct struct {
+	siteid uint
+	ip     uint
+}
+
+func main() {
+	mainConfig := readCfgFile("config.json") // чтение конфигурации
+	var dbConnect = mainConfig["dbUser"].(string) + ":" + mainConfig["dbPsw"].(string) + "@tcp(" + mainConfig["dbAddress"].(string) + ":" + FloatToString(mainConfig["dbPort"].(float64)) + ")/" + mainConfig["dbBase"].(string)
+
+	//	установки log-файла
+	infolog := glg.FileWriter("ab_analyzer.log", 0666) // открытие лог.файла
+	defer infolog.Close()
+	//	customLevel := "FINE"
+	customErrLevel := "CRIT"
+	glg.Get().
+		SetMode(glg.BOTH). // default is STD
+		AddWriter(infolog).
+		SetWriter(infolog).
+		SetLevelColor(glg.TagStringToLevel(customErrLevel), glg.Red) // set color output to user custom level
+	//	завершение установки log-файла
+
+	// Initializing DB connection
+	db, err := sql.Open("mysql", dbConnect)
+	checkErr(err)
+	defer db.Close()
+	db.SetConnMaxLifetime(time.Second * 100)
+
+	// обработчик параметров коммандной строки
+	switch flagOperate() {
+	case "daily":
+		beginTime := logSQLStart(db, 0) // создание статуса начала работы
+		glg.Infof("[%s,%s] %s", "D", beginTime, "DAILY mode")
+		glg.Infof("[%s,%s] %s", "D", beginTime, "started looking for ban ip")
+
+		query := "SELECT siteid, ip AS visits FROM allvisits WHERE ownervisit=0 AND DATE >= UNIX_TIMESTAMP(NOW())-86400 GROUP BY ip, siteid HAVING COUNT(ip) > ? ORDER BY COUNT(ip) DESC"
+		listToBan := mainReqToGetBanList(db, query, uint(mainConfig["maxDailyConnect"].(float64)))
+		glg.Infof("[%s,%s] %s", "D", beginTime, "finished looking for ban ip, begin update banlist")
+
+		updateBanlistInBase(db, listToBan, "D", beginTime, 0)
+
+		glg.Infof("[%s,%s] %s", "D", beginTime, "finihed banlist update")
+		logSQLFinish(db, beginTime, 0) // обновление статуса завершения работы
+
+	case "hourly":
+		beginTime := logSQLStart(db, 1) // создание статуса начала работы
+		glg.Infof("[%s,%s] %s", "H", beginTime, "HOURLY mode")
+		glg.Infof("[%s,%s] %s", "H", beginTime, "started looking for ban ip")
+
+		query := "SELECT siteid, ip AS visits FROM allvisits WHERE ownervisit=0 AND DATE >= UNIX_TIMESTAMP(NOW())-3600 GROUP BY ip, siteid HAVING COUNT(ip) > ? ORDER BY COUNT(ip) DESC"
+		listToBan := mainReqToGetBanList(db, query, uint(mainConfig["maxHourlyConnect"].(float64)))
+		glg.Infof("[%s,%s] %s", "H", beginTime, "finished looking for ban ip, begin update banlist")
+
+		updateBanlistInBase(db, listToBan, "H", beginTime, 0)
+
+		glg.Infof("[%s,%s] %s", "H", beginTime, "finihed banlist update")
+		logSQLFinish(db, beginTime, 1) // обновление статуса завершения работы
+
+	case "10m":
+		beginTime := logSQLStart(db, 2) // создание статуса начала работы
+		glg.Infof("[%s,%s] %s", "10M", beginTime, "10m mode")
+		glg.Infof("[%s,%s] %s", "10M", beginTime, "started looking for ban ip")
+
+		query := "SELECT siteid, ip FROM allvisits WHERE ownervisit=0 AND DATE >= UNIX_TIMESTAMP(NOW())-600 GROUP BY ip, siteid HAVING COUNT(ip) > ? ORDER BY COUNT(ip) DESC"
+		listToBan := mainReqToGetBanList(db, query, uint(mainConfig["max10mConnect"].(float64)))
+		glg.Infof("[%s,%s] %s", "10M", beginTime, "finished looking for ban ip, begin update banlist")
+
+		updateBanlistInBase(db, listToBan, "10M", beginTime, 0)
+
+		glg.Infof("[%s,%s] %s", "10M", beginTime, "finihed banlist update")
+		logSQLFinish(db, beginTime, 2) // обновление статуса завершения работы
+	}
+}
+
+// ###########################
+// обновление банлиста в базе
+func updateBanlistInBase(db *sql.DB, listToBan map[uint]listToBanStruct, logCurrentMode string, logBeginTime string, reason uint) {
+	if len(listToBan) > 0 {
+		glg.Infof("[%s,%s] %s", logCurrentMode, logBeginTime, "updating banlist")
+		for i, _ := range listToBan {
+			stmt, err := db.Prepare("INSERT INTO blacklistip SET siteid = ?, ip = ?, reason = ? ON DUPLICATE KEY UPDATE ban_count = ban_count + 1 AND lastupdate = NOW()")
+			checkErr(err)
+
+			res, err := stmt.Exec(listToBan[i].siteid, listToBan[i].ip, reason)
+			checkErr(err)
+			_ = res
+		}
+	} else {
+		glg.Infof("[%s,%s] %s", logCurrentMode, logBeginTime, "nothing to update in banlist")
+
+	}
+}
+
+// чтение содержимого файла
+func readFile(filename string) string {
+	configFileText, err := ioutil.ReadFile(filename)
+	if err != nil {
+		panic(err)
+	}
+	str := string(configFileText)
+	return str
+}
+
+// чтение конфиг файла
+func readCfgFile(filename string) map[string]interface{} {
+	configFileText, err := ioutil.ReadFile(filename)
+	if err != nil {
+		panic(err)
+	}
+
+	var dat map[string]interface{}
+	// Decode and a check for errors.
+	if err := hjson.Unmarshal(configFileText, &dat); err != nil {
+		panic(err)
+	}
+
+	return dat
+}
+
+// обработчик параметров коммандной строки
+func flagOperate() string {
+	var flagSum uint
+	var retVar string
+
+	// обработка флагов
+	flagDaily := flag.Bool("daily", false, "process daily analyze")
+	flagHourly := flag.Bool("hourly", false, "process hourly analyze")
+	flag10m := flag.Bool("10m", false, "process every 10 minutes analyze")
+
+	flag.Parse()
+	if *flagDaily == true {
+		flagSum++
+		retVar = "daily"
+	}
+	if *flagHourly == true {
+		flagSum++
+		retVar = "hourly"
+	}
+	if *flag10m == true {
+		flagSum++
+		retVar = "10m"
+	}
+	if *flagDaily == false && *flagHourly == false && *flag10m == false {
+		fmt.Println("Missing required parameters. Use -h for help.")
+		os.Exit(0)
+	}
+	if flagSum > 1 {
+		fmt.Println("Too many parameters. Use -h for help.")
+		os.Exit(0)
+	}
+	return retVar
+}
+
+// to convert a float number to a string
+func FloatToString(input_num float64) string {
+	return strconv.FormatFloat(input_num, 'f', 0, 64)
+}
+
+// to convert a float number to uint
+func FloatToUint(input_num float64) uint {
+	return uint(input_num)
+}
+
+// запись в базу времени начала работы
+func logSQLStart(db *sql.DB, flagMode uint) string { // db *sql.DB,
+	beginTime := returnTimestamp()
+	// flagMode 0 - daily
+	// flagMode 1 - hourly
+	// flagMode 2 - 10m
+	stmt, err := db.Prepare("INSERT ab_analyzer_status SET flagmode=?, begin=FROM_UNIXTIME(?)")
+	checkErr(err)
+	res, err := stmt.Exec(flagMode, beginTime)
+	checkErr(err)
+	_ = res
+	return beginTime
+}
+
+// запись в базу времени окончания работы
+func logSQLFinish(db *sql.DB, beginTime string, flagMode uint) {
+	// flagMode 0 - daily
+	// flagMode 1 - hourly
+	// flagMode 2 - 10m
+	stmt, err := db.Prepare("UPDATE ab_analyzer_status SET finish=FROM_UNIXTIME(?) WHERE flagmode=? AND begin=FROM_UNIXTIME(?)")
+	checkErr(err)
+	res, err := stmt.Exec(returnTimestamp(), flagMode, beginTime)
+	checkErr(err)
+	_ = res
+}
+
+// возвращает timestamp в виде строки
+func returnTimestamp() string {
+	return strconv.Itoa(int(time.Now().Unix()))
+}
+
+// проверка ошибок
+func checkErr(err error) {
+	if err != nil {
+		panic(err)
+	}
+}
+
+// запрос на анализ и получение бан листа
+func mainReqToGetBanList(db *sql.DB, query string, maxConnections uint) map[uint]listToBanStruct { // тут надо возвращать массив, а не map
+	listToBan := make(map[uint]listToBanStruct)
+	var (
+		count  uint
+		ip     uint
+		siteid uint
+	)
+
+	mainQuery, err := db.Query(query, maxConnections)
+	//	mainDailyQuery, err := db.Query("SELECT siteid, ip, COUNT(ip) AS visits FROM allvisits WHERE ownervisit=0 AND DATE >= UNIX_TIMESTAMP(NOW())-86400 GROUP BY ip, siteid HAVING `visits` > ? ORDER BY visits DESC", maxDailyConnect)
+	checkErr(err)
+	defer mainQuery.Close()
+	for mainQuery.Next() {
+		err := mainQuery.Scan(&siteid, &ip)
+		checkErr(err)
+		listToBan[count] = listToBanStruct{
+			siteid: siteid,
+			ip:     ip}
+		count++
+	}
+	return listToBan
+}
+
+// ipv4 2 int64
+func IP4toInt(ipv4 string) int64 {
+	IPv4Address := net.ParseIP(ipv4)
+	IPv4Int := big.NewInt(0)
+	IPv4Int.SetBytes(IPv4Address.To4())
+	return IPv4Int.Int64()
+}
+
+// int64 2 ipv4
+func InttoIP4(ipInt int64) string {
+	// need to do two bit shifting and “0xff” masking
+	b0 := strconv.FormatInt((ipInt>>24)&0xff, 10)
+	b1 := strconv.FormatInt((ipInt>>16)&0xff, 10)
+	b2 := strconv.FormatInt((ipInt>>8)&0xff, 10)
+	b3 := strconv.FormatInt((ipInt & 0xff), 10)
+	return b0 + "." + b1 + "." + b2 + "." + b3
+}
+
+// примеры сообщений в лог файл и на экран
+//	glg.Info("info")
+//	glg.Infof("%s : %s", "info", "formatted")
+//	glg.Log("log")
+//	glg.Logf("%s : %s", "info", "formatted")
+//	glg.Debug("debug")
+//	glg.Debugf("%s : %s", "info", "formatted")
+//	glg.Warn("warn")
+//	glg.Warnf("%s : %s", "info", "formatted")
+//	glg.Error("error")
+//	glg.Errorf("%s : %s", "info", "formatted")
+//	glg.Success("ok")
+//	glg.Successf("%s : %s", "info", "formatted")
+//	glg.Fail("fail")
+//	glg.Failf("%s : %s", "info", "formatted")
+//	glg.Print("Print")
+//	glg.Println("Println")
+//	glg.Printf("%s : %s", "printf", "formatted")
+//	glg.CustomLog(customLevel, "custom logging")
+//	glg.CustomLog(customErrLevel, "custom error logging")

+ 12 - 0
config.json

@@ -0,0 +1,12 @@
+{
+	dbUser: autoban
+	dbPsw: dbpasswd
+	dbAddress: 127.0.0.1
+	dbPort: 3306
+	dbBase: autoban_v2
+	maxDailyConnect: 1000
+	maxHourlyConnect: 200
+	max10mConnect: 50
+	httpAddFolder: 
+}
+

+ 9 - 0
go.mod

@@ -0,0 +1,9 @@
+module developing.khoz.ru/ab_analyzer
+
+go 1.16
+
+require (
+	github.com/go-sql-driver/mysql v1.6.0
+	github.com/hjson/hjson-go v3.1.0+incompatible
+	github.com/kpango/glg v1.5.8
+)

+ 52 - 0
go.sum

@@ -0,0 +1,52 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/goccy/go-json v0.4.11 h1:92nyX606ZN/cUFwctfxwDWm8YWSA38Zlv9s7taFeLyo=
+github.com/goccy/go-json v0.4.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw=
+github.com/hjson/hjson-go v3.1.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kpango/fastime v1.0.16 h1:1prFG/3pTjzcDeCTxt98VB4IvjxcySLs0ldCEhZg0R8=
+github.com/kpango/fastime v1.0.16/go.mod h1:lVqUTcXmQnk1wriyvq5DElbRSRDC0XtqbXQRdz0Eo+g=
+github.com/kpango/glg v1.5.8 h1:ZyxQa0Ft27dWci+2X7vMCCjHGEZCTFWLBHnLrAzxQZs=
+github.com/kpango/glg v1.5.8/go.mod h1:HI0g/1T4dmUhdoT2isXHrCM4FeNjc+t7fZujjvqYIeQ=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
+go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=