1

I am writing custom layer decoders with gopacket.

LayerA contains a field Type that can be one of the following values:

  • B-only, the next layer is LayerB, followed by a raw payload
  • C-only, the next layer is LayerC, followed by a raw payload
  • B-C, the next layer is LayerB, followed by LayerC then a raw payload

There is no field in LayerB that can be used to know if LayerC is the next or not. LayerB and LayerC decoding does not depend on whenever the other layer is present or not.

What would be the proper way to write the decode function of LayerA, since it's the one that knows what are the next layers?

There is not a lot of tutorials about custom layers with gopacket, and this case is not like the basic ones covered there.

It seems the logic should be put in LayerA decoding function, just before calling p.NextDecoder.

I thought of two ways to achieve this:

1. Use a closure

Add a field nextDecoder Decoder to the struct LayerB. In the decoder of LayerA, when Type is C-only, simply use the decoder of LayerC. Otherwise, create a struct LayerB and fill the field nextDecoder accordingly. Then use this struct in a closure, that will be used as the next decoder.

Issues

The decoding logic of LayerB would be in the LayerA decoding function (see code in Palyground below). Moreover, which decoding function to use when registering the LayerB with gopacket.RegisterLayer?

2. Have two separate layers LayerB-C and LayerB-only

LayerB-C next decoder would be LayerC's, LayerB-only's would be just the payload layer.

Issues

The decoding function of LayerB-only and LayerB-C is the same, expect the call the p.NextDecoder. Since there is no notion of 'inheritance' in go, I am not sure how to design this to avoid duplication. Maybe create a LayerB-base interface with a function nextDecoder() LayerType, and make LayerB-C and LayerB-only implement it? Or embed a type LayerB-base that has a function Decode? But neither of them doesn't feel right.

Code

Here is some code for each described way: https://play.golang.org/p/N9ZpYqFb16Q. The actual content of the layers are not relevant, except LayerA.Type.

The result of this code is as expected but I would like to know if there is a better or more idiomatic to do it.

anonom
  • 125
  • 11
  • 1
    It sounds a lot like you're describing a system where the payload belongs to `LayerA`, with `LayerB` and `LayerC` being optional headers for that layer rather than new levels of encapsulation. That might just be due to the simplified version of the problem you've presented here though. – James Henstridge Jul 06 '19 at 08:10
  • Hi @JamesHenstridge, ah yes it makes sense to see them as optional headers! I think it's the case, since it's `LayerA` only that knows about their presence. Thank you, it will simplify the structure! – anonom Jul 08 '19 at 23:02

1 Answers1

0

You can do this by declaring the next layer to be an interface, which could support either B or C. As long as whatever you declare fits as a LayerType, this should work fine.