This commit is contained in:
crusader 2018-09-05 14:59:34 +09:00
parent 6161d7fade
commit 4728182733
2 changed files with 110 additions and 38 deletions

View File

@ -15,8 +15,16 @@ import (
"git.loafle.net/overflow_scanner/probe/internal/pcap" "git.loafle.net/overflow_scanner/probe/internal/pcap"
"github.com/google/gopacket" "github.com/google/gopacket"
"github.com/google/gopacket/layers" "github.com/google/gopacket/layers"
"golang.org/x/net/icmp" )
"golang.org/x/net/ipv4"
const (
// IP flag
DF = 0x02
// // IP header len
// IPHLEN = 40
//
// SIOCGIFMTU = 0x8921
UINT16 = 65535
) )
func scanV4(discoverySession session.DiscoverySession) error { func scanV4(discoverySession session.DiscoverySession) error {
@ -38,12 +46,15 @@ func scanV4(discoverySession session.DiscoverySession) error {
}() }()
timerStopped := make(chan struct{}) timerStopped := make(chan struct{})
stopChan := make(chan struct{})
defer close(stopChan)
go func() { go func() {
hosts := make(map[string]*omd.Host) hosts := make(map[string]*omd.Host)
var delay atomic.Value var delay atomic.Value
delay.Store(false) delay.Store(false)
ticker := time.NewTicker(time.Millisecond * 500) ticker := time.NewTicker(time.Millisecond * 1000)
for { for {
select { select {
@ -67,7 +78,7 @@ func scanV4(discoverySession session.DiscoverySession) error {
} }
}() }()
if err := sendICMP4(ps, zone, targetHosts); nil != err { if err := sendICMP4(ps, discoverySession, stopChan); nil != err {
log.Printf("sendICMP %v", err) log.Printf("sendICMP %v", err)
return nil return nil
} }
@ -80,31 +91,53 @@ func scanV4(discoverySession session.DiscoverySession) error {
} }
} }
func sendICMP4(ps pcap.PCapScanner, zone *omd.Zone, targetHosts []net.IP) error { func sendICMP4(ps pcap.PCapScanner, discoverySession session.DiscoverySession, stopChan chan struct{}) error {
conn, err := icmp.ListenPacket("ip4:icmp", "") targetHosts := discoverySession.TargetHosts()
if nil != err {
return err
}
defer conn.Close()
msg, err := makeMessageICMP4() icmp4Packet, err := makePacketICMPv4(discoverySession.Zone())
if nil != err { if nil != err {
return err return err
} }
var dst net.IPAddr buf := gopacket.NewSerializeBuffer()
LOOP: LOOP:
for _, targetHost := range targetHosts { for _, targetHost := range targetHosts {
dst.IP = targetHost h := discoverySession.DiscoveredHost(targetHost.String())
if _, err := conn.WriteTo(msg, &dst); nil != err { if nil != h && "" != h.Mac {
mac, err := net.ParseMAC(h.Mac)
if nil != err {
icmp4Packet.Eth.DstMAC = nil
} else {
icmp4Packet.Eth.DstMAC = mac
}
}
if nil == icmp4Packet.Eth.DstMAC {
icmp4Packet.Eth.DstMAC = net.HardwareAddr{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
}
icmp4Packet.IP.DstIP = targetHost
icmp4Packet.IP.Id = uint16(rand.Intn(UINT16))
icmp4Packet.ICMPv4.Id = uint16(rand.Intn(0xffff))
icmp4Packet.ICMPv4.Seq = uint16(rand.Intn(0xffff))
if err := gopacket.SerializeLayers(buf, icmp4Packet.Opts, icmp4Packet.Eth, icmp4Packet.IP, icmp4Packet.ICMPv4); err != nil {
log.Print(err)
continue LOOP
}
if err := ps.WritePacketData(buf.Bytes()); err != nil {
log.Print(err)
continue LOOP continue LOOP
} }
select { select {
case <-time.After(time.Microsecond * 100): case <-time.After(time.Microsecond * 100):
case <-stopChan:
return nil
}
} }
}
return nil return nil
} }
@ -152,17 +185,47 @@ func handlePacketICMP4(zone *omd.Zone, targetHosts []net.IP, hosts map[string]*o
return h return h
} }
func makeMessageICMP4() ([]byte, error) { type PacketICMPv4 struct {
id := rand.Intn(0xffff) Eth *layers.Ethernet
seq := rand.Intn(0xffff) IP *layers.IPv4
ICMPv4 *layers.ICMPv4
return (&icmp.Message{ Opts gopacket.SerializeOptions
Type: ipv4.ICMPTypeEcho, }
Code: 0,
Body: &icmp.Echo{ func makePacketICMPv4(zone *omd.Zone) (*PacketICMPv4, error) {
ID: id, packetICMPv4 := &PacketICMPv4{}
Seq: seq,
Data: []byte("PING by overFlow"), srcIP := net.ParseIP(zone.Address)
}, if nil == srcIP {
}).Marshal(nil) return nil, fmt.Errorf("IP(%s) of zone is not valid", zone.Address)
}
srcMac, err := net.ParseMAC(zone.Mac)
if nil != err {
return nil, err
}
packetICMPv4.Eth = &layers.Ethernet{
SrcMAC: srcMac,
EthernetType: layers.EthernetTypeIPv4,
}
packetICMPv4.IP = &layers.IPv4{
SrcIP: srcIP,
Flags: DF,
Version: 4,
TTL: 64,
Protocol: layers.IPProtocolICMPv4,
}
packetICMPv4.ICMPv4 = &layers.ICMPv4{
TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoRequest, 0),
}
packetICMPv4.Opts = gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
return packetICMPv4, nil
} }

View File

@ -18,7 +18,12 @@ func Test_scanV4(t *testing.T) {
"testRequester", "testRequester",
types.DiscoveryRequestTypeHost, types.DiscoveryRequestTypeHost,
__test.Zone(), __test.Zone(),
__test.DiscoverHost(__test.DiscoveryConfig(), 1, 254, nil), __test.DiscoverHost(
__test.DiscoveryConfig(),
1,
254,
nil,
),
) )
type args struct { type args struct {
@ -49,8 +54,8 @@ func Test_scanV4(t *testing.T) {
func Test_sendICMP4(t *testing.T) { func Test_sendICMP4(t *testing.T) {
type args struct { type args struct {
ps pcap.PCapScanner ps pcap.PCapScanner
zone *omd.Zone discoverySession session.DiscoverySession
targetHosts []net.IP stopChan chan struct{}
} }
tests := []struct { tests := []struct {
name string name string
@ -61,7 +66,7 @@ func Test_sendICMP4(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := sendICMP4(tt.args.ps, tt.args.zone, tt.args.targetHosts); (err != nil) != tt.wantErr { if err := sendICMP4(tt.args.ps, tt.args.discoverySession, tt.args.stopChan); (err != nil) != tt.wantErr {
t.Errorf("sendICMP4() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("sendICMP4() error = %v, wantErr %v", err, tt.wantErr)
} }
}) })
@ -91,23 +96,27 @@ func Test_handlePacketICMP4(t *testing.T) {
} }
} }
func Test_makeMessageICMP4(t *testing.T) { func Test_makePacketICMPv4(t *testing.T) {
type args struct {
zone *omd.Zone
}
tests := []struct { tests := []struct {
name string name string
want []byte args args
want *PacketICMPv4
wantErr bool wantErr bool
}{ }{
// TODO: Add test cases. // TODO: Add test cases.
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := makeMessageICMP4() got, err := makePacketICMPv4(tt.args.zone)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("makeMessageICMP4() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("makePacketICMPv4() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if !reflect.DeepEqual(got, tt.want) { if !reflect.DeepEqual(got, tt.want) {
t.Errorf("makeMessageICMP4() = %v, want %v", got, tt.want) t.Errorf("makePacketICMPv4() = %v, want %v", got, tt.want)
} }
}) })
} }