versiones ultima torvalds nucleo linus c linux-kernel

c - torvalds - ultima version de linux



Linux: se puede usar Recvmsg para recibir los IP_TOS de cada paquete entrante (3)

Normalmente accede al campo ToS a través de getsockopt () / setsockopt (), pero parece ser muy dependiente de la implementación . Es posible que desee buscar do_ip_setsockopt () en las fuentes del kernel, en el árbol de kernel de Linux en linux / net / ipv4 / ip_sockglue.c

Tu mejor amigo para navegar por la fuente está ahí .

¿Se puede usar recvmsg () para obtener el campo IP_TOS de cada paquete entrante o simplemente muestra el valor de IP_TOS que se establece para el socket en particular? Si no, ¿alguien sabe de una solución para obtener los valores de IP_TOS de cada paquete entrante? Estoy usando una aplicación UDP y, por lo tanto, no puedo ver el campo IP_TOS en la capa de la aplicación, como es el caso con TCP. Gracias.

Agregando el código que he escrito hasta ahora, en caso de que ayude:

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


Finalmente logré resolver el problema y estoy agregando el código aquí para que otros lo usen. Espero que esto sea de ayuda para otros. Este es para IP_TTL:

Establezca el UDPSocket para recibir los valores de 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"); }

Y recupere los valores de IP_TTL de cada paquete de la siguiente manera (El siguiente programa puede recuperar el mensaje de datos a través de iov [0], fragmento de código dado a continuación):

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

El mensaje de datos se puede enviar y obtener de la siguiente manera:

Lado del remitente:

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

Lado receptor (suposición DATA_To_SEND tiene un parámetro llamado "seq"):

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

Lo siguiente es para IP_TOS. Configure el socket para recibir 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");

y recupere el valor IP_TOS de cada encabezado de paquete de la siguiente manera:

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


setsockopt() un ejemplo simple de uso y setsockopt() para enviar paquetes con capacidad ECN y obtener bits ECN de paquetes recibidos utilizando también recvmsg() y getsockopt() . Puedes encontrarlo en:

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

El uso de getsockopt() probablemente no funcione en otras plataformas, entonces Linux, pero puede usarlo con las funciones recv() y recvfrom() .

Por cierto: INET_ECN_MASK , INET_ECN_CE , etc. no están definidos en in.h Por lo tanto, deberá incluir los encabezados del kernel de Linux (sobreexceso en mi humilde opinión) o puede (re) definir sus propias 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 */