DIRECTORY Arpa USING [nullAddress, Address], ArpaBuf USING [Hdr], ArpaIP USING [Buffers, GetUserBytes], BasicTime USING [Now], Convert USING [RopeFromTime], ConvertExtras USING [RopeFromArpaAddress], IO USING [Flush, int, rope, PutChar, PutF, PutRope, STREAM], Rope USING [ROPE, Cat], ArpaTCPLogging, ArpaTCPOps USING [tcpHdrByteLength, ConnectionState, Flip, TCPHeaderP, TCPHandle]; ArpaTCPLoggingImpl: CEDAR MONITOR IMPORTS ArpaIP, BasicTime, Convert, ConvertExtras, IO, Rope, ArpaTCPOps EXPORTS ArpaTCPLogging = BEGIN OPEN ArpaTCPOps, ArpaTCPLogging; pktFile, logFile: PUBLIC IO.STREAM _ NIL; pktBytesPrinted: INT _ 200; allAddresses: Arpa.Address = [255,255,255,255]; addrToWatch: PUBLIC Arpa.Address _ allAddresses; StateToRope: PROC [state: ConnectionState] RETURNS [stateRope: Rope.ROPE] = { SELECT state FROM closed => stateRope _ "CLS"; listen => stateRope _ "LSN"; synSent => stateRope _ "SSN"; synRcvd => stateRope _ "SRD"; established => stateRope _ "EST"; finWait1 => stateRope _ "FW1"; finWait2 => stateRope _ "FW2"; closeWait => stateRope _ "CWT"; closing => stateRope _ "CLG"; lastAck => stateRope _ "LAK"; timeWait => stateRope _ "TWT" ENDCASE; }; PutAddr: PROC [s: IO.STREAM, addr: Arpa.Address] = { s.PutF["[%03g.%03g.%03g.%03g]", IO.int[addr.a], IO.int[addr.b], IO.int[addr.c], IO.int[addr.d]]; }; PutData: PROC [s: IO.STREAM, data: ArpaIP.Buffers, fudge: BOOL] = { cruft: INT _ 0; length: INT _ ArpaIP.GetUserBytes[data].bodyBytes; c: INT; tcpDataStart: INT; tcpHdrPtr: TCPHeaderP; IF length <= ArpaTCPOps.tcpHdrByteLength THEN RETURN; TRUSTED { tcpHdrPtr _ LOOPHOLE[@data.body]; tcpDataStart _ tcpHdrPtr.dataWordOffset*4; IF fudge THEN { -- Recv case ?? IF tcpHdrPtr.dataWordOffset # 5 THEN { -- TCP Options end: INT = tcpHdrPtr.dataWordOffset*4; s.PutRope["Options: "]; FOR i: INT IN [4*5..end) DO c _ data.body.bytes[tcpDataStart+i]; s.PutF["%b ", IO.int[c]]; ENDLOOP; s.PutChar['\n]; }; length _ length - tcpHdrPtr.dataWordOffset*4; }; }; IF length = 0 THEN RETURN; FOR i: INT IN [0..MIN[length,pktBytesPrinted]) DO c _ data.body.bytes[tcpDataStart+i]; IF c IN [40b..176b] THEN s.PutChar['\000 + c] ELSE { cruft _ cruft + 1; IF cruft > 10 THEN { s.PutRope["(more)"]; EXIT; }; s.PutF["<%b>", IO.int[c]]; }; ENDLOOP; s.PutChar['\n]; }; PrintTCPPacket: PUBLIC ENTRY PROC [handle: ArpaTCPOps.TCPHandle, data: ArpaIP.Buffers, dir: Direction] = TRUSTED { tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@data.body]; ipHdr: ArpaBuf.Hdr _ LOOPHOLE[data.hdr1]; dirString, stateString, ctlString, time: Rope.ROPE; IF pktFile = NIL AND logFile = NIL THEN RETURN; IF ipHdr.protocol # tcp THEN RETURN; IF addrToWatch = Arpa.nullAddress THEN RETURN; IF addrToWatch # allAddresses AND addrToWatch # data.hdr1.dest AND addrToWatch # data.hdr1.source THEN RETURN; time _ Convert.RopeFromTime[ from: BasicTime.Now[], start: hours, end: seconds, useAMPM: FALSE, includeZone: FALSE]; SELECT dir FROM fromNet => dirString _ "R"; toNet => dirString _ "S"; rexmitToNet => dirString _ "X" ENDCASE; IF handle = NIL THEN stateString _ "CLS" ELSE stateString _ StateToRope[handle.state]; ctlString _ ""; IF tcpHdrPtr.urg THEN ctlString _ ctlString.Cat["U"]; IF tcpHdrPtr.ack THEN ctlString _ ctlString.Cat["A"]; IF tcpHdrPtr.psh THEN ctlString _ ctlString.Cat["P"]; IF tcpHdrPtr.rst THEN ctlString _ ctlString.Cat["R"]; IF tcpHdrPtr.syn THEN ctlString _ ctlString.Cat["S"]; IF tcpHdrPtr.fin THEN ctlString _ ctlString.Cat["F"]; IF pktFile # NIL THEN { pktFile.PutChar['\n]; PutAddr[pktFile, data.hdr1.source]; pktFile.PutF[" %g -> ", IO.int[tcpHdrPtr.sourcePort]]; PutAddr[pktFile, data.hdr1.dest]; pktFile.PutF[" %g\n", IO.int[tcpHdrPtr.dstnPort]]; pktFile.PutF[" %g %g %6g ", IO.rope[stateString], IO.rope[dirString], IO.rope[ctlString]]; pktFile.PutF["%7g %7g %7g %7g\n", IO.int[Flip[tcpHdrPtr.seqNumber] MOD 100000], IO.int[Flip[tcpHdrPtr.ackNumber] MOD 100000], IO.int[tcpHdrPtr.window], IO.int[ArpaIP.GetUserBytes[data].bodyBytes]]; PutData[pktFile, data, dir = fromNet]; }; IF logFile # NIL THEN { logFile.PutChar['\n]; logFile.PutF["%g ", IO.rope[time]]; PutAddr[logFile, data.hdr1.source]; logFile.PutF[" %g -> ", IO.int[tcpHdrPtr.sourcePort]]; PutAddr[logFile, data.hdr1.dest]; logFile.PutF[" %g\n", IO.int[tcpHdrPtr.dstnPort]]; logFile.PutF[" %g %g %6g ", IO.rope[stateString], IO.rope[dirString], IO.rope[ctlString]]; logFile.PutF["%7g %7g %7g %7g\n", IO.int[Flip[tcpHdrPtr.seqNumber] MOD 100000], IO.int[Flip[tcpHdrPtr.ackNumber] MOD 100000], IO.int[tcpHdrPtr.window], IO.int[ArpaIP.GetUserBytes[data].bodyBytes]]; PutData[logFile, data, dir = fromNet]; logFile.Flush[]; }; }; PrintStateChange: PUBLIC ENTRY PROC [handle: ArpaTCPOps.TCPHandle, newState: ArpaTCPOps.ConnectionState] = { old, new, time: Rope.ROPE; IF pktFile = NIL AND logFile = NIL THEN RETURN; IF addrToWatch = Arpa.nullAddress THEN RETURN; IF addrToWatch # allAddresses AND addrToWatch # handle.foreignAddr THEN RETURN; time _ Convert.RopeFromTime[ from: BasicTime.Now[], start: hours, end: seconds, useAMPM: FALSE, includeZone: FALSE]; old _ StateToRope[handle.state]; new _ StateToRope[newState]; IF pktFile # NIL THEN { pktFile.PutChar['\n]; pktFile.PutF["[ME] %g <-> ", IO.int[handle.localPort]]; PutAddr[pktFile, handle.foreignAddr]; pktFile.PutF[" %g", IO.int[handle.foreignPort]]; pktFile.PutF[" %g -> %g\n", IO.rope[old], IO.rope[new]]; }; IF logFile # NIL THEN { logFile.PutF["\n%g ", IO.rope[time]]; logFile.PutF["[ME] %g <-> ", IO.int[handle.localPort]]; PutAddr[logFile, handle.foreignAddr]; logFile.PutF[" %g", IO.int[handle.foreignPort]]; logFile.PutF[" %g -> %g\n", IO.rope[old], IO.rope[new]]; logFile.Flush[]; }; }; PrintMessage: PUBLIC ENTRY PROC [r: Rope.ROPE] = { IF pktFile = NIL AND logFile = NIL THEN RETURN; IF pktFile # NIL THEN pktFile.PutF["%g\n", IO.rope[r]]; IF logFile # NIL THEN { logFile.PutF["%g\n", IO.rope[r]]; logFile.Flush[]; }; }; PrintMessageWithSrc: PUBLIC ENTRY PROC [r: Rope.ROPE, sourceAddr: Arpa.Address] = { IF pktFile = NIL AND logFile = NIL THEN RETURN; IF addrToWatch = Arpa.nullAddress THEN RETURN; IF addrToWatch # allAddresses AND addrToWatch # sourceAddr THEN RETURN; IF pktFile # NIL THEN pktFile.PutF["%g, source: %g\n", IO.rope[r], IO.rope[ConvertExtras.RopeFromArpaAddress[sourceAddr]]]; IF logFile # NIL THEN { logFile.PutF["%g, source: %g\n", IO.rope[r], IO.rope[ConvertExtras.RopeFromArpaAddress[sourceAddr]]]; logFile.Flush[]; }; }; END. ΈArpaTCPLoggingImpl.mesa Copyright (C) 1983, 1984, 1985 by Xerox Corporation. All rights reserved. The following program was created in 1983 but has not been published within the meaning of the copyright law, is furnished under license, and may not be used, copied and/or disclosed except in accordance with the terms of said license. Last Edited by: Nichols, August 25, 1983 2:37 pm Last Edited by: Taft, January 4, 1984 12:59 pm Doug Terry, October 16, 1987 3:41:05 pm PDT Hal Murray May 16, 1985 3:15:02 am PDT John Larson, April 14, 1986 11:24:32 pm PST Print or log TCP packets. The following information is printed for each packet: state of Connection Received, Sent or Retransmitted (R, S or X) Control Flags (Urgent, Ack, Push, Reset, SYN, FIN) Sequence number mod 100000 Ack number mod 100000 Window length (number of bytes of TCP header and data) source Address and Port -> Destination Address and Port Print or log state transitions. Κϊ– "cedar" style˜head™Icode2šœ΅™΅J™0J™.Icode™+J™&M™+šΟk ˜ Lšœœ˜"Lšœœ˜Lšœœ˜%Lšœ œ˜Lšœœ˜Lšœœ˜*Lšœœ,œ˜