// set the checksum field, totalSize covers all the fields for // which the checksum is calculated // offset is points to the beginning of the IP header (!!!) // Should be called after the UDP header + data have been written public static void SetUdpChecksum(byte[] !packet, int ipOffset, ref UdpHeader udpHeader) { // sum IP pseudo ushort ipPayloadSize = 0; ushort headerSum = IPFormat.SumPseudoHeader(packet, ipOffset, ref ipPayloadSize); Debug.Assert(((ushort)udpHeader.length) == ipPayloadSize); // now add it to the udp header + data int ipHeaderSize = (packet[ipOffset] & 0xf) * 4; int udpOffset = ipOffset + ipHeaderSize; Debug.Assert(packet[udpOffset + 6] == 0); Debug.Assert(packet[udpOffset + 7] == 0); ushort payloadSum = IPFormat.SumShortValues(packet, udpOffset, ipPayloadSize); udpHeader.checksum = IPFormat.ComplementAndFixZeroChecksum( IPFormat.SumShortValues(headerSum, payloadSum)); packet[udpOffset + 6] = (byte)(udpHeader.checksum >> 8); packet[udpOffset + 7] = (byte)(udpHeader.checksum & 0xff); }
// set the checksum field // offset points to the beginning of the IP header (!!!) // Should be called after the TCP header + data have been written public static void SetTcpChecksum(byte[] !packet, int ipOffset, ref TcpHeader tcpHeader) { // sum IP pseudo ushort ipPayloadLength = 0; ushort headerSum = IPFormat.SumPseudoHeader(packet, ipOffset, ref ipPayloadLength); int ipHeaderSize = (packet[ipOffset] & 0xf) * 4; int tcpOffset = ipOffset + ipHeaderSize; Debug.Assert(packet[tcpOffset + 16] == 0); Debug.Assert(packet[tcpOffset + 17] == 0); // now add it to the TCP header + data ushort payloadSum = IPFormat.SumShortValues(packet, tcpOffset, ipPayloadLength); tcpHeader.checksum = (ushort) ~(IPFormat.SumShortValues(headerSum, payloadSum)); // Complement and change +0 to -0 if needed. ushort tcpChecksum = IPFormat.ComplementAndFixZeroChecksum( (IPFormat.SumShortValues(headerSum, payloadSum))); tcpHeader.checksum = tcpChecksum; unchecked { packet[tcpOffset + 16] = (byte)(tcpChecksum >> 8); packet[tcpOffset + 17] = (byte)(tcpChecksum >> 0); } }
public static bool IsChecksumValid(IPFormat.IPHeader !ipHeader, TcpHeader tcpHeader, NetPacket !payload) { // Compute partial checksums of headers ushort checksum = IPFormat.SumPseudoHeader(ipHeader); checksum = IPFormat.SumShortValues(checksum, SumHeader(tcpHeader)); // Checksum payload (without potential odd byte) int length = payload.Available; int end = length & ~1; int i = 0; uint payloadChecksum = 0; while (i != end) { byte b0 = payload.PeekAvailable(i++); byte b1 = payload.PeekAvailable(i++); payloadChecksum += ((((uint)b0) << 8) + (uint)b1); } // Handle odd byte. if (i != length) { payloadChecksum += (((uint)payload.PeekAvailable(i++)) << 8); } // Merge bits from payload checksum checksum = IPFormat.SumUInt16AndUInt32Values(checksum, payloadChecksum); // Complement and change +0 to -0 if needed. checksum = IPFormat.ComplementAndFixZeroChecksum(checksum); // Check for match. bool checksumMatch = (tcpHeader.checksum == checksum); // If checksum error, unconditionally output message to debugger. if (checksumMatch == false) { DebugStub.WriteLine("Bad TCP checksum {0:x4} != {1:x4}: SEQ {2:x8} ACK {3:x8}", __arglist(tcpHeader.checksum, checksum, tcpHeader.seq, tcpHeader.ackSeq )); } // IsValid is a Match. return(checksumMatch); }
/// <summary> /// Update checksum when a 16-bit value that composed the original /// checksum changes. Useful for recomputing checksum when /// TTL changes when acting as a router. /// </summary> public static ushort UpdateChecksum(ushort checksum, ushort oldValue, ushort newValue) { // From RFC1624 ushort newChecksum; unchecked { newChecksum = (ushort)~checksum; newChecksum += (ushort)~oldValue; newChecksum += newValue; } return(IPFormat.ComplementAndFixZeroChecksum(newChecksum)); }
/// <summary> /// Write IP and UDP headers and payload data into a /// byte array. /// </summary> /// <param name="pkt">Array of bytes representing /// packet to be sent.</param> /// <param name="offset">Offset of IP Header within /// packet.</param> /// <param name="ipHeader">IP header to be written /// to packet.</param> /// <param name="udpHeader">UDP header to be written /// to packet.</param> /// <param name="payload">Payload of UDP Packet.</param> /// <param name="payloadOffset">The offset of start /// of the payload data within the payload /// array.</param> /// <param name="payloadLength">The size of the payload data.</param> public static void WriteUdpPacket(byte[] !pkt, int offset, IPFormat.IPHeader !ipHeader, ref UdpHeader udpHeader, byte[] payload, int payloadOffset, int payloadLength) { int udpStart = IPFormat.WriteIPHeader(pkt, offset, ipHeader); int udpEnd = WriteUdpHeader(pkt, udpStart, ref udpHeader); if (pkt != payload || udpEnd != payloadOffset) { Array.Copy(payload, payloadOffset, pkt, udpEnd, payloadLength); } SetUdpChecksum(pkt, offset, ref udpHeader); }
// write an ICMP echo request public static int WriteIcmpEchoRequest(byte[] !pkt, int offset, ref IcmpEchoRequest request) { int o = offset; // write the common header o = WriteIcmpHeader(pkt, offset, ref request.header); // dump the data (endian doesn't matter, since it is a user data) Array.Copy(request.data, 0, pkt, o, request.data.Length); // calc the checksum ushort chk = IPFormat.Checksum(pkt, offset, request.GetSize()); pkt[offset + 2] = (byte)(((ushort)chk) >> 8); pkt[offset + 3] = (byte)(((ushort)chk) & 0xff); request.header.chksum = chk; return(o); }
// a fast method that uses that modified the ECHO request // packet to an ECHO reply. // return true if success public static void CreateFastEchoReply(byte[] !pkt, int icmpPacketSize) { // 1. switch the source IP and destination IP // 2. change ICMP code to IcmpFormat.IcmpType.ECHO_REPLY // 3. should use ARP table to find out the mac address of the target // (if it is on the local network) // CURRENTLY: just switch MAC addresses as well. // 4. recompute ICMP and IP checksums int ipStart = EthernetFormat.Size; int icmpStart = ipStart + IPFormat.Size; pkt[icmpStart] = (byte)IcmpFormat.IcmpType.ECHO_REPLY; // zero checksum pkt[icmpStart + 2] = 0; pkt[icmpStart + 3] = 0; ushort chk = IPFormat.Checksum(pkt, icmpStart, icmpPacketSize); pkt[icmpStart + 2] = (byte)(chk >> 8); pkt[icmpStart + 3] = (byte)chk; // switch IPs byte[] tmp = new byte[6]; Array.Copy(pkt, ipStart + 16, tmp, 0, 4); // dest->tmp Array.Copy(pkt, ipStart + 12, pkt, ipStart + 16, 4); // src->dest Array.Copy(tmp, 0, pkt, ipStart + 12, 4); // tmp->src // zero the checksum pkt[ipStart + 10] = 0; pkt[ipStart + 11] = 0; // calculate checksum chk = IPFormat.Checksum(pkt, ipStart, IPFormat.Size); pkt[ipStart + 10] = (byte)(((ushort)chk) >> 8); pkt[ipStart + 11] = (byte)(((ushort)chk) & 0xff); // TBC: currently just switch mac addresses Array.Copy(pkt, 6, tmp, 0, 6); // src -> temp Array.Copy(pkt, 0, pkt, 6, 6); // dest -> src Array.Copy(tmp, 0, pkt, 0, 6); // tmp -> dest }
// writes an IP header to a packet // return the next place to write to, fixes the checksum field public static int WriteIPHeader(byte[] !pkt, int offset, IPHeader !hdr) { // check we have enough packet space if (pkt.Length - offset < Size) { return(offset); } int o = offset; pkt[o++] = hdr.verLen; pkt[o++] = hdr.tos; pkt[o++] = (byte)(((ushort)hdr.totalLength) >> 8); pkt[o++] = (byte)(((ushort)hdr.totalLength) & 0xff); pkt[o++] = (byte)(((ushort)hdr.id) >> 8); pkt[o++] = (byte)(((ushort)hdr.id) & 0xff); pkt[o++] = (byte)(((ushort)hdr.offset) >> 8); pkt[o++] = (byte)(((ushort)hdr.offset) & 0xff); pkt[o++] = hdr.ttl; pkt[o++] = hdr.protocol; pkt[o++] = 0; pkt[o++] = 0; // set the ip addresses hdr.srcAddr.CopyOut(pkt, o); o += IPv4.Length; hdr.destAddr.CopyOut(pkt, o); o += IPv4.Length; // calculate checksum ushort chk = IPFormat.FixZeroChecksum(Checksum(pkt, offset, Size)); pkt[offset + 10] = (byte)(((ushort)chk) >> 8); pkt[offset + 11] = (byte)(((ushort)chk) & 0xff); // save the header checksum hdr.checksum = chk; return(o); }
public static bool IsChecksumValid(IPFormat.IPHeader !ipHeader, UdpHeader udpHeader, NetPacket !payload) { // Compute partial checksums of headers ushort checksum = IPFormat.SumPseudoHeader(ipHeader); checksum = IPFormat.SumShortValues(checksum, UdpFormat.SumHeader(udpHeader)); // Checksum payload int length = payload.Available; int end = length & ~1; int i = 0; while (i != end) { int x = ((((int)payload.PeekAvailable(i++)) << 8) + (int)payload.PeekAvailable(i++)); checksum = IPFormat.SumShortValues(checksum, (ushort)x); } if (i != length) { int x = (((int)payload.PeekAvailable(i++)) << 8); checksum = IPFormat.SumShortValues(checksum, (ushort)x); } checksum = IPFormat.ComplementAndFixZeroChecksum(checksum); if (udpHeader.checksum != checksum) { DebugStub.WriteLine("Bad UDP checksum {0:x4} != {1:x4}", __arglist(udpHeader.checksum, checksum)); } return(udpHeader.checksum == checksum); }
public static bool IsCheckSumOK(IPHeader !hdr) { ushort sum = (ushort)((((int)hdr.verLen) << 8) + ((int)hdr.tos)); sum = SumShortValues(sum, hdr.totalLength); sum = SumShortValues(sum, hdr.id); sum = SumShortValues(sum, hdr.offset); sum = SumShortValues(sum, (ushort)((((int)hdr.ttl) << 8) + ((int)hdr.protocol))); sum = SumShortValues(sum, (ushort)(((uint)hdr.srcAddr) >> 16)); sum = SumShortValues(sum, (ushort)(((uint)hdr.srcAddr) & 0xFFFFU)); sum = SumShortValues(sum, (ushort)(((uint)hdr.destAddr) >> 16)); sum = SumShortValues(sum, (ushort)(((uint)hdr.destAddr) & 0xFFFFU)); sum = IPFormat.ComplementAndFixZeroChecksum(sum); if (sum != hdr.checksum) { DebugStub.WriteLine("Bad IP Checksum {0:x4} != {1:x4}", __arglist(hdr.checksum, sum)); } return(sum == hdr.checksum); }
// a helper method to write the TCP segment (without data) public static void WriteTcpSegment(byte[] !pktData, ushort localPort, ushort destPort, uint ackSeq, uint seq, ushort wnd, IPv4 sIP, IPv4 dIP, ushort dataLen, bool isAck, bool isSyn, bool isRst, bool isFin, bool withOptions) { // now create the IP,TCP headers! int start = EthernetFormat.Size; // prepare it... TcpFormat.TcpHeader tcpHeader = new TcpFormat.TcpHeader(); tcpHeader.sourcePort = localPort; tcpHeader.destPort = destPort; if (withOptions) { tcpHeader.off_res1 = 0x60; } else { tcpHeader.off_res1 = 0x50; } tcpHeader.ackSeq = ackSeq; tcpHeader.seq = seq; tcpHeader.window = wnd; if (isFin) { TcpFormat.SetFIN(ref tcpHeader); } if (isSyn) { TcpFormat.SetSYN(ref tcpHeader); } if (isAck) { TcpFormat.SetACK(ref tcpHeader); } if (isRst) { TcpFormat.SetReset(ref tcpHeader); } IPFormat.IPHeader ipHeader = new IPFormat.IPHeader(); ipHeader.SetDefaults(IPFormat.Protocol.TCP); ipHeader.totalLength = (ushort)(IPFormat.Size + TcpFormat.Size + dataLen); ipHeader.srcAddr = sIP; ipHeader.destAddr = dIP; IPFormat.SetDontFragBit(ipHeader); // write the ip header + ip checksum start = IPFormat.WriteIPHeader(pktData, start, ipHeader); // write TCP header, no checksum start = TcpFormat.WriteTcpHeader(pktData, start, ref tcpHeader); // calc the checksum... TcpFormat.SetTcpChecksum(pktData, EthernetFormat.Size, ref tcpHeader); }