Posts tagged ‘ICMP’
Mengirim Raw Packet: Latihan Ping
Setelah sebelumnya aku belajar membaca raw packet yang diterima network card, kali ini aku ingin mencoba mengirim raw packet secara langsung. Keuntungannya adalah aku bisa bebas menentukan semua parameter packet yang aku kirim. Sebagai latihan, aku akan mencoba membuat program yang mirip seperti program PING yang mengirim dan menerima packet ICMP ECHO.
Format packet ICMP ditentukan oleh RFC 792. Berikut ini adalah contoh packet ECHO REQUEST yang dikirim oleh program PING:
xx xx 08 00 4a 5c 02 00 01 00 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61 62 63 64 65 66 67 68 68
Dan ini adalah contoh ECHO REPLY atas packet di atas:
xx xx 00 00 52 5c 02 00 01 00 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61 62 63 64 65 66 67 68 69
Byte awal 08 menunjukkan kalau packet tersebut adalah ECHO REQUEST, dan byte 00 menunjukkan kalau packet tersebut adalah ECHO REPLY. Byte kedua (CODE) berisi nilai 00. Kemudian diteruskan dengan dua byte checksum. Dua byte berikutnya adalah IDENTIFIER, dilanjutkan dengan dua byte SEQUENCE NUMBER. Sepertinya program PING selalu menggunakan IDENTIFIER dengan nilai 0×0200. Nilai SEQUENCE NUMBER dipergunakan untuk mencocokkan antara request dan reply. Setelah itu PING mengirimkan 32 byte data yang berupa deretan huruf.
Sebelum memulai mengirim packet, aku harus memastikan bawah packet ICMP di-enkapsulasi lagi oleh packet IP, lalu oleh packet Ethernet. Untuk mempermudah pembuatan program, aku membuat sebuah struct sederhana yang merepresentasikan packet ECHO REQUEST seperti berikut ini:
struct ECHO_REQUEST {
u_char mac_destination[6];
u_char mac_source[6];
u_short type;
u_char ip_version_headerlength;
u_char ip_services;
u_short ip_totalLength;
u_short ip_identification;
u_char ip_flag;
u_char ip_fragment_offset;
u_char ip_ttl;
u_char ip_protocol;
u_short ip_checksum;
u_char ip_source[4];
u_char ip_destination[4];
u_char icmp_type;
u_char icmp_code;
u_short icmp_checksum;
u_short icmp_identifier;
u_short icmp_sequence;
u_char icmp_data[32];
};
Jika aku ingin men-PING komputer dengan IP 192.168.1.1 dari komputer dengan IP 192.168.1.2, maka aku dapat mengisi setiap field di packet seperti:
void initializeEchoRequestPacket(ECHO_REQUEST *echoRequest) {
u_char mac_destination[6] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
valuecpy(echoRequest->mac_destination, mac_destination, 6);
u_char mac_source[6] = {0x2, 0x2, 0x2, 0x2, 0x2, 0x2 };
valuecpy(echoRequest->mac_source, mac_source, 6);
echoRequest->type = 0x0008;
echoRequest->ip_version_headerlength = 0x45;
echoRequest->ip_services = 0x00;
echoRequest->ip_totalLength = 0x3C00;
echoRequest->ip_identification = 0x0400;
echoRequest->ip_flag = 00;
echoRequest->ip_fragment_offset = 0x0000;
echoRequest->ip_ttl = 0x80;
echoRequest->ip_protocol = 0x01;
echoRequest->ip_checksum = 0x0000;
u_char ip_source[4] = {192,168,1,2};
valuecpy(echoRequest->ip_source, ip_source, 4);
u_char ip_dest[4] = {192,168,1,1};
valuecpy(echoRequest->ip_destination, ip_dest, 4);
echoRequest->icmp_type = 0x08;
echoRequest->icmp_code = 0x00;
echoRequest->icmp_checksum = 0x0000;
echoRequest->icmp_identifier = 0x0002;
echoRequest->icmp_sequence = 0x000d;
for (int i=0; i<32; i++) { echoRequest->icmp_data[i] = 'B';
}
}
Agar packet ICMP ECHO REQUEST ini dapat dikirim dan diterima, selain mengisi IP address dengan benar, aku juga harus mengisi nilai MAC Source dan MAC Destination (yang merupakan bagian dari Ethernet Frame) dengan benar. Selain itu, aku juga harus melakukan kalkulasi untuk menghasilkan checksum dengan benar. Proses kalkulasi dan contoh kode program untuk kalkulasi checksum dapat dilihat di RFC 1071. Ini adalah contoh fungsi sederhana untuk menghitung nilai checksum untuk IP Header:
void calculateIPChecksum(ECHO_REQUEST *packet) {
u_short *shortValue = (u_short*)
(&packet->ip_version_headerlength);
long totalValue = 0;
for (int i=0; i<10; i++) {
totalValue += (*shortValue);
shortValue++;
}
while (totalValue>>16) {
totalValue = (totalValue & 0xffff) + (totalValue>>16);
}
packet->ip_checksum = ~totalValue;
}
Fungsi di atas mengandaikan IP Header berukuran fixed 20 bytes atau 10 words. Kalkulasi checksum dilakukan dengan menjumlahkan seluruh word (integer 16-bit) yang membentuk IP Header. Jika hasil jumlah dalam bentuk angka 16-bit ini mengandung carry/overflow , maka carry dari MSB dijumlahkan ke LSB, dan ini dilakukan berulang sampai tidak ada carry lagi. Dan hasilnya, 1′s complement dari nilai tersebut adalah nilai cheksum yang dipakai.
Dan sebagai langkah terakhir untuk mengirim ECHO REQUEST, aku harus melakukan proses pengiriman packet. Cara yang paling gampang adalah dengan menggunakan fungsi pcap_sendpacket(). Sebagai contoh, aku mengirimkan 15 kali ECHO REQUEST dengan menggunaakan kode seperti berikut:
for (int j=0; j<15; j++) {
struct ECHO_REQUEST *echoRequest =
new struct ECHO_REQUEST();
initializeEchoRequestPacket(echoRequest);
echoRequest->ip_identification = (u_short) j;
echoRequest->icmp_identifier = 0x0002;
echoRequest->icmp_sequence = (u_short) j;
calculateIPChecksum(echoRequest);
calculateICMPChecksum(echoRequest);
if (pcap_sendpacket(handle, (u_char*)((void*)echoRequest), 74)) {
printf("ERROR: %s\n", pcap_geterr(handle));
exit(EXIT_FAILURE);
}
delete echoRequest;
}
O ya, sebagai data pada ECHO REQUEST, aku mengirimkan 32 byte huruf ‘B’. Sebenarnya, aku punya kebebasan untuk memberikan nilai apa saja disini. Salah satu ide kreatif yang pernah aku temui adalah mengirimkan data melalui ICMP ECHO, seperti isi web page atau text chatting. Administrator cenderung memblokir komunikasi TCP/IP berdasarkan port. Jika ia berbaik hati membolehkan packet ICMP REQUEST keluar masuk dengan leluasa [test dengan mencoba apakah program PING dapat dipakai], maka seseorang bisa saja melakukan tunneling. Misalnya, request HTTP disisipkan sebagai data dalam packet ICMP ECHO REQUEST, kemudian diterima oleh komputer lain yang bebas dari blokiran. Program spesial di komputer lain tersebut membaca data spesial di ICMP ECHO REQUEST tersebut, lalu melakukan koneksi internet, dan mengirimkan hasilnya ke komputer pengguna, juga dalam bentuk ICMP ECHO REQUEST/REPLY. Sang administrator di ruangan khususnya, kini sedang serius membaca log firewall (atau mungkin membaca chat gadis-gadis QA sambil sesekali tertawa, no offense here, just a speculation), hanya akan melihat dua komputer saling nge-ping.
ICMP: Sang Pemberitahu Masalah
Komunikasi pesan dari pengirim hingga penerima mungkin saja mengalami masalah ditengah saja. Untuk memberi tahu kepada pengirim bahwa telah terjadi suatu masalah, Internet Control Message Protocol (ICMP) siap bekerja. Berikut ini adalah contoh packet ICMP:
.. .. 03 03 6b 69 00 00 00 00 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ...
Byte pertama menunjukkan jenis pesan ICMP. Nilai 03 menunjukkan ini adalah pesan “Destination Not Reachable”. Nilai lain yang mungkin adalah:
00 = Echo Reply 03 = Destination Not Reachable 04 = Source Quench 05 = Redirection Required 08 = Echo Request 11 = Time To Live Exceeded 12 = Parameter Problem 13 = Timestamp Request 14 = Timestamp Reply 17 = Address Mask Request 18 = Address Mask Reply
Banyak utility jaringan yang memanfaatkan ICMP, misalnya PING yang akan mengirim “Echo Request” dan memeriksa “Echo Reply”.
Byte kedua berisi kode untuk memperjelas pesan ICMP. Pada contoh di atas, byte kedua bernilai 03, yang menunjukkan informasi “Port unreachable”. Setelah itu ada dua byte checksum.
Byte ke-lima sampai byte ke-delapan seharusnya berisi parameter. Tetapi tidak semua pesan ICMP mengandung parameter, dan kebetulan “Destination Not Reachable” tidak membutuhkan parameter, sehingga nilainya 00 semua.
Byte berikutnya merupakan isi dari pesan, dan layout-nya berbeda-beda tergantung pada jenis pesan ICMP. Pada contoh di atas, byte berikutnya mengandung packet IP asli yang mengalami “Destination Not Reachable”. Packet asli tersebut tidak ditampilkan, hanya berupa tanda “xx” saja.