📄 net-pcap.cc
字号:
/*- * Copyright (c) 1998 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and the Network Research Group at * Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic const char rcsid[] = "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/net-pcap.cc,v 1.17 2000/02/08 23:35:13 salehi Exp $ (LBL)";#endif#include <stdio.h>#ifndef WIN32#include <unistd.h>#endif#include <time.h>#include <errno.h>#include <string.h>#ifdef WIN32#include <io.h>#define close closesocket#else#include <sys/param.h>#include <sys/socket.h>#include <sys/ioctl.h>#endif#if defined(sun) && defined(__svr4__)#include <sys/systeminfo.h>#endif#ifdef __cplusplusextern "C" {#include <pcap.h>}#else#include <pcap.h>#endif#include "config.h"#include "scheduler.h"#include "net.h"#include "tclcl.h"/* * observations about pcap library * device name is in the ifreq struct sense, should be doc'd * pcap_lookupdev returns a ptr to static data * q: does lookupdev only return devs in the AF_INET addr family? * why does pcap_compile require a netmask? seems odd * would like some way to tell it what buffer to use * arriving packets have the link layer hdr at the beginning, doc * not convenient/possible to open bpf read/write * no real way to know what file (/dev/bpf?) it is using * would be nice if pcap_lookdev helped out more by * returning ifnet or ifreq or whatever structure * pcap_lookupnet makes calls to get our addr, but * then tosses it anyhow, should get us addr and netmask * interface type codes could be via rfc1573 * see freebsd net/if_types.h * want a way to set immed mode * pcap_next masks errors by returning 0 if pcap_dispatch fails * a pcap_t carries it's own internal buffer, and * _dispatch gives pointers into it when invoked [eek] * when you open pcap using a file, pcap_fileno always * returns -1; not so convenient * */#define PNET_PSTATE_INACTIVE 0#define PNET_PSTATE_ACTIVE 1//// PcapNetwork: a "network" (source or possibly sink of packets)// this is a base class only-- the derived classes are:// PcapLiveNetwork [a live net; currently bpf + ethernet]// PcapFileNetwork [packets from a tcpdump-style trace file]//class PcapNetwork : public Network {public: PcapNetwork() : t_firstpkt_(0.0), pfd_(-1), pcnt_(0), local_netmask_(0) { } int rchannel() { return(pfd_); } int schannel() { return(pfd_); } virtual int command(int argc, const char*const* argv); virtual int open(int mode, const char *) = 0; virtual int skiphdr() = 0; virtual double gents(pcap_pkthdr*) = 0; // generate timestamp int recv(u_char *buf, int len, sockaddr&, double&); // get from net int send(u_char *buf, int len); // write to net void close(); void reset(); int filter(const char*); // compile + install a filter int stat_pkts(); int stat_pdrops(); double offset_; // time offset to 1st pkt in a trace double t_firstpkt_; // ts of 1st pkt recvdprotected: static void phandler(u_char* u, pcap_pkthdr* h, u_char* p); virtual void bindvars() = 0; char errbuf_[PCAP_ERRBUF_SIZE]; // place to put err msgs char srcname_[PATH_MAX]; // device or file name int pfd_; // pcap fd int pcnt_; // # pkts counted int state_; // PNET_PSTATE_xxx (above) int optimize_; // bpf optimizer enable pcap_t* pcap_; // reference to pcap state struct bpf_program bpfpgm_; // generated program struct pcap_stat pcs_; // status unsigned int local_netmask_; // seems shouldn't be necessary :(};//// PcapLiveNetwork: a live network tap//struct NetworkAddress { u_int len_; u_char addr_[16]; // enough for IPv6 ip addr};class PcapLiveNetwork : public PcapNetwork {public: PcapLiveNetwork() : local_net_(0), dlink_type_(-1) { linkaddr_.len_ = 0; netaddr_.len_ = 0; bindvars(); reset(); } NetworkAddress& laddr() { return (linkaddr_); } NetworkAddress& naddr() { return (netaddr_); }protected: double gents(pcap_pkthdr*) { return Scheduler::instance().clock(); } int devtonaddr(const char* name, NetworkAddress&); int open(int mode); int open(int mode, const char*); int command(int argc, const char*const* argv); int skiphdr(); const char* autodevname(); void bindvars(); int snaplen_; // # of bytes to grab int promisc_; // put intf into promisc mode? double timeout_; NetworkAddress linkaddr_; // link-layer address NetworkAddress netaddr_; // network-layer (IP) address unsigned int local_net_; int dlink_type_; // data link type (see pcap)private: // XXX somewhat specific to bpf-- this stuff is a hack until pcap // can be fixed to allow for opening the bpf r/w#ifdef MT_OWN_PCAP pcap_t * pcap_open_live(char *, int slen, int prom, int, char *, int); int bpf_open(pcap_t *p, char *errbuf, int how);#endif};class PcapFileNetwork : public PcapNetwork {public: int open(int mode, const char *); int skiphdr() { return 0; } // XXX check meprotected: double gents(pcap_pkthdr* p) { // time stamp of packet is its relative time // in the trace file, plus sim start time, plus offset double pts = p->ts.tv_sec + p->ts.tv_usec * 0.000001; pts -= t_firstpkt_; pts += offset_ + Scheduler::instance().clock(); return (pts); } void bindvars(); int command(int argc, const char*const* argv);};static class PcapLiveNetworkClass : public TclClass {public: PcapLiveNetworkClass() : TclClass("Network/Pcap/Live") {} TclObject* create(int, const char*const*) { return (new PcapLiveNetwork); }} net_pcaplive;static class PcapFileNetworkClass : public TclClass {public: PcapFileNetworkClass() : TclClass("Network/Pcap/File") {} TclObject* create(int, const char*const*) { return (new PcapFileNetwork); }} net_pcapfile;//// defs for base PcapNetwork class//voidPcapNetwork::bindvars(){ bind_bool("optimize_", &optimize_);}voidPcapNetwork::reset(){ state_ = PNET_PSTATE_INACTIVE; pfd_ = -1; pcap_ = NULL; *errbuf_ = '\0'; *srcname_ = '\0'; pcnt_ = 0;}voidPcapNetwork::close(){ if (state_ == PNET_PSTATE_ACTIVE && pcap_) pcap_close(pcap_); reset();}/* compile up a bpf program *//* XXXwe aren't using 'bcast', so don't care about mask... sigh */intPcapNetwork::filter(const char *pgm){ if (pcap_compile(pcap_, &bpfpgm_, (char *)pgm, optimize_, local_netmask_) < 0) { fprintf(stderr, "pcapnet obj(%s): couldn't compile filter pgm", name()); return -1; } if (pcap_setfilter(pcap_, &bpfpgm_) < 0) { fprintf(stderr, "pcapnet obj(%s): couldn't set filter pgm", name()); return -1; } return(bpfpgm_.bf_len);}/* return number of pkts received */intPcapNetwork::stat_pkts(){ if (pcap_stats(pcap_, &pcs_) < 0) return (-1); return (pcs_.ps_recv);}/* return number of pkts dropped */intPcapNetwork::stat_pdrops(){ if (pcap_stats(pcap_, &pcs_) < 0) return (-1); return (pcs_.ps_drop);}#ifndef MIN#define MIN(x, y) ((x)<(y) ? (x) : (y))#endif#include "ether.h"/* recv is what others call to grab a packet from the pfilter */struct pcap_singleton { struct pcap_pkthdr *hdr; const u_char *pkt;}; voidPcapNetwork::phandler(u_char* userdata, pcap_pkthdr* ph, u_char* pkt){ pcap_singleton *ps = (pcap_singleton*) userdata; ps->hdr = ph; ps->pkt = pkt;}intPcapNetwork::recv(u_char *buf, int len, sockaddr& /*fromaddr*/, double &ts){ if (state_ != PNET_PSTATE_ACTIVE) { fprintf(stderr, "warning: net/pcap obj(%s) read-- not active\n", name()); return -1; } int pktcnt = 1; // all in buffer, or until error int np; // counts # of pkts dispatched pcap_singleton ps = { 0, 0 }; np = pcap_dispatch(pcap_, pktcnt, phandler, (u_char*) &ps); if (np < 0) { fprintf(stderr, "PcapNetwork(%s): recv: pcap_dispatch: %s\n", name(), pcap_strerror(errno)); return (np); } else if (np == 0) { /* we get here on EOF of a Pcap/File Network */ return (np); } else if (np != pktcnt) { fprintf(stderr, "PcapNetwork(%s): warning: recv: pcap_dispatch: requested pktcnt (%d) doesn't match actual (%d)\n", name(), pktcnt, np); } pcap_pkthdr* ph = ps.hdr; if (ph == NULL || ps.pkt == NULL) { fprintf(stderr, "PcapNetwork(%s): recv: pcap_dispatch: no packet present\n", name()); return (-1); } if (++pcnt_ == 1) { // mark time stamp of first pkt t_firstpkt_ = ph->ts.tv_sec + ph->ts.tv_usec * 0.000001; } int n = MIN(ph->caplen, (unsigned)len); ts = gents(ph); // mark with timestamp // link layer header will be placed at the beginning from pcap int s = skiphdr(); // go to IP header memcpy(buf, ps.pkt + s, n - s); return n - s;}/* send a packet out through the packet filter */intPcapNetwork::send(u_char *buf, int len){ int n; if ((n = write(pfd_, buf, len)) < 0) perror("write to pcap fd"); return n;}int PcapNetwork::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "close") == 0) { close(); return (TCL_OK); } if (strcmp(argv[1], "srcname") == 0) { tcl.result(srcname_); return (TCL_OK); } if (strcmp(argv[1], "pkts") == 0) { tcl.resultf("%d", stat_pkts()); return (TCL_OK); } if (strcmp(argv[1], "pdrops") == 0) { tcl.resultf("%d", stat_pdrops()); return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "filter") == 0) { if (state_ != PNET_PSTATE_ACTIVE) { fprintf(stderr, "net/pcap obj(%s): can't install filter prior to opening data source\n", name()); return (TCL_ERROR); } int plen; if ((plen = filter(argv[2])) < 0) { fprintf(stderr, "problem compiling/installing filter program\n"); return (TCL_ERROR); } tcl.resultf("%d", plen); return (TCL_OK); } } return (Network::command(argc, argv));}//// defs for PcapLiveNetwork//#include <fcntl.h>#include <net/if.h>intPcapLiveNetwork::open(int mode, const char *devname){ close();#ifdef MY_OWN_PCAP pcap_ = pcap_open_live((char*) devname, snaplen_, promisc_, int(timeout_ * 1000.), errbuf_, mode);#else pcap_ = pcap_open_live((char*) devname, snaplen_, promisc_, int(timeout_ * 1000.), errbuf_);#endif // MY_OWN_PCAP if (pcap_ == NULL) { fprintf(stderr, "pcap/live object (%s) couldn't open packet source %s: %s\n", name(), devname, errbuf_); return -1; } mode_ = mode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -