google / gopacket

Provides packet processing capabilities for Go
BSD 3-Clause "New" or "Revised" License
6.35k stars 1.13k forks source link

FixLengths Option doesn't work for EAP Layer #931

Open cmarmonier opened 2 years ago

cmarmonier commented 2 years ago

This code sent EAPoL packet, but it doesn't work Length field value of EAP field is 12 : it should be 16. Length field value of 802.1X field is 0 : it should be 16.

func eapol_ResponseIdentity(handle *pcap.Handle, iface *net.Interface, id uint8, identity []byte) error {

    //.len := 5 + uint16(len(identity))

    eap1 := layers.EAP{
        Code:     layers.EAPCodeResponse,
        Id:       id,
        Type:     layers.EAPTypeIdentity,
        TypeData: identity,
        //.Length:   len,
    }

    eapol := layers.EAPOL{
        Version: 1,
        Type:    layers.EAPOLTypeEAP,
        Length:  eap1.Length,
    }

    eth := layers.Ethernet{
        SrcMAC:       iface.HardwareAddr,
        DstMAC:       net.HardwareAddr{0x01, 0x80, 0xc2, 0x00, 0x00, 0x03},
        EthernetType: layers.EthernetTypeEAPOL,
    }

    buf := gopacket.NewSerializeBuffer()
    opts := gopacket.SerializeOptions{
        FixLengths: true,
        //.FixLengths:       false,
        ComputeChecksums: true,
    }

    gopacket.SerializeLayers(buf, opts, &eth, &eapol, &eap1)
    log.Printf("send EOPoL : Response Identity %v, %s...", id, string(identity))
    if err := handle.WritePacketData(buf.Bytes()); err != nil {
        log.Printf("Send err ", err)
        return err
    }
    //log.Printf("send packet [OK]")

    return nil
}

I think problem come from calculation of Length field value of EAP field. If you uncomment lines with "//.", code works... but it isn't normal to do it...

cmarmonier commented 2 years ago

I fixed problem but I'm not sure it is the best method.

I modified eap.go (I added CalcLen function) :

// 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 *EAP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
    if opts.FixLengths {
        //e.Length = uint16(len(e.TypeData) + 1)
        e.Length = e.CalcLen() // bugfix : add + 4
    }
    size := len(e.TypeData) + 4
    if size > 4 {
        size++
    }
    bytes, err := b.PrependBytes(size)
    if err != nil {
        return err
    }
    bytes[0] = byte(e.Code)
    bytes[1] = e.Id
    binary.BigEndian.PutUint16(bytes[2:], e.Length)
    if size > 4 {
        bytes[4] = byte(e.Type)
        copy(bytes[5:], e.TypeData)
    }
    return nil
}

func (e *EAP) CalcLen() uint16 {
    return uint16(len(e.TypeData) + 1 + 4) // bugfix : add + 4
}

And I must call CalcLen() in my function :

func eapol_ResponseIdentity(handle *pcap.Handle, iface *net.Interface, id uint8, identity []byte) error {

    eap1 := layers.EAP{
        Code:     layers.EAPCodeResponse,
        Id:       id,
        Type:     layers.EAPTypeIdentity,
        TypeData: identity,
    }
    // I must call CalcLen() for update eap1.Length for
    // EAPOL layer. Is it possible to implemente a
    // a Length calculation for EAPOL layer when 
    // FixLengths = true ?
    eap1.Length = eap1.CalcLen() 

    eapol := layers.EAPOL{
        Version: 1,
        Type:    layers.EAPOLTypeEAP,
        Length:  eap1.Length,
    }

    eth := layers.Ethernet{
        SrcMAC:       iface.HardwareAddr,
        DstMAC:       net.HardwareAddr{0x01, 0x80, 0xc2, 0x00, 0x00, 0x03},
        EthernetType: layers.EthernetTypeEAPOL,
    }

    buf := gopacket.NewSerializeBuffer()
    opts := gopacket.SerializeOptions{
        FixLengths: true,
        ComputeChecksums: true,
    }

    gopacket.SerializeLayers(buf, opts, &eth, &eapol, &eap1)
    log.Printf("send EOPoL : Response Identity %v, %s...", id, string(identity))
    if err := handle.WritePacketData(buf.Bytes()); err != nil {
        log.Printf("Send err ", err)
        return err
    }
    //log.Printf("send packet [OK]")

    return nil
}

Someone can confirm that it is the best method ?

Is it possible to implemente auto calculate EAPOL field length ? (EAPOL field length = sum of EAP field lengths)