【问题标题】:setting setsockopt for detect ip option设置 setsockopt 以检测 ip 选项
【发布时间】:2016-03-23 00:04:36
【问题描述】:

我想检测传入 Internet 数据包的 ip 选项。这是我的代码。

//#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");
      }
   }    
}

问题是标头长度为 6,但长度应为 20 以检测所有 ip 选项。在 setsockopt 中,启用的变量的类型可能应该是 char,但我在运行程序时遇到了一些问题:事实上,使用 char 类型它会给我一个无效参数的错误。我还想知道如何使用getsockoption 打印这些选项。有什么问题?我希望我的问题很清楚:)

【问题讨论】:

  • 请正确缩进您的代码,以便于阅读。
  • 您如何使用 IP 版本和像这样合并为单个字节的标头长度?您需要将它们分成 4 位数量,以便它们有用。

标签: c networking ip setsockopt getsockopt


【解决方案1】:

您为 IP 标头定义的结构可能与 IP 数据包标头广泛兼容,但它还不够好且不易使用。

在我的 Linux 系统上,系统标头在 /usr/include/linux/ip.h 中定义 IP 标头,如下所示:

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. */
};

如您所见,这会正确破坏 IP 版本和标头长度,并且针对大端或小端目标进行编译更安全。

通过这样的结构定义,您可以在sizeof(struct iphdr) 字节之后找到IP 选项的开始,整个IP 标头的大小将为ip.ihl * 4,其中ip 是struct iphdr

您需要上面乘以 4,因为ihl 是构成 IP 标头的 32 位字的数量,而不是标头本身的字节数。

您可以查看IPv4 (Wikipedia),其中包含有关 IP 标头选项及其格式的一些一般信息,以及 IANAs list of IP Options 的完整列表,以及描述每个选项详细信息的各种 RFC 的链接。

【讨论】:

  • 好的,我进行了更改。现在标头长度为 24,我如何查看 ip 选项? setsockopt 设置是否适合检测这些选项?
  • 好的,这意味着您有 4 个字节的 IP 选项。不,getsockopt/setsockopt 用于套接字,与 IP 标头选项无关。我在答案的底部添加了一个段落,其中包含一些指向页面的链接,其中包含有关 IP 标头选项的内容,但我担心您将不得不亲自处理数据,我没有认为有一个简单的库适合您 AFAIK。
猜你喜欢
  • 1970-01-01
  • 2014-05-19
  • 2018-03-18
  • 1970-01-01
  • 2013-07-06
  • 2020-05-03
  • 1970-01-01
  • 2022-12-24
  • 2015-08-21
相关资源
最近更新 更多