套接字文件描述符会自动更改

3

我尝试使用原始套接字编程来捕获所有到达我的NIC的UDP数据包。但是,我遇到了一个奇怪的问题。当我的程序在运行时,我的套接字描述符会自动更改。以下是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>

int main () {

int sockfd = socket (PF_INET, SOCK_RAW, IPPROTO_UDP);
if (sockfd < 0) {
    perror ("socket failed");
    return -1;
}

char *buf = malloc (8192);
memset (buf, 0, 8192);
if (!buf) {
    perror ("calloc failed\n");
    return -1;
}

int ret_recv;
i:
while ((ret_recv = recv (sockfd, buf, 8192, 0)) > -1) {
    printf ("%d\n", ret_recv);
    struct iphdr *iph = (struct iphdr *) buf;
    //struct udphdr *udph = (struct udphdr *) (buf + sizeof (struct iphdr));
    struct tcphdr *tcph = (struct tcphdr *) (buf + sizeof (struct iphdr));
    char ip[4];
    printf ("source ip: %s\n", inet_ntop (AF_INET, &iph->saddr, ip, sizeof (struct sockaddr_in)));
    printf ("dest ip: %s\n", inet_ntop (AF_INET, &iph->daddr, ip, sizeof (struct sockaddr_in)));
    //printf ("port: %d\n", ntohs (udph->source));
    printf ("port: %d\n", ntohs (tcph->source));
}
perror ("recv failed");
//goto i;
return 0;
}

在我的输出结果中,没有无限循环打印数据包信息,只有一个数据包信息被打印。因此我使用gdb进行了检查。我使用了display sockfd指令。在socket调用后,sockfd的值为7。然后在while循环中,在执行dest ip的printf之后,sockfd的值更改为808988216。因此,recv函数失败并报错“坏的文件描述符”。我找不到实际出了什么问题。感谢您的帮助。 :-)

1
你用valgrind运行了你的程序吗?我猜测你在while {}内部破坏了堆栈。顺便说一下,将char ip [4]更改为inet_ntop到ip [16]或更好的ip [INET_ADDRSTRLEN]。 - strkol
1
内存损坏大放异彩。检查您的指针算术运算。 - user703016
发布的代码是正确的。我怀疑这不是真正的代码(你可能会省略一些内容,认为“这不可能是全部代码”)。 - cnicutar
1
为什么你在使用malloc()之后才检查其结果?当你调用malloc()而不是calloc()时,为什么要打印“calloc失败”?当调用calloc()可以同时完成两者并使您的调试输出正确时,为什么要调用malloc()memset()?为什么要使用struct tcphdr *来查看UDP数据包? - user207421
@EJP:最初我使用了calloc。后来我改用了malloc和memset。但是忘记编辑打印输出;-)。我还使用了tcphdr结构体代替了udphdr结构体。实际上,我只访问了源端口。在udphdr和tcphdr中,第一个字段是相同的,都是指源端口地址。因此,在此程序中不会有任何区别。我只是在学习过程中。这是我的一个试验性程序,所以请不要期望标准化。 :-) - theB
1
我本来就能猜到这一切。实际上,我已经猜到了。提出这些问题的原因是为了改进你的代码,并让你思考它。 - user207421
1个回答

3

以下是缓冲区溢出:

char ip[4];
    printf ("source ip: %s\n", inet_ntop (AF_INET, &iph->saddr, ip, sizeof (struct sockaddr_in)));

缓冲区不足以容纳IP地址的字符串形式。此外,第四个参数在向inet_ntop()提供有关可用空间的信息时存在误导,它应该是:
char ip[INET_ADDRSTRLEN];
printf ("source ip: %s\n", inet_ntop (AF_INET, &iph->saddr, ip, sizeof ip));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接