mirror of https://github.com/bjdgyc/anylink.git
审计日志异步+批量入库
This commit is contained in:
parent
10ca7c9c85
commit
3c5acd31fb
|
@ -16,6 +16,11 @@ func Add(data interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddBatch(data interface{}) error {
|
||||||
|
_, err := xdb.Insert(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func Update(fieldName string, value interface{}, data interface{}) error {
|
func Update(fieldName string, value interface{}, data interface{}) error {
|
||||||
_, err := xdb.Where(fieldName+"=?", value).Update(data)
|
_, err := xdb.Where(fieldName+"=?", value).Update(data)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -11,6 +11,7 @@ require (
|
||||||
github.com/google/gopacket v1.1.19
|
github.com/google/gopacket v1.1.19
|
||||||
github.com/gorilla/handlers v1.5.1
|
github.com/gorilla/handlers v1.5.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/ivpusic/grpool v1.0.0
|
||||||
github.com/lib/pq v1.10.2
|
github.com/lib/pq v1.10.2
|
||||||
github.com/mattn/go-sqlite3 v1.14.8
|
github.com/mattn/go-sqlite3 v1.14.8
|
||||||
github.com/orcaman/concurrent-map v1.0.0
|
github.com/orcaman/concurrent-map v1.0.0
|
||||||
|
|
|
@ -266,6 +266,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||||
|
github.com/ivpusic/grpool v1.0.0 h1:+FCiCo3GhfsvzfXuJWnpJUNb/VaqyYVgG8C+qvh07Rc=
|
||||||
|
github.com/ivpusic/grpool v1.0.0/go.mod h1:WPmiAI5ExAn06vg+0JzyPzXMQutJmpb7TrBtyLJkOHQ=
|
||||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
|
|
|
@ -1,24 +1,12 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
|
||||||
|
|
||||||
"github.com/bjdgyc/anylink/base"
|
"github.com/bjdgyc/anylink/base"
|
||||||
"github.com/bjdgyc/anylink/dbdata"
|
"github.com/bjdgyc/anylink/dbdata"
|
||||||
"github.com/bjdgyc/anylink/pkg/utils"
|
|
||||||
"github.com/bjdgyc/anylink/sessdata"
|
"github.com/bjdgyc/anylink/sessdata"
|
||||||
"github.com/songgao/water/waterutil"
|
"github.com/songgao/water/waterutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
acc_proto_udp = iota + 1
|
|
||||||
acc_proto_tcp
|
|
||||||
acc_proto_https
|
|
||||||
acc_proto_http
|
|
||||||
)
|
|
||||||
|
|
||||||
func payloadIn(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
func payloadIn(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
||||||
if pl.LType == sessdata.LTypeIPData && pl.PType == 0x00 {
|
if pl.LType == sessdata.LTypeIPData && pl.PType == 0x00 {
|
||||||
// 进行Acl规则判断
|
// 进行Acl规则判断
|
||||||
|
@ -27,8 +15,11 @@ func payloadIn(cSess *sessdata.ConnSession, pl *sessdata.Payload) bool {
|
||||||
// 校验不通过直接丢弃
|
// 校验不通过直接丢弃
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if base.Cfg.AuditInterval >= 0 {
|
||||||
logAudit(cSess, pl)
|
cSess.IpAuditPool.JobQueue <- func() {
|
||||||
|
logAudit(cSess, pl)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closed := false
|
closed := false
|
||||||
|
@ -106,68 +97,3 @@ func checkLinkAcl(group *dbdata.Group, pl *sessdata.Payload) bool {
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 访问日志审计
|
|
||||||
func logAudit(cSess *sessdata.ConnSession, pl *sessdata.Payload) {
|
|
||||||
if base.Cfg.AuditInterval < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ipProto := waterutil.IPv4Protocol(pl.Data)
|
|
||||||
// 访问协议
|
|
||||||
var accessProto uint8
|
|
||||||
// 只统计 tcp和udp 的访问
|
|
||||||
switch ipProto {
|
|
||||||
case waterutil.TCP:
|
|
||||||
accessProto = acc_proto_tcp
|
|
||||||
case waterutil.UDP:
|
|
||||||
accessProto = acc_proto_udp
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ipSrc := waterutil.IPv4Source(pl.Data)
|
|
||||||
ipDst := waterutil.IPv4Destination(pl.Data)
|
|
||||||
ipPort := waterutil.IPv4DestinationPort(pl.Data)
|
|
||||||
|
|
||||||
b := getByte51()
|
|
||||||
key := *b
|
|
||||||
copy(key[:16], ipSrc)
|
|
||||||
copy(key[16:32], ipDst)
|
|
||||||
binary.BigEndian.PutUint16(key[32:34], ipPort)
|
|
||||||
|
|
||||||
info := ""
|
|
||||||
if ipProto == waterutil.TCP {
|
|
||||||
accessProto, info = onTCP(waterutil.IPv4Payload(pl.Data))
|
|
||||||
}
|
|
||||||
key[34] = byte(accessProto)
|
|
||||||
if info != "" {
|
|
||||||
md5Sum := md5.Sum([]byte(info))
|
|
||||||
copy(key[35:51], hex.EncodeToString(md5Sum[:]))
|
|
||||||
}
|
|
||||||
s := utils.BytesToString(key)
|
|
||||||
nu := utils.NowSec().Unix()
|
|
||||||
|
|
||||||
// 判断已经存在,并且没有过期
|
|
||||||
v, ok := cSess.IpAuditMap.Get(s)
|
|
||||||
if ok && nu-v.(int64) < int64(base.Cfg.AuditInterval) {
|
|
||||||
// 回收byte对象
|
|
||||||
putByte51(b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cSess.IpAuditMap.Set(s, nu)
|
|
||||||
|
|
||||||
audit := dbdata.AccessAudit{
|
|
||||||
Username: cSess.Sess.Username,
|
|
||||||
Protocol: uint8(ipProto),
|
|
||||||
Src: ipSrc.String(),
|
|
||||||
Dst: ipDst.String(),
|
|
||||||
DstPort: ipPort,
|
|
||||||
CreatedAt: utils.NowSec(),
|
|
||||||
AccessProto: accessProto,
|
|
||||||
Info: info,
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = dbdata.Add(audit)
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bjdgyc/anylink/base"
|
||||||
|
"github.com/bjdgyc/anylink/dbdata"
|
||||||
|
"github.com/bjdgyc/anylink/pkg/utils"
|
||||||
|
"github.com/bjdgyc/anylink/sessdata"
|
||||||
|
"github.com/songgao/water/waterutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
acc_proto_udp = iota + 1
|
||||||
|
acc_proto_tcp
|
||||||
|
acc_proto_https
|
||||||
|
acc_proto_http
|
||||||
|
)
|
||||||
|
|
||||||
|
// 保存批量的审计日志
|
||||||
|
type LogBatch struct {
|
||||||
|
Logs []dbdata.AccessAudit
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日志池
|
||||||
|
type LogSink struct {
|
||||||
|
logChan chan dbdata.AccessAudit
|
||||||
|
autoCommitChan chan *LogBatch // 超时通知
|
||||||
|
}
|
||||||
|
|
||||||
|
var logAuditSink *LogSink
|
||||||
|
|
||||||
|
// 写入日志通道
|
||||||
|
func logAuditWrite(aa dbdata.AccessAudit) {
|
||||||
|
logAuditSink.logChan <- aa
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量写入数据表
|
||||||
|
func logAuditBatch() {
|
||||||
|
if base.Cfg.AuditInterval < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logAuditSink = &LogSink{
|
||||||
|
logChan: make(chan dbdata.AccessAudit, 1000),
|
||||||
|
autoCommitChan: make(chan *LogBatch, 10),
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
limit = 100 // 超过上限批量写入数据表
|
||||||
|
logAudit dbdata.AccessAudit
|
||||||
|
logBatch *LogBatch
|
||||||
|
commitTimer *time.Timer // 超时自动提交
|
||||||
|
timeOutBatch *LogBatch
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case logAudit = <-logAuditSink.logChan:
|
||||||
|
if logBatch == nil {
|
||||||
|
logBatch = &LogBatch{}
|
||||||
|
commitTimer = time.AfterFunc(
|
||||||
|
1*time.Second, func(logBatch *LogBatch) func() {
|
||||||
|
return func() {
|
||||||
|
logAuditSink.autoCommitChan <- logBatch
|
||||||
|
}
|
||||||
|
}(logBatch),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
logBatch.Logs = append(logBatch.Logs, logAudit)
|
||||||
|
if len(logBatch.Logs) >= limit {
|
||||||
|
commitTimer.Stop()
|
||||||
|
_ = dbdata.AddBatch(logBatch.Logs)
|
||||||
|
logBatch = nil
|
||||||
|
}
|
||||||
|
case timeOutBatch = <-logAuditSink.autoCommitChan:
|
||||||
|
if timeOutBatch != logBatch {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if logBatch != nil {
|
||||||
|
_ = dbdata.AddBatch(logBatch.Logs)
|
||||||
|
}
|
||||||
|
logBatch = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析IP包的数据
|
||||||
|
func logAudit(cSess *sessdata.ConnSession, pl *sessdata.Payload) {
|
||||||
|
ipProto := waterutil.IPv4Protocol(pl.Data)
|
||||||
|
// 访问协议
|
||||||
|
var accessProto uint8
|
||||||
|
// 只统计 tcp和udp 的访问
|
||||||
|
switch ipProto {
|
||||||
|
case waterutil.TCP:
|
||||||
|
accessProto = acc_proto_tcp
|
||||||
|
case waterutil.UDP:
|
||||||
|
accessProto = acc_proto_udp
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ipSrc := waterutil.IPv4Source(pl.Data)
|
||||||
|
ipDst := waterutil.IPv4Destination(pl.Data)
|
||||||
|
ipPort := waterutil.IPv4DestinationPort(pl.Data)
|
||||||
|
|
||||||
|
b := getByte51()
|
||||||
|
key := *b
|
||||||
|
copy(key[:16], ipSrc)
|
||||||
|
copy(key[16:32], ipDst)
|
||||||
|
binary.BigEndian.PutUint16(key[32:34], ipPort)
|
||||||
|
|
||||||
|
info := ""
|
||||||
|
if ipProto == waterutil.TCP {
|
||||||
|
plData := waterutil.IPv4Payload(pl.Data)
|
||||||
|
if len(plData) < 14 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
flags := plData[13]
|
||||||
|
switch flags {
|
||||||
|
case flags & 0x20:
|
||||||
|
// base.Debug("URG "+info, "#", str)
|
||||||
|
return
|
||||||
|
case flags & 0x10:
|
||||||
|
// base.Debug("ACK ", ipSrc, "#", ipDst, "#", ipPort)
|
||||||
|
return
|
||||||
|
case flags & 0x08:
|
||||||
|
// base.Debug("PSH "+info, "#", str)
|
||||||
|
return
|
||||||
|
case flags & 0x04:
|
||||||
|
// base.Debug("RST "+info, "#", str)
|
||||||
|
return
|
||||||
|
case flags & 0x02:
|
||||||
|
// base.Debug("SYNC "+info, "#", str)
|
||||||
|
return
|
||||||
|
case flags & 0x01:
|
||||||
|
// base.Debug("FIN "+info, "#", str)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
accessProto, info = onTCP(plData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key[34] = byte(accessProto)
|
||||||
|
if info != "" {
|
||||||
|
md5Sum := md5.Sum([]byte(info))
|
||||||
|
copy(key[35:51], hex.EncodeToString(md5Sum[:]))
|
||||||
|
}
|
||||||
|
s := utils.BytesToString(key)
|
||||||
|
nu := utils.NowSec().Unix()
|
||||||
|
|
||||||
|
// 判断已经存在,并且没有过期
|
||||||
|
v, ok := cSess.IpAuditMap.Get(s)
|
||||||
|
if ok && nu-v.(int64) < int64(base.Cfg.AuditInterval) {
|
||||||
|
// 回收byte对象
|
||||||
|
putByte51(b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cSess.IpAuditMap.Set(s, nu)
|
||||||
|
|
||||||
|
audit := dbdata.AccessAudit{
|
||||||
|
Username: cSess.Sess.Username,
|
||||||
|
Protocol: uint8(ipProto),
|
||||||
|
Src: ipSrc.String(),
|
||||||
|
Dst: ipDst.String(),
|
||||||
|
DstPort: ipPort,
|
||||||
|
CreatedAt: utils.NowSec(),
|
||||||
|
AccessProto: accessProto,
|
||||||
|
Info: info,
|
||||||
|
}
|
||||||
|
logAuditWrite(audit)
|
||||||
|
}
|
|
@ -5,22 +5,23 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tcpParsers = []func([]byte) (uint8, string){
|
var tcpParsers = []func([]byte) (uint8, string){
|
||||||
sniParser,
|
sniNewParser,
|
||||||
httpParser,
|
httpParser,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
sniRe = regexp.MustCompile("\x00\x00.{4}\x00.{2}([a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6})\x00")
|
|
||||||
)
|
|
||||||
|
|
||||||
func onTCP(payload []byte) (uint8, string) {
|
func onTCP(payload []byte) (uint8, string) {
|
||||||
if len(payload) < 13 {
|
size := len(payload)
|
||||||
|
if size < 13 {
|
||||||
return acc_proto_tcp, ""
|
return acc_proto_tcp, ""
|
||||||
}
|
}
|
||||||
ihl := (payload[12] & 0xf0) >> 2
|
ihl := (payload[12] & 0xf0) >> 2
|
||||||
|
if int(ihl) > size {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
data := payload[ihl:]
|
data := payload[ihl:]
|
||||||
for _, parser := range tcpParsers {
|
for _, parser := range tcpParsers {
|
||||||
if proto, info := parser(data); info != "" {
|
if proto, info := parser(data); info != "" {
|
||||||
|
@ -30,11 +31,133 @@ func onTCP(payload []byte) (uint8, string) {
|
||||||
return acc_proto_tcp, ""
|
return acc_proto_tcp, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sniNewParser(b []byte) (uint8, string) {
|
||||||
|
dataSize := len(b)
|
||||||
|
if dataSize < 2 || b[0] != 0x16 || b[1] != 0x03 {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
rest := b[5:]
|
||||||
|
restLen := len(rest)
|
||||||
|
if restLen == 0 {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
current := 0
|
||||||
|
handshakeType := rest[0]
|
||||||
|
current += 1
|
||||||
|
if handshakeType != 0x1 {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
// Skip over another length
|
||||||
|
current += 3
|
||||||
|
// Skip over protocolversion
|
||||||
|
current += 2
|
||||||
|
// Skip over random number
|
||||||
|
current += 4 + 28
|
||||||
|
if current >= restLen {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
// Skip over session ID
|
||||||
|
sessionIDLength := int(rest[current])
|
||||||
|
current += 1
|
||||||
|
current += sessionIDLength
|
||||||
|
if current >= restLen {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
cipherSuiteLength := (int(rest[current]) << 8) + int(rest[current+1])
|
||||||
|
current += 2
|
||||||
|
current += cipherSuiteLength
|
||||||
|
if current >= restLen {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
compressionMethodLength := int(rest[current])
|
||||||
|
current += 1
|
||||||
|
current += compressionMethodLength
|
||||||
|
|
||||||
|
if current >= restLen {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
current += 2
|
||||||
|
hostname := ""
|
||||||
|
for current+4 < restLen && hostname == "" {
|
||||||
|
extensionType := (int(rest[current]) << 8) + int(rest[current+1])
|
||||||
|
current += 2
|
||||||
|
extensionDataLength := (int(rest[current]) << 8) + int(rest[current+1])
|
||||||
|
current += 2
|
||||||
|
if extensionType == 0 {
|
||||||
|
// Skip over number of names as we're assuming there's just one
|
||||||
|
current += 2
|
||||||
|
if current >= restLen {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
nameType := rest[current]
|
||||||
|
current += 1
|
||||||
|
if nameType != 0 {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
if current+1 >= restLen {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
nameLen := (int(rest[current]) << 8) + int(rest[current+1])
|
||||||
|
current += 2
|
||||||
|
if current+nameLen >= restLen {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
hostname = string(rest[current : current+nameLen])
|
||||||
|
}
|
||||||
|
current += extensionDataLength
|
||||||
|
}
|
||||||
|
if hostname == "" {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
return acc_proto_https, hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beta
|
||||||
|
func httpNewParser(data []byte) (uint8, string) {
|
||||||
|
methodArr := []string{"OPTIONS", "HEAD", "GET", "POST", "PUT", "DELETE", "TRACE", "CONNECT"}
|
||||||
|
pos := bytes.IndexByte(data, 10)
|
||||||
|
if pos == -1 {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
method, uri, _ := strings.Cut(string(data[:pos]), " ")
|
||||||
|
ok := false
|
||||||
|
for _, v := range methodArr {
|
||||||
|
if v == method {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
hostname := ""
|
||||||
|
// GET http://www.google.com/index.html HTTP/1.1
|
||||||
|
if len(uri) > 7 && uri[:4] == "http" {
|
||||||
|
uriSlice := strings.Split(uri[7:], "/")
|
||||||
|
hostname = uriSlice[0]
|
||||||
|
return acc_proto_http, hostname
|
||||||
|
}
|
||||||
|
packet := string(data)
|
||||||
|
hostPos := strings.Index(packet, "Host: ")
|
||||||
|
if hostPos == -1 {
|
||||||
|
hostPos = strings.Index(packet, "HOST: ")
|
||||||
|
if hostPos == -1 {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hostEndPos := strings.Index(packet[hostPos:], "\n")
|
||||||
|
if hostEndPos == -1 {
|
||||||
|
return acc_proto_tcp, ""
|
||||||
|
}
|
||||||
|
hostname = packet[hostPos+6 : hostPos+hostEndPos-1]
|
||||||
|
return acc_proto_http, hostname
|
||||||
|
}
|
||||||
|
|
||||||
func sniParser(data []byte) (uint8, string) {
|
func sniParser(data []byte) (uint8, string) {
|
||||||
dataSize := len(data)
|
dataSize := len(data)
|
||||||
if dataSize < 2 || data[0] != 0x16 || data[1] != 0x03 {
|
if dataSize < 2 || data[0] != 0x16 || data[1] != 0x03 {
|
||||||
return acc_proto_tcp, ""
|
return acc_proto_tcp, ""
|
||||||
}
|
}
|
||||||
|
sniRe := regexp.MustCompile("\x00\x00.{4}\x00.{2}([a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6})\x00")
|
||||||
m := sniRe.FindSubmatch(data)
|
m := sniRe.FindSubmatch(data)
|
||||||
if len(m) < 2 {
|
if len(m) < 2 {
|
||||||
return acc_proto_tcp, ""
|
return acc_proto_tcp, ""
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
httpsPacket = []byte{148, 152, 1, 187, 110, 58, 1, 82, 45, 244, 84, 34, 80, 24, 1, 54, 130, 216, 0, 0, 22, 3, 1, 2, 0, 1, 0, 1, 252, 3, 3, 110, 25, 141, 34, 174, 156, 58, 62, 6, 81, 231, 155, 116, 22, 30, 12, 195, 250, 214, 125, 161, 255, 107, 203, 106, 173, 167, 25, 6, 78, 13, 5, 32, 228, 144, 162, 34, 197, 103, 28, 86, 28, 66, 156, 108, 36, 31, 171, 238, 245, 133, 82, 184, 67, 0, 89, 194, 8, 172, 219, 83, 62, 90, 133, 223, 0, 14, 19, 1, 19, 2, 19, 3, 192, 43, 192, 44, 192, 47, 192, 48, 1, 0, 1, 165, 0, 0, 0, 31, 0, 29, 0, 0, 26, 106, 103, 119, 45, 100, 114, 99, 110, 46, 106, 111, 115, 46, 100, 98, 97, 110, 107, 99, 108, 111, 117, 100, 46, 99, 110, 0, 23, 0, 0, 255, 1, 0, 1, 0, 0, 10, 0, 8, 0, 6, 0, 29, 0, 23, 0, 24, 0, 11, 0, 2, 1, 0, 0, 35, 0, 208, 204, 119, 182, 195, 85, 35, 227, 85, 38, 141, 121, 60, 221, 102, 189, 82, 161, 136, 147, 248, 243, 32, 17, 28, 191, 115, 109, 63, 239, 38, 44, 22, 180, 30, 142, 213, 136, 229, 115, 24, 99, 225, 150, 231, 152, 12, 7, 210, 230, 134, 189, 83, 193, 253, 130, 123, 242, 15, 60, 122, 146, 187, 107, 173, 113, 167, 28, 65, 242, 221, 224, 20, 130, 12, 35, 247, 29, 123, 145, 18, 171, 197, 193, 0, 152, 32, 129, 227, 54, 124, 94, 154, 65, 99, 5, 90, 141, 113, 224, 189, 232, 169, 33, 159, 66, 230, 39, 1, 206, 193, 213, 154, 217, 18, 8, 205, 168, 140, 25, 229, 82, 56, 14, 134, 209, 113, 209, 28, 205, 71, 143, 44, 89, 69, 58, 236, 211, 80, 41, 136, 44, 23, 87, 16, 81, 133, 54, 61, 19, 97, 133, 69, 182, 98, 201, 210, 139, 195, 0, 108, 215, 79, 194, 7, 56, 126, 203, 43, 229, 224, 138, 41, 55, 41, 207, 74, 67, 5, 26, 19, 156, 130, 218, 27, 223, 79, 204, 82, 209, 61, 239, 44, 247, 214, 175, 1, 192, 192, 192, 11, 247, 243, 48, 29, 77, 90, 100, 93, 0, 16, 0, 14, 0, 12, 2, 104, 50, 8, 104, 116, 116, 112, 47, 49, 46, 49, 0, 5, 0, 5, 1, 0, 0, 0, 0, 0, 13, 0, 20, 0, 18, 4, 3, 8, 4, 4, 1, 5, 3, 8, 5, 5, 1, 8, 6, 6, 1, 2, 1, 0, 51, 0, 38, 0, 36, 0, 29, 0, 32, 38, 165, 55, 231, 178, 23, 75, 55, 19, 164, 173, 248, 204, 115, 141, 138, 78, 66, 254, 21, 79, 109, 43, 124, 242, 80, 10, 185, 127, 92, 125, 36, 0, 45, 0, 2, 1, 1, 0, 43, 0, 5, 4, 3, 4, 3, 3, 0, 21, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
httpPacket = []byte{200, 102, 0, 80, 135, 147, 39, 86, 46, 120, 134, 242, 80, 24, 255, 255, 244, 240, 0, 0, 71, 69, 84, 32, 47, 32, 72, 84, 84, 80, 47, 49, 46, 49, 13, 10, 85, 115, 101, 114, 45, 65, 103, 101, 110, 116, 58, 32, 68, 97, 108, 118, 105, 107, 47, 50, 46, 49, 46, 48, 32, 40, 76, 105, 110, 117, 120, 59, 32, 85, 59, 32, 65, 110, 100, 114, 111, 105, 100, 32, 49, 48, 59, 32, 69, 76, 83, 45, 65, 78, 48, 48, 32, 66, 117, 105, 108, 100, 47, 72, 85, 65, 87, 69, 73, 69, 76, 83, 45, 65, 78, 48, 48, 41, 13, 10, 72, 111, 115, 116, 58, 32, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 13, 10, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 58, 32, 75, 101, 101, 112, 45, 65, 108, 105, 118, 101, 13, 10, 65, 99, 99, 101, 112, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, 112, 13, 10, 13, 10}
|
||||||
|
httpPacket2 = []byte{200, 102, 0, 80, 135, 147, 39, 86, 46, 120, 134, 242, 80, 24, 255, 255, 244, 240, 0, 0, 71, 69, 84, 32, 47, 32, 72, 84, 84, 80, 47, 49, 46, 49, 13, 10, 85, 115, 101, 114, 45, 65, 103, 101, 110, 116, 58, 32, 68, 97, 108, 118, 105, 107, 47, 50, 46, 49, 46, 48, 32, 40, 76, 105, 110, 117, 120, 59, 32, 85, 59, 32, 65, 110, 100, 114, 111, 105, 100, 32, 49, 48, 59, 32, 69, 76, 83, 45, 65, 78, 48, 48, 32, 66, 117, 105, 108, 100, 47, 72, 85, 65, 87, 69, 73, 69, 76, 83, 45, 65, 78, 48, 48, 41, 13, 10, 72, 79, 83, 84, 58, 32, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 13, 10, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 58, 32, 75, 101, 101, 112, 45, 65, 108, 105, 118, 101, 13, 10, 65, 99, 99, 101, 112, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, 112, 13, 10, 13, 10}
|
||||||
|
httpPacket3 = []byte{200, 102, 0, 80, 135, 147, 39, 86, 46, 120, 134, 242, 80, 24, 255, 255, 244, 240, 0, 0, 71, 69, 84, 32, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 47, 105, 110, 100, 101, 120, 46, 104, 116, 109, 108, 32, 72, 84, 84, 80, 47, 49, 46, 49, 13, 10, 85, 115, 101, 114, 45, 65, 103, 101, 110, 116, 58, 32, 68, 97, 108, 118, 105, 107, 47, 50, 46, 49, 46, 48, 32, 40, 76, 105, 110, 117, 120, 59, 32, 85, 59, 32, 65, 110, 100, 114, 111, 105, 100, 32, 49, 48, 59, 32, 69, 76, 83, 45, 65, 78, 48, 48, 32, 66, 117, 105, 108, 100, 47, 72, 85, 65, 87, 69, 73, 69, 76, 83, 45, 65, 78, 48, 48, 41, 13, 10, 72, 79, 83, 84, 58, 32, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 13, 10, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 58, 32, 75, 101, 101, 112, 45, 65, 108, 105, 118, 101, 13, 10, 65, 99, 99, 101, 112, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 103, 122, 105, 112, 13, 10, 13, 10}
|
||||||
|
httpsSni = "jgw-drcn.jos.dbankcloud.cn"
|
||||||
|
httpHost = "www.google.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handlerTcpPayload(packet []byte) []byte {
|
||||||
|
ihl := (packet[12] & 0xf0) >> 2
|
||||||
|
data := packet[ihl:]
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
func BenchmarkSniParser(b *testing.B) {
|
||||||
|
data := handlerTcpPayload(httpsPacket)
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
sniParser(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewSniParser(b *testing.B) {
|
||||||
|
data := handlerTcpPayload(httpsPacket)
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
sniNewParser(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHttpParser(b *testing.B) {
|
||||||
|
data := handlerTcpPayload(httpPacket)
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
httpParser(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewHttpParser(b *testing.B) {
|
||||||
|
data := handlerTcpPayload(httpPacket)
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
httpNewParser(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewSniParser(t *testing.T) {
|
||||||
|
ast := assert.New(t)
|
||||||
|
data := handlerTcpPayload(httpsPacket)
|
||||||
|
_, sni := sniNewParser(data)
|
||||||
|
ast.Equal(sni, httpsSni)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewHttpParser(t *testing.T) {
|
||||||
|
ast := assert.New(t)
|
||||||
|
// Host
|
||||||
|
data := handlerTcpPayload(httpPacket)
|
||||||
|
_, hostname := httpNewParser(data)
|
||||||
|
ast.Equal(hostname, httpHost)
|
||||||
|
// HOST
|
||||||
|
data = handlerTcpPayload(httpPacket2)
|
||||||
|
_, hostname = httpNewParser(data)
|
||||||
|
ast.Equal(hostname, httpHost)
|
||||||
|
// GET http://www.google.com/index.html HTTP/1.1
|
||||||
|
data = handlerTcpPayload(httpPacket3)
|
||||||
|
_, hostname = httpNewParser(data)
|
||||||
|
ast.Equal(hostname, httpHost)
|
||||||
|
}
|
|
@ -37,6 +37,8 @@ func Start() {
|
||||||
go admin.StartAdmin()
|
go admin.StartAdmin()
|
||||||
go startTls()
|
go startTls()
|
||||||
go startDtls()
|
go startDtls()
|
||||||
|
|
||||||
|
go logAuditBatch()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Stop() {
|
func Stop() {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/bjdgyc/anylink/base"
|
"github.com/bjdgyc/anylink/base"
|
||||||
"github.com/bjdgyc/anylink/dbdata"
|
"github.com/bjdgyc/anylink/dbdata"
|
||||||
"github.com/bjdgyc/anylink/pkg/utils"
|
"github.com/bjdgyc/anylink/pkg/utils"
|
||||||
|
"github.com/ivpusic/grpool"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -50,7 +51,7 @@ type ConnSession struct {
|
||||||
PayloadOutCstp chan *Payload // Cstp的数据
|
PayloadOutCstp chan *Payload // Cstp的数据
|
||||||
PayloadOutDtls chan *Payload // Dtls的数据
|
PayloadOutDtls chan *Payload // Dtls的数据
|
||||||
IpAuditMap utils.IMaps // 审计的ip数据
|
IpAuditMap utils.IMaps // 审计的ip数据
|
||||||
|
IpAuditPool *grpool.Pool // 审计的IP包解析池
|
||||||
// dSess *DtlsSession
|
// dSess *DtlsSession
|
||||||
dSess *atomic.Value
|
dSess *atomic.Value
|
||||||
}
|
}
|
||||||
|
@ -192,11 +193,8 @@ func (s *Session) NewConn() *ConnSession {
|
||||||
|
|
||||||
// ip 审计
|
// ip 审计
|
||||||
if base.Cfg.AuditInterval >= 0 {
|
if base.Cfg.AuditInterval >= 0 {
|
||||||
if base.Cfg.ServerDTLS {
|
cSess.IpAuditMap = utils.NewMap("cmap", 0)
|
||||||
cSess.IpAuditMap = utils.NewMap("cmap", 0)
|
cSess.IpAuditPool = grpool.NewPool(1, 600)
|
||||||
} else {
|
|
||||||
cSess.IpAuditMap = utils.NewMap("", 512)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dSess := &DtlsSession{
|
dSess := &DtlsSession{
|
||||||
|
|
Loading…
Reference in New Issue