Skip to content

Why not add Packet Body Length field to EAPOL frame? #249

@qtopie

Description

@qtopie

I am learning IEEE 802.1X protocol with gopacket. Currently, there are only three fields in EAPOL interface.
I know that when no further information is needed and the packet body length is set to 0 (and the body is omitted). However, if there is a packet body, such as an EAP message, its length and data are added on as appropriate.

  • So why there is no Length field in EAPOL type? since sometimes it decodes EAPOL packet with errors

example:

  • packet (Get from wireshark)
----
# Packet 0 from /tmp/wireshark_eth0_20161108163321_MDBpM6.pcapng
- 154
- 6.941372676
- Hangzhou_91:eb:ec
- Nearest
- EAP
- 64
- Request, Identity

0000   01 80 c2 00 00 03 50 da 00 91 eb ec 88 8e 01 00  ......P.........
0010   00 05 01 01 00 05 01 00 00 00 00 00 00 00 00 00  ................
0020   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0030   00 00 00 00 00 00 00 00 00 00 00 00 29 70 35 65  ............)p5e
  • Code:
import (
	"fmt"
	"log"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

var (
	device      string = "eth0"
	snapshotLen int32  = 1024
	promiscuous bool   = false
	err         error
	timeout     time.Duration = -1 * time.Second
	handle      *pcap.Handle
)

func main() {
	// Open device
	handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
	var filter string = "ether proto 0x888e || udp port 61440"
	err = handle.SetBPFFilter(filter)
	if err != nil {
		log.Fatal(err)
	}
	defer handle.Close()

	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	for packet := range packetSource.Packets() {
		printPacketInfo(packet)
	}
}

func printPacketInfo(packet gopacket.Packet) {
	eapolP := gopacket.NewPacket(packet.Data(), layers.LayerTypeEthernet, gopacket.Default)
	fmt.Println(eapolP)
}
  • Running log
PACKET: 64 bytes
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..50..] SrcMAC=50:da:00:91:eb:ec DstMAC=01:80:c2:00:00:03 EthernetType=EAPOL Length=0}
- Layer 2 (02 bytes) = EAPOL    {Contents=[1, 0] Payload=[..48..] Version=1 Type=EAP}
- Layer 3 (48 bytes) = DecodeFailure    Packet decoding error: runtime error: slice bounds out of range

PACKET: 64 bytes
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..50..] SrcMAC=50:da:00:91:eb:ec DstMAC=01:80:c2:00:00:03 EthernetType=EAPOL Length=0}
- Layer 2 (02 bytes) = EAPOL    {Contents=[1, 0] Payload=[..48..] Version=1 Type=EAP}
- Layer 3 (48 bytes) = DecodeFailure    Packet decoding error: runtime error: slice bounds out of range

But it supposed to be like this (with following modified codeseapol.go):

- Layer 1 (14 bytes) = Ethernet	{Contents=[..14..] Payload=[..50..] SrcMAC=50:da:00:91:eb:ec DstMAC=01:80:c2:00:00:03 EthernetType=EAPOL Length=0}
- Layer 2 (04 bytes) = EAPOL	{Contents=[1, 0, 0, 5] Payload=[..46..] Version=1 Type=EAP Length=5}
- Layer 3 (05 bytes) = EAP	{Contents=[..5..] Payload=[..41..] Code=1 Id=1 Length=5 Type=1 TypeData=[..41..]}
  • By the way, why there is not SerializeTo method associated with EAPOL type?
    Provided with the customized code I have been tested:

layers/eapol.go

// Copyright 2012 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

package layers

import (
	"encoding/binary"

	"github.com/google/gopacket"
)

// EAPOL defines an EAP over LAN (802.1x) layer.
type EAPOL struct {
	BaseLayer
	Version uint8
	Type    EAPOLType
	Length  uint16
}

// LayerType returns LayerTypeEAPOL.
func (e *EAPOL) LayerType() gopacket.LayerType { return LayerTypeEAPOL }

// DecodeFromBytes decodes the given bytes into this layer.
func (e *EAPOL) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	e.Version = data[0]
	e.Type = EAPOLType(data[1])
	e.Length = binary.BigEndian.Uint16(data[2:4])
	e.BaseLayer = BaseLayer{data[:4], data[4:]}
	return nil
}

// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (e *EAPOL) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, _ := b.PrependBytes(4)
	bytes[0] = e.Version
	bytes[1] = byte(e.Type)
	binary.BigEndian.PutUint16(bytes[2:], e.Length)
	return nil
}

// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (e *EAPOL) CanDecode() gopacket.LayerClass {
	return LayerTypeEAPOL
}

// NextLayerType returns the layer type contained by this DecodingLayer.
func (e *EAPOL) NextLayerType() gopacket.LayerType {
	return e.Type.LayerType()
}

func decodeEAPOL(data []byte, p gopacket.PacketBuilder) error {
	e := &EAPOL{}
	return decodingLayerDecoder(e, data, p)
}

Thank you in advance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions