OSX用に構築している小さなツールの場合、特定のイーサネットコントローラーとの間で送受信されるパケットの長さをキャプチャしたいと思います。
イーサネットカードを取得すると、最大パケットサイズ、リンク速度などの追加情報も取得します。
(私が呼んでいる)'trafficMonitor'を起動すると、次のように起動します。
static void initializeTrafficMonitor(const char* interfaceName, int packetSize) {
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t* sessionHandle = pcap_open_live(interfaceName, packetSize, 1, 100, errbuf);
if (sessionHandle == NULL)
{
printf("Error opening session for device %s: %s\n", interfaceName, errbuf);
return;
}
pcap_loop(sessionHandle, -1, packetReceived, NULL);
}
提供されるinterfaceName
のは、たとえば、インターフェースのBSD名ですen0
。変数は整数であり、そのpacketSize
イーサネットアダプターの最大パケットサイズを指定します(当時は論理的であるように見えました)。たとえば、WiFiアダプターのパケットサイズはです1538
。
私のコールバックメソッドが呼び出されpacketReceived
、次のようになります。
void packetReceived(u_char* args, const struct pcap_pkthdr* header, const u_char* packet) {
struct pcap_work_item* item = malloc(sizeof(struct pcap_pkthdr) + header->caplen);
item->header = *header;
memcpy(item->data, packet, header->caplen);
threadpool_add(threadPool, handlePacket, item, 0);
}
パケットのすべてのプロパティを新しい構造体に詰め込み、ワーカースレッドを起動してパケットを分析し、結果を処理します。これはpcapを待たせないためであり、このワーカースレッドメソッドを追加する前にすでに存在していたこの問題を修正する試みです。
handlePacket
メソッドは次のようになります。
void handlePacket(void* args) {
const struct pcap_work_item* workItem = args;
const struct sniff_ethernet* ethernet = (struct sniff_ethernet*)(workItem->data);
u_int size_ip;
const struct sniff_ip* ip = (struct sniff_ip*)(workItem->data + SIZE_ETHERNET);
size_ip = IP_HL(ip) * 4;
if (size_ip < 20) {
return;
}
const u_int16_t type = ether_packet(&workItem->header, workItem->data);
switch (ntohs(type)) {
case ETHERTYPE_IP: {
char sourceIP[INET_ADDRSTRLEN];
char destIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ip->ip_src, sourceIP, sizeof(sourceIP));
inet_ntop(AF_INET, &ip->ip_dst, destIP, sizeof(destIP));
[refToSelf registerPacketTransferFromSource:sourceIP destinationIP:destIP packetLength:workItem->header.caplen packetType:ethernet->ether_type];
break;
}
case ETHERTYPE_IPV6: {
// handle v6
char sourceIP[INET6_ADDRSTRLEN];
char destIP[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ip->ip_src, sourceIP, sizeof(sourceIP));
inet_ntop(AF_INET6, &ip->ip_dst, destIP, sizeof(destIP));
[refToSelf registerPacketTransferFromSource:sourceIP destinationIP:destIP packetLength:workItem->header.caplen packetType:ethernet->ether_type];
break;
}
}
}
イーサネットパケットの種類に基づいて、IPv4またはIPv6アドレスを使用して送信されたパケットであるかどうかを判断しようとします。それが決定された後、私はいくつかの詳細をObjectiveCメソッドに送信します(送信元IPアドレス、宛先IPアドレス、およびパケット長)。
tcpdumpのWebサイト(http://www.tcpdump.org/pcap.html)で説明されている構造体にパケットをキャストしました。
問題は、pcapが送受信されたパケットに追いついていないように見えることです。すべてのパケットをスニッフィングしていないか、パケット長が間違っています。
pcapがそれらすべてをキャッチするようにコードを調整する必要がある場所、または何らかの問題がある場所にポインターがありますか?
これらのメソッドは私のobjectiveCアプリケーションから呼び出されrefToSelf
、objCクラスへの参照です。
編集: pcap_loopがブロックしているため、バックグラウンドスレッドでinitializeTrafficMonitorを呼び出しています。