1. Libpcap的安裝:
下載壓縮包,解壓
./configure
make
sudo make install
2. Libpcap的使用
注意兩點:
-lpcap
使用root權限
自動獲取網絡接口:
char * pcap_lookupdev(char * errbuf)
參數:如果出錯,則errbuf存放出錯信息字符串,errbuf至少應該是PCAP_ERRBUF_SIZE個字節長度的
返回值:返回第一個合適的網絡接口的字符串指針
打開網絡接口:
pcap_t * pcap_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)
返回值:指定接口的pcap_t類型指針,后面的所有操作都要使用這個指針。
第一個參數:自動獲取的網絡接口字符串,可以直接使用硬編碼。
第二個參數:對于每個數據包,從開頭要抓多少個字節,我們可以設置這個值來只抓每個數據包的頭部,而不關心具體的內容。典型的以太網幀長度是1518字節,但其他的某些協議的數據包會更長一點,但任何一個協議的一個數據包長度都必然小于65535個字節。
第三個參數:指定是否打開混雜模式(Promiscuous Mode),0表示非混雜模式,任何其他值表示混合模式。如果要打開混雜模式,那么網卡必須也要打開混雜模式,可以使用如下的命令打開eth0混雜模式:
ifconfig eth0 promisc
第四個參數:指定需要等待的毫秒數,超過這個數值后,第3步獲取數據包的這幾個函數就會立即返回。0表示一直等待直到有數據包到來。
第五個參數:存放出錯信息的數組。
釋放網絡接口:
void pcap_close(pcap_t * p)
獲取數據包:
int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
第一個參數:返回的pcap_t類型的指針
第二個參數:需要抓的數據包的個數,一旦抓到了cnt個數據包,pcap_loop立即返回。負數的cnt表示pcap_loop永遠循環抓包,直到出現錯誤。
第三個參數:一個回調函數指針,它必須是如下的形式:
void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
第一個參數:pcap_loop的后一個參數,當收到足夠數量的包后pcap_loop會調用callback回調函數,同時將pcap_loop()的user參數傳遞給它
第二個參數:收到的數據包的pcap_pkthdr類型的指針
第三個參數:收到的數據包數據
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define PORT 8888
#define SERVER_IP "192.168.1.153"
int main()
{
int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(PORT);
bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(server_sockfd, 5);
char ch;
int client_sockfd;
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
while(1)
{
printf("server waiting:\n");
/* accept a connection */
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len);
/* exchange data */
read(client_sockfd, &ch, 1);
printf("get char from client: %c\n", ch);
++ch;
write(client_sockfd, &ch, 1);
close(client_sockfd);
}
return 0;
}
根據以上代碼編寫客戶端,運行后可查看接收到的具體數據包。
int pcap_lookupnet(const char * device, bpf_u_int32 * netp, bpf_u_int32 * maskp, char * errbuf)
可以獲取指定設備的ip地址,子網掩碼等信息
netp:傳出參數,指定網絡接口的ip地址
maskp:傳出參數,指定網絡接口的子網掩碼
pcap_lookupnet()失敗返回-1