什么是BSD(或便携式)方式来获取ToS字节(如linux中的IP_RECVTOS)?

什么是BSD(或便携式)方式来获取ToS字节(如linux中的IP_RECVTOS)?,c,unix,sockets,network-programming,C,Unix,Sockets,Network Programming,获取接收到的数据包的ToS字节的正确(便携、稳定)方法是什么?我正在使用recvmsg()进行UDP,在linux上,如果我设置了sockopt()IP_RECVTOS/IPV6_RECVTOS类,我就可以获得ToS,但我的BSD系统上似乎没有IP_RECVTOS。正确的方法是什么 我主要希望它能在BSD和Solaris上工作 编辑: 澄清: 我目前使用recvmsg(),在Linux上的msg_控制字段中获取TTL和TOS,但为了获取TTL和TOS,我需要设置sockopt()-启用IP_RE

获取接收到的数据包的ToS字节的正确(便携、稳定)方法是什么?我正在使用recvmsg()进行UDP,在linux上,如果我设置了sockopt()IP_RECVTOS/IPV6_RECVTOS类,我就可以获得ToS,但我的BSD系统上似乎没有IP_RECVTOS。正确的方法是什么

我主要希望它能在BSD和Solaris上工作

编辑: 澄清: 我目前使用recvmsg(),在Linux上的msg_控制字段中获取TTL和TOS,但为了获取TTL和TOS,我需要设置sockopt()-启用IP_RECVTTL和IP_RECVTOS。而且,由于Solaris和BSD(目前正在使用FreeBSD)没有IP_RECVTOS,从我所看到的情况来看,在循环CMSG数据时,我没有得到TOS

我尝试启用IP_RECVOPTS和IP_recvretops,但仍然没有任何IP_TOS类型的CMSG

编辑2: 我希望ToS能够验证(尽可能多地)它在传输过程中没有被覆盖。例如,如果一个VoIP应用程序突然发现它没有得到EF标记的数据包,那么一定是出了问题,应该会出现警报。(不,我不希望EF在公共互联网上受到尊重或保留)


我想要TTL基本上就是因为我能。假设这可以用来触发“我和对方之间的网络发生了变化”警报,这有助于了解某些东西是否同时停止工作。

不幸的是,这类事情通常在不同的*IX之间有所不同。在Solaris上,您希望将
getsockopt
IP_-TOS
一起使用;我不知道BSD

有关详细信息,请参阅。

正确的标准解决方案可能是使用
cmsg(3)
。您将在“Unix网络编程”一书中找到完整的描述,这是一本必读的书


谷歌代码搜索找到了这个。我在想是否可以创建两个套接字

  • 一个DGRAM类型的插座,专门用于发送

  • 一个专门用于接收的原始插座

  • 由于您使用的是UDP,因此可以在原始Sock Fd上调用bind+recvFrom,然后手动解压缩IP头以确定TOS或TTL

    当您想要发送时,请使用DGRAM sockFd,这样您就不必亲自创建UDP&IP数据包了

    可能存在这样的问题:内核可能会将接收到的缓冲区传递给两个套接字,或者传递给UDP套接字,而不是原始套接字,或者只传递给原始套接字。如果是这种情况(或者依赖于实现),那么我们就回到了原点。但是,您可以尝试在原始套接字上调用bind,看看它是否有帮助。我知道这可能是黑客攻击,但在网上搜索BSD的setsockopt时没有返回任何结果

    编辑:我编写了一个示例程序 它实现了目标

    下面的代码创建了两个套接字(一个原始套接字和一个udp套接字)。udp套接字绑定在我期望接收数据的实际端口上,而原始套接字绑定在端口0上。我在Linux上对此进行了测试,正如我预期的那样,端口2905的任何数据都会被两个套接字接收。但是,我能够检索TTL和TOS值。不要对代码的质量投反对票。我只是在试验它是否有效

    进一步编辑:禁用UDP套接字接收。 我进一步增强了代码以禁用UDP数据包接收使用setsockopt,我将UDP的套接字接收缓冲区设置为0。这确保内核不会将数据包传递到UDP套接字。IMHO,您现在可以专门使用UDP套接字进行发送,使用原始套接字进行读取。这在BSD和Solaris中也适用

    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<netinet/ip.h>
    #include<arpa/inet.h>
    #include<string.h>
    
    #include "protHeaders.x"
    #include "gen.h"
    
     int main(void)
     {
      S32 rawSockFd;
      S32 udpSockFd;
      struct sockaddr_in rsin;
      struct sockaddr_in usin;
      S32 one = 1;
      const S32* val = &one;
      struct timeval tv;
      fd_set rfds;
      S32 maxFd;
      S16 ret;
      S8 rawBuffer[2048];
      S8 udpBuffer[2048];
      struct sockaddr udpFrom,rawFrom;
      socklen_t rLen,uLen;
    
      memset(rawBuffer,0,sizeof(rawBuffer));
      memset(udpBuffer,0,sizeof(udpBuffer));
      memset(udpFrom,0,sizeof(udpFrom));
      memset(rawFrom,0,sizeof(rawFrom));
    
      if ((rawSockFd = socket(PF_INET,SOCK_RAW,IPPROTO_UDP)) < 0)
          {
             perror("socket:create");
             RETVALUE(RFAILED);
          }
    
      /* doing the IP_HDRINCL call */
      if (setsockopt(rawSockFd,IPPROTO_IP,IP_HDRINCL,val,sizeof(one)) < 0)
        {
           perror("Server:setsockopt");
           RETVALUE(RFAILED);
        }
    
       rsin.sin_family      = AF_INET;
       rsin.sin_addr.s_addr = htonl(INADDR_ANY);
       rsin.sin_port        = htons(0);
    
       usin.sin_family      = AF_INET;
       usin.sin_addr.s_addr = htons(INADDR_ANY);
       usin.sin_port        = htons(2905);
    
       if(bind(rawSockFd,(struct sockaddr *)&rsin, sizeof(rsin)) < 0 )
        {
         perror("Server: bind failed");
         RETVALUE(RFAILED);
        } 
    
    
      if ((udpSockFd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
          {
             perror("socket:create");
             RETVALUE(RFAILED);
          }
    
       if(bind(udpSockFd,(struct sockaddr *)&usin, sizeof(usin)) < 0 )
        {
         perror("Server: bind failed on udpsocket");
         RETVALUE(RFAILED);
        } 
    
      /*set upd socket receive buffer to 0 */
     one = 0; 
     if (setsockopt(udpSockFd,SOL_SOCKET,SO_RCVBUF,(char *)&one,sizeof(one)) < 0)
      {
         perror("Server:setsockopt on udpsocket failed");
         RETVALUE(RFAILED);
      }
    
      tv.tv_sec  = 0;
      tv.tv_usec = 0;
    
      maxFd = (rawSockFd > udpSockFd)? rawSockFd:udpSockFd;
    
        while(1)
        {
         FD_ZERO(&rfds);
         FD_SET(rawSockFd,&rfds);
         FD_SET(udpSockFd,&rfds);
    
         ret = select(maxFd+1,&rfds,0,0,&tv);
    
          if ( ret == -1)
             {
                 perror("Select Failed");
                 RETVALUE(RFAILED);
             }
    
           if(FD_ISSET(rawSockFd,&rfds))
            {
              printf("Raw Socked Received Message\n");
              if(recvfrom(rawSockFd,rawBuffer,sizeof(rawBuffer),0,&rawFrom,&rLen) == -1)
               {
                  perror("Raw socket recvfrom failed");
                  RETVALUE(RFAILED);
               }
             /*print the tos */
              printf("TOS:%x\n",*(rawBuffer+1));
              printf("TTL:%x\n",*(rawBuffer+8));
            }
    
           if(FD_ISSET(udpSockFd,&rfds))
            {
              printf("UDP Socked Received Message\n");
              if(recvfrom(udpSockFd,udpBuffer,sizeof(udpBuffer),0,&udpFrom,&uLen) == -1)
               {
                 perror("Udp socket recvfrom failed");
                 RETVALUE(RFAILED);
               }
              printf("%s\n",udpBuffer);
            }
    
    
        }
    
      RETVALUE(ROK);
     }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括“protHeaders.x”
    #包括“gen.h”
    内部主(空)
    {
    S32-rawSockFd;
    S32-udpSockFd;
    rsin中的结构sockaddr_;
    usin中的结构sockaddr_;
    S32一=1;
    常量S32*val=&one;
    结构时间值电视;
    fd_集rfds;
    S32-maxFd;
    S16-ret;
    S8 rawBuffer[2048];
    S8 udpBuffer[2048];
    结构sockaddr udpFrom,rawFrom;
    索克伦·特伦,乌伦;
    memset(rawBuffer,0,sizeof(rawBuffer));
    memset(udpBuffer,0,sizeof(udpBuffer));
    memset(udpFrom,0,sizeof(udpFrom));
    memset(rawFrom,0,sizeof(rawFrom));
    if((rawSockFd=socket(PF_INET,SOCK_RAW,IPPROTO_UDP))<0)
    {
    perror(“套接字:创建”);
    返回值(RFAILED);
    }
    /*执行IP_HDRINCL呼叫*/
    如果(设置锁定选项(rawSockFd、IPPROTO_IP、IP_HDRINCL、val、大小(一个))<0)
    {
    perror(“服务器:setsockopt”);
    返回值(RFAILED);
    }
    rsin.sin_family=AF_INET;
    rsin.sin_addr.s_addr=htonl(在任何情况下);
    rsin.sin_port=htons(0);
    usin.sin_family=AF_INET;
    usin.sin_addr.s_addr=htons(INADDR_ANY);
    usin.sinu port=htons(2905);
    if(bind(rawSockFd,(struct sockaddr*)&rsin,sizeof(rsin))<0)
    {
    perror(“服务器:绑定失败”);
    返回值(RFAILED);
    } 
    如果((udpSockFd=套接字(PF_INET、SOCK_DGRAM、IPPROTO_UDP))<0)
    {
    perror(“套接字:创建”);
    返回值(RFAILED);
    }
    if(bind(udpSockFd,(struct sockaddr*)&usin,sizeof(usin))<0
    {
    perror(“服务器:在udpsocket上绑定失败”);
    返回值(RFAILED);
    } 
    /*将upd套接字接收缓冲区设置为0*/
    1=0;
    if(setsockopt(udpSockFd,SOL_SOCKET,SO_RCVBUF,(char*)&one,sizeof(one))<0)
    {
    perror(“服务器:udpsocket上的setsockopt失败”);
    返回值(RFAILED);
    }
    tv.tv_sec=0;
    tv.tv_usec=0;
    maxFd=(rawSockFd>udpSockFd)?rawSockFd:udpSockFd;
    而(1)
    {
    FD_ZERO(和RFD);
    FD_集(rawSockFd和RFD);
    FD_集(udpSockFd和rfds);
    ret=选择(最大FD+1,&rfds,0,0,&tv);
    如果(ret==-1)
    {
    perror(“选择失败”);
    返回值(RFAILED);
    }
    if(FD_ISSET(rawSockFd和RFD))
    {
    printf(“原始套接字接收消息\n”);
    如果