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

通讯编程

开发平台:

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/ping_responder.cc,v 1.8 2000/09/01 03:04:10 haoboy Exp $";
  36. #endif
  37. #include <stdio.h>
  38. #include <sys/types.h>
  39. #include <netinet/in.h>
  40. #include <netinet/in_systm.h>
  41. #include <netinet/ip.h>
  42. #include <netinet/ip_icmp.h>
  43. #include <netinet/ip_icmp.h>
  44. #include <arpa/inet.h>
  45. #include "agent.h"
  46. #include "scheduler.h"
  47. #include "emulate/internet.h"
  48. //
  49. // ping_responder.cc -- this agent may be inserted into nse as
  50. // a real-world responder to ICMP ECHOREQUEST operations.  It's
  51. // used to test emulation mode, mostly (and in particular the rt scheduler)
  52. // 
  53. class PingResponder : public Agent {
  54. public:
  55. PingResponder() : Agent(PT_LIVE) { }
  56. void recv(Packet*, Handler*);
  57. protected:
  58. icmp* validate(int, ip*);
  59. void reflect(ip*);
  60. };
  61. static class PingResponderClass : public TclClass { 
  62. public:
  63.         PingResponderClass() : TclClass("Agent/PingResponder") {}
  64.         TclObject* create(int , const char*const*) {
  65.                 return (new PingResponder());
  66.         } 
  67. } class_pingresponder;
  68. /*
  69.  * receive an ICMP echo request packet from the simulator.
  70.  * Actual IP packet is in the "data" portion of the packet, and
  71.  * is assumed to start with the IP header
  72.  */
  73. void
  74. PingResponder::recv(Packet* pkt, Handler*)
  75. {
  76. hdr_cmn *ch = HDR_CMN(pkt);
  77. int psize = ch->size();
  78. u_char* payload = pkt->accessdata();
  79. if (payload == NULL) {
  80. fprintf(stderr, "%f: PingResponder(%s): recv NULL data arean",
  81. Scheduler::instance().clock(), name());
  82. Packet::free(pkt);
  83. return;
  84. }
  85. /*
  86.  * assume here that the data area contains an IP header!
  87.  */
  88. icmp* icmph;
  89. if ((icmph = validate(psize, (ip*) payload)) == NULL) {
  90. Internet::print_ip((ip*) payload);
  91. Packet::free(pkt);
  92. return;
  93. }
  94. /*
  95.  * tasks: change icmp type to echo-reply, recompute IP hdr cksum,
  96.  * recompute ICMP cksum
  97.  */
  98. icmph->icmp_type = ICMP_ECHOREPLY;
  99. reflect((ip*) payload); // like kernel routine icmp_reflect()
  100. /*
  101.  * set up simulator packet to go to the correct place
  102.  */
  103. Agent::initpkt(pkt);
  104. ch->size() = psize; // will have been overwrittin by initpkt
  105. target_->recv(pkt);
  106. return;
  107. }
  108. /*
  109.  * check a bunch of stuff:
  110.  * ip vers ok, ip hlen is 5, proto is icmp, len big enough,
  111.  * not fragmented, cksum ok, saddr not mcast/bcast
  112.  */
  113. icmp*
  114. PingResponder::validate(int sz, ip* iph)
  115. {
  116. if (sz < 20) {
  117. fprintf(stderr, "%f: PingResponder(%s): sim pkt too small for base IP header(%d)n",
  118. Scheduler::instance().clock(), name(), sz);
  119. return (NULL);
  120. }
  121. int ipver = (*((char*)iph) & 0xf0) >> 4;
  122. if (ipver != 4) {
  123. fprintf(stderr, "%f: PingResponder(%s): IP bad ver (%d)n",
  124. Scheduler::instance().clock(), name(), ipver);
  125. return (NULL);
  126. }
  127. int iplen = ntohs(iph->ip_len);
  128. int iphlen = (*((char*)iph) & 0x0f) << 2;
  129. if (iplen < (iphlen + 8)) {
  130. fprintf(stderr, "%f: PingResponder(%s): IP dgram not long enough (len: %d)n",
  131. Scheduler::instance().clock(), name(), iplen);
  132. return (NULL);
  133. }
  134. if (sz < iplen) {
  135. fprintf(stderr, "%f: PingResponder(%s): IP dgram not long enough (len: %d)n",
  136. Scheduler::instance().clock(), name(), iplen);
  137. return (NULL);
  138. }
  139. if (iphlen != 20) {
  140. fprintf(stderr, "%f: PingResponder(%s): IP bad hlen (%d)n",
  141. Scheduler::instance().clock(), name(), iphlen);
  142. return (NULL);
  143. }
  144. if (Internet::in_cksum((u_short*) iph, iphlen)) {
  145. fprintf(stderr, "%f: PingResponder(%s): IP bad cksumn",
  146. Scheduler::instance().clock(), name());
  147. return (NULL);
  148. }
  149. if (iph->ip_p != IPPROTO_ICMP) {
  150. fprintf(stderr, "%f: PingResponder(%s): not ICMP (proto: %d)n",
  151. Scheduler::instance().clock(), name(), iph->ip_p);
  152. return (NULL);
  153. }
  154. if (iph->ip_off != 0) {
  155. fprintf(stderr, "%f: PingResponder(%s): fragment! (off: 0x%x)n",
  156. Scheduler::instance().clock(), name(), ntohs(iph->ip_off));
  157. return (NULL);
  158. }
  159. if (iph->ip_src.s_addr == 0xffffffff || iph->ip_src.s_addr == 0) {
  160. fprintf(stderr, "%f: PingResponder(%s): bad src addr (%s)n",
  161. Scheduler::instance().clock(), name(),
  162. inet_ntoa(iph->ip_src));
  163. return (NULL);
  164. }
  165. if (IN_MULTICAST(ntohl(iph->ip_src.s_addr))) {
  166. fprintf(stderr, "%f: PingResponder(%s): mcast src addr (%s)n",
  167. Scheduler::instance().clock(), name(),
  168. inet_ntoa(iph->ip_src));
  169. return (NULL);
  170. }
  171. icmp* icp = (icmp*) (iph + 1);
  172. if (Internet::in_cksum((u_short*) icp, iplen - iphlen) != 0) {
  173. fprintf(stderr,
  174. "%f: PingResponder(%s): bad ICMP cksumn",
  175. Scheduler::instance().clock(), name());
  176. return (NULL);
  177. }
  178. if (icp->icmp_type != ICMP_ECHO) {
  179. fprintf(stderr, "%f: PingResponder(%s): not echo request (%d)n",
  180. Scheduler::instance().clock(), name(),
  181. icp->icmp_type);
  182. return (NULL);
  183. }
  184. if (icp->icmp_code != 0) {
  185. fprintf(stderr, "%f: PingResponder(%s): bad code (%d)n",
  186. Scheduler::instance().clock(), name(),
  187. icp->icmp_code);
  188. return (NULL);
  189. }
  190. return (icp);
  191. }
  192. /*
  193.  * reflect: fix up the IP and ICMP info to reflect the packet
  194.  * back from where it came in real life
  195.  *
  196.  * this routine will just assume no IP options on the pkt
  197.  */
  198. void
  199. PingResponder::reflect(ip* iph)
  200. {
  201. in_addr daddr = iph->ip_dst;
  202. int iplen = ntohs(iph->ip_len);
  203. int iphlen = (*((char*)iph) & 0x0f) << 2;
  204. /* swap src and dest IP addresses on IP header */
  205. iph->ip_dst = iph->ip_src;
  206. iph->ip_src = daddr;
  207. iph->ip_sum = 0;
  208. iph->ip_sum = Internet::in_cksum((u_short*) iph, iphlen);
  209. /* recompute the icmp cksum */
  210. icmp* icp = (icmp*)(iph + 1); // just past standard IP header
  211. icp->icmp_cksum = 0;
  212. icp->icmp_cksum = Internet::in_cksum((u_short*)icp, iplen - iphlen);
  213. }