网络扫描技术揭秘读书笔记3--TCP SYN扫描

时间:2022-02-25 01:05:56

TCP SYN扫描(使用Winpcap库实现)


0.核心原理

半开扫描(TCP SYN)不同于CSocket和Socket2扫描,后两者扫描都是完成了一个完整的三次握手(即connect函数),而半开扫描则只完成了两次握手就宣告结果,因为仅通过两次握手已读到了要读的数据

扫描函数的原理就是完成三次握手中的前两次,其中第一次是由扫描器向被扫描的服务器端发送SYN同步数据包第二次服务器端回复扫描器ACK确认数据包。按原“计划”,扫描器应该再向服务器发送一个ACK确认包完成三次握手,然而TCP SYN半开扫描在第三次握手时中止该操作或者向服务器端发送FIN结束数据包

1.使用核心库函数以及核心代码:

#include <pcap.h>
#include <iphlpapi.h>
#pragma comment(lib,"iphlpapi.lib")
#define DEF_BUF_SIZE 100
#define ACK_SYN 1
#define ACK_RST 0
#define ILLEGAL_FLAG -1
#define MAX_FRAME_LEN 1500
//IP地址转换处理
typedef union MultiByteStruct  
{//IP地址联合体  
    int iInt;   //int有符号整型  
    float fFloat;   //浮点数  
    UINT uInt;  //无符号整数  
    ULONG uLong;    //ULONG无符号整型  
    DWORD dwDword;  //DWORD有符号整型  
    WORD wWord[2];  //WORD无符号整型数组  
    UCHAR ucByte[4];    //无符号字符数组  
    char cByte[4];  //字符数组  
}UNIONIP,*PUNIONIP; 
SYNTHREADPARAM SynThreadParam;//传递给TCP SYNSCAN 线程的参数结构体
static USHORT g_uLocalPort=1240;//绑定的本地端口号

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

CString IPIntToStr(UINT IPInt)
{
	CString IPStr;  
	UNIONIP IP;  
	IP.uInt=IPInt;  
//	IPStr.Format(_T("%d.%d.%d.%d"),IP.ucByte[0],IP.ucByte[1],IP.ucByte[2],IP.ucByte[3]);
	IPStr.Format(_T("%d.%d.%d.%d"),IP.ucByte[3],IP.ucByte[2],IP.ucByte[1],IP.ucByte[0]);
	return IPStr;    
}

//char *->CString
void CharStrToCString(CString *str,const char *char_str)  
{
	int byteLen=strlen(char_str); 
	int Charlen=MultiByteToWideChar(CP_ACP,0,char_str,byteLen,NULL,0);  
	TCHAR *TcharTempItem=new TCHAR[Charlen+1];    
	MultiByteToWideChar(CP_ACP,0,char_str,byteLen,TcharTempItem,Charlen);  
	TcharTempItem[Charlen]='\0';
	*str=TcharTempItem;//*****
}

void  CPortScan_TCPDlg::SynScan_By_WinpCap(UNIONIP uIPBegin,UNIONIP uIPEnd,UINT uPortBegin,UINT uPortEnd)
{
	MessageBox(_T("sys scan by winpcap style..."));
	PSDHEADER psdHeader;    //伪TCP包头  
	UCHAR *tcp_packet_str=new UCHAR[MIN_TCPPACKET_LEN+1];
	PACKET tcp_packet;
	UINT SrcIp;
	// 获取本地地址信息
	char szLocalName[DEF_BUF_SIZE]={0};
	gethostname(szLocalName,DEF_BUF_SIZE);
	hostent* pHost=gethostbyname(szLocalName);
	if(pHost!=NULL)
		memcpy(&SrcIp,pHost->h_addr_list[0],pHost->h_length);
	else
		return ;
	//获取网卡设备句柄
	pcap_t *fp;
	pcap_if_t *d;
	GetAdapterHandle(&fp,&d);
	if(!fp)
		MessageBox(_T("获取网卡设备句柄失败!"));
	//recv response packet (ACK+SYN)
	//Theread:监听目标主机(UNIONIP uIPBegin,UNIONIP uIPEnd)的TCP响应数据包	
	SynThreadParam.fp=fp;
	SynThreadParam.d=d;
	SynThreadParam.uIPBegin=uIPBegin;
	SynThreadParam.uIPEnd=uIPEnd;
	SynThreadParam.SrcIp=SrcIp;
	SynThreadParam.ptr=this;
	CString strIP=IPIntToStr(uIPBegin.uInt);
	HTREEITEM curr=m_ctlTreeResult.InsertItem(strIP,1,1,TVI_ROOT); 
	SynThreadParam.TreeItem=curr;
	AfxBeginThread(ThreadRecvTCPSYNPacket,&SynThreadParam,THREAD_PRIORITY_IDLE);//监听返回的ACK+SYN数据包
	Sleep(1000);//预留做监听的准备时间   或者设置定时器判断  开始发送数据包的时间 12.16
	//end for 12.16
	for (UINT ip=uIPBegin.uInt;ip<=uIPEnd.uInt;ip++)  
	{
		BYTE SrcMac[6];
		BYTE DstMac[6];
		GetMacAddress(SrcMac);//
		GetMacAddrOfIP(ip,DstMac);//
		for(UINT port=m_uPortBegin;port<=m_uPortEnd;port++)  
		{ 
			memset(tcp_packet_str,0,MIN_TCPPACKET_LEN+1);
			memset(&tcp_packet,0,sizeof(PACKET));
			//EtherHeader part
			memcpy(tcp_packet.ethhead.DestMac,DstMac,6);
			memcpy(tcp_packet.ethhead.SrcMac,SrcMac,6);
			USHORT type=0x0800;//***以太网帧类型   0x0800  网际协议  ***
			tcp_packet.ethhead.Type=htons(type);

			//分别自己填充IP头、TCP头、伪TCP头,并计算其中的校验和  
			//设置IP头   
			tcp_packet.ipHeader.h_verlen=0x45;   
			tcp_packet.ipHeader.tos=0;   
			tcp_packet.ipHeader.total_len=htons(sizeof(IPHEADER)+sizeof(TCPHEADER));   
			tcp_packet.ipHeader.ident=1;   
			tcp_packet.ipHeader.frag_and_flags=0;   
			tcp_packet.ipHeader.ttl=128;   
			tcp_packet.ipHeader.proto=IPPROTO_TCP;   
			tcp_packet.ipHeader.checksum=0;   
			tcp_packet.ipHeader.sourceIP=SrcIp;   
			tcp_packet.ipHeader.destIP=htonl(ip);//   
			//设置TCP头   
			tcp_packet.translayer.tcpHeader.th_sport=htons(g_uLocalPort);   
			tcp_packet.translayer.tcpHeader.th_dport=htons(port); //
			tcp_packet.translayer.tcpHeader.th_seq=htonl(SEQ);  
			tcp_packet.translayer.tcpHeader.th_ack=0;   
			tcp_packet.translayer.tcpHeader.th_lenres=(sizeof(TCPHEADER)/4<<4|0);   
			tcp_packet.translayer.tcpHeader.th_flag=2; //2:SYN;1:FIN;16:ACK   
			tcp_packet.translayer.tcpHeader.th_win=htons(512);   
			tcp_packet.translayer.tcpHeader.th_urp=0;   
			tcp_packet.translayer.tcpHeader.th_sum=0;  
			//伪TCP头  
			psdHeader.saddr=tcp_packet.ipHeader.sourceIP;
			psdHeader.daddr=tcp_packet.ipHeader.destIP;   
			psdHeader.mbz=0;   
			psdHeader.ptcl=IPPROTO_TCP;   
			psdHeader.tcpl=htons(sizeof(TCPHEADER));   
			//TCP头校验和  checksum(PsdHeader+TcpHeader)
			char tempBuf[40];
			memcpy(tempBuf,&psdHeader,sizeof(PSDHEADER));
			memcpy(tempBuf+sizeof(psdHeader),&tcp_packet.translayer.tcpHeader,sizeof(TCPHEADER));
			tcp_packet.translayer.tcpHeader.th_sum=CheckSum((USHORT*)tempBuf,sizeof(PSDHEADER)+sizeof(TCPHEADER));
			//*****IP头校验和   checksum(IpHeader)
			memcpy(tempBuf,&tcp_packet.ipHeader,sizeof(IPHEADER));
			tcp_packet.ipHeader.checksum=CheckSum((USHORT*)tempBuf,sizeof(IPHEADER));
			//数据包流序列化
			memcpy(tcp_packet_str,(UCHAR*)&tcp_packet,sizeof(PACKET));
			SetDlgItemInt(IDC_PORT_EDIT,port);
			if(pcap_sendpacket(fp,tcp_packet_str,sizeof(PACKET)) != 0)//发送数据包  sizeof(PACKET)
			{
				MessageBox(_T("pcap_sendpacket()函数执行发生错误!"));
				return;
			}
		}
	}
}


//[in] Param :{fp,d,IP,ptr,TreeItem...}
UINT ThreadRecvTCPSYNPacket(LPVOID pParam)
{
	//capture,resolve,check  12.16
	SYNTHREADPARAM *SynThreadParam=(SYNTHREADPARAM *)pParam;
	pcap_t *fp=SynThreadParam->fp;
	pcap_if_t *d=SynThreadParam->d;
	UNIONIP uIPBegin=SynThreadParam->uIPBegin;
	UNIONIP uIPEnd=SynThreadParam->uIPEnd;
	UINT SrcIp=SynThreadParam->SrcIp;
	CPortScan_TCPDlg *ptr=SynThreadParam->ptr; 
    HTREEITEM curr=SynThreadParam->TreeItem; 
	
	const BYTE *pkt_data=new BYTE[MAX_FRAME_LEN];
	UINT res;
	struct pcap_pkthdr *header;
	char *packet_filter_str=new char[100];
	char SrcIp_str[16],DstIp_str[16];
	SOCKADDR_IN addr_src,addr_dst;
	struct bpf_program fcode;
	bpf_u_int32 NetMask;
	if(d->addresses->netmask)
		NetMask=((struct sockaddr_in *)d->addresses->netmask)->sin_addr.s_addr;
	else
		NetMask=0xffffff;
	//filter response tcp packets
	//tcp and ip src host (uIPBegin to uIPEnd)  and ip dst host localhost
	//	for (UINT ip=uIPBegin.uInt;ip<=uIPEnd.uInt;ip++)
	memset(packet_filter_str,0,100);
	strcpy(packet_filter_str,"tcp and ip src host ");
	addr_dst.sin_addr.S_un.S_addr=htonl(uIPBegin.uInt);//***only the first destination host(12.16)
	strcpy(SrcIp_str,inet_ntoa(addr_dst.sin_addr));//SrcIp
	strcat(packet_filter_str,SrcIp_str);
	strcat(packet_filter_str," and ip dst host ");
	addr_src.sin_addr.S_un.S_addr=SrcIp;
	strcpy(DstIp_str,inet_ntoa(addr_src.sin_addr));//DstIp
	strcat(packet_filter_str,DstIp_str);
	if(pcap_compile(fp, &fcode, packet_filter_str, 1, NetMask)<0)
	{
		AfxMessageBox(_T("Error compiling filter: wrong syntax."));
		return 1;
	}
	if(pcap_setfilter(fp, &fcode)<0)
	{
		AfxMessageBox(_T("Error setting the filter."));
		return 1;
	}
	int elapse_times=0;
	while((res=pcap_next_ex(fp,&header,&pkt_data))>=0)
	{
		if(elapse_times>10)//根据超时次数粗略确定已经没有余下的响应数据包
			break;
		if(res==0)
		{
		//	ptr->MessageBox(_T("获取报文超时!"));
			elapse_times++;
			continue;
		}
		//resolve received tcp_packet and check relevant bits
		PACKET *TcpPacket=(PACKET *)pkt_data;
		int iphead_len=((TcpPacket->ipHeader.h_verlen)&0x0f)*4;
		TCPHEADER *TcpHeader=(TCPHEADER *)(pkt_data+sizeof(ETHERNET_HEAD)+iphead_len);
		UCHAR flag=TcpHeader->th_flag;
		USHORT opened_port=ntohs(TcpHeader->th_sport);//ntohs()  12.16 p.m.
		CString strTemp;
		if(((flag&0x10)>>4)&((flag&0x02)>>1))//0 0 URG ACK PSH RST SYN FIN
		{
			struct servent *se;  
			CString strNameTemp;
			se=getservbyport(TcpHeader->th_sport,"tcp");  
			if(se!=NULL)  //get the info of the port and corresponding server name
			{
				strTemp.Format(_T("%d "),opened_port);
				CharStrToCString(&strNameTemp,se->s_name);
				strTemp+=strNameTemp;
			}
			else  
				strTemp.Format(_T("%d"),opened_port);  
			
			ptr->m_ctlTreeResult.InsertItem(strTemp,2,2,curr); //insert the port node into the tree
		}
	}

	if(res == -1)
	{
		AfxMessageBox(_T("Error reading the packets"));
		return 1;
	}
	ptr->MessageBox(_T("Finished SynScan..."));
	return 1;
}

void GetMacAddress(BYTE *mac_addr)
{
	IP_ADAPTER_INFO adapter[5];  //Maximum 5 adapters
	DWORD buflen=sizeof(adapter);
	DWORD status=GetAdaptersInfo(adapter,&buflen);
	BYTE s[8];
	if(status==ERROR_SUCCESS)
	{
		PIP_ADAPTER_INFO painfo=adapter;
		memcpy(s,painfo->Address,6);
		for(int i=0;i<6;i++)
		{
			mac_addr[i]=s[i];
		}
	}
}

void GetAdapterHandle(pcap_t **fp,pcap_if_t **d)
{
	pcap_if_t *alldevs;
	char errbuf[PCAP_ERRBUF_SIZE];
	int i,inum;//网卡设备编号
	if(pcap_findalldevs(&alldevs, errbuf) == -1)
	{
		AfxMessageBox(_T("pcap_findalldevs()函数执行发生错误!"));
		exit(1);
	}
	inum=3;//如何动态获取本地连接网卡  --需改进
	for (*d=alldevs, i=0; i< inum-1 ;*d=(*d)->next, i++);
	if ((*fp = pcap_open_live((*d)->name,65536,1,1000,errbuf)) == NULL)
	{
		AfxMessageBox(_T("打开适配器发生错误"));
		exit(1);
	}
}

void GetMacAddrOfIP(UINT ip,BYTE *mac_addr)
{
	//获取网卡设备句柄
	pcap_t *fp;
	pcap_if_t *d;	
	GetAdapterHandle(&fp,&d);
	if(!fp)
		AfxMessageBox(_T("获取网卡设备句柄失败!"));
	// 获取本地地址信息:IP和MAC
	UINT SrcIP;
	UINT DstIP=ip;//[in] formal parameter
	BYTE SrcMac[6];
	BYTE DstMac[6];
	char szLocalName[DEF_BUF_SIZE]={0};
	gethostname(szLocalName,DEF_BUF_SIZE);
	hostent* pHost=gethostbyname(szLocalName);
	if(pHost!=NULL)
		memcpy(&SrcIP,pHost->h_addr_list[0],pHost->h_length);
	else
		return ;
	GetMacAddress(SrcMac);
	memset(DstMac,0xff,6);
	//1.构造ARP请求包
	//SrcMac SrcIP  DstMac DstIP=ip
	ARP_PACKET arp_request;
	USHORT type=0x0806;
	USHORT hardware_type=0x0001;
	USHORT protocol_type=0x0800;
	BYTE mac_len=0x06;
	BYTE ip_len=0x04;
	USHORT option=0x0001;//1  Request
	//MAC Frame Head
	memset(&arp_request,0,sizeof(ARP_PACKET));
	memcpy(arp_request.EthHead.DestMac,DstMac,6);
	memcpy(arp_request.EthHead.SrcMac,SrcMac,6);
	arp_request.EthHead.Type=htons(type);
	//ARP Request Head
	arp_request.ArpFrame.hardware_type=htons(hardware_type);
	arp_request.ArpFrame.protocol_type=htons(protocol_type);
	arp_request.ArpFrame.add_len=mac_len;
	arp_request.ArpFrame.pro_len=ip_len;
	arp_request.ArpFrame.option=htons(option);
	memcpy(arp_request.ArpFrame.sour_addr,SrcMac,6);
	arp_request.ArpFrame.sour_ip=SrcIP;//SrcIP: net sequence
	memcpy(arp_request.ArpFrame.dest_addr,DstMac,6);
	arp_request.ArpFrame.dest_ip=htonl(DstIP);//DstIP UINT:host sequence 
	memset(arp_request.ArpFrame.padding,0x00,18);
	if(pcap_sendpacket(fp,(BYTE *)&arp_request,sizeof(arp_request)) != 0)
	{
		AfxMessageBox(_T("pcap_sendpacket()函数执行发生错误!"));
		return;
	}
	//2.recv arp response packet
	const BYTE *pkt_data;
	UINT res;
	struct pcap_pkthdr *header;
	char *packet_filter_str=new char[100];
	char mac_str[18];
	char ip_str[16];
	struct bpf_program fcode;
	bpf_u_int32 NetMask;
	if(d->addresses->netmask)//掩码不为空
		NetMask=((struct sockaddr_in *)d->addresses->netmask)->sin_addr.s_addr;
	else
		NetMask=0xffffff;//默认为 C类网络
	GetMacStrFromByte(SrcMac,mac_str);//MAC Str
	SOCKADDR_IN addr;
	addr.sin_addr.S_un.S_addr=htonl(DstIP);//************下面的innet_ntoa()参数是--网络上--的一个IP地址************
	strcpy(ip_str,inet_ntoa(addr.sin_addr));//IP Str
	//packet_filter_str="arp and ether dst str(SrcMac) and src host str(DstIP)"
	//packet_filter_str   +=  arp_request.ArpFrame.option=0x0002
	memset(packet_filter_str,0,100);
	strcpy(packet_filter_str,"arp and ether dst ");
	strcat(packet_filter_str,mac_str);
	strcat(packet_filter_str," and src host ");
	strcat(packet_filter_str,ip_str);
	if(pcap_compile(fp, &fcode, packet_filter_str, 1, NetMask)<0)
	{
		AfxMessageBox(_T("Error compiling filter: wrong syntax."));
		return;
	}
	if(pcap_setfilter(fp, &fcode)<0)
	{
		AfxMessageBox(_T("Error setting the filter."));
		return ;
	}
	/* Capture data */
	while((res = pcap_next_ex(fp,&header,&pkt_data))>=0)
	{
		if(res == 0)/* Timeout elapsed */
			continue;
		if(pkt_data)
			break;
	}
	if(res == -1)
	{
		AfxMessageBox(_T("Error reading the packets"));
		return;
	}
	//3.resolve response arp arp packet of sour_addr attribute
	//const BYTE * pkt_data  -->SrcMac
	ETHERNET_HEAD *Ether_Header=(ETHERNET_HEAD *)pkt_data;
	memcpy(mac_addr,Ether_Header->SrcMac,6);
}

void GetMacStrFromByte(BYTE *SrcMac,char *mac_str)
{
	/*
	In:  SrcMac={00,30,18,A3,D2,8E};
	Out: mac_str="00:30:18:A3:D2:8E"
	*/
	char *MacStr=new char[18];
	memset(MacStr,0,18);
	for(int i=0;i<6;i++)
	{
		MacStr[3*i]=GetHexChar((SrcMac[i]&0xf0)>>4);
		MacStr[3*i+1]=GetHexChar(SrcMac[i]&0x0f);
		if(i<=4)
			MacStr[3*i+2]=':';
	}
	strcpy(mac_str,MacStr);
}

char GetHexChar(BYTE HexNum)
{
	if(HexNum>=0&&HexNum<=9)
		return '0'+HexNum;
	else if(HexNum>=0xA&&HexNum<=0xF)
		return 'A'+HexNum-0xA;
	else
	{
		AfxMessageBox(_T("Illegal HexNum!"));
		return 0;
	}
}


2.运行结果分析:

(1)

TCP SYN扫描结果:发现目标主机出现超时重ACK+SYN 数据包的现象

网络扫描技术揭秘读书笔记3--TCP SYN扫描

第一个重传(TCP Retransmission)的数据包是来自目标主机的端口netbios-ssn(139)的数据包

网络扫描技术揭秘读书笔记3--TCP SYN扫描

使用Wireshark工具得到该数据包的SEQ/ACK分析:判断为可疑的重传数据包


网络扫描技术揭秘读书笔记3--TCP SYN扫描

(2)

添加端口对应的服务名称之后,最终的运行结果:
网络扫描技术揭秘读书笔记3--TCP SYN扫描

(3)使用nmap扫描工具进行对比:

网络扫描技术揭秘读书笔记3--TCP SYN扫描

3.忽略掉的问题

只扫描了知名端口(1-1024);

没有动态识别本地连接对应的网卡;

没有对重传数据包的判定;

只考虑了对单一主机的扫描,没有考虑多个目标主机的情况;

获取的端口服务名只是使用getservbyport()从本地配置文件读取;

接收TCP响应包的线程函数的退出仅仅根据超时次数,没有恰当处理退出的条件;

其它

......


4.定义的相关数据结构

#pragma pack (1)
typedef struct SYNThreadParamStruct
{
	pcap_t *fp;
	pcap_if_t *d;
	UNIONIP uIPBegin;
	UNIONIP uIPEnd;
	UINT SrcIp;
	CPortScan_TCPDlg *ptr; 
    HTREEITEM TreeItem; 
}SYNTHREADPARAM;

//以太网帧头
typedef struct _ETHERNET_HEAD
{
	BYTE DestMac[6];//目的MAC地址
	BYTE SrcMac[6];//源MAC地址
	USHORT Type;//协议类型 IP(0x0800) ARP(0x0806是ARP帧的类型值)  RARP
}ETHERNET_HEAD;//14Bytes

typedef struct _ARP_HEADER
{ 
	//固定头长度:28Bytes
	USHORT hardware_type; //硬件类型:以太网接口类型为1 
	USHORT protocol_type; //协议类型:IP协议类型为0X0800 
	BYTE add_len; //硬件地址长度:MAC地址长度为6B 
	BYTE pro_len; //协议地址长度:IP地址长度为4B 
	USHORT option; //操作:ARP请求为1,ARP应答为2 
	BYTE sour_addr[6]; //源MAC地址:发送方的MAC地址 
	UINT sour_ip; //源IP地址:发送方的IP地址 
	BYTE dest_addr[6]; //目的MAC地址:ARP请求中该字段没有意义;ARP响应中为接收方的MAC地址 
	UINT dest_ip; //目的IP地址:ARP请求中为请求解析的IP地址;ARP响应中为接收方的IP地址
	BYTE padding[18]; //填充字符长度=以太网最小帧长(64Bytes)-MAC帧头(14Bytes)-ARP包固定长度(28Bytes)-帧校验序列FCS(4Bytes)
}ARP_HEADER,*PARP_HEADER; 

// ARP Packet = ETHERNET_HEAD + ARP_HEADER
typedef struct _ARP_PACKET
{
	ETHERNET_HEAD EthHead;
	ARP_HEADER ArpFrame;
}ARP_PACKET,*PARP_PACKET;

typedef struct _iphdr  
{  
    unsigned char h_verlen;     //4位IP版本号+4位首部长度
    unsigned char tos;  //8位服务类型TOS  
    unsigned short total_len;   //16位总长度(字节)  
    unsigned short ident;   //16位标识  标记当前分片为第几个分片
    unsigned short frag_and_flags;  //3位标志位+13位片偏移
    unsigned char ttl;  //8位生存时间 TTL  
    unsigned char proto;    //8位协议(TCP、UDP或其他协议)  
    unsigned short checksum;    //16位IP首部校验和  
    unsigned int sourceIP;  //32位源IP地址  
    unsigned int destIP;    //32位目的IP地址  
}IPHEADER;  

//TCP伪首部的作用主要是进行校验和的计算  
typedef struct psd_hdr  //定义TCP伪首部   12Bytes
{   
    unsigned long saddr;    //源地址   
    unsigned long daddr;    //目的地址   
    char mbz;   
    char ptcl;  //协议类型   
    unsigned short tcpl;    //TCP长度   
}PSDHEADER;  
 
typedef struct _tcphdr  //定义TCP首部  
{  
    USHORT th_sport;    //16位源端口  
    USHORT th_dport;    //16位目的端口  
    unsigned int th_seq;    //32位序列号  
    unsigned int th_ack;    //32位确认号 
    unsigned char th_lenres;    //4位首部长度/6位保留字  
    unsigned char th_flag;  //6位标志位 
    USHORT th_win;  //16位窗口大小  
    USHORT th_sum;  //16位校验和  
    USHORT th_urp;  //16位紧急数据偏移量  
}TCPHEADER;  
  
//数据包
typedef struct _packet  
{  
	ETHERNET_HEAD  ethhead;
    IPHEADER ipHeader;  
    union Translayer  
    {  
		TCPHEADER tcpHeader;  
        UDPHEADER udpHeader;  
        ICMPHEADER icmpHeader;  
    }translayer;  
	//char padding[10];//填充字符
}PACKET;  

#pragma pack()