|
|
@ -22,12 +22,16 @@ const minFrag = 60 + 20 // max IPv4 header + basic TCP header
|
|
|
|
type TCPFlag uint8
|
|
|
|
type TCPFlag uint8
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
const (
|
|
|
|
TCPFin TCPFlag = 0x01
|
|
|
|
TCPFin TCPFlag = 0x01
|
|
|
|
TCPSyn TCPFlag = 0x02
|
|
|
|
TCPSyn TCPFlag = 0x02
|
|
|
|
TCPRst TCPFlag = 0x04
|
|
|
|
TCPRst TCPFlag = 0x04
|
|
|
|
TCPPsh TCPFlag = 0x08
|
|
|
|
TCPPsh TCPFlag = 0x08
|
|
|
|
TCPAck TCPFlag = 0x10
|
|
|
|
TCPAck TCPFlag = 0x10
|
|
|
|
TCPSynAck TCPFlag = TCPSyn | TCPAck
|
|
|
|
TCPUrg TCPFlag = 0x20
|
|
|
|
|
|
|
|
TCPECNEcho TCPFlag = 0x40
|
|
|
|
|
|
|
|
TCPCWR TCPFlag = 0x80
|
|
|
|
|
|
|
|
TCPSynAck TCPFlag = TCPSyn | TCPAck
|
|
|
|
|
|
|
|
TCPECNBits TCPFlag = TCPECNEcho | TCPCWR
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Parsed is a minimal decoding of a packet suitable for use in filters.
|
|
|
|
// Parsed is a minimal decoding of a packet suitable for use in filters.
|
|
|
@ -180,7 +184,7 @@ func (q *Parsed) decode4(b []byte) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
|
|
|
|
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
|
|
|
|
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
|
|
|
|
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
|
|
|
|
q.TCPFlags = TCPFlag(sub[13]) & 0x3F
|
|
|
|
q.TCPFlags = TCPFlag(sub[13])
|
|
|
|
headerLength := (sub[12] & 0xF0) >> 2
|
|
|
|
headerLength := (sub[12] & 0xF0) >> 2
|
|
|
|
q.dataofs = q.subofs + int(headerLength)
|
|
|
|
q.dataofs = q.subofs + int(headerLength)
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -282,7 +286,7 @@ func (q *Parsed) decode6(b []byte) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
|
|
|
|
q.Src = q.Src.WithPort(binary.BigEndian.Uint16(sub[0:2]))
|
|
|
|
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
|
|
|
|
q.Dst = q.Dst.WithPort(binary.BigEndian.Uint16(sub[2:4]))
|
|
|
|
q.TCPFlags = TCPFlag(sub[13]) & 0x3F
|
|
|
|
q.TCPFlags = TCPFlag(sub[13])
|
|
|
|
headerLength := (sub[12] & 0xF0) >> 2
|
|
|
|
headerLength := (sub[12] & 0xF0) >> 2
|
|
|
|
q.dataofs = q.subofs + int(headerLength)
|
|
|
|
q.dataofs = q.subofs + int(headerLength)
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -374,8 +378,14 @@ func (q *Parsed) Payload() []byte {
|
|
|
|
return q.b[q.dataofs:q.length]
|
|
|
|
return q.b[q.dataofs:q.length]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IsTCPSyn reports whether q is a TCP SYN packet
|
|
|
|
// Transport returns the transport header and payload (IP subprotocol, such as TCP or UDP).
|
|
|
|
// (i.e. the first packet in a new connection).
|
|
|
|
// This is a read-only view; that is, p retains the ownership of the buffer.
|
|
|
|
|
|
|
|
func (p *Parsed) Transport() []byte {
|
|
|
|
|
|
|
|
return p.b[p.subofs:]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// IsTCPSyn reports whether q is a TCP SYN packet,
|
|
|
|
|
|
|
|
// without ACK set. (i.e. the first packet in a new connection)
|
|
|
|
func (q *Parsed) IsTCPSyn() bool {
|
|
|
|
func (q *Parsed) IsTCPSyn() bool {
|
|
|
|
return (q.TCPFlags & TCPSynAck) == TCPSyn
|
|
|
|
return (q.TCPFlags & TCPSynAck) == TCPSyn
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -424,6 +434,40 @@ func (q *Parsed) IsEchoResponse() bool {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RemoveECNBits modifies p and its underlying memory buffer to remove
|
|
|
|
|
|
|
|
// ECN bits, if any. It reports whether it did so.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// It currently only does the TCP flags.
|
|
|
|
|
|
|
|
func (p *Parsed) RemoveECNBits() bool {
|
|
|
|
|
|
|
|
if p.IPVersion == 0 {
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.IPProto != ipproto.TCP {
|
|
|
|
|
|
|
|
// TODO(bradfitz): handle non-TCP too? for now only trying to
|
|
|
|
|
|
|
|
// fix the Issue 2642 problem.
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.TCPFlags&TCPECNBits == 0 {
|
|
|
|
|
|
|
|
// Nothing to do.
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clear flags.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// First in the parsed output.
|
|
|
|
|
|
|
|
p.TCPFlags = p.TCPFlags & ^TCPECNBits
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Then in the underlying memory.
|
|
|
|
|
|
|
|
tcp := p.Transport()
|
|
|
|
|
|
|
|
old := binary.BigEndian.Uint16(tcp[12:14])
|
|
|
|
|
|
|
|
tcp[13] = byte(p.TCPFlags)
|
|
|
|
|
|
|
|
new := binary.BigEndian.Uint16(tcp[12:14])
|
|
|
|
|
|
|
|
oldSum := binary.BigEndian.Uint16(tcp[16:18])
|
|
|
|
|
|
|
|
newSum := ^checksumUpdate2ByteAlignedUint16(^oldSum, old, new)
|
|
|
|
|
|
|
|
binary.BigEndian.PutUint16(tcp[16:18], newSum)
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func Hexdump(b []byte) string {
|
|
|
|
func Hexdump(b []byte) string {
|
|
|
|
out := new(strings.Builder)
|
|
|
|
out := new(strings.Builder)
|
|
|
|
for i := 0; i < len(b); i += 16 {
|
|
|
|
for i := 0; i < len(b); i += 16 {
|
|
|
@ -455,3 +499,26 @@ func Hexdump(b []byte) string {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out.String()
|
|
|
|
return out.String()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// From gVisor's unexported API:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// checksumUpdate2ByteAlignedUint16 updates a uint16 value in a calculated
|
|
|
|
|
|
|
|
// checksum.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// The value MUST begin at a 2-byte boundary in the original buffer.
|
|
|
|
|
|
|
|
func checksumUpdate2ByteAlignedUint16(xsum, old, new uint16) uint16 {
|
|
|
|
|
|
|
|
// As per RFC 1071 page 4,
|
|
|
|
|
|
|
|
//(4) Incremental Update
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// To update the checksum, simply add the differences of the
|
|
|
|
|
|
|
|
// sixteen bit integers that have been changed. To see why this
|
|
|
|
|
|
|
|
// works, observe that every 16-bit integer has an additive inverse
|
|
|
|
|
|
|
|
// and that addition is associative. From this it follows that
|
|
|
|
|
|
|
|
// given the original value m, the new value m', and the old
|
|
|
|
|
|
|
|
// checksum C, the new checksum C' is:
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// C' = C + (-m) + m' = C + (m' - m)
|
|
|
|
|
|
|
|
return checksumCombine(xsum, checksumCombine(new, ^old))
|
|
|
|
|
|
|
|
}
|
|
|
|