设置UDP套接字的源IP [英] Setting the source IP for a UDP socket

查看:1299
本文介绍了设置UDP套接字的源IP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个绑定到INADDR_ANY的UDP套接字,用于监听我的服务器所有IP上的数据包。我通过同一个套接字发送回复。

I have a UDP socket that is bound to INADDR_ANY to listen to packets on all the IPs my server has. I'm sending out replies through the same socket.

现在服务器自动选择在发送数据包时将哪个IP用作源IP,但我想能够自己设置传出源IP。

Right now the server chooses automatically which IP is used as the source IP when packets are sent out, but I would like to be able to set the outgoing source IP myself.

有没有办法做到这一点而无需为每个IP创建一个单独的套接字?

Is there any way to do that without having to create a separate socket for each IP ?

推荐答案

Nikolai,为每个地址使用单独的套接字和bind(2)或弄乱路由表通常不是一个可行的选择,例如动态地址。单个 IP_ADDRANY - 绑定的UDP服务器应该能够响应收到数据包的相同动态分配的IP地址。

Nikolai, using a separate socket and bind(2) for each address or messing with routing tables is often not a feasible option e.g. with dynamic addresses. A single IP_ADDRANY-bound UDP server should be able to appear to respond on the same dynamically-assigned IP address a packet is received on.

幸运的是,还有另一种方式。根据系统的支持,您可以使用 IP_PKTINFO 套接字选项来设置或接收有关消息的辅助数据。辅助数据(通过 cmsg(3))可通过 comp.os.linux.development.system 有一个特定于 IP_PKTINFO的完整代码示例

Luckily, there is another way. Depending on your system's support you can make use of the IP_PKTINFO socket options to set or receive ancillary data about a message. Ancillary data (via cmsg(3)) is covered in many places online though comp.os.linux.development.system had a full code sample specific to IP_PKTINFO.

链接中的代码使用 IP_PKTINFO (或 IP_RECVDSTADDR 取决于平台)从辅助 cmsg(3)数据中获取UDP消息的目标地址。这里解释:

The code in the link uses IP_PKTINFO (or IP_RECVDSTADDR depending on the platform) to get the destination address of a UDP message from the ancillary cmsg(3) data. Paraphrased here:

struct msghdr msg;
struct cmsghdr *cmsg;
struct in_addr addr;
// after recvmsg(sd, &msg, flags);
for(cmsg = CMSG_FIRSTHDR(&msg);
    cmsg != NULL;
    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
  if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
    addr = ((struct in_pktinfo*)CMSG_DATA(cmsg))->ipi_addr;
    printf("message received on address %s\n", inet_ntoa(addr));
  }
}

Gene,您的问题询问如何设置源地址在传出的数据包上使用 IP_PKTINFO ,可以设置结构的 ipi_spec_dst 字段in_pktinfo sendmsg(2)的辅助数据中的$ c>。有关如何创建和操作的指南,请参阅上面引用的帖子, cmsg(3) sendmsg(2) struct msghdr 中的辅助数据。一个例子(这里不保证)可能是:

Gene, your question asked how to set the source address on outgoing packets. With IP_PKTINFO it is possible to set the ipi_spec_dst field of the struct in_pktinfo in the ancillary data passed to sendmsg(2). See the post referenced above, cmsg(3), and sendmsg(2) for guidelines on how to create and manipulate the ancillary data in a struct msghdr. An example (no guarantee here) might be:

struct msghdr msg;
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
// after initializing msghdr & control data to CMSG_SPACE(sizeof(struct in_pktinfo))
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
pktinfo->ipi_ifindex = src_interface_index;
pktinfo->ipi_spec_dst = src_addr;
// bytes_sent = sendmsg(sd, &msg, flags);

注意这与IPv6不同:使用 struct in6_pktinfo :: ipi6_addr

Note this is different in IPv6: use struct in6_pktinfo::ipi6_addr in both the recvmsg and sendmsg cases.

另请注意,Windows不支持in_pktinfo结构中与ipi_spec_dst等效的内容,因此您无法使用此方法在传出的winsock2数据包上设置源地址。

Note also that Windows does not support an equivalent to ipi_spec_dst in the in_pktinfo struct, so you cannot use this method to set the source address on an outgoing winsock2 packet.

(引用的手册页 - 约1个超链接限制)

(man pages referenced - getting around 1 hyperlink limit)

http:// linux.die.net/man/2/sendmsg
http:// linux.die.net/man/3/cmsg

这篇关于设置UDP套接字的源IP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆