123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- // Copyright 2012 Google, Inc. All rights reserved.
- // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
- //
- // Use of this source code is governed by a BSD-style license
- // that can be found in the LICENSE file in the root of the source
- // tree.
- package layers
- import (
- "encoding/binary"
- "fmt"
- "github.com/google/gopacket"
- )
- // UDP is the layer for UDP headers.
- type UDP struct {
- BaseLayer
- SrcPort, DstPort UDPPort
- Length uint16
- Checksum uint16
- sPort, dPort []byte
- tcpipchecksum
- }
- // LayerType returns gopacket.LayerTypeUDP
- func (u *UDP) LayerType() gopacket.LayerType { return LayerTypeUDP }
- func (udp *UDP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- if len(data) < 8 {
- df.SetTruncated()
- return fmt.Errorf("Invalid UDP header. Length %d less than 8", len(data))
- }
- udp.SrcPort = UDPPort(binary.BigEndian.Uint16(data[0:2]))
- udp.sPort = data[0:2]
- udp.DstPort = UDPPort(binary.BigEndian.Uint16(data[2:4]))
- udp.dPort = data[2:4]
- udp.Length = binary.BigEndian.Uint16(data[4:6])
- udp.Checksum = binary.BigEndian.Uint16(data[6:8])
- udp.BaseLayer = BaseLayer{Contents: data[:8]}
- switch {
- case udp.Length >= 8:
- hlen := int(udp.Length)
- if hlen > len(data) {
- df.SetTruncated()
- hlen = len(data)
- }
- udp.Payload = data[8:hlen]
- case udp.Length == 0: // Jumbogram, use entire rest of data
- udp.Payload = data[8:]
- default:
- return fmt.Errorf("UDP packet too small: %d bytes", udp.Length)
- }
- return nil
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (u *UDP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- var jumbo bool
- payload := b.Bytes()
- if _, ok := u.pseudoheader.(*IPv6); ok {
- if len(payload)+8 > 65535 {
- jumbo = true
- }
- }
- bytes, err := b.PrependBytes(8)
- if err != nil {
- return err
- }
- binary.BigEndian.PutUint16(bytes, uint16(u.SrcPort))
- binary.BigEndian.PutUint16(bytes[2:], uint16(u.DstPort))
- if opts.FixLengths {
- if jumbo {
- u.Length = 0
- } else {
- u.Length = uint16(len(payload)) + 8
- }
- }
- binary.BigEndian.PutUint16(bytes[4:], u.Length)
- if opts.ComputeChecksums {
- // zero out checksum bytes
- bytes[6] = 0
- bytes[7] = 0
- csum, err := u.computeChecksum(b.Bytes(), IPProtocolUDP)
- if err != nil {
- return err
- }
- u.Checksum = csum
- }
- binary.BigEndian.PutUint16(bytes[6:], u.Checksum)
- return nil
- }
- func (u *UDP) CanDecode() gopacket.LayerClass {
- return LayerTypeUDP
- }
- // NextLayerType use the destination port to select the
- // right next decoder. It tries first to decode via the
- // destination port, then the source port.
- func (u *UDP) NextLayerType() gopacket.LayerType {
- if lt := u.DstPort.LayerType(); lt != gopacket.LayerTypePayload {
- return lt
- }
- return u.SrcPort.LayerType()
- }
- func decodeUDP(data []byte, p gopacket.PacketBuilder) error {
- udp := &UDP{}
- err := udp.DecodeFromBytes(data, p)
- p.AddLayer(udp)
- p.SetTransportLayer(udp)
- if err != nil {
- return err
- }
- return p.NextDecoder(udp.NextLayerType())
- }
- func (u *UDP) TransportFlow() gopacket.Flow {
- return gopacket.NewFlow(EndpointUDPPort, u.sPort, u.dPort)
- }
- // For testing only
- func (u *UDP) SetInternalPortsForTesting() {
- u.sPort = make([]byte, 2)
- u.dPort = make([]byte, 2)
- binary.BigEndian.PutUint16(u.sPort, uint16(u.SrcPort))
- binary.BigEndian.PutUint16(u.dPort, uint16(u.DstPort))
- }
|