1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
package db
import (
"encoding/json"
"fmt"
"github.com/go-redis/redis"
"github.com/inconshreveable/log15"
"github.com/mozqnet/go-exploitdb/models"
pb "gopkg.in/cheggaaa/pb.v1"
)
/**
# Redis Data Structure
- HASH
┌───┬───────────────────────┬────────────┬────────────────┬────────────────────────────────┐
│NO │ HASH │ FIELD │ VALUE │ PURPOSE │
└───┴───────────────────────┴────────────┴────────────────┴────────────────────────────────┘
┌───┬───────────────────────┬────────────┬────────────────┬────────────────────────────────┐
│ 1 │EXPLOIT#E#$EXPLOITDBID │ $CVEID │ $EXPLOIT JSON │ TO GET EXPLOIT FROM EXPLOITDBID│
├───┼───────────────────────┼────────────┼────────────────┼────────────────────────────────┤
│ 2 │EXPLOIT#C#$CVEID │$EXPLOITDBID│ $EXPLOIT JSON │ TO GET EXPLOIT FROM CVEID │
└───┴───────────────────────┴────── ────┴────────────────┴────────────────────────────────┘
**/
const (
dialectRedis = "redis"
exploitDBIDPrefix = "EXPLOIT#E#"
cveIDPrefix = "EXPLOIT#C#"
)
// RedisDriver is Driver for Redis
type RedisDriver struct {
name string
conn *redis.Client
}
// Name return db name
func (r *RedisDriver) Name() string {
return r.name
}
// OpenDB opens Database
func (r *RedisDriver) OpenDB(dbType, dbPath string, debugSQL bool) (locked bool, err error) {
if err = r.connectRedis(dbPath); err != nil {
err = fmt.Errorf("Failed to open DB. dbtype: %s, dbpath: %s, err: %s", dbType, dbPath, err)
}
return
}
func (r *RedisDriver) connectRedis(dbPath string) error {
var err error
var option *redis.Options
if option, err = redis.ParseURL(dbPath); err != nil {
log15.Error("Failed to parse url.", "err", err)
return err
}
r.conn = redis.NewClient(option)
err = r.conn.Ping().Err()
return err
}
// MigrateDB migrates Database
func (r *RedisDriver) MigrateDB() error {
return nil
}
// GetExploitByCveID :
func (r *RedisDriver) GetExploitByCveID(cveID string) (exploits []*models.Exploit) {
result := r.conn.HGetAll(cveIDPrefix + cveID)
if result.Err() != nil {
log15.Error("Failed to get cve.", "err", result.Err())
return nil
}
for _, j := range result.Val() {
var exploit models.Exploit
if err := json.Unmarshal([]byte(j), &exploit); err != nil {
log15.Error("Failed to Unmarshal json.", "err", err)
return nil
}
exploits = append(exploits, &exploit)
}
return exploits
}
// GetExploitByID :
func (r *RedisDriver) GetExploitByID(exploitDBID string) (exploits []*models.Exploit) {
results := r.conn.HGetAll(exploitDBIDPrefix + exploitDBID)
if results.Err() != nil {
log15.Error("Failed to get cve.", "err", results.Err())
return nil
}
for _, j := range results.Val() {
var exploit models.Exploit
if err := json.Unmarshal([]byte(j), &exploit); err != nil {
log15.Error("Failed to Unmarshal json.", "err", err)
return nil
}
exploits = append(exploits, &exploit)
}
return exploits
}
// GetExploitAll :
func (r *RedisDriver) GetExploitAll() (exploits []*models.Exploit) {
log15.Error("redis does not correspond to all")
return
}
// GetExploitMultiByCveID :
func (r *RedisDriver) GetExploitMultiByCveID(cveIDs []string) (exploitsMap map[string][]*models.Exploit) {
exploitsMap = map[string][]*models.Exploit{}
rs := map[string]*redis.StringStringMapCmd{}
pipe := r.conn.Pipeline()
for _, cveID := range cveIDs {
rs[cveID] = pipe.HGetAll(cveIDPrefix + cveID)
}
if _, err := pipe.Exec(); err != nil {
if err != redis.Nil {
log15.Error("Failed to get multi cve json.", "err", err)
return nil
}
}
for cveID, results := range rs {
var exploits []*models.Exploit
for _, j := range results.Val() {
var exploit models.Exploit
if results.Err() != nil {
log15.Error("Failed to Get Explit", "err", results.Err())
continue
}
if err := json.Unmarshal([]byte(j), &exploit); err != nil {
log15.Error("Failed to Unmarshal json.", "err", err)
return nil
}
exploits = append(exploits, &exploit)
}
exploitsMap[cveID] = exploits
}
return exploitsMap
}
//InsertExploit :
func (r *RedisDriver) InsertExploit(exploits []models.Exploit) (err error) {
bar := pb.StartNew(len(exploits))
var noCveIDExploitCount, cveIDExploitCount int
for _, exploit := range exploits {
var pipe redis.Pipeliner
pipe = r.conn.Pipeline()
bar.Increment()
j, err := json.Marshal(exploit)
if err != nil {
return fmt.Errorf("Failed to marshal json. err: %s", err)
}
if 0 < len(exploit.CveID) {
if result := pipe.HSet(cveIDPrefix+exploit.CveID, exploit.ExploitUniqueID, string(j)); result.Err() != nil {
return fmt.Errorf("Failed to HSet CVE. err: %s", result.Err())
}
cveIDExploitCount++
} else {
noCveIDExploitCount++
}
// NoCveID -> NONE
if len(exploit.CveID) == 0 {
exploit.CveID = "NONE"
}
if result := pipe.HSet(exploitDBIDPrefix+exploit.ExploitUniqueID, exploit.CveID, string(j)); result.Err() != nil {
return fmt.Errorf("Failed to HSet Exploit. err: %s", result.Err())
}
if _, err = pipe.Exec(); err != nil {
return fmt.Errorf("Failed to exec pipeline. err: %s", err)
}
}
bar.Finish()
log15.Info("No CveID Exploit Count", "count", noCveIDExploitCount)
log15.Info("CveID Exploit Count", "count", cveIDExploitCount)
return nil
}
|