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 */