/* * verify.c -- the connection matching engine * Part of the tcpick project * * Author: Francesco Stablum * * Copyright (C) 2003, 2004 Francesco Stablum * Licensed under the GPL * */ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "tcpick.h" #include "extern.h" #define CURRENT_CONN (prev_conn->next) #define ACK_OFF ntohl( tcppacket->ack_seq ) - Desc->oth->sip /* FIXME: to def.h? */ #define IS_CLIENT_SENDER \ CURRENT_CONN->client.ip.s_addr == ippacket->ip_src.s_addr && \ CURRENT_CONN->server.ip.s_addr == ippacket->ip_dst.s_addr && \ CURRENT_CONN->client.port == tcppacket->source && \ CURRENT_CONN->server.port == tcppacket->dest #define IS_SERVER_SENDER \ CURRENT_CONN->client.ip.s_addr == ippacket->ip_dst.s_addr && \ CURRENT_CONN->server.ip.s_addr == ippacket->ip_src.s_addr && \ CURRENT_CONN->client.port == tcppacket->dest && \ CURRENT_CONN->server.port == tcppacket->source #define IS_SYN_SENT \ tcppacket->syn == 1 && \ tcppacket->ack == 0 #define IS_SYN_RECEIVED \ tcppacket->syn == 1 && \ tcppacket->ack == 1 && \ Desc->side == SERVER && \ CURRENT_CONN->status == SYN_SENT #define IS_ESTABLISHING \ tcppacket->syn == 0 && \ tcppacket->ack == 1 && \ Desc->side == CLIENT && \ CURRENT_CONN->status == SYN_RECEIVED && \ CURRENT_CONN->client.sip == ntohl( tcppacket->seq ) #define IS_DATA_FLOW 1 #define IS_FIN_WAIT_1 \ tcppacket->fin == 1 && \ CURRENT_CONN->status == ESTABLISHED #define IS_FIN_WAIT_2__CLOSE_WAIT \ tcppacket->ack == 1 && \ tcppacket->fin == 0 && \ CURRENT_CONN->status == FIN_WAIT_1 && \ CURRENT_CONN->closer != Desc->side #define IS_TIME_WAIT__LAST_ACK \ tcppacket->ack == 1 && \ tcppacket->fin == 1 && \ ( CURRENT_CONN->status == FIN_WAIT_2__CLOSE_WAIT || \ CURRENT_CONN->status == FIN_WAIT_1 ) && \ CURRENT_CONN->closer != Desc->side #define IS_CLOSING \ tcppacket->ack == 1 && \ tcppacket->fin == 0 && \ CURRENT_CONN->status == TIME_WAIT__LAST_ACK && \ CURRENT_CONN->closer == Desc->side #define IS_RESET \ tcppacket->rst == 1 __inline__ int established_packet ( struct CONN * conn_ptr, struct HOST_DESC * Desc) /* called by verify() packets of established connections come here */ { register u_int32_t off; if( payload_len ) { off = ntohl( tcppacket->seq ) - Desc->sip ; /* unacknowledged data */ addfr( & (Desc->unack), Desc->wlen, off, payload, payload_len ); } if( payload_len == 0) { /* acknowledge data */ flush_ack ( Desc->oth, conn_ptr, ACK_OFF ); } else if( tcppacket->psh ) { /* PUSH data */ flush_ack ( Desc, conn_ptr, ACK_OFF ); } } __inline__ int verify() /* called by got_packet(). this is the engine that matches the packets with their connection */ { register struct HOST_DESC * Desc = NULL; register struct CONN * prev_conn; prev_conn = first_conn; /* SYN-SENT: (outside of the loop because the * loop is used for sessions just tracked) */ if( IS_SYN_SENT ) { newconn( last_conn ); return(1); } if(! CURRENT_CONN ) return 0 ; while (! Desc ) { /* cycle until it finds a connection that matches on server or client side */ if ( IS_CLIENT_SENDER ) Desc = & (CURRENT_CONN->client); else if ( IS_SERVER_SENDER ) Desc = & (CURRENT_CONN->server); else { prev_conn = prev_conn->next; if(! CURRENT_CONN ) return 0 ; } } /* update time of last packet in connection */ CURRENT_CONN->lasttime = time(NULL); /* when this point is reached, we have found the right matching connection */ if( IS_SYN_RECEIVED ) { CURRENT_CONN->server.sip = ntohl(tcppacket->seq) + 1; status_switch( prev_conn, SYN_RECEIVED ); return 1; } /* 3rd packet of the 3-way-handshake*/ if( IS_ESTABLISHING ) { status_switch( prev_conn, ESTABLISHED ); return 1; } /* data or ack packets */ if( IS_DATA_FLOW ) { if( REBUILD ) established_packet ( CURRENT_CONN, Desc ); } /* first FIN sent */ if( IS_FIN_WAIT_1 ) { status_switch( prev_conn, FIN_WAIT_1 ); CURRENT_CONN->closer = Desc->side; return 1; } /* ACK of first FIN sent */ if( IS_FIN_WAIT_2__CLOSE_WAIT ) { status_switch( prev_conn, FIN_WAIT_2__CLOSE_WAIT ); return 1; } /* second FIN sent */ if( IS_TIME_WAIT__LAST_ACK ) { status_switch( prev_conn, TIME_WAIT__LAST_ACK ); return 1; } /* LAST-ACK sent */ if( IS_CLOSING ) { status_switch( prev_conn, CLOSED ); return 1; } /* RST sent */ if( IS_RESET ) { status_switch( prev_conn, RESET ); return 1; } /* nice work :^) */ }