google / gopacket

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

question: TLS example #687

Open detailyang opened 5 years ago

detailyang commented 5 years ago

Hello. I see the TLS layer has merged to master but there is no example to reference.

It would be good if gopacket provides the TLS example.

Many thanks:)

xhdix commented 5 years ago

I used the method available at https://github.com/google/gopacket/blob/master/layers/tls_test.go. But it didn't work.

    if tls, ok := p.Layer(layers.LayerTypeTLS).(*layers.TLS); ok {
        fmt.Printf("work: ", tls)
    } else {
        t.Error("doesn't work -- No TLS layer type found in packet")
    }

Returns nil for all packets (TLS).

xhdix commented 5 years ago

@jselvi & @gconnell Have you tried it with a real packet before?

spitfire55 commented 5 years ago

UPDATE: See comment below for automatically decoding TLS from a PacketSource

Can confirm that live packet capture doesn't automatically decode TLS layers. Right now, I have to manually decode it w/ the following code:


if packet.ApplicationLayer() != nil {
            var tls layers.TLS
            var decoded []gopacket.LayerType
            parser := gopacket.NewDecodingLayerParser(layers.LayerTypeTLS, &tls)
            err := parser.DecodeLayers(packet.ApplicationLayer().LayerContents(), &decoded); if err != nil {
                return
            }
            for _, layerType := range decoded {
                switch layerType {
                case layers.LayerTypeTLS:
                    // do things with tls variable
                }
            }
        }
jselvi commented 5 years ago

I contributed with this layer because I needed it for my tool. You can see a basic example on in: https://github.com/jselvi/fiesta/blob/master/pkg/tlsrelay/tls.go#L28 In this tool, it has been working perfectly.

I implemented this some time ago and I can't remember the details, but I tried to mimic the decisions that were taken in other layers, so you shouldn't see a different behaviour.

xhdix commented 5 years ago

@jselvi Thanks But It only works when you use NewPacket(). It doesn't work even when you use OpenOffline()

spitfire55 commented 5 years ago

So I identified why this behavior is occuring. If you want to automatically decode TLS layers from a packet source (pcap or handle), you need to set DecodeStreamsAsDatagrams to true. Otherwise, if this is false, tcp.go simply sets all TCP payloads as LayerTypePayload.

As explained by the documentation for DecodeStreamsAsDatagrams:

// DecodeStreamsAsDatagrams enables routing of application-level layers in the TCP
// decoder. If true, we should try to decode layers after TCP in single packets.
// This is disabled by default because the reassembly package drives the decoding
// of TCP payload data after reassembly.

And the relevant lines of code from tcp.go:

func decodeTCP(data []byte, p gopacket.PacketBuilder) error {
    tcp := &TCP{}
    err := tcp.DecodeFromBytes(data, p)
    p.AddLayer(tcp)
    p.SetTransportLayer(tcp)
    if err != nil {
        return err
    }
    if p.DecodeOptions().DecodeStreamsAsDatagrams {
        return p.NextDecoder(tcp.NextLayerType())
    } else {
        return p.NextDecoder(gopacket.LayerTypePayload)
    }
}
jselvi commented 5 years ago

Oh, I see. But this is something that should happen with every application layer, not only TLS. I understood that this was a problem not happening when decoding packet containing an application layer other than TLS.

Btw, that flag is set to true in the tests: https://github.com/google/gopacket/blob/2d7fab0d91d6bb77c1df6bdeb222270a2aa13820/layers/tls_test.go#L224

Thanks @spitfire55 !

notti commented 5 years ago

So I identified why this behavior is occuring. If you want to automatically decode TLS layers from a packet source (pcap or handle), you need to set DecodeStreamsAsDatagrams to true. Otherwise, if this is false, tcp.go simply sets all TCP payloads as LayerTypePayload.

Oh, I see. But this is something that should happen with every application layer, not only TLS. I understood that this was a problem not happening when decoding packet containing an application layer other than TLS.

The reason for this is that TCP carries a stream of data and not datagrams. This means that single TCP packets do not generally carry single payloads. E.g., for TLS, if you're lucky one TCP packet will contain a single TLS record - but in many cases one TCP packet will contain:

So the correct way to go about this would be to use reassembly, and then pull the tls records out of the reassembled stream. This problem also exists for the other TCP payloads and is the reason why #587 and #584 are not yet implemented (we don't have some kind of mechanism to somehow mix reassembly and packets, and a mechanism for implementing stream based protocols that can consume a reassembled stream). TLS and modbus shouldn't have been merged this way - sorry for the confusion.