⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fromdevicebakc

📁 COPE the first practical network coding scheme which is developped on click
💻
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * fromdevice.{cc,hh} -- element reads packets live from network via pcap * Douglas S. J. De Couto, Eddie Kohler, John Jannotti * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2001 International Computer Science Institute * Copyright (c) 2005 Regents of the University of California * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "fromdevice.hh"#include <click/error.hh>#include <click/confparse.hh>#include <click/glue.hh>#include <click/packet_anno.hh>#include <click/standard/scheduleinfo.hh>#include <unistd.h>#include <fcntl.h>#ifndef __sun#include <sys/ioctl.h>#else#include <sys/ioccom.h>#endif#if FROMDEVICE_LINUX# include <sys/socket.h># include <net/if.h># include <features.h># if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1#  include <netpacket/packet.h>#  include <net/ethernet.h># else#  include <net/if_packet.h>#  include <linux/if_packet.h>#  include <linux/if_ether.h># endif#endif#include "fakepcap.hh"CLICK_DECLSFromDevice::FromDevice()    : Element(0, 1),#if FROMDEVICE_LINUX      _linux_fd(-1),#endif#if FROMDEVICE_PCAP      _pcap(0), _pcap_task(this), _pcap_complaints(0),#endif      _promisc(0), _snaplen(0){}FromDevice::~FromDevice(){}intFromDevice::configure(Vector<String> &conf, ErrorHandler *errh){    bool promisc = false, outbound = false, sniffer = true;    _snaplen = 2046;    _force_ip = false;    String bpf_filter, capture;    if (cp_va_parse(conf, this, errh,		    cpString, "interface name", &_ifname,		    cpOptional,		    cpBool, "be promiscuous?", &promisc,		    cpUnsigned, "maximum packet length", &_snaplen,		    cpKeywords,		    "SNIFFER", cpBool, "act as sniffer?", &sniffer,		    "PROMISC", cpBool, "be promiscuous?", &promisc,		    "SNAPLEN", cpUnsigned, "maximum packet length", &_snaplen,		    "FORCE_IP", cpBool, "force IP packets?", &_force_ip,		    "CAPTURE", cpWord, "capture method", &capture,		    "BPF_FILTER", cpString, "BPF filter", &bpf_filter,		    "OUTBOUND", cpBool, "emit outbound packets?", &outbound,		    cpEnd) < 0)	return -1;    if (_snaplen > 8190 || _snaplen < 14)	return errh->error("maximum packet length out of range");    #if FROMDEVICE_PCAP    _bpf_filter = bpf_filter;#endif    // set _capture    if (capture == "") {#if FROMDEVICE_PCAP && FROMDEVICE_LINUX	_capture = (bpf_filter ? CAPTURE_PCAP : CAPTURE_LINUX);#elif FROMDEVICE_LINUX	_capture = CAPTURE_LINUX;#elif FROMDEVICE_PCAP	_capture = CAPTURE_PCAP;#else	return errh->error("this platform does not support any capture method");#endif    }#if FROMDEVICE_LINUX    else if (capture == "LINUX")	_capture = CAPTURE_LINUX;#endif#if FROMDEVICE_PCAP    else if (capture == "PCAP")	_capture = CAPTURE_PCAP;#endif    else	return errh->error("capture method '%s' not supported", capture.c_str());        if (bpf_filter && _capture != CAPTURE_PCAP)	errh->warning("not using PCAP capture method, BPF filter ignored");        if (!sniffer)	return errh->error("SNIFFER must be set to true for now");    _promisc = promisc;    _outbound = outbound;    return 0;}#if FROMDEVICE_LINUXintFromDevice::open_packet_socket(String ifname, ErrorHandler *errh){    int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));    if (fd == -1)	return errh->error("%s: socket: %s", ifname.cc(), strerror(errno));    // get interface index    struct ifreq ifr;    memset(&ifr, 0, sizeof(ifr));    strncpy(ifr.ifr_name, ifname.cc(), sizeof(ifr.ifr_name));    int res = ioctl(fd, SIOCGIFINDEX, &ifr);    if (res != 0) {	close(fd);	return errh->error("%s: SIOCGIFINDEX: %s", ifname.cc(), strerror(errno));    }    int ifindex = ifr.ifr_ifindex;    // bind to the specified interface.  from packet man page, only    // sll_protocol and sll_ifindex fields are used; also have to set    // sll_family    sockaddr_ll sa;    memset(&sa, 0, sizeof(sa));    sa.sll_family = AF_PACKET;    sa.sll_protocol = htons(ETH_P_ALL);    sa.sll_ifindex = ifindex;    res = bind(fd, (struct sockaddr *)&sa, sizeof(sa));    if (res != 0) {	close(fd);	return errh->error("%s: bind: %s", ifname.cc(), strerror(errno));    }    // nonblocking I/O on the packet socket so we can poll    fcntl(fd, F_SETFL, O_NONBLOCK);      return fd;}intFromDevice::set_promiscuous(int fd, String ifname, bool promisc){    // get interface flags    struct ifreq ifr;    memset(&ifr, 0, sizeof(ifr));    strncpy(ifr.ifr_name, ifname.cc(), sizeof(ifr.ifr_name));    if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0)	return -2;    int was_promisc = (ifr.ifr_flags & IFF_PROMISC ? 1 : 0);    // set or reset promiscuous flag#ifdef SOL_PACKET    if (ioctl(fd, SIOCGIFINDEX, &ifr) != 0)	return -2;    struct packet_mreq mr;    memset(&mr, 0, sizeof(mr));    mr.mr_ifindex = ifr.ifr_ifindex;    mr.mr_type = (promisc ? PACKET_MR_PROMISC : PACKET_MR_ALLMULTI);    if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0)	return -3;#else    if (was_promisc != promisc) {	ifr.ifr_flags = (promisc ? ifr.ifr_flags | IFF_PROMISC : ifr.ifr_flags & ~IFF_PROMISC);	if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)	    return -3;    }#endif    return was_promisc;}#endif /* FROMDEVICE_LINUX */intFromDevice::initialize(ErrorHandler *errh){    if (!_ifname)	return errh->error("interface not set");#if FROMDEVICE_PCAP    if (_capture == CAPTURE_PCAP) {	assert(!_pcap);	char *ifname = _ifname.mutable_c_str();	char ebuf[PCAP_ERRBUF_SIZE];	_pcap = pcap_open_live(ifname, _snaplen, _promisc,			       1,     /* timeout: don't wait for packets */			       ebuf);	// Note: pcap error buffer will contain the interface name	if (!_pcap)	    return errh->error("%s", ebuf);	// nonblocking I/O on the packet socket so we can poll	int pcap_fd = fd();# if HAVE_PCAP_SETNONBLOCK	if (pcap_setnonblock(_pcap, 1, ebuf) < 0)	    errh->warning("pcap_setnonblock: %s", ebuf);# else	if (fcntl(pcap_fd, F_SETFL, O_NONBLOCK) < 0)	    errh->warning("setting nonblocking: %s", strerror(errno));# endif# ifdef BIOCSSEESENT	{	    int r, accept = _outbound;	    if ((r = ioctl(pcap_fd, BIOCSSEESENT, &accept)) == -1)		return errh->error("%s: BIOCSSEESENT: %s", ifname, strerror(errno));	    else if (r != 0)		errh->warning("%s: BIOCSSEESENT returns %d", ifname, r);	}# endif# if defined(BIOCIMMEDIATE) && !defined(__sun) // pcap/bpf ioctl, not in DLPI/bufmod	{	    int r, yes = 1;	    if ((r = ioctl(pcap_fd, BIOCIMMEDIATE, &yes)) == -1)		return errh->error("%s: BIOCIMMEDIATE: %s", ifname, strerror(errno));	    else if (r != 0)		errh->warning("%s: BIOCIMMEDIATE returns %d", ifname, r);	}# endif	bpf_u_int32 netmask;	bpf_u_int32 localnet;	if (pcap_lookupnet(ifname, &localnet, &netmask, ebuf) < 0)	    errh->warning("%s", ebuf);  	// Later versions of pcap distributed with linux (e.g. the redhat	// linux pcap-0.4-16) want to have a filter installed before they	// will pick up any packets.	// compile the BPF filter	struct bpf_program fcode;	if (pcap_compile(_pcap, &fcode, _bpf_filter.mutable_c_str(), 0, netmask) < 0)	    return errh->error("%s: %s", ifname, pcap_geterr(_pcap));	if (pcap_setfilter(_pcap, &fcode) < 0)	    return errh->error("%s: %s", ifname, pcap_geterr(_pcap));	add_select(pcap_fd, SELECT_READ);	_datalink = pcap_datalink(_pcap);	if (_force_ip && !fake_pcap_dlt_force_ipable(_datalink))	    errh->warning("%s: strange data link type %d, FORCE_IP will not work", ifname, _datalink);	ScheduleInfo::initialize_task(this, &_pcap_task, false, errh);    }#endif#if FROMDEVICE_LINUX    if (_capture == CAPTURE_LINUX) {	_linux_fd = open_packet_socket(_ifname, errh);	if (_linux_fd < 0)	    return -1;	int promisc_ok = set_promiscuous(_linux_fd, _ifname, _promisc);	if (promisc_ok < 0) {	    if (_promisc)		errh->warning("cannot set promiscuous mode");	    _was_promisc = -1;	} else	    _was_promisc = promisc_ok;	add_select(_linux_fd, SELECT_READ);	_datalink = FAKE_DLT_EN10MB;    }#endif        return 0;}voidFromDevice::cleanup(CleanupStage){#if FROMDEVICE_LINUX    if (_linux_fd >= 0) {	if (_was_promisc >= 0)	    set_promiscuous(_linux_fd, _ifname, _was_promisc);	close(_linux_fd);	_linux_fd = -1;    }#endif#if FROMDEVICE_PCAP    if (_pcap) {	pcap_close(_pcap);	_pcap = 0;    }#endif}#if FROMDEVICE_PCAPCLICK_ENDDECLSextern "C" {voidFromDevice_get_packet(u_char* clientdata,		      const struct pcap_pkthdr* pkthdr,		      const u_char* data){    static char bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };    FromDevice *fd = (FromDevice *) clientdata;    int length = pkthdr->caplen;#if defined(__sparc)    // Packet::make(data,length) allocates new buffer to install    // DEFAULT_HEADROOM (28 bytes). Thus data winds up on a 4 byte    // boundary, irrespective of its original alignment. We assume we    // want a two byte offset from a four byte boundary (DLT_EN10B).    //    // Furthermore, note that pcap-dlpi on Solaris uses bufmod by    // default, hence while pcap-dlpi.pcap_read() is careful to load    // the initial read from the stream head into a buffer aligned    // appropriately for the network interface type, (I believe)    // subsequent packets in the batched read will be copied from the    // Stream's byte sequence into the pcap-dlpi user-level buffer at    // arbitrary alignments.    Packet *p = Packet::make(data - 2, length + 2);    p->pull(2); #else    Packet *p = Packet::make(data, length);#endif    // set packet type annotation    if (p->data()[0] & 1) {	if (memcmp(bcast_addr, p->data(), 6) == 0)	    p->set_packet_type_anno(Packet::BROADCAST);	else	    p->set_packet_type_anno(Packet::MULTICAST);    }    // set annotations    p->set_timestamp_anno(Timestamp::make_usec(pkthdr->ts.tv_sec, pkthdr->ts.tv_usec));    SET_EXTRA_LENGTH_ANNO(p, pkthdr->len - length);    if (!fd->_force_ip || fake_pcap_force_ip(p, fd->_datalink))	fd->output(0).push(p);    else	p->kill();}}CLICK_DECLS#endifvoidFromDevice::selected(int){#if FROMDEVICE_PCAP    if (_capture == CAPTURE_PCAP) {	// Read and push() at most one packet.	int r = pcap_dispatch(_pcap, 1, FromDevice_get_packet, (u_char *) this);	if (r > 0)	    _pcap_task.reschedule();	else if (r < 0 && ++_pcap_complaints < 5)	    ErrorHandler::default_handler()->error("%{element}: %s", this, pcap_geterr(_pcap));    }#endif#if FROMDEVICE_LINUX    if (_capture == CAPTURE_LINUX) {	struct sockaddr_ll sa;	socklen_t fromlen = sizeof(sa);	// store data offset 2 bytes into the packet, assuming that first 14	// bytes are ether header, and that we want remaining data to be	// 4-byte aligned.  this assumes that _packetbuf is 4-byte aligned,	// and that the buffer allocated by Packet::make is also 4-byte	// aligned.  Actually, it doesn't matter if the packet is 4-byte	// aligned; perhaps there is some efficiency aspect?  who cares....	WritablePacket *p = Packet::make(2, 0, _snaplen, 0);	int len = recvfrom(_linux_fd, p->data(), p->length(), MSG_TRUNC, (sockaddr *)&sa, &fromlen);	if (len > 0 && (sa.sll_pkttype != PACKET_OUTGOING || _outbound)) {	    if (len > _snaplen) {		assert(p->length() == (uint32_t)_snaplen);		SET_EXTRA_LENGTH_ANNO(p, len - _snaplen);	    } else		p->take(_snaplen - len);	    p->set_packet_type_anno((Packet::PacketType)sa.sll_pkttype);	    p->timestamp_anno().set_timeval_ioctl(_linux_fd, SIOCGSTAMP);	    if (!_force_ip || fake_pcap_force_ip(p, _datalink))		output(0).push(p);	    else		p->kill();	} else {	    p->kill();	    if (len <= 0 && errno != EAGAIN)		click_chatter("FromDevice(%s): recvfrom: %s", _ifname.cc(), strerror(errno));	}    }#endif}#if FROMDEVICE_PCAPboolFromDevice::run_task(){    // Read and push() at most one packet.    int r = pcap_dispatch(_pcap, 1, FromDevice_get_packet, (u_char *) this);    if (r > 0)	_pcap_task.fast_reschedule();    else if (r < 0 && ++_pcap_complaints < 5)	ErrorHandler::default_handler()->error("%{element}: %s", this, pcap_geterr(_pcap));    return r > 0;}#endifvoidFromDevice::kernel_drops(bool& known, int& max_drops) const{#if FROMDEVICE_LINUX    // You might be able to do this better by parsing netstat/ifconfig output,    // but for now, we just give up.#endif    known = false, max_drops = -1;#if FROMDEVICE_PCAP    if (_capture == CAPTURE_PCAP) {	struct pcap_stat stats;	if (pcap_stats(_pcap, &stats) >= 0)	    known = true, max_drops = stats.ps_drop;    }#endif}StringFromDevice::read_kernel_drops(Element* e, void*){    FromDevice* fd = static_cast<FromDevice*>(e);    int max_drops;    bool known;    fd->kernel_drops(known, max_drops);    if (known)	return String(max_drops) + "\n";    else if (max_drops >= 0)	return "<" + String(max_drops) + "\n";    else	return "??\n";}StringFromDevice::read_encap(Element* e, void*){    FromDevice* fd = static_cast<FromDevice*>(e);    return String(fake_pcap_unparse_dlt(fd->_datalink)) + "\n";}voidFromDevice::add_handlers(){    add_read_handler("kernel_drops", read_kernel_drops, 0);    add_read_handler("encap", read_encap, 0);}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel FakePcap)EXPORT_ELEMENT(FromDevice)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -