2010-05-21 3 views
7

Peut-on utiliser recvmsg() pour obtenir le champ IP_TOS de chaque paquet entrant ou seulement afficher la valeur IP_TOS qui est définie pour le socket particulier. Sinon, quelqu'un connaît-il une solution pour obtenir les valeurs IP_TOS de chaque paquet entrant? J'utilise une application UDP et, par conséquent, je ne vois pas le champ IP_TOS sur la couche application, comme c'est le cas avec TCP. Merci.Linux: Recvmsg peut-il être utilisé pour recevoir le IP_TOS de chaque paquet entrant

Ajout du code que je l'ai écrit à ce jour, Incase il aide:

struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 

struct cmsghdr cmsgcmsg[1]; 
msg.msg_control = cmsgcmsg; 
msg.msg_controllen = sizeof(struct cmsghdr); 


nRet = recvmsg(udpSocket, &msg, 0); 

if (nRet > 0) { 
    struct cmsghdr *cmsg; 
    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) { 

    if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_TOS) && 
    (cmsg->cmsg_len)){ 
       int tos = *(uint8_t *)CMSG_DATA(cmsg); 
       int isecn = ((tos & INET_ECN_MASK) == INET_ECN_CE); 
      printf("the tos = %i , is ecn = %d \n", tos, isecn); 

    } 
    } 

Répondre

0

Vous pouvez accéder normalement au champ ToS par getsockopt()/setsockopt(), mais il semble être very implementation dependent. Vous pouvez regarder autour do_ip_setsockopt() dans les sources du noyau, dans l'arborescence du noyau Linux à linux/net/ipv4/ip_sockglue.c

Votre meilleur ami pour naviguer dans la source est there.

+1

Merci. Autant que je sache, il semble que setsockopt()/getsockopt() soit utilisé pour définir et obtenir les options qui seraient définies sur les paquets sortants, alors que setsockopt (IPPROTO_IP) + recvmesg() pourrait être utilisé pour lire les IP_TOS et autres IP_OPTIONS des paquets entrants. Le code semble me manquer cependant, et tout ce que je reçois est des valeurs de poubelle. – Mayutan

8

J'ai finalement réussi à résoudre le problème et j'ajoute le code ici pour que d'autres puissent l'utiliser. J'espère que cela aide les autres. Celui-ci est pour IP_TTL:

Définissez le UDPSocket pour recevoir des valeurs IP_TTL:

int ttl = 60; 
if(setsockopt(udpSocket, IPPROTO_IP, IP_RECVTTL, &ttl,sizeof(ttl))<0) 
{ 
    printf("cannot set recvttl\n"); 
} 
else 
{ 
    printf("socket set to recvttl\n"); 
} 

et récupérer les valeurs de IP_TTL de chaque paquet de la manière suivante (Le programme suivant peut récupérer le message de données via IOV [0 ], extrait de code donné ci-dessous):

struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 

int *ttlptr=NULL; 
int received_ttl = 0; 

int cmsg_size = sizeof(struct cmsghdr)+sizeof(received_ttl); // NOTE: Size of header + size of data 
char buf[CMSG_SPACE(sizeof(received_ttl))]; 
msg.msg_control = buf; // Assign buffer space for control header + header data/value 
msg.msg_controllen = sizeof(buf); //just initializing it 

nRet = recvmsg(udpSocket, &msg, 0); 



if (nRet > 0) { 
    struct cmsghdr *cmsg; 
    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) { 

      if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_TTL) && 
      (cmsg->cmsg_len)){ 
       ttlptr = (int *) CMSG_DATA(cmsg); 
       received_ttl = *ttlptr; 
       printf("received_ttl = %i and %d \n", ttlptr, received_ttl); 
       break; 
      } 
    } 
} 

le message de données peuvent être envoyées et obtenu de la manière suivante:

Sender Side:

struct DATA_to_SEND pkt; 
struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 
nRet = sendmsg(udpSocket, &msg,0); 

récepteur latéral (prise en charge Data_to_Send a un paramètre appelé "seq"):

struct DATA_to_SEND pkt; 
seqNum = ((struct DATA_to_SEND *) iov[0].iov_base)->seq; 

Ce qui suit est pour IP_TOS. Réglez la prise pour recevoir IP_TOS:

unsigned char set = 0x03; 
if(setsockopt(udpSocket, IPPROTO_IP, IP_RECVTOS, &set,sizeof(set))<0) 
{ 
    printf("cannot set recvtos\n"); 
} 
else 
{ 
     printf("socket set to recvtos\n"); 

et récupérer la valeur IP_TOS de chaque tête de paquet par:

struct PC_Pkt pkt; 
int *ecnptr; 
unsigned char received_ecn; 

struct msghdr msg; 
struct iovec iov[1]; 
memset(&msg, '\0', sizeof(msg)); 
msg.msg_iov = iov; 
msg.msg_iovlen = 1; 
iov[0].iov_base = (char *) &pkt; 
iov[0].iov_len = sizeof(pkt); 

int cmsg_size = sizeof(struct cmsghdr)+sizeof(received_ecn); 
char buf[CMSG_SPACE(sizeof(received_ecn))]; 
msg.msg_control = buf; 
msg.msg_controllen = sizeof(buf); 

nRet = recvmsg(udpSocket, &msg, 0); 

if (nRet > 0) { 
struct cmsghdr *cmsg; 
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 
cmsg = CMSG_NXTHDR(&msg,cmsg)) { 
     if ((cmsg->cmsg_level == IPPROTO_IP) && 
     (cmsg->cmsg_type == IP_TOS) && (cmsg->cmsg_len)){ 
       ecnptr = (int *) CMSG_DATA(cmsg); 
     received_ecn = *ecnptr; 
     int isecn = ((received_ecn & INET_ECN_MASK) == INET_ECN_CE); 

       printf("received_ecn = %i and %d, is ECN CE marked = %d \n", ecnptr, received_ecn, isecn); 

       break; 
    } 
    } 
} 
+1

Double-up pour partager également le code de la solution. –

+0

quel est ce nombre magique de ttl = 60? –

1

J'ai créé exemple simple d'utilisation et setsockopt() pour envoyer des paquets ECN capables et obtenir bits ECN à partir des paquets reçus en utilisant recvmsg() ainsi que getsockopt(). Vous pouvez le trouver à l'adresse:

https://gist.github.com/jirihnidek/95c369996a81be1b854e

L'utilisation getsockopt() ne fonctionnera probablement pas à d'autres plates-formes alors Linux, mais vous pouvez l'utiliser avec recv() et recvfrom() fonctions.

BTW: INET_ECN_MASK, INET_ECN_CE, etc. ne sont pas définis dans in.h.Ainsi, vous devrez inclure les en-têtes du noyau Linux (dépassement IMHO) ou vous pouvez (re) définir vos propres constantes:

#define INET_ECN_NOT_ECT 0x00 /* ECN was not enabled */ 
#define INET_ECN_ECT_1  0x01 /* ECN capable packet */ 
#define INET_ECN_ECT_0  0x02 /* ECN capable packet */ 
#define INET_ECN_CE   0x03 /* ECN congestion */ 
#define INET_ECN_MASK  0x03 /* Mask of ECN bits */ 
+0

Holy crap, un exemple décent d'utilisation de 'recvmsg()'. Merci beaucoup! –