Esempio n. 1
0
void connect_do(void *pri_work, const ip_report_t *r) {
	char shost_s[32];
	union {
		void *ptr;
		send_pri_workunit_t *w;
		uint8_t *inc;
	} w_u;
	union {
		void *ptr;
		connection_status_t *c;
	} c_u;
	union {
		const uint8_t *packet;
		const ip_report_t *r;
		const uint16_t *len;
	} r_u;
	struct in_addr ia;
	uint64_t state_key=0;
	size_t dlen=0, pk_len=0;
	uint32_t dhost=0, shost=0;
	uint16_t sport=0, dport=0;

	if (r == NULL) {
		PANIC("r ptr NULL");
	}
	if (state_tbl == NULL) {
		PANIC("state table null");
	}
	if (pri_work == NULL) {
		PANIC("pri_work NULL");
	}

	if (r->magic != IP_REPORT_MAGIC) {
		ERR("wrong magic number for IP report");
		return;
	}

	state_key=get_connectionkey(r);

	dhost=r->host_addr;
	dport=r->sport;
	sport=r->dport;
	shost=r->send_addr;

	if (rbfind(state_tbl, state_key, &c_u.ptr) > 0) {
		DBG(M_CON, "connection with flags are %s status is %d", strtcpflgs(r->type), c_u.c->status);

		r_u.r=r;

		if (r_u.r->doff) {
			pk_len=r_u.r->doff;
			r_u.packet += sizeof(ip_report_t);
			if (*r_u.len != pk_len) {
				ERR("report is damaged?, packet seems broken");
				return;
			}
			else {
				r_u.len++;

				dlen=try_and_extract_tcp_data(r_u.packet, pk_len, c_u.c);
				if (dlen > 0) {
					c_u.c->tseq += dlen;
				}
			}
		}

		if (c_u.c->m_tstamp == 0 || c_u.c->t_tstamp == 0) {
			c_u.c->m_tstamp=0;
			c_u.c->t_tstamp=0;
		}
		else {
			c_u.c->m_tstamp++; /* XXX good enough for testing */
		}


		if (dlen < c_u.c->window) c_u.c->window -= dlen;

		if (r->type & TH_RST) {
			c_u.c->status=U_TCP_CLOSE;
			s->stats.stream_remote_abort++;
			a_conns--;
		}

		switch (c_u.c->status) {
			case U_TCP_ESTABLISHED:

				if (r->type & TH_PSH) {
					w_u.ptr=xmalloc(sizeof(send_pri_workunit_t));
					w_u.w->magic=PRI_4SEND_MAGIC;
					w_u.w->dhost=dhost;
					w_u.w->dport=dport;
					w_u.w->sport=sport;
					w_u.w->shost=c_u.c->send_ip;
					w_u.w->tseq=c_u.c->tseq;
					w_u.w->mseq=c_u.c->mseq;
					w_u.w->window_size=c_u.c->window;
					w_u.w->flags=TH_ACK|TH_FIN;
					w_u.w->doff=0;
					w_u.w->t_tstamp=c_u.c->t_tstamp;
					w_u.w->m_tstamp=c_u.c->m_tstamp;
					c_u.c->m_tstamp++;

					DBG(M_CON, "setting connection state into FIN_WAIT2 and sending ACK|FIN");

					c_u.c->status=U_TCP_FIN_WAIT2;

					fifo_push(pri_work, w_u.ptr);
					s->stats.stream_segments_sent++;
					c_u.c->mseq++;
					w_u.ptr=NULL;
				}
				else if (r->type & TH_FIN) {

					c_u.c->tseq += 1; /* FIN eats a seq ;] */

					w_u.ptr=xmalloc(sizeof(send_pri_workunit_t));
					w_u.w->magic=PRI_4SEND_MAGIC;
					w_u.w->dhost=dhost;
					w_u.w->dport=dport;
					w_u.w->sport=sport;
					w_u.w->shost=c_u.c->send_ip;
					w_u.w->tseq=c_u.c->tseq;
					w_u.w->mseq=c_u.c->mseq;
					w_u.w->window_size=c_u.c->window;
					w_u.w->flags=TH_ACK;
					w_u.w->doff=0;
					w_u.w->t_tstamp=c_u.c->t_tstamp;
					w_u.w->m_tstamp=c_u.c->m_tstamp;

					DBG(M_CON, "acking FIN");

					fifo_push(pri_work, w_u.ptr);
					s->stats.stream_segments_sent++;

					w_u.ptr=xmalloc(sizeof(send_pri_workunit_t));
					w_u.w->magic=PRI_4SEND_MAGIC;
					w_u.w->dhost=dhost;
					w_u.w->dport=dport;
					w_u.w->sport=sport;
					w_u.w->shost=c_u.c->send_ip;
					w_u.w->tseq=c_u.c->tseq;
					w_u.w->mseq=c_u.c->mseq;
					w_u.w->window_size=c_u.c->window;
					w_u.w->flags=TH_ACK|TH_FIN;
					w_u.w->doff=0;
					w_u.w->t_tstamp=c_u.c->t_tstamp;
					w_u.w->m_tstamp=c_u.c->m_tstamp;

					c_u.c->m_tstamp++;

					DBG(M_CON, "setting connection into state closed and sending ACK|FIN");
					fifo_push(pri_work, w_u.ptr);
					s->stats.stream_segments_sent++;

					c_u.c->status=U_TCP_CLOSE;

					fifo_push(pri_work, w_u.ptr);
					s->stats.stream_segments_sent++;
					w_u.ptr=NULL;
					c_u.c->mseq++;
					a_conns--;
				}
				break; /* U_TCP_ESTABLISHED: */

			case U_TCP_CLOSE:
				if (r->type == TH_ACK) {
					break;
				}

				DBG(M_CON, "reseting a packet type %s (no connection entry)", strtcpflgs(r->type));

				s->stats.stream_closed_alien_pkt++;

				w_u.ptr=xmalloc(sizeof(send_pri_workunit_t));
				w_u.w->magic=PRI_4SEND_MAGIC;
				w_u.w->dhost=dhost;
				w_u.w->dport=dport;
				w_u.w->sport=sport;
				w_u.w->shost=c_u.c->send_ip;
				w_u.w->tseq=c_u.c->tseq;
				w_u.w->mseq=c_u.c->mseq;
				w_u.w->window_size=c_u.c->window;
				w_u.w->flags=TH_RST;
				w_u.w->doff=0;
				w_u.w->t_tstamp=c_u.c->t_tstamp;
				w_u.w->m_tstamp=c_u.c->m_tstamp;
				c_u.c->m_tstamp++;

				DBG(M_CON, "reseting packed to closed connection");
				fifo_push(pri_work, w_u.ptr);
				s->stats.stream_segments_sent++;
				w_u.ptr=NULL;
				break; /* U_TCP_CLOSE */

			case U_TCP_FIN_WAIT2:

				if (r->type & TH_FIN) {
					/* ok its closed both ways, lets ack the fin and be done with it */

					c_u.c->tseq += 1;

					w_u.ptr=xmalloc(sizeof(send_pri_workunit_t));
					w_u.w->magic=PRI_4SEND_MAGIC;
					w_u.w->dhost=dhost;
					w_u.w->dport=dport;
					w_u.w->sport=sport;
					w_u.w->shost=c_u.c->send_ip;
					w_u.w->tseq=c_u.c->tseq;
					w_u.w->mseq=c_u.c->mseq;
					w_u.w->window_size=c_u.c->window;
					w_u.w->flags=TH_ACK;
					w_u.w->doff=0;
					w_u.w->t_tstamp=c_u.c->t_tstamp;
					w_u.w->m_tstamp=c_u.c->m_tstamp;
					c_u.c->m_tstamp++;

					c_u.c->status=U_TCP_CLOSE;

					fifo_push(pri_work, w_u.ptr);
					s->stats.stream_segments_sent++;
					w_u.ptr=NULL;
					DBG(M_CON, "Setting connection to closed and acking final fin");
				}
				break; /* U_TCP_FIN_WAIT2 */
# if 0
				if (r->type & (TH_ACK|TH_SYN)) {
				}
				break;
			case U_TCP_FIN_WAIT1:
			case U_TCP_FIN_WAIT2:
			case U_TCP_CLOSING:
			case U_TCP_TIME_WAIT:
			case U_TCP_CLOSE_WAIT:
			case U_TCP_LAST_ACK:
			case U_TCP_CLOSE:
# endif
			default:
				ERR("I have no code. I have no code");
				break;
		}

	} /* found in state table */
	else if ((r->type & (TH_ACK|TH_SYN)) == (TH_ACK|TH_SYN)) { /* should it be in state table */
		DBG(M_CON, "Connection with flags %s", strtcpflgs(r->type));

		/* yes this is a new connection */
		c_u.ptr=xmalloc(sizeof(connection_status_t));
		memset(c_u.ptr, 0, sizeof(connection_status_t));

		c_u.c->status=U_TCP_ESTABLISHED;

		c_u.c->send_ip=shost; /* Our IP */
		c_u.c->recv_len=0;
		c_u.c->send_len=0;
		c_u.c->send_buf=NULL;
		c_u.c->recv_buf=NULL;
		c_u.c->recv_stseq=0;
		c_u.c->tseq=r->tseq;
		c_u.c->mseq=r->mseq;
		c_u.c->window=r->window_size; /* XXX wscale */
		c_u.c->t_tstamp=r->t_tstamp;
		c_u.c->m_tstamp=r->m_tstamp;
		c_u.c->ack_pending=1;

		if (GET_IMMEDIATE()) {
			ia.s_addr=shost;
			snprintf(shost_s, sizeof(shost_s) -1, "%s", inet_ntoa(ia));
			ia.s_addr=dhost;
			VRB(0, "connected %s:%u -> %s:%u", shost_s, sport, inet_ntoa(ia), dport);
		}

		s->stats.stream_connections_est++;

		rbinsert(state_tbl, state_key, c_u.ptr);
		a_conns++;

		send_connect(state_key, c_u.c, pri_work, r);
	} /* looks like something we want to connect to ;] */
	else {
		s->stats.stream_completely_alien_packet++;
		DBG(M_CON, "ignoring packet with flags %s", strtcpflgs(r->type));
	}

	return;
}
Esempio n. 2
0
static void do_connect(ip_report_t *r) {
	char tcpflags[32];
	union {
		void *ptr;
		send_pri_workunit_t *w;
	} w_u;
	union {
		void *ptr;
		connection_status_t *c;
	} c_u;
	union {
		uint8_t *packet;
		ip_report_t *r;
		uint16_t *len;
	} r_u;
	struct in_addr ia;
	size_t pk_len=0;
	uint64_t state_key=0;

	assert(r != NULL);

	state_key=get_connectionkey((const ip_report_t *)r);

	str_tcpflags(&tcpflags[0], r->type);

	if (TBLFIND(state_tbl, state_key, &c_u.ptr) > 0) {
		if (c_u.ptr == NULL) PANIC("state table is a liar");

		if (s->verbose > 5) MSG(M_DBG2, "### I should (reset|ignore) this packet, flags are %s status is %d", tcpflags, c_u.c->status);

		w_u.ptr=xmalloc(sizeof(send_pri_workunit_t));
		w_u.w->magic=PRI_SEND_MAGIC;
		w_u.w->dhost=r->host_addr;
		w_u.w->dport=r->sport;
		w_u.w->sport=r->dport;

		r_u.r=r;

		if (r_u.r->doff) {
			pk_len=r_u.r->doff;
			r_u.packet += sizeof(ip_report_t);
			if (*r_u.len != pk_len) {
				MSG(M_ERR, "report is damaged?!?!?, packet seems broken, sad bunny both ears down");
			}
			else {
				r_u.len++;
				if (pk_len > (sizeof(struct mytcphdr) + sizeof(struct myiphdr))) {
					try_and_extract_tcp_data(r_u.packet, pk_len, c_u.c);
				}
			}
		}

		switch (r->type) {
			case TH_ACK|TH_PSH:
				w_u.w->flags=TH_RST;
				break;
			case TH_ACK:
			case TH_ACK|TH_SYN:
				//xfree(w_u.ptr);
				return;
			default:
				w_u.w->flags=TH_RST;
				if (s->verbose > 4) MSG(M_ERR, "reseting, nothing better to do here yet, flags are `%s'", tcpflags);
				break;
		}

		w_u.w->mseq=r->mseq;
		w_u.w->tseq=r->tseq + (r->window_size / 2); /* increment inside the window somewhere */
		w_u.w->window_size=r->window_size;

		fifo_push(pri_work, w_u.ptr);
	}
	else if ((r->type & (TH_ACK|TH_SYN)) == (TH_ACK|TH_SYN)) {
		if (s->verbose > 5) MSG(M_DBG2, "I should ack this packet, flags are %s", tcpflags);

		w_u.ptr=xmalloc(sizeof(send_pri_workunit_t));
		w_u.w->magic=PRI_SEND_MAGIC;
		w_u.w->dhost=r->host_addr;
		w_u.w->dport=r->sport;
		w_u.w->sport=r->dport;
		w_u.w->tseq=r->tseq + 1;
		w_u.w->mseq=r->mseq;
		w_u.w->window_size=r->window_size;
		w_u.w->flags=TH_ACK;
		fifo_push(pri_work, w_u.ptr);

		c_u.ptr=xmalloc(sizeof(connection_status_t));
		memset(c_u.ptr, 0, sizeof(connection_status_t));

		c_u.c->status=U_TCP_ESTABLISHED;

		c_u.c->recv_len=0;
		c_u.c->send_len=0;
		c_u.c->send_buf=NULL;
		c_u.c->recv_buf=NULL;

		ia.s_addr=w_u.w->dhost;

		if (s->verbose) MSG(M_VERB, "connected %u -> %s:%u", w_u.w->sport, inet_ntoa(ia), w_u.w->dport);

		TBLINSERT(state_tbl, state_key, c_u.ptr);
	}
	else {
		if (s->verbose > 6) MSG(M_DBG2, "do_connect Ignoring packet with flags %s", tcpflags);
	}

	return;
}