📄 net-pcap.cc
字号:
dlink_type_ = pcap_datalink(pcap_); pfd_ = pcap_fileno(pcap_); strncpy(srcname_, devname, sizeof(srcname_)-1); { // use SIOCGIFADDR hook in bpf to get link addr struct ifreq ifr; struct sockaddr *sa = &ifr.ifr_addr;#ifdef HAVE_SIOCGIFHWADDR memset(&ifr, 0, sizeof(struct ifreq)); strcpy(ifr.ifr_name, devname); if (ioctl(pfd_, SIOCGIFHWADDR, &ifr) < 0) { fprintf(stderr, "pcap/live (%s) SIOCGIFHWADDR on bpf fd %d\n", name(), pfd_); }#else if (ioctl(pfd_, SIOCGIFADDR, &ifr) < 0) { fprintf(stderr, "pcap/live (%s) SIOCGIFADDR on bpf fd %d\n", name(), pfd_); }#endif if (dlink_type_ != DLT_EN10MB) { fprintf(stderr, "sorry, only ethernet supported\n"); return -1; } linkaddr_.len_ = ETHER_ADDR_LEN; // for now memcpy(linkaddr_.addr_, sa->sa_data, linkaddr_.len_); } (void) devtonaddr(devname, netaddr_); state_ = PNET_PSTATE_ACTIVE; if (pcap_lookupnet(srcname_, &local_net_, &local_netmask_, errbuf_) < 0) { fprintf(stderr, "warning: pcap/live (%s) couldn't get local IP network info: %s\n", name(), errbuf_) ; } { int immed = 1; if (ioctl(pfd_, BIOCIMMEDIATE, &immed) < 0) { fprintf(stderr, "warning: pcap/live (%s) couldn't set immed\n", name()); perror("ioctl(BIOCIMMEDIATE)"); } } return 0;}/* * how many bytes of link-hdr to skip before net-layer hdr */intPcapLiveNetwork::skiphdr(){ switch (dlink_type_) { case DLT_NULL: return 0; case DLT_EN10MB: return ETHER_HDR_LEN; default: fprintf(stderr, "Network/Pcap/Live(%s): unknown link type: %d\n", name(), dlink_type_); } return -1;}const char *PcapLiveNetwork::autodevname(){ const char *dname; if ((dname = pcap_lookupdev(errbuf_)) == NULL) { fprintf(stderr, "warning: PcapNet/Live(%s) : %s\n", name(), errbuf_); return (NULL); } return (dname); // ptr to static data in pcap library}/* * devtonaddr -- map device name to its IP/Network layer address * this routine wouldn't be necessary if pcap_lookupnet gave * out the info it gets anyhow */#include <netinet/in.h>intPcapLiveNetwork::devtonaddr(const char *devname, NetworkAddress& na){ register int fd; ifreq ifr; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stderr, "PcapLiveNet(%s): devtoaddr: couldn't create sock\n", name()); return (-1); } memset(&ifr, 0, sizeof(ifr));#ifdef linux /* XXX Work around Linux kernel bug */ ifr.ifr_addr.sa_family = AF_INET;#endif (void)strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { fprintf(stderr, "PcapLiveNetwork(%s): devtoaddr: no addr\n", name()); (void)::close(fd); return (-1); } sockaddr* sa = &ifr.ifr_addr; if (sa->sa_family != AF_INET) { fprintf(stderr, "PcapLiveNet(%s): af not AF_INET (%d)\n", name(), sa->sa_family); } sockaddr_in* sin = (sockaddr_in*) sa; na.len_ = 4; // for now, assump IPv4 memset(na.addr_, 0, sizeof(na.addr_)); unsigned sz = sizeof(na.addr_); if (sizeof(ifr) < sz) sz = sizeof(ifr); memcpy(na.addr_, &sin->sin_addr, sz); return (0);}voidPcapLiveNetwork::bindvars(){ bind("snaplen_", &snaplen_); bind_bool("promisc_", &promisc_); bind_time("timeout_", &timeout_); bind("offset_", &offset_); PcapNetwork::bindvars();}voidPcapFileNetwork::bindvars(){ bind("offset_", &offset_);}intPcapLiveNetwork::open(int mode){ return (open(mode, autodevname()));}int PcapLiveNetwork::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "linkaddr") == 0) { /// XXX: only for ethernet now tcl.result(Ethernet::etheraddr_string(linkaddr_.addr_)); return (TCL_OK); } if (strcmp(argv[1], "netaddr") == 0) { if (netaddr_.len_ != 4) { fprintf(stderr, "PcapLive(%s): net addr not len 4 (%d)\n", name(), netaddr_.len_); return (TCL_ERROR); } tcl.resultf("%d.%d.%d.%d", netaddr_.addr_[0], netaddr_.addr_[1], netaddr_.addr_[2], netaddr_.addr_[3]); return (TCL_OK); } } else if (argc == 3) { // $obj open mode if (strcmp(argv[1], "open") == 0) { int mode = parsemode(argv[2]); if (open(mode) < 0) return (TCL_ERROR); tcl.result(srcname_); return (TCL_OK); } } else if (argc == 4) { // $obj open mode devicename if (strcmp(argv[1], "open") == 0) { int mode = parsemode(argv[2]); if (open(mode, argv[3]) < 0) return (TCL_ERROR); tcl.result(srcname_); return (TCL_OK); } } return (PcapNetwork::command(argc, argv));}//// defs for PcapFileNetwork// use a file instead of a live network//intPcapFileNetwork::open(int /*mode*/, const char *filename){ close(); pcap_ = pcap_open_offline((char*) filename, errbuf_); if (pcap_ == NULL) { fprintf(stderr, "pcap/file object (%s) couldn't open packet source %s: %s\n", name(), filename, errbuf_); return -1; } mode_ = O_RDONLY; // sorry, that's all for now // // pcap only ever puts -1 in the pcap_fileno, which // isn't so convenient, so do this instead: // pfd_ = pcap_fileno(pcap_); pfd_ = fileno(pcap_file(pcap_)); strncpy(srcname_, filename, sizeof(srcname_)-1); state_ = PNET_PSTATE_ACTIVE; return 0;}int PcapFileNetwork::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 4) { // $obj open mode filename if (strcmp(argv[1], "open") == 0) { int mode = parsemode(argv[2]); if (open(mode, argv[3]) < 0) return (TCL_ERROR); tcl.resultf("%s", argv[3]); return (TCL_OK); } } return (PcapNetwork::command(argc, argv));}//// XXX: the following routines are unfortunately necessary, // because libpcap has no obvious was of making the bpf fd// be read-write :(. The implication here is nasty:// our own version of bpf_open and pcap_open_live// and the later routine requires the struct pcap internal state/* * Savefile */ struct pcap_sf { FILE *rfile; int swapped; int version_major; int version_minor; u_char *base;}; struct pcap_md { struct pcap_stat stat; /*XXX*/ int use_bpf; u_long TotPkts; /* can't oflow for 79 hrs on ether */ u_long TotAccepted; /* count accepted by filter */ u_long TotDrops; /* count of dropped packets */ long TotMissed; /* missed by i/f during this run */ long OrigMissed; /* missed by i/f before this run */#ifdef linux int pad; int skip; char *device;#endif}; struct pcap { int fd; int snapshot; int linktype; int tzoff; /* timezone offset */ int offset; /* offset for proper alignment */ struct pcap_sf sf; struct pcap_md md; /* * Read buffer. */ int bufsize; u_char *buffer; u_char *bp; int cc; /* * Place holder for pcap_next(). */ u_char *pkt; /* * Placeholder for filter code if bpf not in kernel. */ struct bpf_program fcode; char errbuf[PCAP_ERRBUF_SIZE];};/* * the routines bpf_open and pcap_open_live really * should not be here, and instead should be part of the * pcap library. Unfortunately, if we ever want to writes to * the bpf fd, we need to open it r/w, and the normal pcap * library does not permit us to do this. So for now, here * are these routines. */#include <net/if.h>#ifdef MY_OWN_PCAPintPcapLiveNetwork::bpf_open(pcap_t *, char *errbuf, int how){ int fd; int n = 0; char device[sizeof "/dev/bpf000"]; /* * Go through all the minors and find one that isn't in use. */ do { (void)sprintf(device, "/dev/bpf%d", n++); fd = ::open(device, how, 0); } while (fd < 0 && n < 1000 && errno == EBUSY); /* * XXX better message for all minors used */ if (fd < 0) sprintf(errbuf, "%s: %s", device, pcap_strerror(errno)); return (fd);}pcap_t *PcapLiveNetwork::pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf, int how){ int fd; struct ifreq ifr; struct bpf_version bv; u_int v; pcap_t *p; p = (pcap_t *)malloc(sizeof(*p)); if (p == NULL) { sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); return (NULL); } bzero(p, sizeof(*p)); fd = bpf_open(p, ebuf, how); if (fd < 0) goto bad; p->fd = fd; p->snapshot = snaplen; if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno)); goto bad; } if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) { sprintf(ebuf, "kernel bpf filter out of date"); goto bad; } (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { sprintf(ebuf, "%s: %s", device, pcap_strerror(errno)); goto bad; } /* Get the data link layer type. */ if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno)); goto bad; }#if _BSDI_VERSION - 0 >= 199510 /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */ switch (v) { case DLT_SLIP: v = DLT_SLIP_BSDOS; break; case DLT_PPP: v = DLT_PPP_BSDOS; break; }#endif p->linktype = v; /* set timeout */ if (to_ms != 0) { struct timeval to; to.tv_sec = to_ms / 1000; to.tv_usec = (to_ms * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) { sprintf(ebuf, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); goto bad; } } if (promisc) /* set promiscuous mode, okay if it fails */ (void)ioctl(p->fd, BIOCPROMISC, NULL); if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno)); goto bad; } p->bufsize = v; p->buffer = (u_char *)malloc(p->bufsize); if (p->buffer == NULL) { sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); goto bad; } return (p); bad: ::close(fd); free(p); return (NULL);}#endif // MY_OWN_PCAP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -