def state_conn_finish(self, ts, tcp, to_server): # Still acknowledging older packets. if self.cli != tcp.ack and self.srv != tcp.ack: self.state_conn(ts, tcp, to_server) return if tcp.flags & dpkt.tcp.TH_ACK: if to_server: if self.srv != tcp.ack: raise InvalidTcpPacketOrder(tcp) # Process any final packets. tcp.ack -= 1 self.state_conn(ts, tcp, to_server) # Indicate the end of this connection. self.srv = None if not to_server: if self.cli != tcp.ack: raise InvalidTcpPacketOrder(tcp) # Process any final packets. tcp.ack -= 1 self.state_conn(ts, tcp, to_server) # Indicate the end of this connection. self.cli = None if tcp.flags & dpkt.tcp.TH_FIN: if to_server: self.cli = tcp.seq + 1 else: self.srv = tcp.seq + 1
def state_init_ack(self, ts, tcp, to_server): # Retransmission of the SYN packet. Let's ignore that for now. if to_server and tcp.flags == dpkt.tcp.TH_SYN: # self.parent.handle(self.s, ts, TCPRetransmission(), # None, special="deadhost") return # Retransmission of the SYN ACK packet. Indicates that the client is # not responding within the given timeframe; a potential SYN flood? if not to_server and tcp.flags == (dpkt.tcp.TH_SYN | dpkt.tcp.TH_ACK): # self.parent.handle(self.s, ts, TCPRetransmission(), # None, special="synflood") return # The client has retransmitted the SYN ACK packet twice (usually) and # now gives up through a RST packet. if not to_server and tcp.flags == dpkt.tcp.TH_RST: # self.parent.handle(self.s, ts, TCPRetransmission(), # None, special="synflood") return # The client has received a SYN ACK but is no longer interested in # connecting to this service and thus quits through a RST. if to_server and tcp.flags == dpkt.tcp.TH_RST: return if not to_server: log.warning( "The server is spamming the client even though an " "ACK has not been provided yet (timestamp %f).", ts) return # It is possible that a client sends out a request straight away along # with the ACK packet (the push flag might also be set) if tcp.flags & dpkt.tcp.TH_ACK and tcp.data: self.state = "conn" self.state_conn(ts, tcp, to_server) return # You know, let's send a FIN packet. if to_server and tcp.flags & dpkt.tcp.TH_FIN: self.state = "conn_finish" return if tcp.flags != dpkt.tcp.TH_ACK: raise InvalidTcpPacketOrder(tcp) if tcp.seq != self.cli: raise UnknownTcpSequenceNumber(tcp) if tcp.ack != self.srv: raise UnknownTcpSequenceNumber(tcp) if tcp.data: raise UnexpectedTcpData(tcp) self.state = "conn"
def state_init_syn_ack(self, ts, tcp, to_server): # Retransmission of the SYN packet. Indicates that the server is not # responding within the given timeframe and thus might be a dead host. if to_server and tcp.flags == dpkt.tcp.TH_SYN: # self.parent.handle(self.s, ts, TCPRetransmission(), # None, special="deadhost") return # The reply from a server when no service is listening on the given # port. Generally speaking the client will retry sending SYN packets. if tcp.flags & dpkt.tcp.TH_RST: # self.parent.handle(self.s, ts, None, None, special="deadhost") self.state = "init_syn" return # Some PCAPs completely miss out on incoming traffic. Not really sure # whether trying to parse this really makes sense, but here we go. if to_server and tcp.flags == dpkt.tcp.TH_ACK: self.cli, self.srv = tcp.seq, tcp.ack return self.state_init_ack(ts, tcp, to_server) # Not much to comment here really. if not to_server and tcp.flags == dpkt.tcp.TH_ACK: log.warning( "Server replied with an ACK to a SYN packet " "(timestamp %f).", ts) return # A best guess would be; the SYN ACK/ACK packets were not captured. if to_server and tcp.flags & dpkt.tcp.TH_ACK and tcp.data: log.warning( "We didn't receive SYN ACK or ACK packets but are proceeding " "straight away to the TCP data (timestamp %f).", ts) self.cli, self.srv, self.state = tcp.seq, tcp.ack, "conn" return self.state_conn(ts, tcp, to_server) if not to_server and tcp.flags == (dpkt.tcp.TH_PUSH | dpkt.tcp.TH_ACK): self.state = "init_syn" return if to_server or tcp.flags != (dpkt.tcp.TH_SYN | dpkt.tcp.TH_ACK): raise InvalidTcpPacketOrder(tcp) if tcp.data: raise UnexpectedTcpData(tcp) self.cli = tcp.ack self.srv = tcp.seq + 1 self.state = "init_ack"
def state_init_syn(self, ts, tcp, to_server): # When no service is listening on the other end a server may send RST # packets back after which the state will be reverted to "init_syn". # And thus we have to handle any additional RSTs here as well. (Note # that we don't really change the state here, so RSTs from the # opposite side will also end up here). if tcp.flags & dpkt.tcp.TH_RST: return if not to_server and tcp.flags != dpkt.tcp.TH_SYN: raise InvalidTcpPacketOrder(tcp) if not to_server and tcp.data: raise UnexpectedTcpData(tcp) self.ts = ts self.cli = tcp.seq self.state = "init_syn_ack"