SỬ DỤNG RAW SOCKET

Một phần của tài liệu SỬ DỤNG KỸ THUẬT LẬP TRÌNH SOCKET XÂY DỰNG CHƯƠNG TRÌNH SCAN IP (Trang 21 - 28)

CHƯƠNG 2. LẬP TRÌNH MẠNG VỚI SOCKET

1.8. SỬ DỤNG RAW SOCKET

Gói tin ICMP không sử dụng TCP hoặc UDP nên chúng ta không thể sử dụng các lớp được hỗ trợ như TCPClient hay UDPClient mà phải sử dụng một Raw Socket.

Muốn tạo Raw Socket khi tạo Socket ta phải sử dụng SocketType.Raw, giao thức ICMP.

Cách tạo Raw Socket như sau:

Socket newsock= new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);

o Raw Socket Format

Value Description

GGP Gateway – to – Gateway Protocol

ICMP Internet Control Message Protocol

IDP IDP Protocol

IGMP Internet Group Management Protocol

IP A raw IP packet

IPX Novell IPX Protocol

ND Net Disk Protocol

PUP Xerox PARC Universal Protocol (PUP)

Raw A raw IP Packet

SPX Novell SPX Protocol

SPXLL Novell SPXv2 Protocol

Unknown An unknown protocol

Unspecified An unspecified protocol

Gửi gói dữ liệu Raw:

o Là giao thức không hướng kết nối, không cần bind socket đến cổng cục bổ để gửi gói tin hoặc dùng phương thức Conncect() để kết nối nó với host cụ thể ở xa.

xvii

o Sử dụng phương thức SendTo() của lớp Socket để gửi.

o Công trong giao thức ICMP không quan trọng.

o Chú ý: Vì raw socket không format dữ liệu nên mảng byte sẽ truyền nguyên định dạng đến host ở xa. Do đó ta phải tạo thủ công gói ICMP thành mảng byte rồi mới gởi. Nếu có lỗi bạn sẽ không có gói ICMP trả về.

Socket newsock= new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);

IPEndPoint iep = new IPEndPoint (IPAdress.Parse(“192.168.1.2”),0);

Sock.SendTo(packet, iep);

Nhận gói dữ liệu Raw

o Dữ liệu nhận được từ raw socket phức tạp hơn, ta phải dùng phương thức ReceiveFrom().

o Raw socket không xác định giao thức tầng trên, dữ liệu trả về phương thức ReceiveFrom() chứa toàn bộ nội dung gói IP.

o Chú ý: Vì phương thức ReceiveFrom() cho toàn bộ gói tin IP, ta phải khai báo kích thước buffer nhận nhiều hơn dữ liệu chứa bên trong ít nhất là 20 bytes.

Tạo lớp ICMP Class

o Tạo lớp ICMP class để dễ dùng trong các ứng dụng mạng có các gói ICMP.

o Lớp ICMP thường cần có các biến dữ liệu trong bản sau:

Variable Size Type

Type 1 byte Byte

Code 1 byte Byte

Checksum 2 bytes Unsigned 16-bit integer Message Multibyte Byte array

o Không gán giá trị cho các biến dữ liệu. Ta sẽ gán giá trị cho chúng khi thực sự khởi tạo gói ICMP.

class ICMP {

xviii

public byte Type;

public byte Code;

public UInt16 Checksum;

public int MessageSize;

public byte[] Message = new byte[1024];

public ICMP() {

} }

o Để tạo gói ICMP mới, ta khai báo và gán giá trị:

ICMP packet = new ICMP();

packet.Type = 0x08;

packet.Code = 0x00;

packet.Checksum = 0;

o Đoạn code trên tạo phần đầu của gói ICMP Echo Request.

o Gói Echo Request định nghĩa các trường trong thành phần thông điệp ICMP (Idnetifier và Sequence), bạn phải quyết định xây dựng thành phần này như thế nào. Bằng 2 cách:

• Tạo lớp khác cho trường Echo Request và lấy mảng byte của lớp.

• Chuyển các trường thông điệp riêng thành mảng byte và đặt chúng vào thành phần dữ liệu.

o Nếu bạn định tạo nhiều gói Echo Request, nên tạo lớp Ping định nghĩa các trường Echo Request riêng biệt.

o Ngược lại ta làm theo cách sau:

Buffer.BlockCopy(BitConverter.GetBytes((short)1),0, packet.Message, 0, 2);

Buffer.BlockCopy(BitConverter.GetBytes((short)1),0, packet.Message, 2, 2);

byte[] data = Encoding.ASCII.GetBytes("test packet");

Buffer.BlockCopy(data, 0, packet.Message, 4, data.Length);

xix

packet.MessageSize = data.Length + 4;

o Các trường Identifier và Sequence cho gói Echo Reply lần lượt chuyển thành mảng byte và đặt đúng vị trí trong thành phần thông điệp.

Xây dựng lại đối tượng ICMP Object

o Sau khi gởi gói ICMP, thường ta sẽ nhận lại gói ICMP của thiết bị từ xa trả về. Để lây nội dung của gói đó, bạn nên tạo lớp ICMP khởi dựng khác để lấy mảng byte ICMP và đặt giá trị vào thành phần dữ liệu phù hợp trong lớp:

public ICMP(byte[] data, int size) {

Type = data[20];

Code = data[21];

Checksum = BitConverter.ToUInt16(data, 22);

MessageSize = size - 24;

Buffer.BlockCopy(data, 24, Message, 0, MessageSize);

}

o Lưu ý raw socket trả về toàn bộ gói IP. Như vậy ta phải bỏ qua thông tin IP header trước khi trích thông tin gói ICMP.

o Thành phần Type ở vì trí 20 trong mảng byte. Các thành phần dữ liệu riêng biệt trong gói ICMP được trích theo từng byte vào thành phần ICMP phù hợp.

o Sau khi tạo đối tượng ICMP mới với dữ liệu gói nhận được, ta có thể xem được thành phần dữ liệu riêng biệt:

int recv = ReceiveFrom(data, ref ep);

ICMP response = new ICMP(data, recv);

Console.WriteLine("Received ICMP packet:");

Console.WriteLine(" Type {0}", response.Type);

Console.WriteLine(" Code: {0}", response.Code);

Int16 Identifier = BitConverter.ToInt16(response.Message, 0);

Int16 Sequence = BitConverter.ToInt16(response.Message, 2);

Console.WriteLine(" Identifier: {0}", Identifier);

xx

Console.WriteLine(" Sequence: {0}", Sequence);

stringData = Encoding.ASCII.GetString(response.Message, 4, response.MessageSize - 4);

Console.WriteLine(" data: {0}", stringData);

o Vì 2 bytes đầu tạo trường số nguyên không dấu Identifier vaf 2 bytes thứ hai là trường số nguyên không dấu Sequence, bạn có thể dùng lớp BitConverter để gán các giá trị đó.

o Phần còn lại của thành phần thông điệp được gán cho trường Message của gói Echo Reply packet.

o Từ đoạn code này, ta dễ thấy vì sao thành MessageSize được thêm vào lớp ICMP. Nếu không có nó, sẽ khó xây dựng lại thành phần Message từ gói nhận được.

The ICMP Packet Creator

o Sau khi đối tượng ICMP mới được tạo ra và các thành phần dữ liệu gói được xác định, bạn muốn gởi gói đến thiết bị ở xa. Bạn không thể gởi đối tượng ICMP bằng phương thức SendTo(); cần chuyển nó thành mảng byte.

o Các dễ nhất để gởi đối tượng phức tạp qua mạng là tạo phương thức chuyển mỗi thành phần dữ liệu thành mảng byte và nối các mảng byte lớn hơn dùng phương thức Buffer.BlockCopy():

public byte[] getBytes() {

byte[] data = new byte[MessageSize + 9];

Buffer.BlockCopy(BitConverter.GetBytes(Type), 0, data, 0, 1);

Buffer.BlockCopy(BitConverter.GetBytes(Code), 0, data, 1, 1);

Buffer.BlockCopy(BitConverter.GetBytes(Checksum), 0, data, 2, 2);

Buffer.BlockCopy(Message, 0, data, 4, MessageSize);

return data;

}

o Khi tất cả các thành phần dữ liệu được chuyển thành mảng byte có đúng dạng gói ICMP có thể nó đến thiết bị mạng ở xa:

xxi

IPEndPoint iep = new IPEndPoint(IPAddress.Parse("192.168.1.2"), 0);

sock.SendTo(packet.getBytes(), iep);

o Chú ý: Giá trị Identifier và Sequence không được chuyển thành byte trước khi đưa vào mảng vì thiết bị mạng ở xa sẽ trả về cho bạn gói y hệt.

o Đây là phần khó nhất khi tạo ra gói ICMP packet. Cách làm là tạo phương thức tự chứa tính checksum và đưa vào lớp ICMP phụ vụ cho ứng dụng ICMP.

o Cho vài ví dụ tính checksum, sau đây là ví dụ:

public UInt16 getChecksum() {

UInt32 chcksm = 0;

byte[] data = getBytes();

int packetsize = MessageSize + 8;

int index = 0;

while ( index < packetsize) {

chcksm += Convert.ToUInt32(BitConverter.ToUInt16(data, index));

index += 2;

}

chcksm = (chcksm >> 16) + (chcksm & 0xffff);

chcksm += (chcksm >> 16);

return (UInt16)(~chcksm);

o Đầu tiên gán đầy giá trị tất cả thành phần dữ liệu, đặt thành phần Checksum thành zero. Sau đó, gọi phương thức getChecksum() để tình checksum của gói ICMP, đặt kết quả vào thành phần Cheksum của gói:

packet.Checksum = 0;

packet.Checksum = packet.getChecksum();

o Sau khi tính xong Cheksum gởi gói đi sử udnjg phương thức SendTo().

o Chú ý: Khi nhận gói ICMP phải lấy giá trị Checksum và so sánh với giá trị đã tính cho gói. Nếu 2 giá trị không so khớp, đã có lỗi và cần truyền lại gói.

xxii

xxiii

Một phần của tài liệu SỬ DỤNG KỸ THUẬT LẬP TRÌNH SOCKET XÂY DỰNG CHƯƠNG TRÌNH SCAN IP (Trang 21 - 28)

Tải bản đầy đủ (PDF)

(47 trang)