Frage

Was ist die richtige (tragbar, stabil) Weg, um das ToS Byte eines empfangenen Pakets zu bekommen? Ich mache UDP mit recvmsg () und auf Linux kann ich die ToS, wenn ich setsockopt () IP_RECVTOS / IPV6_RECVTCLASS, aber IP_RECVTOS scheint nicht auf meine BSD-Systemen zur Verfügung zu stehen. Was ist der richtige Weg, dies zu tun?

ich dies in erster Linie will auf dem BSDs und Solaris arbeiten.

Edit: Um klarzustellen: Ich benutze recvmsg zur Zeit (), wo ich die TTL und TOS im msg_control Feld erhalten auf Linux, aber um TTL und TOS ich SetSockOpt müssen get () - ermöglichen IP_RECVTTL und IP_RECVTOS. Und da Solaris und BSD (Arbeiten mit FreeBSD im Moment) nicht IP_RECVTOS haben von dem, was ich sehe, kann ich nicht bekommen, TOS, wenn sie über den CMSG Daten Looping.

Ich habe versucht, ermöglicht IP_RECVOPTS und IP_RECVRETOPTS, aber ich immer noch nicht bekommen jede IP_TOS Typ CMSG.

Edit 2: Ich mag ToS der Lage sein zu überprüfen (so viel wie möglich), dass es beim Transport nicht überschrieben wurde. Wenn zum Beispiel ganz plötzlich bemerkt eine VoIP-Anwendung, die es nicht EF-Pakete markiert bekommen, dann ist etwas nicht in Ordnung, und es soll ein Alarm sein. (Und nein, ich erwarte nicht EF respektiert oder über das öffentliche Internet erhalten werden)

Ich möchte TTL im Grunde nur, weil ich es kann. Hypothetisch diese verwendet werden könnten, auslösen „etwas im Netz zwischen mir verändert und auf der anderen Seite“ Warnungen, die nützlich sein können, zu wissen, ob Somethings stoppt gleichzeitig arbeiten.

War es hilfreich?

Lösung

Ich dachte, wenn Sie zwei Sockets erstellen.

  1. Eine Buchse vom Typ dgram verwendet ausschließlich für das Senden

  2. Ein Raw-Socket verwendete ausschließlich für den Empfang.

Da Sie UDP verwenden, können Sie eine Bindung + Recvfrom auf dem Raw-Socken-Fd rufen und dann auspacken manuell die IP-Header, um die TOS oder TTL zu bestimmen.

Wenn Sie senden möchten, verwenden Sie die dgram sockfd so müssen Sie nicht stören müssen, um tatsächlich die UDP und IP-Paket selbst zu erstellen.

Es können Probleme wie der Kern sein kann, den empfangenen Puffer zu den beiden Buchsen oder an den UDP-Sockets anstelle von Raw Socket oder einfach nur an den Raw Socket übergeben. Wenn das der Fall ist (oder wenn ist es abhängig von der Implementierung), dann sind wir auf Platz eins zurück. Sie können jedoch versuchen, auf der Raw Socket bind und sehen, ob es hilft. Ich bin dies vielleicht ein Hack bewusst, aber für einen setsockopt auf dem Netz Suche nach BSD nichts zurückgegeben.

Bearbeiten : Ich schrieb ein Beispielprogramm Es Art erreicht das Ziel.

Der folgende Code erstellt zwei Buchsen (roh und ein udp). Die udp Buchse ist auf dem tatsächlichen Port gebunden Ich erwarte, Daten zu empfangen, während die Raw-Socket an Port 0. Ich habe dies auf Linux getestet gebunden ist und wie ich alle Daten erwartet für Port 2905 wird von beiden die Buchsen empfangen. Ich bin jedoch in der Lage, die TTL & TOS-Werte abzurufen. Nicht downvote für die Qualität des Codes. Ich bin nur zu experimentieren, ob es funktionieren wird.

Weitere EDIT: Deaktiviert die erhalten von UDP-Socket . Ich habe weiter den Code erweitert die durch das UDP-Paket empfangen zu deaktivieren. Mit setsockopt, habe ich den Anschluss des UDP empfangen 0 puffern. Das den Kernel stellt sicher, nicht das Paket an den UDP-Socket übergeben. IMHO, Sie können jetzt das UDP-Sockets ausschließlich für das Senden verwenden und den Raw-Socket zum Lesen. Diese sollte für Sie arbeiten in BSD und Solaris auch.

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

Andere Tipps

Die „richtige“ und Standardlösung ist wahrscheinlich cmsg(3) zu verwenden. Hier finden Sie eine vollständige Beschreibung finden in Stevens ‘ "Unix Netzwerkprogrammierung" Buch, ein must-read .

Google Code Suche hat mir diese Beispiel für die Verwendung

Mein Verständnis ist, dass zum einen BSD nicht IP_RECVTOS wie Funktionalität unterstützen und zum anderen BSD Raw Sockets nicht unterstützen den Empfang von UDP noch TCP-Pakete. Allerdings gibt es zwei weitere Möglichkeiten, dies zu tun, zum einen durch die / dev / BPF-Schnittstelle - entweder direkt oder über libpcap. Oder zweitens durch UMLEITEN Sockets, die zur Umleitung von bestimmtem Datenverkehr zulassen fließt Userland.

Hat jemand getestet tatsächlich den Code oben auf einer BSD-Box? (Es kann auf Solaris arbeiten ...)

Unter Linux wird dieser Ansatz funktioniert aber wie bereits erwähnt ist es auch möglich (und bequemes) setsockopt () mit IP_TOS an der Ausgangsbuchse zu verwenden, um den abgehenden TOS-Byte und setsockopt einzustellen () mit IP_RECVTOS auf der Eingangsbuchse und Verwendung recvmsg () den TOS-Byte abgerufen werden.

Unfortuneatly diese Art der Sache ändert sich in der Regel über verschiedene * ixs. Unter Solaris möchten Sie getsockopt mit IP_TOS verwenden; Ich weiß nicht, über BSD.

Siehe man 7 ip Details

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top