forked from sandia-minimega/minimega
/
ipmac.go
98 lines (82 loc) · 1.95 KB
/
ipmac.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright (2013) Sandia Corporation.
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
package bridge
import (
log "minilog"
"net"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
func (b *Bridge) snooper() {
var (
dot1q layers.Dot1Q
eth layers.Ethernet
ip4 layers.IPv4
ip6 layers.IPv6
arp layers.ARP
)
parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet,
&dot1q,
ð,
&ip4,
&ip6,
&arp,
)
decodedLayers := []gopacket.LayerType{}
for !b.destroyed() {
data, _, err := b.handle.ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if err != nil {
// only log error if it's not because we've been destroyed
if !b.destroyed() {
log.Error("error reading packet data: %v", err)
}
break
}
if err := parser.DecodeLayers(data, &decodedLayers); err != nil {
if err2, ok := err.(gopacket.UnsupportedLayerType); ok {
switch gopacket.LayerType(err2) {
case layers.LayerTypeICMPv6, gopacket.LayerTypePayload:
// ignore
err = nil
default:
continue
}
}
if err != nil {
log.Error("error parsing packet: %v", err)
continue
}
}
for _, layerType := range decodedLayers {
switch layerType {
case layers.LayerTypeICMPv6:
b.updateIP(eth.SrcMAC.String(), ip6.SrcIP)
case layers.LayerTypeARP:
b.updateIP(eth.SrcMAC.String(), net.IP(arp.SourceProtAddress))
}
}
}
log.Info("%v snoop out", b.Name)
}
func (b *Bridge) updateIP(mac string, ip net.IP) {
if ip == nil || ip.IsLinkLocalUnicast() {
return
}
log.Debug("got mac/ip pair: %v, %v", mac, ip)
bridgeLock.Lock()
defer bridgeLock.Unlock()
for _, tap := range b.taps {
if tap.Defunct || tap.MAC != mac {
continue
}
if ip := ip.To4(); ip != nil {
tap.IP4 = ip.String()
} else {
tap.IP6 = ip.String()
}
}
}