1 // Copyright 2018 The gVisor Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 15 package header
16 17 import (
18 "encoding/binary"
19 "math"
20 21 "gvisor.dev/gvisor/pkg/tcpip"
22 "gvisor.dev/gvisor/pkg/tcpip/checksum"
23 )
24 25 const (
26 udpSrcPort = 0
27 udpDstPort = 2
28 udpLength = 4
29 udpChecksum = 6
30 )
31 32 const (
33 // UDPMaximumPacketSize is the largest possible UDP packet.
34 UDPMaximumPacketSize = 0xffff
35 )
36 37 // UDPFields contains the fields of a UDP packet. It is used to describe the
38 // fields of a packet that needs to be encoded.
39 type UDPFields struct {
40 // SrcPort is the "source port" field of a UDP packet.
41 SrcPort uint16
42 43 // DstPort is the "destination port" field of a UDP packet.
44 DstPort uint16
45 46 // Length is the "length" field of a UDP packet.
47 Length uint16
48 49 // Checksum is the "checksum" field of a UDP packet.
50 Checksum uint16
51 }
52 53 // UDP represents a UDP header stored in a byte array.
54 type UDP []byte
55 56 const (
57 // UDPMinimumSize is the minimum size of a valid UDP packet.
58 UDPMinimumSize = 8
59 60 // UDPMaximumSize is the maximum size of a valid UDP packet. The length field
61 // in the UDP header is 16 bits as per RFC 768.
62 UDPMaximumSize = math.MaxUint16
63 64 // UDPProtocolNumber is UDP's transport protocol number.
65 UDPProtocolNumber tcpip.TransportProtocolNumber = 17
66 )
67 68 // SourcePort returns the "source port" field of the UDP header.
69 func (b UDP) SourcePort() uint16 {
70 return binary.BigEndian.Uint16(b[udpSrcPort:])
71 }
72 73 // DestinationPort returns the "destination port" field of the UDP header.
74 func (b UDP) DestinationPort() uint16 {
75 return binary.BigEndian.Uint16(b[udpDstPort:])
76 }
77 78 // Length returns the "length" field of the UDP header.
79 func (b UDP) Length() uint16 {
80 return binary.BigEndian.Uint16(b[udpLength:])
81 }
82 83 // Payload returns the data contained in the UDP datagram.
84 func (b UDP) Payload() []byte {
85 return b[UDPMinimumSize:]
86 }
87 88 // Checksum returns the "checksum" field of the UDP header.
89 func (b UDP) Checksum() uint16 {
90 return binary.BigEndian.Uint16(b[udpChecksum:])
91 }
92 93 // SetSourcePort sets the "source port" field of the UDP header.
94 func (b UDP) SetSourcePort(port uint16) {
95 binary.BigEndian.PutUint16(b[udpSrcPort:], port)
96 }
97 98 // SetDestinationPort sets the "destination port" field of the UDP header.
99 func (b UDP) SetDestinationPort(port uint16) {
100 binary.BigEndian.PutUint16(b[udpDstPort:], port)
101 }
102 103 // SetChecksum sets the "checksum" field of the UDP header.
104 func (b UDP) SetChecksum(xsum uint16) {
105 checksum.Put(b[udpChecksum:], xsum)
106 }
107 108 // SetLength sets the "length" field of the UDP header.
109 func (b UDP) SetLength(length uint16) {
110 binary.BigEndian.PutUint16(b[udpLength:], length)
111 }
112 113 // CalculateChecksum calculates the checksum of the UDP packet, given the
114 // checksum of the network-layer pseudo-header and the checksum of the payload.
115 func (b UDP) CalculateChecksum(partialChecksum uint16) uint16 {
116 // Calculate the rest of the checksum.
117 return checksum.Checksum(b[:UDPMinimumSize], partialChecksum)
118 }
119 120 // IsChecksumValid returns true iff the UDP header's checksum is valid.
121 func (b UDP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum uint16) bool {
122 xsum := PseudoHeaderChecksum(UDPProtocolNumber, dst, src, b.Length())
123 xsum = checksum.Combine(xsum, payloadChecksum)
124 return b.CalculateChecksum(xsum) == 0xffff
125 }
126 127 // Encode encodes all the fields of the UDP header.
128 func (b UDP) Encode(u *UDPFields) {
129 b.SetSourcePort(u.SrcPort)
130 b.SetDestinationPort(u.DstPort)
131 b.SetLength(u.Length)
132 b.SetChecksum(u.Checksum)
133 }
134 135 // SetSourcePortWithChecksumUpdate implements ChecksummableTransport.
136 func (b UDP) SetSourcePortWithChecksumUpdate(new uint16) {
137 old := b.SourcePort()
138 b.SetSourcePort(new)
139 b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
140 }
141 142 // SetDestinationPortWithChecksumUpdate implements ChecksummableTransport.
143 func (b UDP) SetDestinationPortWithChecksumUpdate(new uint16) {
144 old := b.DestinationPort()
145 b.SetDestinationPort(new)
146 b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
147 }
148 149 // UpdateChecksumPseudoHeaderAddress implements ChecksummableTransport.
150 func (b UDP) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullChecksum bool) {
151 xsum := b.Checksum()
152 if fullChecksum {
153 xsum = ^xsum
154 }
155 156 xsum = checksumUpdate2ByteAlignedAddress(xsum, old, new)
157 if fullChecksum {
158 xsum = ^xsum
159 }
160 161 b.SetChecksum(xsum)
162 }
163 164 // UDPValid returns true if the pkt has a valid UDP header. It checks whether:
165 // - The length field is too small.
166 // - The length field is too large.
167 // - The checksum is invalid.
168 //
169 // UDPValid corresponds to net/netfilter/nf_conntrack_proto_udp.c:udp_error.
170 func UDPValid(hdr UDP, payloadChecksum func() uint16, payloadSize uint16, netProto tcpip.NetworkProtocolNumber, srcAddr, dstAddr tcpip.Address, skipChecksumValidation bool) (lengthValid, csumValid bool) {
171 if length := hdr.Length(); length > payloadSize+UDPMinimumSize || length < UDPMinimumSize {
172 return false, false
173 }
174 175 if skipChecksumValidation {
176 return true, true
177 }
178 179 // On IPv4, UDP checksum is optional, and a zero value means the transmitter
180 // omitted the checksum generation, as per RFC 768:
181 //
182 // An all zero transmitted checksum value means that the transmitter
183 // generated no checksum (for debugging or for higher level protocols that
184 // don't care).
185 //
186 // On IPv6, UDP checksum is not optional, as per RFC 2460 Section 8.1:
187 //
188 // Unlike IPv4, when UDP packets are originated by an IPv6 node, the UDP
189 // checksum is not optional.
190 if netProto == IPv4ProtocolNumber && hdr.Checksum() == 0 {
191 return true, true
192 }
193 194 return true, hdr.IsChecksumValid(srcAddr, dstAddr, payloadChecksum())
195 }
196