📄 savefile.c
字号:
*
* In addition, DG/UX tcpdump writes out files with a version
* number of 543.0, and with the caplen and len fields in the
* pre-2.3 order.
*/
switch (hdr.version_major) {
case 2:
if (hdr.version_minor < 3)
p->sf.lengths_swapped = SWAPPED;
else if (hdr.version_minor == 3)
p->sf.lengths_swapped = MAYBE_SWAPPED;
else
p->sf.lengths_swapped = NOT_SWAPPED;
break;
case 543:
p->sf.lengths_swapped = SWAPPED;
break;
default:
p->sf.lengths_swapped = NOT_SWAPPED;
break;
}
#ifndef WIN32
/*
* You can do "select()" and "poll()" on plain files on most
* platforms, and should be able to do so on pipes.
*
* You can't do "select()" on anything other than sockets in
* Windows, so, on Win32 systems, we don't have "selectable_fd".
*/
p->selectable_fd = fileno(fp);
#endif
p->read_op = pcap_offline_read;
p->setfilter_op = install_bpf_program;
p->set_datalink_op = NULL; /* we don't support munging link-layer headers */
p->getnonblock_op = sf_getnonblock;
p->setnonblock_op = sf_setnonblock;
p->stats_op = sf_stats;
p->close_op = sf_close;
return (p);
bad:
if(fp)
fclose(fp);
free(p);
return (NULL);
}
/*
* Read sf_readfile and return the next packet. Return the header in hdr
* and the contents in buf. Return 0 on success, SFERR_EOF if there were
* no more packets, and SFERR_TRUNC if a partial packet was encountered.
*/
static int
sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, u_int buflen)
{
struct pcap_sf_patched_pkthdr sf_hdr;
FILE *fp = p->sf.rfile;
size_t amt_read;
bpf_u_int32 t;
/*
* Read the packet header; the structure we use as a buffer
* is the longer structure for files generated by the patched
* libpcap, but if the file has the magic number for an
* unpatched libpcap we only read as many bytes as the regular
* header has.
*/
amt_read = fread(&sf_hdr, 1, p->sf.hdrsize, fp);
if (amt_read != p->sf.hdrsize) {
if (ferror(fp)) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"error reading dump file: %s",
pcap_strerror(errno));
return (-1);
} else {
if (amt_read != 0) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"truncated dump file; tried to read %d header bytes, only got %lu",
p->sf.hdrsize, (unsigned long)amt_read);
return (-1);
}
/* EOF */
return (1);
}
}
if (p->sf.swapped) {
/* these were written in opposite byte order */
hdr->caplen = SWAPLONG(sf_hdr.caplen);
hdr->len = SWAPLONG(sf_hdr.len);
hdr->ts.tv_sec = SWAPLONG(sf_hdr.ts.tv_sec);
hdr->ts.tv_usec = SWAPLONG(sf_hdr.ts.tv_usec);
} else {
hdr->caplen = sf_hdr.caplen;
hdr->len = sf_hdr.len;
hdr->ts.tv_sec = sf_hdr.ts.tv_sec;
hdr->ts.tv_usec = sf_hdr.ts.tv_usec;
}
/* Swap the caplen and len fields, if necessary. */
switch (p->sf.lengths_swapped) {
case NOT_SWAPPED:
break;
case MAYBE_SWAPPED:
if (hdr->caplen <= hdr->len) {
/*
* The captured length is <= the actual length,
* so presumably they weren't swapped.
*/
break;
}
/* FALLTHROUGH */
case SWAPPED:
t = hdr->caplen;
hdr->caplen = hdr->len;
hdr->len = t;
break;
}
if (hdr->caplen > buflen) {
/*
* This can happen due to Solaris 2.3 systems tripping
* over the BUFMOD problem and not setting the snapshot
* correctly in the savefile header. If the caplen isn't
* grossly wrong, try to salvage.
*/
static u_char *tp = NULL;
static size_t tsize = 0;
if (hdr->caplen > 65535) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"bogus savefile header");
return (-1);
}
if (tsize < hdr->caplen) {
tsize = ((hdr->caplen + 1023) / 1024) * 1024;
if (tp != NULL)
free((u_char *)tp);
tp = (u_char *)malloc(tsize);
if (tp == NULL) {
tsize = 0;
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"BUFMOD hack malloc");
return (-1);
}
}
amt_read = fread((char *)tp, 1, hdr->caplen, fp);
if (amt_read != hdr->caplen) {
if (ferror(fp)) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"error reading dump file: %s",
pcap_strerror(errno));
} else {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"truncated dump file; tried to read %u captured bytes, only got %lu",
hdr->caplen, (unsigned long)amt_read);
}
return (-1);
}
/*
* We can only keep up to buflen bytes. Since caplen > buflen
* is exactly how we got here, we know we can only keep the
* first buflen bytes and must drop the remainder. Adjust
* caplen accordingly, so we don't get confused later as
* to how many bytes we have to play with.
*/
hdr->caplen = buflen;
memcpy((char *)buf, (char *)tp, buflen);
} else {
/* read the packet itself */
amt_read = fread((char *)buf, 1, hdr->caplen, fp);
if (amt_read != hdr->caplen) {
if (ferror(fp)) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"error reading dump file: %s",
pcap_strerror(errno));
} else {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"truncated dump file; tried to read %u captured bytes, only got %lu",
hdr->caplen, (unsigned long)amt_read);
}
return (-1);
}
}
return (0);
}
/*
* Print out packets stored in the file initialized by sf_read_init().
* If cnt > 0, return after 'cnt' packets, otherwise continue until eof.
*/
int
pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
struct bpf_insn *fcode = p->fcode.bf_insns;
int status = 0;
int n = 0;
#ifdef HAVE_REMOTE
static int samp_npkt; // parameter needed for sampling, whtn '1 out of N' method has been requested
static struct timeval samp_time; // parameter needed for sampling, whtn '1 every N ms' method has been requested
#endif /* HAVE_REMOTE */
while (status == 0) {
struct pcap_pkthdr h;
/*
* Has "pcap_breakloop()" been called?
* If so, return immediately - if we haven't read any
* packets, clear the flag and return -2 to indicate
* that we were told to break out of the loop, otherwise
* leave the flag set, so that the *next* call will break
* out of the loop without having read any packets, and
* return the number of packets we've processed so far.
*/
if (p->break_loop) {
if (n == 0) {
p->break_loop = 0;
return (-2);
} else
return (n);
}
status = sf_next_packet(p, &h, p->buffer, p->bufsize);
if (status) {
if (status == 1)
return (0);
return (status);
}
if (fcode == NULL ||
bpf_filter(fcode, p->buffer, h.len, h.caplen)) {
#ifdef HAVE_REMOTE
if (p->rmt_samp.method == PCAP_SAMP_1_EVERY_N)
{
samp_npkt= (samp_npkt + 1) % p->rmt_samp.value;
// Discard all packets that are not '1 out of N'
if (samp_npkt != 0)
continue;
}
if (p->rmt_samp.method == PCAP_SAMP_FIRST_AFTER_N_MS)
{
// Check if the timestamp of the arrived packet is smaller than our target time
if ( (h.ts.tv_sec < samp_time.tv_sec) ||
( (h.ts.tv_sec == samp_time.tv_sec) && (h.ts.tv_usec < samp_time.tv_usec) ) )
continue;
// The arrived packet is suitable for being sent to the remote host
// So, let's update the target time
samp_time.tv_usec= h.ts.tv_usec + p->rmt_samp.value * 1000;
if (samp_time.tv_usec > 1000000)
{
samp_time.tv_sec= h.ts.tv_sec + samp_time.tv_usec / 1000000;
samp_time.tv_usec= samp_time.tv_usec % 1000000;
}
}
#endif /* HAVE_REMOTE */
(*callback)(user, &h, p->buffer);
if (++n >= cnt && cnt > 0)
break;
}
}
/*XXX this breaks semantics tcpslice expects */
return (n);
}
/*
* Output a packet to the initialized dump file.
*/
void
pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
{
register FILE *f;
struct pcap_sf_pkthdr sf_hdr;
f = (FILE *)user;
sf_hdr.ts.tv_sec = h->ts.tv_sec;
sf_hdr.ts.tv_usec = h->ts.tv_usec;
sf_hdr.caplen = h->caplen;
sf_hdr.len = h->len;
/* XXX we should check the return status */
(void)fwrite(&sf_hdr, sizeof(sf_hdr), 1, f);
(void)fwrite((char *)sp, h->caplen, 1, f);
}
/*
* Initialize so that sf_write() will output to the file named 'fname'.
*/
pcap_dumper_t *
pcap_dump_open(pcap_t *p, const char *fname)
{
FILE *f;
int linktype;
linktype = dlt_to_linktype(p->linktype);
if (linktype == -1) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"%s: link-layer type %d isn't supported in savefiles",
fname, linktype);
return (NULL);
}
if (fname[0] == '-' && fname[1] == '\0') {
f = stdout;
#ifdef WIN32
_setmode(_fileno(f), _O_BINARY);
#endif
} else {
#ifndef WIN32
f = fopen(fname, "w");
#else
f = fopen(fname, "wb");
#endif
if (f == NULL) {
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
fname, pcap_strerror(errno));
return (NULL);
}
#ifdef WIN32
setbuf(f, NULL); /* XXX - why? */
#endif
}
(void)sf_write_header(f, linktype, p->tzoff, p->snapshot);
return ((pcap_dumper_t *)f);
}
FILE *
pcap_dump_file(pcap_dumper_t *p)
{
return ((FILE *)p);
}
int
pcap_dump_flush(pcap_dumper_t *p)
{
if (fflush((FILE *)p) == EOF)
return (-1);
else
return (0);
}
void
pcap_dump_close(pcap_dumper_t *p)
{
#ifdef notyet
if (ferror((FILE *)p))
return-an-error;
/* XXX should check return from fclose() too */
#endif
(void)fclose((FILE *)p);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -