wirshark发包工具源码

需要下载https://link.csdn.net/?target=https%3A%2F%2Fwww.winpcap.org%2Finstall%2Fbin%2FWpdPack_4_1_2.zip开源库并且使用。
目前只能发送udp的码流

#define HAVE_REMOTE
#define WPCAP
#pragma comment(lib,“wpcap.lib”)
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
#include<Winsock2.h>
#include
#include<windows.h>
#include “kdvtype.h”
#include<string.h>
#include <iphlpapi.h>

#pragma comment(lib,“ws2_32.lib”)
#pragma comment(lib,“iphlpapi.lib”)

using namespace std;

#define ETHER_ADDR_LEN 6
#define ETHERTYPE_PUP 0x0200 /* Xerox PUP /
#define ETHERTYPE_SPRITE 0x0500 /
Sprite /
#define ETHERTYPE_IP 0x0800 /
IP /
#define ETHERTYPE_ARP 0x0806 /
Address resolution /
#define ETHERTYPE_REVARP 0x8035 /
Reverse ARP /
#define ETHERTYPE_AT 0x809B /
AppleTalk protocol /
#define ETHERTYPE_AARP 0x80F3 /
AppleTalk ARP /
#define ETHERTYPE_VLAN 0x8100 /
IEEE 802.1Q VLAN tagging /
#define ETHERTYPE_IPX 0x8137 /
IPX /
#define ETHERTYPE_IPV6 0x86dd /
IP protocol version 6 /
#define ETHERTYPE_LOOPBACK 0x9000 /
used to test interfaces /
#define MaxQueueLength 2500000 /
max length of queue */
#define DATA_NO_ERROR 0
#define IP_HEADER_ERROR -1

s32 data_handle(pcap_pkthdr * &pktheader,const u8 * &pchBuffer,s32 nInDlt);
u16 CalcChecksum(u16 *pwBuffer, s32 nSize);

s8 *g_pachSrcIP = new char[20];//存储源IP地址
s8 *g_pachDstIP = new char[20];//存储目的IP地址
u16 g_wSport = 0;//发送端口
u16 g_wDport = 0;//接收端口
s8 errbuf[PCAP_ERRBUF_SIZE] = { 0 };//用于保存错误信息
s32 g_nRtpLen = 0;
u16 g_nOldPT = 0;
u16 g_nNewPT = 0;

//保存以太网首部
struct TEther_header
{
u8 ether_dhost[ETHER_ADDR_LEN]; //目的MAC地址
u8 ether_shost[ETHER_ADDR_LEN]; //源MAC地址
u16 ether_type; //帧类型
};

//保存IPV4首部
struct TIp_header
{
u8 ihl:4; //IP header length
u8 version:4; //IP version
u8 tos; //Type of service
u16 tot_len; //Total length
u16 id; //Unique identifier
u16 frag_off; //Fragment offset field
u8 ttl; //Time to live
u8 protocol; //Protocol type
u16 check; //IP checksum
unsigned int saddr; //Source address
unsigned int daddr; //Destination address
};

//保存TCP首部
struct TTcphdr
{
u16 srcport; // 源端口
u16 dstport; // 目的端口
u32 seqnum; // 顺序号
u32 acknum; // 确认号
u8 dataoff; // TCP头长
u8 flags; // 标志(URG、ACK等)
u16 window; // 窗口大小
u16 check; // 校验和
u16 urg_ptr; // 紧急指针
};

//保存UDP首部
struct TUdphdr
{
u16 source; //source port
u16 dest; //destination port
u16 len; //udp length
u16 check; //udp checksum
};

//保存RTP首部
struct TRtphdr
{
u16 cc:4; /* CSRC count /
u16 x:1; /
header extension flag /
u16 p:1; /
padding flag /
u16 v:2; /
packet type /
u16 pt:7; /
payload type /
u16 m:1; /
marker bit /
u16 seq; /
sequence number /
u32 ts; /
timestamp /
u32 ssrc; /
synchronization source */
};

//保存UDP伪首部
struct TPsd_Header
{
u32 sourceip; //源IP地址
u32 destip; //目的IP地址
u8 mbz; //置空(0)
u8 ptcl; //协议类型
u16 plen; //UDP数据包总长度(单位:字节)
};

void main()
{
s32 nPcaplen = 0;
s32 nErr = 0;
s32 nCont = 0;
s32 nRet = 0;
s32 nInDlt = 0;
s32 nIndex = 0;
s32 nGet = 0;
s32 nLoop = 0;
s32 nSend = 0;
s32 nBind = 0;
long lCurTvUsec = 0;
long lCurTvSec = 0;
long lLastTvUsec = 0;
long lLastTvSec = 0;
long lDifTvUsec = 0;
s8 *file = new char[20];
s8 *DstIP = new char[20];
s8 *SrcIP = new char[20];
s8 packet_filter[512] = {“ip and udp and not icmp”};
u16 wDstPort = 0;
u16 wSrcPort = 0;
unsigned int res = 0;
unsigned int netmask = 0;
pcap_send_queue *ptSqueue = NULL;
struct pcap_pkthdr pktheader = NULL;
struct bpf_program fcode;
const u8 pktdata = NULL;
pcap_t
ptIndev = NULL;
pcap_t
ptOutdev = NULL;
pcap_if_t *alldevs =NULL;
pcap_if_t *d = NULL;
FILE *fp = NULL;
pcap_if_t *ptTemp = NULL;
struct sockaddr_in tDstAddr;
struct sockaddr_in tSrcAddr;

//从配置文件获取数据
LPTSTR lpPath =LPTSTR(new char[MAX_PATH]);
strcpy((char *)lpPath,"./config.ini");
GetPrivateProfileString("FILTERINFO","SRC_IP",NULL,SrcIP,20,lpPath);//获取过滤的源IP,默认返回值NULL
GetPrivateProfileString("FILTERINFO","DST_IP",NULL,DstIP,20,lpPath);//获取过滤的目的IP,默认返回值NULL
GetPrivateProfileString("SENDINFO","SRC_IP",NULL,g_pachSrcIP,20,lpPath);//获取发送的源IP,默认返回值NULL
GetPrivateProfileString("SENDINFO","DST_IP",NULL,g_pachDstIP,20,lpPath);//获取发送的目的IP,默认返回值NULL
GetPrivateProfileString("FILE","NAME",NULL,file,20,lpPath);//由NAME字段获取文件名,默认返回值NULL
wSrcPort = (u16)GetPrivateProfileInt("FILTERINFO","SRC_PORT",0,lpPath);//获取过滤的源端口,默认返回值0
wDstPort = (u16)GetPrivateProfileInt("FILTERINFO","DST_PORT",0,lpPath);//获取过滤的目的端口,默认返回值0
g_wSport = (u16)GetPrivateProfileInt("SENDINFO","SRC_PORT",0,lpPath);//由SRC_PORT字段获取源端口,默认返回值0
g_wDport = (u16)GetPrivateProfileInt("SENDINFO","DST_PORT",0,lpPath);//由DST_PORT字段获取目的端口,默认返回值0
g_nOldPT = (u16)GetPrivateProfileInt("SETPT","OLDPT",0, lpPath);
g_nNewPT = (u16)GetPrivateProfileInt("SETPT", "NEWPT", 0, lpPath);

printf("+++wSrcPort:%d\n",wSrcPort);
//添加过滤条件
if(*SrcIP != '0')
{
	sprintf(packet_filter,"%s and src host %s",packet_filter,SrcIP);
}

if(*DstIP != '0')
{
	sprintf(packet_filter,"%s and dst host %s",packet_filter,DstIP);
}

if(wSrcPort != 0)
{
	sprintf(packet_filter,"%s and src port %u",packet_filter,wSrcPort);
}

if(wDstPort != 0)
{
	sprintf(packet_filter,"%s and dst port %u",packet_filter,wDstPort);
}

WSADATA WSAData;
WORD sockVersion = MAKEWORD(2,2);//当前版本号为2.2
if(WSAStartup(sockVersion,&WSAData)!=0)
{
	printf("WSAStartup error\n");
	return;
}

SOCKET nSockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //创建套接字
//判断创建是否成功
if(nSockfd == SOCKET_ERROR)
{
	printf("socket error:%d\n", WSAGetLastError);
	closesocket(nSockfd);
	return;
}

memset(&tSrcAddr,0,sizeof(tSrcAddr));
tSrcAddr.sin_family = AF_INET; //IP协议
tSrcAddr.sin_port = htons(g_wSport);//端口
tSrcAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//设置IP地址

nBind = bind(nSockfd,(SOCKADDR *)&tSrcAddr,sizeof(SOCKADDR));
if (nBind == SOCKET_ERROR)
{
	printf("bind error:%d\n", WSAGetLastError);
	closesocket(nSockfd);
	return;
}
memset(&tDstAddr,0,sizeof(tDstAddr));
tDstAddr.sin_family = AF_INET; //IP协议
tDstAddr.sin_port = htons(g_wDport);//端口
tDstAddr.sin_addr.S_un.S_addr = inet_addr(g_pachDstIP);//设置IP地址

/*s32 nFlag = 1;
if(setsockopt(nSockfd, IPPROTO_IP, IP_HDRINCL, (s8 *)&nFlag, sizeof(nFlag))<0)
{
    printf("setsockopt() error!/n");
	printf("错误代码是:%d\n",WSAGetLastError());
    closesocket(nSockfd);
	system("pause");
	return;   
}*/

//获取网卡接口列表
if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf) == -1)
{
	printf("error in pcap_findalldevs_ex:%s",errbuf);
	system("pause");
	return ;
}

printf("网络接口设备列表如下:\n");

for(d = alldevs; d!=NULL; d = d->next)
{
	printf("%d. %s", ++nIndex, d->name);
    if(d->description)
	{
		printf(" (%s)\n", d->description);
	}
    else
	{
		printf(" (No description available)\n");
	}
}

printf("\n请选择设备:\n");
while(1)
{
	cin>>nGet;
	if(nGet <=0 || nGet >nIndex)
	{
		printf("输入错误,请重新输入\n");
	}
	else
	{
		break;
	}
}

//跳转至指定设备
for(s32 i = 1; i < nGet; i++)
{
	alldevs = alldevs->next;
}
ptTemp = alldevs;

//打开pcap文件
nErr = fopen_s(&fp,file,"r");
if(nErr != 0)
{
	 printf("open pcap file error , please check file name\n");
	 pcap_freealldevs(ptTemp);
	 system("pause");
	 return;
}

//获取pcap文件长度
if(fseek(fp,0,SEEK_END) == -1)//错误返回-1
{
	perror("get pcap file length error:");//打印错误原因
	system("pause");
	return;
}
nPcaplen = ftell(fp) - sizeof(struct pcap_file_header);//ftell用于得到文件位置指针当前位置相对于文件首的偏移字节数
fclose(fp);

printf("是否循环发送:\n1.是  2.否\n");
cin>>nLoop;

do{
	//打开数据包文件并进行读取,数据格式与tcpdump和tcpslice兼容
	if((ptIndev = pcap_open_offline(file,errbuf))==NULL)
	{
		printf("pcap_open_offline error: %s\n",errbuf);//errbuf传递错误信息
		printf("warning :Pcapng format is not supported!\n");//无法打开pcapng文件,需要转化成pcap文件 
		pcap_freealldevs(ptTemp);
		system("pause");
		return;
	}	

	//获取数据包捕获描述符,查看数据包
	if((ptOutdev = pcap_open_live(ptTemp->name,//指定打开的设备名
		65536,//捕获数据的最大字节数
		1,    //设置混杂模式
		1000, //读取超时时间 单位:毫秒
		errbuf)) == NULL)
	{
		printf("pcap_open_live error :%s\n",errbuf);
		pcap_freealldevs(ptTemp);
		system("pause");
		return;
	}

	nInDlt = pcap_datalink(ptIndev);//获取链路层类型

	//这里只考虑以太网和Linux
	if(nInDlt!=DLT_EN10MB && nInDlt!=DLT_LINUX_SLL)
	{
		printf("program works only on Ethernet networks and Linux cooked capture!\n");
		pcap_freealldevs(ptTemp);
		system("pause");
		return;
	}

	//获取netmask
	if(ptTemp->addresses != NULL)
	{
		netmask = ((struct sockaddr_in*)(ptTemp->addresses->netmask))->sin_addr.S_un.S_addr;
	}
	else
	{
		netmask = 0xffffff;/* 255.255.255.0 */
	}

	//编译过滤器
	if(pcap_compile(ptIndev,&fcode,packet_filter,1,netmask)<0)
	{
		printf("compile error\n");
		printf("Warning :incorrect ip address or port!");
		pcap_freealldevs(ptTemp);
		system("pause");
		return;
	}

	if(pcap_setfilter(ptIndev,&fcode) < 0)
	{
		printf("setfilter error\n");
		pcap_freealldevs(ptTemp);
		system("pause");
		return;
	}

	//按帧发送
	while((res = pcap_next_ex(ptIndev, &pktheader, &pktdata)) == 1)
	{
		nCont++;
		nRet = data_handle(pktheader,pktdata,nInDlt);

		lDifTvUsec = (pktheader->ts.tv_sec-lLastTvSec)*1000+(pktheader->ts.tv_usec-lLastTvUsec)/1000;
		if(nCont == 1 || lDifTvUsec < 0)
		{
			lDifTvUsec = 0;
		}
		printf("ts.tv_sec = %ld , tv_usec =%ld  ", pktheader->ts.tv_sec, pktheader->ts.tv_usec);
		printf("lDifTvUsec= %ld  ",lDifTvUsec);
		Sleep(lDifTvUsec);

		nSend = sendto(nSockfd,(s8 *)pktdata,nRet,0,(struct sockaddr *)&tDstAddr, sizeof(SOCKADDR));
		printf("nSend = %d\n",nSend);
		if(nSend < 0)
		{
			printf("sendto error:%d\n", WSAGetLastError);
			goto stop;
		}
		
		lLastTvSec = pktheader->ts.tv_sec;//获取时间戳秒位
		lLastTvUsec = pktheader->ts.tv_usec;//获取时间戳毫秒位
	}

	/*//获取最后一个数据包,将最后一帧所在队列发送
	if (res == (unsigned int)-2)
	{
		nCont++;
		nRet = data_handle(pktheader,pktdata,nInDlt);

		lDifTvUsec = (pktheader->ts.tv_sec-lLastTvSec)*1000+(pktheader->ts.tv_usec-lLastTvUsec)/1000;

		nSend = sendto(nSockfd,(s8 *)pktdata,nRet,0,(struct sockaddr *)&tDstAddr, sizeof(SOCKADDR));
		printf("nSend = %d\n",nSend);
		if(nSend < 0)
		{
			printf("sendto error:%d\n", WSAGetLastError);
			goto stop;
		}

		lLastTvSec = 0;//获取时间戳秒位
		lLastTvUsec = 0;//获取时间戳毫秒位
	}*/

	lLastTvSec = 0;
	lLastTvUsec = 0;
	nCont = 0;
}while(nLoop == 1);

stop:
pcap_freealldevs(ptTemp);
pcap_close(ptIndev);
pcap_close(ptOutdev);
closesocket(nSockfd);
WSACleanup();
return;
}

/*=============================================================================
函 数 名: CalcChecksum
功 能: 校验和计算, 在外壳调用前保证为nSize偶数
算法实现: (可选项)
全局变量: 无
参 数: u16 wBuffer
s32 nSize 偶数
返 回 值: u16
=============================================================================
/
u16 CalcChecksum(u16 *pwBuffer, s32 nSize)
{
u32 dwCkSum = 0;

//把所有16位的字相加,如果遇到进位,则将高于16字节的进位部分的值加到最低位上
while (nSize > 1)
{
    dwCkSum += *pwBuffer++;
    nSize  -= sizeof(u16);
}
if(nSize)
{
    dwCkSum += *(u8*)pwBuffer;
}

dwCkSum  = (dwCkSum >> 16) + (dwCkSum & 0xffff);
dwCkSum += (dwCkSum >> 16);

return (u16)(~dwCkSum);//取反

}

/=============================================================================
函数名 :udp data_handle
功能 :数据包处理
算法实现 :(可选项)
引用全局变量:无
输入参数说明:
&pktheader 数据包头的引用
&pchBuffer 数据包内容的引用
nDlt 数据包文件描述符
&dwTimeStamp 数据包时间戳的引用
返回值说明: 正常返回DATA_NO_ERROR
=============================================================================
/
s32 data_handle(pcap_pkthdr * &pktheader,const u8 * &pchBuffer,s32 nDlt)
{
s32 nRtpLen = 0;
//对于Linux 只需偏移2个字节即可
if(nDlt == DLT_LINUX_SLL)
{
pchBuffer += 2;
pktheader->len -= 2;
pktheader->caplen -= 2;
}

TEther_header* ptEther_header  =  (TEther_header*)pchBuffer;//以太网首部指针
TIp_header* ptIp_header	=	(TIp_header*)(pchBuffer + sizeof(TEther_header));//IP数据头指针
TUdphdr* ptUdp_header  =  (TUdphdr*)(pchBuffer + sizeof(TEther_header) + sizeof(TIp_header));//UDP数据头指针
TRtphdr* ptRtp_header =  (TRtphdr*)(pchBuffer + sizeof(TEther_header) + sizeof(TIp_header)+sizeof(TUdphdr));//RTP数据头指针

pchBuffer = (u8 *)ptRtp_header;

if (ptRtp_header->pt == g_nOldPT)
{
	ptRtp_header->pt = g_nNewPT;
}

nRtpLen = htons(ptUdp_header->len)-8;
return nRtpLen;

}

/=============================================================================
函数名 :udp data_handle
功能 :数据包处理
算法实现 :(可选项)
引用全局变量:无
输入参数说明:
&pktheader 数据包头的引用
&pchBuffer 数据包内容的引用
nDlt 数据包文件描述符
&dwTimeStamp 数据包时间戳的引用
返回值说明: 正常返回DATA_NO_ERROR
=============================================================================
/
s32 tcp_data_handle(pcap_pkthdr * &pktheader,const u8 * &pchBuffer,s32 nDlt)
{
s32 nRtpLen = 0;
//对于Linux 只需偏移2个字节即可
if(nDlt == DLT_LINUX_SLL)
{
pchBuffer += 2;
pktheader->len -= 2;
pktheader->caplen -= 2;
}

TEther_header* ptEther_header  =  (TEther_header*)pchBuffer;//以太网首部指针
TIp_header* ptIp_header	=	(TIp_header*)(pchBuffer + sizeof(TEther_header));//IP数据头指针
//TUdphdr* ptUdp_header  =  (TUdphdr*)(pchBuffer + sizeof(TEther_header) + sizeof(TIp_header));//UDP数据头指针
//TRtphdr* ptRtp_header =  (TRtphdr*)(pchBuffer + sizeof(TEther_header) + sizeof(TIp_header)+sizeof(TUdphdr));//RTP数据头指针

TTcphdr* ptTcp_header  =  (TTcphdr*)(pchBuffer + sizeof(TEther_header) + sizeof(TIp_header));//TCP数据头指针
TRtphdr* ptRtp_header =  (TRtphdr*)(pchBuffer + sizeof(TEther_header) + sizeof(TIp_header)+sizeof(TTcphdr));//RTP数据头指针

pchBuffer = (u8 *)ptRtp_header;

if (ptRtp_header->pt == g_nOldPT)
{
	ptRtp_header->pt = g_nNewPT;
}
printf("+++pt:%d\n",ptRtp_header->pt);
nRtpLen = htons(ptTcp_header->window)-20;
return nRtpLen;

}

/*#define _CRT_SECURE_NO_WARNINGS // 消除fopen告警
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include
#include <winsock2.h>

#pragma comment(lib, “ws2_32.lib”)

int main(int argn, char*agrv[])
{
if(argn < 2)
{
printf(“请把要解析的文件作为第一个参数.\n”);
getchar();
return 0;
}

FILE *fp = fopen(agrv[1], "rb");
if (!fp) 
{
	printf("打开文件 %s 失败.\n", agrv[1]);
	getchar();
	return 0;
}

WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);

int Sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(2020);
sin.sin_addr.s_addr	= INADDR_ANY;//dwBindIp

if (bind(Sockfd, (struct sockaddr*) &sin, sizeof(sin)) < 0)
{
	printf("服务绑定端口%d失败,请检查端口是否被其他服务占用!\n", 2020);
	closesocket(Sockfd);
	return -1;
}

struct sockaddr_in dst;
memset(&dst, 0, sizeof(dst));
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = inet_addr("1.2.3.4");;
dst.sin_port = htons(2021);

char *buf = new char[64 * 1024];
int addr_len = sizeof(dst);
unsigned short rtp_len;
while (true)
{
	if (2 != fread(&rtp_len, 1, 2, fp))
		break;
	rtp_len = ntohs(rtp_len);
	printf("+++rtp_len:%d\n",rtp_len);
	if (rtp_len != fread(buf, 1, rtp_len, fp))
		break;
	printf("+++rtp_len1:%d\n",rtp_len);
	sendto(Sockfd, buf, rtp_len, 0, (sockaddr*)&dst, addr_len);
	Sleep(1);
}
printf("转换完毕.\n");
delete buf;
return 0;

}*/

config.ini配置文件
[FILTERINFO]
SRC_IP = 172.16.65.92
SRC_PORT = 554

DST_IP = 172.16.64.86
DST_PORT = 13591

[SENDINFO]
DST_IP = 172.16.131.171
DST_PORT = 50000

SRC_IP = 172.16.64.84
SRC_PORT = 59001

[FILE]
NAME = “rtsp_tcp2.pcap”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
wireshark源码分析问题这几天在看wireshark(ethereal)源代码。看源代码的主要兴趣点是它的分析模块(dissect)。分析之后他的数据存在哪儿,怎么打印的(-V参数)。我想把分析后的数据,提取出来,存在自己定义的数据结构里面,或者按我自己的格式写入文本中。 看了几天,对一些数据结构,似懂非懂,一些流程也是似懂非懂。可能由于经验不足的原因,搞来搞去就在几个函数,结构体里面打转。好几次以为找到切入点,发现又回来原来的起点。 这两天看晕了。有点打击,水平太差劲了。。呵呵。先这边问问,看看有没有熟悉的朋友。指点一下。先谢谢了。 这样问问题可能太细了。感觉也不大合适。 1. 我应该如何来看代码?如何找到突破点? 2. 有wireshark有了解的朋友,说说你们关于源码剖析的体会。 3. 说什么都可以,朋友觉得对我有用,有启发就好。千万别 “我顶,UP啊”。呵呵:emn23:我觉得重要的是看 pcap库 本帖最后由 peidright 于 2010-04-02 16:36 编辑 楼上说得对!。 看源代码之前,问下你自己,看代码的目的是什么? 对于 wireshark 来说,你是想学他写界面? 还是抓包? 还是业务逻辑? 界面的话,wireshark 还行 抓包的话,应该看pcap库 业务逻辑的话。不应该看wireshark,看tcpdump.看下啊,:em03:看看这个也许对你有帮助 添加一个基础的RDP解析器 下面我们将循序渐进地设计一个基础的RDP解析器。它依次包含如下构成要素: 包类型字段(占用8比特位,可能的值为:1,初始;2,终结;3,数据); 标志集字段(占用8比特位:0x01,始包;0x02,结束包;0x04先包); 序列号字段(占用16比特位); 1. 创建解析器 首先您需要选择解析器的类型:内置型(包含在主程序中)或插件型。 插件是容易编写的,先做一个插件型解析器吧。 例1. 解析器初始设定. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include void proto_register_rdp(); void proto_reg_handoff_rdp(); static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree); static int proto_rdp=-1; static dissector_handle_t rdp_handle; static gint ett_rdp = -1; define TCP_PORT_RDP 3389 void proto_register_rdp(void) { proto_rdp=proto_register_protocol( "RDP Protocol", "RDP", "rdp"); } 现在来逐一分析这段代码。首先我们有一些常规的包含文件,最好依惯例在文件始包含进来。随后是一些函数的前置声明,我们稍后定义它们。 接下来我们定义了一个整型变量"proto_rdp"用于记录我们的协议注册信息。它被初始化为"-1",当解析器注册到主程序中后,其值便会得到更新。这样做可保证我们方便地判断是否已经做了初始工作。将所有不打算对外输出的全局变量和函数声明为"static"是一个良好的习惯,因为这可以保证命名空间不被污染。通常这是容易做到的,除非您的解析器非常庞大以致跨越多个文件。 之后的模块变量"TCP_PORT_RDP"则包含了协议使用的TCP端口号,我们会对通过该端口的数据流进行解析。 solaris10下proc编译问题 >紧随其后的是解析器句柄"rdp_handle",我们稍后对它进行初始化。 至此我们已经拥有了和主程序交互的基本元素,接下来最好再把那些预声明的函数定义一下,就从注册函数"proto_register_rdp"始吧。 首先调用函数"proto_register_protocol"注册协议。我们能够给协议起3个名字以适用不同的地方。全名和短名用在诸如"首选项(Preferences)"和"已激活协议(Enabled protocols)"对话框以及记录中已生成的域名列表内。缩略名则用于过滤器。 下面我们需要一个切换函数。 例2. 解析器切换. void proto_reg_handoff_rdp(void) { static gboolean initialized=FALSE; if(!initialized) { rdp_handle = create_dissector_handle(dissect_rdp, proto_rdp); dissector_add("tcp.port", TCP_PORT_RDP, rdp_handle); initialized=TRUE; } } 这段代码做了什么呢?如果解析器尚未初始化,则对它进行初始化。首先创建解析器。这时注册了了函数"dissect_rdp"用于完成实际的解析工作。之后将该解析器与TCP端口号相关联,以使主程序收到该端口的UDP数据流时通知该解析器。 至此我们终于可以写一些解析代码了。不过目前我们仅写点儿基本功能占个位置。 例3.解析 static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree) { if(check_col(pinfo->cinfo, COL_PROTOCOL)) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDP"); } if(check_col(pinfo->cinfo,COL_INFO)) { col_clear(pinfo->cinfo,COL_INFO); } } 该函数用于解析传递给它的数据包。包数据由"tvb"参数指向的特殊缓冲区保管。现在我们已深入到协议的细节,对它们您肯定是了若指掌。包信息结构参数"pinfo"包含了协议的基本数据,以供我们更新。参数"tree"则指明了详细解析发生的地方。 这里我们仅做了保证通过的少量工作。前两行检查UI中"协议(Protocol)"列是否已显示。如果该列已存在,就在这儿显示我们的协议名称。这样人们就知道它被识别出来了。另外,如果"信息(INFO)"列已显示,我们就将它的内容清除。 至此我们已经准备好一个可以编译和安装的基本解析器。不过它目前只能识别和标示协议。 为了编译解析器并创建插件,还需要在解析器代码文件"packet-rdp.c"所在目录下创建一些提供支持的文件: - Makefile.am - UNIX/Linux的makefile模板 - Makefile.common - 包含了插件文件的名称 - Makefile.nmake - 包含了针对Windows平台的Wireshark插件makefile - moduleinfo.h - 包含了插件版本信息 - moduleinfo.nmake - 包含了针对Windows平台的DLL版本信息 - packet-rdp.c - 这是您的解析器原代码文件 - plugin.rc.in - 包含了针对Windows平台的DLL资源模板 "Makefile.common"和"Makefile.am"文件中涉及到相关文件和解析器名称的地方一定要修改正确。"moduldeinfo.h"和"moduleinfo.nmake"文件中的版本信息也需要正确填充。一切准备妥善后就可以将解析器编译为DLL或共享库文件了(使用nmake工具)。在wireshark文件夹下的"plugins"文件夹中,建立"rdp"文件夹。将修改过的Makefile.common,Makefile.am,moduleinfo.nmake,moduldeinfo.h,Makefile.nmake及packet-rdp.c文件考到"rdp"文件夹下,然后进行编译,rdp插件自动生成完整,就可以正常工作了。 1. 解析协议细节 现在我们已经有了一个可以运用的简单解析器,让我们再为它添点儿什么吧。首先想到的应该就是标示数据包的有效信息了。解析器在这方面给我们提供了支持。 首先要做的事情是创建一个子树以容纳我们的解析结果。这会使协议的细节显示得井井有条。现在解析器在两种情况下被调用http://www.boomss.com:其一,用于获得数据包的概要信息;其二,用于获得数据包的详细信息。这两种情况可以通过树指针参数"tree"来进行区分。如果树指针为NULL,我们只需要提供概要信息;反之,我们就需要拆解协议完成细节的显示了。基于此,让我们来增强这个解析器吧。 例4 static void dissect_rdp(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree) { proto_item *ti=NULLV; if(check_col(pinfo->cinfo,COL_PROTOCOL)) { col_set_str(pinfo->cinfo,COL_PROTOCOL,"RDP"); } if(check_col(pinfo->cinfo,COL_INFO)) { col_clear(pinfo->cinfo,COL_INFO); } if(tree) { ti = proto_tree_add_item(tree, proto_rdp, tvb, offset, -1, FALSE);} } 这里我们为解析添加一个子树。它将用于保管协议的细节,仅在必要时显示这些内容。 我们还要标识被协议占据的数据区域。在我们的这种情况下,协议占据了传入数据的全部,因为我们假设协议没有封装其它内容。因此,我们用"proto_tree_add_item"函数添加新的树结点,将它添加到传入的协议树"tree"中,用协议句柄"proto_rdp"标识它,用传入的缓冲区"tvb"作为数据,并将有效数据范围的起点设为"0",长度设为"-1"(表示缓冲区内的全部数据)。至于最后的参数"FALSE",我们暂且忽略。 做了这个更改之后,在包明细面板区中应该会出现一个针对该协议的标签;选择该标签后,在包字节面板区中包的剩余内容就会高亮显示。 现在进入下一步,添加一些协议解析功能。在这一步我们需要构建一组帮助解析的表结构。这需要对"proto_register_rdp"函数做些修改。首先定义一组静态数组。 例5 定义数据结构 static hf_register_info hf[]= { { &hf;_rdp_version, { "TPKT Header:Version", "rdp.version",

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值