@@ -22,12 +22,16 @@ const minFrag = 60 + 20 // max IPv4 header + basic TCP header
22
22
type TCPFlag uint8
23
23
24
24
const (
25
- TCPFin TCPFlag = 0x01
26
- TCPSyn TCPFlag = 0x02
27
- TCPRst TCPFlag = 0x04
28
- TCPPsh TCPFlag = 0x08
29
- TCPAck TCPFlag = 0x10
30
- TCPSynAck TCPFlag = TCPSyn | TCPAck
25
+ TCPFin TCPFlag = 0x01
26
+ TCPSyn TCPFlag = 0x02
27
+ TCPRst TCPFlag = 0x04
28
+ TCPPsh TCPFlag = 0x08
29
+ TCPAck TCPFlag = 0x10
30
+ TCPUrg TCPFlag = 0x20
31
+ TCPECNEcho TCPFlag = 0x40
32
+ TCPCWR TCPFlag = 0x80
33
+ TCPSynAck TCPFlag = TCPSyn | TCPAck
34
+ TCPECNBits TCPFlag = TCPECNEcho | TCPCWR
31
35
)
32
36
33
37
// Parsed is a minimal decoding of a packet suitable for use in filters.
@@ -180,7 +184,7 @@ func (q *Parsed) decode4(b []byte) {
180
184
}
181
185
q .Src = q .Src .WithPort (binary .BigEndian .Uint16 (sub [0 :2 ]))
182
186
q .Dst = q .Dst .WithPort (binary .BigEndian .Uint16 (sub [2 :4 ]))
183
- q .TCPFlags = TCPFlag (sub [13 ]) & 0x3F
187
+ q .TCPFlags = TCPFlag (sub [13 ])
184
188
headerLength := (sub [12 ] & 0xF0 ) >> 2
185
189
q .dataofs = q .subofs + int (headerLength )
186
190
return
@@ -282,7 +286,7 @@ func (q *Parsed) decode6(b []byte) {
282
286
}
283
287
q .Src = q .Src .WithPort (binary .BigEndian .Uint16 (sub [0 :2 ]))
284
288
q .Dst = q .Dst .WithPort (binary .BigEndian .Uint16 (sub [2 :4 ]))
285
- q .TCPFlags = TCPFlag (sub [13 ]) & 0x3F
289
+ q .TCPFlags = TCPFlag (sub [13 ])
286
290
headerLength := (sub [12 ] & 0xF0 ) >> 2
287
291
q .dataofs = q .subofs + int (headerLength )
288
292
return
@@ -374,8 +378,14 @@ func (q *Parsed) Payload() []byte {
374
378
return q .b [q .dataofs :q .length ]
375
379
}
376
380
377
- // IsTCPSyn reports whether q is a TCP SYN packet
378
- // (i.e. the first packet in a new connection).
381
+ // Transport returns the transport header and payload (IP subprotocol, such as TCP or UDP).
382
+ // This is a read-only view; that is, p retains the ownership of the buffer.
383
+ func (p * Parsed ) Transport () []byte {
384
+ return p .b [p .subofs :]
385
+ }
386
+
387
+ // IsTCPSyn reports whether q is a TCP SYN packet,
388
+ // without ACK set. (i.e. the first packet in a new connection)
379
389
func (q * Parsed ) IsTCPSyn () bool {
380
390
return (q .TCPFlags & TCPSynAck ) == TCPSyn
381
391
}
@@ -424,6 +434,40 @@ func (q *Parsed) IsEchoResponse() bool {
424
434
}
425
435
}
426
436
437
+ // RemoveECNBits modifies p and its underlying memory buffer to remove
438
+ // ECN bits, if any. It reports whether it did so.
439
+ //
440
+ // It currently only does the TCP flags.
441
+ func (p * Parsed ) RemoveECNBits () bool {
442
+ if p .IPVersion == 0 {
443
+ return false
444
+ }
445
+ if p .IPProto != ipproto .TCP {
446
+ // TODO(bradfitz): handle non-TCP too? for now only trying to
447
+ // fix the Issue 2642 problem.
448
+ return false
449
+ }
450
+ if p .TCPFlags & TCPECNBits == 0 {
451
+ // Nothing to do.
452
+ return false
453
+ }
454
+
455
+ // Clear flags.
456
+
457
+ // First in the parsed output.
458
+ p .TCPFlags = p .TCPFlags & ^ TCPECNBits
459
+
460
+ // Then in the underlying memory.
461
+ tcp := p .Transport ()
462
+ old := binary .BigEndian .Uint16 (tcp [12 :14 ])
463
+ tcp [13 ] = byte (p .TCPFlags )
464
+ new := binary .BigEndian .Uint16 (tcp [12 :14 ])
465
+ oldSum := binary .BigEndian .Uint16 (tcp [16 :18 ])
466
+ newSum := ^ checksumUpdate2ByteAlignedUint16 (^ oldSum , old , new )
467
+ binary .BigEndian .PutUint16 (tcp [16 :18 ], newSum )
468
+ return true
469
+ }
470
+
427
471
func Hexdump (b []byte ) string {
428
472
out := new (strings.Builder )
429
473
for i := 0 ; i < len (b ); i += 16 {
@@ -455,3 +499,26 @@ func Hexdump(b []byte) string {
455
499
}
456
500
return out .String ()
457
501
}
502
+
503
+ // From gVisor's unexported API:
504
+
505
+ // checksumUpdate2ByteAlignedUint16 updates a uint16 value in a calculated
506
+ // checksum.
507
+ //
508
+ // The value MUST begin at a 2-byte boundary in the original buffer.
509
+ func checksumUpdate2ByteAlignedUint16 (xsum , old , new uint16 ) uint16 {
510
+ // As per RFC 1071 page 4,
511
+ //(4) Incremental Update
512
+ //
513
+ // ...
514
+ //
515
+ // To update the checksum, simply add the differences of the
516
+ // sixteen bit integers that have been changed. To see why this
517
+ // works, observe that every 16-bit integer has an additive inverse
518
+ // and that addition is associative. From this it follows that
519
+ // given the original value m, the new value m', and the old
520
+ // checksum C, the new checksum C' is:
521
+ //
522
+ // C' = C + (-m) + m' = C + (m' - m)
523
+ return checksumCombine (xsum , checksumCombine (new , ^ old ))
524
+ }
0 commit comments