probe/ping/service/matcher/matcher.go
crusader 419c5cb6ac ing
2018-09-18 01:25:56 +09:00

251 lines
6.1 KiB
Go

package matcher
import (
"crypto/tls"
"net"
"strings"
"time"
omd "git.loafle.net/overflow/model/discovery"
omm "git.loafle.net/overflow/model/meta"
osm "git.loafle.net/overflow/service_matcher-go"
ouej "git.loafle.net/overflow/util-go/encoding/json"
ounp "git.loafle.net/overflow/util-go/net/ping"
"git.loafle.net/overflow_scanner/probe/internal/matcher"
)
func Ping(service *omd.Service, pingOption ounp.Option) (ounp.Result, error) {
portNumber, err := ouej.NumberToInt(service.Port.PortNumber)
if nil != err {
return nil, err
}
matchCtx := osm.NewMatchCtx(service.Port.Host.Address, portNumber)
_matcher := matcher.GetMatcherByKey(service.Key)
if _matcher.IsPrePacket() {
return processPrepacket(service, pingOption, matchCtx, _matcher), nil
}
return processPostpacket(service, pingOption, matchCtx, _matcher), nil
}
func processPrepacket(service *omd.Service, pingOption ounp.Option, matchCtx *osm.MatchCtx, _matcher osm.Matcher) ounp.Result {
pingResult := &ounp.PingResult{
Responses: make(map[int]ounp.Response, 0),
Summary: &ounp.PingSummary{},
}
buf := make([]byte, 1024)
LOOP:
for indexR := 0; indexR < pingOption.GetRetry(); indexR++ {
matchCtx.InitAttribute()
conn, err := getConnection(service, pingOption)
if nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
continue LOOP
}
if err := conn.SetReadDeadline(time.Now().Add(time.Duration(pingOption.GetDeadline()) * time.Second)); nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
conn.Close()
continue LOOP
}
n, err := conn.Read(buf)
if nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
conn.Close()
continue LOOP
}
if err := _matcher.Match(matchCtx, 0, osm.NewPacket(buf, n)); nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
conn.Close()
continue LOOP
}
packetCount := _matcher.PacketCount(matchCtx)
if 0 == packetCount {
pingResult.Responses[indexR] = &ounp.PingResponse{
Time: 0,
}
conn.Close()
continue LOOP
}
isMatched := false
INNER_LOOP:
for indexM := 0; indexM < packetCount; indexM++ {
_packet := _matcher.Packet(matchCtx, indexM)
if err := conn.SetWriteDeadline(time.Now().Add(time.Duration(pingOption.GetDeadline()) * time.Second)); nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
_, err := conn.Write(_packet.Buffer)
if nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
if err := conn.SetReadDeadline(time.Now().Add(time.Duration(pingOption.GetDeadline()) * time.Second)); nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
n, err := conn.Read(buf)
if nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
if err := _matcher.Match(matchCtx, indexM+1, osm.NewPacket(buf, n)); nil == err {
isMatched = true
} else {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: "Protocol not match",
}
break INNER_LOOP
}
}
conn.Close()
if isMatched {
pingResult.Responses[indexR] = &ounp.PingResponse{
Time: 0,
}
}
}
return pingResult
}
func processPostpacket(service *omd.Service, pingOption ounp.Option, matchCtx *osm.MatchCtx, _matcher osm.Matcher) ounp.Result {
pingResult := &ounp.PingResult{
Responses: make(map[int]ounp.Response, 0),
Summary: &ounp.PingSummary{},
}
buf := make([]byte, 1024)
LOOP:
for indexR := 0; indexR < pingOption.GetRetry(); indexR++ {
matchCtx.InitAttribute()
packetCount := _matcher.PacketCount(matchCtx)
if 0 == packetCount {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: "Protocol not match",
}
continue LOOP
}
conn, err := getConnection(service, pingOption)
if nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
continue LOOP
}
isMatched := false
INNER_LOOP:
for indexM := 0; indexM < packetCount; indexM++ {
_packet := _matcher.Packet(matchCtx, indexM)
if err := conn.SetWriteDeadline(time.Now().Add(time.Duration(pingOption.GetDeadline()) * time.Second)); nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
_, err := conn.Write(_packet.Buffer)
if nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
if err := conn.SetReadDeadline(time.Now().Add(time.Duration(pingOption.GetDeadline()) * time.Second)); nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
n, err := conn.Read(buf)
if nil != err {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: err.Error(),
}
break INNER_LOOP
}
if err := _matcher.Match(matchCtx, indexM+1, osm.NewPacket(buf, n)); nil == err {
if packetCount-1 == indexM {
isMatched = true
break INNER_LOOP
}
} else {
pingResult.Responses[indexR] = &ounp.PingResponse{
Error: "Protocol not match",
}
break INNER_LOOP
}
}
conn.Close()
if isMatched {
pingResult.Responses[indexR] = &ounp.PingResponse{
Time: 0,
}
}
}
return pingResult
}
func getConnection(service *omd.Service, pingOption ounp.Option) (net.Conn, error) {
addr := net.JoinHostPort(service.Port.Host.Address, service.Port.PortNumber.String())
portType := strings.ToLower(service.Port.MetaPortType.Key)
switch omm.ToMetaCryptoTypeEnum(service.MetaCryptoType) {
case omm.MetaCryptoTypeEnumTLS:
dialer := &net.Dialer{
Timeout: time.Duration(pingOption.GetDeadline()) * time.Second,
}
return tls.DialWithDialer(
dialer,
portType,
addr,
&tls.Config{
InsecureSkipVerify: true,
ServerName: service.Port.Host.Address,
},
)
default:
return net.DialTimeout(portType, addr, time.Duration(pingOption.GetDeadline())*time.Second)
}
}