原始套接字 IP_HDRINCL

 原始套接字可以访问ICMP和ICMP等协议包,可以读写内核不处理的IP数据包。可以创建自定义的IP数据包首部。一句话,使用原始套接字可以

  编写基于IP协议的通讯程序。

  1.创建原始套接字具体格式如下:int sockfd;sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP);第一个参数:协议族 AF_INET 代表TCP/IP协议第二个参数:SOCKET类型第三个参数:协议类型注意:@如果指定协议为0时,原始套接字可以接收内核传递给原始套接字的任何IP数据包,且只有超级用户才可以创建原始套接字。

  @当需要编写自己的IP数据包首部时,可以在原始套接字上设置套接字选项IP_HDRINCL.在不设置这个选项的情况下,IP协议自动填充IP数据包的首部。

  int on = 1;if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)

  { fprintf(stderr, "setsockopt IP_HDRINCL ERROR! /n");exit(1);}

  原始套接字直接使用IP协议的套接字,所以是非面向连接的。在这个套接字上可以调用connect和bind函数,分别执行绑定对方和本地地址。

  说明:

  bind函数:调用bind函数后,发送数据包的源IP地址将是bind函数指定的地址。如是不调用bind,则内核将以发接口的主IP地址填充。如果设置了IP_HDRINCL,那么必须手工填充每个发送数据包的源IP地址。

  connetc函数:调用connect函数后,可以用write和send发送数据包。内核将用这个绑定的地址填充IP数据包的目的IP地址。

  发送数据包

  使用原始套接字发送数据包必须遵循以下规则:1.如果没有用connect函数绑定对方地址时,则应使用sendto或sendmsg函数发送数据包,在函数参数中指定对方地址。如?饔昧薱onnect函数,则可以直接使用send,write或writev来发送数据包。

  2.如果没有设置IP_HDRINCL选项时,包内可写的内容为数据部分,内核将自动创建IP首部。如果设置了IP_HDRINCL选项,则包内要填充的内容为IP数据包和首部。内核只负责填充下面两个域:。如果将IP数据包的标识域设置为0,内核将设置这个域。内核总是计算和填充IP数据包首部的校验和。

  注意:IP数据包首部各个域的内容都是网络字节顺序。

  接收数据包

  内核遵循以下规则接收数据包:1.UDP和TCP数据包从不传送给一个原始套接字。如果要查看这两类数据包,只能通过直接访问数据链路层来实现。

  2.大多数ICMP数据包的一个拷贝传送给匹配的原始套接字。

  3.内核处理的所有其它类型的数据包的一个拷贝都传给匹配的原始套接字。

  4.所有内核不能识别的协议类型的IP数据包都传送给匹配的原始套接字。对于这些IP数据包,内核只做必要的检验工作。

  在将一个IP数据包传送给原始套接字之前,内核需要选择匹配的原始套接字1.数据包的协议域必须与接收原始套接字的协议类型匹配。

  2.如果原始套接字调用了bind函数绑定了本地IP地址,那么到达的IP数据包的源IP地址必须和对方的IP相匹配。

  3.如果原始套接字调用connect函数指定了对方的IP地址,则到达的IP数据包的源IP地址秘须与这它相同。

  

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验三 发送TCP数据包 实验目的: 设计一个发送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_OVERLAPPED); 设置SOCK_RAW标志,表示我们声明的是一个原始套接字类型。 为使用发送接收超时设置,必须将标志位置位置为WSA_FLAG_OVERLAPPED。在本课程设计 中,发送TCP包时隐藏了自己的IP地址,因此我们要自己填充IP头,设置IP头操作选项。 其中flag设置为ture,并设定 IP_HDRINCL 选项,表明自己来构造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); cksum += (cksum >>16); return (USHORT)(~cksum); } 程序流程图: 源程序代码: #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #include <time.h> #include <windows.h> #include <string.h> #include <stdlib.h> #include <iostream.h> #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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值