/* print the contents of this packet to the console */ void print_packet(flow_t flow, const u_char *data, u_int32_t length) { printf("%s: ", flow_filename(flow)); fwrite(data, length, 1, stdout); putchar('\n'); fflush(stdout); }
/* print the contents of this packet to the console */ void print_packet(flow_t flow, flow_state_t *state, const u_char *data, u_int32_t length) { int current_color = 0; /* Colors: green, blue, red */ char *color[3] = { "\033[0;32m", "\033[0;34m", "\033[0;31m" }; if (use_color) { if (IS_SET(state->flags, FLOW_DIR_CS)) current_color = 1; else if (IS_SET(state->flags, FLOW_DIR_SC)) current_color = 2; printf("%s", color[current_color]); } if (suppress_header == 0) printf("%s: ", flow_filename(flow)); fwrite(data, length, 1, stdout); if (use_color) printf("\033[0m"); putchar('\n'); fflush(stdout); }
/* Closes the file belonging to a flow -- returns 1 if a file was * actually closed, 0 otherwise (if it was already closed) */ int close_file(flow_state_t *flow_state) { if (flow_state->fp == NULL) return 0; DEBUG(5) ("%s: closing file", flow_filename(flow_state->flow)); /* close the file and remember that it's closed */ fclose(flow_state->fp); flow_state->fp = NULL; flow_state->pos = 0; return 1; }
/* Sort FDs in the fd_table according to the comparison function (see * comment above) */ void sort_fds() { qsort(fd_ring, max_fds, sizeof(struct flow_state_t *), flow_state_compare); #if 0 /* code to dump the table - for debugging */ { int i; for(i = 0; i < max_fds; i++) { if (fd_ring[i] == NULL) continue; else fprintf(stderr, "fd_slot %d: %s (lasttime=%d)\n", i, flow_filename(fd_ring[i]->flow), fd_ring[i]->last_access); } } #endif }
/* Create a new flow state structure, initialize its contents, and add * it to its hash bucket. It is prepended to the hash bucket because * 1) doing so is fast (requiring constant time regardless of bucket * size; and 2) it'll tend to make lookups faster for more recently * added state, which will probably be more often used state. * * Returns a pointer to the new state. */ flow_state_t *create_flow_state(flow_t flow, tcp_seq isn) { /* create space for the new state */ flow_state_t *new_flow = MALLOC(flow_state_t, 1); /* determine where in the hash this goes */ int index = HASH_FLOW(flow); /* link it in to the hash bucket at the beginning */ new_flow->next = flow_hash[index]; flow_hash[index] = new_flow; /* initialize contents of the state structure */ new_flow->flow = flow; new_flow->isn = isn; new_flow->fp = NULL; new_flow->pos = 0; new_flow->flags = 0; new_flow->last_access = current_time++; DEBUG(5) ("%s: new flow", flow_filename(flow)); return new_flow; }
FILE *open_file(flow_state_t *flow_state) { char *filename = flow_filename(flow_state->flow); int done; /* This shouldn't be called if the file is already open */ if (flow_state->fp) { DEBUG(20) ("huh -- trying to open already open file!"); return flow_state->fp; } /* Now try and open the file */ do { if (attempt_fopen(flow_state, filename) != NULL) { /* open succeeded... great */ done = 1; } else { if (errno == ENFILE || errno == EMFILE) { /* open failed because too many files are open... close one and try again */ contract_fd_ring(); DEBUG(5) ("too many open files -- contracting FD ring to %d", max_fds); done = 0; } else { /* open failed for some other reason... give up */ done = 1; } } } while (!done); /* If the file isn't open at this point, there's a problem */ if (flow_state->fp == NULL) { /* we had some problem opening the file -- set FINISHED so we * don't keep trying over and over again to reopen it */ SET_BIT(flow_state->flags, FLOW_FINISHED); perror(filename); return NULL; } /* Now we decide which FD slot we use, and close the file that's * there (if any). Note that even if flow_state is not NULL, its * associated file pointer may already be closed. Note well that we * DO NOT free the state that we find in our slot; the state stays * around forever (pointed to by the hash table). This table only * keeps a pointer to state structures that have open files so that * we can close them later. * * We are putting the close after the open so that we don't bother * closing files if the open fails. (For this, we pay a price of * needing to keep a spare, idle FD around.) */ if (++next_slot == max_fds) { /* take this opportunity to sort from oldest to newest -- * optimally we'd like to do this before every close, but that * might take too long. */ sort_fds(); next_slot = 0; } /* close the next one in line */ if (fd_ring[next_slot] != NULL) close_file(fd_ring[next_slot]); /* put ourslves in its place */ fd_ring[next_slot] = flow_state; /* set flags and remember where in the file we are */ SET_BIT(flow_state->flags, FLOW_FILE_EXISTS); FGETPOS(flow_state->fp, &(flow_state->pos)); return flow_state->fp; }
/* store the contents of this packet to its place in its file */ void store_packet(flow_t flow, const u_char *data, u_int32_t length, u_int32_t seq) { flow_state_t *state; tcp_seq offset; long fpos; /* see if we have state about this flow; if not, create it */ if ((state = find_flow_state(flow)) == NULL) { state = create_flow_state(flow, seq); } /* if we're done collecting for this flow, return now */ if (IS_SET(state->flags, FLOW_FINISHED)) return; /* calculate the offset into this flow -- should handle seq num * wrapping correctly because tcp_seq is the right size */ offset = seq - state->isn; /* I want to guard against receiving a packet with a sequence number * slightly less than what we consider the ISN to be; the max * (though admittedly non-scaled) window of 64K should be enough */ if (offset >= 0xffff0000) { DEBUG(2) ("dropped packet with seq < isn on %s", flow_filename(flow)); return; } /* reject this packet if it falls entirely outside of the range of * bytes we want to receive for the flow */ if (bytes_per_flow && (offset > bytes_per_flow)) return; /* if we don't have a file open for this flow, try to open it. * return if the open fails. Note that we don't have to explicitly * save the return value because open_file() puts the file pointer * into the structure for us. */ if (state->fp == NULL) { if (open_file(state) == NULL) { return; } } /* We are go for launch! Everything's ready for us to do a write. */ /* reduce length if it goes beyond the number of bytes per flow */ if (bytes_per_flow && (offset + length > bytes_per_flow)) { SET_BIT(state->flags, FLOW_FINISHED); length = bytes_per_flow - offset; } /* if we're not at the correct point in the file, seek there */ if (offset != state->pos) { fpos = offset; FSETPOS(state->fp, &fpos); } /* write the data into the file */ DEBUG(25) ("%s: writing %ld bytes @%ld", flow_filename(state->flow), (long) length, (long) offset); if (fwrite(data, length, 1, state->fp) != 1) { /* sigh... this should be a nice, plain DEBUG statement that * passes strerrror() as an argument, but SunOS 4.1.3 doesn't seem * to have strerror. */ if (debug_level >= 1) { DEBUG(1) ("write to %s failed: ", flow_filename(state->flow)); perror(""); } } fflush(state->fp); /* remember the position for next time */ state->pos = offset + length; if (IS_SET(state->flags, FLOW_FINISHED)) { DEBUG(5) ("%s: stopping capture", flow_filename(state->flow)); close_file(state); } }