forked from weaveworks/weave
/
ethernet_decoder.go
91 lines (82 loc) · 2.65 KB
/
ethernet_decoder.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
package weave
import (
"bytes"
"code.google.com/p/gopacket"
"code.google.com/p/gopacket/layers"
"log"
"net"
)
func NewEthernetDecoder() *EthernetDecoder {
dec := &EthernetDecoder{}
dec.parser = gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &dec.eth, &dec.ip)
return dec
}
func (dec *EthernetDecoder) DecodeLayers(data []byte) error {
return dec.parser.DecodeLayers(data, &dec.decoded)
}
func (dec *EthernetDecoder) CheckFrameTooBig(err error, sendFrame func([]byte) error) error {
if ftbe, ok := err.(FrameTooBigError); ok {
// we know: 1. ip is valid, 2. it was ip and DF was set
icmpFrame, err := dec.formICMPMTUPacket(ftbe.EPMTU)
if err != nil {
return err
}
log.Printf("Sending ICMP 3,4 (%v -> %v): PMTU= %v\n", dec.ip.DstIP, dec.ip.SrcIP, ftbe.EPMTU)
return sendFrame(icmpFrame)
} else {
return err
}
}
func (dec *EthernetDecoder) formICMPMTUPacket(mtu int) ([]byte, error) {
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true}
ipHeaderSize := int(dec.ip.IHL) * 4 // IHL is the number of 32-byte words in the header
payload := gopacket.Payload(dec.ip.BaseLayer.Contents[:ipHeaderSize+8])
err := gopacket.SerializeLayers(buf, opts,
&layers.Ethernet{
SrcMAC: dec.eth.DstMAC,
DstMAC: dec.eth.SrcMAC,
EthernetType: dec.eth.EthernetType},
&layers.IPv4{
Version: 4,
TOS: dec.ip.TOS,
Id: 0,
Flags: 0,
FragOffset: 0,
TTL: 64,
Protocol: layers.IPProtocolICMPv4,
DstIP: dec.ip.SrcIP,
SrcIP: dec.ip.DstIP},
&layers.ICMPv4{
TypeCode: 0x304,
Id: 0,
Seq: uint16(mtu)},
&payload)
if err != nil {
return []byte{}, err
}
return buf.Bytes(), nil
}
var (
// see http://en.wikipedia.org/wiki/Multicast_address#Ethernet
broadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
zeroMAC, _ = net.ParseMAC("00:00:00:00:00:00")
stpMACPrefix = []byte{0x01, 0x80, 0xC2, 0x00, 0x00}
ipv4MulticastMACPrefix = []byte{0x01, 0x00, 0x5E}
ipv6MulticastMACPrefix = []byte{0x33, 0x33}
)
func (dec *EthernetDecoder) DropFrame() bool {
return bytes.Equal(stpMACPrefix, dec.eth.DstMAC[:len(stpMACPrefix)])
}
func (dec *EthernetDecoder) BroadcastFrame() bool {
return bytes.Equal(broadcastMAC, dec.eth.DstMAC) ||
// treat multicast frames as broadcast
bytes.Equal(ipv4MulticastMACPrefix, dec.eth.DstMAC[:len(ipv4MulticastMACPrefix)]) ||
bytes.Equal(ipv6MulticastMACPrefix, dec.eth.DstMAC[:len(ipv6MulticastMACPrefix)])
}
func (dec *EthernetDecoder) IsPMTUVerify() bool {
return bytes.Equal(zeroMAC, dec.eth.SrcMAC) &&
bytes.Equal(zeroMAC, dec.eth.DstMAC)
}