169 lines
3.1 KiB
Go
169 lines
3.1 KiB
Go
package redis
|
|
|
|
import (
|
|
"bufio"
|
|
"strings"
|
|
|
|
csm "git.loafle.net/commons/service_matcher-go"
|
|
)
|
|
|
|
const REDIS_PING string = "*1\r\n$4\r\nPING\r\n"
|
|
const REDIS_INFO string = "*1\r\n$4\r\nINFO\r\n"
|
|
const REDIS_QUIT string = "*1\r\n$4\r\nQUIT\r\n"
|
|
|
|
type RedisMatcher struct {
|
|
csm.Matchers
|
|
meta csm.Metadata
|
|
|
|
protected bool
|
|
}
|
|
|
|
func (r *RedisMatcher) Key() string {
|
|
return "REDIS"
|
|
}
|
|
|
|
func (r *RedisMatcher) Name() string {
|
|
name := "Redis"
|
|
if r.protected {
|
|
return name + " (protected)"
|
|
}
|
|
if v, ok := r.meta["redis_mode"]; ok {
|
|
name = name + " " + v
|
|
}
|
|
if v, ok := r.meta["redis_version"]; ok {
|
|
name = name + " (" + v + ")"
|
|
}
|
|
return name
|
|
}
|
|
|
|
func (r *RedisMatcher) Meta() csm.Metadata {
|
|
return r.meta
|
|
}
|
|
|
|
func (r *RedisMatcher) IsPrePacket() bool {
|
|
return false
|
|
}
|
|
|
|
func (r *RedisMatcher) HasResponse(index int) bool {
|
|
return true
|
|
}
|
|
|
|
func (r *RedisMatcher) IsError(info csm.MatchInfo, index int, packet *csm.Packet) bool {
|
|
return false
|
|
}
|
|
|
|
func (r *RedisMatcher) Match(info csm.MatchInfo, index int, packet *csm.Packet) error {
|
|
|
|
if packet == nil || packet.Buffer == nil || packet.Len == 0 {
|
|
return csm.NoPacketReceivedError()
|
|
}
|
|
|
|
resp := strings.Split(string(packet.Buffer), "\r\n")[0]
|
|
if len(resp) <= 0 {
|
|
return csm.NotMatchedError()
|
|
}
|
|
|
|
switch index {
|
|
case 0:
|
|
sign := string([]rune(resp)[0])
|
|
if len(sign) <= 0 {
|
|
return csm.NotMatchedError()
|
|
}
|
|
|
|
if sign == "+" {
|
|
if resp == "+PONG" || resp == "+OK" {
|
|
return nil
|
|
}
|
|
}
|
|
if sign == "-" {
|
|
if resp == "-NOAUTH" || resp == "-ERR" {
|
|
return nil
|
|
}
|
|
}
|
|
r.protected = r.checkProtectedMode(packet)
|
|
if r.protected {
|
|
return nil
|
|
}
|
|
|
|
case 1: // INFO
|
|
|
|
info := string(packet.Buffer)
|
|
if !r.protected {
|
|
r.parseInfo(info)
|
|
}
|
|
return nil
|
|
case 2:
|
|
sign := string([]rune(resp)[0])
|
|
if sign == "+" || sign == "-" {
|
|
return nil
|
|
}
|
|
return nil
|
|
default:
|
|
return csm.NotMatchedError()
|
|
}
|
|
return csm.NotMatchedError()
|
|
}
|
|
|
|
func (r *RedisMatcher) checkProtectedMode(packet *csm.Packet) bool {
|
|
var (
|
|
compareSign = "-"
|
|
compareMsg = "DENIED"
|
|
)
|
|
str := string(packet.Buffer[:packet.Len])
|
|
|
|
if str == "" {
|
|
return false
|
|
}
|
|
if 0 >= len(str) || len(compareMsg)+2 > len(str) {
|
|
return false
|
|
}
|
|
|
|
firstCompare := str[0:1]
|
|
seconcdCompare := str[1 : len(compareMsg)+1]
|
|
|
|
if firstCompare != compareSign {
|
|
return false
|
|
}
|
|
if seconcdCompare != compareMsg {
|
|
return false
|
|
}
|
|
|
|
r.protected = true
|
|
|
|
return true
|
|
}
|
|
|
|
func (r *RedisMatcher) parseInfo(info string) {
|
|
scanner := bufio.NewScanner(strings.NewReader(info))
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
if strings.Compare(line, "") == 0 {
|
|
break
|
|
}
|
|
if len(line) > 0 && strings.Contains(line, ":") {
|
|
kv := strings.Split(line, ":")
|
|
if len(kv[0]) > 0 && len(kv[1]) > 0 {
|
|
r.meta[kv[0]] = kv[1]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *RedisMatcher) PacketCount() int {
|
|
if r.protected {
|
|
return 1
|
|
}
|
|
return 3
|
|
}
|
|
|
|
func NewMatcher() csm.Matcher {
|
|
|
|
m := &RedisMatcher{}
|
|
m.meta = csm.NewMetadata()
|
|
|
|
m.AddPacket(csm.NewPacket([]byte(REDIS_PING), len(REDIS_PING)))
|
|
m.AddPacket(csm.NewPacket([]byte(REDIS_INFO), len(REDIS_INFO)))
|
|
m.AddPacket(csm.NewPacket([]byte(REDIS_QUIT), len(REDIS_QUIT)))
|
|
return m
|
|
}
|