Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

ping_responder.cc

Go to the documentation of this file.
00001 /*    
00002  * Copyright (c) 1998 Regents of the University of California.
00003  * All rights reserved.
00004  *    
00005  * Redistribution and use in source and binary forms, with or without 
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. All advertising materials mentioning features or use of this software
00014  *    must display the following acknowledgement:
00015  *      This product includes software developed by the Network Research
00016  *      Group at Lawrence Berkeley National Laboratory.
00017  * 4. Neither the name of the University nor of the Laboratory may be used
00018  *    to endorse or promote products derived from this software without
00019  *    specific prior written permission.
00020  *   
00021  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
00028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00031  * SUCH DAMAGE.
00032  */  
00033 
00034 #ifndef lint
00035 static const char rcsid[] =
00036     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/ping_responder.cc,v 1.8 2000/09/01 03:04:10 haoboy Exp $";
00037 #endif
00038 
00039 #include <stdio.h>
00040 #include <sys/types.h>
00041 #include <netinet/in.h>
00042 #include <netinet/in_systm.h>
00043 #include <netinet/ip.h>
00044 #include <netinet/ip_icmp.h>
00045 #include <netinet/ip_icmp.h>
00046 #include <arpa/inet.h>
00047 
00048 #include "agent.h"
00049 #include "scheduler.h"
00050 #include "emulate/internet.h"
00051 
00052 //
00053 // ping_responder.cc -- this agent may be inserted into nse as
00054 // a real-world responder to ICMP ECHOREQUEST operations.  It's
00055 // used to test emulation mode, mostly (and in particular the rt scheduler)
00056 // 
00057 
00058 class PingResponder : public Agent {
00059 public:
00060         PingResponder() : Agent(PT_LIVE) { }
00061         void recv(Packet*, Handler*);
00062 protected:
00063         icmp* validate(int, ip*);
00064         void reflect(ip*);
00065 };
00066 
00067 static class PingResponderClass : public TclClass { 
00068 public:
00069         PingResponderClass() : TclClass("Agent/PingResponder") {}
00070         TclObject* create(int , const char*const*) {
00071                 return (new PingResponder());
00072         } 
00073 } class_pingresponder;
00074 
00075 /*
00076  * receive an ICMP echo request packet from the simulator.
00077  * Actual IP packet is in the "data" portion of the packet, and
00078  * is assumed to start with the IP header
00079  */
00080 
00081 void
00082 PingResponder::recv(Packet* pkt, Handler*)
00083 {
00084         hdr_cmn *ch = HDR_CMN(pkt);
00085         int psize = ch->size();
00086         u_char* payload = pkt->accessdata();
00087 
00088         if (payload == NULL) {
00089                 fprintf(stderr, "%f: PingResponder(%s): recv NULL data area\n",
00090                         Scheduler::instance().clock(), name());
00091                 Packet::free(pkt);
00092                 return;
00093         }
00094 
00095         /*
00096          * assume here that the data area contains an IP header!
00097          */
00098 
00099         icmp* icmph;
00100         if ((icmph = validate(psize, (ip*) payload)) == NULL) {
00101                 Internet::print_ip((ip*) payload);
00102                 Packet::free(pkt);
00103                 return;
00104         }
00105 
00106 
00107         /*
00108          * tasks: change icmp type to echo-reply, recompute IP hdr cksum,
00109          * recompute ICMP cksum
00110          */
00111 
00112         icmph->icmp_type = ICMP_ECHOREPLY;
00113         reflect((ip*) payload);         // like kernel routine icmp_reflect()
00114 
00115         /*
00116          * set up simulator packet to go to the correct place
00117          */
00118 
00119         Agent::initpkt(pkt);
00120         ch->size() = psize; // will have been overwrittin by initpkt
00121 
00122         target_->recv(pkt);
00123         return;
00124 }
00125 
00126 /*
00127  * check a bunch of stuff:
00128  *      ip vers ok, ip hlen is 5, proto is icmp, len big enough,
00129  *      not fragmented, cksum ok, saddr not mcast/bcast
00130  */
00131 
00132 icmp*
00133 PingResponder::validate(int sz, ip* iph)
00134 {
00135         if (sz < 20) {
00136                 fprintf(stderr, "%f: PingResponder(%s): sim pkt too small for base IP header(%d)\n",
00137                         Scheduler::instance().clock(), name(), sz);
00138                 return (NULL);
00139         }
00140 
00141         int ipver = (*((char*)iph) & 0xf0) >> 4;
00142         if (ipver != 4) {
00143                 fprintf(stderr, "%f: PingResponder(%s): IP bad ver (%d)\n",
00144                         Scheduler::instance().clock(), name(), ipver);
00145                 return (NULL);
00146         }
00147 
00148         int iplen = ntohs(iph->ip_len);
00149         int iphlen = (*((char*)iph) & 0x0f) << 2;
00150         if (iplen < (iphlen + 8)) {
00151                 fprintf(stderr, "%f: PingResponder(%s): IP dgram not long enough (len: %d)\n",
00152                         Scheduler::instance().clock(), name(), iplen);
00153                 return (NULL);
00154         }
00155 
00156         if (sz < iplen) {
00157                 fprintf(stderr, "%f: PingResponder(%s): IP dgram not long enough (len: %d)\n",
00158                         Scheduler::instance().clock(), name(), iplen);
00159                 return (NULL);
00160         }
00161 
00162         if (iphlen != 20) {
00163                 fprintf(stderr, "%f: PingResponder(%s): IP bad hlen (%d)\n",
00164                         Scheduler::instance().clock(), name(), iphlen);
00165                 return (NULL);
00166         }
00167 
00168         if (Internet::in_cksum((u_short*) iph, iphlen)) {
00169                 fprintf(stderr, "%f: PingResponder(%s): IP bad cksum\n",
00170                         Scheduler::instance().clock(), name());
00171                 return (NULL);
00172         }
00173 
00174         if (iph->ip_p != IPPROTO_ICMP) {
00175                 fprintf(stderr, "%f: PingResponder(%s): not ICMP (proto: %d)\n",
00176                         Scheduler::instance().clock(), name(), iph->ip_p);
00177                 return (NULL);
00178         }
00179 
00180 
00181         if (iph->ip_off != 0) {
00182                 fprintf(stderr, "%f: PingResponder(%s): fragment! (off: 0x%x)\n",
00183                         Scheduler::instance().clock(), name(), ntohs(iph->ip_off));
00184                 return (NULL);
00185         }
00186 
00187         if (iph->ip_src.s_addr == 0xffffffff || iph->ip_src.s_addr == 0) {
00188                 fprintf(stderr, "%f: PingResponder(%s): bad src addr (%s)\n",
00189                         Scheduler::instance().clock(), name(),
00190                         inet_ntoa(iph->ip_src));
00191                 return (NULL);
00192         }
00193 
00194         if (IN_MULTICAST(ntohl(iph->ip_src.s_addr))) {
00195                 fprintf(stderr, "%f: PingResponder(%s): mcast src addr (%s)\n",
00196                         Scheduler::instance().clock(), name(),
00197                         inet_ntoa(iph->ip_src));
00198                 return (NULL);
00199         }
00200         icmp* icp = (icmp*) (iph + 1);
00201         if (Internet::in_cksum((u_short*) icp, iplen - iphlen) != 0) {
00202                 fprintf(stderr,
00203                         "%f: PingResponder(%s): bad ICMP cksum\n",
00204                         Scheduler::instance().clock(), name());
00205                 return (NULL);
00206         }
00207         if (icp->icmp_type != ICMP_ECHO) {
00208                 fprintf(stderr, "%f: PingResponder(%s): not echo request (%d)\n",
00209                         Scheduler::instance().clock(), name(),
00210                         icp->icmp_type);
00211                 return (NULL);
00212         }
00213 
00214         if (icp->icmp_code != 0) {
00215                 fprintf(stderr, "%f: PingResponder(%s): bad code (%d)\n",
00216                         Scheduler::instance().clock(), name(),
00217                         icp->icmp_code);
00218                 return (NULL);
00219         }
00220         return (icp);
00221 }
00222 
00223 /*
00224  * reflect: fix up the IP and ICMP info to reflect the packet
00225  * back from where it came in real life
00226  *
00227  * this routine will just assume no IP options on the pkt
00228  */
00229 
00230 void
00231 PingResponder::reflect(ip* iph)
00232 {
00233         in_addr daddr = iph->ip_dst;
00234         int iplen = ntohs(iph->ip_len);
00235         int iphlen = (*((char*)iph) & 0x0f) << 2;
00236 
00237         /* swap src and dest IP addresses on IP header */
00238         iph->ip_dst = iph->ip_src;
00239         iph->ip_src = daddr;
00240         iph->ip_sum = 0;
00241         iph->ip_sum = Internet::in_cksum((u_short*) iph, iphlen);
00242 
00243         /* recompute the icmp cksum */
00244         icmp* icp = (icmp*)(iph + 1);   // just past standard IP header
00245         icp->icmp_cksum = 0;
00246         icp->icmp_cksum = Internet::in_cksum((u_short*)icp, iplen - iphlen);
00247 }

Generated on Tue Apr 20 12:14:27 2004 for NS2.26SourcesOriginal by doxygen 1.3.3