构造一个ICMP包的类

ICMP 类(参考文章http://dev.21tx.com/2006/02/23/10773_1.html修改的)

using System;
using System.Collections.Generic;
using System.Text;

namespace ICMPCreate
{
    class ICMPPacket
    {
        private byte _type;//类型

        private byte _code;//代码;

        private UInt16 _checkSum;//校验和;

        private UInt16 _identifiter;//标识符

        private UInt16 _seqNumber;//序列号

        private byte[] _data;//选项数据

        private byte[] bt_buffer;//要发送的数据,构造完成的数据包。

        private bool isError = false;//是否出现错误,没有出现错误时为false;

        //返回要发送的数据报文;
        public byte[] BT_Buffer
        {
            get { return bt_buffer; }
        }
               
        /// <summary>
        ///在构造icmp的过程中是否出现错误;
        /// </summary>
        public bool ISError
        {
            get { return isError; }
        }

        /// <summary>
        /// icmpPacket
        /// </summary>
        /// <param name="type">icmp类型</param>
        /// <param name="code">icmp代码</param>
        /// <param name="checkSum">icmp校验和(置为零即可,程序中会计算校验和)</param>
        /// <param name="identifier">icmp标志符,自己设定,标志本icmp进程</param>
        /// <param name="seqNum">发送icmp的顺序号,在使用ping的时候,第一个为0,第二个可以设置为1...</param>
        /// <param name="dataSize">发送选项数据量的大小(偶数奇数均可)</param>
        public ICMPPacket(byte type,byte code,UInt16 checkSum,UInt16 identifier,UInt16 seqNum,int dataSize)
        {
            //初始化数据
            _type = type;
            _code = code;
            _checkSum = checkSum;
            _identifiter = identifier;
            seqNum = _seqNumber;
            _data = new byte [dataSize];
            //填充选项数据;
            if (dataSize % 2 != 0)
                dataSize++;
            for (int i = 0; i < dataSize;i++ )
            {
                _data[i] = (byte)'#';
            }

            int sendLength = 8 + _data.Length;//icmp头部长度(字节)加上datasize;
            bt_buffer = new byte [sendLength];
            if (sendLength != CountByte(bt_buffer))
            {
                isError = true;//出现错误设定为true               
            }
            _checkSum = SumOfCheck(bt_buffer);//计算完校验和了

            if (sendLength != CountByte(bt_buffer))
            {
                isError = true;//出现错误设定为true              
            }
        }
            
        private int CountByte(byte []buffer)
        {
            byte[] b_type = new byte[1] { _type};
            byte[] b_code = new byte[1] { _code};
            byte[] b_ckSum = BitConverter.GetBytes (_checkSum);
            byte[] b_id = BitConverter.GetBytes(_identifiter);
            byte[] b_seqNum = BitConverter.GetBytes(_seqNumber);
           
            int i = 0;
            Buffer.BlockCopy(b_type, 0, buffer, i, b_type.Length);      //在这里使用Buffer.BlockCopy比Array.Copy好
            i += b_type.Length;
            Buffer.BlockCopy(b_code, 0, buffer, i, b_code.Length);           
            i += b_code.Length;
            Buffer.BlockCopy(b_ckSum,0,buffer,i,b_ckSum.Length);
            i += b_ckSum.Length;
            Buffer.BlockCopy(b_id, 0, buffer, i, b_id.Length);
            i += b_id.Length;
            Buffer.BlockCopy(b_seqNum, 0, buffer, i, b_seqNum.Length);
            i += b_seqNum.Length;
            Buffer.BlockCopy(_data, 0, buffer, i, _data.Length);
            i += _data.Length;

            return i;
        }
        /// <summary>
        /// 求校验和,将_buffer中的每两个字节组合成一个16位的数字,放到一个数组中。之后把这个数组中
        /// 的数先转换成int类型,再全部相加到sum中。对于产生的余数在sum的高16位,再把sum高16位和低十六
        /// 位相加。这里还可能会再次产生余数因此需要再次把sum的第十六位和高十六位再相加一次。最后求反即可。
        /// </summary>
        /// <param name="_buffer">要计算的数组</param>
        /// <returns>校验和结果</returns>
        public UInt16 SumOfCheck(byte[] _buffer)
        {
            int ckSum = 0;//最终存放校验和的变量
            int buffer_length = _buffer.Length;
            int UintLength = (int)Math.Ceiling((double)buffer_length / 2);//转换成16进制的数组长度
            UInt16[] byteToUint16 = new UInt16[UintLength];//存放的位置;
            int i = 0, j = 0, highIndex = buffer_length - 2;
            if (BitConverter.IsLittleEndian)//littleendian格式,低地址低字节
            {               
                while (i < highIndex)
                {
                    byteToUint16[j] = (UInt16)(_buffer[i]| _buffer[++i]<<8 );//这里在移位后会返回一个int类型的值
                    j++;
                    i++;
                }
                if (buffer_length % 2 == 0)
                {
                    //buffer的长度为偶数时,循环会剩下两个字节
                    byteToUint16[j] = (UInt16)(_buffer[i]  | _buffer[++i]<< 8);
                }
                else
                {
                    //buffer的长度不为奇数时,循环会剩下一个字节
                    byteToUint16[j] = (UInt16)(_buffer[i] | (byte)0<<8);
                }
            }
            else
            {
                while (i < highIndex)//低地址高字节
                {
                    byteToUint16[j] = (UInt16)(_buffer[i]<<8| _buffer[++i] );//这里在移位后会返回一个int类型的值
                    j++;
                    i++;
                }
                if (buffer_length % 2 == 0)
                {
                    //buffer的长度为偶数时,循环会剩下两个字节
                    byteToUint16[j] = (UInt16)(_buffer[i] << 8 | _buffer[++i]);
                }
                else
                {
                    //buffer的长度不为奇数时,循环会剩下一个字节
                    byteToUint16[j] = (UInt16)(_buffer[i] << 8 | (byte)0);
                }
            }          
           
            for (int k = 0; k < UintLength; k++)
            {
                ckSum += (Int32)byteToUint16[k];//所有数相加;
            }
           
            ckSum = (ckSum >> 16) + (ckSum & 0xffff);//把余数也加进去,加两次即可把所有可能的余数加完。可简单证明。
            ckSum += ckSum >> 16;//这里就不用管高十六位了,因为下一步会把高十六位给截断。

            //求反
            return (UInt16)(~ckSum);
        }


    }
}

测试(对于发回来的数据包暂时还没有处理。)

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace ICMPCreate
{
    class Program
    {
        static void Main(string[] args)
        {           
            ICMPPacket packet = new ICMPPacket(8, 0, 0, 45, 2, 4);
            if (packet.ISError == true)
            {
                //出现错误
                Console.WriteLine("Error in create icmp packet!");
                Console.Read();
                return;
            }
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
            IPHostEntry remote = Dns.GetHostEntry("192.168.2.1");
            EndPoint epRemote = (EndPoint)new IPEndPoint(remote.AddressList[0], 0);//远程端点:                    
            byte[] receiveDate = new byte[100];
            int startTime = Environment.TickCount;
            if (s.SendTo(packet.BT_Buffer, epRemote) == -1)
            {
                Console.WriteLine("Error in send icmp packet");
                Console.Read();
                s.Close();
                return;
            }
            int rByte = s.ReceiveFrom(receiveDate, SocketFlags.None, ref epRemote);
            int timeout = Environment.TickCount - startTime;
            if (rByte == -1)
            {
                Console.WriteLine("主机没有响应!");
                Console.Read();
                s.Close();
                return;
            }
            s.Close();          
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值