为什么这个使用 BPF 和 RAW SOCKET 的程序会挂起?
Why this program which use BPF and RAW SOCKET just hangs?
目标: 使用 BPF 编写一个简单的数据包过滤器。数据包过滤器应该允许您选择接口。
问题: 如果我取消对代码中倒数第三条指令的注释(调用 recvfrom
的地方,执行就会挂起,我不能看不到任何输出(我应该能够在标准输出中看到的 "buffer zeroed")。
问题: 1) 我该如何解决? 2) 为什么程序在执行期间挂起并且不显示第一个 printf
输出? 3) 我怎样才能从任何接口接收?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <linux/filter.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/if.h>
#define DEFAULT_IF "wlan0"
/* definisco programma bpf */
/* tcpdump -i lo icmp -dd */
struct sock_filter bpfcode[] = {
{ 0x28, 0, 0, 0x0000000c }, /* (000) ldh [12] */
{ 0x15, 0, 3, 0x00000800 }, /* (001) jeq #0x800 jt 2 jf 5 */
{ 0x30, 0, 0, 0x00000017 }, /* (002) ldb [23] */
{ 0x15, 0, 1, 0x00000001 }, /* (003) jeq #0x1 jt 4 jf 5 */
{ 0x6, 0, 0, 0x00040000 }, /* (004) ret #262144 */
{ 0x6, 0, 0, 0x00000000 }, /* (005) ret #0 */
};
int main(int argc, char *argv[])
{
struct sock_fprog bpf = {
sizeof(bpfcode) / sizeof(struct sock_filter),
bpfcode
};
socklen_t saddr_len = sizeof(struct sockaddr_ll);
struct sockaddr_ll addr;
unsigned char *buffer;
char ifname[IFNAMSIZ];
int ret, sfd, rval;
buffer = calloc(1, 65536);
if (!buffer) {
perror("calloc");
return -1;
}
// prendi nome interfaccia
if (argc > 1)
strcpy(ifname, argv[1]);
else
strcpy(ifname, DEFAULT_IF);
// creazione raw socket
sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sfd < 0) {
perror("socket");
return -1;
}
// attacco filtro alla socket
ret = setsockopt(sfd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
if (ret < 0) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
// quando si usa packet socket bisogna settare sll_protocol e
// sll_ifindex se si vuol fare il bind ad una specifica interfaccia
memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ALL);
addr.sll_ifindex = if_nametoindex(ifname);
printf("index %d", addr.sll_ifindex);
// viene assegnato un indirizzo al socket
if (bind(sfd, (struct sockaddr *) &addr,
sizeof(struct sockaddr_ll)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// ricevo traffico
if (!buffer[0])
printf("buffer zeroed");
// rval = recvfrom(sfd, buffer, 65536, 0, (struct sockaddr *)&addr,
// &saddr_len);
if (buffer[0])
printf("something was written in the buffer");
return 0;
}
How do I fix it?
您想具体解决什么问题?见下文。
Why the programs hangs during the execution and doesn't show the first printf
output?
两者 printf()
都有效,除非您没有在消息末尾打印任何换行符 ('\n'
),因此系统不会将您的消息刷新到控制台。只需以换行符结束您的消息,您就会按预期看到您的消息。
至于挂起,这只是因为recvfrom()
等待数据包到达。好吧,在您的情况下,不仅仅是 any 数据包,因为您正在对 ICMP 进行过滤。从外部 Ping 您的接口,程序应该会恢复。或者,为了调试你的 C 程序,只需在你的 BPF 程序中保留 { 0x6, 0, 0, 0x00040000 }
(return non-zero),任何接收到的数据包都应该这样做。
How can I receive from ANY interface?
How to bind a socket to multiple interfaces
目标: 使用 BPF 编写一个简单的数据包过滤器。数据包过滤器应该允许您选择接口。
问题: 如果我取消对代码中倒数第三条指令的注释(调用 recvfrom
的地方,执行就会挂起,我不能看不到任何输出(我应该能够在标准输出中看到的 "buffer zeroed")。
问题: 1) 我该如何解决? 2) 为什么程序在执行期间挂起并且不显示第一个 printf
输出? 3) 我怎样才能从任何接口接收?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <linux/filter.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/if.h>
#define DEFAULT_IF "wlan0"
/* definisco programma bpf */
/* tcpdump -i lo icmp -dd */
struct sock_filter bpfcode[] = {
{ 0x28, 0, 0, 0x0000000c }, /* (000) ldh [12] */
{ 0x15, 0, 3, 0x00000800 }, /* (001) jeq #0x800 jt 2 jf 5 */
{ 0x30, 0, 0, 0x00000017 }, /* (002) ldb [23] */
{ 0x15, 0, 1, 0x00000001 }, /* (003) jeq #0x1 jt 4 jf 5 */
{ 0x6, 0, 0, 0x00040000 }, /* (004) ret #262144 */
{ 0x6, 0, 0, 0x00000000 }, /* (005) ret #0 */
};
int main(int argc, char *argv[])
{
struct sock_fprog bpf = {
sizeof(bpfcode) / sizeof(struct sock_filter),
bpfcode
};
socklen_t saddr_len = sizeof(struct sockaddr_ll);
struct sockaddr_ll addr;
unsigned char *buffer;
char ifname[IFNAMSIZ];
int ret, sfd, rval;
buffer = calloc(1, 65536);
if (!buffer) {
perror("calloc");
return -1;
}
// prendi nome interfaccia
if (argc > 1)
strcpy(ifname, argv[1]);
else
strcpy(ifname, DEFAULT_IF);
// creazione raw socket
sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sfd < 0) {
perror("socket");
return -1;
}
// attacco filtro alla socket
ret = setsockopt(sfd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
if (ret < 0) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
// quando si usa packet socket bisogna settare sll_protocol e
// sll_ifindex se si vuol fare il bind ad una specifica interfaccia
memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ALL);
addr.sll_ifindex = if_nametoindex(ifname);
printf("index %d", addr.sll_ifindex);
// viene assegnato un indirizzo al socket
if (bind(sfd, (struct sockaddr *) &addr,
sizeof(struct sockaddr_ll)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// ricevo traffico
if (!buffer[0])
printf("buffer zeroed");
// rval = recvfrom(sfd, buffer, 65536, 0, (struct sockaddr *)&addr,
// &saddr_len);
if (buffer[0])
printf("something was written in the buffer");
return 0;
}
How do I fix it?
您想具体解决什么问题?见下文。
Why the programs hangs during the execution and doesn't show the first
printf
output?两者
printf()
都有效,除非您没有在消息末尾打印任何换行符 ('\n'
),因此系统不会将您的消息刷新到控制台。只需以换行符结束您的消息,您就会按预期看到您的消息。至于挂起,这只是因为
recvfrom()
等待数据包到达。好吧,在您的情况下,不仅仅是 any 数据包,因为您正在对 ICMP 进行过滤。从外部 Ping 您的接口,程序应该会恢复。或者,为了调试你的 C 程序,只需在你的 BPF 程序中保留{ 0x6, 0, 0, 0x00040000 }
(return non-zero),任何接收到的数据包都应该这样做。How can I receive from ANY interface?
How to bind a socket to multiple interfaces