service_matcher-go/redis/redis.go
2018-08-15 16:17:18 +09:00

169 lines
3.1 KiB
Go

package redis
import (
"bufio"
"strings"
osm "git.loafle.net/overflow/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 {
osm.Matchers
meta osm.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() osm.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 osm.MatchInfo, index int, packet *osm.Packet) bool {
return false
}
func (r *RedisMatcher) Match(info osm.MatchInfo, index int, packet *osm.Packet) error {
if packet == nil || packet.Buffer == nil || packet.Len == 0 {
return osm.NoPacketReceivedError()
}
resp := strings.Split(string(packet.Buffer), "\r\n")[0]
if len(resp) <= 0 {
return osm.NotMatchedError()
}
switch index {
case 0:
sign := string([]rune(resp)[0])
if len(sign) <= 0 {
return osm.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 osm.NotMatchedError()
}
return osm.NotMatchedError()
}
func (r *RedisMatcher) checkProtectedMode(packet *osm.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() osm.Matcher {
m := &RedisMatcher{}
m.meta = osm.NewMetadata()
m.AddPacket(osm.NewPacket([]byte(REDIS_PING), len(REDIS_PING)))
m.AddPacket(osm.NewPacket([]byte(REDIS_INFO), len(REDIS_INFO)))
m.AddPacket(osm.NewPacket([]byte(REDIS_QUIT), len(REDIS_QUIT)))
return m
}