Linux: can Recvmsg be used to receive IP_TOS of each incoming packet

Is it possible to use recvmsg () to get the IP_TOS field for each incoming packet, or just specify the IP_TOS value set for a particular socket. If not, does anyone know of a solution to get IP_TOS values ​​for all incoming packets. I am using a UDP application and therefore cannot view the IP_TOS field at the application level, as is the case with TCP. Thank you

Adding the code I wrote so far if it helps:

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); } } 
+7
c linux-kernel
source share
3 answers

I finally managed to solve the problem, and I am adding code here for others to use. Hope this helps others. This is for IP_TTL:

Set UDPSocket to get IP_TTL values:

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

and extracting the IP_TTL values ​​from each packet as follows (The following program can receive a data message through IOV [0], code snippet below):

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

A data message can be sent and received as follows:

Sender's 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); 

Receiver side (assumption DATA_To_SEND has a parameter named "seq"):

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

Below for IP_TOS. Set the socket to receive 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"); 

and get the IP_TOS value from each packet header:

  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; } } } 
+8
source share

I created a simple usage example and setsockopt() to send ECN-enabled packets and get ECN bits from received packets using recvmsg() , as well as getsockopt() . You can find it at:

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

Using getsockopt() probably won't work on other platforms and then Linux, but you can use it with the recv() and recvfrom() functions.

BTW: INET_ECN_MASK , INET_ECN_CE , etc. not defined in in.h Thus, you will need to include the Linux kernel headers (IMHO overhoot) or you can (re) define your own constants:

 #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 */ 
+1
source share

Usually you access the ToS field through getockopt () / setsockopt (), but it seems to be very implementation dependent . You can look around do_ip_setsockopt () in the kernel sources in the Linux kernel tree in linux / net / ipv4 / ip_sockglue.c

Your best friend to navigate the source there .

0
source share

All Articles