logo资料库

发送TCP数据包.doc

第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
资料共11页,剩余部分请下载后查看
实验目的: • 设计一个发送 TCP 数据包的程序,并根据本设计说明 TCP 数据包的结构 以及 TCP 协议与 IP 协议的关系,使大家对 TCP 协议的工作原理有更深入 的认识。 • 实验要求: 本程序的功能是填充一个 TCP 数据包,并发送给目的主机。 • 以命令行形式运行:SendTCP source_ip source_port dest_ip dest_port 其中 SendTCP 为程序名;source_ip 为源 IP 地址;source_port 为源端口;dest_ip 为目的 IP 地址; dest_port 为目的端口。 • 其他的 TCP 头部参数自行设定。 • 数据字段为“This is my homework of network!”. • 成功发送后在屏幕上输出“send OK”。 课程设计分析: • 使用原始套接字 • 定义 IP 头部、TCP 头部和伪头部的数据结构 • 填充数据包 • 发送数据包 设计思想: 本课程设计的目标是发送一个 TCP 数据包,可以利用原始套接字来完成这个 工作。整个程序由初始化原始套接字和发送 TCP 数据包两个部分组成。 创建一个原始套接字,并设置 IP 头选项 SOCKET sock; sock = socket(AF_INET,SOCK_RAW,IPPROTO_IP); 或者: sock=WSASoccket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OV ERLAPPED); 设置 SOCK_RAW 标志,表示我们声明的是一个原始套接字类型。 为使用发送接收超时设置,必须将标志位置位置为 WSA_FLAG_OVERLAPPED。 在本课程设计中,发送 TCP 包时隐藏了自己的 IP 地址,因此我们要自己填充 IP 头,设置 IP 头操作选项。其中 flag 设置为 ture,并设定 IP_HDRINCL 选项,表 1
明 自己 来 构造 IP 头 。注 意 ,如 果 设置 IP_HDRINCL 选 项, 那 么必 须 具有 administrator 权限,要不就必须修改注册表: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Afd\Parameter\ 修改键:DisableRawSecurity(类型为 DWORD),把值修改为 1。如果没有,就 添加。 BOOL Flag=TRUE; setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&Flag, sizeof(Flag)); int timeout=1000; setsockopt(sock, SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout)); 在这里我们使用基本套接字 SOL_SOCKET,设置 SO_SNDTIMEO 表示使用发送 超时设置,超时时间设置为 1000ms。 构造 IP 头和 TCP 头 这里, IP 头和 TCP 头以及 TCP 伪部的构造请参考下面它们的数据结构。 计算校验和的子函数 在填充数据包的过程中,需要调用计算校验和的函数 checksum 两次,分别用于校验 IP 头和 TCP 头部(加上伪头部),其实现代码如下: USHORT 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); 2
cksum += (cksum >>16); return (USHORT)(~cksum); } 程序流程图: 开始 构造原始套接字,并初始化 填充IP头部 计算IP头部检验和 构造TCP伪头部 填充TCP头部 计算TCP头部校验和 发送TCP数据报 结束 源程序代码: #include #include 3
#include #include #include #include #include #include #pragma comment(lib,"ws2_32.lib") #define IPVER 4 //IP 协议预定 #define MAX_BUFF_LEN 65500 //发送缓冲区最大值 typedef struct ip_hdr //定义 IP 首部 { UCHAR h_verlen; //4 位首部长度,4 位 IP 版本号 UCHAR tos; //8 位服务类型 TOS USHORT total_len; //16 位总长度(字节) USHORT ident; //16 位标识 USHORT frag_and_flags; //3 位标志位 UCHAR ttl; UCHAR proto; //8 位生存时间 TTL //8 位协议 (TCP, UDP 或其他) USHORT checksum; //16 位 IP 首部校验和 ULONG sourceIP; //32 位源 IP 地址 ULONG destIP; }IP_HEADER; //32 位目的 IP 地址 typedef struct tsd_hdr //定义 TCP 伪首部 { ULONG saddr; //源地址 ULONG daddr; //目的地址 4
UCHAR mbz; //没用 UCHAR ptcl; //协议类型 USHORT tcpl; //TCP 长度 }PSD_HEADER; typedef struct tcp_hdr //定义 TCP 首部 { USHORT th_sport; USHORT th_dport; ULONG th_seq; ULONG th_ack; //16 位源端口 //16 位目的端口 //32 位序列号 //32 位确认号 UCHAR th_lenres; //4 位首部长度/6 位保留字 UCHAR th_flag; USHORT th_win; USHORT th_sum; USHORT th_urp; }TCP_HEADER; //6 位标志位 //16 位窗口大小 //16 位校验和 //16 位紧急数据偏移量 //CheckSum:计算校验和的子函数 USHORT checksum(USHORT *buffer, int size) { unsigned long cksum=0; while(size >1) { } cksum+=*buffer++; size -=sizeof(USHORT); if(size) { 5
cksum += *(UCHAR*)buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); } int main(int argc, char* argv[]) { WSADATA WSAData; SOCKET sock; IP_HEADER ipHeader; TCP_HEADER tcpHeader; PSD_HEADER psdHeader; char Sendto_Buff[MAX_BUFF_LEN]; //发送缓冲区 unsigned short check_Buff[MAX_BUFF_LEN]; //检验和缓冲区 const char tcp_send_data[]={"This is my homework of networt,I am happy!"}; BOOL flag; int rect,nTimeOver; if (argc!= 5) { } printf("Useage: SendTcp soruce_ip source_port dest_ip dest_port \n"); return false; 6
if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0) { } printf("WSAStartup Error!\n"); return false; if((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0, WSA_FLAG_OVERLAPPED))==INVALID_SOCKET) { } printf("Socket Setup Error!\n"); return false; flag=true; if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag))== SO CKET_ERROR) { } printf("setsockopt IP_HDRINCL error!\n"); return false; nTimeOver=1000; (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR) printf("setsockopt SO_SNDTIMEO error!\n"); return false; if { } //填充 IP 首部 ipHeader.h_verlen=(IPVER<<4 | sizeof(ipHeader)/sizeof(unsigned long)); 7
ipHeader.tos=(UCHAR)0; ipHeader.total_len=htons((unsigned short)sizeof(ipHeader)+sizeof(tcpHeader)+sizeof(tcp_send_data)); ipHeader.ident=0; //16 位标识 ipHeader.frag_and_flags=0; //3 位标志位 ipHeader.ttl=128; //8 位生存时间 ipHeader.proto=IPPROTO_UDP; //协议类型 ipHeader.checksum=0; //检验和暂时为 0 ipHeader.sourceIP=inet_addr(argv[1]); //32 位源 IP 地址 ipHeader.destIP=inet_addr(argv[3]); //32 位目的 IP 地址 //计算 IP 头部检验和 memset(check_Buff,0,MAX_BUFF_LEN); memcpy(check_Buff,&ipHeader,sizeof(IP_HEADER)); ipHeader.checksum=checksum(check_Buff,sizeof(IP_HEADER)); //构造 TCP 伪首部 psdHeader.saddr=ipHeader.sourceIP; psdHeader.daddr=ipHeader.destIP; psdHeader.mbz=0; psdHeader.ptcl=ipHeader.proto; psdHeader.tcpl=htons(sizeof(TCP_HEADER)+sizeof(tcp_send_data)); //填充 TCP 首部 tcpHeader.th_dport=htons(atoi(argv[4])); //16 位目的端口号 tcpHeader.th_sport=htons(atoi(argv[2])); //16 位源端口号 tcpHeader.th_seq=0; tcpHeader.th_ack=0; //TCP 长度和保留位 //SYN 序列号 //ACK 序列号置为 0 8
分享到:
收藏