92 lines
2.6 KiB
Go
92 lines
2.6 KiB
Go
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.PMTU)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("Sending ICMP 3,4 (%v -> %v): PMTU= %v\n", dec.ip.DstIP, dec.ip.SrcIP, ftbe.PMTU)
|
|
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)
|
|
}
|