Parse Result instead of only returning a string

This commit is contained in:
Dolf Schimmel (Freeaqingme)
2016-04-03 17:05:04 +02:00
parent 1b4a274e85
commit ace0f266eb
2 changed files with 77 additions and 35 deletions

View File

@@ -33,6 +33,13 @@ import (
"strings"
)
const (
RES_OK = "OK"
RES_FOUND = "FOUND"
RES_ERROR = "ERROR"
RES_PARSE_ERROR = "PARSE ERROR"
)
type Clamd struct {
address string
}
@@ -45,6 +52,15 @@ type Stats struct {
Queue string
}
type ScanResult struct {
Raw string
Description string
Path string
Hash string
Size int
Status string
}
var EICAR = []byte(`X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*`)
func (c *Clamd) newConnection() (conn *CLAMDConn, err error) {
@@ -67,14 +83,12 @@ func (c *Clamd) newConnection() (conn *CLAMDConn, err error) {
return
}
func (c *Clamd) simpleCommand(command string) (chan string, error) {
func (c *Clamd) simpleCommand(command string) (chan *ScanResult, error) {
conn, err := c.newConnection()
if err != nil {
return nil, err
}
// defer conn.Close()
err = conn.sendCommand(command)
if err != nil {
return nil, err
@@ -83,10 +97,7 @@ func (c *Clamd) simpleCommand(command string) (chan string, error) {
ch, wg, err := conn.readResponse()
go func() {
// wait for waitgroup
wg.Wait()
// close connection
conn.Close()
}()
@@ -104,7 +115,7 @@ func (c *Clamd) Ping() error {
select {
case s := (<-ch):
switch s {
switch s.Raw {
case "PONG":
return nil
default:
@@ -118,7 +129,7 @@ func (c *Clamd) Ping() error {
/*
Print program and database versions.
*/
func (c *Clamd) Version() (chan string, error) {
func (c *Clamd) Version() (chan *ScanResult, error) {
dataArrays, err := c.simpleCommand("VERSION")
return dataArrays, err
}
@@ -137,17 +148,17 @@ func (c *Clamd) Stats() (*Stats, error) {
stats := &Stats{}
for s := range ch {
if strings.HasPrefix(s, "POOLS") {
stats.Pools = strings.Trim(s[6:], " ")
} else if strings.HasPrefix(s, "STATE") {
stats.State = s
} else if strings.HasPrefix(s, "THREADS") {
stats.Threads = s
} else if strings.HasPrefix(s, "QUEUE") {
stats.Queue = s
} else if strings.HasPrefix(s, "MEMSTATS") {
stats.Memstats = s
} else if strings.HasPrefix(s, "END") {
if strings.HasPrefix(s.Raw, "POOLS") {
stats.Pools = strings.Trim(s.Raw[6:], " ")
} else if strings.HasPrefix(s.Raw, "STATE") {
stats.State = s.Raw
} else if strings.HasPrefix(s.Raw, "THREADS") {
stats.Threads = s.Raw
} else if strings.HasPrefix(s.Raw, "QUEUE") {
stats.Queue = s.Raw
} else if strings.HasPrefix(s.Raw, "MEMSTATS") {
stats.Memstats = s.Raw
} else if strings.HasPrefix(s.Raw, "END") {
} else {
// return nil, errors.New(fmt.Sprintf("Unknown response, got %s.", s))
}
@@ -167,7 +178,7 @@ func (c *Clamd) Reload() error {
select {
case s := (<-ch):
switch s {
switch s.Raw {
case "RELOADING":
return nil
default:
@@ -191,7 +202,7 @@ func (c *Clamd) Shutdown() error {
Scan file or directory (recursively) with archive support enabled (a full path is
required).
*/
func (c *Clamd) ScanFile(path string) (chan string, error) {
func (c *Clamd) ScanFile(path string) (chan *ScanResult, error) {
command := fmt.Sprintf("SCAN %s", path)
ch, err := c.simpleCommand(command)
return ch, err
@@ -201,7 +212,7 @@ func (c *Clamd) ScanFile(path string) (chan string, error) {
Scan file or directory (recursively) with archive and special file support disabled
(a full path is required).
*/
func (c *Clamd) RawScanFile(path string) (chan string, error) {
func (c *Clamd) RawScanFile(path string) (chan *ScanResult, error) {
command := fmt.Sprintf("RAWSCAN %s", path)
ch, err := c.simpleCommand(command)
return ch, err
@@ -211,7 +222,7 @@ func (c *Clamd) RawScanFile(path string) (chan string, error) {
Scan file in a standard way or scan directory (recursively) using multiple threads
(to make the scanning faster on SMP machines).
*/
func (c *Clamd) MultiScanFile(path string) (chan string, error) {
func (c *Clamd) MultiScanFile(path string) (chan *ScanResult, error) {
command := fmt.Sprintf("MULTISCAN %s", path)
ch, err := c.simpleCommand(command)
return ch, err
@@ -221,7 +232,7 @@ func (c *Clamd) MultiScanFile(path string) (chan string, error) {
Scan file or directory (recursively) with archive support enabled and dont stop
the scanning when a virus is found.
*/
func (c *Clamd) ContScanFile(path string) (chan string, error) {
func (c *Clamd) ContScanFile(path string) (chan *ScanResult, error) {
command := fmt.Sprintf("CONTSCAN %s", path)
ch, err := c.simpleCommand(command)
return ch, err
@@ -231,7 +242,7 @@ func (c *Clamd) ContScanFile(path string) (chan string, error) {
Scan file or directory (recursively) with archive support enabled and dont stop
the scanning when a virus is found.
*/
func (c *Clamd) AllMatchScanFile(path string) (chan string, error) {
func (c *Clamd) AllMatchScanFile(path string) (chan *ScanResult, error) {
command := fmt.Sprintf("ALLMATCHSCAN %s", path)
ch, err := c.simpleCommand(command)
return ch, err
@@ -247,7 +258,7 @@ the actual chunk. Streaming is terminated by sending a zero-length chunk. Note:
do not exceed StreamMaxLength as defined in clamd.conf, otherwise clamd will
reply with INSTREAM size limit exceeded and close the connection
*/
func (c *Clamd) ScanStream(r io.Reader) (chan string, error) {
func (c *Clamd) ScanStream(r io.Reader) (chan *ScanResult, error) {
conn, err := c.newConnection()
if err != nil {
return nil, err

49
conn.go
View File

@@ -30,6 +30,8 @@ import (
"fmt"
"io"
"net"
"regexp"
"strconv"
"strings"
"sync"
"time"
@@ -38,6 +40,10 @@ import (
const CHUNK_SIZE = 1024
const TCP_TIMEOUT = time.Second * 2
var resultRegex = regexp.MustCompile(
`^(?P<path>[^:]+): ((?P<desc>[^:]+)(\((?P<virhash>([^:]+)):(?P<virsize>\d+)\))? )?(?P<status>FOUND|ERROR|OK)$`,
)
type CLAMDConn struct {
net.Conn
}
@@ -75,18 +81,13 @@ func (conn *CLAMDConn) sendChunk(data []byte) error {
return err
}
func (c *CLAMDConn) readResponse() (chan string, *sync.WaitGroup, error) {
func (c *CLAMDConn) readResponse() (chan *ScanResult, *sync.WaitGroup, error) {
var wg sync.WaitGroup
wg.Add(1)
// read data
reader := bufio.NewReader(c)
ch := make(chan *ScanResult)
// reading
ch := make(chan string)
// var dataArrays []string
go func() {
defer func() {
close(ch)
@@ -104,14 +105,44 @@ func (c *CLAMDConn) readResponse() (chan string, *sync.WaitGroup, error) {
}
line = strings.TrimRight(line, " \t\r\n")
ch <- line
ch <- parseResult(line)
}
}()
return ch, &wg, nil
}
func parseResult(line string) *ScanResult {
res := &ScanResult{}
res.Raw = line
matches := resultRegex.FindStringSubmatch(line)
if len(matches) == 0 {
res.Status = RES_PARSE_ERROR
return res
}
for i, name := range resultRegex.SubexpNames() {
switch name {
case "path":
res.Path = matches[i]
case "desc":
res.Description = matches[i]
case "virhash":
res.Hash = matches[i]
case "virsize":
i, err := strconv.Atoi(matches[i])
if err == nil {
res.Size = i
}
case "status":
res.Status = matches[i]
}
}
return res
}
func newCLAMDTcpConn(address string) (*CLAMDConn, error) {
conn, err := net.DialTimeout("tcp", address, TCP_TIMEOUT)