7
7
package quic
8
8
9
9
import (
10
+ "encoding/binary"
10
11
"net"
11
12
"net/netip"
12
13
"sync"
@@ -141,15 +142,11 @@ func parseControl(d *datagram, control []byte) {
141
142
case unix .IPPROTO_IP :
142
143
switch hdr .Type {
143
144
case unix .IP_TOS , unix .IP_RECVTOS :
144
- // Single byte containing the IP TOS field.
145
- // The low two bits are the ECN field.
146
- //
147
145
// (Linux sets the type to IP_TOS, Darwin to IP_RECVTOS,
148
- // jus check for both.)
149
- if len (data ) < 1 {
150
- break
146
+ // just check for both.)
147
+ if ecn , ok := parseIPTOS (data ); ok {
148
+ d . ecn = ecn
151
149
}
152
- d .ecn = ecnBits (data [0 ] & ecnMask )
153
150
case unix .IP_PKTINFO :
154
151
if a , ok := parseInPktinfo (data ); ok {
155
152
d .localAddr = netip .AddrPortFrom (a , d .localAddr .Port ())
@@ -158,12 +155,11 @@ func parseControl(d *datagram, control []byte) {
158
155
case unix .IPPROTO_IPV6 :
159
156
switch hdr .Type {
160
157
case unix .IPV6_TCLASS :
161
- // Single byte containing the traffic class field.
158
+ // 32-bit integer containing the traffic class field.
162
159
// The low two bits are the ECN field.
163
- if len (data ) < 1 {
164
- break
160
+ if ecn , ok := parseIPv6TCLASS (data ); ok {
161
+ d . ecn = ecn
165
162
}
166
- d .ecn = ecnBits (data [0 ] & ecnMask )
167
163
case unix .IPV6_PKTINFO :
168
164
if a , ok := parseIn6Pktinfo (data ); ok {
169
165
d .localAddr = netip .AddrPortFrom (a , d .localAddr .Port ())
@@ -173,27 +169,33 @@ func parseControl(d *datagram, control []byte) {
173
169
}
174
170
}
175
171
176
- func parseInPktinfo (b []byte ) (netip.Addr , bool ) {
177
- // struct in_pktinfo {
178
- // unsigned int ipi_ifindex; /* send/recv interface index */
179
- // struct in_addr ipi_spec_dst; /* Local address */
180
- // struct in_addr ipi_addr; /* IP Header dst address */
181
- // };
182
- if len (b ) != 12 {
183
- return netip.Addr {}, false
172
+ // IPV6_TCLASS is specified by RFC 3542 as an int.
173
+
174
+ func parseIPv6TCLASS (b []byte ) (ecnBits , bool ) {
175
+ if len (b ) != 4 {
176
+ return 0 , false
184
177
}
185
- return netip . AddrFrom4 ([ 4 ] byte ( b [ 8 :][: 4 ]) ), true
178
+ return ecnBits ( binary . NativeEndian . Uint32 ( b ) & ecnMask ), true
186
179
}
187
180
188
- func parseIn6Pktinfo (b []byte ) (netip.Addr , bool ) {
189
- // struct in6_pktinfo {
190
- // struct in6_addr ipi6_addr; /* src/dst IPv6 address */
191
- // unsigned int ipi6_ifindex; /* send/recv interface index */
192
- // };
193
- if len (b ) != 20 {
181
+ func appendCmsgECNv6 (b []byte , ecn ecnBits ) []byte {
182
+ b , data := appendCmsg (b , unix .IPPROTO_IPV6 , unix .IPV6_TCLASS , 4 )
183
+ binary .NativeEndian .PutUint32 (data , uint32 (ecn ))
184
+ return b
185
+ }
186
+
187
+ // struct in_pktinfo {
188
+ // unsigned int ipi_ifindex; /* send/recv interface index */
189
+ // struct in_addr ipi_spec_dst; /* Local address */
190
+ // struct in_addr ipi_addr; /* IP Header dst address */
191
+ // };
192
+
193
+ // parseInPktinfo returns the destination address from an IP_PKTINFO.
194
+ func parseInPktinfo (b []byte ) (dst netip.Addr , ok bool ) {
195
+ if len (b ) != 12 {
194
196
return netip.Addr {}, false
195
197
}
196
- return netip .AddrFrom16 ([ 16 ]byte (b [: 16 ])). Unmap ( ), true
198
+ return netip .AddrFrom4 ([ 4 ]byte (b [8 :][: 4 ]) ), true
197
199
}
198
200
199
201
// appendCmsgIPSourceAddrV4 appends an IP_PKTINFO setting the source address
@@ -210,31 +212,28 @@ func appendCmsgIPSourceAddrV4(b []byte, src netip.Addr) []byte {
210
212
return b
211
213
}
212
214
213
- // appendCmsgIPSourceAddrV6 appends an IP_PKTINFO or IPV6_PKTINFO
214
- // setting the source address for an outbound datagram.
215
+ // struct in6_pktinfo {
216
+ // struct in6_addr ipi6_addr; /* src/dst IPv6 address */
217
+ // unsigned int ipi6_ifindex; /* send/recv interface index */
218
+ // };
219
+
220
+ // parseIn6Pktinfo returns the destination address from an IPV6_PKTINFO.
221
+ func parseIn6Pktinfo (b []byte ) (netip.Addr , bool ) {
222
+ if len (b ) != 20 {
223
+ return netip.Addr {}, false
224
+ }
225
+ return netip .AddrFrom16 ([16 ]byte (b [:16 ])).Unmap (), true
226
+ }
227
+
228
+ // appendCmsgIPSourceAddrV6 appends an IPV6_PKTINFO setting the source address
229
+ // for an outbound datagram.
215
230
func appendCmsgIPSourceAddrV6 (b []byte , src netip.Addr ) []byte {
216
- // struct in6_pktinfo {
217
- // struct in6_addr ipi6_addr; /* src/dst IPv6 address */
218
- // unsigned int ipi6_ifindex; /* send/recv interface index */
219
- // };
220
231
b , data := appendCmsg (b , unix .IPPROTO_IPV6 , unix .IPV6_PKTINFO , 20 )
221
232
ip := src .As16 ()
222
233
copy (data [0 :], ip [:])
223
234
return b
224
235
}
225
236
226
- func appendCmsgECNv4 (b []byte , ecn ecnBits ) []byte {
227
- b , data := appendCmsg (b , unix .IPPROTO_IP , unix .IP_TOS , 4 )
228
- data [0 ] = byte (ecn )
229
- return b
230
- }
231
-
232
- func appendCmsgECNv6 (b []byte , ecn ecnBits ) []byte {
233
- b , data := appendCmsg (b , unix .IPPROTO_IPV6 , unix .IPV6_TCLASS , 4 )
234
- data [0 ] = byte (ecn )
235
- return b
236
- }
237
-
238
237
// appendCmsg appends a cmsg with the given level, type, and size to b.
239
238
// It returns the new buffer, and the data section of the cmsg.
240
239
func appendCmsg (b []byte , level , typ int32 , size int ) (_ , data []byte ) {
0 commit comments