【问题标题】:How do i capture MAC address of Access points and hosts connected to it?如何捕获接入点和连接到它的主机的 MAC 地址?
【发布时间】:2011-05-30 10:05:45
【问题描述】:

我知道我必须使用 libpcap 库来捕获 IEEE 802.11 帧以显示它们的 MAC 地址,例如我的无线适配器处于监控模式,并且在我执行 pcap_datalink 时仅支持“802.11 plus radiotap radio header”。

在 pcap_loop 的回调函数中,我应该如何从数据包中提取 MAC 地址?我如何区分不同类型的数据包?谷歌搜索并没有太多答案,主要是关于如何从有线接口提取数据包。

 void procPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet)
 {
         //what should i do here?
 }

  pcap_t *handler=pcap_open_live ("wlan0", BUFSIZ,1,-1,errbuff);
 if(pcap_datalink(handler) == DLT_IEEE802_11_RADIO) 
 {
          pcap_loop(handler, -1 ,procPacket, NULL );              
 }

【问题讨论】:

    标签: c++ pcap libpcap


    【解决方案1】:

    最好的方法是从 tcpdump 源代码中提取所需的代码,就我而言,这基本上是 libpcap 的操作指南和网络介绍合二为一。

    无论如何,您需要的是从pcap_open_live 收集到的数据包处理功能。您还需要创建另一个线程或进程,因为pcap_open_live 会在当前线程工作时阻塞它。

    现在,数据包处理函数如下所示:

    void packethandler( u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packet )
    {
        // ... allocs etc
    
        // these instructions convert the "packet" string
        // to a struct and determine it's type, a setting in 
        // the ethernet header.
        eptr = (struct ether_header *) packet;
        ether_type = ntohs(eptr->ether_type);
    
        // ...
    
        // these two functions extract the mac addresses 
        // into appropriately alloc'd strings.
        // ether_ntoa converts the binary representation
        // of the mac address into a string
        snprintf(ethernet_shost, 20, "%s", ether_ntoa((struct ether_addr *)eptr->ether_shost));
        snprintf(ethernet_dhost, 20, "%s", ether_ntoa((struct ether_addr *)eptr->ether_dhost));
    
        // carry on...
    }
    

    这将为您获取作为字符串的 mac 地址。但是请注意,联网并不容易。你需要知道你在用二进制信息字符串做什么,转换等,你需要知道数字和选项的含义。如果 tcpdump 源看起来很复杂,那是因为网络复杂。此外,我还没有列出实现此过程所需的标题。那里有 pcap 教程;我建议你花时间阅读它们。我只是给你一个答案不会教你建立网络。

    此外,此功能不完整。您将需要为存储阵列进行适当的分配(pcap 是一个 C 库,您可能希望使用 char* 而不是 string,然后稍后再提取回 string)。

    【讨论】:

    • 谢谢,但您的代码只有在无线适配器连接到网络(不是监控模式)时才能工作,我正在寻找一些允许我查看 IEEE802.11 信标帧的示例,并从那里提取 Destin/source/BSSID MAC 地址。我确实查看了 tcpdump 源代码,这确实令人困惑。我知道我必须查看帧控制位(子类型:8)来检查它是否是信标帧,但我不知道首先要这样做。
    • 嗯,是的,直到你稍微解开它。然后另一个建议是尝试使用 aircrack 源,它可以实现您正在寻找的东西。我不知道它是怎么做到的。但是,我怀疑上述方法在连接到监控模式下的接口时可能会起作用,因为在监控模式下,所有命中接口的数据包都会被暴露,而不仅仅是那些被拒绝的接口数据包。我认为无论如何它都是这样工作的。至于确定接入点的mac地址,同样,airodump具体会给你一个线索。
    【解决方案2】:

    好的,我找到了解决方案,基本上以下代码跳过了 ech 数据包的无线电标头,并获取了接入点的 bassid/MAC 地址。

    例如:我的无线电标头的长度为 18,它是一个 radiotap 标头,如果您的是 prism/AVS 标头,则长度将是另一个大小。

    要获得连接到 AP 的客户端 MAC 地址,我认为您必须检查 FROM DS/TO DS 位。

    typedef struct mac_header{
    unsigned char fc[2];
    unsigned char id[2];
    unsigned char add1[6];
    unsigned char add2[6];
    unsigned char add3[6];
    unsigned char sc[2];
    }mac_header;
    typedef struct frame_control{
    unsigned protocol:2;
    unsigned type:2;
    unsigned subtype:4;
    unsigned to_ds:1;
    unsigned from_ds:1;
    unsigned more_frag:1;
    unsigned retry:1;
    unsigned pwr_mgt:1;
    unsigned more_data:1;
    unsigned wep:1;
    unsigned order:1;
    }frame_control;
    
    typedef struct beacon_header{
    unsigned char timestamp[8];
    
    unsigned char beacon_interval[2];
    unsigned char cap_info[2];
    }beacon_header;
    
    void procPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet)
    {
    
        char * temp;
        char ssid[32];    
        struct mac_header *p= (struct mac_header *)(packet+RADIOTAP_HEADER_SIZE);
        struct frame_control *control = (struct frame_control *) p->fc;
        temp = (char *) (packet + sizeof (struct mac_header) +sizeof (struct    beacon_header)+RADIOTAP_HEADER_SIZE);
        if ((control->protocol == 0) && (control->type == 0) && (control->subtype == 8) )  // beacon frame
        {        
             memset(ssid,0,32);
             memcpy (ssid, &temp[2], temp[1]);
             printf ("Destination Add : %s\n", ether_ntoa ((struct ether_addr *)p->add1));
             printf ("Source Add : %s\n", ether_ntoa ((struct ether_addr *)p->add2));
             printf ("BSSID : %s\n", ether_ntoa ((struct ether_addr *)p->add3));
             printf ("ssid = %s\n", ssid);
        }
    
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-30
      相关资源
      最近更新 更多