【问题标题】:C raw socket receive or sniff incoming packets onlyC 原始套接字仅接收或嗅探传入的数据包
【发布时间】:2014-07-25 21:13:35
【问题描述】:

我只需要在特定接口(同时具有 eth0 和 eth1,仅 eth1)上为传入数据包设置原始套接字。换句话说,我只需要一个特定接口上的传入个数据包。

与其他嗅探器比较

在 ifconfig 中,每个接口都有一个 RX Packets 字段。虽然这保持不变,但此嗅探器仍将注册为接收数据包。也许 RX Packets 仅限于某些协议?我还将它与 python 嗅探器进行了比较——存在同样的问题。 python 嗅探器不会像这个 c 嗅探器那样返回尽可能多的数据包。我无法将它与wireshark 进行比较,因为我无法在系统上安装它,它是嵌入式的。

绑定

我想也许我错误地绑定了这个,但这似乎有效。运行其中两个,一个在 eth0 上,另一个在 eth1 上会给出不同的结果/

疑似问题

在我看来,问题在于 recvfrom 命令不只过滤传入的数据包,而是从缓冲区读取,无论是传入的还是传出的。也许有一种方法可以查看地址以查看数据包是传入还是传出,就像在 python 中一样,或者可能 recvfrom 已经在这样做了。

注意

程序在接近尾声时打印嗅探到的数据包大小和接收到该大小数据包的时间。这是精简后的代码。提前致谢。

#include<errno.h>  //error codes
#include<linux/if_packet.h>
#include<linux/if_ether.h>
#include<time.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<string.h>
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<net/if.h>
const int TIME_INTERVAL = 2;
const int BUF_LENGTH = 65534;
int main()
{
    int sock_errno(void), data_size=0, raw_sock;
    long recv_count = 0, last_count = 0, rate = 0;
    time_t start;
    socklen_t clilen;
    struct sockaddr_in cliaddr, servaddr; 
    char buffer[BUF_LENGTH];
    int hist[BUF_LENGTH];
    int i;
    for (i = 0; i < BUF_LENGTH; i++)
        hist[i] = 0;
    int table[BUF_LENGTH];
    int index = 0;

    //Create a raw socket that shall sniff
    raw_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    //bind to interface
    clilen = sizeof(struct sockaddr_in);
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth1");
    setsockopt(raw_sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
    start = time(NULL);
    while (1)
    {
        data_size = recvfrom(raw_sock, buffer, BUF_LENGTH, 0, (struct sockaddr*)&cliaddr, &clilen);
        recv_count = recv_count + data_size;

        hist[data_size] = hist[data_size] + 1;

        if (time(NULL) - start > TIME_INTERVAL) // display data every time interval
        {
            start = time(NULL);
            rate = (float)(recv_count - last_count) / TIME_INTERVAL;
            printf("(I) Bytes received: %d\n", recv_count);

            for (i=0; i<BUF_LENGTH; i++) {
                if (hist[i] > 0) //only print received packet sizes
                {
                    printf("%d - ", i); //print packet size
                    printf("%d\n", hist[i]); //print received counter
                }
            }
            printf("\n\n");

        }
    }
    close(raw_sock);
    return 0;
}

【问题讨论】:

  • 当然,在两个不同的接口上运行会得到不同的结果,因为两个接口会得到不同的包。
  • 没错,是为了确认我确实正确绑定了它们。
  • 那么您能否详细说明您的问题?你试图做什么来解决任何问题?效果如何?
  • 它正在嗅探没有被 ifconfig 命令或其他用 python 编写的嗅探器拾取的数据包。
  • ifconfig 命令不是数据包嗅探器,它是用来配置接口的。另外,是否与专业嗅探器(例如Wireshark)进行了比较?

标签: c sockets


【解决方案1】:

查看Raw Socket promiscuous mode not sniffing what I write的答案

查看http://man7.org/linux/man-pages/man7/packet.7.html 将 cliaddr 的类型更改为 struct sockaddr_ll 然后您可以查看 cliaddr.sll_pkttype 以确定传入或传出

struct sockaddr_ll {
           unsigned short sll_family;   /* Always AF_PACKET */
           unsigned short sll_protocol; /* Physical layer protocol */
           int            sll_ifindex;  /* Interface number */
           unsigned short sll_hatype;   /* ARP hardware type */
           unsigned char  sll_pkttype;  /* Packet type */
           unsigned char  sll_halen;    /* Length of address */
           unsigned char  sll_addr[8];  /* Physical layer address */
       };

sll_pkttype 包含数据包类型。 有效类型是 PACKET_HOST 用于寻址到本地主机的数据包, PACKET_BROADCAST 用于物理层广播包, PACKET_MULTICAST 用于发送到物理层多播的数据包 地址,PACKET_OTHERHOST 用于发送到其他主机的数据包 在混杂模式下被设备驱动程序捕获,并且 PACKET_OUTGOING 来自本地主机的数据包 循环回一个数据包套接字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    相关资源
    最近更新 更多