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 Mar 6 16:47:49 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6