1. 程式人生 > >原始套接字實現

原始套接字實現

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#ifdef WIN32
#include <Winsock2.h>
#include <ws2ipdef.h>
#include <WS2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#endif

#ifdef WIN32
#pragma comment(lib,"ws2_32.lib")
#else
#define SOCKET_ERROR -1
typedef int BOOL;
#endif



#define  DEFAULT_PORT 10089


typedef struct ip_head
{ 
	union 
	{  
		unsigned char Version;  
		unsigned char HeadLen; 
	};
	unsigned char ServiceType; 
	unsigned short TotalLen; 
	unsigned short Identifier; 
	union 
	{  
		unsigned short Flags; 
		unsigned short FragOffset; 
	}; 
	unsigned char TimeToLive; 
	unsigned char Protocol; 
	unsigned short HeadChecksum; 
	unsigned int SourceAddr; 
	unsigned int DestinAddr; 
}IP_HEADER;


/*
 * TCP header.
 * Per RFC 793, September, 1981.
 */
typedef struct tcp_head {
	u_short th_sport;               /* source port */
	u_short th_dport;               /* destination port */
	unsigned int th_seq;                 /* sequence number */
	unsigned int th_ack;                 /* acknowledgement number */
	unsigned char th_lenres;
	u_char  th_flags;
	u_short th_win;                 /* window */
	u_short th_sum;                 /* checksum */
	u_short th_urp;                 /* urgent pointer */
}TCP_HEADER;

//tcp偽報頭
typedef struct psd_hdr
{
	unsigned long saddr;
	unsigned long daddr;
	char mbz;
	char ptcl; //協議型別
	unsigned short tcpl;  //tcp長度
}PSD_HEADER;

typedef struct udp_head
{
	unsigned short uh_sport;
	unsigned short uh_dport;
	unsigned short uh_len;
	unsigned short uh_sum;
}UDP_HEADER;

struct tcpiphdr
{
	ip_head ipHead;
	tcp_head tcpHead;
};

void InitSocket()
{
#ifdef WIN32
	WSADATA wsaData; 
	WORD wVersionRequested = MAKEWORD(2, 2); 
	int err = WSAStartup(wVersionRequested, &wsaData); 
	if(err != 0)
	{
		printf("windows socket DLL initiates faild\n");
		exit(-1);
	}
#endif
}


int GetErrNo()
{
#ifdef WIN32
	return WSAGetLastError();
#else
	return errno;
#endif
}

const char* GetErrStr(int errnum)
{
	#ifdef WIN32
	return "請檢視msdn幫助文件或定義winerror.h";
#else
	return strerror(errnum);
#endif
}
//設定虛擬IP地址
void SetVirtualIp(int fd, const char* userIp)
{
	bool flag = true;
	if(setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char *) &flag,sizeof(flag))==SOCKET_ERROR)
	{
		printf("windows socket DLL initiates faild\n");
		exit(-1);
	}
}

unsigned short CheckSum(unsigned short *buffer, int size)
{
	unsigned long cksum = 0;
	while(size > 0)
	{
		cksum += *buffer;
		size -= sizeof(unsigned short );
	}
	if (size)
	{
		cksum += *(unsigned short*)buffer;
	}
	cksum = (cksum >> 16) + (cksum & 0xffff);
	cksum += (cksum >> 16);
	return (unsigned short )(~cksum);
}

void WriteTcpPkg(const char* sourceIp, const char* destIp, unsigned int destPort,  char* szBuffer )
{
	int iTotalSize = sizeof(ip_head) + sizeof(tcp_head);
	int iIpVersion = 4;
	int iIpSize = sizeof(ip_head)/sizeof(unsigned long);
	ip_head ipHead;
	tcp_head tcpHead;
	psd_hdr psdHead;

	ipHead.Version = (iIpVersion << 4) | iIpSize;
	//ipHead.ServiceType = 0;
	ipHead.TotalLen = htons(iTotalSize);
	ipHead.Identifier = 1;
	ipHead.FragOffset = 0;
	ipHead.TimeToLive = 128;
	ipHead.Protocol = IPPROTO_TCP;
	ipHead.HeadChecksum = 0;
	ipHead.SourceAddr =	inet_addr(sourceIp);
	ipHead.DestinAddr = inet_addr(destIp);

	tcpHead.th_sport = htons(DEFAULT_PORT);
	tcpHead.th_dport = htons(destPort);
	tcpHead.th_seq = htonl(0x12345678);
	tcpHead.th_ack = 0;
	tcpHead.th_lenres = (sizeof(tcp_head)/4 << 4 | 0);
	tcpHead.th_flags = 2;  //標誌位探測  2是syn
	tcpHead.th_win = htons(512);
	tcpHead.th_urp = 0;
	tcpHead.th_sum = 0;

	psdHead.saddr = ipHead.SourceAddr;
	psdHead.daddr = ipHead.DestinAddr;
	psdHead.mbz = 0;
	psdHead.ptcl = IPPROTO_TCP;
	psdHead.tcpl = htons(sizeof(tcp_head));

	//計算校驗和
	memcpy(szBuffer, &psdHead, sizeof(psdHead)); 
	memcpy(szBuffer + sizeof(psdHead), &tcpHead, sizeof(tcpHead)); 
	tcpHead.th_sum = CheckSum( (unsigned short*)szBuffer, sizeof(psdHead) + sizeof(tcpHead));


	memcpy(szBuffer, &ipHead, sizeof(ipHead));
	memcpy(szBuffer + sizeof(ipHead), &tcpHead, sizeof(tcpHead));
	memset(szBuffer + sizeof(ipHead) + sizeof(tcpHead), 0, sizeof(int)); 
	ipHead.HeadChecksum = CheckSum((unsigned short*)szBuffer, sizeof(ipHead) + sizeof(tcpHead));

	memcpy(szBuffer, &ipHead, sizeof(ipHead));
}



void MyConnectTcp(sockaddr_in &servaddr)
{
	int fd = socket(AF_INET, SOCK_DGRAM, 0);
	int r = connect(fd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	int ret = sendto(fd, "hello", 5, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
	struct sockaddr_in clientaddr;
	socklen_t size = sizeof(clientaddr);
	char szBuf[1024];
	ret = recvfrom(fd, szBuf, 1024, 0,(struct sockaddr*)&clientaddr, &size);
}

int main(int argc, char** argv)
{
	if(argc < 5)
	{
		printf("usage : tm_client servIp servPort data userIp\n");
		exit(-1);
	}
	char 	servIp[64], userIp[64], workfId[16];
	int port = atoi(argv[2]);
	strcpy(servIp, argv[1]);
	strcpy(workfId, argv[3]);
	strcpy(userIp, argv[4]);
	struct sockaddr_in servaddr;

	InitSocket();

	//建立原始套接字,需要有超級使用者的許可權
	int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if( fd == SOCKET_ERROR)
	{
		printf("%s\n", GetErrStr(GetErrNo()));
		printf("socket函式執行失敗\n");
		return 1;
	}
	
	//Header is included with data. 報文將由自己組裝,以資料的形式進行傳送
	BOOL flag = true;
	if(setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
	{
		printf("%d", GetErrNo());
		printf("set socket IP_HDRINCL faild\n");
		exit(-1);
	}

	//設定超時
	int nTimeOver = 1000;
	if(setsockopt(fd,SOL_SOCKET,SO_SNDTIMEO,(char *)&nTimeOver,sizeof(nTimeOver))==SOCKET_ERROR)
	{
		printf("%d", GetErrNo());
		printf("set socket SO_SNDTIMEO faild\n");
		exit(-1);
	}

	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = inet_addr(servIp);
	servaddr.sin_port = htons(port);


	char szDataBuf[1024];
	
	memset(szDataBuf, 0, sizeof(szDataBuf));

	int ipsize = sizeof(ip_head), tcpsize = sizeof(tcp_head);
	int iTotalSize = sizeof(ip_head) + sizeof(tcp_head);
	WriteTcpPkg(userIp, servIp, port, szDataBuf);

	//此處在XP系統下會返回錯誤碼WSAEINTR,表示通過WSACancelBlockingCall函式中斷了,xp sp2及以上版本都會遇到這個問題
	if(sendto(fd, szDataBuf, iTotalSize, 0, (struct sockaddr*)&servaddr, sizeof(servaddr)) == SOCKET_ERROR)
	{
		printf("sendto message faild, errno = %d\n", GetErrNo());
		exit(-1);
	}


	struct sockaddr_in cliaddr;
	socklen_t cliLen = sizeof(cliaddr);

	if( recvfrom(fd,szDataBuf, sizeof(iTotalSize), 0, (struct sockaddr*)&cliaddr, &cliLen) < 0)
	{
		printf("recvfrom message faild\n");
		exit(-1);
	}

#ifdef WIN32
	closesocket(fd);
	WSACleanup();
#else
  close(fd);
#endif
	return 0;
}

相關推薦

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

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

原始實現網路監聽

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

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

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

原始實現

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

原始實現--arp欺騙

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

ping 程式(vc6.0 原始實現

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

利用原始實現tracert路由追蹤

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

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

Windows網路程式設計(七):原始開發

在呼叫socket()函式時,如果將第二個引數填為SOCK_RAW,代表建立的是原始套接字型別,第三個引數可以選擇IPPROTO_ICMP、IPPROTO_TCP、IPPROTO和IPPROTO_RAW。 #include <winsock2.h> #pragma co