支持 Mysql

This commit is contained in:
SanJin 2019-09-08 23:14:24 +08:00
parent 56cc2e1ca2
commit 5062db1227
22 changed files with 457 additions and 182 deletions

View File

@ -120,7 +120,7 @@
for (var i = 0; i < data.length; i++) {
_h += '<tr>';
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 += ' <td class="td" style="text-align: center;"><span class="closex"></span></td>';
}
if (data[i].dart_status == 1) {
if (data[i].deep_status == 1) {
_h += ' <td class="td" style="text-align: center;"><span class="openx"></span></td>';
} else {
_h += ' <td class="td" style="text-align: center;"><span class="closex"></span></td>';

View File

@ -391,7 +391,7 @@
_h += ' <td><span class="info" onclick="show(' + data.result[i].id + ')">点击查看</span></td>';
_h += ' <td class="td"><span class="cinfo">' + data.result[i].info.length + '</span></td>';
_h += ' <td class="td">' + data.result[i].create_time.replace("T", " ").replace("+08:00", " ") + '</td>';
_h += ' <td class="td">' + data.result[i].create_time.replace("T", " ").replace("+08:00", " ").replace("Z", "") + '</td>';
_h += '</tr>';
}

View File

@ -59,7 +59,7 @@
<tr id="tr{{$e.type}}" data-id="{{$e.id}}">
<td style="font-weight: bold;">{{$e.setting_name}} </td>
<td>{{$e.setting_dis}}</td>
<td id="trx{{$e.type}}"><script>var t={{$e.update_time}}; document.getElementById("trx{{$e.type}}").innerHTML= t.replace("T", " ").replace("+08:00", " ");</script></td>
<td id="trx{{$e.type}}"><script>var t={{$e.update_time}}; document.getElementById("trx{{$e.type}}").innerHTML= t.replace("T", " ").replace("+08:00", " ").replace("Z", "");</script></td>
<td>{{if ne $e.info ""}}
<span class="yes_config">已配置</span>
{{else}}

View File

@ -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]

View File

@ -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()
})
}

View File

@ -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)

12
core/pool/pool.go Normal file
View File

@ -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
}

View File

@ -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.

View File

@ -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 {

View File

@ -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()
})
}
}

View File

@ -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()
})
}
}

View File

@ -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()
})
}
}

View File

@ -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"))

Binary file not shown.

24
db/sql/hfish_colony.sql Normal file
View File

@ -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;

19
db/sql/hfish_info.sql Normal file
View File

@ -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;

24
db/sql/hfish_setting.sql Normal file
View File

@ -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;

View File

@ -19,6 +19,9 @@ const (
ErrFailConfigCode = 1004
ErrFailConfigMsg = "请配置后在启用"
ErrFailPlugCode = 1005
ErrFailPlugMsg = "上报信息错误"
)
func Check(e error, tips string) {

8
go.mod
View File

@ -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

25
go.sum
View File

@ -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=

View File

@ -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 {

View File

@ -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{