icmp added

This commit is contained in:
crusader 2018-08-31 19:05:49 +09:00
parent f95ca6bdf1
commit 0e953adb3d
8 changed files with 664 additions and 6 deletions

View File

@ -0,0 +1,19 @@
package icmp
import (
omm "git.loafle.net/overflow/model/meta"
"git.loafle.net/overflow_scanner/probe/discovery/session"
)
func Scan(discoverySession session.DiscoverySession) error {
metaIPTypeEnum := omm.ToMetaIPTypeEnum(discoverySession.Zone().MetaIPType)
switch metaIPTypeEnum {
case omm.MetaIPTypeEnumV4:
return scanV4(discoverySession)
case omm.MetaIPTypeEnumV6:
return scanV4(discoverySession)
}
return nil
}

View File

@ -0,0 +1,175 @@
package icmp
import (
"fmt"
"log"
"math/rand"
"net"
"sync/atomic"
"time"
omd "git.loafle.net/overflow/model/discovery"
omm "git.loafle.net/overflow/model/meta"
omu "git.loafle.net/overflow/model/util"
"git.loafle.net/overflow_scanner/probe/discovery/session"
"git.loafle.net/overflow_scanner/probe/internal/pcap"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
func scanV4(discoverySession session.DiscoverySession) error {
targetHosts := discoverySession.TargetHosts()
if nil == targetHosts || 0 == len(targetHosts) {
return nil
}
zone := discoverySession.Zone()
ps, err := pcap.RetainScanner(zone)
if nil != err {
return fmt.Errorf("Cannot retain pcap instance %v", err)
}
defer func() {
pcap.ReleaseScanner(zone)
}()
icmpChan := ps.OpenICMP4()
defer func() {
ps.CloseICMP4(icmpChan)
}()
timerStopped := make(chan struct{})
go func() {
hosts := make(map[string]*omd.Host)
var delay atomic.Value
delay.Store(false)
ticker := time.NewTicker(time.Millisecond * 500)
for {
select {
case packet, ok := <-icmpChan:
if !ok {
// logging.Logger().Debugf("icmp channel is closed")
return
}
delay.Store(true)
if h := handlePacketICMP4(zone, targetHosts, hosts, packet); nil != h {
if h != nil {
log.Println(h)
}
// resultChan <- h
}
case <-ticker.C:
if false == delay.Load().(bool) {
ticker.Stop()
timerStopped <- struct{}{}
return
}
delay.Store(false)
}
}
}()
if err := sendICMP4(ps, zone, targetHosts); nil != err {
log.Printf("sendICMP %v", err)
return nil
}
select {
case <-timerStopped:
return nil
}
}
func sendICMP4(ps pcap.PCapScanner, zone *omd.Zone, targetHosts []net.IP) error {
conn, err := icmp.ListenPacket("ip4:icmp", "")
if nil != err {
return err
}
defer conn.Close()
msg, err := makeMessageICMP4()
if nil != err {
return err
}
var dst net.IPAddr
LOOP:
for _, targetHost := range targetHosts {
dst.IP = targetHost
if _, err := conn.WriteTo(msg, &dst); nil != err {
continue LOOP
}
timer := time.NewTimer(time.Microsecond * 100)
select {
case <-timer.C:
}
}
return nil
}
func handlePacketICMP4(zone *omd.Zone, targetHosts []net.IP, hosts map[string]*omd.Host, packet gopacket.Packet) *omd.Host {
_ethLayer := packet.Layer(layers.LayerTypeEthernet)
ethLayer := _ethLayer.(*layers.Ethernet)
_ip4Layer := packet.Layer(layers.LayerTypeIPv4)
ip4Layer := _ip4Layer.(*layers.IPv4)
_icmp4Layer := packet.Layer(layers.LayerTypeICMPv4)
icmp4Layer := _icmp4Layer.(*layers.ICMPv4)
if icmp4Layer.TypeCode != layers.ICMPv4TypeEchoReply {
return nil
}
ip := ip4Layer.SrcIP
if _, ok := hosts[ip.String()]; ok {
return nil
}
isTarget := false
for _, h := range targetHosts {
if h.Equal(ip) {
isTarget = true
break
}
}
if !isTarget {
return nil
}
h := &omd.Host{
MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
Address: ip.String(),
Mac: net.HardwareAddr(ethLayer.SrcMAC).String(),
Zone: zone,
DiscoveredDate: omu.NowPtr(),
}
hosts[ip.String()] = h
return h
}
func makeMessageICMP4() ([]byte, error) {
id := rand.Intn(0xffff)
seq := rand.Intn(0xffff)
return (&icmp.Message{
Type: ipv4.ICMPTypeEcho,
Code: 0,
Body: &icmp.Echo{
ID: id,
Seq: seq,
Data: []byte("PING by overFlow"),
},
}).Marshal(nil)
}

View File

@ -0,0 +1,125 @@
package icmp
import (
"net"
"reflect"
"testing"
omd "git.loafle.net/overflow/model/discovery"
omm "git.loafle.net/overflow/model/meta"
"git.loafle.net/overflow_scanner/probe/discovery/session"
"git.loafle.net/overflow_scanner/probe/discovery/types"
"git.loafle.net/overflow_scanner/probe/internal/pcap"
"github.com/google/gopacket"
)
func Test_scanV4(t *testing.T) {
s := session.NewMockDiscoverySession(
"testRequester",
types.DiscoveryRequestTypeHost,
&omd.Zone{
Network: "192.168.1.0/24",
Iface: "enp3s0",
MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
Address: "192.168.1.101",
Mac: "44:8a:5b:f1:f1:f3",
},
&omd.DiscoverHost{
MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV4),
FirstScanRange: "192.168.1.1",
LastScanRange: "192.168.1.254",
DiscoveryConfig: &omd.DiscoveryConfig{},
},
)
type args struct {
discoverySession session.DiscoverySession
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "1",
args: args{
discoverySession: s,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := scanV4(tt.args.discoverySession); (err != nil) != tt.wantErr {
t.Errorf("scanV4() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func Test_sendICMP4(t *testing.T) {
type args struct {
ps pcap.PCapScanner
zone *omd.Zone
targetHosts []net.IP
}
tests := []struct {
name string
args args
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := sendICMP4(tt.args.ps, tt.args.zone, tt.args.targetHosts); (err != nil) != tt.wantErr {
t.Errorf("sendICMP4() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func Test_handlePacketICMP4(t *testing.T) {
type args struct {
zone *omd.Zone
targetHosts []net.IP
hosts map[string]*omd.Host
packet gopacket.Packet
}
tests := []struct {
name string
args args
want *omd.Host
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := handlePacketICMP4(tt.args.zone, tt.args.targetHosts, tt.args.hosts, tt.args.packet); !reflect.DeepEqual(got, tt.want) {
t.Errorf("handlePacketICMP4() = %v, want %v", got, tt.want)
}
})
}
}
func Test_makeMessageICMP4(t *testing.T) {
tests := []struct {
name string
want []byte
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := makeMessageICMP4()
if (err != nil) != tt.wantErr {
t.Errorf("makeMessageICMP4() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("makeMessageICMP4() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,175 @@
package icmp
import (
"fmt"
"log"
"math/rand"
"net"
"sync/atomic"
"time"
omd "git.loafle.net/overflow/model/discovery"
omm "git.loafle.net/overflow/model/meta"
omu "git.loafle.net/overflow/model/util"
"git.loafle.net/overflow_scanner/probe/discovery/session"
"git.loafle.net/overflow_scanner/probe/internal/pcap"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
)
func scanV6(discoverySession session.DiscoverySession) error {
targetHosts := discoverySession.TargetHosts()
if nil == targetHosts || 0 == len(targetHosts) {
return nil
}
zone := discoverySession.Zone()
ps, err := pcap.RetainScanner(zone)
if nil != err {
return fmt.Errorf("Cannot retain pcap instance %v", err)
}
defer func() {
pcap.ReleaseScanner(zone)
}()
icmpChan := ps.OpenICMP6()
defer func() {
ps.CloseICMP6(icmpChan)
}()
timerStopped := make(chan struct{})
go func() {
hosts := make(map[string]*omd.Host)
var delay atomic.Value
delay.Store(false)
ticker := time.NewTicker(time.Millisecond * 500)
for {
select {
case packet, ok := <-icmpChan:
if !ok {
// logging.Logger().Debugf("icmp channel is closed")
return
}
delay.Store(true)
if h := handlePacketICMP6(zone, targetHosts, hosts, packet); nil != h {
if h != nil {
log.Println(h)
}
// resultChan <- h
}
case <-ticker.C:
if false == delay.Load().(bool) {
ticker.Stop()
timerStopped <- struct{}{}
return
}
delay.Store(false)
}
}
}()
if err := sendICMP6(ps, zone, targetHosts); nil != err {
log.Printf("sendICMP %v", err)
return nil
}
select {
case <-timerStopped:
return nil
}
}
func sendICMP6(ps pcap.PCapScanner, zone *omd.Zone, targetHosts []net.IP) error {
conn, err := icmp.ListenPacket("ip6:ipv6-icmp", "")
if nil != err {
return err
}
defer conn.Close()
msg, err := makeMessageICMP6()
if nil != err {
return err
}
var dst net.IPAddr
LOOP:
for _, targetHost := range targetHosts {
dst.IP = targetHost
if _, err := conn.WriteTo(msg, &dst); nil != err {
continue LOOP
}
timer := time.NewTimer(time.Microsecond * 100)
select {
case <-timer.C:
}
}
return nil
}
func handlePacketICMP6(zone *omd.Zone, targetHosts []net.IP, hosts map[string]*omd.Host, packet gopacket.Packet) *omd.Host {
_ethLayer := packet.Layer(layers.LayerTypeEthernet)
ethLayer := _ethLayer.(*layers.Ethernet)
_ip6Layer := packet.Layer(layers.LayerTypeIPv6)
ip6Layer := _ip6Layer.(*layers.IPv6)
_icmp6Layer := packet.Layer(layers.LayerTypeICMPv6)
icmp6Layer := _icmp6Layer.(*layers.ICMPv6)
if icmp6Layer.TypeCode != layers.ICMPv6TypeEchoReply {
return nil
}
ip := ip6Layer.SrcIP
if _, ok := hosts[ip.String()]; ok {
return nil
}
isTarget := false
for _, h := range targetHosts {
if h.Equal(ip) {
isTarget = true
break
}
}
if !isTarget {
return nil
}
h := &omd.Host{
MetaIPType: omm.ToMetaIPType(omm.MetaIPTypeEnumV6),
Address: ip.String(),
Mac: net.HardwareAddr(ethLayer.SrcMAC).String(),
Zone: zone,
DiscoveredDate: omu.NowPtr(),
}
hosts[ip.String()] = h
return h
}
func makeMessageICMP6() ([]byte, error) {
id := rand.Intn(0xffff)
seq := rand.Intn(0xffff)
return (&icmp.Message{
Type: ipv6.ICMPTypeEchoRequest,
Code: 0,
Body: &icmp.Echo{
ID: id,
Seq: seq,
Data: []byte("PING by overFlow"),
},
}).Marshal(nil)
}

View File

@ -37,7 +37,7 @@ SERVICE_LOOP:
ENTRY_LOOP: ENTRY_LOOP:
for _, entry := range entries { for _, entry := range entries {
// log.Print("serviceEntry ", entry) log.Print("serviceEntry ", entry)
name := entry.Instance // HP\ LaserJet\ P1505n name := entry.Instance // HP\ LaserJet\ P1505n
service := entry.Service // _pdl-datastream._tcp service := entry.Service // _pdl-datastream._tcp

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net" "net"
"strconv"
"sync" "sync"
omd "git.loafle.net/overflow/model/discovery" omd "git.loafle.net/overflow/model/discovery"
@ -26,13 +27,17 @@ type DiscoverySession interface {
DiscoverPort() *omd.DiscoverPort DiscoverPort() *omd.DiscoverPort
DiscoverService() *omd.DiscoverService DiscoverService() *omd.DiscoverService
TargetHosts() []net.IP
SetDiscoveryDelegator(chan<- interface{})
AddHost(host *omd.Host) *omd.Host AddHost(host *omd.Host) *omd.Host
AddPort(port *omd.Port) *omd.Port AddPort(port *omd.Port) *omd.Port
AddService(service *omd.Service) *omd.Service AddService(service *omd.Service) *omd.Service
TargetHosts() []net.IP DiscoveredHost(address string) *omd.Host
DiscoveredPort(host *omd.Host, portNumber int) map[string]*omd.Port
SetDiscoveryDelegator(chan<- interface{}) DiscoveredService(port *omd.Port, name string) map[string]*omd.Service
} }
type ofDiscoverySession struct { type ofDiscoverySession struct {
@ -243,6 +248,53 @@ func (ds *ofDiscoverySession) AddService(service *omd.Service) *omd.Service {
return s return s
} }
func (ds *ofDiscoverySession) DiscoveredHost(address string) *omd.Host {
h, ok := ds.hosts[address]
if !ok {
return nil
}
return h
}
func (ds *ofDiscoverySession) DiscoveredPort(host *omd.Host, portNumber int) map[string]*omd.Port {
h, _ := ds.findHost(host, false)
if nil == h {
return nil
}
hostPorts, ok := ds.ports[h]
if !ok {
return nil
}
ports, ok := hostPorts[json.Number(strconv.Itoa(portNumber))]
if !ok {
return nil
}
return ports
}
func (ds *ofDiscoverySession) DiscoveredService(port *omd.Port, name string) map[string]*omd.Service {
p, _ := ds.findPort(port, false)
if nil == p {
return nil
}
portServices, ok := ds.services[p]
if !ok {
return nil
}
services, ok := portServices[name]
if !ok {
return nil
}
return services
}
func (ds *ofDiscoverySession) findHost(host *omd.Host, add bool) (h *omd.Host, modified bool) { func (ds *ofDiscoverySession) findHost(host *omd.Host, add bool) (h *omd.Host, modified bool) {
modified = false modified = false
var ok bool var ok bool

View File

@ -10,6 +10,8 @@ type PacketType int
const ( const (
PacketTypeUnknown PacketType = iota PacketTypeUnknown PacketType = iota
PacketTypeARP PacketTypeARP
PacketTypeICMPv4
PacketTypeICMPv6
PacketTypeTCP PacketTypeTCP
PacketTypeUDP PacketTypeUDP
) )
@ -23,6 +25,16 @@ func getPacketType(packet gopacket.Packet) PacketType {
return PacketTypeARP return PacketTypeARP
} }
layer = packet.Layer(layers.LayerTypeICMPv4)
if layer != nil {
return PacketTypeICMPv4
}
layer = packet.Layer(layers.LayerTypeICMPv6)
if layer != nil {
return PacketTypeICMPv6
}
layer = packet.Layer(layers.LayerTypeTCP) layer = packet.Layer(layers.LayerTypeTCP)
if layer != nil { if layer != nil {
if _, ok := layer.(*layers.TCP); ok { if _, ok := layer.(*layers.TCP); ok {
@ -43,6 +55,10 @@ func handlePacket(ps *pCapScan, packet gopacket.Packet) {
switch getPacketType(packet) { switch getPacketType(packet) {
case PacketTypeARP: case PacketTypeARP:
handlePacketARP(ps, packet) handlePacketARP(ps, packet)
case PacketTypeICMPv4:
handlePacketICMP4(ps, packet)
case PacketTypeICMPv6:
handlePacketICMP6(ps, packet)
case PacketTypeTCP: case PacketTypeTCP:
handlePacketTCP(ps, packet) handlePacketTCP(ps, packet)
case PacketTypeUDP: case PacketTypeUDP:
@ -63,6 +79,30 @@ func handlePacketARP(ps *pCapScan, packet gopacket.Packet) {
} }
} }
func handlePacketICMP4(ps *pCapScan, packet gopacket.Packet) {
ps.icmp4ListenerChanMtx.RLock()
defer ps.icmp4ListenerChanMtx.RUnlock()
// icmp4Layer := packet.Layer(layers.LayerTypeICMPv4)
// icmp4 := icmp4Layer.(*layers.ICMPv4)
for _, ch := range ps.icmp4ListenerChans {
ch <- packet
}
}
func handlePacketICMP6(ps *pCapScan, packet gopacket.Packet) {
ps.icmp6ListenerChanMtx.RLock()
defer ps.icmp6ListenerChanMtx.RUnlock()
// icmp6Layer := packet.Layer(layers.LayerTypeICMPv6)
// icmp6 := icmp6Layer.(*layers.ICMPv6)
for _, ch := range ps.icmp6ListenerChans {
ch <- packet
}
}
func handlePacketTCP(ps *pCapScan, packet gopacket.Packet) { func handlePacketTCP(ps *pCapScan, packet gopacket.Packet) {
ipLayer := packet.Layer(layers.LayerTypeIPv4) ipLayer := packet.Layer(layers.LayerTypeIPv4)
if nil == ipLayer { if nil == ipLayer {

View File

@ -23,6 +23,12 @@ type PCapScanner interface {
OpenARP() chan *layers.ARP OpenARP() chan *layers.ARP
CloseARP(ch chan *layers.ARP) CloseARP(ch chan *layers.ARP)
OpenICMP4() chan gopacket.Packet
CloseICMP4(ch chan gopacket.Packet)
OpenICMP6() chan gopacket.Packet
CloseICMP6(ch chan gopacket.Packet)
OpenTCP(ip string) chan *layers.TCP OpenTCP(ip string) chan *layers.TCP
CloseTCP(ip string, ch chan *layers.TCP) CloseTCP(ip string, ch chan *layers.TCP)
@ -45,6 +51,12 @@ type pCapScan struct {
arpListenerChanMtx sync.RWMutex arpListenerChanMtx sync.RWMutex
arpListenerChans []chan *layers.ARP arpListenerChans []chan *layers.ARP
icmp4ListenerChanMtx sync.RWMutex
icmp4ListenerChans []chan gopacket.Packet
icmp6ListenerChanMtx sync.RWMutex
icmp6ListenerChans []chan gopacket.Packet
tcpListenerChanMtx sync.RWMutex tcpListenerChanMtx sync.RWMutex
tcpListenerChans map[string][]chan *layers.TCP tcpListenerChans map[string][]chan *layers.TCP
@ -70,13 +82,15 @@ func (ps *pCapScan) start() error {
// set filter // set filter
// todo add tcp, udp filter // todo add tcp, udp filter
//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 { //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 {
if err = h.SetBPFFilter("arp or tcp or udp"); nil != err { if err = h.SetBPFFilter("arp or icmp or icmp6 or tcp or udp"); nil != err {
h.Close() h.Close()
return err return err
} }
ps.pCapHandle = h ps.pCapHandle = h
ps.arpListenerChans = make([]chan *layers.ARP, 0) ps.arpListenerChans = make([]chan *layers.ARP, 0)
ps.icmp4ListenerChans = make([]chan gopacket.Packet, 0)
ps.icmp6ListenerChans = make([]chan gopacket.Packet, 0)
ps.tcpListenerChans = make(map[string][]chan *layers.TCP, 0) ps.tcpListenerChans = make(map[string][]chan *layers.TCP, 0)
ps.udpListenerChans = make(map[string][]chan gopacket.Packet, 0) ps.udpListenerChans = make(map[string][]chan gopacket.Packet, 0)
@ -119,6 +133,50 @@ func (ps *pCapScan) CloseARP(ch chan *layers.ARP) {
} }
} }
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:]...)
}
}
func (ps *pCapScan) OpenTCP(ip string) chan *layers.TCP { func (ps *pCapScan) OpenTCP(ip string) chan *layers.TCP {
ps.tcpListenerChanMtx.Lock() ps.tcpListenerChanMtx.Lock()
defer ps.tcpListenerChanMtx.Unlock() defer ps.tcpListenerChanMtx.Unlock()
@ -222,6 +280,20 @@ func (ps *pCapScan) destroy() {
} }
ps.udpListenerChanMtx.Unlock() ps.udpListenerChanMtx.Unlock()
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()
ps.arpListenerChanMtx.Lock() ps.arpListenerChanMtx.Lock()
for _, v := range ps.arpListenerChans { for _, v := range ps.arpListenerChans {
close(v) close(v)
@ -235,7 +307,7 @@ func (ps *pCapScan) destroy() {
func handleReceive(ps *pCapScan) { func handleReceive(ps *pCapScan) {
defer ps.stopWg.Done() defer ps.stopWg.Done()
pSrc := gopacket.NewPacketSource(ps.pCapHandle, layers.LayerTypeEthernet) pSrc := gopacket.NewPacketSource(ps.pCapHandle, ps.pCapHandle.LinkType())
inPacket := pSrc.Packets() inPacket := pSrc.Packets()
for { for {