qingxp9
qingxp9

Reputation: 141

How to parse information element in 802.11 probe request frame with gopacket

Gopacket supports parsing information elements in beacon and probe response frames, like this:

for _, layer := range packet.Layers() {
    if layer.LayerType() == layers.LayerTypeDot11InformationElement {
        dot11info, ok := layer.(*layers.Dot11InformationElement)
        }
}

But gopacket doesn't support parsing information elements in probe request frame. I can only use packet.Layer(layers.LayerTypeDot11MgmtProbeReq).(*layers.Dot11MgmtProbeReq) to get the Contents and Payload, and the information elements are in this Contents.

So how can I parse these information elements in probe request frame?

Upvotes: 2

Views: 1142

Answers (2)

Patrick Jones
Patrick Jones

Reputation: 71

As a head's up, the reason that you can't just parse IEs from probe requests like you could from beacons or probe responses is because gopacket itself never actually assigns to the Payload field of the Dot11MgmtProbeReq struct. See DecodeFromBytes in Dot11MgmtBeacon and Dot11MgmtProbeResp; Dot11MgmtProbeReq has no such method. Replacing Dot11MgmtProbeReq from gopacket with the following code fixes this issue (although this may be overkill for you):

type Dot11MgmtProbeReq struct {
    Dot11Mgmt
}

func decodeDot11MgmtProbeReq(data []byte, p gopacket.PacketBuilder) error {
    d := &Dot11MgmtProbeReq{}
    return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtProbeReq) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtProbeReq }
func (m *Dot11MgmtProbeReq) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtProbeReq }
func (m *Dot11MgmtProbeReq) NextLayerType() gopacket.LayerType {
    return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtProbeReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
    m.Payload = data
    return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

One straightforward way to extract IEs in general is to set up a single core function to pass the list of IEs from the current frame into a function that decodes all relevant elements into a map[string][]byte where the string is a human-readable name for the string. That way, any frame-specific fields can be requested in their specific cases. (You need to write a map[layers.Dot11InformationElementID]string` to do this).

Upvotes: 2

Giulio Micheloni
Giulio Micheloni

Reputation: 1380

I believe you have to write yourself. Have you already tried this implementation?

The parser is the following:

func (pr *capturedRequest) decodeProbeRequestLayer(probeLayer *layers.Dot11MgmtProbeReq) {
    var body []byte
    body = probeLayer.LayerContents()
    for i := uint64(0); i < uint64(len(body)); {
        id := layers.Dot11InformationElementID(body[i])
        i++
        switch id {
        case layers.Dot11InformationElementIDSSID:
            elemLen := uint64(body[i])
            i++
            if elemLen > 0 {
                pr.SSID = string(body[i : i+elemLen])
                i += elemLen
            }
            break
        case layers.Dot11InformationElementIDVendor:
            pr.VendorSpecific = body[i+1:]
            return
        default:
            elemLen := uint64(body[i])
            i += 1 + elemLen
            break
        }
    }
}

Upvotes: 3

Related Questions