void connect_grabbanners(ip_report_t *r) { union { void *ptr; connection_status_t *c; } c_u; uint64_t state_key=0; uint8_t *c_ptr=NULL; output_data_t *e_out=NULL; char pchars[256]; size_t p_off=0, j=0; state_key=get_connectionkey(r); if (rbfind(state_tbl, state_key, &c_u.ptr) > 0) { memset(pchars, 0, sizeof(pchars)); for (j=0, p_off=0, c_ptr=c_u.c->recv_buf; j < c_u.c->recv_len; j++, c_ptr++) { if (isgraph(*c_ptr) || *c_ptr == ' ') { pchars[p_off++]=(char )*c_ptr; } if (p_off > (sizeof(pchars) -2)) break; } if (p_off > 0) { e_out=(output_data_t *)xmalloc(sizeof(output_data_t)); e_out->type=OD_TYPE_BANNER; e_out->t_u.banner=xstrdup(pchars); fifo_push(r->od_q, (void *)e_out); } } return; }
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; }
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; }
/* destructive */ static char *get_report_extra(ip_report_t *r) { static char out[512]; size_t out_off=0; int sret=0; union { void *ptr; output_data_t *d; } d_u; assert(r != NULL); CLEAR(out); if (r->od_q == NULL) { PANIC("i have no legs"); } while ((d_u.ptr=fifo_pop(r->od_q)) != NULL) { /* XXX this needs to be a bit more flexable than what it is (only checking 1 type, etc) */ sret=snprintf(&out[out_off], (sizeof(out) - (out_off + 1)), "%s", (d_u.d->type == OD_TYPE_OS ? d_u.d->t_u.os : d_u.d->t_u.banner)); if (sret < 1) break; out_off += sret; if (out_off >= (sizeof(out) -1)) { /* malloc is for girls ;] hide rms this function has serious limits */ MSG(M_ERR, "Report Buffer is overflowing, breaking, ask author to not be so wordy next time"); break; } xfree(d_u.ptr); } if (GET_DOCONNECT()) { uint64_t state_key=0; union { void *ptr; connection_status_t *c; } c_u; uint8_t pchars[256], *c_ptr=NULL; size_t p_off=0; size_t j=0; state_key=get_connectionkey(r); if (TBLFIND(state_tbl, state_key, &c_u.ptr) > 0) { memset(pchars, 0, sizeof(pchars)); for (j=0, p_off=0, c_ptr=c_u.c->recv_buf ; j < c_u.c->recv_len ; j++, c_ptr++) { if (isprint(*c_ptr)) { pchars[p_off++]=*c_ptr; } if (p_off > (sizeof(pchars) -1)) break; } if (p_off > 0) { snprintf(&out[out_off], sizeof(out) - (out_off + 1), " `%s'", pchars); } } } if (strlen(out)) return &out[0]; return NULL; }