1. 程式人生 > >網路通訊程式設計筆記(二):pcap庫使用

網路通訊程式設計筆記(二):pcap庫使用

  Libpcap是Packet Capture Libray的英文縮寫,即資料包捕獲函式庫。該庫提供的C函式介面用於捕捉經過指定網路介面的資料包,該介面應該是被設為混雜模式。這個在原始套接子中有提到。

  著名的軟體TCPDUMP就是在Libpcap的基礎上開發而成的。Libpcap提供的介面函式實現和封裝了與資料包截獲有關的過程。

  Libpcap提供了使用者級別的網路資料包捕獲介面,並充分考慮到應用程式的可移植性。Libpcap可以在絕大多數Linux平臺上執行。在Windows平臺上,也有一款與其功能類似的開發庫:Wincap。

  它的工作在上層應用程式與網路介面之間。

  主要功能:

  • 資料包捕獲:捕獲流經網絡卡的原始資料包
  • 自定義資料包傳送:構造任何格式的原始資料包
  • 流量採集與統計:採集網路中的流量資訊
  • 規則過濾:提供自帶規則過濾功能,按需要選擇過濾規則

  它的應用範圍非常廣泛,典型應用包括玩羅協議分析器,網路流量發生器,網路入侵檢測系統,網路掃描器和其他安全工具。

  作為捕捉網路資料包的庫,它是一個獨立於系統的使用者級的API介面,為底層網路檢測提供了一個可移植的框架。

  一個包的捕捉分為三個主要部分,包括面向底層包捕獲、面向中間層的資料包過濾和麵嚮應用層的使用者介面。這與Linux作業系統對資料包的處理流程是相同的(網絡卡->網絡卡驅動->資料鏈路層->IP層->傳輸層->應用程式)。包捕獲機制是在資料鏈路層增加一個旁路處理(並不干擾系統自身的網路協議棧的處理),對傳送和接收的資料包通過Linux核心做過濾和緩衝處理,最後直接傳遞給上層應用程式。


  下面介紹Libpcap的抓包流程:

  1. 查詢網路裝置:目的是發現可用的網絡卡,實現的函式為pcap_lookupdev(),如果當前有多個網絡卡,函式就會返回一個網路裝置名的指標列表。
  2. 開啟網路裝置:利用上一步中的返回值,可以決定使用哪個網絡卡,通過函式pcap_open_live()開啟網絡卡,返回用於捕捉網路資料包的秒數字。
  3. 獲得網路引數:這裡是利用函式pcap_lookupnet(),可以獲得指定網路裝置的IP地址和子網掩碼。
  4. 編譯過濾策略:Lipcap的主要功能就是提供資料包的過濾,函式pcap_compile()來實現。
  5. 設定過濾器:在上一步的基礎上利用pcap_setfilter()函式來設定。
  6. 利用回撥函式,捕獲資料包:函式pcap_loop()和pcap_dispatch()來抓去資料包,也可以利用函式pcap_next()和pcap_next_ex()來完成同樣的工作。
  7. 關閉網路裝置:pcap_close()函式關係裝置,釋放資源。


程式碼分析見網址:http://www.cnblogs.com/coder2012/archive/2013/04/13/3012390.html


libpcap從eth0(引數可選)抓取發往192.168.10.0/24網段的udp包程式

#include <pcap.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <libnet.h>
int sockfd4=0;
struct sockaddr_in servaddr4;
socklen_t addr_len =sizeof(struct sockaddr_in);

/*乙太網頭*/
struct sniff_ethernet
{
        u_char ether_dhost[ETHER_ADDR_LEN];
        u_char ether_shost[ETHER_ADDR_LEN];
        u_short ether_type;
};

/*IP頭*/
struct sniff_ip
{
        u_char ip_vhl;
        u_char ip_tos;
        u_short ip_len;
        u_short ip_id;
        u_short ip_off;
        #define IP_RF 0x8000
        #define IP_DF 0x4000
        #define IP_MF 0x2000
        #define IP_OFFMASK 0x1fff
        u_char ip_ttl;
        u_char ip_p;
        u_short ip_sum;
        struct in_addr ip_src,ip_dst;
};

/*UDP報頭*/
struct sniff_udp
{
        u_short udp_sport;
        u_short udp_dport;
        u_short udp_len;
        u_short udp_sum;
};

/*************************************************************
 功能:回撥函式,處理抓到的資料包
 第一個引數是pcap_loop的最後一個引數,當收到足夠數量的包後pcap_loop會呼叫callback回撥函式(本函式中為getPacket),同時將pcap_loop()的user引數傳遞給它,
 第二個引數是收到的資料包的pcap_pkthdr型別的指標,
 第三個引數是收到的資料包資料
 **************************************************************/
void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
{
	int * id = (int *)arg; 
	printf("id: %d\n", ++(*id));/*包計數*/
	printf("Packet length: %d\n", pkthdr->len);/*理論包長度*/
	printf("Number of bytes: %d\n", pkthdr->caplen);/*真正捕獲包長度*/
	printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));/*包時間戳 */
	
	/*兩位16進位制數輸出,每輸出16個換行*/
	int i;
	for(i=0; i<pkthdr->len; ++i)
	{
		printf(" %02x", packet[i]);
		if( (i + 1) % 16 == 0 )
		{
			printf("\n");
		}
	}
	printf("\n");
	
	struct sniff_ethernet *ethernet;/*以太幀包頭*/
	struct sniff_ip *ip;            /*ip包頭*/
    struct sniff_udp *udp;          /*udp包頭*/
    u_char *payload;                /*資料包負載的資料*/
    int payload_size;               /*資料包負載的資料大小*/

    ethernet=(struct sniff_ethernet*)(packet);                                                                /*指向乙太網頭*/
    ip=(struct sniff_ip*)(packet + sizeof(struct sniff_ethernet));                                            /*指向IP頭*/
    udp=(struct sniff_udp*)(packet + sizeof(struct sniff_ethernet)+sizeof(struct sniff_ip));                  /*指向udp頭*/
    payload=(u_char *)(packet+sizeof(struct sniff_ethernet)+sizeof(struct sniff_ip)+sizeof(struct sniff_udp));/*指向負載*/
	payload_size=ntohs(udp->udp_len)-sizeof(struct sniff_udp);                                                /*算出負載長度*/
    printf("len:%d,srcport:%d,dstport:%d\n",payload_size,ntohs(udp->udp_sport),ntohs(udp->udp_dport));        /*列印負載長度,udp的源埠和目的埠*/
    sendto(sockfd4,ip,payload_size+sizeof(struct sniff_ip)+sizeof(struct sniff_udp),0,(struct sockaddr *)&servaddr4,addr_len);/*將IP包從sockfd4傳送到servaddr4*/
}

int main(int argc ,char* argv[])
{
	char errBuf[PCAP_ERRBUF_SIZE], * devStr;/*定義儲存錯誤資訊的字串,執行嗅探的裝置*/
	/*下面這個函式會返回指定介面的pcap_t型別指標,後面的所有操作都要使用這個指標。
    第一個引數是第一步獲取的網路介面字串,可以直接使用硬編碼。
	第二個引數是對於每個資料包,從開頭要抓多少個位元組,我們可以設定這個值來只抓每個資料包的頭部,而不關心具體的內容。典型的乙太網幀長度是1518位元組,但其他的某些協議的資料包會更長一點,但任何一個協議的一個數據包長度都必然小於65535個位元組。
	第三個引數指定是否開啟混雜模式(Promiscuous Mode),0表示非混雜模式,任何其他值表示混合模式。如果要開啟混雜模式,那麼網絡卡必須也要開啟混雜模式,可以使用如下的命令開啟eth0混雜模式:ifconfig eth0 promisc
	第四個引數指定需要等待的毫秒數,超過這個數值後,第3步獲取資料包的這幾個函式就會立即返回。0表示一直等待直到有資料包到來。
	第五個引數是存放出錯資訊的陣列*/
	pcap_t * device = pcap_open_live(argv[1], BUFSIZ, 1, 0, errBuf);

	if(!device)
	{
		printf("error: pcap_open_live(): %s\n", errBuf);
		exit(1);
	}
	/* construct a filter 
	libpcap利用BPF來過濾資料包。過濾資料包需要完成3件事:
	a) 構造一個過濾表示式
  b) 編譯這個表示式,語法高階容易
  c) 應用這個過濾器*/
	struct bpf_program filter;
	pcap_compile(device, &filter, "udp and dst net 192.168.10.0/24", 1, 0);
	pcap_setfilter(device, &filter);
	
    /*建立本地sockfd4,目的為本地5012埠的servaddr4的UDP傳送端*/	
	sockfd4=socket(AF_INET,SOCK_DGRAM,0);
	bzero(&servaddr4,sizeof(servaddr4));
	servaddr4.sin_family=AF_INET;
	servaddr4.sin_port=htons(5012);
	inet_pton(AF_INET,"127.0.0.1",&servaddr4.sin_addr);
		
	int id = 0;/*包編號,會傳遞給回撥函式*/
	
	/* wait loop forever */
	/*第一個引數是返回的pcap_t型別的指標
	  第二個引數是需要抓的資料包的個數,一旦抓到了cnt個數據包,pcap_loop立即返回。負數的cnt表示pcap_loop永遠迴圈抓包,直到出現錯誤。
	  第三個引數是一個回撥函式指標(getPacket)*/
	pcap_loop(device, -1, getPacket, (u_char*)&id);
	pcap_close(device);/*釋放網路介面*/
	return 0;
}





相關推薦

網路通訊程式設計筆記pcap使用

  Libpcap是Packet Capture Libray的英文縮寫,即資料包捕獲函式庫。該庫提供的C函式介面用於捕捉經過指定網路介面的資料包,該介面應該是被設為混雜模式。這個在原始套接子中有提到。   著名的軟體TCPDUMP就是在Libpcap的基礎上開發而成的。L

網路通訊協議筆記

切換到使用者的角度,看看使用者是如何從上至下,與這些協議互動的。 網路通訊就是交換資料包。電腦A向電腦B傳送一個數據包,後者收到了,回覆一個數據包,從而實現兩臺電腦之間的通訊。資料包的結構,基本上是下面這樣: 傳送這個包,需要知道兩個地址: * 對方的MAC地址

JRtplib開發筆記JRtplib編譯、示例演示

原博主部落格地址:https://blog.csdn.net/qq21497936 本文章部落格地址:https://blog.csdn.net/qq21497936/article/details/84785593 《JRtplib開發筆記(一):JRtplib簡介、JThread庫編譯》

網路程式設計 筆記 基於 Windows簡單通訊

windows套接字程式設計 1、設定庫Alt+F7 ->“配置屬性”-> “聯結器” -> “輸入” -> “附加依賴項” -> “ws2_32.lib” 2、標頭檔案:#include <winsock2.h>

STM32開發筆記48STM32F4+DP83848乙太網通訊指南系列系統時鐘

本章為系列指南第二章,主要是介紹一下STM32F4的時鐘配置。時鐘是一個嵌入式產品從零開始開發的基石,一切邏輯都在時鐘的節奏中安靜地彈奏著,時鐘為整個電路帶來了歡快的「心跳」。開發者如果對時鐘沒有控制能力,就會把脈不準整個旋律的節奏,從而導致諸如通訊波特率、通訊時序、延時操作等關鍵功能全都紊亂,系統

Deep Learning 學習筆記神經網路Python實現

多層神經網路的Python實現。 程式碼先貼上,程式設計的東西不解釋。 程式碼中出現的SupervisedLearningModel、NNLayer和SoftmaxRegression,請參考上一篇筆記:Deep Learning 學習筆記(一)——softmax

Kubernetes學習筆記網路原理

Kubernetes網路模型 Kubernetes網路模型設計的一個基礎原則是:每個Pod都擁有一個獨立的IP地址,而且假定所有Pod都在一個可以直接連通的、扁平的網路空間中。所以不管它們是否執行在同一個Node(宿主機)中,都要求它們可以直接通過對方的

UI網路筆記UI網路之Post同步和非同步的密文請求

一、Post相關內容 1、有同步、非同步的方式; 2、get(明文)瀏覽器裡看,post(密文)把引數變成NSData 3、post可變字串需要兩個: 一個拼接URL+interface req的時候只把URL+interface的字串放進來 一個拼接ke

Linux網路學習筆記域名解析(DNS)——以 CoreDNS 為例

>個人筆記,觀點不一定正確. 適合對 Kubernetes 有一定了解的同學。 ## 前言 最近一直在學習 Kubernetes,但是手頭沒有個自有域名,要測試 ingress 就比較麻煩,每次都是手動改 hosts 檔案。。 今天突然想到——K8s 內部就是用 DNS 做的服務發現,我為啥不自己弄一個

javascript學習筆記定義函數、調用函數、參數、返回值、局部和全局變量

兩個 cnblogs bsp 結果 value ava ase com 調用 定義函數、調用函數、參數、返回值 關鍵字function定義函數,格式如下: function 函數名(){ 函數體 } 調用函數、參數、返回值的規則和c語言規則類似。 1 <!DOC

CSS學習筆記特性

code 背景色 左移 line tex lin 安裝 其中 cas 一、顏色特性 1. 前景色:color 用種方式指定前景色,3種方式分別是rgb顏色,#16進制編碼,顏色名稱: color: rgb(100,100,100); color: #ee3e80; col

JS筆記隱式轉換

-1 筆記 總結 img 轉換 隱式轉換 基礎 blog com 最近剛開始復習JS的基礎知識,看到隱式轉換這一塊,發現它的規則很多,紅寶書上列出的框框又有些冗雜,所以這裏我借一個式子總結一下其中的規律以及一些有趣的現象。 JS筆記(二):隱式轉換

Unity3D之Mecanim動畫系統學習筆記模型導入

leg character ... sdk ocs 物體 mat 版本 sset 我們要在Unity3D中使用上模型和動畫,需要經過下面幾個階段的制作,下面以一個人形的模型開發為準來介紹。 模型制作 模型建模(Modelling) 我們的美術在建模時一般會制作一個稱為

kubernetes學習筆記bashborad安裝配置

tag log struct recommend ide col create part describe 官方推薦方法: 連接:https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashb

python3學習筆記Python初識

區別 說明 from 學習筆記 情況 不能 col 需要 學習 一、算法 在開始認真地編程之前,首先來解釋下什麽是計算機程序設計。簡單地說,它就是告訴計算機要做什麽。計算機可以做很多事情,但是它不會自己思考,需要我們告訴它具體細節,並且使用計算機能夠理解的語言把算法告

Linux學習筆記實戰-根據微服務端口號關閉進程

java 地方 img linux學習 區分 殺死進程 項目組 cannot home 前言 現在項目組基本都用Springboot,每個服務占用一個端口號,有時需要選擇性的關閉,但在任務管理器上他們的名稱都是java.exe,無法區分,這才學以致用。 killPort.s

Person Re-identification 系列論文筆記A Discriminatively Learned CNN Embedding for Person Re-identification

triplet put ali com multi 深度學習 native alt 出現   A Discriminatively Learned CNN Embedding for Person Re-identification Zheng Z, Zheng L, Ya

Guava學習筆記基礎Joiner,Objects,Splitter及Strings

nonnull obj expect null dto 字符 情況 core cte 添加Maven依賴 JoinerTest import com.google.common.base.Joiner; import org.junit.Assert; import org

opencv 視覺項目學習筆記 基於 svm 和 knn 車牌識別

its ++ eas -a rect() repr poi obj std 車牌識別的屬於常見的 模式識別 ,其基本流程為下面三個步驟: 1) 分割: 檢測並檢測圖像中感興趣區域; 2)特征提取: 對字符圖像集中的每個部分進行提取; 3)分類: 判斷圖像快是不是車牌或者 每

安卓開發學習筆記Android Stuidio無法引用Intent來創建對象,出現cannot resolve xxx

編譯器 port stact 消失 click first 紅色 xxx font 筆者在進行安卓開發時,發現自己的代碼語法完全沒有問題。尤其是創建intent對象的時候,語法完全是正確的,但是Android Stuidio卻顯示報錯,Intent類顯示為紅色,如圖所示: