1. 程式人生 > >利用原始套接字實現對流經本機IP包的捕獲

利用原始套接字實現對流經本機IP包的捕獲

經過上一篇部落格的總結,我知道到了原始套接字接收到的字串的開始欄位是IP資料報的首部,所以我想除了之前利用win_pcap可以捕獲資料包以外,理論上來說原始套接字也可以實現對IP資料報的捕獲。思路也很簡單,捕獲到字串以後轉換成指向IP首部結構體的指標,再列印相關資訊就可以了。

當然由於網絡卡會預設丟掉不屬於本機的資料包,所以需要將套接字設定為接收所有資料。win_pcap是直接對網絡卡進行設定。ioctlsocket( )函式用於控制套接字上的I/O行為,同時獲取與那個套接字上掛起的網路I/O操作的有關資訊。

int ioctlsocket(
SOCKET s,//套接字
long cmd,//對s的命令
u_long* argp//命令引數指標 )//如果成功的話返回0,如果失敗的話返回錯誤程式碼
函式的示例(讓socket接收所有資料包):
u_long flag=1;
ioctlsocket(s,SIO_RCVALL,&flag);

於是有了以下一段程式碼:

#include "stdafx.h"
#include <winsock2.h>
#include <ws2tcpip.h> 
#include "mstcpip.h"     //自定義
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")

struct IPHEADER
{
	unsigned char h_verlen; //4位首部長度,4位IP版本號 
	unsigned char tos; //8位服務型別TOS 
	unsigned short total_len; //16位總長度(位元組) 
	unsigned short ident; //16位標識 
	unsigned short frag_and_flags; //3位標誌位 
	unsigned char ttl; //8位生存時間 TTL 
	unsigned char proto; //8位協議 (TCP, UDP 或其他) 
	unsigned short checksum; //16位IP首部校驗和 
	in_addr sourceIP; //32位源IP地址 
	in_addr destIP; //32位目的IP地址 
};

#define BUFSIZE 256
#define RECVBUF 1520

int analyzeIP(IPHEADER *pip, int buflen)
{
	if (buflen < 20)
	{
		printf("此包不完整!\n");
	}
	printf("版本號:%d\n", pip->h_verlen >> 4);
	printf("首部長度(位元組):%d\n", (pip->h_verlen & 0x0f)*4);
	printf("總長度:%d\n", pip->total_len);
	printf("協議型別:%d\n", pip->proto);
	printf("源地址:%s\n", inet_ntoa(pip->sourceIP));
	printf("目的地址:%s\n", inet_ntoa(pip->destIP));
	return 0;
}

int main()
{
	SOCKET s;
	WSADATA wsa;
	int retval;
	retval = WSAStartup(MAKEWORD(2, 2), &wsa);
	if (retval == SOCKET_ERROR)
	{
		printf("startup failed\n");
		WSACleanup();
		return 0;
	}
	s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
	if (s == INVALID_SOCKET)
	{
		printf("socket error\n");
		WSACleanup();
		return 0;
	}
	sockaddr_in addr;
	char hostname[BUFSIZE] = { 0 };
	int namelen;
	namelen = gethostname(hostname, BUFSIZE);//取得本機名,存放在hostname裡面
	hostent *ph = gethostbyname(hostname);
	if (ph == NULL)
	{
		printf("gethostbyname failed\n");
		WSACleanup();
		closesocket(s);
		return 0;
	}
	addr.sin_family = AF_INET;
	addr.sin_port = htons(0);
	memcpy(&(addr.sin_addr), ph->h_addr, ph->h_length);
	retval = bind(s, (sockaddr*)&addr, sizeof(sockaddr_in));
	if (retval == SOCKET_ERROR)
	{
		printf("bind error\n");
		closesocket(s);
		WSACleanup();
		return 0;
	}
	unsigned long flag = 1;
	retval = ioctlsocket(s, SIO_RCVALL, &flag);//將網絡卡設定為混雜
	if (retval != 0)
	{
		printf("ioctlsocket error\n");
		closesocket(s);
		WSACleanup();
		return 0;
	}
	char recvbuf[RECVBUF];
	size_t size;
	IPHEADER *p_ipheader;
	int cnt = 0;
	while (1)
	{
		size = recv(s, recvbuf, RECVBUF, 0);
		if (size == 0 || size == SOCKET_ERROR)
		{
			printf("recv error\n");
			closesocket(s);
			WSACleanup();
			continue;
		}
		cnt++;
		printf("第 %d 個包\n", cnt);
		p_ipheader = (IPHEADER*)recvbuf;
		analyzeIP(p_ipheader, size);
		memset(recvbuf, 0, sizeof(recvbuf));
	}
	WSACleanup();
	closesocket(s);
	return 0;
}


但當我把這個程式和win_pcap的程式一起執行的時候,發現這個程式捕獲的包沒有win_pcap的程式捕獲得多,而且這個程式捕獲的包部分資訊也很奇怪,比如源地址,目的地址等,於是我猜想這可能是windows處於安全原因對原始套接字的使用也做出了限制。

相關推薦

利用原始實現流經IP捕獲

經過上一篇部落格的總結,我知道到了原始套接字接收到的字串的開始欄位是IP資料報的首部,所以我想除了之前利用win_pcap可以捕獲資料包以外,理論上來說原始套接字也可以實現對IP資料報的捕獲。思路也很簡單,捕獲到字串以後轉換成指向IP首部結構體的指標,再列印相關資訊就可以了

利用原始實現tracert路由追蹤

在windows的命令列下,使用tracert 域名/IP地址 可以記錄本機到目的主機所經過的路由器的IP地址。這個功能使用原始套接字也可以實現。 我們通過不斷地向目的主機發送ICMP-ECHORequest包,並且將包的TTL一開始設為1,這樣一到達閘道器路由器後,路由器

網路程式設計——原始實現原理

目錄 1. 基礎知識  1.1、概述 1.2、鏈路層原始套接字  1.3、網路層原始套接字 2、原始套接字的實現 2.1  原始套接字報文收發流程 2.2鏈路層原始套接字的實現     2.2.1  套接字建

原始實現網路監聽

 作者:張志強 下載原始碼 1、引言    網路監聽工具(sinff)是提供給網路管理員的一類管理工具。在乙太網中(Ethernet),當網路上連線多臺計算機時,某瞬間只能有一臺計算機可以傳送資料。乙太網中,資料是以被稱為幀的資料結構為單位進行交換的。通常,在計算機網路上交換

原始實現

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #ifdef WIN32 #include <Winsock2

原始實現--arp欺騙

1、利用原始套接字實現arp欺騙:       首先我們要清楚arp的原理: 這樣我們就可以很清楚我們要做什麼了: 2、既然這樣我們就可以十分明白自己該怎樣做了。   來看一下linux下的一些對於arp頭部的構造的原始碼和各個欄位的常見引數解析:去檔案/usr/

利用網路實現TCP互動

我們來了解一下TCP互動流程: 大致流程如下: (1)伺服器根據地址的型別(屬於ipv4還是ipv6等)、socket型別(比如TCP、UDP)去建立socket,創建出的套接字socket本質

ping 程式(vc6.0 原始實現

#include <stdio.h> #include <WINSOCK2.H> #include <windows.h> #include <ws2tcpip.h> //IP_TTL #pragma comment(li

Linux原始實現分析---轉

本文從IPV4協議棧原始套接字的分類入手,詳細介紹了鏈路層和網路層原始套接字的特點及其核心實現細節。並結合原始套接字的實際應用,說明各型別原始套接字的適應範圍,以及在實際使用時需要注意的問題。 一、原始套接字概述 協議棧的原始套接字從實現上可以分為“鏈路層原始套

[原始碼和文件分享]使用原始Raw Socket實現資料嗅探

背景 網路上隨時都流通了大量的資料包,我們要想實現抓包並分析,實現思路思路大概是:在合適的時候捕獲資料包,儲存到緩衝區,作為備用;然後,按照一定的結構和格式去讀取緩衝區的內容。由於各種公開的網路協議是已知的,所以對於資料包的分析就比較簡單。 通常我們都是使用類似WireShark的抓包軟體嗅

Linux原始之sniffer部分實現

1.概述  通常在同一個網段的所有網路介面都有訪問在物理媒體上傳輸的所有資料的能力,而每個網路介面都還應該有一個硬體地址,該硬體地址不同於網路中存在的其他網路介面的硬體地址,同時,每個網路至少還要一個廣播地址。(代表所有的介面地址),在正常情況下,一個合法的網路介面應該只響應這樣的兩種資料幀:&

Linux原始之ARP協議實現

1. ARP協議介紹  ARP(AddressResolutionProtocol)地址解析協議用於將計算機的網路地址(IP地址32位)轉化為實體地址(MAC地址48位)[RFC826].ARP協議是屬於鏈路層的協議,在乙太網中的資料幀從一個主機到達網內的另一臺主機是根據48位的乙太網地址(硬體

Linux網路程式設計之原始-ping協議實現

1.概述 PING協議是用來檢驗本地主機與遠端主機是否連線,傳送的是ICMP ECHO_REQUEST包。普通的套接字是基於TCP或者是UDP的,無法傳送ICMP包,所以必須用原始套接字來實現。PING協議的客戶端型別值為8,程式碼值為0,表示請求。而PING協議的響應端型別值為0,程式碼值也為

python基礎之socket編程-------基於tcp的實現遠程執行命令的操作

logs lose stream res std 遠程控制 python log out 遠程實現cmd功能: import socket import subprocess phone=socket.socket(socket.AF_INET,socket.SOC

原始-TCP/IP下三層數據顯示

pf_packet printf linu 0.11 pes span close double ddr 1 #include <stdio.h> 2 #include <errno.h> 3 #include <unistd.

網絡駭客初級之原始(SOCK_RAW)

原始套接字 駭客 網絡駭客初級之原始套接字(SOCK_RAW)本文用實際程序完成了MAC數據包分析,網絡數據分析,MAC地址掃描器和飛秋欺騙在這裏我把原來的入門改成了初級,因為對於原始套接字的操作確實在普通的TCP,UDP之上TCP和UDP確實涵蓋了普通的網絡應用程序,但請註意“普通”二字,要成為一名

非阻塞實現並發處理

pre ror enc con put 服務 生成 import data 服務端 import socket server = socket.socket() server.setblocking(False) server.bind((‘0.0.0.0‘,8080)

實現埠重用

假如埠被socket使用過,並且利用socket.close()來關閉連線,但此時埠還沒有釋放,要經過一個TIME_WAIT的過程之後才能使用,這是TNN的相當煩銀的,為了實現埠的馬上覆用,可以選擇setsockopt()函式來達到目的。(以下是網上找到的一篇文章的一小段相關例子,試用之後,相當有效果,特此提

原始

步驟 傳遞 進程 讀寫 使用 整數 註意 完整 raw 定義原始套接字的目的在於提供訪問某個協議的接口, 通過原始套接字, 進程可以讀寫ICMPv4, IGMPv4和ICMPv6等分組, 進程也可以讀寫內核不處理其協議字段的IPv4數據報, 進程還可以使用IP_HDRINC

原始 傳送 TCP SYN

通過原始套接字、setsockopt、IP_HDRINCL套接字選項,我們可以在應用程序裡面構造自己的IP包: 所以我們在初始化原始套接字之後,可以呼叫setsockopt函式來開啟IP_HDRINCL套接字選項,並且構造自己的IP頭,TCP/UDP頭,最後再像傳送普通包一樣呼叫sendt