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  }