通过除有效负载之外的方法在Linux UDP套接字之间交换任意数据

时间:2016-09-02 14:38:32

标签: c linux sockets network-programming

我试图在两个Linux UDP套接字之间交换任意数据(几个字节,比如说12或16)而不将这些数据注入到消息的有效负载中。我希望数据与数据包的其余部分保持一致,但它应该与有效负载分开,因为接收应用程序应该能够在不知道额外数据的情况下读取有效负载。

到目前为止,我已经想到了但尚未尝试的方法

  1. 辅助数据
  2. IP选项字段
  3. 如果您已成功使用这些方法,请告诉我,或者更好地指出一些代码。

1 个答案:

答案 0 :(得分:1)

如评论中所述,您可以使用IP选项发送所需数据。由于IP选项(对于IPv4)的最大长度为40个字节,因此这足以容纳您的额外数据。

在发送数据包之前,请使用setsockopt拨打IP_OPTIONS选项名称,以及包含选项的缓冲区。

第一个字节包含选项类型,第二个字节包含选项的总长度(包括前两个字节)。

选项类型字节的格式如下:

  • 已复制(1位):如果需要将选项复制到碎片包的所有片段中,则设置为1.
  • 选项类别(2位):常规选项类别。 0表示“控制”选项,2表示“调试和测量”。保留1和3。
  • 选项编号(5位):指定选项。

选项编号30保留用于实验目的,因此这是您要使用的选项。

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

所有选项的总长度必须是4的倍数,因此在此示例中自定义选项的长度为14时,会添加两个NO-OP选项以将其填充。

在Linux上,您需要是root才能使用此选项。

读取数据包时,需要设置IP_RECVOPTS选项才能访问选项:

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

然后,您可以使用recvmsg代替recvfrom来获取该数据:

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]);
            }
            printf("\n");
        }
        cmhdr = CMSG_NXTHDR(&mhdr, cmhdr);
    }
}

如果找到选项,您将获得组合在一起的所有IP选项。因此,您需要进一步解析选项数据的内容,以查找特定于应用程序的数据。