вівторок, 5 жовтня 2010 р.

Using RAW Sockets under Linux

Here is a small demo of raw sockets under Linux.
This will send an ICMP ping over network and wait for response.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>

#include <sys/socket.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <arpa/inet.h>

#define PROTOCOL (IPPROTO_ICMP)
#define ADDRESS "172.17.57.112"


uint16_t chksum16(void* addr, int len) {
 register int sum = 0;
 uint16_t answer = 0;
 register uint16_t* w = (uint16_t*)addr;
 register int nleft = len;

 while (nleft > 1) {
  sum += *w++;
  nleft -= 2;
 }

 if (nleft == 1) {
  *(uint8_t *) (&answer) = *(uint8_t *) w;
  sum += answer;
 }
 sum = (sum >> 16) + (sum & 0xffff);
 sum += (sum >> 16);
 answer = ~sum;
 return (answer);
}

struct Packet {
 iphdr ip;
 icmphdr icmp;
};

int main() {
 Packet outBuff;
 memset(&outBuff, 0, sizeof(Packet));

 outBuff.ip.ihl   = 5;
 outBuff.ip.version  = 4;
 outBuff.ip.tot_len  = sizeof(Packet);
 outBuff.ip.id   = htons(getuid());
 outBuff.ip.ttl   = 255;
 outBuff.ip.protocol  = PROTOCOL;
 outBuff.ip.saddr  = inet_addr("172.17.57.112");
 outBuff.ip.daddr  = inet_addr(ADDRESS);
 outBuff.ip.check  = chksum16(&outBuff.ip, sizeof(iphdr));

 outBuff.icmp.type  = ICMP_ECHO;
 outBuff.icmp.checksum = chksum16(&outBuff.icmp, sizeof(icmphdr));

 struct sockaddr_in peer;
 peer.sin_family = AF_INET;
 peer.sin_addr.s_addr = inet_addr(ADDRESS);

 int sock = socket(AF_INET, SOCK_RAW, PROTOCOL);
 int optval;
 if (sock != -1 && setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int)) != -1) {
  if (sendto(sock, &outBuff, sizeof(Packet), 0, (sockaddr *)&peer, sizeof(sockaddr)) != -1) {
   printf("Echo sent\n");

   Packet inBuff;
   memset(&inBuff, 0, sizeof(Packet));
   while (recv(sock, &inBuff, sizeof(Packet), 0) != -1) {
    if (chksum16((unsigned short *)&inBuff.ip, sizeof(iphdr)) == 0) {
    } else {
     printf("IP CRC error\n");
    }

    if (chksum16((unsigned short *)&inBuff.icmp, sizeof(icmphdr)) == 0) {
     switch (inBuff.icmp.type) {
     case ICMP_ECHO: {
      printf("Echo received\n");
      continue;
     } break;
     case ICMP_ECHOREPLY: {
      printf("Got reply\n");
     } break;
     case ICMP_DEST_UNREACH: {
      printf("Destination unreachable\n");
     } break;
     case ICMP_HOST_UNKNOWN: {
      printf("Host unknown\n");
     } break;
     default: {
      printf("Type: %d\n", inBuff.icmp.type);
     } break;
     }
    } else {
     printf("ICMP CRC error\n");
    }

    break;
   }
  }

  close(sock);
 } else {
  printf("Cannot open socket\n");
 }

 return 0;
}

Немає коментарів:

Дописати коментар