/* * Copyright 2010 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.pcap.decoder.tcp; public class TcpStateUpdater { private static final int FIN = 1; private static final int SYN = 2; private static final int ACK = 16; private static final int FIN_ACK = 17; private static final int SYN_ACK = 18; private static final int PSH_ACK = 24; private static final int FIN_PSH_ACK = 25; private final TcpTransitionMapper tMap; public TcpStateUpdater() { tMap = new TcpTransitionMapper(); } public void updateState(TcpSessionImpl session, TcpPacket packet) { if (packet == null) return; TcpState clientState = session.getClientState(); TcpState serverState = session.getServerState(); switch (packet.getFlags()) { case SYN: clientState = tMap.map(packet, clientState, Action.SEND_SYN); serverState = tMap.map(packet, serverState, Action.RECV_SYN); break; case SYN_ACK: clientState = tMap.map(packet, clientState, Action.RECV_SYNACKED); break; case ACK: case PSH_ACK: if (serverState == TcpState.SYN_RCVD) serverState = tMap.map(packet, serverState, Action.RECV_SYNACKED); if (session.getPacketCountAfterFin() >= 1) { // Except case if (session.getFirstFinSeq() == packet.getRelativeAck() && session.getFirstFinAck() == packet.getRelativeSeq()) return; else if (session.getFirstFinSeq() > packet.getRelativeAck()) return; session.setPacketCountAfterFin(session.getPacketCountAfterFin() + 1); } if (session.getPacketCountAfterFin() == 2) { if (packet.getDirection() == TcpDirection.ToServer) { clientState = tMap.map(packet, clientState, Action.RECV_FIN); serverState = tMap.map(packet, serverState, Action.RECV_ACKED); } else { serverState = tMap.map(packet, serverState, Action.RECV_FIN); clientState = tMap.map(packet, clientState, Action.RECV_ACKED); } } else if (session.getPacketCountAfterFin() == 3) { if (packet.getDirection() == TcpDirection.ToServer) { if (serverState == TcpState.LAST_ACK) serverState = tMap.map(packet, serverState, Action.RECV_FINACKED); else // simultaneous close. clientState = tMap.map(packet, clientState, Action.RECV_FIN); } else { if (clientState == TcpState.LAST_ACK) clientState = tMap.map(packet, clientState, Action.RECV_FINACKED); else // simultaneous close. serverState = tMap.map(packet, serverState, Action.RECV_FIN); } } else if (session.getPacketCountAfterFin() == 4) { if (packet.getDirection() == TcpDirection.ToServer) { serverState = tMap.map(packet, serverState, Action.RECV_FINACKED); clientState = tMap.map(packet, clientState, Action.RECV_FIN); } else { clientState = tMap.map(packet, clientState, Action.RECV_FINACKED); serverState = tMap.map(packet, serverState, Action.RECV_FIN); } } break; case FIN: case FIN_ACK: case FIN_PSH_ACK: session.setPacketCountAfterFin(session.getPacketCountAfterFin() + 1); if (session.getPacketCountAfterFin() == 1) { if (packet.getDirection() == TcpDirection.ToServer) clientState = tMap.map(packet, clientState, Action.SEND_FIN); else serverState = tMap.map(packet, serverState, Action.SEND_FIN); session.setFirstFinSeq(packet.getRelativeSeq()); session.setFirstFinAck(packet.getRelativeAck()); } else if (session.getPacketCountAfterFin() == 2) { if (packet.getDirection() == TcpDirection.ToServer) { if ((packet.getRelativeSeq() == session.getFirstFinAck()) && (packet.getRelativeAck() == session.getFirstFinSeq())) { clientState = tMap.map(packet, clientState, Action.SEND_FIN); } else { clientState = tMap.map(packet, clientState, Action.RECV_FIN); serverState = tMap.map(packet, serverState, Action.RECV_FINACKED); clientState = tMap.map(packet, clientState, Action.SEND_FIN); } } else { if ((packet.getRelativeSeq() == session.getFirstFinAck()) && (packet.getRelativeAck() == session.getFirstFinSeq())) { serverState = tMap.map(packet, serverState, Action.SEND_FIN); } else { serverState = tMap.map(packet, serverState, Action.RECV_FIN); clientState = tMap.map(packet, clientState, Action.RECV_FINACKED); serverState = tMap.map(packet, serverState, Action.SEND_FIN); } } } else if (session.getPacketCountAfterFin() == 3) { if (packet.getDirection() == TcpDirection.ToServer) { clientState = tMap.map(packet, clientState, Action.SEND_FIN); serverState = tMap.map(packet, serverState, Action.RECV_FIN); } else { clientState = tMap.map(packet, clientState, Action.RECV_FIN); serverState = tMap.map(packet, serverState, Action.SEND_FIN); } } break; } session.setClientState(clientState); session.setServerState(serverState); } }