📄 ping_responder.cc
字号:
/* * 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 lintstatic const char rcsid[] = "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/ping_responder.cc,v 1.7 1998/05/27 23:21:38 kfall Exp $";#endif#include <stdio.h>#include <sys/types.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <netinet/ip_icmp.h>#include <arpa/inet.h>#include "agent.h"#include "scheduler.h"#include "emulate/internet.h"//// ping_responder.cc -- this agent may be inserted into nse as// a real-world responder to ICMP ECHOREQUEST operations. It's// used to test emulation mode, mostly (and in particular the rt scheduler)// class PingResponder : public Agent {public: PingResponder() : Agent(PT_LIVE) { } void recv(Packet*, Handler*);protected: icmp* validate(int, ip*); void reflect(ip*);};static class PingResponderClass : public TclClass { public: PingResponderClass() : TclClass("Agent/PingResponder") {} TclObject* create(int , const char*const*) { return (new PingResponder()); } } class_pingresponder;/* * receive an ICMP echo request packet from the simulator. * Actual IP packet is in the "data" portion of the packet, and * is assumed to start with the IP header */voidPingResponder::recv(Packet* pkt, Handler*){ hdr_cmn *ch = (hdr_cmn*)pkt->access(off_cmn_); int psize = ch->size(); u_char* payload = pkt->accessdata(); if (payload == NULL) { fprintf(stderr, "%f: PingResponder(%s): recv NULL data area\n", Scheduler::instance().clock(), name()); Packet::free(pkt); return; } /* * assume here that the data area contains an IP header! */ icmp* icmph; if ((icmph = validate(psize, (ip*) payload)) == NULL) { Internet::print_ip((ip*) payload); Packet::free(pkt); return; } /* * tasks: change icmp type to echo-reply, recompute IP hdr cksum, * recompute ICMP cksum */ icmph->icmp_type = ICMP_ECHOREPLY; reflect((ip*) payload); // like kernel routine icmp_reflect() /* * set up simulator packet to go to the correct place */ Agent::initpkt(pkt); ch->size() = psize; // will have been overwrittin by initpkt target_->recv(pkt); return;}/* * check a bunch of stuff: * ip vers ok, ip hlen is 5, proto is icmp, len big enough, * not fragmented, cksum ok, saddr not mcast/bcast */icmp*PingResponder::validate(int sz, ip* iph){ if (sz < 20) { fprintf(stderr, "%f: PingResponder(%s): sim pkt too small for base IP header(%d)\n", Scheduler::instance().clock(), name(), sz); return (NULL); } int ipver = (*((char*)iph) & 0xf0) >> 4; if (ipver != 4) { fprintf(stderr, "%f: PingResponder(%s): IP bad ver (%d)\n", Scheduler::instance().clock(), name(), ipver); return (NULL); } int iplen = ntohs(iph->ip_len); int iphlen = (*((char*)iph) & 0x0f) << 2; if (iplen < (iphlen + 8)) { fprintf(stderr, "%f: PingResponder(%s): IP dgram not long enough (len: %d)\n", Scheduler::instance().clock(), name(), iplen); return (NULL); } if (sz < iplen) { fprintf(stderr, "%f: PingResponder(%s): IP dgram not long enough (len: %d)\n", Scheduler::instance().clock(), name(), iplen); return (NULL); } if (iphlen != 20) { fprintf(stderr, "%f: PingResponder(%s): IP bad hlen (%d)\n", Scheduler::instance().clock(), name(), iphlen); return (NULL); } if (Internet::in_cksum((u_short*) iph, iphlen)) { fprintf(stderr, "%f: PingResponder(%s): IP bad cksum\n", Scheduler::instance().clock(), name()); return (NULL); } if (iph->ip_p != IPPROTO_ICMP) { fprintf(stderr, "%f: PingResponder(%s): not ICMP (proto: %d)\n", Scheduler::instance().clock(), name(), iph->ip_p); return (NULL); } if (iph->ip_off != 0) { fprintf(stderr, "%f: PingResponder(%s): fragment! (off: 0x%x)\n", Scheduler::instance().clock(), name(), ntohs(iph->ip_off)); return (NULL); } if (iph->ip_src.s_addr == 0xffffffff || iph->ip_src.s_addr == 0) { fprintf(stderr, "%f: PingResponder(%s): bad src addr (%s)\n", Scheduler::instance().clock(), name(), inet_ntoa(iph->ip_src)); return (NULL); } if (IN_MULTICAST(ntohl(iph->ip_src.s_addr))) { fprintf(stderr, "%f: PingResponder(%s): mcast src addr (%s)\n", Scheduler::instance().clock(), name(), inet_ntoa(iph->ip_src)); return (NULL); } icmp* icp = (icmp*) (iph + 1); if (Internet::in_cksum((u_short*) icp, iplen - iphlen) != 0) { fprintf(stderr, "%f: PingResponder(%s): bad ICMP cksum\n", Scheduler::instance().clock(), name()); return (NULL); } if (icp->icmp_type != ICMP_ECHO) { fprintf(stderr, "%f: PingResponder(%s): not echo request (%d)\n", Scheduler::instance().clock(), name(), icp->icmp_type); return (NULL); } if (icp->icmp_code != 0) { fprintf(stderr, "%f: PingResponder(%s): bad code (%d)\n", Scheduler::instance().clock(), name(), icp->icmp_code); return (NULL); } return (icp);}/* * reflect: fix up the IP and ICMP info to reflect the packet * back from where it came in real life * * this routine will just assume no IP options on the pkt */voidPingResponder::reflect(ip* iph){ in_addr daddr = iph->ip_dst; int iplen = ntohs(iph->ip_len); int iphlen = (*((char*)iph) & 0x0f) << 2; /* swap src and dest IP addresses on IP header */ iph->ip_dst = iph->ip_src; iph->ip_src = daddr; iph->ip_sum = 0; iph->ip_sum = Internet::in_cksum((u_short*) iph, iphlen); /* recompute the icmp cksum */ icmp* icp = (icmp*)(iph + 1); // just past standard IP header icp->icmp_cksum = 0; icp->icmp_cksum = Internet::in_cksum((u_short*)icp, iplen - iphlen);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -