net-pcap.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:24k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*-
  2.  * Copyright (c) 1998 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *      This product includes software developed by the University of
  16.  *      California, Berkeley and the Network Research Group at
  17.  *      Lawrence Berkeley Laboratory.
  18.  * 4. Neither the name of the University nor of the Laboratory may be used
  19.  *    to endorse or promote products derived from this software without
  20.  *    specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  */
  34. #ifndef lint
  35. static const char rcsid[] =
  36.     "@(#) $Header: /cvsroot/nsnam/ns-2/emulate/net-pcap.cc,v 1.23 2005/09/07 06:35:45 tomh Exp $ (LBL)";
  37. #endif
  38. #include <stdio.h>
  39. #ifndef WIN32
  40. #include <unistd.h>
  41. #endif
  42. #include <time.h>
  43. #include <errno.h>
  44. #include <string.h>
  45. #ifdef WIN32
  46. #include <io.h>
  47. #define close closesocket
  48. #else
  49. #include <sys/param.h>
  50. #include <sys/socket.h>
  51. #include <sys/ioctl.h>
  52. #endif
  53. #if defined(sun) && defined(__svr4__)
  54. #include <sys/systeminfo.h>
  55. #endif
  56. #ifdef __cplusplus
  57. extern "C" {
  58. #include <pcap.h>
  59. }
  60. #else
  61. #include <pcap.h>
  62. #endif
  63. #include "config.h"
  64. #include "scheduler.h"
  65. #include "net.h"
  66. #include "tclcl.h"
  67. #include "packet.h"
  68. /*
  69.  * observations about pcap library
  70.  * device name is in the ifreq struct sense, should be doc'd
  71.  * pcap_lookupdev returns a ptr to static data
  72.  * q: does lookupdev only return devs in the AF_INET addr family?
  73.  * why does pcap_compile require a netmask? seems odd
  74.  * would like some way to tell it what buffer to use
  75.  * arriving packets have the link layer hdr at the beginning, doc
  76.  * not convenient/possible to open bpf read/write
  77.  * no real way to know what file (/dev/bpf?) it is using
  78.  * would be nice if pcap_lookdev helped out more by
  79.  * returning ifnet or ifreq or whatever structure
  80.  * pcap_lookupnet makes calls to get our addr, but
  81.  * then tosses it anyhow, should get us addr and netmask
  82.  * interface type codes could be via rfc1573
  83.  * see freebsd net/if_types.h
  84.  * want a way to set immed mode
  85.  * pcap_next masks errors by returning 0 if pcap_dispatch fails
  86.  * a pcap_t carries it's own internal buffer, and
  87.  * _dispatch gives pointers into it when invoked [eek]
  88.  * when you open pcap using a file, pcap_fileno always
  89.  * returns -1; not so convenient
  90.  *
  91.  */
  92. #define PNET_PSTATE_INACTIVE 0
  93. #define PNET_PSTATE_ACTIVE 1
  94. //
  95. // PcapNetwork: a "network" (source or possibly sink of packets)
  96. // this is a base class only-- the derived classes are:
  97. // PcapLiveNetwork [a live net; currently bpf + ethernet]
  98. // PcapFileNetwork [packets from a tcpdump-style trace file]
  99. //
  100. class PcapNetwork : public Network {
  101. public:
  102. PcapNetwork() : t_firstpkt_(0.0),
  103. pfd_(-1), pcnt_(0), local_netmask_(0) { }
  104. int rchannel() { return(pfd_); }
  105. int schannel() { return(pfd_); }
  106. virtual int command(int argc, const char*const* argv);
  107. virtual int open(int mode, const char *) = 0;
  108. virtual int skiphdr() = 0;
  109. virtual double gents(pcap_pkthdr*) = 0; // generate timestamp
  110. int recv(u_char *buf, int len, sockaddr&, double&); // get from net
  111. int send(u_char *buf, int len); // write to net
  112. int recv(netpkt_handler callback, void *clientdata); // get from net
  113. void close();
  114. void reset();
  115. int filter(const char*); // compile + install a filter
  116. int stat_pkts();
  117. int stat_pdrops();
  118. double offset_; // time offset to 1st pkt in a trace
  119. double t_firstpkt_; // ts of 1st pkt recvd
  120. protected:
  121. static void phandler(u_char* u, const pcap_pkthdr* h, const u_char* p);
  122. static void phandler_callback(u_char* u, const pcap_pkthdr* h, const u_char* p);
  123. virtual void bindvars() = 0;
  124. char errbuf_[PCAP_ERRBUF_SIZE]; // place to put err msgs
  125. char srcname_[PATH_MAX]; // device or file name
  126. int pfd_; // pcap fd
  127. int pcnt_; // # pkts counted
  128. int state_; // PNET_PSTATE_xxx (above)
  129. int optimize_; // bpf optimizer enable
  130. pcap_t* pcap_; // reference to pcap state
  131. struct bpf_program bpfpgm_; // generated program
  132. struct pcap_stat pcs_; // status
  133. unsigned int local_netmask_; // seems shouldn't be necessary :(
  134. };
  135. //
  136. // PcapLiveNetwork: a live network tap
  137. //
  138. struct NetworkAddress {
  139.         u_int   len_;
  140.         u_char  addr_[16]; // enough for IPv6 ip addr
  141. };
  142. class PcapLiveNetwork : public PcapNetwork {
  143. public:
  144. PcapLiveNetwork() : local_net_(0), dlink_type_(-1) {
  145. linkaddr_.len_ = 0;
  146. netaddr_.len_ = 0;
  147. bindvars(); reset();
  148. }
  149. NetworkAddress& laddr() { return (linkaddr_); }
  150. NetworkAddress& naddr() { return (netaddr_); }
  151. protected:
  152. double gents(pcap_pkthdr*) {
  153. return Scheduler::instance().clock();
  154. }
  155. int devtonaddr(const char* name, NetworkAddress&);
  156. int open(int mode);
  157. int open(int mode, const char*);
  158. int command(int argc, const char*const* argv);
  159. int skiphdr();
  160. const char* autodevname();
  161. void bindvars();
  162. int snaplen_; // # of bytes to grab
  163. int promisc_; // put intf into promisc mode?
  164. double timeout_;
  165. NetworkAddress linkaddr_; // link-layer address
  166. NetworkAddress netaddr_; // network-layer (IP) address
  167. unsigned int local_net_;
  168. int dlink_type_; // data link type (see pcap)
  169. private:
  170. // XXX somewhat specific to bpf-- this stuff is  a hack until pcap
  171. // can be fixed to allow for opening the bpf r/w
  172. #ifdef MT_OWN_PCAP
  173. pcap_t * pcap_open_live(char *, int slen, int prom, int, char *, int);
  174. int bpf_open(pcap_t *p, char *errbuf, int how);
  175. #endif
  176. };
  177. class PcapFileNetwork : public PcapNetwork {
  178. public:
  179. int open(int mode, const char *);
  180. int skiphdr() { return 0; } // XXX check me
  181. protected:
  182. double gents(pcap_pkthdr* p) {
  183. // time stamp of packet is its relative time
  184. // in the trace file, plus sim start time, plus offset
  185. double pts = p->ts.tv_sec + p->ts.tv_usec * 0.000001;
  186. pts -= t_firstpkt_;
  187. pts += offset_ + Scheduler::instance().clock();
  188. return (pts);
  189. }
  190. void bindvars();
  191. int command(int argc, const char*const* argv);
  192. };
  193. static class PcapLiveNetworkClass : public TclClass {
  194. public:
  195. PcapLiveNetworkClass() : TclClass("Network/Pcap/Live") {}
  196. TclObject* create(int, const char*const*) {
  197. return (new PcapLiveNetwork);
  198. }
  199. } net_pcaplive;
  200. static class PcapFileNetworkClass : public TclClass {
  201. public:
  202. PcapFileNetworkClass() : TclClass("Network/Pcap/File") {}
  203. TclObject* create(int, const char*const*) {
  204. return (new PcapFileNetwork);
  205. }
  206. } net_pcapfile;
  207. //
  208. // defs for base PcapNetwork class
  209. //
  210. void
  211. PcapNetwork::bindvars()
  212. {
  213. bind_bool("optimize_", &optimize_);
  214. }
  215. void
  216. PcapNetwork::reset()
  217. {
  218. state_ = PNET_PSTATE_INACTIVE;
  219. pfd_ = -1;
  220. pcap_ = NULL;
  221. *errbuf_ = '';
  222. *srcname_ = '';
  223. pcnt_ = 0;
  224. }
  225. void
  226. PcapNetwork::close()
  227. {
  228. if (state_ == PNET_PSTATE_ACTIVE && pcap_)
  229. pcap_close(pcap_);
  230. reset();
  231. }
  232. /* compile up a bpf program */
  233. /* XXXwe aren't using 'bcast', so don't care about mask... sigh */
  234. int
  235. PcapNetwork::filter(const char *pgm)
  236. {
  237. if (pcap_compile(pcap_, &bpfpgm_, (char *)pgm,
  238.     optimize_, local_netmask_) < 0) {
  239. fprintf(stderr, "pcapnet obj(%s): couldn't compile filter pgm",
  240. name());
  241. return -1;
  242. }
  243. if (pcap_setfilter(pcap_, &bpfpgm_) < 0) {
  244. fprintf(stderr, "pcapnet obj(%s): couldn't set filter pgm",
  245. name());
  246. return -1;
  247. }
  248. return(bpfpgm_.bf_len);
  249. }
  250. /* return number of pkts received */
  251. int
  252. PcapNetwork::stat_pkts()
  253. {
  254. if (pcap_stats(pcap_, &pcs_) < 0)
  255. return (-1);
  256. return (pcs_.ps_recv);
  257. }
  258. /* return number of pkts dropped */
  259. int
  260. PcapNetwork::stat_pdrops()
  261. {
  262. if (pcap_stats(pcap_, &pcs_) < 0)
  263. return (-1);
  264. return (pcs_.ps_drop);
  265. }
  266. #ifndef MIN
  267. #define MIN(x, y) ((x)<(y) ? (x) : (y))
  268. #endif
  269. #include "ether.h"
  270. /* recv is what others call to grab a packet from the pfilter */
  271. struct pcap_singleton {
  272.         struct pcap_pkthdr *hdr;
  273.         const u_char *pkt;
  274. };   
  275. struct pcap_singleton_callback {
  276.         netpkt_handler callback;
  277.         void *clientdata;
  278.         PcapNetwork *net;
  279. };   
  280. void
  281. PcapNetwork::phandler(u_char* userdata, const pcap_pkthdr* ph, const u_char* pkt)
  282. {
  283. pcap_singleton *ps = (pcap_singleton*) userdata;
  284. ps->hdr = (pcap_pkthdr*)ph;
  285. ps->pkt = (u_char*)pkt;
  286. }
  287. void
  288. PcapNetwork::phandler_callback(u_char* userdata, const pcap_pkthdr* ph, const u_char* pkt)
  289. {
  290. pcap_singleton_callback *ps = (pcap_singleton_callback*) userdata;
  291. Packet *p = Packet::alloc(ph->caplen);
  292. PcapNetwork *inst = ps->net;
  293. if (++(inst->pcnt_) == 1) {
  294. // mark time stamp of first pkt
  295. inst->t_firstpkt_ = ph->ts.tv_sec + ph->ts.tv_usec * 0.000001;
  296. }
  297. // link layer header will be placed at the beginning from pcap
  298. int s = inst->skiphdr(); // go to IP header
  299. memcpy(p->accessdata(), pkt + s, ph->caplen - s);
  300. ps->callback(ps->clientdata, p, ph->ts);
  301. }
  302. int
  303. PcapNetwork::recv(u_char *buf, int len, sockaddr& /*fromaddr*/, double &ts)
  304. {
  305. if (state_ != PNET_PSTATE_ACTIVE) {
  306. fprintf(stderr, "warning: net/pcap obj(%s) read-- not activen",
  307. name());
  308. return -1;
  309. }
  310. int pktcnt = 1; // all in buffer, or until error
  311. int np; // counts # of pkts dispatched
  312. pcap_singleton ps = { 0, 0 };
  313. np = pcap_dispatch(pcap_, pktcnt, phandler, (u_char*) &ps);
  314. if (np < 0) {
  315. fprintf(stderr,
  316. "PcapNetwork(%s): recv: pcap_dispatch: %sn",
  317.     name(), pcap_strerror(errno));
  318. return (np);
  319. } else if (np == 0) {
  320. /* we get here on EOF of a Pcap/File Network */
  321. return (np);
  322. } else if (np != pktcnt) {
  323. fprintf(stderr,
  324. "PcapNetwork(%s): warning: recv: pcap_dispatch: requested pktcnt (%d) doesn't match actual (%d)n",
  325.     name(), pktcnt, np);
  326. }
  327. pcap_pkthdr* ph = ps.hdr;
  328. if (ph == NULL || ps.pkt == NULL) {
  329. fprintf(stderr,
  330. "PcapNetwork(%s): recv: pcap_dispatch: no packet presentn",
  331.     name());
  332. return (-1);
  333. }
  334. if (++pcnt_ == 1) {
  335. // mark time stamp of first pkt
  336. t_firstpkt_ = ph->ts.tv_sec + ph->ts.tv_usec * 0.000001;
  337. }
  338. int n = MIN(ph->caplen, (unsigned)len);
  339. ts = gents(ph); // mark with timestamp
  340. // link layer header will be placed at the beginning from pcap
  341. int s = skiphdr(); // go to IP header
  342. memcpy(buf, ps.pkt + s, n - s);
  343. return n - s;
  344. }
  345. int
  346. PcapNetwork::recv(netpkt_handler callback, void *clientdata)
  347. {
  348. if (state_ != PNET_PSTATE_ACTIVE) {
  349. fprintf(stderr, "warning: net/pcap obj(%s) read-- not activen",
  350. name());
  351. return -1;
  352. }
  353. int pktcnt = -1; // all in buffer, or until error
  354. int np; // counts # of pkts dispatched
  355. pcap_singleton_callback ps = { callback, clientdata, this };
  356. np = pcap_dispatch(pcap_, pktcnt, phandler_callback, (u_char *)&ps);
  357. #ifdef MY_OWN_PCAP // directly access pcap_t's member
  358. assert( pcap_->cc == 0 ); // i.e. we have emptied pcap's buffer
  359. #endif // MY_OWN_PCAP
  360. return np;
  361. }
  362. /* send a packet out through the packet filter */
  363. int
  364. PcapNetwork::send(u_char *buf, int len)
  365. {
  366. int n;
  367. if ((n = write(pfd_, buf, len)) < 0)
  368. perror("write to pcap fd");
  369. return n;
  370. }
  371. int PcapNetwork::command(int argc, const char*const* argv)
  372. {
  373. Tcl& tcl = Tcl::instance();
  374. if (argc == 2) {
  375. if (strcmp(argv[1], "close") == 0) {
  376. close();
  377. return (TCL_OK);
  378. }
  379. if (strcmp(argv[1], "srcname") == 0) {
  380. tcl.result(srcname_);
  381. return (TCL_OK);
  382. }
  383. if (strcmp(argv[1], "pkts") == 0) {
  384. tcl.resultf("%d", stat_pkts());
  385. return (TCL_OK);
  386. }
  387. if (strcmp(argv[1], "pdrops") == 0) {
  388. tcl.resultf("%d", stat_pdrops());
  389. return (TCL_OK);
  390. }
  391. } else if (argc == 3) {
  392. if (strcmp(argv[1], "filter") == 0) {
  393. if (state_ != PNET_PSTATE_ACTIVE) {
  394. fprintf(stderr, "net/pcap obj(%s): can't install filter prior to opening data sourcen",
  395. name());
  396. return (TCL_ERROR);
  397. }
  398. int plen;
  399. if ((plen = filter(argv[2])) < 0) {
  400. fprintf(stderr, "problem compiling/installing filter programn");
  401. return (TCL_ERROR);
  402. }
  403. tcl.resultf("%d", plen);
  404. return (TCL_OK);
  405. }
  406. }
  407. return (Network::command(argc, argv));
  408. }
  409. //
  410. // defs for PcapLiveNetwork
  411. //
  412. #include <fcntl.h>
  413. #include <net/if.h>
  414. int
  415. PcapLiveNetwork::open(int mode, const char *devname)
  416. {
  417. close();
  418. #ifdef MY_OWN_PCAP
  419. pcap_ = pcap_open_live((char*) devname, snaplen_, promisc_,
  420.        int(timeout_ * 1000.), errbuf_, mode);
  421. #else
  422. pcap_ = pcap_open_live((char*) devname, snaplen_, promisc_,
  423.        int(timeout_ * 1000.), errbuf_);
  424. #endif // MY_OWN_PCAP
  425. if (pcap_ == NULL) {
  426. fprintf(stderr,
  427.   "pcap/live object (%s) couldn't open packet source %s: %sn",
  428. name(), devname, errbuf_);
  429. return -1;
  430. }
  431. mode_ = mode;
  432. dlink_type_ = pcap_datalink(pcap_);
  433. pfd_ = pcap_fileno(pcap_);
  434. strncpy(srcname_, devname, sizeof(srcname_)-1);
  435. {
  436. // use SIOCGIFADDR hook in bpf to get link addr
  437. struct ifreq ifr;
  438. struct sockaddr *sa = &ifr.ifr_addr;
  439. #ifdef HAVE_SIOCGIFHWADDR
  440. memset(&ifr, 0, sizeof(struct ifreq));
  441. strcpy(ifr.ifr_name, devname);
  442. if (ioctl(pfd_, SIOCGIFHWADDR, &ifr) < 0) {
  443. fprintf(stderr,
  444.   "pcap/live (%s) SIOCGIFHWADDR on bpf fd %dn",
  445.   name(), pfd_);
  446. }
  447. #else
  448. if (ioctl(pfd_, SIOCGIFADDR, &ifr) < 0) {
  449. fprintf(stderr,
  450.   "pcap/live (%s) SIOCGIFADDR on bpf fd %dn",
  451.   name(), pfd_);
  452. }
  453. #endif
  454. if (dlink_type_ != DLT_EN10MB) {
  455. fprintf(stderr,
  456. "sorry, only ethernet supportedn");
  457. return -1;
  458. }
  459. linkaddr_.len_ = ETHER_ADDR_LEN; // for now
  460. memcpy(linkaddr_.addr_, sa->sa_data, linkaddr_.len_);
  461. }
  462. (void) devtonaddr(devname, netaddr_);
  463. state_ = PNET_PSTATE_ACTIVE;
  464. if (pcap_lookupnet(srcname_, &local_net_, &local_netmask_, errbuf_) < 0) {
  465. fprintf(stderr,
  466.   "warning: pcap/live (%s) couldn't get local IP network info: %sn",
  467.   name(), errbuf_) ;
  468. }
  469. #if !defined(__linux__)&&!defined(__APPLE__)
  470. {
  471. int immed = 1;
  472. if (ioctl(pfd_, BIOCIMMEDIATE, &immed) < 0) {
  473. fprintf(stderr,
  474. "warning: pcap/live (%s) couldn't set immedn",
  475. name());
  476. perror("ioctl(BIOCIMMEDIATE)");
  477. }
  478. }
  479. #endif
  480. return 0;
  481. }
  482. /*
  483.  * how many bytes of link-hdr to skip before net-layer hdr
  484.  */
  485. int
  486. PcapLiveNetwork::skiphdr()
  487. {
  488. switch (dlink_type_) {
  489. case DLT_NULL:
  490. return 0;
  491. case DLT_EN10MB:
  492. return ETHER_HDR_LEN;
  493. default:
  494. fprintf(stderr,
  495.     "Network/Pcap/Live(%s): unknown link type: %dn",
  496. name(), dlink_type_);
  497. }
  498. return -1;
  499. }
  500. const char *
  501. PcapLiveNetwork::autodevname()
  502. {
  503. const char *dname;
  504. if ((dname = pcap_lookupdev(errbuf_)) == NULL) {
  505. fprintf(stderr, "warning: PcapNet/Live(%s) : %sn",
  506. name(), errbuf_);
  507. return (NULL);
  508. }
  509. return (dname); // ptr to static data in pcap library
  510. }
  511. /*
  512.  * devtonaddr -- map device name to its IP/Network layer address
  513.  * this routine wouldn't be necessary if pcap_lookupnet gave
  514.  * out the info it gets anyhow
  515.  */
  516. #include <netinet/in.h>
  517. int
  518. PcapLiveNetwork::devtonaddr(const char *devname, NetworkAddress& na)
  519. {
  520.         register int fd;
  521.         ifreq ifr;
  522.                                 
  523.         fd = socket(AF_INET, SOCK_DGRAM, 0);
  524.         if (fd < 0) {       
  525.                 fprintf(stderr,
  526. "PcapLiveNet(%s): devtoaddr: couldn't create sockn",
  527. name());
  528.                 return (-1);
  529.         }
  530.         memset(&ifr, 0, sizeof(ifr));
  531. #ifdef linux
  532.         /* XXX Work around Linux kernel bug */
  533.         ifr.ifr_addr.sa_family = AF_INET;
  534. #endif   
  535.         (void)strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
  536.         if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
  537.                 fprintf(stderr, "PcapLiveNetwork(%s): devtoaddr: no addrn",
  538. name());
  539.                 (void)::close(fd);   
  540.                 return (-1);
  541.         }               
  542. sockaddr* sa = &ifr.ifr_addr;
  543. if (sa->sa_family != AF_INET) {
  544.                 fprintf(stderr,
  545. "PcapLiveNet(%s): af not AF_INET (%d)n",
  546. name(), sa->sa_family);
  547. }
  548. sockaddr_in* sin = (sockaddr_in*) sa;
  549. na.len_ = 4; // for now, assump IPv4
  550. memset(na.addr_, 0, sizeof(na.addr_));
  551. unsigned sz = sizeof(na.addr_);
  552. if (sizeof(ifr) < sz)
  553. sz = sizeof(ifr);
  554. memcpy(na.addr_, &sin->sin_addr, sz);
  555. return (0);
  556. }
  557. void
  558. PcapLiveNetwork::bindvars()
  559. {
  560. bind("snaplen_", &snaplen_);
  561. bind_bool("promisc_", &promisc_);
  562. bind_time("timeout_", &timeout_);
  563. bind("offset_", &offset_);
  564. PcapNetwork::bindvars();
  565. }
  566. void
  567. PcapFileNetwork::bindvars()
  568. {
  569. bind("offset_", &offset_);
  570. }
  571. int
  572. PcapLiveNetwork::open(int mode)
  573. {
  574. return (open(mode, autodevname()));
  575. }
  576. int PcapLiveNetwork::command(int argc, const char*const* argv)
  577. {
  578. Tcl& tcl = Tcl::instance();
  579. if (argc == 2) {
  580. if (strcmp(argv[1], "linkaddr") == 0) {
  581. /// XXX: only for ethernet now
  582. tcl.result(Ethernet::etheraddr_string(linkaddr_.addr_));
  583. return (TCL_OK);
  584. }
  585. if (strcmp(argv[1], "netaddr") == 0) {
  586. if (netaddr_.len_ != 4) {
  587. fprintf(stderr,
  588.   "PcapLive(%s): net addr not len 4 (%d)n",
  589. name(), netaddr_.len_);
  590. return (TCL_ERROR);
  591. }
  592. tcl.resultf("%d.%d.%d.%d",
  593. netaddr_.addr_[0],
  594. netaddr_.addr_[1],
  595. netaddr_.addr_[2],
  596. netaddr_.addr_[3]);
  597. return (TCL_OK);
  598. }
  599. } else if (argc == 3) {
  600. // $obj open mode
  601. if (strcmp(argv[1], "open") == 0) {
  602. int mode = parsemode(argv[2]);
  603. if (open(mode) < 0)
  604. return (TCL_ERROR);
  605. tcl.result(srcname_);
  606. return (TCL_OK);
  607. }
  608. } else if (argc == 4) {
  609. // $obj open mode devicename
  610. if (strcmp(argv[1], "open") == 0) {
  611. int mode = parsemode(argv[2]);
  612. if (open(mode, argv[3]) < 0)
  613. return (TCL_ERROR);
  614. tcl.result(srcname_);
  615. return (TCL_OK);
  616. }
  617. }
  618. return (PcapNetwork::command(argc, argv));
  619. }
  620. //
  621. // defs for PcapFileNetwork
  622. // use a file instead of a live network
  623. //
  624. int
  625. PcapFileNetwork::open(int /*mode*/, const char *filename)
  626. {
  627. close();
  628. pcap_ = pcap_open_offline((char*) filename, errbuf_);
  629. if (pcap_ == NULL) {
  630. fprintf(stderr,
  631.   "pcap/file object (%s) couldn't open packet source %s: %sn",
  632. name(), filename, errbuf_);
  633. return -1;
  634. }
  635. mode_ = O_RDONLY; // sorry, that's all for now
  636. //
  637. // pcap only ever puts -1 in the pcap_fileno, which
  638. // isn't so convenient, so do this instead:
  639. // pfd_ = pcap_fileno(pcap_);
  640. pfd_ = fileno(pcap_file(pcap_));
  641. strncpy(srcname_, filename, sizeof(srcname_)-1);
  642. state_ = PNET_PSTATE_ACTIVE;
  643. return 0;
  644. }
  645. int PcapFileNetwork::command(int argc, const char*const* argv)
  646. {
  647. Tcl& tcl = Tcl::instance();
  648. if (argc == 4) {
  649. // $obj open mode filename
  650. if (strcmp(argv[1], "open") == 0) {
  651. int mode = parsemode(argv[2]);
  652. if (open(mode, argv[3]) < 0)
  653. return (TCL_ERROR);
  654. tcl.resultf("%s", argv[3]);
  655. return (TCL_OK);
  656. }
  657. }
  658. return (PcapNetwork::command(argc, argv));
  659. }
  660. //
  661. // XXX: the following routines are unfortunately necessary, 
  662. // because libpcap has no obvious was of making the bpf fd
  663. // be read-write :(.  The implication here is nasty:
  664. // our own version of bpf_open and pcap_open_live
  665. // and the later routine requires the struct pcap internal state
  666. /*   
  667.  * Savefile
  668.  */  
  669. struct pcap_sf {
  670.         FILE *rfile; 
  671.         int swapped;
  672.         int version_major;
  673.         int version_minor;
  674.         u_char *base;
  675. };   
  676.      
  677. struct pcap_md {
  678.         struct pcap_stat stat;
  679.         /*XXX*/ 
  680.         int use_bpf;
  681.         u_long  TotPkts;        /* can't oflow for 79 hrs on ether */
  682.         u_long  TotAccepted;    /* count accepted by filter */
  683.         u_long  TotDrops;       /* count of dropped packets */
  684.         long    TotMissed;      /* missed by i/f during this run */
  685.         long    OrigMissed;     /* missed by i/f before this run */
  686. #ifdef linux
  687.         int pad;
  688.         int skip;
  689.         char *device;
  690. #endif
  691. };   
  692. struct pcap {
  693.         int fd;
  694.         int snapshot;
  695.         int linktype;
  696.         int tzoff;              /* timezone offset */
  697.         int offset;             /* offset for proper alignment */
  698.         struct pcap_sf sf;
  699.         struct pcap_md md;
  700.         /*
  701.          * Read buffer.
  702.          */
  703.         int bufsize;
  704.         u_char *buffer;
  705.         u_char *bp;
  706.         int cc;
  707.         /*
  708.          * Place holder for pcap_next().
  709.          */
  710.         u_char *pkt;
  711.         
  712.         /*
  713.          * Placeholder for filter code if bpf not in kernel.
  714.          */
  715.         struct bpf_program fcode;
  716.         char errbuf[PCAP_ERRBUF_SIZE];
  717. };
  718. /*
  719.  * the routines bpf_open and pcap_open_live really
  720.  * should not be here, and instead should be part of the
  721.  * pcap library.  Unfortunately, if we ever want to writes to
  722.  * the bpf fd, we need to open it r/w, and the normal pcap
  723.  * library does not permit us to do this.  So for now, here
  724.  * are these routines.
  725.  */
  726. #include <net/if.h>
  727. #ifdef MY_OWN_PCAP
  728. int
  729. PcapLiveNetwork::bpf_open(pcap_t *, char *errbuf, int how)
  730. {
  731.         int fd;
  732.         int n = 0;
  733.         char device[sizeof "/dev/bpf000"];
  734.         /*
  735.          * Go through all the minors and find one that isn't in use.
  736.          */
  737.         do {
  738.                 (void)sprintf(device, "/dev/bpf%d", n++);
  739.                 fd = ::open(device, how, 0);
  740.         } while (fd < 0 && n < 1000 && errno == EBUSY);
  741.         /*
  742.          * XXX better message for all minors used
  743.          */
  744.         if (fd < 0)
  745.                 sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
  746.         return (fd);
  747. }
  748. pcap_t *
  749. PcapLiveNetwork::pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf, int how)
  750. {
  751.         int fd;
  752.         struct ifreq ifr;
  753.         struct bpf_version bv;
  754.         u_int v;
  755.         pcap_t *p;
  756.         p = (pcap_t *)malloc(sizeof(*p));
  757.         if (p == NULL) {
  758.                 sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
  759.                 return (NULL);
  760.         }
  761.         bzero(p, sizeof(*p));
  762.         fd = bpf_open(p, ebuf, how);
  763.         if (fd < 0)
  764.                 goto bad;
  765.         p->fd = fd;
  766.         p->snapshot = snaplen;
  767.         if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
  768.                 sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
  769.                 goto bad;
  770.         }
  771.         if (bv.bv_major != BPF_MAJOR_VERSION ||
  772.             bv.bv_minor < BPF_MINOR_VERSION) {
  773.                 sprintf(ebuf, "kernel bpf filter out of date");
  774.                 goto bad;
  775.         }
  776.         (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
  777.         if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
  778.                 sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
  779.                 goto bad;
  780.         }
  781.         /* Get the data link layer type. */
  782.         if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
  783.                 sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
  784.                 goto bad;
  785.         }
  786. #if _BSDI_VERSION - 0 >= 199510
  787.         /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
  788.         switch (v) {
  789.         case DLT_SLIP:
  790.                 v = DLT_SLIP_BSDOS;
  791.                 break;
  792.         case DLT_PPP:
  793.                 v = DLT_PPP_BSDOS;
  794.                 break;
  795.         }
  796. #endif  
  797.         p->linktype = v;
  798.         /* set timeout */
  799.         if (to_ms != 0) {
  800.                 struct timeval to;
  801.                 to.tv_sec = to_ms / 1000;
  802.                 to.tv_usec = (to_ms * 1000) % 1000000;
  803.                 if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
  804.                         sprintf(ebuf, "BIOCSRTIMEOUT: %s",
  805.                                 pcap_strerror(errno));
  806.                         goto bad;
  807.                 }
  808.         }
  809.         if (promisc)
  810.                 /* set promiscuous mode, okay if it fails */
  811.                 (void)ioctl(p->fd, BIOCPROMISC, NULL); 
  812.         if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
  813.                 sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
  814.                 goto bad;
  815.         }   
  816.         p->bufsize = v;
  817.         p->buffer = (u_char *)malloc(p->bufsize);
  818.         if (p->buffer == NULL) {
  819.                 sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
  820.                 goto bad;
  821.         }       
  822.         return (p);
  823.  bad:   
  824.         ::close(fd);
  825.         free(p);
  826.         return (NULL);
  827. }
  828. #endif // MY_OWN_PCAP