From 3f1edad4e6ba0a7876750aea55507fae14d8badf Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Wed, 11 Oct 2017 16:40:58 +0200 Subject: ODPM 266: Go-libmemif + 2 examples. Change-Id: Icdb9b9eb2314eff6c96afe7996fcf2728291de4a Signed-off-by: Milan Lenco --- .../google/gopacket/reassembly/tcpcheck.go | 246 +++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 vendor/github.com/google/gopacket/reassembly/tcpcheck.go (limited to 'vendor/github.com/google/gopacket/reassembly/tcpcheck.go') diff --git a/vendor/github.com/google/gopacket/reassembly/tcpcheck.go b/vendor/github.com/google/gopacket/reassembly/tcpcheck.go new file mode 100644 index 0000000..4b52aba --- /dev/null +++ b/vendor/github.com/google/gopacket/reassembly/tcpcheck.go @@ -0,0 +1,246 @@ +// Copyright 2012 Google, Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. + +package reassembly + +import ( + "encoding/binary" + "fmt" + + "github.com/google/gopacket" + "github.com/google/gopacket/layers" +) + +/* + * Check TCP packet against options (window, MSS) + */ + +type tcpStreamOptions struct { + mss int + scale int + receiveWindow uint +} + +// TCPOptionCheck contains options for the two directions +type TCPOptionCheck struct { + options [2]tcpStreamOptions +} + +func (t *TCPOptionCheck) getOptions(dir TCPFlowDirection) *tcpStreamOptions { + if dir == TCPDirClientToServer { + return &t.options[0] + } + return &t.options[1] +} + +// NewTCPOptionCheck creates default options +func NewTCPOptionCheck() TCPOptionCheck { + return TCPOptionCheck{ + options: [2]tcpStreamOptions{ + tcpStreamOptions{ + mss: 0, + scale: -1, + receiveWindow: 0, + }, tcpStreamOptions{ + mss: 0, + scale: -1, + receiveWindow: 0, + }, + }, + } +} + +// Accept checks whether the packet should be accepted by checking TCP options +func (t *TCPOptionCheck) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir TCPFlowDirection, acked Sequence, start *bool) error { + options := t.getOptions(dir) + if tcp.SYN { + mss := -1 + scale := -1 + for _, o := range tcp.Options { + // MSS + if o.OptionType == 2 { + if len(o.OptionData) != 2 { + return fmt.Errorf("MSS option data length expected 2, got %d", len(o.OptionData)) + } + mss = int(binary.BigEndian.Uint16(o.OptionData[:2])) + } + // Window scaling + if o.OptionType == 3 { + if len(o.OptionData) != 1 { + return fmt.Errorf("Window scaling length expected: 1, got %d", len(o.OptionData)) + } + scale = int(o.OptionData[0]) + } + } + options.mss = mss + options.scale = scale + } else { + if acked != invalidSequence { + revOptions := t.getOptions(dir.Reverse()) + length := len(tcp.Payload) + + // Check packet is in the correct window + diff := acked.Difference(Sequence(tcp.Seq)) + if diff == -1 && (length == 1 || length == 0) { + // This is probably a Keep-alive + // TODO: check byte is ok + } else if diff < 0 { + return fmt.Errorf("Re-emitted packet (diff:%d,seq:%d,rev-ack:%d)", diff, + tcp.Seq, acked) + } else if revOptions.mss > 0 && length > revOptions.mss { + return fmt.Errorf("%d > mss (%d)", length, revOptions.mss) + } else if revOptions.receiveWindow != 0 && revOptions.scale < 0 && diff > int(revOptions.receiveWindow) { + return fmt.Errorf("%d > receiveWindow(%d)", diff, revOptions.receiveWindow) + } + } + } + // Compute receiveWindow + options.receiveWindow = uint(tcp.Window) + if options.scale > 0 { + options.receiveWindow = options.receiveWindow << (uint(options.scale)) + } + return nil +} + +// TCPSimpleFSM implements a very simple TCP state machine +// +// Usage: +// When implementing a Stream interface and to avoid to consider packets that +// would be rejected due to client/server's TCP stack, the Accept() can call +// TCPSimpleFSM.CheckState(). +// +// Limitations: +// - packet should be received in-order. +// - no check on sequence number is performed +// - no RST +type TCPSimpleFSM struct { + dir TCPFlowDirection + state int + options TCPSimpleFSMOptions +} + +// TCPSimpleFSMOptions holds options for TCPSimpleFSM +type TCPSimpleFSMOptions struct { + SupportMissingEstablishment bool // Allow missing SYN, SYN+ACK, ACK +} + +// Internal values of state machine +const ( + TCPStateClosed = 0 + TCPStateSynSent = 1 + TCPStateEstablished = 2 + TCPStateCloseWait = 3 + TCPStateLastAck = 4 + TCPStateReset = 5 +) + +// NewTCPSimpleFSM creates a new TCPSimpleFSM +func NewTCPSimpleFSM(options TCPSimpleFSMOptions) *TCPSimpleFSM { + return &TCPSimpleFSM{ + state: TCPStateClosed, + options: options, + } +} + +func (t *TCPSimpleFSM) String() string { + switch t.state { + case TCPStateClosed: + return "Closed" + case TCPStateSynSent: + return "SynSent" + case TCPStateEstablished: + return "Established" + case TCPStateCloseWait: + return "CloseWait" + case TCPStateLastAck: + return "LastAck" + case TCPStateReset: + return "Reset" + } + return "?" +} + +// CheckState returns false if tcp is invalid wrt current state or update the state machine's state +func (t *TCPSimpleFSM) CheckState(tcp *layers.TCP, dir TCPFlowDirection) bool { + if t.state == TCPStateClosed && t.options.SupportMissingEstablishment && !(tcp.SYN && !tcp.ACK) { + /* try to figure out state */ + switch true { + case tcp.SYN && tcp.ACK: + t.state = TCPStateSynSent + t.dir = dir.Reverse() + case tcp.FIN && !tcp.ACK: + t.state = TCPStateEstablished + case tcp.FIN && tcp.ACK: + t.state = TCPStateCloseWait + t.dir = dir.Reverse() + default: + t.state = TCPStateEstablished + } + } + + switch t.state { + /* openning connection */ + case TCPStateClosed: + if tcp.SYN && !tcp.ACK { + t.dir = dir + t.state = TCPStateSynSent + return true + } + case TCPStateSynSent: + if tcp.RST { + t.state = TCPStateReset + return true + } + + if tcp.SYN && tcp.ACK && dir == t.dir.Reverse() { + t.state = TCPStateEstablished + return true + } + if tcp.SYN && !tcp.ACK && dir == t.dir { + // re-transmission + return true + } + /* established */ + case TCPStateEstablished: + if tcp.RST { + t.state = TCPStateReset + return true + } + + if tcp.FIN { + t.state = TCPStateCloseWait + t.dir = dir + return true + } + // accept any packet + return true + /* closing connection */ + case TCPStateCloseWait: + if tcp.RST { + t.state = TCPStateReset + return true + } + + if tcp.FIN && tcp.ACK && dir == t.dir.Reverse() { + t.state = TCPStateLastAck + return true + } + if tcp.ACK { + return true + } + case TCPStateLastAck: + if tcp.RST { + t.state = TCPStateReset + return true + } + + if tcp.ACK && t.dir == dir { + t.state = TCPStateClosed + return true + } + } + return false +} -- cgit 1.2.3-korg