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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1998 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 Network Research
  16.  *      Group at Lawrence Berkeley National Laboratory.
  17.  * 4. Neither the name of the University nor of the Laboratory may be used
  18.  *    to endorse or promote products derived from this software without
  19.  *    specific prior written permission.
  20.  *   
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  31.  * SUCH DAMAGE.
  32.  */  
  33. #ifndef lint
  34. static const char rcsid[] =
  35.     "@(#) $Header: /cvsroot/nsnam/ns-2/emulate/arp.cc,v 1.8 2000/11/09 17:42:23 haoboy Exp $";
  36. #endif
  37. #include "object.h"
  38. #include "packet.h"
  39. #include <sys/types.h>
  40. #include <sys/param.h>
  41. #include <sys/socket.h>
  42. #include <sys/ioctl.h>
  43. #include <netinet/in.h>
  44. #include <netinet/in_systm.h>
  45. #include <netinet/ip.h>
  46. #include <net/if.h>
  47. #include <net/ethernet.h>
  48. #include <net/if_arp.h>
  49. #include <netinet/if_ether.h>
  50. #include <arpa/inet.h>
  51. #include <memory.h>
  52. #include <stdio.h>
  53. #include <errno.h>
  54. #include "emulate/net.h"
  55. #include "emulate/ether.h"
  56. #include "emulate/internet.h"
  57. // Very very very back hack. Should put this detection in autoconf.
  58. #ifndef ether_aton
  59. extern "C" {
  60. ether_addr* ether_aton(const char *);
  61. }
  62. #endif
  63. //
  64. // arp.cc -- this object may be used within nse as
  65. // an ARP requestor/responder.  Only the request side
  66. // is implemented now [5/98]
  67. // 
  68. class ArpAgent : public NsObject, public IOHandler {
  69. public:
  70. ArpAgent();
  71. ~ArpAgent();
  72. protected:
  73. struct acache_entry {
  74. in_addr ip;
  75. ether_addr ether;
  76. char code; // 'D' - dynamic, 'P' - publish
  77. };
  78. char icode(const char*);
  79. acache_entry* find(in_addr&);
  80. void  insert(in_addr&, ether_addr&, char code);
  81. void dispatch(int);
  82. int sendreq(in_addr&);
  83. int sendresp(ether_addr&, in_addr&, ether_addr&);
  84. int resolve(const char* host, char*& result, int sendreq);
  85. void doreq(ether_arp*);
  86. void doreply(ether_arp*);
  87. void recv(Packet*, Handler*) { abort(); }
  88. int command(int, const char*const*);
  89. Network* net_;
  90. ether_header eh_template_;
  91. ether_arp ea_template_;
  92. ether_addr my_ether_;
  93. in_addr my_ip_;
  94. int base_size_; // size of rcv buf
  95. u_char* rcv_buf_;
  96. acache_entry* acache_; // arp mapping cache
  97. int nacache_; // # entries in cache
  98. int cur_; // cur posn in cache
  99. int pending_; // resolve pending?
  100. };
  101. static class ArpAgentClass : public TclClass { 
  102. public:
  103.         ArpAgentClass() : TclClass("ArpAgent") {}
  104.         TclObject* create(int , const char*const*) {
  105.                 return (new ArpAgent());
  106.         } 
  107. } class_arpagent;
  108. ArpAgent::ArpAgent() : net_(NULL), pending_(0)
  109. {
  110. /* dest addr is broadcast */
  111. eh_template_.ether_dhost[0] = 0xff;
  112. eh_template_.ether_dhost[1] = 0xff;
  113. eh_template_.ether_dhost[2] = 0xff;
  114. eh_template_.ether_dhost[3] = 0xff;
  115. eh_template_.ether_dhost[4] = 0xff;
  116. eh_template_.ether_dhost[5] = 0xff;
  117. /* src addr is mine */
  118. memcpy(&eh_template_.ether_shost, &my_ether_, ETHER_ADDR_LEN);
  119. /* type is ARP */
  120. eh_template_.ether_type = htons(ETHERTYPE_ARP);
  121. ea_template_.ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
  122. ea_template_.ea_hdr.ar_pro = htons(ETHERTYPE_IP);
  123. ea_template_.ea_hdr.ar_hln = ETHER_ADDR_LEN;
  124. ea_template_.ea_hdr.ar_pln = 4; /* ip addr len */
  125. ea_template_.ea_hdr.ar_op = htons(ARPOP_REQUEST);
  126. memcpy(&ea_template_.arp_sha, &my_ether_, ETHER_ADDR_LEN); /* sender hw */
  127. memset(&ea_template_.arp_spa, 0, 4); /* sender IP */
  128. memset(&ea_template_.arp_tha, 0, ETHER_ADDR_LEN); /* target hw */
  129. memset(&ea_template_.arp_tpa, 0, 4); /* target hw */
  130. base_size_ = sizeof(eh_template_) + sizeof(ea_template_);
  131. rcv_buf_ = new u_char[base_size_];
  132. bind("cachesize_", &nacache_);
  133. acache_ = new acache_entry[nacache_];
  134. memset(acache_, 0, nacache_*sizeof(acache_entry));
  135. cur_ = nacache_;
  136. }
  137. ArpAgent::~ArpAgent()
  138. {
  139. delete[] rcv_buf_;
  140. delete[] acache_;
  141. }
  142. ArpAgent::acache_entry*
  143. ArpAgent::find(in_addr& target)
  144. {
  145. int n = nacache_;
  146. acache_entry* ae = &acache_[n-1];
  147. while (--n >= 0) {
  148. if (ae->ip.s_addr == target.s_addr) {
  149. return (ae);
  150. }
  151. --ae;
  152. }
  153. return (NULL);
  154. }
  155. char
  156. ArpAgent::icode(const char *how)
  157. {
  158. if (strcmp(how, "publish") == 0)
  159. return 'P';
  160. return 'D';
  161. }
  162. void
  163. ArpAgent::insert(in_addr& target, ether_addr& eaddr, char code)
  164. {
  165. acache_entry* ae;
  166. if (--cur_ < 0)
  167. cur_ = nacache_ - 1;
  168. ae = &acache_[cur_];
  169. ae->ip = target;
  170. ae->ether = eaddr;
  171. ae->code = code;
  172. //printf("INSERTED inet %s, ether %sn",
  173. //inet_ntoa(target), Ethernet::etheraddr_string((u_char*)&eaddr));
  174. return;
  175. }
  176. int
  177. ArpAgent::sendreq(in_addr& target)
  178. {
  179. int pktsz = sizeof(eh_template_) + sizeof(ea_template_);
  180. if (pktsz < 64)
  181. pktsz = 64;
  182. u_char* buf = new u_char[pktsz];
  183. memset(buf, 0, pktsz);
  184. ether_header* eh = (ether_header*) buf;
  185. ether_arp* ea = (ether_arp*) (buf + sizeof(eh_template_));
  186. *eh = eh_template_; /* set ether header */
  187. *ea = ea_template_; /* set ether/IP arp pkt */
  188. memcpy(ea->arp_tpa, &target, sizeof(target));
  189. if (net_->send(buf, pktsz) < 0) {
  190.                 fprintf(stderr,
  191.                     "ArpAgent(%s): sendpkt (%p, %d): %sn",
  192.                     name(), buf, pktsz, strerror(errno));
  193.                 return (-1);
  194. }
  195. delete[] buf;
  196. return (0);
  197. }
  198. /*
  199.  * resp: who to send response to
  200.  * tip: the IP address we are responding for
  201.  * tea: the ether address we want to advertise with tip
  202.  */
  203. int
  204. ArpAgent::sendresp(ether_addr& dest, in_addr& tip, ether_addr& tea)
  205. {
  206. int pktsz = sizeof(eh_template_) + sizeof(ea_template_);
  207. if (pktsz < 64)
  208. pktsz = 64;
  209. u_char* buf = new u_char[pktsz];
  210. memset(buf, 0, pktsz);
  211. ether_header* eh = (ether_header*) buf;
  212. ether_arp* ea = (ether_arp*) (buf + sizeof(eh_template_));
  213. // destination link layer address is back to sender
  214. // (called dest here)
  215. *eh = eh_template_; /* set ether header */
  216. memcpy(eh->ether_dhost, &dest, ETHER_ADDR_LEN);
  217. // set code as ARP reply
  218. *ea = ea_template_; /* set ether/IP arp pkt */
  219. ea->ea_hdr.ar_op = htons(ARPOP_REPLY);
  220. // make it look like a regular arp reply
  221. memcpy(ea->arp_tpa, ea->arp_spa, sizeof(in_addr));
  222. memcpy(ea->arp_tha, ea->arp_sha, sizeof(in_addr));
  223. memcpy(ea->arp_sha, &tea, ETHER_ADDR_LEN);
  224. memcpy(ea->arp_spa, &tip, ETHER_ADDR_LEN);
  225. if (net_->send(buf, pktsz) < 0) {
  226.                 fprintf(stderr,
  227.                     "ArpAgent(%s): sendpkt (%p, %d): %sn",
  228.                     name(), buf, pktsz, strerror(errno));
  229.                 return (-1);
  230. }
  231. delete[] buf;
  232. return (0);
  233. }
  234. /*
  235.  * receive pkt from network:
  236.  * note that net->recv() gives us the pkt starting
  237.  * just BEYOND the frame header
  238.  */
  239. void
  240. ArpAgent::dispatch(int)
  241. {
  242. double ts;
  243. sockaddr sa;
  244. int cc = net_->recv(rcv_buf_, base_size_, sa, ts);
  245. if (cc < int(base_size_ - sizeof(ether_header))) {
  246. if (cc == 0)
  247. return;
  248.                 fprintf(stderr,
  249.                     "ArpAgent(%s): recv small pkt (%d) [base sz:%d]: %sn",
  250.                     name(), cc, base_size_, strerror(errno));
  251. return;
  252. }
  253. ether_arp* ea = (ether_arp*) rcv_buf_;
  254. int op = ntohs(ea->ea_hdr.ar_op);
  255. switch (op) {
  256. case ARPOP_REPLY:
  257. doreply(ea);
  258. break;
  259. case ARPOP_REQUEST:
  260. doreq(ea);
  261. break;
  262. default:
  263. fprintf(stderr,
  264.     "ArpAgent(%s): cannot interpret ARP op %dn",
  265.     name(), op);
  266. return;
  267. }
  268. return;
  269. }
  270. /*
  271.  * process an ARP reply frame -- insert into cache
  272.  */
  273. void
  274. ArpAgent::doreply(ether_arp* ea)
  275. {
  276. /*
  277.  * reply will be from the replier's point of view,
  278.  * so, look in the sender ha/pa fields for the info
  279.  * we want
  280.  */
  281. in_addr t;
  282. ether_addr e;
  283. memcpy(&t, ea->arp_spa, 4); // copy IP address
  284. memcpy(&e, ea->arp_sha, ETHER_ADDR_LEN);
  285. insert(t, e, 'D');
  286. return;
  287. }
  288. /*
  289.  * process an ARP request frame
  290.  */
  291. void
  292. ArpAgent::doreq(ether_arp* ea)
  293. {
  294. in_addr t;
  295. memcpy(&t, ea->arp_tpa, 4); // requested IP addr
  296. acache_entry *ae;
  297. if ((ae = find(t)) == NULL) {
  298. //printf("doreq: didn't find mapping for IP addr %sn",
  299. //inet_ntoa(t));
  300. return;
  301. }
  302. if (ae->code == 'P') {
  303. // return answer to the sender's hardware addr
  304. ether_addr dst;
  305. memcpy(&dst, ea->arp_sha, ETHER_ADDR_LEN);
  306. sendresp(dst, t, ae->ether);
  307. }
  308. return;
  309. }
  310. int
  311. ArpAgent::command(int argc, const char*const* argv)
  312. {
  313. Tcl& tcl = Tcl::instance();
  314. if (argc == 2) {
  315.                 if (strcmp(argv[1], "network") == 0) { 
  316. if (net_ == NULL)
  317. tcl.result("");
  318. else
  319. tcl.result(net_->name());
  320. return (TCL_OK);
  321. }
  322. } else if (argc == 3) {
  323.                 if (strcmp(argv[1], "network") == 0) { 
  324.                         net_ = (Network *)TclObject::lookup(argv[2]);
  325.                         if (net_ != 0) { 
  326. link(net_->rchannel(), TCL_READABLE);
  327. return (TCL_OK);
  328.                         } else {
  329.                                 fprintf(stderr,
  330.                                 "ArpAgent(%s): unknown network %sn",
  331.                                     name(), argv[2]);
  332.                                 return (TCL_ERROR);
  333.                         }       
  334.                         return(TCL_OK);
  335.                 }       
  336. if (strcmp(argv[1], "myether") == 0) {
  337. my_ether_ = *(::ether_aton((char*)argv[2]));
  338. memcpy(&eh_template_.ether_shost, &my_ether_,
  339. ETHER_ADDR_LEN);
  340. memcpy(&ea_template_.arp_sha,
  341. &my_ether_, ETHER_ADDR_LEN);
  342. return (TCL_OK);
  343. }
  344. if (strcmp(argv[1], "myip") == 0) {
  345. u_long a = inet_addr(argv[2]);
  346. if (a == 0)
  347. return (TCL_ERROR);
  348. in_addr ia;
  349. ia.s_addr = a;
  350. my_ip_ = ia;
  351. memcpy(&ea_template_.arp_spa,
  352. &my_ip_, 4);
  353. return (TCL_OK);
  354. }
  355. if (strcmp(argv[1], "lookup") == 0) {
  356. char *p = NULL;
  357. if (resolve(argv[2], p, 0) < 0)
  358. return (TCL_ERROR);
  359. if (p)
  360. tcl.result(p);
  361. return (TCL_OK);
  362. }
  363. if (strcmp(argv[1], "resolve") == 0) {
  364. char *p = NULL;
  365. if (resolve(argv[2], p, 1) < 0)
  366. return (TCL_ERROR);
  367. if (p)
  368. tcl.resultf("%s", p);
  369. return (TCL_OK);
  370. }
  371. } else if (argc == 5) {
  372. // $obj insert iaddr eaddr how
  373. if (strcmp(argv[1], "insert") == 0) {
  374. u_long a = inet_addr(argv[2]);
  375. if (a == 0)
  376. return (TCL_ERROR);
  377. in_addr ia;
  378. ia.s_addr = a;
  379. ether_addr ea = *(::ether_aton((char*)argv[3]));
  380. insert(ia, ea, icode(argv[4]));
  381. return (TCL_OK);
  382. }
  383. }
  384. return (NsObject::command(argc, argv));
  385. }
  386. int
  387. ArpAgent::resolve(const char* host, char*& result, int doreq)
  388. {
  389. u_long a = inet_addr(host);
  390. in_addr ia;
  391. ia.s_addr = a;
  392. acache_entry* ae;
  393. if ((ae = find(ia)) == NULL) {
  394. result = NULL;
  395. if (doreq)
  396. return(sendreq(ia));
  397. return (0);
  398. }
  399. result = Ethernet::etheraddr_string((u_char*) &ae->ether);
  400. return (1);
  401. }