281 lines
6.3 KiB
C
281 lines
6.3 KiB
C
/*
|
|
* Operating System interface to the "Etherfind" program.
|
|
* Code in this module should be NOT specific to a particlar protocol.
|
|
*
|
|
* @(#)nit_streams.c 1.1 94/10/31
|
|
*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/file.h>
|
|
#include <net/if.h>
|
|
|
|
#include <sys/stropts.h>
|
|
|
|
#include <net/nit_if.h>
|
|
#include <net/nit_buf.h>
|
|
|
|
#include "etherfind.h"
|
|
|
|
#define NIT_DEV "/dev/nit"
|
|
|
|
/*
|
|
* We use this value for the chunk size when grabbing all
|
|
* of every packet. Otherwise, we base chunk size on snaplen.
|
|
*/
|
|
#define CHUNKSIZE 8192
|
|
#define MINCHUNK 1500 /* grab at least this much */
|
|
|
|
/*
|
|
* SNAPLEN gives the maximum amount of any packet that we
|
|
* need see, unless the -v, -l or -r flag has been specified.
|
|
*/
|
|
#define SNAPLEN (44)
|
|
|
|
int if_fd = -1;
|
|
u_int chunksize;
|
|
int printlength; /* bytes to print with x flag */
|
|
int snaplen = SNAPLEN;
|
|
|
|
extern char *strncpy();
|
|
extern char *malloc();
|
|
|
|
main_loop(device)
|
|
char *device;
|
|
{
|
|
u_long if_flags = 0;
|
|
int cc;
|
|
char *buf;
|
|
|
|
/*
|
|
* Calculate snapshot length to use based on which headers we're
|
|
* to dig information from. A value of zero means to return
|
|
* everything. If we set snaplen nonzero, we must arrange to
|
|
* get the nit_if-level nit_iflen header as well, to get the
|
|
* original packet's length.
|
|
*/
|
|
snaplen = SNAPLEN;
|
|
if (rpcflag[0] || symflag[0] || (xflag[0] && printlength==0)) {
|
|
/*
|
|
* Need Ethernet header, IP header, TCP/UDP header, and
|
|
* RPC header. But: for now, just punt and grab everything.
|
|
*/
|
|
snaplen = 0;
|
|
}
|
|
else if (printlength > snaplen)
|
|
snaplen = printlength;
|
|
|
|
/*
|
|
* Calculate a chunk size appropriate for the snapshot length
|
|
* at hand. The values used here are heuristics. The chunk
|
|
* size is used to determine how much buffer space we allocate
|
|
* and therfore must be large enough to hold the largest single
|
|
* message the buffering module might hand us. To be safe, we
|
|
* force it to be at least the maximum Ethernet packet length.
|
|
*/
|
|
if (snaplen == 0)
|
|
chunksize = CHUNKSIZE;
|
|
else
|
|
chunksize = 80 * snaplen;
|
|
if (chunksize < MINCHUNK)
|
|
chunksize = MINCHUNK;
|
|
|
|
/*
|
|
* Use malloc to obtain input buffer, so that the buffer
|
|
* is aligned correctly for structures cast over its start.
|
|
* The buffer size depends on the snapshot length in effect.
|
|
*/
|
|
if ((buf = malloc(chunksize)) == NULL) {
|
|
fprintf(stderr, "etherfind: couldn't allocate buffer space\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
if (dflag)
|
|
if_flags |= NI_DROPS;
|
|
if (!pflag)
|
|
if_flags |= NI_PROMISC;
|
|
if (tflag)
|
|
if_flags |= NI_TIMESTAMP;
|
|
if (snaplen > 0)
|
|
if_flags |= NI_LEN;
|
|
initdevice(device, if_flags, snaplen);
|
|
|
|
while ((cc = read(if_fd, buf, (int)chunksize)) >= 0) {
|
|
register char *bp = buf,
|
|
*bufstop = buf + cc;
|
|
|
|
#ifdef DEBUG
|
|
(void) fflush (stdout);
|
|
fprintf(stderr, "==> %d\n", cc);
|
|
(void) fflush(stderr);
|
|
#endif DEBUG
|
|
|
|
/*
|
|
* Loop through each message in the chunk.
|
|
*/
|
|
while (bp < bufstop) {
|
|
register char *cp = bp;
|
|
struct nit_bufhdr *hdrp;
|
|
struct timeval *tvp = NULL;
|
|
u_long drops = 0;
|
|
u_long pktlen;
|
|
|
|
/*
|
|
* Extract information from the successive objects
|
|
* embedded in the current message. Which ones we
|
|
* have depends on how we set up the stream (and
|
|
* therefore on what command line flags were set).
|
|
*
|
|
* If snaplen is positive then the packet was truncated
|
|
* before the buffering module saw it, so we must
|
|
* obtain its length from the nit_if-level nit_iflen
|
|
* header. Otherwise the value in *hdrp suffices.
|
|
*/
|
|
hdrp = (struct nit_bufhdr *)cp;
|
|
cp += sizeof *hdrp;
|
|
if (tflag) {
|
|
struct nit_iftime *ntp;
|
|
|
|
ntp = (struct nit_iftime *)cp;
|
|
cp += sizeof *ntp;
|
|
|
|
tvp = &ntp->nh_timestamp;
|
|
}
|
|
if (dflag) {
|
|
struct nit_ifdrops *ndp;
|
|
|
|
ndp = (struct nit_ifdrops *)cp;
|
|
cp += sizeof *ndp;
|
|
|
|
drops = ndp->nh_drops;
|
|
}
|
|
if (snaplen > 0) {
|
|
struct nit_iflen *nlp;
|
|
|
|
nlp = (struct nit_iflen *)cp;
|
|
cp += sizeof *nlp;
|
|
|
|
pktlen = nlp->nh_pktlen;
|
|
}
|
|
else
|
|
pktlen = hdrp->nhb_msglen;
|
|
|
|
bp += hdrp->nhb_totlen;
|
|
|
|
sp_ts_len = pktlen;
|
|
|
|
/*
|
|
* Process the packet.
|
|
* (now done in separate module)
|
|
*/
|
|
filter(0, cp, sp_ts_len, tvp, drops);
|
|
}
|
|
}
|
|
perror("etherfind read error");
|
|
exit(-1);
|
|
}
|
|
|
|
initdevice(device, if_flags, snaplen)
|
|
char *device;
|
|
u_long if_flags,
|
|
snaplen;
|
|
{
|
|
struct strioctl si;
|
|
struct ifreq ifr;
|
|
struct timeval timeout;
|
|
|
|
if (if_fd >= 0)
|
|
return; /* already open */
|
|
|
|
if ((if_fd = open(NIT_DEV, O_RDONLY)) < 0) {
|
|
perror("nit open");
|
|
exit (1);
|
|
}
|
|
|
|
/*
|
|
* Arrange to get discrete messages from the stream.
|
|
*/
|
|
if (ioctl(if_fd, I_SRDOPT, (char *)RMSGD) < 0) {
|
|
perror("ioctl (I_SRDOPT)");
|
|
exit (1);
|
|
}
|
|
|
|
si.ic_timout = INFTIM;
|
|
|
|
/*
|
|
* Push and configure the buffering module.
|
|
*/
|
|
if (ioctl(if_fd, I_PUSH, "nbuf") < 0) {
|
|
perror("ioctl (I_PUSH \"nbuf\")");
|
|
exit (1);
|
|
}
|
|
|
|
timeout.tv_sec = 1;
|
|
timeout.tv_usec = 0;
|
|
si.ic_cmd = NIOCSTIME;
|
|
si.ic_len = sizeof timeout;
|
|
si.ic_dp = (char *)&timeout;
|
|
if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
|
|
perror("ioctl (I_STR: NIOCSTIME)");
|
|
exit (1);
|
|
}
|
|
|
|
si.ic_cmd = NIOCSCHUNK;
|
|
si.ic_len = sizeof chunksize;
|
|
si.ic_dp = (char *)&chunksize;
|
|
if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
|
|
perror("ioctl (I_STR: NIOCSCHUNK)");
|
|
exit (1);
|
|
}
|
|
|
|
/*
|
|
* Configure the nit device, binding it to the proper
|
|
* underlying interface, setting the snapshot length,
|
|
* and setting nit_if-level flags.
|
|
*/
|
|
(void) strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
|
|
ifr.ifr_name[sizeof ifr.ifr_name - 1] = '\0';
|
|
si.ic_cmd = NIOCBIND;
|
|
si.ic_len = sizeof ifr;
|
|
si.ic_dp = (char *)𝔦
|
|
if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
|
|
perror("ioctl (I_STR: NIOCBIND)");
|
|
exit(1);
|
|
}
|
|
|
|
if (snaplen > 0) {
|
|
si.ic_cmd = NIOCSSNAP;
|
|
si.ic_len = sizeof snaplen;
|
|
si.ic_dp = (char *)&snaplen;
|
|
if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
|
|
perror("ioctl (I_STR: NIOCSSNAP)");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
if (if_flags != 0) {
|
|
si.ic_cmd = NIOCSFLAGS;
|
|
si.ic_len = sizeof if_flags;
|
|
si.ic_dp = (char *)&if_flags;
|
|
if (ioctl(if_fd, I_STR, (char *)&si) < 0) {
|
|
perror("ioctl (I_STR: NIOCSFLAGS)");
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Flush the read queue, to get rid of anything that
|
|
* accumulated before the device reached its final configuration.
|
|
*/
|
|
if (ioctl(if_fd, I_FLUSH, (char *)FLUSHR) < 0) {
|
|
perror("ioctl (I_FLUSH)");
|
|
exit(1);
|
|
}
|
|
}
|
|
|