static int live_open_new(pcap_t *handle, const char *device, int promisc, int to_ms, char *ebuf) { /* 如果設(shè)備給定,則打開(kāi)一個(gè) RAW 類型的套接字,否則,打開(kāi) DGRAM 類型的套接字 */ sock_fd = device ? socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) : socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
/* 取得回路設(shè)備接口的索引 */ handle->md.lo_ifindex = iface_get_id(sock_fd, "lo", ebuf);
/* 如果設(shè)備給定,但接口類型未知或是某些必須工作在加工模式下的特定類型,則使用加工模式 */ if (device) { /* 取得接口的硬件類型 */ arptype = iface_get_arptype(sock_fd, device, ebuf);
/* linux 使用 ARPHRD_xxx 標(biāo)識(shí)接口的硬件類型,而 libpcap 使用DLT_xxx 來(lái)標(biāo)識(shí)。本函數(shù)是對(duì)上述二者的做映射變換,設(shè)置句柄的鏈路層類型為 DLT_xxx,并設(shè)置句柄的偏移量為合適的值,使其與鏈路層頭部之和為 4 的倍數(shù),目的是邊界對(duì)齊 */ map_arphrd_to_dlt(handle, arptype, 1);
/* 如果接口是前面談到的不支持鏈路層頭部的類型,則退而求其次,使用 SOCK_DGRAM 模式 */ if (handle->linktype == xxx) { close(sock_fd); sock_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)); }
/* 獲得給定的設(shè)備名的索引 */ device_id = iface_get_id(sock_fd, device, ebuf); /* 把套接字和給定的設(shè)備綁定,意味著只從給定的設(shè)備上捕獲數(shù)據(jù)包 */ iface_bind(sock_fd, device_id, ebuf);
} else { /* 現(xiàn)在是加工模式 */ handle->md.cooked = 1; /* 數(shù)據(jù)包鏈路層頭部為結(jié)構(gòu) sockaddr_ll, SLL 大概是結(jié)構(gòu)名稱的簡(jiǎn)寫形式 */ handle->linktype = DLT_LINUX_SLL; device_id = -1; } /* 設(shè)置給定設(shè)備為混雜模式 */ if (device && promisc) { memset(&mr, 0, sizeof(mr)); mr.mr_ifindex = device_id; mr.mr_type = PACKET_MR_PROMISC; setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)); }
/* 最后把創(chuàng)建的 socket 保存在句柄 pcap_t 中 */ handle->fd = sock_fd; }
/* 2.0 內(nèi)核下函數(shù)要簡(jiǎn)單的多,因?yàn)橹挥形ㄒ坏囊环N socket 方式 */ static int live_open_old(pcap_t *handle, const char *device, int promisc, int to_ms, char *ebuf) { /* 首先創(chuàng)建一個(gè)SOCK_PACKET類型的 socket */ handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); /* 2.0 內(nèi)核下,不支持捕獲所有接口,設(shè)備必須給定 */ if (!device) { strncpy(ebuf, "pcap_open_live: The \"any\" device isn't supported on 2.0[.x]-kernel systems", PCAP_ERRBUF_SIZE); break; } /* 把 socket 和給定的設(shè)備綁定 */ iface_bind_old(handle->fd, device, ebuf); /*以下的處理和 2.2 版本下的相似,有所區(qū)別的是如果接口鏈路層類型未知,則 libpcap 直接退出 */ arptype = iface_get_arptype(handle->fd, device, ebuf); map_arphrd_to_dlt(handle, arptype, 0); if (handle->linktype == -1) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown arptype %d", arptype); break; }
/* 設(shè)置給定設(shè)備為混雜模式 */ if (promisc) { memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); ioctl(handle->fd, SIOCGIFFLAGS, &ifr); ifr.ifr_flags |= IFF_PROMISC; ioctl(handle->fd, SIOCSIFFLAGS, &ifr); } }
|