00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "TCPDump.h"
00023 #include "IPControlInfo_m.h"
00024 #include "SCTPMessage.h"
00025 #include "SCTPAssociation.h"
00026 #include "IPSerializer.h"
00027 #include "ICMPMessage.h"
00028 #include "UDPPacket_m.h"
00029
00030 #if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) && !defined(__CYGWIN__) && !defined(_WIN64)
00031 #include <netinet/in.h>
00032 #endif
00033
00034 #define MAXBUFLENGTH 65536
00035
00036 TCPDumper::TCPDumper(std::ostream& out)
00037 {
00038 outp = &out;
00039 }
00040
00041 TCPDumper::~TCPDumper()
00042 {
00043 }
00044
00045 void TCPDumper::ipDump(const char *label, IPDatagram *dgram, const char *comment)
00046 {
00047 if (dynamic_cast<SCTPMessage *>(dgram->getEncapsulatedMsg()))
00048 {
00049 SCTPMessage *sctpmsg = check_and_cast<SCTPMessage *>(dgram->getEncapsulatedMsg());
00050 if (dgram->hasBitError())
00051 sctpmsg->setBitError(true);
00052 sctpDump(label, sctpmsg, dgram->getSrcAddress().str(), dgram->getDestAddress().str(), comment);
00053 }
00054 else
00055 delete dgram;
00056 }
00057
00058 void TCPDumper::sctpDump(const char *label, SCTPMessage *sctpmsg, const std::string& srcAddr, const std::string& destAddr, const char *comment)
00059 {
00060 std::ostream& out = *outp;
00061 uint32 numberOfChunks;
00062 SCTPChunk* chunk;
00063 uint8 type;
00064
00065 char buf[30];
00066 sprintf(buf,"[%.3f%s] ", simulation.getSimTime().dbl(), label);
00067 out << buf;
00068
00069
00070 out << srcAddr << "." << sctpmsg->getSrcPort() << " > ";
00071
00072 out << destAddr << "." << sctpmsg->getDestPort() << ": ";
00073 if (sctpmsg->hasBitError())
00074 {
00075 sctpmsg->setChecksumOk(false);
00076 }
00077 numberOfChunks = sctpmsg->getChunksArraySize();
00078 out << "numberOfChunks="<<numberOfChunks<<" VTag="<<sctpmsg->getTag()<<"\n";
00079 if (sctpmsg->hasBitError())
00080 out << "Packet has bit error!!\n";
00081 for (uint32 i=0; i<numberOfChunks; i++)
00082 {
00083 chunk = (SCTPChunk*)sctpmsg->getChunks(i);
00084 type = chunk->getChunkType();
00085 switch (type)
00086 {
00087 case INIT:
00088 out << "INIT ";
00089 break;
00090 case INIT_ACK:
00091 out << "INIT_ACK ";
00092 break;
00093 case COOKIE_ECHO:
00094 out << "COOKIE_ECHO ";
00095 break;
00096 case COOKIE_ACK:
00097 out << "COOKIE_ACK ";
00098 break;
00099 case DATA:
00100 out << "DATA ";
00101 break;
00102 case SACK:
00103 out << "SACK ";
00104 break;
00105 case HEARTBEAT:
00106 out << "HEARTBEAT ";
00107 break;
00108 case HEARTBEAT_ACK:
00109 out << "HEARTBEAT_ACK ";
00110 break;
00111 case ABORT:
00112 out << "ABORT ";
00113 break;
00114 case SHUTDOWN:
00115 out << "SHUTDOWN ";
00116 break;
00117 case SHUTDOWN_ACK:
00118 out << "SHUTDOWN_ACK ";
00119 break;
00120 case SHUTDOWN_COMPLETE:
00121 out << "SHUTDOWN_COMPLETE ";
00122 break;
00123 case ERRORTYPE:
00124 out << "ERROR";
00125 break;
00126
00127 }
00128 }
00129
00130 if (verbosity >= 1)
00131 {
00132 out << endl;
00133 for (uint32 i=0; i<numberOfChunks; i++)
00134 {
00135 chunk = (SCTPChunk*)sctpmsg->getChunks(i);
00136 type = chunk->getChunkType();
00137
00138 sprintf(buf, " %3u: ", i + 1);
00139 out << buf;
00140 switch (type)
00141 {
00142 case INIT:
00143 {
00144 SCTPInitChunk* initChunk;
00145 initChunk = check_and_cast<SCTPInitChunk *>(chunk);
00146 out << "INIT[InitiateTag=";
00147 out << initChunk->getInitTag();
00148 out << "; a_rwnd=";
00149 out << initChunk->getA_rwnd();
00150 out << "; OS=";
00151 out << initChunk->getNoOutStreams();
00152 out << "; IS=";
00153 out << initChunk->getNoInStreams();
00154 out << "; InitialTSN=";
00155 out << initChunk->getInitTSN();
00156 if (initChunk->getAddressesArraySize() > 0)
00157 {
00158 out <<"; Addresses=";
00159 for (uint32 i = 0; i < initChunk->getAddressesArraySize(); i++)
00160 {
00161 if (i > 0)
00162 out << ",";
00163 if (initChunk->getAddresses(i).isIPv6())
00164 out << initChunk->getAddresses(i).str();
00165 else
00166 out << initChunk->getAddresses(i);
00167 }
00168 }
00169
00170 out <<"]";
00171 break;
00172 }
00173 case INIT_ACK:
00174 {
00175 SCTPInitAckChunk* initackChunk;
00176 initackChunk = check_and_cast<SCTPInitAckChunk *>(chunk);
00177 out << "INIT_ACK[InitiateTag=";
00178 out << initackChunk->getInitTag();
00179 out << "; a_rwnd=";
00180 out << initackChunk->getA_rwnd();
00181 out << "; OS=";
00182 out << initackChunk->getNoOutStreams();
00183 out << "; IS=";
00184 out << initackChunk->getNoInStreams();
00185 out << "; InitialTSN=";
00186 out << initackChunk->getInitTSN();
00187 out << "; CookieLength=";
00188 out << initackChunk->getCookieArraySize();
00189 if (initackChunk->getAddressesArraySize() > 0)
00190 {
00191 out <<"; Addresses=";
00192 for (uint32 i = 0; i < initackChunk->getAddressesArraySize(); i++)
00193 {
00194 if (i > 0)
00195 out << ",";
00196 out << initackChunk->getAddresses(i);
00197 }
00198 }
00199 out <<"]";
00200 break;
00201 }
00202 case COOKIE_ECHO:
00203 out << "COOKIE_ECHO[CookieLength=";
00204 out << chunk->getBitLength()/8 - 4;
00205 out <<"]";
00206 break;
00207 case COOKIE_ACK:
00208 out << "COOKIE_ACK ";
00209 break;
00210 case DATA:
00211 {
00212 SCTPDataChunk* dataChunk;
00213 dataChunk = check_and_cast<SCTPDataChunk *>(chunk);
00214 out << "DATA[TSN=";
00215 out << dataChunk->getTsn();
00216 out << "; SID=";
00217 out << dataChunk->getSid();
00218 out << "; SSN=";
00219 out << dataChunk->getSsn();
00220 out << "; PPID=";
00221 out << dataChunk->getPpid();
00222 out << "; PayloadLength=";
00223 out << dataChunk->getBitLength()/8 - 16;
00224 out <<"]";
00225 break;
00226 }
00227 case SACK:
00228 {
00229 SCTPSackChunk* sackChunk;
00230 sackChunk = check_and_cast<SCTPSackChunk *>(chunk);
00231 out << "SACK[CumTSNAck=";
00232 out << sackChunk->getCumTsnAck();
00233 out << "; a_rwnd=";
00234 out << sackChunk->getA_rwnd();
00235 if (sackChunk->getGapStartArraySize() > 0)
00236 {
00237 out <<"; Gaps=";
00238 for (uint32 i = 0; i < sackChunk->getGapStartArraySize(); i++)
00239 {
00240 if (i > 0)
00241 out << ", ";
00242 out << sackChunk->getGapStart(i) << "-" << sackChunk->getGapStop(i);
00243 }
00244 }
00245 if (sackChunk->getDupTsnsArraySize() > 0)
00246 {
00247 out <<"; Dups=";
00248 for (uint32 i = 0; i < sackChunk->getDupTsnsArraySize(); i++)
00249 {
00250 if (i > 0)
00251 out << ", ";
00252 out << sackChunk->getDupTsns(i);
00253 }
00254 }
00255 out <<"]";
00256 break;
00257 }
00258 case HEARTBEAT:
00259 SCTPHeartbeatChunk* heartbeatChunk;
00260 heartbeatChunk = check_and_cast<SCTPHeartbeatChunk *>(chunk);
00261 out << "HEARTBEAT[InfoLength=";
00262 out << chunk->getBitLength()/8 - 4;
00263 out << "; time=";
00264 out << heartbeatChunk->getTimeField();
00265 out <<"]";
00266 break;
00267 case HEARTBEAT_ACK:
00268 out << "HEARTBEAT_ACK[InfoLength=";
00269 out << chunk->getBitLength()/8 - 4;
00270 out <<"]";
00271 break;
00272 case ABORT:
00273 SCTPAbortChunk* abortChunk;
00274 abortChunk = check_and_cast<SCTPAbortChunk *>(chunk);
00275 out << "ABORT[T-Bit=";
00276 out << abortChunk->getT_Bit();
00277 out << "]";
00278 break;
00279 case SHUTDOWN:
00280 SCTPShutdownChunk* shutdown;
00281 shutdown = check_and_cast<SCTPShutdownChunk *>(chunk);
00282 out << "SHUTDOWN[CumTSNAck=";
00283 out << shutdown->getCumTsnAck();
00284 out << "]";
00285 break;
00286 case SHUTDOWN_ACK:
00287 out << "SHUTDOWN_ACK ";
00288 break;
00289 case SHUTDOWN_COMPLETE:
00290 out << "SHUTDOWN_COMPLETE ";
00291 break;
00292 case ERRORTYPE:
00293 {
00294 SCTPErrorChunk* errorChunk;
00295 errorChunk = check_and_cast<SCTPErrorChunk*>(chunk);
00296 uint32 numberOfParameters = errorChunk->getParametersArraySize();
00297 uint32 parameterType;
00298 for (uint32 i=0; i<numberOfParameters; i++)
00299 {
00300 SCTPParameter* param = (SCTPParameter*)errorChunk->getParameters(i);
00301 parameterType = param->getParameterType();
00302 }
00303
00304 break;
00305 }
00306
00307 }
00308 out << endl;
00309 }
00310 }
00311
00312 if (comment)
00313 out << "# " << comment;
00314
00315 out << endl;
00316 }
00317
00318 TCPDump::~TCPDump()
00319 {
00320 }
00321
00322 const char *TCPDumper::intToChunk(int32 type)
00323 {
00324 switch (type)
00325 {
00326 case 0: return "DATA";
00327 case 1: return "INIT";
00328 case 2: return "INIT_ACK";
00329 case 3: return "SACK";
00330 case 4: return "HEARTBEAT";
00331 case 5: return "HEARTBEAT_ACK";
00332 case 6: return "ABORT";
00333 case 7: return "SHUTDOWN";
00334 case 8: return "SHUTDOWN_ACK";
00335 case 9: return "ERRORTYPE";
00336 case 10: return "COOKIE_ECHO";
00337 case 11: return "COOKIE_ACK";
00338 case 14: return "SHUTDOWN_COMPLETE";
00339 }
00340 return "";
00341 }
00342
00343 void TCPDumper::dump(const char *label, const char *msg)
00344 {
00345 std::ostream& out = *outp;
00346
00347
00348 char buf[30];
00349 sprintf(buf,"[%.3f%s] ", simulation.getSimTime().dbl(), label);
00350 out << buf;
00351
00352 out << msg << "\n";
00353 }
00354
00355
00356
00357 Define_Module(TCPDump);
00358
00359 TCPDump::TCPDump() : cSimpleModule(), tcpdump(ev.getOStream())
00360 {
00361
00362
00363 }
00364
00365 void TCPDumper::udpDump(bool l2r, const char *label, IPDatagram *dgram, const char *comment)
00366 {
00367 cMessage *encapmsg = dgram->getEncapsulatedMsg();
00368 if (dynamic_cast<UDPPacket *>(encapmsg))
00369 {
00370 std::ostream& out = *outp;
00371
00372
00373 char buf[30];
00374 sprintf(buf,"[%.3f%s] ", simulation.getSimTime().dbl(), label);
00375 out << buf;
00376 UDPPacket* udppkt = check_and_cast<UDPPacket*>(encapmsg);
00377
00378
00379 if (l2r)
00380 {
00381 out << dgram->getSrcAddress().str() << "." << udppkt->getSourcePort() << " > ";
00382 out << dgram->getDestAddress().str() << "." << udppkt->getDestinationPort() << ": ";
00383 }
00384 else
00385 {
00386 out << dgram->getDestAddress().str() << "." << udppkt->getDestinationPort() << " < ";
00387 out << dgram->getSrcAddress().str() << "." << udppkt->getSourcePort() << ": ";
00388 }
00389
00390
00391 out << "UDP: Payload length=" << udppkt->getByteLength()-8 << endl;
00392 if (udppkt->getSourcePort()==9899 || udppkt->getDestinationPort() == 9899)
00393 {
00394 if (dynamic_cast<SCTPMessage *>(udppkt->getEncapsulatedMsg()))
00395 sctpDump("", (SCTPMessage *)(udppkt->getEncapsulatedMsg()), std::string(l2r?"A":"B"),std::string(l2r?"B":"A"));
00396 }
00397 }
00398 }
00399
00400 void TCPDumper::tcpDump(bool l2r, const char *label, IPDatagram *dgram, const char *comment)
00401 {
00402 cMessage *encapmsg = dgram->getEncapsulatedMsg();
00403 if (dynamic_cast<TCPSegment *>(encapmsg))
00404 {
00405
00406 tcpDump(l2r, label, (TCPSegment *)encapmsg, dgram->getSrcAddress().str(), dgram->getDestAddress().str(), comment);
00407 }
00408 else
00409 {
00410
00411 std::ostream& out = *outp;
00412
00413
00414 char buf[30];
00415 sprintf(buf,"[%.3f%s] ", SIMTIME_DBL(simTime()), label);
00416 out << buf;
00417
00418
00419 out << "? " << encapmsg->getClassName() << " \"" << encapmsg->getName() << "\"\n";
00420 }
00421 }
00422
00423
00424 void TCPDumper::dumpIPv6(bool l2r, const char *label, IPv6Datagram_Base *dgram, const char *comment)
00425 {
00426 cMessage *encapmsg = dgram->getEncapsulatedMsg();
00427 if (dynamic_cast<TCPSegment *>(encapmsg))
00428 {
00429
00430 tcpDump(l2r, label, (TCPSegment *)encapmsg, dgram->getSrcAddress().str(), dgram->getDestAddress().str(), comment);
00431 }
00432 else
00433 {
00434
00435 std::ostream& out = *outp;
00436
00437
00438 char buf[30];
00439 sprintf(buf,"[%.3f%s] ", SIMTIME_DBL(simTime()), label);
00440 out << buf;
00441
00442
00443 out << "? " << encapmsg->getClassName() << " \"" << encapmsg->getName() << "\"\n";
00444 }
00445 }
00446
00447 void TCPDumper::tcpDump(bool l2r, const char *label, TCPSegment *tcpseg, const std::string& srcAddr, const std::string& destAddr, const char *comment)
00448 {
00449 std::ostream& out = *outp;
00450
00451
00452 char buf[30];
00453 sprintf(buf,"[%.3f%s] ", SIMTIME_DBL(simTime()), label);
00454 out << buf;
00455
00456 if (l2r)
00457 {
00458 out << srcAddr << "." << tcpseg->getSrcPort() << " > ";
00459 out << destAddr << "." << tcpseg->getDestPort() << ": ";
00460 }
00461 else
00462 {
00463 out << destAddr << "." << tcpseg->getDestPort() << " < ";
00464 out << srcAddr << "." << tcpseg->getSrcPort() << ": ";
00465 }
00466
00467
00468 bool flags = false;
00469 if (tcpseg->getUrgBit()) {flags=true; out << "U ";}
00470 if (tcpseg->getAckBit()) {flags=true; out << "A ";}
00471 if (tcpseg->getPshBit()) {flags=true; out << "P ";}
00472 if (tcpseg->getRstBit()) {flags=true; out << "R ";}
00473 if (tcpseg->getSynBit()) {flags=true; out << "S ";}
00474 if (tcpseg->getFinBit()) {flags=true; out << "F ";}
00475 if (!flags) {out << ". ";}
00476
00477
00478 if (tcpseg->getPayloadLength()>0 || tcpseg->getSynBit())
00479 {
00480 out << tcpseg->getSequenceNo() << ":" << tcpseg->getSequenceNo()+tcpseg->getPayloadLength();
00481 out << "(" << tcpseg->getPayloadLength() << ") ";
00482 }
00483
00484
00485 if (tcpseg->getAckBit())
00486 out << "ack " << tcpseg->getAckNo() << " ";
00487
00488
00489 out << "win " << tcpseg->getWindow() << " ";
00490
00491
00492 if (tcpseg->getUrgBit())
00493 out << "urg " << tcpseg->getUrgentPointer() << " ";
00494
00495
00496 if (tcpseg->getHeaderLength() > 20)
00497 {
00498 std::string direction = "sent";
00499 if (l2r)
00500 {direction = "received";}
00501
00502 unsigned short numOptions = tcpseg->getOptionsArraySize();
00503 out << "\nTCP Header Option(s) " << direction << ":\n";
00504 for (int i=0; i<numOptions; i++)
00505 {
00506 TCPOption option = tcpseg->getOptions(i);
00507 unsigned short kind = option.getKind();
00508 unsigned short length = option.getLength();
00509 out << (i+1) << ". option kind=" << kind << " length=" << length << "\n";
00510 }
00511 }
00512
00513
00514 if (comment)
00515 out << "# " << comment;
00516
00517 out << endl;
00518 }
00519
00520 void TCPDump::initialize()
00521 {
00522 struct pcap_hdr fh;
00523 const char* file = this->par("dumpFile");
00524 snaplen = this->par("snaplen");
00525 tcpdump.setVerbosity(par("verbosity"));
00526
00527
00528 if (strcmp(file,"")!=0)
00529 {
00530 tcpdump.dumpfile = fopen(file, "wb");
00531 if (!tcpdump.dumpfile)
00532 {
00533 fprintf(stderr, "Cannot open file [%s] for writing: %s\n", file, strerror(errno));
00534 exit(-1);
00535 }
00536
00537 fh.magic = PCAP_MAGIC;
00538 fh.version_major = 2;
00539 fh.version_minor = 4;
00540 fh.thiszone = 0;
00541 fh.sigfigs = 0;
00542 fh.snaplen = snaplen;
00543 fh.network = 0;
00544 fwrite(&fh, sizeof(fh), 1, tcpdump.dumpfile);
00545 }
00546 else
00547 tcpdump.dumpfile = NULL;
00548 }
00549
00550 void TCPDump::handleMessage(cMessage *msg)
00551 {
00552
00553 if (!ev.disable_tracing)
00554 {
00555 bool l2r;
00556
00557 if (dynamic_cast<IPDatagram *>(msg))
00558 {
00559 if (((IPDatagram *)msg)->getTransportProtocol()==132)
00560 {
00561 tcpdump.ipDump("", (IPDatagram *)msg);
00562 }
00563 else
00564 {
00565 if (PK(msg)->hasBitError())
00566 {
00567 delete msg;
00568 return;
00569 }
00570 l2r = msg->arrivedOn("in1");
00571 if (((IPDatagram *)msg)->getTransportProtocol()==6)
00572 {
00573 tcpdump.tcpDump(l2r, "", (IPDatagram *)msg, "");
00574 }
00575 else if (((IPDatagram *)msg)->getTransportProtocol()==17)
00576 tcpdump.udpDump(l2r, "", (IPDatagram *)msg, "");
00577 }
00578 }
00579 else if (dynamic_cast<SCTPMessage *>(msg))
00580 {
00581 l2r = msg->arrivedOn("in1");
00582 tcpdump.sctpDump("", (SCTPMessage *)msg, std::string(l2r?"A":"B"),std::string(l2r?"B":"A"));
00583 }
00584 else if (dynamic_cast<TCPSegment *>(msg))
00585 {
00586 if (PK(msg)->hasBitError())
00587 {
00588 delete msg;
00589 return;
00590 }
00591 l2r = msg->arrivedOn("in1");
00592 tcpdump.tcpDump(l2r, "", (TCPSegment *)msg, std::string(l2r?"A":"B"),std::string(l2r?"B":"A"));
00593 }
00594 else if (dynamic_cast<ICMPMessage *>(msg))
00595 {
00596 if (PK(msg)->hasBitError())
00597 {
00598 delete msg;
00599 return;
00600 }
00601 std::cout<<"ICMPMessage\n";
00602 }
00603 else
00604 {
00605
00606 cPacket *encapmsg = PK(msg);
00607 while (encapmsg && dynamic_cast<IPDatagram *>(encapmsg)==NULL && dynamic_cast<IPv6Datagram_Base *>(encapmsg)==NULL)
00608 encapmsg = encapmsg->getEncapsulatedMsg();
00609 l2r = msg->arrivedOn("in1");
00610 if (!encapmsg)
00611 {
00612
00613
00614 EV << "CANNOT DECODE: packet " << msg->getName() << " doesn't contain either IP or IPv6 Datagram\n";
00615 }
00616 else
00617 {
00618 if (dynamic_cast<IPDatagram *>(encapmsg))
00619 tcpdump.tcpDump(l2r, "", (IPDatagram *)encapmsg);
00620 else if (dynamic_cast<IPv6Datagram_Base *>(encapmsg))
00621 tcpdump.dumpIPv6(l2r, "", (IPv6Datagram_Base *)encapmsg);
00622 else
00623 ASSERT(0);
00624 }
00625 }
00626 }
00627
00628
00629 if (tcpdump.dumpfile!=NULL && dynamic_cast<IPDatagram *>(msg))
00630 {
00631 uint8 buf[MAXBUFLENGTH];
00632 memset((void*)&buf, 0, sizeof(buf));
00633
00634 const simtime_t stime = simulation.getSimTime();
00635
00636
00637 struct pcaprec_hdr ph;
00638 ph.ts_sec = (int32)stime.dbl();
00639 ph.ts_usec = (uint32)((stime.dbl() - ph.ts_sec)*1000000);
00640
00641 uint32 hdr = 2;
00642
00643 IPDatagram *ipPacket = check_and_cast<IPDatagram *>(msg);
00644
00645
00646
00647 int32 serialized_ip = IPSerializer().serialize(ipPacket, buf, sizeof(buf));
00648 ph.incl_len = serialized_ip + sizeof(uint32);
00649
00650 ph.orig_len = ph.incl_len;
00651 fwrite(&ph, sizeof(ph), 1, tcpdump.dumpfile);
00652 fwrite(&hdr, sizeof(uint32), 1, tcpdump.dumpfile);
00653 fwrite(buf, serialized_ip, 1, tcpdump.dumpfile);
00654 }
00655
00656
00657
00658 int32 index = msg->getArrivalGate()->getIndex();
00659 int32 id;
00660 if (msg->getArrivalGate()->isName("ifIn"))
00661 id = findGate("out2",index);
00662 else
00663 id = findGate("ifOut",index);
00664
00665 send(msg, id);
00666 }
00667
00668 void TCPDump::finish()
00669 {
00670 tcpdump.dump("", "tcpdump finished");
00671 if (strcmp(this->par("dumpFile"),"")!=0)
00672 fclose(tcpdump.dumpfile);
00673 }
00674