📄 spp_stream4.c
字号:
void PreprocRestartFunction(int);void PreprocCleanExitFunction(int);static INLINE int isBetween(u_int32_t low, u_int32_t high, u_int32_t cur);static INLINE int NotForStream4(Packet *p);static INLINE int SetFinSent(Packet *p, Session *ssn, int direction);static INLINE int WithinSessionLimits(Packet *p, Stream *stream); /* helpers for dealing with session byte_counters */static INLINE void StreamSegmentSub(Stream *stream, u_int16_t sub);static INLINE void StreamSegmentAdd(Stream *stream, u_int16_t add);/* Here is where we separate which functions will be called in the normal case versus in the asynchronus state*/ int UpdateState(Session *, Packet *, u_int32_t); int UpdateState2(Session *, Packet *, u_int32_t); int UpdateStateAsync(Session *, Packet *, u_int32_t);static void TcpAction(Session *ssn, Packet *p, int action, int direction, u_int32_t pkt_seq, u_int32_t pkt_ack);static void TcpActionAsync(Session *ssn, Packet *p, int action, int direction, u_int32_t pkt_seq, u_int32_t pkt_ack);/** * See if a sequence number is in range. * * @param low base sequence number * @param high acknowledged sequence number * @param cur sequence number to check * * @return 1 if we are between these sequence numbers, 0 otherwise */static INLINE int isBetween(u_int32_t low, u_int32_t high, u_int32_t cur){ DEBUG_WRAP(DebugMessage(DEBUG_STREAM,"(%u,%u,%u) = (low, high, cur)\n", low,high,cur);); return (cur - low) <= (high - low);}#ifdef USE_HASH_TABLE#else /* USE_SPLAY_TREE */int GetSessionCount(){ return ubi_trCount(RootPtr);}static int CompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr){ Session *nSession; Session *iSession; nSession = ((Session *)NodePtr); iSession = (Session *)ItemPtr; if(nSession->server.ip < iSession->server.ip) return 1; else if(nSession->server.ip > iSession->server.ip) return -1; if(nSession->client.ip < iSession->client.ip) return 1; else if(nSession->client.ip > iSession->client.ip) return -1; if(nSession->server.port < iSession->server.port) return 1; else if(nSession->server.port > iSession->server.port) return -1; if(nSession->client.port < iSession->client.port) return 1; else if(nSession->client.port > iSession->client.port) return -1; return 0;}#endif/** * Check to if retransmissions are occuring too quickly * * @param old previous timeval * @param cur current timeval * * @return 1 if the Retransmission is too quick, 0 if it's ok */static int RetransTooFast(struct timeval *old, struct timeval *cur){ struct timeval diff; TIMERSUB(cur, old, &diff); /* require retransmissions wait atleast 1.1s */ if(diff.tv_sec > 1) return 0; else if(diff.tv_sec == 1 && diff.tv_usec > 100) return 0; return 1;}static int DataCompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr){ StreamPacketData *nStream; StreamPacketData *iStream; nStream = ((StreamPacketData *)NodePtr); iStream = ((StreamPacketData *)ItemPtr); if(nStream->seq_num < iStream->seq_num) return 1; else if(nStream->seq_num > iStream->seq_num) return -1; return 0;}static int OverlapCompareFunc(ubi_trItemPtr ItemPtr, void *data){ OverlapData *overlap_info = (OverlapData *)data; StreamPacketData *iStream; iStream = ((StreamPacketData *)ItemPtr); if ((iStream->seq_num > overlap_info->seq_low) && (iStream->seq_num < overlap_info->seq_hi)) return 1; return 0;}static void KillSpd(ubi_trNodePtr NodePtr){ StreamPacketData *tmp; tmp = (StreamPacketData *)NodePtr; stream4_memory_usage -= tmp->pkt_size; free(tmp->pktOrig); stream4_memory_usage -= sizeof(StreamPacketData); free(tmp);}static void TraverseFunc(ubi_trNodePtr NodePtr, void *build_data){ Stream *s; StreamPacketData *spd; BuildData *bd; u_int8_t *buf; int trunc_size; int offset = 0; if(s4data.stop_traverse) return; spd = (StreamPacketData *) NodePtr; bd = (BuildData *) build_data; s = bd->stream; buf = bd->buf; /* Don't reassemble if there's nothing to reassemble. * The first two cases can probably never happen. I personally * prefer strong error checking (read: paranoia). */ if(spd->payload_size == 0) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "not reassembling because " "the payload size is zero.\n");); spd->chuck = SEG_FULL; return; } else if(SEQ_EQ(s->base_seq, s->last_ack)) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "not reassembling because " "base_seq = last_ack (%u).\n", s->base_seq);); return; } /* Packet is completely before the current window. */ else if(SEQ_LEQ(spd->seq_num, s->base_seq) && SEQ_LEQ(spd->seq_num + spd->payload_size, s->base_seq)) { /* ignore this segment, we've already looked at it */ spd->chuck = SEG_FULL; return; } /* Packet starts outside the window and ends inside it. */ else if(SEQ_LT(spd->seq_num, s->base_seq) && isBetween(s->base_seq+1, s->last_ack, (spd->seq_num + spd->payload_size))) { /* case where we've got a segment that wasn't completely ack'd * last time it was processed, do a partial copy into the buffer */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Incompleted segment, copying up " "to last-ack\n");); /* calculate how much un-ack'd data to copy */ trunc_size = (spd->seq_num+spd->payload_size) - s->base_seq; /* figure out where in the original data payload to start copying */ offset = s->base_seq - spd->seq_num; if(trunc_size < 65500 && trunc_size > 0) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Copying %d bytes into buffer, " "offset %d, buf %p\n", trunc_size, offset, buf);); SafeMemcpy(buf, spd->payload+offset, trunc_size, stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE); pc.rebuilt_segs++; bd->total_size += trunc_size; } else { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Woah, got bad TCP segment " "trunctation value (%d)\n", trunc_size);); } spd->chuck = SEG_FULL; } /* if it's in bounds... */ else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) && isBetween(s->base_seq, s->last_ack, (spd->seq_num + spd->payload_size))) { offset = spd->seq_num - s->base_seq; s->next_seq = spd->seq_num + spd->payload_size; DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Copying %d bytes into buffer, " "offset %d, buf %p\n", spd->payload_size, offset, buf);); DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "spd->seq_num (%u) s->last_ack (%u) " "s->base_seq(%u) size: (%u) s->next_seq(%u), " "offset(%u), MAX(%u)\n", spd->seq_num, s->last_ack, s->base_seq, spd->payload_size, s->next_seq, offset, MAX_STREAM_SIZE)); SafeMemcpy(buf+offset, spd->payload, spd->payload_size, stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE); pc.rebuilt_segs++; spd->chuck = SEG_FULL; bd->total_size += spd->payload_size; } else if(isBetween(s->base_seq, s->last_ack-1, spd->seq_num) && SEQ_GT((spd->seq_num + spd->payload_size), s->last_ack)) { /* * if it starts in bounds and hasn't been completely ack'd, * truncate the last piece and copy it in */ trunc_size = s->last_ack - spd->seq_num; DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Truncating overlap of %d bytes\n", spd->seq_num + spd->payload_size - s->last_ack); DebugMessage(DEBUG_STREAM, " => trunc info seq: 0x%X " "size: %d last_ack: 0x%X\n", spd->seq_num, spd->payload_size, s->last_ack); ); offset = spd->seq_num - s->base_seq; if(trunc_size < (65500-offset) && trunc_size > 0) { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Copying %d bytes into buffer, " "offset %d, buf %p\n", trunc_size, offset, buf);); SafeMemcpy(buf+offset, spd->payload, trunc_size, stream_pkt->data, stream_pkt->data + MAX_STREAM_SIZE); pc.rebuilt_segs++; bd->total_size += trunc_size; spd->chuck = SEG_PARTIAL; } else { DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Woah, got bad TCP segment " "trunctation value (%d)\n", trunc_size);); } } else if(SEQ_GEQ(spd->seq_num,s->last_ack)) { /* we're all done, we've walked past the end of the ACK'd data */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM, " => Segment is past last ack'd data, " "ignoring for now...\n"); DebugMessage(DEBUG_STREAM, " => (%d bytes @ seq 0x%X, " "ack: 0x%X)\n", spd->payload_size, spd->seq_num, s->last_ack); ); /* since we're reassembling in order, once we hit an overflow condition * let's stop trying for now */ s4data.stop_traverse = 1; //s4data.stop_seq = spd->seq_num; s4data.stop_seq = s->last_ack; } else { /* The only case that should reach this point is if * spd->seq_num < s->base_seq && * spd->seq_num + spd->payload_size >= s->last_ack * Can that ever happen? */ DEBUG_WRAP(DebugMessage(DEBUG_STREAM, "Ended up in the default case somehow.. !\n" "spd->seq_num(%u) spd->payload_size(%u)\n", spd->seq_num, spd->payload_size);); }} void SegmentCleanTraverse(Stream *s){ StreamPacketData *spd; StreamPacketData *foo; if (!s->data.root) return; spd = (StreamPacketData *) ubi_btFirst((ubi_btNodePtr)&s->data); while(spd != NULL) { if(spd->chuck == SEG_FULL || SEQ_GEQ(s->last_ack,(spd->seq_num+spd->payload_size))) { StreamPacketData *savspd = spd; spd = (StreamPacketData *) ubi_btNext((ubi_btNodePtr)spd);#ifdef DEBUG if(savspd->chuck == SEG_FULL) { DebugMessage(DEBUG_STREAM, "[sct] chucking used segment\n"); } else { DebugMessage(DEBUG_STREAM, "[sct] tossing unused segment\n"); }#endif /*DEBUG*/ foo = (StreamPacketData *) ubi_sptRemove(&s->data, (ubi_btNodePtr) savspd); StreamSegmentSub(s, foo->payload_size); stream4_memory_usage -= foo->pkt_size; free(foo->pktOrig); stream4_memory_usage -= sizeof(StreamPacketData); free(foo); } else { spd = (StreamPacketData *) ubi_btNext((ubi_btNodePtr)spd); } }}/* XXX: this will be removed as we clean up the modularization */void DirectLogTcpdump(struct pcap_pkthdr *, u_int8_t *);static void LogTraverse(ubi_trNodePtr NodePtr, void *foo){ StreamPacketData *spd; spd = (StreamPacketData *) NodePtr; /* XXX: modularization violation */ DirectLogTcpdump((struct pcap_pkthdr *)&spd->pkth, spd->pkt); }void *SafeAlloc(unsigned long size, int tv_sec, Session *ssn){ void *tmp; stream4_memory_usage += size; /* if we use up all of our RAM, try to free up some stale sessions */ if(stream4_memory_usage > s4data.memcap) { pc.str_mem_faults++; sfPerf.sfBase.iStreamFaults++; if(!PruneSessionCache((u_int32_t)tv_sec, 0, ssn)) { /* if we can't prune due to time, just nuke 5 random sessions */ PruneSessionCache(0, 5, ssn); } } tmp = (void *) calloc(size, sizeof(char)); if(tmp == NULL) { FatalError("Unable to allocate memory! (%lu bytes in use)\n", (unsigned long)stream4_memory_usage); } return tmp;}/* * Function: SetupStream4() * * Purpose: Registers the preprocessor keyword and initialization * function into the preprocessor list. This is the function that * gets called from InitPreprocessors() in plugbase.c. * * Arguments: None. * * Returns: void function */void SetupStream4(){ /* link the preprocessor keyword to the init function in the preproc list */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -