原始套接字来两种类型:1)在IP头中使用预定义的协议,ICMP
2) 在IP头中使用自定义的协议
创建可以是 socket / WSASocket 只不过要将套接字设置为 SOCK_RAW
注意 WIDNOWS XP SP2 已经不再支持原始TCP数据的发送了
下面的内容MSDB没有显示完全 ,小菜在各种网络搜索得到:
int setsockopt(
__in SOCKET s, //<span style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14.44444465637207px; line-height: 26px;">s(套接字): 指向一个打开的套接口描述字</span>
__in int level,
__in int optname,
__in const char *optval,
__in int optlen
);
level:(级别): 指定选项代码的类型。 4种类型:
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname(选项名):选项名称 每种level 对应几种选项名
SOL_SOCKET:
SO_BROADCAST 允许发送广播数据 int
适用於 UDP socket。其意义是允许 UDP socket 「广播」(broadcast)讯息到网路上。
SO_DEBUG 允许调试 int
SO_DONTROUTE 不查找路由 int
SO_ERROR 获得套接字错误 int
SO_KEEPALIVE 保持连接 int
检测对方主机是否崩溃,避免(服务器)永远阻塞于TCP连接的输入。 设置该选项后,如果2小时内在此套接口的任一方向都没有数据交换,TCP就自动给对方 发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况: 对方接收一切正常:以期望的 ACK响应。2小时后,TCP将发出另一个探测分节。 对方已崩溃且已重新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接 口本身则被关闭。 对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图得到 一个响应。在发出第一个探测分节11分钟15秒后若仍无响应就放弃。套接口的待处理错 误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable (主机不 可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为 EHOSTUNREACH。
SO_DONTLINGER 若为真,则SO_LINGER选项被禁止。
SO_LINGER 延迟关闭连接 struct linger
上面这两个选项影响close行为
选项 间隔 关闭方式 等待关闭与否
SO_DONTLINGER 不关心 优雅 否
SO_LINGER 零 强制 否
SO_LINGER 非零 优雅 是
若 设置了SO_LINGER(亦即linger结构中的l_onoff域设为非零,参见2.4,4.1.7和4.1.21各节),并设置了零超时间隔,则 closesocket()不被阻塞立即执行,不论是否有排队数据未发送或未被确认。这种关闭方式称为“强制”或“失效”关闭,因为套接口的虚电路立即被 复位,且丢失了未发送的数据。在远端的recv()调用将以WSAECONNRESET出错。
若设置了SO_LINGER并确定了非零的超时间 隔,则closesocket()调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为“优雅的”关闭。请注意如果套接口置为非阻塞且 SO_LINGER设为非零超时,则closesocket()调用将以WSAEWOULDBLOCK错误返回。
若在一个流类套接口上设置了 SO_DONTLINGER(也就是说将linger结构的l_onoff域设为零,则 closesocket()调用立即返回。但是,如果可能,排队的数据将在套接口关闭前发送。请注意,在这种情况下WINDOWS套接口实现将在一段不确 定的时间内保留套接口以及其他资源,这对于想用所以套接口的应用程序来说有一定影响。
IPPROTO_IP:
IP_HDRINCL 在数据包中包含IP首部 int
这个选项常用于黑客技术中,隐藏自己的IP地址
IP_OPTINOS IP首部选项 int
IP_TOS 服务类型
IP_TTL 生存时间 int
TCP_NODELAY
TCP_CORK
CP_NODELAY 和 TCP_CORK,
这 两个选项都对网络连接的行为具有重要的作用。许多UNIX系统都实现了TCP_NODELAY选项,但是,TCP_CORK则是Linux系统所独有的而 且相对较新;它首先在内核版本2.4上得以实现。此外,其他UNIX系统版本也有功能类似的选项,值得注意的是,在某种由BSD派生的系统上的 TCP_NOPUSH选项其实就是TCP_CORK的一部分具体实现。
TCP_NODELAY和TCP_CORK基本上控制了包的 “Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。John Nagle是Nagle算法的发明人,后者就是用他的名字来命名的,他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题(欲了解详情请参 看IETF RFC 896)。他解决的问题就是所谓的silly window syndrome ,中文称“愚蠢窗口症候群”,具体含义是,因为普遍终端应用程序每产生一次击键操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据载荷以及40 个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞,。 Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了,但在我们看来,有些场合下把这一选项关掉也是合乎需要的。
现 在让我们假设某个应用程序发出了一个请求,希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发送 数据,那么交互性的以及客户/服务器型的应用程序将极大地受益。例如,当我们正在发送一个较短的请求并且等候较大的响应时,相关过载与传输的数据总量相比 就会比较低,而且,如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成,这样就禁用了Nagle算 法。
另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据,这种数据传输方式有益于大量数据的通信性能,典型的应用就是文件服 务器。应用 Nagle算法在这种情况下就会产生问题。但是,如果你正在发送大量数据,你可以设置TCP_CORK选项禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。下面就让我们仔细分析下其工作原理。
假设应用程序 使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据,这些信息其实就是报头内容。典型情况下报头很小,而且套接字 上设置了TCP_NODELAY。有报头的包将被立即传输,在某些情况下(取决于内部的包计数器),因为这个包成功地被对方收到后需要请求对方确认。这 样,大量数据的传输就会被推迟而且产生了不必要的网络流量交换。
但是,如果我们在套接字上设置了TCP_CORK(可以比喻为在管道上插入 “塞子”)选项,具有报头的包就会填补大量的数据,所有的数据都根据大小自动地通过包传输出去。当数据传输完成时,最好取消TCP_CORK 选项设置给连接“拔去塞子”以便任一部分的帧都能发送出去。这同“塞住”网络连接同等重要。
总而言之,如果你肯定能一起发送多个数据集合(例如HTTP响应的头和正文),那么我们建议你设置TCP_CORK选项,这样在这些数据之间不存在延迟。能极大地有益于WWW、FTP以及文件服务器的性能,同时也简化了你的工作。示例代码如下:
intfd, on = 1;
…
/* 此处是创建套接字等操作,出于篇幅的考虑省略*/
…
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* cork */
write (fd, …);
fprintf (fd, …);
sendfile (fd, …);
write (fd, …);
sendfile (fd, …);
…
on = 0;
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* 拔去塞子 */
optval(选项值):是一个指向变量的指针 类型:整形,套接口结构, 其他结构类型:linger{}, timeval{ }
optlen(选项长度) :optval 的大小
SYN(synchronous)是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN+ACK应答表示接收到了这个消息,最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。
SYN攻击属于DDoS攻击的一种,它利用TCP协议缺陷,通过发送大量的半连接请求,耗费CPU和内存资源。SYN攻击除了能影响主机外,还可以危害路由器、防火墙等网络系统,事实上SYN攻击并不管目标是什么系统,只要这些系统打开TCP服务就可以实施。服务器接收到连接请求(syn= j),将此信息加入未连接队列,并发送请求包给客户(syn=k,ack=j+1),此时进入SYN_RECV状态。当服务器未收到客户端的确认包时,重发请求包,一直到超时,才将此条目从未连接队列删除。配合IP欺骗,SYN攻击能达到很好的效果,通常,客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。
检测SYN攻击:
当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。我们使用系统自带的netstat 工具来检测SYN攻击:
# netstat -n -p TCP
-n 以数字形式显示地址和端口号。
-p proto 显示 proto 指定的协议的连接;proto 可以是下列任
何一个: TCP、UDP、TCPv6 或 UDPv6。如果与 -s 选
项一起用来显示每个协议的统计,proto 可以是下列任
何一个: IP、IPv6、ICMP、ICMPv6、TCP、TCPv6、UDP
TCP 192.168.0.101:27309 192.168.0.101:168 SYN_SENT
TCP 192.168.0.101:27310 192.168.0.101:169 SYN_SENT
TCP 192.168.0.101:27311 192.168.0.101:170 SYN_SENT
TCP 192.168.0.101:27312 192.168.0.101:171 SYN_SENT
TCP 192.168.0.101:27313 192.168.0.101:172 SYN_SENT
TCP 192.168.0.101:27314 192.168.0.101:173 SYN_SENT
TCP 192.168.0.101:27315 192.168.0.101:174 SYN_SENT
TCP 192.168.0.101:27316 192.168.0.101:175 SYN_SENT
TCP 192.168.0.101:27317 192.168.0.101:176 SYN_SENT
TCP 192.168.0.101:27318 192.168.0.101:177 SYN_SENT
TCP 192.168.0.101:27319 192.168.0.101:178 SYN_SENT
TCP 192.168.0.101:27320 192.168.0.101:179 SYN_SENT
TCP 192.168.0.101:27321 192.168.0.101:180 SYN_SENT
TCP 192.168.0.101:27322 192.168.0.101:181 SYN_SENT
TCP 192.168.0.101:27323 192.168.0.101:182 SYN_SENT
TCP 192.168.0.101:27324 192.168.0.101:183 SYN_SENT
TCP 192.168.0.101:27325 192.168.0.101:184 SYN_SENT
TCP 192.168.0.101:27326 192.168.0.101:185 SYN_SENT
在WINDOWS系统中是SYN_RECEIVED状态,源IP地址都是随机的,表明这是一种带有IP欺骗的SYN攻击。
netstat -n -p TCP | find "192.168.0.101" 查看全部链接
防范技术:
关于SYN攻击防范技术,人们研究得比较早。归纳起来,主要有两大类,一类是通过防火墙、路由器等过滤网关防护,另一类是通过加固TCP/IP协议栈防范
丰富带宽资源
不难看出syn攻击消耗带宽资源所以要想防御synflood一个丰富的带宽资源是必要的,通常的流量攻击,攻击者也是利用肉鸡的带宽资源来达到攻击堵死网络的,所以这个是一个前提
防火墙
利用防火墙来进行防护攻击是目前最有效的方法
SYN代码:
#include "stdafx.h"
#include <string.h>
#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"WS2_32")
#include <WS2TCPIP.h>
#include <time.h>
// New WSAIoctl Options
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
#define SIO_RCVALL_MCAST _WSAIOW(IOC_VENDOR,2)
#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
#define SIO_ABSORB_RTRALERT _WSAIOW(IOC_VENDOR,5)
#define SIO_UCAST_IF _WSAIOW(IOC_VENDOR,6)
#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)
#define SIO_INDEX_BIND _WSAIOW(IOC_VENDOR,8)
#define SIO_INDEX_MCASTIF _WSAIOW(IOC_VENDOR,9)
#define SIO_INDEX_ADD_MCAST _WSAIOW(IOC_VENDOR,10)
#define SIO_INDEX_DEL_MCAST _WSAIOW(IOC_VENDOR,11)
typedef struct _iphdr
{
unsigned char h_lenver; //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首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;
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位紧急数据偏移量
}TCP_HEADER;
struct //定义TCP伪首部
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}psd_header;
SOCKET sockRaw = INVALID_SOCKET,sockListen = INVALID_SOCKET;
int BeginPort,EndPort;
char *HOST;
int iErrorCode;
struct sockaddr_in dest;
BOOL StopScan = FALSE;
#define SEQ 0x28376839
void CheckSockError(int ierror,char *pErrorMsg)
{
if (ierror == SOCKET_ERROR)
{
printf("%s ErrorCode:%d\n",pErrorMsg,ierror);
closesocket(sockRaw);
ExitProcess(-1);
}
}
void meesage()
{
printf("\t-------syn by panda--------------------------\n");
printf("\t-------syn_test [ip] [port-port]-------------\n");
printf("\t-------example: syn_test 127.0.0.1 1-1000----\n");
}
BOOL DecodeIPHeader(char *RecvBuf)
{
IP_HEADER *iphdr = (IP_HEADER*)RecvBuf;
unsigned short iphdrlen = sizeof(unsigned long) * (iphdr->h_lenver&0xf);
TCP_HEADER* tcphdr = (TCP_HEADER*)(RecvBuf + iphdrlen);
if (iphdr->sourceIP != dest.sin_addr.s_addr)
{
return FALSE;
}
if (ntohl(tcphdr->th_ack) != (SEQ+1) && ntohl(tcphdr->th_ack) != SEQ)
{
return FALSE;
}
if (tcphdr->th_flag == 18)
{
printf("\t%d open \n",ntohs(tcphdr->th_sport));
return true;
}
return FALSE;
}
DWORD WINAPI RecvThread(LPVOID para)//接受数据线程
{
//监听本机套接字
sockListen = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
CheckSockError(sockListen,"RecvThread` socket");
BOOL bOpt =true;
iErrorCode = setsockopt(sockRaw,IPPROTO_IP,IP_HDRINCL,(char*)&bOpt,sizeof(bOpt));
CheckSockError(iErrorCode,"RecvThread setsockopt");
//获得本地IP
char LocalName[256];
gethostname(LocalName,sizeof(LocalName));
struct hostent * my_hostent = gethostbyname(LocalName);
SOCKADDR_IN sa;
memcpy(&sa.sin_addr.S_un.S_addr,my_hostent->h_addr_list[0],my_hostent->h_length);
sa.sin_family = AF_INET;
sa.sin_port = htons(8000);
iErrorCode = bind(sockListen,(sockaddr*)&sa,sizeof(sa));
CheckSockError(iErrorCode,"bind");
//设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包
DWORD dwBufferInLen = 1;
DWORD dwBufferLen[10];
DWORD dwBytesReturned = 0;
iErrorCode = WSAIoctl(sockListen,SIO_RCVALL,\
&dwBufferInLen,sizeof(dwBufferInLen),\
&dwBufferLen,sizeof(dwBufferLen),&dwBytesReturned,NULL,NULL);
CheckSockError(iErrorCode,"RecvThread WSAIoctl");
char RecvBuf[65535]={0};
memset(RecvBuf,0,sizeof(RecvBuf));
while (1)//循环监听 本地 数据包
{
iErrorCode = recv(sockListen,RecvBuf,sizeof(RecvBuf),0);
//CheckSockError(iErrorCode,"RecvThread recv");
DecodeIPHeader(RecvBuf);
if (StopScan == TRUE)
{
closesocket(sockListen);
return 0;
}
}
return 0;
}
USHORT CalcCheckSum(USHORT *buffer,int size)
{
unsigned long cksum = 0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum += *(USHORT*)buffer;
}
cksum = (cksum >> 16) + (cksum &0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
int play=0;
void progressbar(void)
{
// 进度条
char *plays[12]=
{
" | ",
" / ",
" - ",
" \\ ",
" | ",
" / ",
" - ",
" \\ ",
" | ",
" / ",
" - ",
" \\ ",
};
printf(" =%s=\r", plays[play]);
play = (play==11)?0:play+1;
Sleep(2);
}
int main(int argc, char* argv[])
{
char *p;
if (argc != 3)
{
meesage();
return 0;
}
p = argv[2];
if (strstr(argv[2],"-"))
{
BeginPort = atoi(argv[2]);
while (*p)
{
if (*(p++) == '-')
{
break;
}
}
EndPort = atoi(p);
if (BeginPort <1 || BeginPort>65535 ||EndPort<1|| EndPort >65535|| EndPort<EndPort)
{
meesage();
return 0;
}
}
HOST = argv[1];
meesage();
WSADATA wsadata;
iErrorCode = WSAStartup(MAKEWORD(2,2),&wsadata);
CheckSockError(iErrorCode, "WsaStartup()");
//////////////////////////////////////////////////////////////////////////////
sockRaw = socket(AF_INET,SOCK_RAW,IPPROTO_IP);
CheckSockError(sockRaw, "socket()");
//设置IP头操作选项 是发送TCP报文的套接字
BOOL bOpt = true;
setsockopt(sockRaw,IPPROTO_IP,IP_HDRINCL,(char*)&bOpt,sizeof(bOpt));
CheckSockError(sockRaw,"setsockopt()");
//获得目标主机IP ,通过发送主机 第一次握手包
memset(&dest,0,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = ntohs(BeginPort);
struct hostent *my_hostent;
if ((dest.sin_addr.s_addr = inet_addr(HOST)) == INADDR_NONE)
{
if ((my_hostent = gethostbyname(HOST)) == NULL)
{
memcpy(&(dest.sin_addr),my_hostent->h_addr_list[0],my_hostent->h_length);
dest.sin_family = my_hostent->h_addrtype;
printf("dest.sin_addr = %s",inet_ntoa(dest.sin_addr));
}
else
{
CheckSockError(SOCKET_ERROR,"gethostbyname");
}
}
//////////////////////////////////////////////////////////////////////////////
sockListen = socket(AF_INET , SOCK_RAW , IPPROTO_IP);
CheckSockError(sockListen, "socket");
//获得本地IP
SOCKADDR_IN sa;
unsigned char LocalName[256];
struct hostent *hp;
iErrorCode = gethostname((char*)LocalName, sizeof(LocalName)-1);
CheckSockError(iErrorCode, "gethostname()");
if((hp = gethostbyname((char*)LocalName)) == NULL)
{
CheckSockError(SOCKET_ERROR, "gethostbyname()");
}
memcpy(&sa.sin_addr.S_un.S_addr, hp->h_addr_list[0],hp->h_length);
sa.sin_family = AF_INET;
sa.sin_port = htons(8000);
iErrorCode = bind(sockListen, (PSOCKADDR)&sa, sizeof(sa));
CheckSockError(iErrorCode, "bind");
//开启本地监听 第二次握手包 线程
HANDLE Thread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RecvThread,0,0,0);
Sleep(1000);
//////////////////////////////////////////////////////////////////////////////
//发送第一次握手包
IP_HEADER ip_header;
TCP_HEADER tcp_header;
//填充IP首部 一个IP包头的长度最长为“1111”,即15*4=60个字节。IP包头最小长度为20字节。对于标准ipv4报头,这个字段的值肯定是20/4=5(10进制)=0101(2进制)。
ip_header.h_lenver = (4<<4 | sizeof(ip_header)/sizeof(unsigned long));
//高四位IP版本号,低四位首部长度
ip_header.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)); //16位总长度(字节)
ip_header.ident=1; //16位标识
ip_header.frag_and_flags=0; //3位标志位
ip_header.ttl=128; //8位生存时间TTL
ip_header.proto=IPPROTO_TCP; //8位协议(TCP,UDP…)
ip_header.checksum=0; //16位IP首部校验和
ip_header.sourceIP=sa.sin_addr.s_addr; //32位源IP地址
ip_header.destIP=dest.sin_addr.s_addr; //32位目的IP地址
//填充TCP首部
tcp_header.th_sport = htons(8000);//源端口号
tcp_header.th_lenres = (sizeof(TCP_HEADER)/4<<4 | 0);//TCP长度和保留位
tcp_header.th_win=htons(16384);
//填充TCP伪首部(用于计算校验和,并不真正发送)
psd_header.saddr=ip_header.sourceIP;
psd_header.daddr=ip_header.destIP;
psd_header.mbz=0;
psd_header.ptcl=IPPROTO_TCP;
psd_header.tcpl=htons(sizeof(tcp_header));
printf("\n");
printf("Scaning %s port : %d-%d\n",HOST,BeginPort,EndPort);
clock_t start,end;//程序运行的起始和结束时间
start=clock();//开始计时
//开始发包~~~~
char SendBuf[128] = {0};
for (;BeginPort < EndPort;BeginPort++)
{
// 进度条
progressbar();
tcp_header.th_dport = htons(BeginPort); //目的端口号
tcp_header.th_ack=0; //ACK序列号置为0
tcp_header.th_flag=2; //SYN 标志
tcp_header.th_seq=htonl(SEQ); //SYN序列号
tcp_header.th_urp=0; //偏移
tcp_header.th_sum=0; //校验和
//计算TCP校验和 即TCP头部和TCP数据进行校验和计算,并由目标端进行验证。
memcpy(SendBuf,&psd_header,sizeof(psd_header));
memcpy(SendBuf+sizeof(psd_header), &tcp_header,sizeof(tcp_header));
tcp_header.th_sum = CalcCheckSum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));
//计算IP校验和 IP包头是变长的,所以提供一个头部校验来保证IP包头中信息的正确性。
memcpy(SendBuf,&ip_header,sizeof(ip_header));
memcpy(SendBuf+sizeof(ip_header),&tcp_header,sizeof(tcp_header));
memset(SendBuf+sizeof(ip_header)+sizeof(tcp_header),0,4);
ip_header.checksum = CalcCheckSum((USHORT *)SendBuf,sizeof(ip_header)+sizeof(tcp_header));
//填充发送缓冲区
memcpy(SendBuf,&ip_header,sizeof(ip_header));
//发送TCP报文
iErrorCode=sendto(sockRaw,SendBuf,sizeof(ip_header)+sizeof(tcp_header),0,\
(struct sockaddr*) &dest,
sizeof(dest));
CheckSockError(iErrorCode, "sendto()");
}
//结束发包~~~~
end=clock();//计时结束
StopScan = TRUE;
printf("Closeing Scan.....\n");
WaitForSingleObject(Thread,5000);
CloseHandle(Thread);
printf("Cost time: %f Sec",(float)(end-start) / CLOCKS_PER_SEC/*1000*/);
if (sockRaw != INVALID_SOCKET)
{
closesocket(sockRaw);
}
if (sockListen!= INVALID_SOCKET)
{
closesocket(sockListen);
}
WSACleanup();
return 0;
}