blob: 97e81c69fccba3fa944db8fe1ca31a8714e67b34 [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// Copyright 2012 Google, Inc. All rights reserved.
2// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
3//
4// Use of this source code is governed by a BSD-style license
5// that can be found in the LICENSE file in the root of the source
6// tree.
7
8package layers
9
10import (
11 "encoding/binary"
12 "fmt"
13
14 "github.com/google/gopacket"
15)
16
17// UDP is the layer for UDP headers.
18type UDP struct {
19 BaseLayer
20 SrcPort, DstPort UDPPort
21 Length uint16
22 Checksum uint16
23 sPort, dPort []byte
24 tcpipchecksum
25}
26
27// LayerType returns gopacket.LayerTypeUDP
28func (u *UDP) LayerType() gopacket.LayerType { return LayerTypeUDP }
29
30func (udp *UDP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
31 if len(data) < 8 {
32 df.SetTruncated()
33 return fmt.Errorf("Invalid UDP header. Length %d less than 8", len(data))
34 }
35 udp.SrcPort = UDPPort(binary.BigEndian.Uint16(data[0:2]))
36 udp.sPort = data[0:2]
37 udp.DstPort = UDPPort(binary.BigEndian.Uint16(data[2:4]))
38 udp.dPort = data[2:4]
39 udp.Length = binary.BigEndian.Uint16(data[4:6])
40 udp.Checksum = binary.BigEndian.Uint16(data[6:8])
41 udp.BaseLayer = BaseLayer{Contents: data[:8]}
42 switch {
43 case udp.Length >= 8:
44 hlen := int(udp.Length)
45 if hlen > len(data) {
46 df.SetTruncated()
47 hlen = len(data)
48 }
49 udp.Payload = data[8:hlen]
50 case udp.Length == 0: // Jumbogram, use entire rest of data
51 udp.Payload = data[8:]
52 default:
53 return fmt.Errorf("UDP packet too small: %d bytes", udp.Length)
54 }
55 return nil
56}
57
58// SerializeTo writes the serialized form of this layer into the
59// SerializationBuffer, implementing gopacket.SerializableLayer.
60// See the docs for gopacket.SerializableLayer for more info.
61func (u *UDP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
62 var jumbo bool
63
64 payload := b.Bytes()
65 if _, ok := u.pseudoheader.(*IPv6); ok {
66 if len(payload)+8 > 65535 {
67 jumbo = true
68 }
69 }
70 bytes, err := b.PrependBytes(8)
71 if err != nil {
72 return err
73 }
74 binary.BigEndian.PutUint16(bytes, uint16(u.SrcPort))
75 binary.BigEndian.PutUint16(bytes[2:], uint16(u.DstPort))
76 if opts.FixLengths {
77 if jumbo {
78 u.Length = 0
79 } else {
80 u.Length = uint16(len(payload)) + 8
81 }
82 }
83 binary.BigEndian.PutUint16(bytes[4:], u.Length)
84 if opts.ComputeChecksums {
85 // zero out checksum bytes
86 bytes[6] = 0
87 bytes[7] = 0
88 csum, err := u.computeChecksum(b.Bytes(), IPProtocolUDP)
89 if err != nil {
90 return err
91 }
92 u.Checksum = csum
93 }
94 binary.BigEndian.PutUint16(bytes[6:], u.Checksum)
95 return nil
96}
97
98func (u *UDP) CanDecode() gopacket.LayerClass {
99 return LayerTypeUDP
100}
101
102// NextLayerType use the destination port to select the
103// right next decoder. It tries first to decode via the
104// destination port, then the source port.
105func (u *UDP) NextLayerType() gopacket.LayerType {
106 if lt := u.DstPort.LayerType(); lt != gopacket.LayerTypePayload {
107 return lt
108 }
109 return u.SrcPort.LayerType()
110}
111
112func decodeUDP(data []byte, p gopacket.PacketBuilder) error {
113 udp := &UDP{}
114 err := udp.DecodeFromBytes(data, p)
115 p.AddLayer(udp)
116 p.SetTransportLayer(udp)
117 if err != nil {
118 return err
119 }
120 return p.NextDecoder(udp.NextLayerType())
121}
122
123func (u *UDP) TransportFlow() gopacket.Flow {
124 return gopacket.NewFlow(EndpointUDPPort, u.sPort, u.dPort)
125}
126
127// For testing only
128func (u *UDP) SetInternalPortsForTesting() {
129 u.sPort = make([]byte, 2)
130 u.dPort = make([]byte, 2)
131 binary.BigEndian.PutUint16(u.sPort, uint16(u.SrcPort))
132 binary.BigEndian.PutUint16(u.dPort, uint16(u.DstPort))
133}