setting setsockopt for detect ip option

1.6k Views Asked by At

i want to detect ip options of incoming internet packets. Here's my code.

//#define IPPROTO_IP 0
//#define IP_OPTIONS 68
#define SENDER_PORT_NUM 53
#define SENDER_IP_ADDR "127.0.0.1" 
#define true 1

static void bail(const char *error)
{
    printf("%s: %s\n", error, strerror(errno));
    exit(1);
}

struct ip_datagram{
   unsigned char ver_ihl;
   unsigned char tos; 
   unsigned short totlen;
   unsigned short id; 
   unsigned short flags_offs;
   unsigned char ttl; 
   unsigned char proto; 
   unsigned short checksum;
   unsigned long src; 
   unsigned long dst; 
   unsigned char payload[1500];
};       
int main(){    

   int s,b,sso,gso, i;
   int contatore = 5;
   int enabled = 1;  
   char *data, *buffer;
   int addrlen;
   struct sockaddr_in addr;    
   struct ip_datagram *ip, *ip_reply;
   struct icmphdr* icmp;    
   //char *src_addr="93.34.229.111";
   char *dst_addr="127.0.0.1";

   data = malloc(sizeof(struct ip_datagram)+ sizeof(struct icmphdr));
   buffer = malloc(sizeof(struct ip_datagram)+ sizeof(struct icmphdr));
   ip = (struct ip_datagram *) (data );
   icmp = (struct icmphdr*) (data + sizeof(struct ip_datagram));

   ip->ver_ihl = 45;
   //ip->ihl = 15;
   ip->totlen = sizeof(struct ip_datagram);
   ip->proto = IPPROTO_ICMP;
   //ip->src =(inet_addr(src_addr));
   ip->dst = inet_addr(dst_addr);
   ip->checksum = in_cksum((unsigned short *)ip, sizeof(struct     ip_datagram)); 
   icmp->type      = ICMP_ECHO;
   icmp->checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));

   s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
   if(s<0)
      printf("errore socket\n");

   sso = setsockopt(s, IPPROTO_IP, IP_OPTIONS,  &enabled, sizeof(enabled));
   if(sso<0)
      bail("errore setsockoptions\n");

   gso = (s, IPPROTO_IP, IP_OPTIONS,  &enabled, sizeof(enabled));
   if(gso<0)
      bail("errore getsockoptions\n");
   else
      printf("IP_OPTIONS VALUE :%d\n", enabled);

   addr.sin_family = AF_INET;
   addr.sin_addr.s_addr = ip->dst;

   while(contatore>0){
      int sent_bytes = sendto(s, (const char *)data, ip->totlen, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr) );

      if(sent_bytes <0){
         printf("failed to send packets\n");
         return 3;
      }
      //printf("Sent %d byte packet from %s to %s\n", ip->totlen, src_addr, dst_addr);
      printf("Sent %d byte packet to %s\n", ip->totlen, dst_addr);   

      addrlen = sizeof(addr);

      int bytes = recvfrom(s, buffer, sizeof(struct ip_datagram) + sizeof(struct icmphdr), 0, (struct sockaddr*)&addr, &addrlen);

      if(bytes<=0){
         printf("errore recvfrom\n");
         break;
      }
      else{
         char *cp;   
         ip_reply = (struct ip_datagram*) buffer;
         cp = (char *)&ip_reply->src;
         printf("Received %d byte reply from %u.%u.%u.%u:\n", ntohs(ip_reply->totlen), cp[0]&0xff,cp[1]&0xff,cp[2]&0xff,cp[3]&0xff);
         printf("ID: %d\n", ntohs(ip_reply->id));
         printf("TTL: %d\n", ip_reply->ttl);
         printf("type of service: %.1X\n", ip_reply->tos);        
         printf("IP ADDRESS SOURCE: %.4X\n", htonl(ip_reply->src));
         printf("IP ADDRESS DESTINATION: %.4X\n", htonl(ip_reply->dst));
         printf("versione + header length: %.1X\n", ip_reply->ver_ihl);
         contatore--;       
         printf("-----------------\n");        
         printf("****************\n");
      }
   }    
}

the problem is the header length is 6 but the length should be 20 for detecting all ip options. In setsockopt, maybe, the type of enabled variable should be a char, but i have some problem when i run the program: in fact, with a char type it gives me an error for invalid argument. I want to know also how to print these options using getsockoption. What's the problem? i hope my question is clear :)

1

There are 1 best solutions below

2
On

The structure you define for your IP header MIGHT be broadly compatible with an IP packet header but it's not really good enough and not easily usable.

On my Linux system the system headers define the IP header in /usr/include/linux/ip.h like this:

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u8    ihl:4,
            version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
    __u8    version:4,
            ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif
    __u8    tos;
    __be16  tot_len;
    __be16  id;
    __be16  frag_off;
    __u8    ttl;
    __u8    protocol;
    __sum16 check;
    __be32  saddr;
    __be32  daddr;
    /*The options start here. */
};

As you can see, this breaks the IP version and header length properly, and it's safer to be compiled for big or little endian targets.

With a structure definition like this you can find the start of the IP options after sizeof(struct iphdr) bytes, and the size of the entire IP header will be ip.ihl * 4, where ip is a struct iphdr.

You need the multiplication by 4 above because ihl is the number of 32 bit words that makes up the IP header, not the byte count of the header itself.

You can look at IPv4 (Wikipedia) which has some general information about IP header options and their format, and IANAs list of IP Options for a complete list, with links to the various RFCs which describe the details of each option.