github.com/gopacket/gopacket@v1.1.0/layers/udp.go (about) 1 // 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 8 package layers 9 10 import ( 11 "encoding/binary" 12 "fmt" 13 14 "github.com/gopacket/gopacket" 15 ) 16 17 // UDP is the layer for UDP headers. 18 type 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 28 func (u *UDP) LayerType() gopacket.LayerType { return LayerTypeUDP } 29 30 func (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. 61 func (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 98 func (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. 105 func (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 112 func 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 123 func (u *UDP) TransportFlow() gopacket.Flow { 124 return gopacket.NewFlow(EndpointUDPPort, u.sPort, u.dPort) 125 } 126 127 // For testing only 128 func (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 }