예제 #1
0
/* If an incoming SYN or SYNACK frame contains a payload and/or FIN,
 * queue this additional data / FIN.
 */
void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb)
{
	struct tcp_sock *tp = tcp_sk(sk);

	if (TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)
		return;

	skb = skb_clone(skb, GFP_ATOMIC);
	if (!skb)
		return;

	skb_dst_drop(skb);
	/* segs_in has been initialized to 1 in tcp_create_openreq_child().
	 * Hence, reset segs_in to 0 before calling tcp_segs_in()
	 * to avoid double counting.  Also, tcp_segs_in() expects
	 * skb->len to include the tcp_hdrlen.  Hence, it should
	 * be called before __skb_pull().
	 */
	tp->segs_in = 0;
	tcp_segs_in(tp, skb);
	__skb_pull(skb, tcp_hdrlen(skb));
	sk_forced_mem_schedule(sk, skb->truesize);
	skb_set_owner_r(skb, sk);

	TCP_SKB_CB(skb)->seq++;
	TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_SYN;

	tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
	__skb_queue_tail(&sk->sk_receive_queue, skb);
	tp->syn_data_acked = 1;

	/* u64_stats_update_begin(&tp->syncp) not needed here,
	 * as we certainly are not changing upper 32bit value (0)
	 */
	tp->bytes_received = skb->len;

	if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
		tcp_fin(sk);
}
예제 #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;
}