此C代码从套接字中提取FreeBSD系统上的源IPv4地址和目标IPv4地址。我将它移植到Linux上,它只能部分工作。它正确打印pk的源地址,但不是pk的目标地址(这将是我的机器的IP地址)。我总是得到目标地址0.0.0.0
。我将代码从FreeBSD移植到Linux,但不提取目标地址
如何更改代码以使其提取/打印目标地址?
static void* start_controlpackets_demuxer_ipv4(void* arg) {
int r;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
struct addrinfo* sorter_addr;
r = getaddrinfo(NULL, LISP_CONTROL_PORT, &hints, &sorter_addr);
if (r != 0) {
fatalr("Unable to get westbound IPv4 listener address", r);
}
struct addrinfo* curr_addr;
int s;
for (curr_addr = sorter_addr; curr_addr != NULL; curr_addr = curr_addr->ai_next) {
s = socket(curr_addr->ai_family, curr_addr->ai_socktype, curr_addr->ai_protocol);
if (s == -1) {
continue;
}
r = bind(s, curr_addr->ai_addr, curr_addr->ai_addrlen);
if (r == -1) {
continue;
}
freeaddrinfo(sorter_addr);
break;
}
if (curr_addr == NULL) {
fatal("Unable to bind westbound IPv4 listener");
}
ipv4_controlpackets_socket = s;
debug_printf("IPv4 westbound server is listening");
/*
* The datagram is kept in the stack space. Should the processing be offloaded to a pool of worker threads,
* it will be necessary to move it to the heap.
*/
uint8_t buf[IP_MAXLEN];
char control_buf[SOCK_MSG_CONTROL_LEN];
int opt = 1;
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt));
while (1) {
ipv4_datagram datagram;
datagram.payload = buf;
struct msghdr raw_msg;
struct iovec iov;
raw_msg.msg_name = &(datagram.source);
raw_msg.msg_namelen = sizeof(datagram.source);
raw_msg.msg_iov = &iov;
raw_msg.msg_iovlen = 1;
raw_msg.msg_iov->iov_base = datagram.payload;
raw_msg.msg_iov->iov_len = IP_MAXLEN;
raw_msg.msg_control = (caddr_t) &control_buf;
raw_msg.msg_controllen = SOCK_MSG_CONTROL_LEN;
raw_msg.msg_flags = 0;
datagram.payload_len = recvmsg(s, &raw_msg, 0);
if (datagram.payload_len < 0) {
fatal("Error reading from westbound IPv4 socket");
}
for (struct cmsghdr *c = CMSG_FIRSTHDR(&raw_msg); c != NULL; c = CMSG_NXTHDR(&raw_msg, c)) {
if (c->cmsg_level != IPPROTO_IP || c->cmsg_type != IP_RECVDSTADDR) {
continue;
}
struct in_addr* tmp_destination = (struct in_addr*) CMSG_DATA(c);
memset(&(datagram.destination), 0, sizeof(datagram.destination));
#ifndef LINUX_OS
datagram.destination.sin_len = sizeof(datagram.destination);
#endif
datagram.destination.sin_family = AF_INET;
datagram.destination.sin_addr = *tmp_destination;
}
char src[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(datagram.source.sin_addr), src, INET_ADDRSTRLEN);
char dst[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(datagram.destination.sin_addr), dst, INET_ADDRSTRLEN);
debug_printf("Processing UDPv4 datagram from %s to %s", src, dst);
process_ipv4_datagram(&datagram);
}
pthread_exit(0);
}
你从哪里得到'IP_RECVDSTADDR'? AFAIK,它是一个BSD /达尔文功能。 ['IP_RECVORIGDSTADDR'](http://man7.org/linux/man-pages/man7/ip.7.html)是Linux中使用的。如果你能验证这些代码在FreeBSD中也能工作,我可以掀起一个Linux例子。 –
您的权利,IP_RECVDSTADDR适用于BSD。我发布的代码的确在FreeBSD上工作,但我需要在Linux上工作。所以改为IP_RECVORIGDSTADDR,因为你建议,但它仍然无法正常工作。 – Pheonix7
在Linux中,套接字选项是'IP_RECVORIGDSTADDR',辅助消息类型是'IP_ORIGDSTADDR',而不是'IP_RECVDSTADDR'。你也应该使用'CMSG _()'宏。在我的答案中看到我的(轻度测试工作)示例代码。 –