Merge pull request #162 from lanrenwo/audit_https

修复解析https+ip偶发出现sni乱码的BUG
This commit is contained in:
bjdgyc 2022-10-19 16:42:19 +08:00 committed by GitHub
commit 6f7fcfc6ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 24 deletions

View File

@ -3,7 +3,6 @@ package handler
import (
"crypto/md5"
"encoding/binary"
"encoding/hex"
"time"
"github.com/bjdgyc/anylink/base"
@ -109,6 +108,8 @@ func logAudit(cSess *sessdata.ConnSession, pl *sessdata.Payload) {
copy(key[:16], ipSrc)
copy(key[16:32], ipDst)
binary.BigEndian.PutUint16(key[32:34], ipPort)
key[34] = byte(accessProto)
copy(key[35:51], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
info := ""
nu := utils.NowSec().Unix()
@ -149,16 +150,20 @@ func logAudit(cSess *sessdata.ConnSession, pl *sessdata.Payload) {
case flags & 0x18:
// PSH ACK
accessProto, info = onTCP(plData)
if info != "" {
// HTTPS or HTTP
if accessProto != acc_proto_tcp {
// 提前存储只含ip数据的key, 避免即记录域名又记录一笔IP数据的记录
ipKey := make([]byte, 51)
copy(ipKey, key)
ipS := utils.BytesToString(ipKey)
cSess.IpAuditMap.Set(ipS, nu)
// 存储含域名的key
key[34] = byte(accessProto)
md5Sum := md5.Sum([]byte(info))
copy(key[35:51], hex.EncodeToString(md5Sum[:]))
// 存储含域名的key
if info != "" {
md5Sum := md5.Sum([]byte(info))
copy(key[35:51], md5Sum[:])
}
}
case flags & 0x19:
// URG

View File

@ -9,7 +9,7 @@ import (
)
var tcpParsers = []func([]byte) (uint8, string){
sniParser,
sniNewParser,
httpParser,
}
@ -21,7 +21,7 @@ func onTCP(payload []byte) (uint8, string) {
}
data := payload[ihl:]
for _, parser := range tcpParsers {
if proto, info := parser(data); info != "" {
if proto, info := parser(data); proto != acc_proto_tcp {
return proto, info
}
}
@ -29,8 +29,7 @@ func onTCP(payload []byte) (uint8, string) {
}
func sniNewParser(b []byte) (uint8, string) {
dataSize := len(b)
if dataSize < 2 || b[0] != 0x16 || b[1] != 0x03 {
if len(b) < 2 || b[0] != 0x16 || b[1] != 0x03 {
return acc_proto_tcp, ""
}
rest := b[5:]
@ -51,27 +50,27 @@ func sniNewParser(b []byte) (uint8, string) {
// Skip over random number
current += 4 + 28
if current >= restLen {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
// Skip over session ID
sessionIDLength := int(rest[current])
current += 1
current += sessionIDLength
if current >= restLen {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
cipherSuiteLength := (int(rest[current]) << 8) + int(rest[current+1])
current += 2
current += cipherSuiteLength
if current >= restLen {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
compressionMethodLength := int(rest[current])
current += 1
current += compressionMethodLength
if current >= restLen {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
current += 2
hostname := ""
@ -84,27 +83,30 @@ func sniNewParser(b []byte) (uint8, string) {
// Skip over number of names as we're assuming there's just one
current += 2
if current >= restLen {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
nameType := rest[current]
current += 1
if nameType != 0 {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
if current+1 >= restLen {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
nameLen := (int(rest[current]) << 8) + int(rest[current+1])
current += 2
if current+nameLen >= restLen {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
hostname = string(rest[current : current+nameLen])
}
current += extensionDataLength
}
if hostname == "" {
return acc_proto_tcp, ""
return acc_proto_https, ""
}
if !validDomainChar(hostname) {
return acc_proto_https, ""
}
return acc_proto_https, hostname
}
@ -150,8 +152,7 @@ func httpNewParser(data []byte) (uint8, string) {
}
func sniParser(data []byte) (uint8, string) {
dataSize := len(data)
if dataSize < 2 || data[0] != 0x16 || data[1] != 0x03 {
if len(data) < 2 || data[0] != 0x16 || data[1] != 0x03 {
return acc_proto_tcp, ""
}
sniRe := regexp.MustCompile("\x00\x00.{4}\x00.{2}([a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6})\x00")
@ -169,3 +170,15 @@ func httpParser(data []byte) (uint8, string) {
}
return acc_proto_tcp, ""
}
// 校验域名的合法字符, 处理乱码问题
func validDomainChar(addr string) bool {
// Allow a-z A-Z . - 0-9
for i := 0; i < len(addr); i++ {
c := addr[i]
if !((c >= 97 && c <= 122) || (c >= 65 && c <= 90) || (c >= 45 && c <= 46) || (c >= 48 && c <= 57)) {
return false
}
}
return true
}

View File

@ -51,22 +51,26 @@ func BenchmarkNewHttpParser(b *testing.B) {
func TestNewSniParser(t *testing.T) {
ast := assert.New(t)
data := handlerTcpPayload(httpsPacket)
_, sni := sniNewParser(data)
proto, sni := sniNewParser(data)
ast.Equal(sni, httpsSni)
ast.Equal(int(proto), acc_proto_https)
}
func TestNewHttpParser(t *testing.T) {
ast := assert.New(t)
// Host
data := handlerTcpPayload(httpPacket)
_, hostname := httpNewParser(data)
proto, hostname := httpNewParser(data)
ast.Equal(hostname, httpHost)
ast.Equal(int(proto), acc_proto_http)
// HOST
data = handlerTcpPayload(httpPacket2)
_, hostname = httpNewParser(data)
proto, hostname = httpNewParser(data)
ast.Equal(hostname, httpHost)
ast.Equal(int(proto), acc_proto_http)
// GET http://www.google.com/index.html HTTP/1.1
data = handlerTcpPayload(httpPacket3)
_, hostname = httpNewParser(data)
proto, hostname = httpNewParser(data)
ast.Equal(hostname, httpHost)
ast.Equal(int(proto), acc_proto_http)
}