refact: refactored sniffer to allow several parsers

This commit is contained in:
evilsocket 2018-01-09 23:43:23 +01:00
commit 55b9b1f189
5 changed files with 235 additions and 180 deletions

View file

@ -3,111 +3,14 @@ package modules
import (
"fmt"
"net"
"os"
"regexp"
"time"
"github.com/evilsocket/bettercap-ng/core"
"github.com/evilsocket/bettercap-ng/log"
"github.com/evilsocket/bettercap-ng/session"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/pcapgo"
)
type SnifferContext struct {
Handle *pcap.Handle
DumpLocal bool
Verbose bool
Filter string
Expression string
Compiled *regexp.Regexp
Output string
OutputFile *os.File
OutputWriter *pcapgo.Writer
}
func NewSnifferContext() *SnifferContext {
return &SnifferContext{
Handle: nil,
DumpLocal: false,
Verbose: true,
Filter: "",
Expression: "",
Compiled: nil,
Output: "",
OutputFile: nil,
OutputWriter: nil,
}
}
var (
no = core.Red("no")
yes = core.Green("yes")
)
func (c *SnifferContext) Log(sess *session.Session) {
if c.DumpLocal {
log.Info("Skip local packets : %s", no)
} else {
log.Info("Skip local packets : %s", yes)
}
if c.Verbose {
log.Info("Verbose : %s", yes)
} else {
log.Info("Verbose : %s", no)
}
if c.Filter != "" {
log.Info("BPF Filter : '%s'", core.Yellow(c.Filter))
}
if c.Expression != "" {
log.Info("Regular expression : '%s'", core.Yellow(c.Expression))
}
if c.Output != "" {
log.Info("File output : '%s'", core.Yellow(c.Output))
}
}
func (c *SnifferContext) Close() {
if c.Handle != nil {
c.Handle.Close()
c.Handle = nil
}
if c.OutputFile != nil {
c.OutputFile.Close()
c.OutputFile = nil
}
}
type SnifferStats struct {
NumLocal uint64
NumMatched uint64
NumDumped uint64
NumWrote uint64
Started time.Time
FirstPacket time.Time
LastPacket time.Time
}
func NewSnifferStats() *SnifferStats {
return &SnifferStats{
NumLocal: 0,
NumMatched: 0,
NumDumped: 0,
NumWrote: 0,
Started: time.Now(),
FirstPacket: time.Time{},
LastPacket: time.Time{},
}
}
type Sniffer struct {
session.SessionModule
Stats *SnifferStats
@ -146,7 +49,12 @@ func NewSniffer(s *session.Session) *Sniffer {
sniff.AddHandler(session.NewModuleHandler("net.sniffer stats", "",
"Print sniffer session configuration and statistics.",
func(args []string) error {
return sniff.PrintStats()
sniff.Ctx.Log(sniff.Session)
if sniff.Stats == nil {
return fmt.Errorf("No stats yet.")
}
return sniff.Stats.Print()
}))
sniff.AddHandler(session.NewModuleHandler("net.sniffer on", "",
@ -208,91 +116,24 @@ func (s Sniffer) isLocalPacket(packet gopacket.Packet) bool {
return false
}
func (s *Sniffer) GetContext() (error, *SnifferContext) {
var err error
ctx := NewSnifferContext()
if ctx.Handle, err = pcap.OpenLive(s.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
return err, ctx
func (s *Sniffer) onPacketMatched(pkt gopacket.Packet) {
if s.Ctx.Verbose == false {
return
}
if err, v := s.Param("net.sniffer.verbose").Get(s.Session); err != nil {
return err, ctx
} else {
ctx.Verbose = v.(bool)
}
if err, v := s.Param("net.sniffer.local").Get(s.Session); err != nil {
return err, ctx
} else {
ctx.DumpLocal = v.(bool)
}
if err, v := s.Param("net.sniffer.filter").Get(s.Session); err != nil {
return err, ctx
} else {
if ctx.Filter = v.(string); ctx.Filter != "" {
err = ctx.Handle.SetBPFFilter(ctx.Filter)
if err != nil {
return err, ctx
}
dumped := false
for _, parser := range PacketParsers {
if parser(pkt) == true {
dumped = true
break
}
}
if err, v := s.Param("net.sniffer.regexp").Get(s.Session); err != nil {
return err, ctx
} else {
if ctx.Expression = v.(string); ctx.Expression != "" {
if ctx.Compiled, err = regexp.Compile(ctx.Expression); err != nil {
return err, ctx
}
}
if dumped == false {
noParser(pkt)
}
if err, v := s.Param("net.sniffer.output").Get(s.Session); err != nil {
return err, ctx
} else {
if ctx.Output = v.(string); ctx.Output != "" {
if ctx.OutputFile, err = os.Create(ctx.Output); err != nil {
return err, ctx
}
ctx.OutputWriter = pcapgo.NewWriter(ctx.OutputFile)
ctx.OutputWriter.WriteFileHeader(65536, layers.LinkTypeEthernet)
}
}
return nil, ctx
}
func (s *Sniffer) PrintStats() error {
if s.Stats == nil {
return fmt.Errorf("No stats yet.")
}
s.Ctx.Log(s.Session)
first := "never"
last := "never"
if s.Stats.FirstPacket.IsZero() == false {
first = s.Stats.FirstPacket.String()
}
if s.Stats.LastPacket.IsZero() == false {
last = s.Stats.LastPacket.String()
}
log.Info("Sniffer Started : %s", s.Stats.Started)
log.Info("First Packet Seen : %s", first)
log.Info("Last Packet Seen : %s", last)
log.Info("Local Packets : %d", s.Stats.NumLocal)
log.Info("Matched Packets : %d", s.Stats.NumMatched)
log.Info("Dumped Packets : %d", s.Stats.NumDumped)
log.Info("Wrote Packets : %d", s.Stats.NumWrote)
return nil
s.Stats.NumDumped++
}
func (s *Sniffer) Start() error {
@ -336,10 +177,7 @@ func (s *Sniffer) Start() error {
if s.Ctx.Compiled == nil || s.Ctx.Compiled.Match(data) == true {
s.Stats.NumMatched++
if s.Ctx.Verbose {
fmt.Println(packet.Dump())
s.Stats.NumDumped++
}
s.onPacketMatched(packet)
if s.Ctx.OutputWriter != nil {
s.Ctx.OutputWriter.WritePacket(packet.Metadata().CaptureInfo, data)

View file

@ -0,0 +1,141 @@
package modules
import (
"os"
"regexp"
"github.com/evilsocket/bettercap-ng/core"
"github.com/evilsocket/bettercap-ng/log"
"github.com/evilsocket/bettercap-ng/session"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/pcapgo"
)
type SnifferContext struct {
Handle *pcap.Handle
DumpLocal bool
Verbose bool
Filter string
Expression string
Compiled *regexp.Regexp
Output string
OutputFile *os.File
OutputWriter *pcapgo.Writer
}
func (s *Sniffer) GetContext() (error, *SnifferContext) {
var err error
ctx := NewSnifferContext()
if ctx.Handle, err = pcap.OpenLive(s.Session.Interface.Name(), 65536, true, pcap.BlockForever); err != nil {
return err, ctx
}
if err, v := s.Param("net.sniffer.verbose").Get(s.Session); err != nil {
return err, ctx
} else {
ctx.Verbose = v.(bool)
}
if err, v := s.Param("net.sniffer.local").Get(s.Session); err != nil {
return err, ctx
} else {
ctx.DumpLocal = v.(bool)
}
if err, v := s.Param("net.sniffer.filter").Get(s.Session); err != nil {
return err, ctx
} else {
if ctx.Filter = v.(string); ctx.Filter != "" {
err = ctx.Handle.SetBPFFilter(ctx.Filter)
if err != nil {
return err, ctx
}
}
}
if err, v := s.Param("net.sniffer.regexp").Get(s.Session); err != nil {
return err, ctx
} else {
if ctx.Expression = v.(string); ctx.Expression != "" {
if ctx.Compiled, err = regexp.Compile(ctx.Expression); err != nil {
return err, ctx
}
}
}
if err, v := s.Param("net.sniffer.output").Get(s.Session); err != nil {
return err, ctx
} else {
if ctx.Output = v.(string); ctx.Output != "" {
if ctx.OutputFile, err = os.Create(ctx.Output); err != nil {
return err, ctx
}
ctx.OutputWriter = pcapgo.NewWriter(ctx.OutputFile)
ctx.OutputWriter.WriteFileHeader(65536, layers.LinkTypeEthernet)
}
}
return nil, ctx
}
func NewSnifferContext() *SnifferContext {
return &SnifferContext{
Handle: nil,
DumpLocal: false,
Verbose: true,
Filter: "",
Expression: "",
Compiled: nil,
Output: "",
OutputFile: nil,
OutputWriter: nil,
}
}
var (
no = core.Red("no")
yes = core.Green("yes")
)
func (c *SnifferContext) Log(sess *session.Session) {
if c.DumpLocal {
log.Info("Skip local packets : %s", no)
} else {
log.Info("Skip local packets : %s", yes)
}
if c.Verbose {
log.Info("Verbose : %s", yes)
} else {
log.Info("Verbose : %s", no)
}
if c.Filter != "" {
log.Info("BPF Filter : '%s'", core.Yellow(c.Filter))
}
if c.Expression != "" {
log.Info("Regular expression : '%s'", core.Yellow(c.Expression))
}
if c.Output != "" {
log.Info("File output : '%s'", core.Yellow(c.Output))
}
}
func (c *SnifferContext) Close() {
if c.Handle != nil {
c.Handle.Close()
c.Handle = nil
}
if c.OutputFile != nil {
c.OutputFile.Close()
c.OutputFile = nil
}
}

View file

@ -0,0 +1,16 @@
package modules
import (
"fmt"
// "github.com/evilsocket/bettercap-ng/session"
"github.com/google/gopacket"
)
type SnifferPacketParser func(pkt gopacket.Packet) bool
var PacketParsers = []SnifferPacketParser{}
func noParser(pkt gopacket.Packet) bool {
fmt.Println(pkt.Dump())
return true
}

View file

@ -0,0 +1,51 @@
package modules
import (
"github.com/evilsocket/bettercap-ng/log"
"time"
)
type SnifferStats struct {
NumLocal uint64
NumMatched uint64
NumDumped uint64
NumWrote uint64
Started time.Time
FirstPacket time.Time
LastPacket time.Time
}
func NewSnifferStats() *SnifferStats {
return &SnifferStats{
NumLocal: 0,
NumMatched: 0,
NumDumped: 0,
NumWrote: 0,
Started: time.Now(),
FirstPacket: time.Time{},
LastPacket: time.Time{},
}
}
func (s *SnifferStats) Print() error {
first := "never"
last := "never"
if s.FirstPacket.IsZero() == false {
first = s.FirstPacket.String()
}
if s.LastPacket.IsZero() == false {
last = s.LastPacket.String()
}
log.Info("Sniffer Started : %s", s.Started)
log.Info("First Packet Seen : %s", first)
log.Info("Last Packet Seen : %s", last)
log.Info("Local Packets : %d", s.NumLocal)
log.Info("Matched Packets : %d", s.NumMatched)
log.Info("Dumped Packets : %d", s.NumDumped)
log.Info("Wrote Packets : %d", s.NumWrote)
return nil
}