arp.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
- /*
- * Copyright (c) 1998 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 Network Research
- * Group at Lawrence Berkeley National 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 lint
- static const char rcsid[] =
- "@(#) $Header: /cvsroot/nsnam/ns-2/emulate/arp.cc,v 1.8 2000/11/09 17:42:23 haoboy Exp $";
- #endif
- #include "object.h"
- #include "packet.h"
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <net/if.h>
- #include <net/ethernet.h>
- #include <net/if_arp.h>
- #include <netinet/if_ether.h>
- #include <arpa/inet.h>
- #include <memory.h>
- #include <stdio.h>
- #include <errno.h>
- #include "emulate/net.h"
- #include "emulate/ether.h"
- #include "emulate/internet.h"
- // Very very very back hack. Should put this detection in autoconf.
- #ifndef ether_aton
- extern "C" {
- ether_addr* ether_aton(const char *);
- }
- #endif
- //
- // arp.cc -- this object may be used within nse as
- // an ARP requestor/responder. Only the request side
- // is implemented now [5/98]
- //
- class ArpAgent : public NsObject, public IOHandler {
- public:
- ArpAgent();
- ~ArpAgent();
- protected:
- struct acache_entry {
- in_addr ip;
- ether_addr ether;
- char code; // 'D' - dynamic, 'P' - publish
- };
-
- char icode(const char*);
- acache_entry* find(in_addr&);
- void insert(in_addr&, ether_addr&, char code);
- void dispatch(int);
- int sendreq(in_addr&);
- int sendresp(ether_addr&, in_addr&, ether_addr&);
- int resolve(const char* host, char*& result, int sendreq);
- void doreq(ether_arp*);
- void doreply(ether_arp*);
- void recv(Packet*, Handler*) { abort(); }
- int command(int, const char*const*);
- Network* net_;
- ether_header eh_template_;
- ether_arp ea_template_;
- ether_addr my_ether_;
- in_addr my_ip_;
- int base_size_; // size of rcv buf
- u_char* rcv_buf_;
- acache_entry* acache_; // arp mapping cache
- int nacache_; // # entries in cache
- int cur_; // cur posn in cache
- int pending_; // resolve pending?
- };
- static class ArpAgentClass : public TclClass {
- public:
- ArpAgentClass() : TclClass("ArpAgent") {}
- TclObject* create(int , const char*const*) {
- return (new ArpAgent());
- }
- } class_arpagent;
- ArpAgent::ArpAgent() : net_(NULL), pending_(0)
- {
- /* dest addr is broadcast */
- eh_template_.ether_dhost[0] = 0xff;
- eh_template_.ether_dhost[1] = 0xff;
- eh_template_.ether_dhost[2] = 0xff;
- eh_template_.ether_dhost[3] = 0xff;
- eh_template_.ether_dhost[4] = 0xff;
- eh_template_.ether_dhost[5] = 0xff;
- /* src addr is mine */
- memcpy(&eh_template_.ether_shost, &my_ether_, ETHER_ADDR_LEN);
- /* type is ARP */
- eh_template_.ether_type = htons(ETHERTYPE_ARP);
- ea_template_.ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
- ea_template_.ea_hdr.ar_pro = htons(ETHERTYPE_IP);
- ea_template_.ea_hdr.ar_hln = ETHER_ADDR_LEN;
- ea_template_.ea_hdr.ar_pln = 4; /* ip addr len */
- ea_template_.ea_hdr.ar_op = htons(ARPOP_REQUEST);
- memcpy(&ea_template_.arp_sha, &my_ether_, ETHER_ADDR_LEN); /* sender hw */
- memset(&ea_template_.arp_spa, 0, 4); /* sender IP */
- memset(&ea_template_.arp_tha, 0, ETHER_ADDR_LEN); /* target hw */
- memset(&ea_template_.arp_tpa, 0, 4); /* target hw */
- base_size_ = sizeof(eh_template_) + sizeof(ea_template_);
- rcv_buf_ = new u_char[base_size_];
- bind("cachesize_", &nacache_);
- acache_ = new acache_entry[nacache_];
- memset(acache_, 0, nacache_*sizeof(acache_entry));
- cur_ = nacache_;
- }
- ArpAgent::~ArpAgent()
- {
- delete[] rcv_buf_;
- delete[] acache_;
- }
- ArpAgent::acache_entry*
- ArpAgent::find(in_addr& target)
- {
- int n = nacache_;
- acache_entry* ae = &acache_[n-1];
- while (--n >= 0) {
- if (ae->ip.s_addr == target.s_addr) {
- return (ae);
- }
- --ae;
- }
- return (NULL);
- }
- char
- ArpAgent::icode(const char *how)
- {
- if (strcmp(how, "publish") == 0)
- return 'P';
- return 'D';
- }
- void
- ArpAgent::insert(in_addr& target, ether_addr& eaddr, char code)
- {
- acache_entry* ae;
- if (--cur_ < 0)
- cur_ = nacache_ - 1;
- ae = &acache_[cur_];
- ae->ip = target;
- ae->ether = eaddr;
- ae->code = code;
- //printf("INSERTED inet %s, ether %sn",
- //inet_ntoa(target), Ethernet::etheraddr_string((u_char*)&eaddr));
- return;
- }
-
- int
- ArpAgent::sendreq(in_addr& target)
- {
- int pktsz = sizeof(eh_template_) + sizeof(ea_template_);
- if (pktsz < 64)
- pktsz = 64;
- u_char* buf = new u_char[pktsz];
- memset(buf, 0, pktsz);
- ether_header* eh = (ether_header*) buf;
- ether_arp* ea = (ether_arp*) (buf + sizeof(eh_template_));
- *eh = eh_template_; /* set ether header */
- *ea = ea_template_; /* set ether/IP arp pkt */
- memcpy(ea->arp_tpa, &target, sizeof(target));
- if (net_->send(buf, pktsz) < 0) {
- fprintf(stderr,
- "ArpAgent(%s): sendpkt (%p, %d): %sn",
- name(), buf, pktsz, strerror(errno));
- return (-1);
- }
- delete[] buf;
- return (0);
- }
- /*
- * resp: who to send response to
- * tip: the IP address we are responding for
- * tea: the ether address we want to advertise with tip
- */
- int
- ArpAgent::sendresp(ether_addr& dest, in_addr& tip, ether_addr& tea)
- {
- int pktsz = sizeof(eh_template_) + sizeof(ea_template_);
- if (pktsz < 64)
- pktsz = 64;
- u_char* buf = new u_char[pktsz];
- memset(buf, 0, pktsz);
- ether_header* eh = (ether_header*) buf;
- ether_arp* ea = (ether_arp*) (buf + sizeof(eh_template_));
- // destination link layer address is back to sender
- // (called dest here)
- *eh = eh_template_; /* set ether header */
- memcpy(eh->ether_dhost, &dest, ETHER_ADDR_LEN);
- // set code as ARP reply
- *ea = ea_template_; /* set ether/IP arp pkt */
- ea->ea_hdr.ar_op = htons(ARPOP_REPLY);
- // make it look like a regular arp reply
- memcpy(ea->arp_tpa, ea->arp_spa, sizeof(in_addr));
- memcpy(ea->arp_tha, ea->arp_sha, sizeof(in_addr));
- memcpy(ea->arp_sha, &tea, ETHER_ADDR_LEN);
- memcpy(ea->arp_spa, &tip, ETHER_ADDR_LEN);
- if (net_->send(buf, pktsz) < 0) {
- fprintf(stderr,
- "ArpAgent(%s): sendpkt (%p, %d): %sn",
- name(), buf, pktsz, strerror(errno));
- return (-1);
- }
- delete[] buf;
- return (0);
- }
- /*
- * receive pkt from network:
- * note that net->recv() gives us the pkt starting
- * just BEYOND the frame header
- */
- void
- ArpAgent::dispatch(int)
- {
- double ts;
- sockaddr sa;
- int cc = net_->recv(rcv_buf_, base_size_, sa, ts);
- if (cc < int(base_size_ - sizeof(ether_header))) {
- if (cc == 0)
- return;
- fprintf(stderr,
- "ArpAgent(%s): recv small pkt (%d) [base sz:%d]: %sn",
- name(), cc, base_size_, strerror(errno));
- return;
- }
- ether_arp* ea = (ether_arp*) rcv_buf_;
- int op = ntohs(ea->ea_hdr.ar_op);
- switch (op) {
- case ARPOP_REPLY:
- doreply(ea);
- break;
- case ARPOP_REQUEST:
- doreq(ea);
- break;
- default:
- fprintf(stderr,
- "ArpAgent(%s): cannot interpret ARP op %dn",
- name(), op);
- return;
- }
- return;
- }
- /*
- * process an ARP reply frame -- insert into cache
- */
- void
- ArpAgent::doreply(ether_arp* ea)
- {
- /*
- * reply will be from the replier's point of view,
- * so, look in the sender ha/pa fields for the info
- * we want
- */
- in_addr t;
- ether_addr e;
- memcpy(&t, ea->arp_spa, 4); // copy IP address
- memcpy(&e, ea->arp_sha, ETHER_ADDR_LEN);
- insert(t, e, 'D');
- return;
- }
- /*
- * process an ARP request frame
- */
- void
- ArpAgent::doreq(ether_arp* ea)
- {
- in_addr t;
- memcpy(&t, ea->arp_tpa, 4); // requested IP addr
- acache_entry *ae;
- if ((ae = find(t)) == NULL) {
- //printf("doreq: didn't find mapping for IP addr %sn",
- //inet_ntoa(t));
- return;
- }
- if (ae->code == 'P') {
- // return answer to the sender's hardware addr
- ether_addr dst;
- memcpy(&dst, ea->arp_sha, ETHER_ADDR_LEN);
- sendresp(dst, t, ae->ether);
- }
- return;
- }
- int
- ArpAgent::command(int argc, const char*const* argv)
- {
- Tcl& tcl = Tcl::instance();
- if (argc == 2) {
- if (strcmp(argv[1], "network") == 0) {
- if (net_ == NULL)
- tcl.result("");
- else
- tcl.result(net_->name());
- return (TCL_OK);
- }
- } else if (argc == 3) {
- if (strcmp(argv[1], "network") == 0) {
- net_ = (Network *)TclObject::lookup(argv[2]);
- if (net_ != 0) {
- link(net_->rchannel(), TCL_READABLE);
- return (TCL_OK);
- } else {
- fprintf(stderr,
- "ArpAgent(%s): unknown network %sn",
- name(), argv[2]);
- return (TCL_ERROR);
- }
- return(TCL_OK);
- }
- if (strcmp(argv[1], "myether") == 0) {
- my_ether_ = *(::ether_aton((char*)argv[2]));
- memcpy(&eh_template_.ether_shost, &my_ether_,
- ETHER_ADDR_LEN);
- memcpy(&ea_template_.arp_sha,
- &my_ether_, ETHER_ADDR_LEN);
- return (TCL_OK);
- }
- if (strcmp(argv[1], "myip") == 0) {
- u_long a = inet_addr(argv[2]);
- if (a == 0)
- return (TCL_ERROR);
- in_addr ia;
- ia.s_addr = a;
- my_ip_ = ia;
- memcpy(&ea_template_.arp_spa,
- &my_ip_, 4);
- return (TCL_OK);
- }
- if (strcmp(argv[1], "lookup") == 0) {
- char *p = NULL;
- if (resolve(argv[2], p, 0) < 0)
- return (TCL_ERROR);
- if (p)
- tcl.result(p);
- return (TCL_OK);
- }
- if (strcmp(argv[1], "resolve") == 0) {
- char *p = NULL;
- if (resolve(argv[2], p, 1) < 0)
- return (TCL_ERROR);
- if (p)
- tcl.resultf("%s", p);
- return (TCL_OK);
- }
- } else if (argc == 5) {
- // $obj insert iaddr eaddr how
- if (strcmp(argv[1], "insert") == 0) {
- u_long a = inet_addr(argv[2]);
- if (a == 0)
- return (TCL_ERROR);
- in_addr ia;
- ia.s_addr = a;
- ether_addr ea = *(::ether_aton((char*)argv[3]));
- insert(ia, ea, icode(argv[4]));
- return (TCL_OK);
- }
- }
- return (NsObject::command(argc, argv));
- }
- int
- ArpAgent::resolve(const char* host, char*& result, int doreq)
- {
- u_long a = inet_addr(host);
- in_addr ia;
- ia.s_addr = a;
- acache_entry* ae;
- if ((ae = find(ia)) == NULL) {
- result = NULL;
- if (doreq)
- return(sendreq(ia));
- return (0);
- }
- result = Ethernet::etheraddr_string((u_char*) &ae->ether);
- return (1);
- }