blob: 5d303dc4a786e0e17258295d5bbbda97c78c78e6 [file] [log] [blame]
Andrea Campanella7167ebb2020-02-24 09:56:38 +01001// Copyright 2012 Google, Inc. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the LICENSE file in the root of the source
5// tree.
6
7package gopacket
8
9import (
10 "fmt"
11)
12
13// SerializableLayer allows its implementations to be written out as a set of bytes,
14// so those bytes may be sent on the wire or otherwise used by the caller.
15// SerializableLayer is implemented by certain Layer types, and can be encoded to
16// bytes using the LayerWriter object.
17type SerializableLayer interface {
18 // SerializeTo writes this layer to a slice, growing that slice if necessary
19 // to make it fit the layer's data.
20 // Args:
21 // b: SerializeBuffer to write this layer on to. When called, b.Bytes()
22 // is the payload this layer should wrap, if any. Note that this
23 // layer can either prepend itself (common), append itself
24 // (uncommon), or both (sometimes padding or footers are required at
25 // the end of packet data). It's also possible (though probably very
26 // rarely needed) to overwrite any bytes in the current payload.
27 // After this call, b.Bytes() should return the byte encoding of
28 // this layer wrapping the original b.Bytes() payload.
29 // opts: options to use while writing out data.
30 // Returns:
31 // error if a problem was encountered during encoding. If an error is
32 // returned, the bytes in data should be considered invalidated, and
33 // not used.
34 //
35 // SerializeTo calls SHOULD entirely ignore LayerContents and
36 // LayerPayload. It just serializes based on struct fields, neither
37 // modifying nor using contents/payload.
38 SerializeTo(b SerializeBuffer, opts SerializeOptions) error
39 // LayerType returns the type of the layer that is being serialized to the buffer
40 LayerType() LayerType
41}
42
43// SerializeOptions provides options for behaviors that SerializableLayers may want to
44// implement.
45type SerializeOptions struct {
46 // FixLengths determines whether, during serialization, layers should fix
47 // the values for any length field that depends on the payload.
48 FixLengths bool
49 // ComputeChecksums determines whether, during serialization, layers
50 // should recompute checksums based on their payloads.
51 ComputeChecksums bool
52}
53
54// SerializeBuffer is a helper used by gopacket for writing out packet layers.
55// SerializeBuffer starts off as an empty []byte. Subsequent calls to PrependBytes
56// return byte slices before the current Bytes(), AppendBytes returns byte
57// slices after.
58//
59// Byte slices returned by PrependBytes/AppendBytes are NOT zero'd out, so if
60// you want to make sure they're all zeros, set them as such.
61//
62// SerializeBuffer is specifically designed to handle packet writing, where unlike
63// with normal writes it's easier to start writing at the inner-most layer and
64// work out, meaning that we often need to prepend bytes. This runs counter to
65// typical writes to byte slices using append(), where we only write at the end
66// of the buffer.
67//
68// It can be reused via Clear. Note, however, that a Clear call will invalidate the
69// byte slices returned by any previous Bytes() call (the same buffer is
70// reused).
71//
72// 1) Reusing a write buffer is generally much faster than creating a new one,
73// and with the default implementation it avoids additional memory allocations.
74// 2) If a byte slice from a previous Bytes() call will continue to be used,
75// it's better to create a new SerializeBuffer.
76//
77// The Clear method is specifically designed to minimize memory allocations for
78// similar later workloads on the SerializeBuffer. IE: if you make a set of
79// Prepend/Append calls, then clear, then make the same calls with the same
80// sizes, the second round (and all future similar rounds) shouldn't allocate
81// any new memory.
82type SerializeBuffer interface {
83 // Bytes returns the contiguous set of bytes collected so far by Prepend/Append
84 // calls. The slice returned by Bytes will be modified by future Clear calls,
85 // so if you're planning on clearing this SerializeBuffer, you may want to copy
86 // Bytes somewhere safe first.
87 Bytes() []byte
88 // PrependBytes returns a set of bytes which prepends the current bytes in this
89 // buffer. These bytes start in an indeterminate state, so they should be
90 // overwritten by the caller. The caller must only call PrependBytes if they
91 // know they're going to immediately overwrite all bytes returned.
92 PrependBytes(num int) ([]byte, error)
93 // AppendBytes returns a set of bytes which appends the current bytes in this
94 // buffer. These bytes start in an indeterminate state, so they should be
95 // overwritten by the caller. The caller must only call AppendBytes if they
96 // know they're going to immediately overwrite all bytes returned.
97 AppendBytes(num int) ([]byte, error)
98 // Clear resets the SerializeBuffer to a new, empty buffer. After a call to clear,
99 // the byte slice returned by any previous call to Bytes() for this buffer
100 // should be considered invalidated.
101 Clear() error
102 // Layers returns all the Layers that have been successfully serialized into this buffer
103 // already.
104 Layers() []LayerType
105 // PushLayer adds the current Layer to the list of Layers that have been serialized
106 // into this buffer.
107 PushLayer(LayerType)
108}
109
110type serializeBuffer struct {
111 data []byte
112 start int
113 prepended, appended int
114 layers []LayerType
115}
116
117// NewSerializeBuffer creates a new instance of the default implementation of
118// the SerializeBuffer interface.
119func NewSerializeBuffer() SerializeBuffer {
120 return &serializeBuffer{}
121}
122
123// NewSerializeBufferExpectedSize creates a new buffer for serialization, optimized for an
124// expected number of bytes prepended/appended. This tends to decrease the
125// number of memory allocations made by the buffer during writes.
126func NewSerializeBufferExpectedSize(expectedPrependLength, expectedAppendLength int) SerializeBuffer {
127 return &serializeBuffer{
128 data: make([]byte, expectedPrependLength, expectedPrependLength+expectedAppendLength),
129 start: expectedPrependLength,
130 prepended: expectedPrependLength,
131 appended: expectedAppendLength,
132 }
133}
134
135func (w *serializeBuffer) Bytes() []byte {
136 return w.data[w.start:]
137}
138
139func (w *serializeBuffer) PrependBytes(num int) ([]byte, error) {
140 if num < 0 {
141 panic("num < 0")
142 }
143 if w.start < num {
144 toPrepend := w.prepended
145 if toPrepend < num {
146 toPrepend = num
147 }
148 w.prepended += toPrepend
149 length := cap(w.data) + toPrepend
150 newData := make([]byte, length)
151 newStart := w.start + toPrepend
152 copy(newData[newStart:], w.data[w.start:])
153 w.start = newStart
154 w.data = newData[:toPrepend+len(w.data)]
155 }
156 w.start -= num
157 return w.data[w.start : w.start+num], nil
158}
159
160func (w *serializeBuffer) AppendBytes(num int) ([]byte, error) {
161 if num < 0 {
162 panic("num < 0")
163 }
164 initialLength := len(w.data)
165 if cap(w.data)-initialLength < num {
166 toAppend := w.appended
167 if toAppend < num {
168 toAppend = num
169 }
170 w.appended += toAppend
171 newData := make([]byte, cap(w.data)+toAppend)
172 copy(newData[w.start:], w.data[w.start:])
173 w.data = newData[:initialLength]
174 }
175 // Grow the buffer. We know it'll be under capacity given above.
176 w.data = w.data[:initialLength+num]
177 return w.data[initialLength:], nil
178}
179
180func (w *serializeBuffer) Clear() error {
181 w.start = w.prepended
182 w.data = w.data[:w.start]
183 w.layers = w.layers[:0]
184 return nil
185}
186
187func (w *serializeBuffer) Layers() []LayerType {
188 return w.layers
189}
190
191func (w *serializeBuffer) PushLayer(l LayerType) {
192 w.layers = append(w.layers, l)
193}
194
195// SerializeLayers clears the given write buffer, then writes all layers into it so
196// they correctly wrap each other. Note that by clearing the buffer, it
197// invalidates all slices previously returned by w.Bytes()
198//
199// Example:
200// buf := gopacket.NewSerializeBuffer()
201// opts := gopacket.SerializeOptions{}
202// gopacket.SerializeLayers(buf, opts, a, b, c)
203// firstPayload := buf.Bytes() // contains byte representation of a(b(c))
204// gopacket.SerializeLayers(buf, opts, d, e, f)
205// secondPayload := buf.Bytes() // contains byte representation of d(e(f)). firstPayload is now invalidated, since the SerializeLayers call Clears buf.
206func SerializeLayers(w SerializeBuffer, opts SerializeOptions, layers ...SerializableLayer) error {
207 w.Clear()
208 for i := len(layers) - 1; i >= 0; i-- {
209 layer := layers[i]
210 err := layer.SerializeTo(w, opts)
211 if err != nil {
212 return err
213 }
214 w.PushLayer(layer.LayerType())
215 }
216 return nil
217}
218
219// SerializePacket is a convenience function that calls SerializeLayers
220// on packet's Layers().
221// It returns an error if one of the packet layers is not a SerializableLayer.
222func SerializePacket(buf SerializeBuffer, opts SerializeOptions, packet Packet) error {
223 sls := []SerializableLayer{}
224 for _, layer := range packet.Layers() {
225 sl, ok := layer.(SerializableLayer)
226 if !ok {
227 return fmt.Errorf("layer %s is not serializable", layer.LayerType().String())
228 }
229 sls = append(sls, sl)
230 }
231 return SerializeLayers(buf, opts, sls...)
232}