예제 #1
0
파일: ipconntrack.c 프로젝트: noelbk/bklib
// track a tcp stream.  returns the difference between this packet's
// SEQ and the expected next SEQ.
int
IpConnTrack_track_stream(IpConnTrack *self, IpConn *conn, 
			 IpConnTcpQueue *queue, 
			 struct netpkt *pkt, 
			 int buffer_stream) {
    netpkt_tcp *tcp;
    netpkt_udp *udp;
    tcp_seq_t seq;
    char *dst, *src;
    int len, diff=0;
    
    do {
	tcp = pkt->pkt_tcp;
	udp = pkt->pkt_udp;
	src = pkt->pkt_msg;
	len = pkt->pkt_len;
	diff = 0;
	
	if( tcp ) {
	    if( tcp_ack(tcp) ) {
		queue->ack = ntohl(tcp->ack_seq);
	    }
	    queue->win = ntohs(tcp->window);

	    seq = ntohl(tcp->seq);

	    if( !queue->seq_ok ) {
		queue->seq_syn = seq;
		queue->seq =  seq;
		queue->seq_ok = 1;
		if( tcp_syn(tcp) ) {
		    queue->seq++;
		}
		else {
		    conn->conn_pkt_flags |= CONN_PKT_TCP_MISSED_SYN;
		}
	    }
	
	    diff = tcp_seq_diff(seq, queue->seq);

	    if( diff > 1 ) {
		// ignore packets (far) in the future
		conn->conn_pkt_flags |= CONN_PKT_TCP_FUTURE_SEQ;
		break;
	    }

	    src += -diff;
	    len -= -diff;
	    if( len <= 0 ) {
		// ignore past packets
		break;
	    }
	    queue->seq += len;
	}
	else if( udp ) {
	}
	
	if( buffer_stream ) {
	    dst = (char*)array_add(&queue->buf, len);
	    assertb(dst);
	    memcpy(dst, src, len);
	}
    } while(0);
    
    return diff;
}
예제 #2
0
void process_tcp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	struct {
		unsigned src_port;
		unsigned dst_port;
		unsigned seqno;
		unsigned ackno;
		unsigned header_length;
		unsigned flags;
		unsigned window;
		unsigned checksum;
		unsigned urgent;
	} tcp;

	ferret->statistics.tcp++;

	if (length == 0) {
		FRAMERR(frame, "tcp: frame empty\n");
		return;
	}
	if (length < 20) {
		FRAMERR(frame, "tcp: frame too short\n");
		return;
	}

/*
	    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/

	tcp.src_port = ex16be(px+0);
	tcp.dst_port = ex16be(px+2);
	tcp.seqno = ex32be(px+4);
	tcp.ackno = ex32be(px+8);
	tcp.header_length = px[12]>>2;
	tcp.flags = px[13];
	tcp.window = ex16be(px+14);
	tcp.checksum = ex16be(px+16);
	tcp.urgent = ex16be(px+18);

	frame->src_port = tcp.src_port;
	frame->dst_port = tcp.dst_port;

	if (tcp.header_length < 20) {
		/* Regress: defcon2008\dump027.pcap(39901) */
		//FRAMERR(frame, "tcp: header too short, expected length=20, found length=%d\n", tcp.header_length);
		return;
	}
	if (tcp.header_length > length) {
		//FRAMERR(frame, "tcp: header too short, expected length=%d, found length=%d\n", tcp.header_length, length);
		return;
	}
	if ((tcp.flags & 0x20) && tcp.urgent > 0) {
		FRAMERR(frame, "tcp: found %d bytes of urgent data\n", tcp.urgent);
		return;
	}

	/* Check the checksum */
	if (!validate_tcp_checksum(px, length, frame->src_ipv4, frame->dst_ipv4)) {
		/* Regress: defcon2008-msnmsgr.pcap(24066) */
		ferret->statistics.errs_tcp_checksum++;		
		return;
	}

	/*TODO: need to check checksum */

	if (tcp.header_length > 20) {
		unsigned o = 20;
		unsigned max = tcp.header_length;

		while (o < tcp.header_length) {
			unsigned tag = px[o++];
			unsigned len;

			if (tag == 0)
				break;
			if (tag == 1)
				continue;

			if (o >= max) {
				FRAMERR(frame, "tcp: options too long\n");
				break;
			}
			len = px[o++];

			if (len < 2) {
				FRAMERR(frame, "tcp: invalid length field\n");
				break;
			}
			if (o+len-2 > max) {
				FRAMERR(frame, "tcp: options too long\n");
				break;
			}

			switch (tag) {
			case 0x02: /* max seg size */
				if (len != 4)
					FRAMERR(frame, "tcp: unknown length: option=%d, length=%d\n", tag, len);
				break;
			case 0x04: /* SACK permitted */
				if (len != 2)
					FRAMERR(frame, "tcp: unknown length: option=%d, length=%d\n", tag, len);
				break;
			case 0x05: /* SACK */
				break;
			case 0x08: /*timestamp*/
				break;
			case 0x03: /*window scale*/
				break;
			default:
				FRAMERR(frame, "tcp: unknown option=%d, length=%d\n", tag, len);
			}

			o += len-2;
		}
	}


	SAMPLE(ferret,"TCP", JOT_NUM("flags", tcp.flags));

	/* Process an "acknowledgement". Among other things, this will identify
	 * when packets have been missed: if the other side claims to have
	 * received a packet, but we never saw it, then we know that it was
	 * dropped somewhere on the network (probably because we are getting
	 * a weak signal via wireless). */
	if (tcp.flags & TCP_ACK) {
		tcp_ack_data(ferret, frame, tcp.ackno);
	}

	switch (tcp.flags & 0x3F) {
	case TCP_SYN:
		tcp_syn(ferret, frame);
		break;
	case TCP_SYN|TCP_ACK:
		tcp_synack(ferret, frame);
		break;
	case TCP_FIN:
	case TCP_FIN|TCP_ACK:
	case TCP_FIN|TCP_ACK|TCP_PSH:
		tcp_fin(ferret, frame);
		break;
	case TCP_ACK:
	case TCP_ACK|TCP_PSH:
		if (length > tcp.header_length)
			tcp_data(ferret, frame, px+tcp.header_length, length-tcp.header_length, tcp.seqno, tcp.ackno);
		break;
	case TCP_RST:
	case TCP_RST|TCP_ACK:
		break;
	case 0x40|TCP_ACK:
		break;
	case TCP_RST|TCP_ACK|TCP_FIN:
	case TCP_RST|TCP_ACK|TCP_PSH:
		break;
	default:
		FRAMERR(frame, "tcp: unexpected combo of flags: 0x%03x\n", tcp.flags);
	}
}
예제 #3
0
파일: ipconntrack.c 프로젝트: noelbk/bklib
int
IpConnTrack_track_state(IpConnTrack *self, IpConn *conn, struct netpkt *pkt) {
    netpkt_tcp *tcp = pkt->pkt_tcp;
    IpConnStats *st=0;
    
    if( conn->conn_pkt_flags & CONN_PKT_FROM_CLIENT ) {
	st = &conn->conn_stats_client;
	if( conn->conn_flags & CONN_LOCAL_CLIENT ) {
	    conn->conn_pkt_flags |= CONN_PKT_LOCAL_SRC;
	}
	if( conn->conn_flags & CONN_LOCAL_SERVER ) {
	    conn->conn_pkt_flags |= CONN_PKT_LOCAL_DST;
	}
    }
    else if( conn->conn_pkt_flags & CONN_PKT_FROM_SERVER ) {
	st = &conn->conn_stats_server;
	if( conn->conn_flags & CONN_LOCAL_CLIENT ) {
	    conn->conn_pkt_flags |= CONN_PKT_LOCAL_DST;
	}
	if( conn->conn_flags & CONN_LOCAL_SERVER ) {
	    conn->conn_pkt_flags |= CONN_PKT_LOCAL_SRC;
	}
    }

    if( st ) {
	st->packets++;
	st->bytes += pkt->pkt_len;

	// track the next expected sequence numbers to mark duplicate
	// packets.  I won't complain if retries are different.
	pkt->pkt_tcp_seq_diff = 0;
	if( tcp ) {
	    u32 seq;

	    seq = ntohl(tcp->seq);
	    if( !st->tcp_seq_next_ok ||
		seq == st->tcp_seq_next ) {
		if( tcp_syn(tcp) ) {
		    st->tcp_seq_next = seq + 1;
		}
		else {
		    st->tcp_seq_next = seq + pkt->pkt_len;
		}
		st->tcp_seq_next_ok = 1;
	    }
	    else {
		pkt->pkt_tcp_seq_diff = 
		    tcp_seq_diff(seq, st->tcp_seq_next);
	    }
	}
    }

    conn->conn_time_prev = conn->conn_time_last;
    conn->conn_time_last = mstime();

    if( tcp ) {
	if( tcp_fin(tcp) || tcp_rst(tcp) ) {
	    conn->conn_state = CONN_STATE_FIN;
	}
    }
    
    return 0;
}