235 lines
7.9 KiB
C#
235 lines
7.9 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
/**
|
||
|
* Microsoft Research, Cambridge
|
||
|
* author: Yaron Weinsberg, Richard Black
|
||
|
*/
|
||
|
|
||
|
using NetStack.Common;
|
||
|
using System;
|
||
|
|
||
|
#if !SINGULARITY
|
||
|
using System.Net;
|
||
|
#endif
|
||
|
|
||
|
using System.Net.IP;
|
||
|
using Drivers.Net;
|
||
|
|
||
|
namespace NetStack.Protocols
|
||
|
{
|
||
|
/**
|
||
|
* declaration of the ICMP header (RFC 792)
|
||
|
*/
|
||
|
public class IcmpFormat
|
||
|
{
|
||
|
// size of common ICMP header
|
||
|
public const int Size = 8;
|
||
|
|
||
|
// ICMP Types
|
||
|
public enum IcmpType
|
||
|
{
|
||
|
ECHO_REPLY=0,
|
||
|
DESTINATION_UNREACHABLE=3,
|
||
|
SOURCE_QUENCH=4,
|
||
|
REDIRECT_MESSAGE=5,
|
||
|
ECHO_REQUEST=8,
|
||
|
TIME_EXCEEDED=11,
|
||
|
PARAMETER_PROBLEM=12,
|
||
|
TIMESTAMP_REQUEST=13,
|
||
|
TIMESTAMP_REPLY=14,
|
||
|
INFO_REQUEST=15,
|
||
|
INFO_REPLY=16,
|
||
|
ADD_MASK_REQUEST=17,
|
||
|
ADD_MASK_REPLY=18
|
||
|
}
|
||
|
|
||
|
// Destination Unreachable Codes
|
||
|
public enum Type3Code
|
||
|
{
|
||
|
NET_UNREACHABLE=0,
|
||
|
HOST_UNREACHABLE=1,
|
||
|
PROT_UNREACHABLE=2
|
||
|
/* and some more, let's add as needed */
|
||
|
}
|
||
|
|
||
|
// the common ICMP header
|
||
|
public struct IcmpHeader
|
||
|
{
|
||
|
public byte type;
|
||
|
public byte code;
|
||
|
public ushort chksum;
|
||
|
public ushort id;
|
||
|
public ushort seq;
|
||
|
}
|
||
|
|
||
|
// write common ICMP header
|
||
|
// (ignores the checksum field, notice that the checksum is
|
||
|
// calculated for the whole packet!)
|
||
|
public static int WriteIcmpHeader(byte[]! pkt,int offset,ref IcmpHeader hdr)
|
||
|
{
|
||
|
int o = offset;
|
||
|
pkt[o++] = hdr.type;
|
||
|
pkt[o++] = hdr.code;
|
||
|
pkt[o++] = 0;
|
||
|
pkt[o++] = 0;
|
||
|
pkt[o++] = (byte)(hdr.id>>8);
|
||
|
pkt[o++] = (byte)hdr.id;
|
||
|
pkt[o++] = (byte)(hdr.seq>>8);
|
||
|
pkt[o++] = (byte)hdr.seq;
|
||
|
|
||
|
return o;
|
||
|
}
|
||
|
|
||
|
// construct an ICMP header from a packet
|
||
|
public static bool ReadIcmpHeader(IBuffer! buf, out IcmpHeader hdr)
|
||
|
{
|
||
|
bool b;
|
||
|
b = buf.Read8(out hdr.type);
|
||
|
b &= buf.Read8(out hdr.code);
|
||
|
b &= buf.ReadNet16(out hdr.chksum);
|
||
|
b &= buf.ReadNet16(out hdr.id);
|
||
|
b &= buf.ReadNet16(out hdr.seq);
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
// Timestamp or Timestamp Reply Message
|
||
|
public struct TimeStamps
|
||
|
{
|
||
|
public IcmpHeader header;
|
||
|
public uint origTimeStamp;
|
||
|
public uint rcvTimeStamp;
|
||
|
public uint txTimeStamp;
|
||
|
}
|
||
|
|
||
|
// various ICMP messages
|
||
|
|
||
|
// IcmpEchoRequest
|
||
|
public struct IcmpEchoRequest
|
||
|
{
|
||
|
public IcmpHeader header;
|
||
|
public byte[] data;
|
||
|
|
||
|
// get the size of the message (depends on the received data)
|
||
|
public int GetSize()
|
||
|
{
|
||
|
return (IcmpFormat.Size+data.Length);
|
||
|
}
|
||
|
|
||
|
// ctor
|
||
|
public IcmpEchoRequest(ref IcmpHeader hdr,byte[]! msgData)
|
||
|
{
|
||
|
header=hdr;
|
||
|
|
||
|
// set the data
|
||
|
data = new byte[msgData.Length];
|
||
|
Array.Copy(msgData,0,data,0,msgData.Length);
|
||
|
}
|
||
|
|
||
|
public IcmpEchoRequest(ushort id,ushort seq,byte[]! msgData)
|
||
|
{
|
||
|
header.type = (byte)IcmpFormat.IcmpType.ECHO_REQUEST;
|
||
|
header.code = 0;
|
||
|
header.chksum = 0;
|
||
|
header.seq = seq;
|
||
|
header.id = id;
|
||
|
// set the data
|
||
|
data = new byte[msgData.Length];
|
||
|
Array.Copy(msgData,0,data,0,msgData.Length);
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
// write an ICMP echo reply for an ICMP Echo request
|
||
|
public static int WriteIcmpEchoReply(byte[]! pkt,int offset,ref IcmpEchoRequest request)
|
||
|
{
|
||
|
int o = offset;
|
||
|
|
||
|
// change the request header code to 0
|
||
|
request.header.type = (byte)IcmpFormat.IcmpType.ECHO_REPLY;
|
||
|
// write the common header
|
||
|
o = WriteIcmpHeader(pkt,offset,ref request.header);
|
||
|
// fix it again
|
||
|
request.header.type = (byte)IcmpFormat.IcmpType.ECHO_REQUEST;
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
}
|
||
|
}
|