Kariem Kariem - 11 months ago 37
C Question

Exchanging arbitrary data between Linux UDP sockets through methods other than payload

I'm trying to exchange arbitrary data (few bytes, say 12 or 16) between two Linux UDP sockets without injecting this data into the payload of the message. I want the data to go on the wire with the rest of the packet, but it should be separate from the payload in as much as the receiving application should be able to read the payload without knowing about the extra data.

Methods I have thought of so far but haven't tried yet

  1. Ancillary Data

  2. IP options field

If you've used those methods successfully, please let me know or even better point me at some code.

Answer Source

As mentioned in the comments, you can send the data you want using IP options. Since the maximum length of IP options (for IPv4) is 40 bytes, this is enough space to put your extra data.

Before sending a packet, make a call to setsockopt with IP_OPTIONS for the option name, along with a buffer containing the options.

The first byte contains the option type and the second contains the total length of the option (including the first two bytes).

The format of the option type byte is as follows:

  • Copied (1 bit): Set to 1 if the options need to be copied into all fragments of a fragmented packet.
  • Option Class (2 bits): A general options category. 0 is for "control" options, and 2 is for "debugging and measurement". 1, and 3 are reserved.
  • Option Number (5 bits): Specifies an option.

Option number 30 is reserved for experimental purposes, so that's the one you'll want to use.

unsigned char options[] = {
    30,    // option type 30 (experimental)
    14,    // option length
    1,2,3,4,5,6,7,8,9,10,11,12,   // option data
    1,     // option type 1 (no-op, no length field)
    1      // option type 1 (no-op, no length field)
if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, (char *)&options, sizeof(options))== -1) {
    perror("Error setting options");

The total length of all options must be a multiple of 4, so in this example where the custom option has length 14, two NO-OP options are added to pad it out.

On Linux, you need to be root to use this option.

When reading packets, you need to set the IP_RECVOPTS option to have access to the options:

int option = 1;
if (setsockopt(sock, IPPROTO_IP, IP_RECVOPTS, (char *)&option, sizeof(option)) == -1) {
    perror("Error setting IP_RECVOPTS");

Then you would use recvmsg instead of recvfrom to get to that data:

struct sockaddr_in sin_recv;
char mes[1500];
struct msghdr mhdr;
struct iovec iov;
struct cmsghdr *cmhdr;
char control[1000];
int len;
unsigned char *options;
unsigned int i;

mhdr.msg_name = &sin_recv;
mhdr.msg_namelen = sizeof(sin_recv);
mhdr.msg_iov = &iov;
mhdr.msg_iovlen = 1;
mhdr.msg_control = &control;
mhdr.msg_controllen = sizeof(control);
iov.iov_base = mes;
iov.iov_len = sizeof(mes);
if ((len = recvmsg(sock, &mhdr, 0)) == -1) {
    perror("Error receiving");
} else {
    cmhdr = CMSG_FIRSTHDR(&mhdr);
    while (cmhdr) {
        if (cmhdr->cmsg_level == IPPROTO_IP &&
                cmhdr->cmsg_type == IP_RECVOPTS) {
            options = CMSG_DATA(cmhdr);
            printf("options: ");
            for (i=0;i<cmhdr->cmsg_len-sizeof(struct cmsghdr);i++) {
                printf("%02x ", options[i]);
        cmhdr = CMSG_NXTHDR(&mhdr, cmhdr);

If you do find options, you'll get all IP options grouped together. So you would need to further parse the contents of the option data to find your app specific data.