为什么使用BPF和RAW SOCKET的该程序只是挂起? [英] Why this program which use BPF and RAW SOCKET just hangs?

查看:204
本文介绍了为什么使用BPF和RAW SOCKET的该程序只是挂起?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标:使用BPF编写一个简单的数据包过滤器。数据包过滤器应允许您选择接口。

GOAL: write a simple packet filter using BPF. The packet filter should allow you to choose the interface.

问题::如果我在代码中取消倒数第三条指令的注释(有调用 recvfrom 时,执行只是挂起,我看不到任何输出(也没有应该在stdout中看到的缓冲区归零)。

PROBLEM: if I uncomment the third to last instruction in the code (where there is a call to recvfrom, the execution just hangs and I can't see no output (neither "buffer zeroed" which I should be able to see in the stdout).

问题:1)我该如何解决? 2)为什么程序在执行过程中挂起而没有显示第一个 printf 输出? 3)如何从ANY界面接收消息?

QUESTIONS: 1) how can I fix it? 2) why the programs hangs during the execution and doesn't show the first printf output? 3) how can I receive from ANY interface?

#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?

您要确切地解决什么?见下文。

What do you want to fix exactly? See below.


为什么程序在执行过程中挂起并且没有显示第一个 printf 输出?

两个 printf()都可以,除非您没有在消息末尾打印任何换行符('\n'),所以系统不会将消息刷新到控制台。只需以换行符结束您的消息,您就会看到预期的消息。

Both printf() do work, except you're not printing any line breaks ('\n') at the end of your messages, so the system does not flush your message to the console. Just end your messages with line breaks and you will see your messages as expected.

对于挂起来说,这仅仅是因为 recvfrom()等到数据包到达。嗯,由于您要在ICMP上进行过滤,因此您的情况不仅限于 any 数据包。从外部Ping您的界面,程序应继续运行。另外,要调试C程序,只需在BPF程序中保留 {0x6,0,0,0x00040000} (返回非零),任何接收到的数据包都应该这样做。

As for the hang, this is simply because recvfrom() waits until a packet arrives. Well, not just any packet in your case, since you are filtering on ICMP. Ping your interface from the outside, and the program should resume. Alternatively, for debugging your C program, just keep { 0x6, 0, 0, 0x00040000 } (return non-zero) in your BPF program, and any received packet should do.


如何从任何界面接收?

How can I receive from ANY interface?

如何将套接字绑定到多个接口

这篇关于为什么使用BPF和RAW SOCKET的该程序只是挂起?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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