gpt4 book ai didi

c - 我将代码从 FreeBSD 移植到 Linux,但它没有提取目标地址

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:07:56 25 4
gpt4 key购买 nike

此 C 代码从套接字中提取 FreeBSD 系统上的源和目标 IPv4 地址。我将它移植到 Linux,但它只能部分工作。它正确地打印了 pk 的源地址,但没有打印 pk 的目标地址(这将是我机器的 IP 地址)。我总是得到 0.0.0.0 的目标地址。

如何更改代码以使其也提取/打印目标地址?

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

最佳答案

在 Linux 中,套接字选项是 IP_RECVORIGDSTADDR . (您的代码也无法初始化 iov。)

这是一个在 Linux 中运行的简单测试示例(如果使用 2.6.29、3.x 或更高版本的内核)。

#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>


typedef struct {
struct sockaddr_in source;
struct sockaddr_in destination;
uint8_t *payload;
int payload_len;
} ipv4_datagram;

void process_ipv4_datagram(ipv4_datagram *const datagram)
{
char src_host[128], src_port[32];
char dst_host[128], dst_port[32];
int result, i;

src_host[0] = src_port[0] = '\0';
dst_host[0] = dst_port[0] = '\0';

result = getnameinfo((const struct sockaddr *)(&datagram->source),
sizeof (struct sockaddr_in),
src_host, sizeof src_host,
src_port, sizeof src_port,
NI_NUMERICHOST | NI_NUMERICSERV);
if (result) {
fprintf(stderr, "Warning: Cannot translate source address: %s.\n", gai_strerror(result));
fflush(stderr);
}

result = getnameinfo((const struct sockaddr *)(&datagram->destination),
sizeof (struct sockaddr_in),
dst_host, sizeof dst_host,
dst_port, sizeof dst_port,
NI_NUMERICHOST | NI_NUMERICSERV);
if (result) {
fprintf(stderr, "Warning: Cannot translate destination address: %s.\n", gai_strerror(result));
fflush(stderr);
}

printf("Received %d bytes,\n", datagram->payload_len);
printf(" From %s port %s\n", src_host, src_port);
printf(" To %s port %s", dst_host, dst_port);
for (i = 0; i < datagram->payload_len; i++)
if (i & 15)
printf(" %02x", datagram->payload[i]);
else
printf("\n\t%02x", datagram->payload[i]);
printf("\n");
fflush(stdout);
}

static volatile sig_atomic_t done = 0;

static void handle_done(int signum)
{
__sync_bool_compare_and_swap(&done, (sig_atomic_t)0, (sig_atomic_t)signum);
}

static int install_done(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}


int main(int argc, char *argv[])
{
int socketfd = -1;

/* Verify command line parameters, and print usage if necessary.
*/
if (argc < 2 || argc > 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s [ ADDRESS/HOST ] PORT\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "This listens on IPv4 UDP connections, and reports on them.\n");
fprintf(stderr, "Send INT (Ctrl+C), HUP, or TERM signal to exit.\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}

/* Install INT, TERM, and HUP signal handlers.
* They all set the 'done' flag if caught.
*/
if (install_done(SIGINT) ||
install_done(SIGTERM) ||
install_done(SIGHUP)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}

/* Open the listening socket. */
{
struct addrinfo *list = NULL, *curr, hints;
const char *node, *serv;
int result;

/* Empty or "-" or "*" address is the wildcard address. */
if (argc == 3) {
node = argv[1];
serv = argv[2];
if (node[0] == '\0' || !strcmp(node, "-") || !strcmp(node, "*"))
node = NULL;
} else {
node = NULL;
serv = argv[1];
}

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
result = getaddrinfo(node, serv, &hints, &list);
if (result) {
if (node)
fprintf(stderr, "%s %s: %s.\n", node, serv, gai_strerror(result));
else
fprintf(stderr, "%s: %s.\n", serv, gai_strerror(result));
return EXIT_FAILURE;
}

result = 0;
socketfd = -1;
for (curr = list; curr != NULL; curr = curr->ai_next) {
socketfd = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
if (socketfd == -1)
continue;

if (bind(socketfd, curr->ai_addr, curr->ai_addrlen) == 0)
break;

result = errno;
close(socketfd);
socketfd = -1;
}

freeaddrinfo(list);

if (socketfd == -1) {
if (result)
fprintf(stderr, "%s.\n", strerror(result));
else
fprintf(stderr, "Cannot bind to socket.\n");
return EXIT_FAILURE;
}
}

/* Enable the IP_RECVORIGDSTADDR socket option. */
{
int flag = 1;
if (setsockopt(socketfd, IPPROTO_IP, IP_RECVORIGDSTADDR, &flag, sizeof flag) == -1) {
fprintf(stderr, "IP_RECVORIGDSTADDR not supported: %s.\n", strerror(errno));
close(socketfd);
return EXIT_FAILURE;
}
}

/* Receive datagram messages, until signaled.
* Note that signal delivery causes recvmsg() to return with -1, errno == EINTR.
*/
while (!done) {
char data_buffer[1024];
char ancillary_buffer[1024];
ssize_t data_bytes;

ipv4_datagram dgram;
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;

iov.iov_base = data_buffer;
iov.iov_len = sizeof data_buffer;

msg.msg_name = &(dgram.source);
msg.msg_namelen = sizeof dgram.source;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ancillary_buffer;
msg.msg_controllen = sizeof ancillary_buffer;
msg.msg_flags = 0;

memset(&(dgram.source), 0, sizeof dgram.source);
memset(&(dgram.destination), 0, sizeof dgram.destination);

data_bytes = recvmsg(socketfd, &msg, 0);
if (data_bytes == (ssize_t)-1) {

/* Interrupted by a signal? */
if (errno == EINTR)
continue;

/* Other errors we can ignore? */
if (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == ECONNREFUSED)
continue;

fprintf(stderr, "Error receiving data: %s.\n", strerror(errno));
fflush(stderr);
break;
}

dgram.payload = (void *)data_buffer;
dgram.payload_len = data_bytes;

/* Find IP_ORIGDSTADDR ancillary message. */
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
if (cmsg->cmsg_level == IPPROTO_IP &&
cmsg->cmsg_type == IP_ORIGDSTADDR)
memmove(&dgram.destination, CMSG_DATA(cmsg), sizeof dgram.destination);

process_ipv4_datagram(&dgram);
}

close(socketfd);
return EXIT_SUCCESS;
}

这是一个编辑版本,用于说明所需的 ipv4_datagram 结构和 process_ipv4_datagram() 函数的用法。

使用例如编译它

gcc -Wall -Wextra -O2 example.c -o example

如果你运行例如

./example host port

您可以使用 Ctrl+C 来指示它干净地退出。使用例如netcat 使用例如测试连接(来自同一本地网络上的其他机器)

date | nc -q 1 -u host port

关于c - 我将代码从 FreeBSD 移植到 Linux,但它没有提取目标地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34766075/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com