什么是获取ToS字节的BSD(或可移植)方式(如linux中的IP_RECVTOS)?

获取接收数据包的ToS字节的正确(可移植,稳定)方式是什么?我正在使用recvmsg()进行UDP,并且在
linux上我可以获得ToS,如果我setsockopt()IP_RECVTOS / IPV6_RECVTCLASS,但IP_RECVTOS似乎在我的BSD系统上不可用.这样做的正确方法是什么?

我主要希望这可以在BSD和Solaris上运行.

编辑:
澄清:
我目前使用recvmsg(),我在Linux上的msg_control字段中获取TTL和TOS,但为了获得TTL和TOS,我需要setsockopt() – 启用IP_RECVTTL和IP_RECVTOS.而且由于Solaris和BSD(目前与FreeBSD合作)没有我所看到的IP_RECVTOS,因此在循环CMSG数据时我没有获得TOS.

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

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

我想要TTL基本上只是因为我可以.假设这可以用来触发“我和另一方之间的网络中的某些变化”警报,这可能有助于了解某些事情是否同时停止工作.

最佳答案 我在想你是否可以创建两个套接字.

> DGRAM类型的一个插座专门用于发送
>一个专门用于接收的Raw套接字.

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

当你想发送时,使用DGRAM sockFd,所以你不必费心去实际创建UDP&你自己的IP包.

可能存在内核可能将接收到的缓冲区传递到套接字或UDP套接字而不是Raw套接字或仅传递给Raw套接字的问题.如果是这种情况(或者如果它依赖于实现),那么我们将回到原点.但是,您可以尝试在Raw套接字上调用bind并查看它是否有帮助.我知道这可能是一个黑客,但在网上搜索一个用于BSD的setsockopt没有返回任何内容.

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

下面的代码创建了两个套接字(一个原始和一个udp). udp套接字绑定在我期望接收数据的实际端口上,而原始套接字绑定在端口0上.我在Linux上进行了测试,就像我预期的那样,两个套接字都接收到端口2905的任何数据.然而,我能够检索TTL& TOS值.不要为了代码的质量而投票.我只是在试验它是否会起作用.

进一步编辑:禁用UDP套接字接收.
我进一步增强了代码以禁用UDP数据包的接收.使用setsockopt,我将UDP的套接字接收缓冲区设置为0.这可确保内核不会将数据包传递给UDP套接字.恕我直言,您现在可以使用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);
 }
点赞