diff --git a/admin/colony.html b/admin/colony.html index dcdb61c..229df35 100644 --- a/admin/colony.html +++ b/admin/colony.html @@ -120,7 +120,7 @@ for (var i = 0; i < data.length; i++) { _h += ''; - var last_update_time = data[i].last_update_time.replace("T", " ").replace("+08:00", " "); + var last_update_time = data[i].last_update_time.replace("T", " ").replace("+08:00", "").replace("Z", ""); last_update_time = last_update_time.substring(0, 19); last_update_time = last_update_time.replace(/-/g, '/'); var timestamp = new Date(last_update_time).getTime(); @@ -143,7 +143,7 @@ _h += ' '; } - if (data[i].dart_status == 1) { + if (data[i].deep_status == 1) { _h += ' '; } else { _h += ' '; diff --git a/admin/fish.html b/admin/fish.html index e9c37a7..85752bf 100644 --- a/admin/fish.html +++ b/admin/fish.html @@ -391,7 +391,7 @@ _h += ' 点击查看'; _h += ' ' + data.result[i].info.length + ''; - _h += ' ' + data.result[i].create_time.replace("T", " ").replace("+08:00", " ") + ''; + _h += ' ' + data.result[i].create_time.replace("T", " ").replace("+08:00", " ").replace("Z", "") + ''; _h += ''; } diff --git a/admin/setting.html b/admin/setting.html index 48d9233..1577969 100644 --- a/admin/setting.html +++ b/admin/setting.html @@ -59,7 +59,7 @@ {{$e.setting_name}} {{$e.setting_dis}} - + {{if ne $e.info ""}} 已配置 {{else}} diff --git a/config.ini b/config.ini index 3490145..227ce21 100644 --- a/config.ini +++ b/config.ini @@ -1,5 +1,5 @@ [rpc] -status = 1 # 模式 0关闭 1服务端 2客户端 +status = 0 # 模式 0关闭 1服务端 2客户端 addr = 0.0.0.0:7879 # RPC 服务端地址 or 客户端地址 name = Server # 状态1 服务端 名称 状态2 客户端 名称 @@ -7,8 +7,9 @@ name = Server # 状态1 服务端 名称 状 addr = 0.0.0.0:9001 # 管理后台启动地址 account = admin # 登录账号 password = admin # 登录密码 -db_type = sqlite # 1 sqlite 2 mysql -db_max_open = 5 # 最大连接池,0 表示无限制 +db_type = sqlite # sqlite or mysql +db_max_open = 50 # 最大连接池,0 表示无限制 +db_max_idle = 50 # 最大空闲数,0 表示无限制 db_str = ./db/hfish.db?cache=shared&mode=rwc # sqlite or mysql 连接字符串 # sqlite : ./db/hfish.db?cache=shared&mode=rwc # mysql : 账号:密码@tcp(地址:端口)/数据库名?charset=utf8&parseTime=true&loc=Local @@ -54,7 +55,7 @@ addr = 0.0.0.0:3306 # Mysql 服务端地址 注意 files = /etc/passwd,/etc/group # Mysql 服务端读取客户端任意文件; 多写逗号分隔,会随机取 [telnet] -status = 0 # 是否启动 Telnet 0 关闭 1 启动 +status = 1 # 是否启动 Telnet 0 关闭 1 启动 addr = 0.0.0.0:23 # Telnet 服务端地址 注意端口冲突 [ftp] diff --git a/core/alert/alert.go b/core/alert/alert.go index 00055e0..ed06416 100644 --- a/core/alert/alert.go +++ b/core/alert/alert.go @@ -13,9 +13,10 @@ import ( "HFish/view/data" "github.com/gin-gonic/gin" "HFish/error" + "sync" ) -func AlertMail(model string, typex string, agent string, ipx string, country string, region string, city string, infox string) { +func AlertMail(model string, typex string, agent string, ipx string, country string, region string, city string, infox string, wg *sync.WaitGroup) { // 判断邮件通知 try.Try(func() { // 只有新加入才会发送邮件通知 @@ -55,11 +56,14 @@ func AlertMail(model string, typex string, agent string, ipx string, country str send.SendMail(config[4:], "[HFish]提醒你,"+typex+"有鱼上钩!", text, config) } } + + wg.Done() }).Catch(func() { + wg.Done() }) } -func AlertWebHook(id string, model string, typex string, projectName string, agent string, ipx string, country string, region string, city string, infox string, time string) { +func AlertWebHook(id string, model string, typex string, projectName string, agent string, ipx string, country string, region string, city string, infox string, time string, wg *sync.WaitGroup) { // 判断 WebHook 通知 try.Try(func() { result, err := dbUtil.DB().Table("hfish_setting").Fields("status", "info").Where("type", "=", "webHook").First() @@ -106,7 +110,10 @@ func AlertWebHook(id string, model string, typex string, projectName string, age defer resp.Body.Close() //defer request.Body.Close() } + + wg.Done() }).Catch(func() { + wg.Done() }) } diff --git a/core/dbUtil/dbUtil.go b/core/dbUtil/dbUtil.go index eb6e6fb..2562723 100644 --- a/core/dbUtil/dbUtil.go +++ b/core/dbUtil/dbUtil.go @@ -1,11 +1,11 @@ package dbUtil import ( - "github.com/gohouse/gorose" _ "github.com/go-sql-driver/mysql" _ "github.com/mattn/go-sqlite3" "HFish/utils/conf" "HFish/utils/log" + "github.com/gohouse/gorose" ) var engin *gorose.Engin @@ -16,15 +16,16 @@ func init() { dbType := conf.Get("admin", "db_type") dbStr := conf.Get("admin", "db_str") dbMaxOpen := conf.GetInt("admin", "db_max_open") + dbMaxIdle := conf.GetInt("admin", "db_max_idle") if dbType == "sqlite" { - engin, err = gorose.Open(&gorose.Config{Driver: "sqlite3", Dsn: dbStr, SetMaxOpenConns: dbMaxOpen}) + engin, err = gorose.Open(&gorose.Config{Driver: "sqlite3", Dsn: dbStr, SetMaxOpenConns: dbMaxOpen, SetMaxIdleConns: dbMaxIdle}) if err != nil { log.Pr("HFish", "127.0.0.1", "连接 Sqlite 数据库失败", err) } } else if dbType == "mysql" { - engin, err = gorose.Open(&gorose.Config{Driver: "mysql", Dsn: dbStr, SetMaxOpenConns: dbMaxOpen}) + engin, err = gorose.Open(&gorose.Config{Driver: "mysql", Dsn: dbStr, SetMaxOpenConns: dbMaxOpen, SetMaxIdleConns: dbMaxIdle}) if err != nil { log.Pr("HFish", "127.0.0.1", "连接 Mysql 数据库失败", err) diff --git a/core/pool/pool.go b/core/pool/pool.go new file mode 100644 index 0000000..521e77f --- /dev/null +++ b/core/pool/pool.go @@ -0,0 +1,12 @@ +package pool + +import ( + "sync" + "github.com/panjf2000/ants" +) + +func New(size int) (sync.WaitGroup, *ants.Pool) { + wg := sync.WaitGroup{} + pool, _ := ants.NewPool(size) + return wg, pool +} diff --git a/core/protocol/ftp/graval/commands.go b/core/protocol/ftp/graval/commands.go index 4034c69..4a59d90 100644 --- a/core/protocol/ftp/graval/commands.go +++ b/core/protocol/ftp/graval/commands.go @@ -11,6 +11,9 @@ import ( "HFish/core/report" "HFish/utils/is" "HFish/core/rpc/client" + "sync" + "github.com/panjf2000/ants" + "HFish/core/pool" ) type ftpCommand interface { @@ -329,24 +332,42 @@ func (cmd commandPass) RequireAuth() bool { return false } +// 加入线程池 + +var ( + wg sync.WaitGroup + poolX *ants.Pool +) + +func init() { + wg, poolX = pool.New(10) + defer poolX.Release() +} + func (cmd commandPass) Execute(conn *ftpConn, param string) { - info := conn.reqUser + "&&" + param - arr := strings.Split(conn.conn.RemoteAddr().String(), ":") + wg.Add(1) + poolX.Submit(func() { - // 判断是否为 RPC 客户端 - if is.Rpc() { - go client.ReportResult("FTP", "", arr[0], info, "0") - } else { - go report.ReportFTP(arr[0], "本机", info) - } + info := conn.reqUser + "&&" + param + arr := strings.Split(conn.conn.RemoteAddr().String(), ":") - if conn.driver.Authenticate(conn.reqUser, param) { - conn.user = conn.reqUser - conn.reqUser = "" - conn.writeMessage(230, "Password ok, continue") - } else { - conn.writeMessage(530, "Incorrect password, not logged in") - } + // 判断是否为 RPC 客户端 + if is.Rpc() { + go client.ReportResult("FTP", "", arr[0], info, "0") + } else { + go report.ReportFTP(arr[0], "本机", info) + } + + if conn.driver.Authenticate(conn.reqUser, param) { + conn.user = conn.reqUser + conn.reqUser = "" + conn.writeMessage(230, "Password ok, continue") + } else { + conn.writeMessage(530, "Incorrect password, not logged in") + } + + wg.Done() + }) } // commandPasv responds to the PASV FTP command. diff --git a/core/protocol/memcache/memcache.go b/core/protocol/memcache/memcache.go index 735f3e0..a2e4511 100644 --- a/core/protocol/memcache/memcache.go +++ b/core/protocol/memcache/memcache.go @@ -23,7 +23,6 @@ import ( "bufio" "fmt" "io" - "log" "net" "os" "strconv" @@ -32,6 +31,8 @@ import ( "HFish/utils/is" "HFish/core/rpc/client" "HFish/core/report" + "HFish/core/pool" + "HFish/utils/log" ) var linkedHashMap = LinkedHashMap.NewLinkedHashMap() @@ -407,87 +408,91 @@ func tcpServer(address string, rateLimitChan chan int, exitChan chan int) { exitChan <- 1 } - log.Println("[Memcache TCP] Listning on " + address) - defer l.Close() + wg, poolX := pool.New(10) + defer poolX.Release() + for { - conn, err := l.Accept() - trackID := randNumber(100000, 999999) + wg.Add(1) + poolX.Submit(func() { + time.Sleep(time.Second * 2) - if err != nil { - fmt.Println(err.Error()) - continue - } + conn, err := l.Accept() - go func() { - skip := false - reader := bufio.NewReader(conn) - log.Printf("[Memcache TCP %d] Accepted a client socket from %s\n", trackID, conn.RemoteAddr().String()) - - arr := strings.Split(conn.RemoteAddr().String(), ":") - - // 判断是否为 RPC 客户端 - var id string - - if is.Rpc() { - id = client.ReportResult("MEMCACHE", "", arr[0], conn.RemoteAddr().String()+" 已经连接", "0") - } else { - id = strconv.FormatInt(report.ReportMemCche(arr[0], "本机", conn.RemoteAddr().String()+" 已经连接"), 10) + if err != nil { + log.Pr("Mysql", "127.0.0.1", "Mysql 连接失败", err) } - for { - <-rateLimitChan - str, err := reader.ReadString('\n') - if skip { - skip = false - continue - } - if err != nil { - log.Printf("[Memcache TCP %d] Closed a client socket.\n", trackID) - conn.Close() - break - } - str = strings.TrimSpace(str) + go func() { + skip := false + reader := bufio.NewReader(conn) + + arr := strings.Split(conn.RemoteAddr().String(), ":") + + // 判断是否为 RPC 客户端 + var id string if is.Rpc() { - go client.ReportResult("MEMCACHE", "", "", "&&"+str, id) + id = client.ReportResult("MEMCACHE", "", arr[0], conn.RemoteAddr().String()+" 已经连接", "0") } else { - go report.ReportUpdateMemCche(id, "&&"+str) + id = strconv.FormatInt(report.ReportMemCche(arr[0], "本机", conn.RemoteAddr().String()+" 已经连接"), 10) } - log.Printf("[Memcache TCP %d] Client request: %s.\n", trackID, str) - args := strings.Split(str, " ") - function, exist := commands[args[0]] - if !exist { - conn.Write(RESPONSE_ERROR) - continue - } - - args = args[1:] - for { - response, requiredBytes := function(args) - if requiredBytes == -1 { + <-rateLimitChan + str, err := reader.ReadString('\n') + if skip { + skip = false + continue + } + if err != nil { conn.Close() break } - if requiredBytes == 0 { - conn.Write(response) - break + str = strings.TrimSpace(str) + + if is.Rpc() { + go client.ReportResult("MEMCACHE", "", "", "&&"+str, id) + } else { + go report.ReportUpdateMemCche(id, "&&"+str) } - data := make([]byte, requiredBytes) - _, err = io.ReadFull(reader, data) - if err != nil { - break + args := strings.Split(str, " ") + function, exist := commands[args[0]] + if !exist { + conn.Write(RESPONSE_ERROR) + continue } - skip = true - args = append(args, string(data)) + + args = args[1:] + + for { + response, requiredBytes := function(args) + if requiredBytes == -1 { + conn.Close() + break + } + if requiredBytes == 0 { + conn.Write(response) + break + } + + data := make([]byte, requiredBytes) + _, err = io.ReadFull(reader, data) + if err != nil { + break + } + skip = true + args = append(args, string(data)) + } + } - } - }() + }() + + wg.Done() + }) } } @@ -505,8 +510,6 @@ func udpServer(address string, rateLimitChan chan int, exitChan chan int) { exitChan <- 1 } - log.Println("[Memcache UDP] Listning on " + address) - go func() { buf := make([]byte, 1500) for { @@ -523,7 +526,7 @@ func udpServer(address string, rateLimitChan chan int, exitChan chan int) { if request == "" { continue } - log.Printf("[Memcache UDP] Client request: [%s] from: %s\n", request, addr.String()) + args := strings.Split(request, " ") function, exist := commands[args[0]] if !exist { diff --git a/core/protocol/mysql/mysql.go b/core/protocol/mysql/mysql.go index 334d950..ee64957 100644 --- a/core/protocol/mysql/mysql.go +++ b/core/protocol/mysql/mysql.go @@ -13,6 +13,8 @@ import ( "HFish/utils/is" "HFish/core/rpc/client" "strconv" + "HFish/core/pool" + "time" ) //读取文件时每次读取的字节数 @@ -47,26 +49,38 @@ func Start(addr string, files string) { // 读取文件列表 fileNames = strings.Split(files, ",") + wg, poolX := pool.New(10) + defer poolX.Release() + for { - conn, _ := listener.Accept() - ip, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) + wg.Add(1) + poolX.Submit(func() { + time.Sleep(time.Second * 2) - //由于文件最后保存的文件名包含ip地址,为了本地测试加了这个 - if ip == "::1" { - ip = "localhost" - } + conn, err := listener.Accept() - //这里记录每个客户端连接的次数,实现获取多个文件 - _, ok := recordClient[ip] - if ok { - if recordClient[ip] < len(fileNames)-1 { - recordClient[ip] += 1 + if err != nil { + log.Pr("Mysql", "127.0.0.1", "Mysql 连接失败", err) } - } else { - recordClient[ip] = 0 - } - go connectionClientHandler(conn) + arr := strings.Split(conn.RemoteAddr().String(), ":") + + ip := arr[0] + + //这里记录每个客户端连接的次数,实现获取多个文件 + _, ok := recordClient[ip] + if ok { + if recordClient[ip] < len(fileNames)-1 { + recordClient[ip] += 1 + } + } else { + recordClient[ip] = 0 + } + + go connectionClientHandler(conn) + + wg.Done() + }) } } diff --git a/core/protocol/redis/redis.go b/core/protocol/redis/redis.go index 0114cab..2056d39 100644 --- a/core/protocol/redis/redis.go +++ b/core/protocol/redis/redis.go @@ -11,6 +11,8 @@ import ( "HFish/utils/is" "HFish/core/rpc/client" "fmt" + "HFish/core/pool" + "time" ) var kvData map[string]string @@ -23,25 +25,37 @@ func Start(addr string) { defer netListen.Close() + wg, poolX := pool.New(10) + defer poolX.Release() + for { - conn, err := netListen.Accept() - if err != nil { - continue - } - arr := strings.Split(conn.RemoteAddr().String(), ":") + wg.Add(1) + poolX.Submit(func() { + time.Sleep(time.Second * 2) - // 判断是否为 RPC 客户端 - var id string + conn, err := netListen.Accept() - if is.Rpc() { - id = client.ReportResult("REDIS", "", arr[0], conn.RemoteAddr().String()+" 已经连接", "0") - } else { - id = strconv.FormatInt(report.ReportRedis(arr[0], "本机", conn.RemoteAddr().String()+" 已经连接"), 10) - } + if err != nil { + log.Pr("Redis", "127.0.0.1", "Redis 连接失败", err) + } - log.Pr("Redis", arr[0], "已经连接") + arr := strings.Split(conn.RemoteAddr().String(), ":") - go handleConnection(conn, id) + // 判断是否为 RPC 客户端 + var id string + + if is.Rpc() { + id = client.ReportResult("REDIS", "", arr[0], conn.RemoteAddr().String()+" 已经连接", "0") + } else { + id = strconv.FormatInt(report.ReportRedis(arr[0], "本机", conn.RemoteAddr().String()+" 已经连接"), 10) + } + + log.Pr("Redis", arr[0], "已经连接") + + go handleConnection(conn, id) + + wg.Done() + }) } } diff --git a/core/protocol/telnet/telnet.go b/core/protocol/telnet/telnet.go index d8056de..9276092 100644 --- a/core/protocol/telnet/telnet.go +++ b/core/protocol/telnet/telnet.go @@ -8,12 +8,14 @@ import ( "os" "HFish/utils/is" "HFish/core/rpc/client" - "strconv" "HFish/core/report" "HFish/utils/log" "github.com/bitly/go-simplejson" "HFish/utils/json" "HFish/utils/file" + "strconv" + "time" + "HFish/core/pool" ) // 服务端连接 @@ -27,29 +29,38 @@ func server(address string, exitChan chan int) { defer l.Close() + wg, poolX := pool.New(10) + defer poolX.Release() + for { - conn, err := l.Accept() + wg.Add(1) + poolX.Submit(func() { + time.Sleep(time.Second * 2) - if err != nil { - fmt.Println(err.Error()) - continue - } + conn, err := l.Accept() - arr := strings.Split(conn.RemoteAddr().String(), ":") + if err != nil { + log.Pr("Telnet", "127.0.0.1", "Telnet 连接失败", err) + } - // 判断是否为 RPC 客户端 - var id string + arr := strings.Split(conn.RemoteAddr().String(), ":") - if is.Rpc() { - id = client.ReportResult("TELNET", "", arr[0], conn.RemoteAddr().String()+" 已经连接", "0") - } else { - id = strconv.FormatInt(report.ReportTelnet(arr[0], "本机", conn.RemoteAddr().String()+" 已经连接"), 10) - } + var id string - log.Pr("Telnet", arr[0], "已经连接") + // 判断是否为 RPC 客户端 + if is.Rpc() { + id = client.ReportResult("TELNET", "", arr[0], conn.RemoteAddr().String()+" 已经连接", "0") + } else { + id = strconv.FormatInt(report.ReportTelnet(arr[0], "本机", conn.RemoteAddr().String()+" 已经连接"), 10) + } - // 根据连接开启会话, 这个过程需要并行执行 - go handleSession(conn, exitChan, id) + log.Pr("Telnet", arr[0], "已经连接") + + // 根据连接开启会话, 这个过程需要并行执行 + go handleSession(conn, exitChan, id) + + wg.Done() + }) } } diff --git a/core/report/report.go b/core/report/report.go index a3f2139..f637781 100644 --- a/core/report/report.go +++ b/core/report/report.go @@ -10,6 +10,9 @@ import ( "strings" "HFish/core/alert" "HFish/utils/conf" + "HFish/core/pool" + "sync" + "github.com/panjf2000/ants" ) type HFishInfo struct { @@ -26,16 +29,37 @@ type HFishInfo struct { time string } +var ( + wg sync.WaitGroup + poolX *ants.Pool + + wgUpdate sync.WaitGroup + poolUpdateX *ants.Pool +) + +func init() { + wg, poolX = pool.New(10) + defer poolX.Release() + + wgUpdate, poolUpdateX = pool.New(10) + defer poolUpdateX.Release() +} + // 通知模块 -func alertx(id string, model string, typex string, projectName string, agent string, ipx string, country string, region string, city string, infox string, time string) { - // 邮件通知 - alert.AlertMail(model, typex, agent, ipx, country, region, city, infox) +func alertx(id string, model string, typex string, projectName string, agent string, ipx string, country string, region string, city string, infox string, timex string) { + wg.Add(1) + poolX.Submit(func() { + time.Sleep(time.Second * 2) - // WebHook - alert.AlertWebHook(id, model, typex, projectName, agent, ipx, country, region, city, infox, time) + // 邮件通知 + alert.AlertMail(model, typex, agent, ipx, country, region, city, infox, &wg) - // 大数据展示 - //alert.AlertDataWs(model, typex, projectName, agent, ipx, country, region, city, time) + // WebHook + alert.AlertWebHook(id, model, typex, projectName, agent, ipx, country, region, city, infox, timex, &wg) + + // 大数据展示 + //alert.AlertDataWs(model, typex, projectName, agent, ipx, country, region, city, time) + }) } // 上报 集群 状态 @@ -113,6 +137,7 @@ func isWhiteIp(ip string) bool { // 通用的插入 func insertInfo(typex string, projectName string, agent string, ipx string, country string, region string, city string, info string) int64 { + id, err := dbUtil.DB().Table("hfish_info").Data(map[string]interface{}{ "type": typex, "project_name": projectName, @@ -128,38 +153,54 @@ func insertInfo(typex string, projectName string, agent string, ipx string, coun if err != nil { log.Pr("HFish", "127.0.0.1", "插入上钩信息失败", err) } + return id } +// 更新 +func updateInfoCore(id string, info string) { + time.Sleep(time.Second * 2) + + try.Try(func() { + var sql string + + // 此处为了兼容 Mysql + Sqlite + dbType := conf.Get("admin", "db_type") + + if dbType == "sqlite" { + sql = ` + UPDATE hfish_info + SET info = info||? + WHERE + id = ?; + ` + } else if dbType == "mysql" { + sql = ` + UPDATE hfish_info + SET info = CONCAT(info, ?) + WHERE + id = ?; + ` + } + + _, err := dbUtil.DB().Execute(sql, info, id) + + if err != nil { + log.Pr("HFish", "127.0.0.1", "更新上钩信息失败", err) + } + + wgUpdate.Done() + }).Catch(func() { + wgUpdate.Done() + }) +} + // 通用的更新 func updateInfo(id string, info string) { - - var sql string - - // 此处为了兼容 Mysql + Sqlite - dbType := conf.Get("admin", "db_type") - - if dbType == "sqlite" { - sql = ` - UPDATE hfish_info - SET info = info||? - WHERE - id = ?; - ` - } else if dbType == "mysql" { - sql = ` - UPDATE hfish_info - SET info = CONCAT(info, ?) - WHERE - id = ?; - ` - } - - _, err := dbUtil.DB().Execute(sql, info, id) - - if err != nil { - log.Pr("HFish", "127.0.0.1", "更新上钩信息失败", err) - } + wgUpdate.Add(1) + poolUpdateX.Submit(func() { + updateInfoCore(id, info) + }) } // 上报 WEB @@ -194,6 +235,12 @@ func ReportPlugWeb(projectName string, agent string, ipx string, info string) { // 上报 SSH func ReportSSH(ipx string, agent string, info string) int64 { + defer func() { + if err := recover(); err != nil { + log.Pr("HFish", "127.0.0.1", "执行SSH插入失败", err) + } + }() + // IP 不在白名单,进行上报 if (isWhiteIp(ipx) == false) { country, region, city := ip.GetIp(ipx) @@ -206,6 +253,12 @@ func ReportSSH(ipx string, agent string, info string) int64 { // 更新 SSH 操作 func ReportUpdateSSH(id string, info string) { + defer func() { + if err := recover(); err != nil { + log.Pr("HFish", "127.0.0.1", "执行SSH更新失败", err) + } + }() + if (id != "0") { go updateInfo(id, info) go alertx(id, "update", "SSH", "SSH蜜罐", "", "", "", "", "", info, time.Now().Format("2006-01-02 15:04:05")) diff --git a/db/hfish.db b/db/hfish.db index 358601c..510e0e2 100644 Binary files a/db/hfish.db and b/db/hfish.db differ diff --git a/db/sql/hfish_colony.sql b/db/sql/hfish_colony.sql new file mode 100644 index 0000000..4a081a6 --- /dev/null +++ b/db/sql/hfish_colony.sql @@ -0,0 +1,24 @@ +-- ---------------------------- +-- Table structure for `hfish_colony` +-- ---------------------------- +DROP TABLE IF EXISTS `hfish_colony`; +CREATE TABLE `hfish_colony` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `agent_name` varchar(20) NOT NULL DEFAULT '', + `agent_ip` varchar(20) NOT NULL DEFAULT '', + `web_status` int(2) NOT NULL DEFAULT '0', + `deep_status` int(2) NOT NULL DEFAULT '0', + `ssh_status` int(2) NOT NULL DEFAULT '0', + `redis_status` int(2) NOT NULL DEFAULT '0', + `mysql_status` int(2) NOT NULL DEFAULT '0', + `http_status` int(2) NOT NULL DEFAULT '0', + `telnet_status` int(2) NOT NULL DEFAULT '0', + `ftp_status` int(2) NOT NULL DEFAULT '0', + `mem_cache_status` int(2) NOT NULL DEFAULT '0', + `plug_status` int(2) NOT NULL DEFAULT '0', + `last_update_time` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `un_agent` (`agent_name`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/db/sql/hfish_info.sql b/db/sql/hfish_info.sql new file mode 100644 index 0000000..8af17f6 --- /dev/null +++ b/db/sql/hfish_info.sql @@ -0,0 +1,19 @@ +-- ---------------------------- +-- Table structure for `hfish_info` +-- ---------------------------- +DROP TABLE IF EXISTS `hfish_info`; +CREATE TABLE `hfish_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(20) NOT NULL DEFAULT '', + `project_name` varchar(20) NOT NULL DEFAULT '', + `agent` varchar(20) NOT NULL DEFAULT '', + `ip` varchar(20) NOT NULL DEFAULT '', + `country` varchar(10) NOT NULL DEFAULT '', + `region` varchar(10) NOT NULL DEFAULT '', + `city` varchar(10) NOT NULL, + `info` text NOT NULL, + `create_time` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/db/sql/hfish_setting.sql b/db/sql/hfish_setting.sql new file mode 100644 index 0000000..daac760 --- /dev/null +++ b/db/sql/hfish_setting.sql @@ -0,0 +1,24 @@ +-- ---------------------------- +-- Table structure for `hfish_setting` +-- ---------------------------- +DROP TABLE IF EXISTS `hfish_setting`; +CREATE TABLE `hfish_setting` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `type` varchar(50) NOT NULL DEFAULT '', + `info` varchar(50) NOT NULL DEFAULT '', + `update_time` datetime NOT NULL, + `status` int(2) NOT NULL DEFAULT '0', + `setting_name` varchar(50) NOT NULL DEFAULT '', + `setting_dis` varchar(50) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `index_key` (`type`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4; + +-- ---------------------------- +-- Records of `hfish_setting` +-- ---------------------------- +BEGIN; +INSERT INTO `hfish_setting` VALUES ('1', 'mail', '', '2019-09-02 20:15:00', '0', 'E-mail 群发', '群发邮件SMTP服务器配置'), ('2', 'alertMail', '', '2019-09-02 18:58:12', '0', 'E-mail 通知', '蜜罐告警会通过邮件告知信息'), ('3', 'webHook', '', '2019-09-03 11:49:00', '0', 'WebHook 通知', '蜜罐告警会请求指定API告知信息'), ('4', 'whiteIp', '', '2019-09-02 20:15:00', '0', 'IP 白名单', '蜜罐上钩会过滤掉白名单IP'); +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/error/error.go b/error/error.go index d65d8a2..8f07b54 100644 --- a/error/error.go +++ b/error/error.go @@ -19,6 +19,9 @@ const ( ErrFailConfigCode = 1004 ErrFailConfigMsg = "请配置后在启用" + + ErrFailPlugCode = 1005 + ErrFailPlugMsg = "上报信息错误" ) func Check(e error, tips string) { diff --git a/go.mod b/go.mod index 6767413..101278d 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,17 @@ require ( github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/gin-gonic/gin v1.4.0 github.com/gliderlabs/ssh v0.2.2 - github.com/gorilla/websocket v1.4.1 // indirect + github.com/go-sql-driver/mysql v1.4.1 + github.com/gohouse/gorose v0.0.0-20190830103550-ad3ce0985b9e + github.com/gorilla/websocket v1.4.1 github.com/ipipdotnet/ipdb-go v1.2.0 github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 github.com/kr/pretty v0.1.0 // indirect github.com/mattn/go-sqlite3 v1.11.0 + github.com/panjf2000/ants v1.2.0 github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 + golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 + google.golang.org/appengine v1.6.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.46.0 diff --git a/go.sum b/go.sum index bc1e801..b8144b4 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,14 @@ github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/gohouse/gocar v0.0.2 h1:pzf7zhDSuWa7GpSszi6mEQslp+Pthypn5yi8c+zomK0= +github.com/gohouse/gocar v0.0.2/go.mod h1:zE2+ip1u8MKvLyqTKxQIeZEI4lN1XPXK7AZdbikD6RE= +github.com/gohouse/gorose v0.0.0-20190830103550-ad3ce0985b9e h1:gvQbXcpfZzyVnUOUDYdy2TRm0z8WATHgHQ+CJZYjFSE= +github.com/gohouse/gorose v0.0.0-20190830103550-ad3ce0985b9e/go.mod h1:+1d8SYnSZQxO01R1Vj65tKQ873DN6hHgVtJ9CmGPpQ0= +github.com/gohouse/t v0.0.5 h1:ol19APh/fC7usS2XgZ7i3Usgo8eF9xszOPfGPhR6Zg8= +github.com/gohouse/t v0.0.5/go.mod h1:CUtvHWNU9GY0Lvk+gcrhs9Ixmei7J5QQXiAvqcwccsk= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -41,12 +49,15 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/panjf2000/ants v1.2.0 h1:Ufw4aDz9RqH1RVblx2W9L9Uv5vSX5apbX5+peR7LQ5k= +github.com/panjf2000/ants v1.2.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= @@ -61,15 +72,29 @@ github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +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-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c h1:+EXw7AwNOKzPFXMZ1yNjO40aWCh3PIquJB2fYlv9wcs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +google.golang.org/appengine v1.6.2 h1:j8RI1yW0SkI+paT6uGwMlrMI/6zwYA6/CFil8rxOzGI= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/main.go b/main.go index b3c60be..88f302c 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,7 @@ func main() { } else if args[1] == "init" || args[1] == "--init" { setting.Init() } else if args[1] == "version" || args[1] == "--version" { - fmt.Println("v0.3") + fmt.Println("v0.3.1") } else if args[1] == "run" || args[1] == "--run" { setting.Run() } else { diff --git a/view/api/view.go b/view/api/view.go index 488c110..32138aa 100644 --- a/view/api/view.go +++ b/view/api/view.go @@ -10,6 +10,7 @@ import ( "HFish/core/rpc/client" "HFish/utils/is" "HFish/utils/log" + "fmt" ) // 上报WEB蜜罐 @@ -30,6 +31,8 @@ func ReportWeb(c *gin.Context) { "code": error.ErrFailApiKeyCode, "msg": error.ErrFailApiKeyMsg, }) + + return } else { // 判断是否为 RPC 客户端 @@ -64,6 +67,8 @@ func ReportDeepWeb(c *gin.Context) { "code": error.ErrFailApiKeyCode, "msg": error.ErrFailApiKeyMsg, }) + + return } else { // 判断是否为 RPC 客户端 @@ -80,26 +85,60 @@ func ReportDeepWeb(c *gin.Context) { } } +type PlugInfo struct { + Name string `json:"name"` + Ip string `json:"ip"` + SecKey string `json:"sec_key"` + Info map[string]interface{} `json:"info"` +} + // 蜜罐插件API func ReportPlugWeb(c *gin.Context) { - name := c.PostForm("name") - info := c.PostForm("info") - secKey := c.PostForm("sec_key") - ip := c.PostForm("ip") + var info PlugInfo + err := c.BindJSON(&info) + + if err != nil { + fmt.Println(err) + log.Pr("HFish", "127.0.0.1", "插件上报信息错误", err) + + c.JSON(http.StatusOK, gin.H{ + "code": error.ErrFailPlugCode, + "msg": error.ErrFailPlugMsg, + "data": err, + }) + return + } + + args := "" + + if len(info.Info) != 0 { + for k, v := range info.Info["args"].(map[string]interface{}) { + if args == "" { + args += k + "=" + v.(string) + } else { + args += "&" + k + "=" + v.(string) + } + } + } + + data := "Host:" + info.Info["host"].(string) + "&&Url:" + info.Info["uri"].(string) + "&&Method:" + info.Info["method"].(string) + "&&Args:" + args + "&&UserAgent:" + info.Info["http_user_agent"].(string) + "&&RemoteAddr:" + info.Info["remote_addr"].(string) + "&&TimeLocal:" + info.Info["time_local"].(string) apiSecKey := conf.Get("api", "sec_key") - if secKey != apiSecKey { + if info.SecKey != apiSecKey { c.JSON(http.StatusOK, gin.H{ "code": error.ErrFailApiKeyCode, "msg": error.ErrFailApiKeyMsg, }) + + return } else { + // 判断是否为 RPC 客户端 if is.Rpc() { - go client.ReportResult("PLUG", name, ip, info, "0") + go client.ReportResult("PLUG", info.Name, info.Ip, data, "0") } else { - go report.ReportPlugWeb(name, "本机", ip, info) + go report.ReportPlugWeb(info.Name, "本机", info.Ip, data) } c.JSON(http.StatusOK, gin.H{