2018-08-12 10:24:23 +00:00
package pcap
import (
"fmt"
"sort"
"sync"
2018-08-13 07:19:59 +00:00
omd "git.loafle.net/overflow/model/discovery"
2018-08-12 10:24:23 +00:00
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
2018-08-13 07:19:59 +00:00
func newPCapScanner ( zone * omd . Zone ) PCapScanner {
2018-08-12 10:24:23 +00:00
ps := & pCapScan {
2018-08-12 11:08:31 +00:00
zone : zone ,
2018-08-12 10:24:23 +00:00
}
return ps
}
type PCapScanner interface {
OpenARP ( ) chan * layers . ARP
CloseARP ( ch chan * layers . ARP )
2018-08-31 10:05:49 +00:00
OpenICMP4 ( ) chan gopacket . Packet
CloseICMP4 ( ch chan gopacket . Packet )
OpenICMP6 ( ) chan gopacket . Packet
CloseICMP6 ( ch chan gopacket . Packet )
2018-08-12 10:24:23 +00:00
OpenTCP ( ip string ) chan * layers . TCP
CloseTCP ( ip string , ch chan * layers . TCP )
OpenUDP ( ip string ) chan gopacket . Packet
CloseUDP ( ip string , ch chan gopacket . Packet )
WritePacketData ( data [ ] byte ) ( err error )
start ( ) error
stop ( )
retain ( )
release ( ) bool
}
type pCapScan struct {
pCapHandle * pcap . Handle
2018-08-13 07:19:59 +00:00
zone * omd . Zone
2018-08-12 10:24:23 +00:00
arpListenerChanMtx sync . RWMutex
arpListenerChans [ ] chan * layers . ARP
2018-08-31 10:05:49 +00:00
icmp4ListenerChanMtx sync . RWMutex
icmp4ListenerChans [ ] chan gopacket . Packet
icmp6ListenerChanMtx sync . RWMutex
icmp6ListenerChans [ ] chan gopacket . Packet
2018-08-12 10:24:23 +00:00
tcpListenerChanMtx sync . RWMutex
tcpListenerChans map [ string ] [ ] chan * layers . TCP
udpListenerChanMtx sync . RWMutex
udpListenerChans map [ string ] [ ] chan gopacket . Packet
refCount int
stopChan chan struct { }
stopWg sync . WaitGroup
}
func ( ps * pCapScan ) start ( ) error {
if ps . stopChan != nil {
return fmt . Errorf ( "PCapScanner: already running. Stop it before starting it again" )
}
// new pcap handle
var h * pcap . Handle
var err error
if h , err = pcap . OpenLive ( ps . zone . Iface , 65536 , true , pcap . BlockForever ) ; nil != err {
return err
}
// set filter
// todo add tcp, udp filter
2018-08-15 06:18:40 +00:00
//if err = h.SetBPFFilter("arp and src net " + ps.zone.Network + " or (((tcp[tcpflags] & (tcp-syn|tcp-ack) != 0) or (tcp[tcpflags] & (tcp-rst) != 0)) and port 60000) or udp "); nil != err {
2018-08-31 10:05:49 +00:00
if err = h . SetBPFFilter ( "arp or icmp or icmp6 or tcp or udp" ) ; nil != err {
2018-08-12 10:24:23 +00:00
h . Close ( )
return err
}
ps . pCapHandle = h
ps . arpListenerChans = make ( [ ] chan * layers . ARP , 0 )
2018-08-31 10:05:49 +00:00
ps . icmp4ListenerChans = make ( [ ] chan gopacket . Packet , 0 )
ps . icmp6ListenerChans = make ( [ ] chan gopacket . Packet , 0 )
2018-08-12 10:24:23 +00:00
ps . tcpListenerChans = make ( map [ string ] [ ] chan * layers . TCP , 0 )
ps . udpListenerChans = make ( map [ string ] [ ] chan gopacket . Packet , 0 )
ps . stopChan = make ( chan struct { } )
ps . stopWg . Add ( 1 )
go handleReceive ( ps )
return nil
}
func ( ps * pCapScan ) stop ( ) {
if ps . stopChan == nil {
panic ( "PCapScanner: must be started before stopping it" )
}
close ( ps . stopChan )
ps . stopWg . Wait ( )
ps . stopChan = nil
}
func ( ps * pCapScan ) OpenARP ( ) chan * layers . ARP {
ps . arpListenerChanMtx . Lock ( )
defer ps . arpListenerChanMtx . Unlock ( )
c := make ( chan * layers . ARP , 0 )
ps . arpListenerChans = append ( ps . arpListenerChans , c )
return c
}
func ( ps * pCapScan ) CloseARP ( ch chan * layers . ARP ) {
ps . arpListenerChanMtx . Lock ( )
defer ps . arpListenerChanMtx . Unlock ( )
i := sort . Search ( len ( ps . arpListenerChans ) , func ( i int ) bool {
return ch == ps . arpListenerChans [ i ]
} )
if - 1 != i {
close ( ch )
ps . arpListenerChans = append ( ps . arpListenerChans [ : i ] , ps . arpListenerChans [ i + 1 : ] ... )
}
}
2018-08-31 10:05:49 +00:00
func ( ps * pCapScan ) OpenICMP4 ( ) chan gopacket . Packet {
ps . icmp4ListenerChanMtx . Lock ( )
defer ps . icmp4ListenerChanMtx . Unlock ( )
c := make ( chan gopacket . Packet , 0 )
ps . icmp4ListenerChans = append ( ps . icmp4ListenerChans , c )
return c
}
func ( ps * pCapScan ) CloseICMP4 ( ch chan gopacket . Packet ) {
ps . icmp4ListenerChanMtx . Lock ( )
defer ps . icmp4ListenerChanMtx . Unlock ( )
i := sort . Search ( len ( ps . icmp4ListenerChans ) , func ( i int ) bool {
return ch == ps . icmp4ListenerChans [ i ]
} )
if - 1 != i {
close ( ch )
ps . icmp4ListenerChans = append ( ps . icmp4ListenerChans [ : i ] , ps . icmp4ListenerChans [ i + 1 : ] ... )
}
}
func ( ps * pCapScan ) OpenICMP6 ( ) chan gopacket . Packet {
ps . icmp6ListenerChanMtx . Lock ( )
defer ps . icmp6ListenerChanMtx . Unlock ( )
c := make ( chan gopacket . Packet , 0 )
ps . icmp6ListenerChans = append ( ps . icmp6ListenerChans , c )
return c
}
func ( ps * pCapScan ) CloseICMP6 ( ch chan gopacket . Packet ) {
ps . icmp6ListenerChanMtx . Lock ( )
defer ps . icmp6ListenerChanMtx . Unlock ( )
i := sort . Search ( len ( ps . icmp6ListenerChans ) , func ( i int ) bool {
return ch == ps . icmp6ListenerChans [ i ]
} )
if - 1 != i {
close ( ch )
ps . icmp6ListenerChans = append ( ps . icmp6ListenerChans [ : i ] , ps . icmp6ListenerChans [ i + 1 : ] ... )
}
}
2018-08-12 10:24:23 +00:00
func ( ps * pCapScan ) OpenTCP ( ip string ) chan * layers . TCP {
ps . tcpListenerChanMtx . Lock ( )
defer ps . tcpListenerChanMtx . Unlock ( )
if _ , ok := ps . tcpListenerChans [ ip ] ; ! ok {
ps . tcpListenerChans [ ip ] = make ( [ ] chan * layers . TCP , 0 )
}
ch := make ( chan * layers . TCP , 0 )
ps . tcpListenerChans [ ip ] = append ( ps . tcpListenerChans [ ip ] , ch )
return ch
}
func ( ps * pCapScan ) CloseTCP ( ip string , ch chan * layers . TCP ) {
ps . tcpListenerChanMtx . Lock ( )
defer ps . tcpListenerChanMtx . Unlock ( )
if _ , ok := ps . tcpListenerChans [ ip ] ; ! ok {
return
}
chs := ps . tcpListenerChans [ ip ]
i := sort . Search ( len ( chs ) , func ( i int ) bool {
return ch == chs [ i ]
} )
if - 1 != i {
close ( ch )
ps . tcpListenerChans [ ip ] = append ( ps . tcpListenerChans [ ip ] [ : i ] , ps . tcpListenerChans [ ip ] [ i + 1 : ] ... )
}
}
func ( ps * pCapScan ) OpenUDP ( ip string ) chan gopacket . Packet {
ps . udpListenerChanMtx . Lock ( )
defer ps . udpListenerChanMtx . Unlock ( )
if _ , ok := ps . udpListenerChans [ ip ] ; ! ok {
ps . udpListenerChans [ ip ] = make ( [ ] chan gopacket . Packet , 0 )
}
ch := make ( chan gopacket . Packet , 0 )
ps . udpListenerChans [ ip ] = append ( ps . udpListenerChans [ ip ] , ch )
return ch
}
func ( ps * pCapScan ) CloseUDP ( ip string , ch chan gopacket . Packet ) {
ps . udpListenerChanMtx . Lock ( )
defer ps . udpListenerChanMtx . Unlock ( )
if _ , ok := ps . udpListenerChans [ ip ] ; ! ok {
return
}
chs := ps . udpListenerChans [ ip ]
i := sort . Search ( len ( chs ) , func ( i int ) bool {
return ch == chs [ i ]
} )
if - 1 != i {
close ( ch )
ps . udpListenerChans [ ip ] = append ( ps . udpListenerChans [ ip ] [ : i ] , ps . udpListenerChans [ ip ] [ i + 1 : ] ... )
}
}
func ( ps * pCapScan ) WritePacketData ( data [ ] byte ) ( err error ) {
return ps . pCapHandle . WritePacketData ( data )
}
func ( ps * pCapScan ) retain ( ) {
ps . refCount ++
}
func ( ps * pCapScan ) release ( ) bool {
ps . refCount --
if 0 > ps . refCount {
ps . refCount = 0
}
return 0 == ps . refCount
}
func ( ps * pCapScan ) destroy ( ) {
ps . tcpListenerChanMtx . Lock ( )
for k , v := range ps . tcpListenerChans {
for _ , ch := range v {
close ( ch )
}
v = v [ : 0 ]
delete ( ps . tcpListenerChans , k )
}
ps . tcpListenerChanMtx . Unlock ( )
ps . udpListenerChanMtx . Lock ( )
for k , v := range ps . udpListenerChans {
for _ , ch := range v {
close ( ch )
}
v = v [ : 0 ]
delete ( ps . udpListenerChans , k )
}
ps . udpListenerChanMtx . Unlock ( )
2018-08-31 10:05:49 +00:00
ps . icmp4ListenerChanMtx . Lock ( )
for _ , v := range ps . icmp4ListenerChans {
close ( v )
}
ps . icmp4ListenerChans = ps . icmp4ListenerChans [ : 0 ]
ps . icmp4ListenerChanMtx . Unlock ( )
ps . icmp6ListenerChanMtx . Lock ( )
for _ , v := range ps . icmp6ListenerChans {
close ( v )
}
ps . icmp6ListenerChans = ps . icmp6ListenerChans [ : 0 ]
ps . icmp6ListenerChanMtx . Unlock ( )
2018-08-12 10:24:23 +00:00
ps . arpListenerChanMtx . Lock ( )
for _ , v := range ps . arpListenerChans {
close ( v )
}
ps . arpListenerChans = ps . arpListenerChans [ : 0 ]
ps . arpListenerChanMtx . Unlock ( )
ps . pCapHandle . Close ( )
}
func handleReceive ( ps * pCapScan ) {
defer ps . stopWg . Done ( )
2018-08-31 10:05:49 +00:00
pSrc := gopacket . NewPacketSource ( ps . pCapHandle , ps . pCapHandle . LinkType ( ) )
2018-08-12 10:24:23 +00:00
inPacket := pSrc . Packets ( )
for {
select {
case packet := <- inPacket :
handlePacket ( ps , packet )
case <- ps . stopChan :
ps . destroy ( )
return
}
}
2018-08-15 06:18:40 +00:00
2018-08-12 10:24:23 +00:00
}