linux 高级网络编程进阶之rawsocket
2016-11-04 17:51
507 查看
在linux套接字编程中,常见的套接字类型有SOCK_STREAM, SOCK_DGRAM .
int socket(int domain,
int type, int protocal), 其中 type 字段的 选项可以是:
SOCK_STREAM
SOCK_DGRAM
SOCK_SEQPACKET
SOCK_RAW
Provides raw network protocal access.
SOCK_RDM
SOCK_PACKET
原始套接字rawsocket 因其能获得最底层的IP包,因而有其特殊的作用。其用处,例如:
1. 怎样发送一个自定义的IP包 ?
2. 怎样发送一个ICMP协议包 ?
3. 怎样分析所有经过网络的包 ,而不管这包是否是发给自己的?
4. 怎样伪装本地IP地址 ?
以上所有这些,原始套接字(SOCK_RAW), 都可以帮你实现! !
(tips: 原始套接字广泛应用于高级网络编程,也是一种广泛的黑客手段,著名的网络sniffer, 拒绝服务攻击Dos, IP欺骗 等都可以通过原始套接字实现)
原始套接字的使用,有一点需要注意:只有管理员权限 (root) 才可使用
在创建套接字时的第三个选项 protocal , 可以指定获取某一类型的 rawsocket
socket(PF_PACKET, SOCK_RAW,
int protocal )
protocal 选项:
- 不能为0
- 传参数时需要使用 htons() 转换
ETH_P_IP : IPv4 数据包
ETH_P_ARP : ARP 数据包
ETH_P_ALL : 任何协议的数据包
下面将介绍一种,最简单最有效的 rawsocket 应用:抓取ip包
在此之前,有两点需要了解:一是 以太网帧结构,二是ip 包报文头结构
Frame 以太网帧结构
从帧首界定符SFD之后, 从 DA 开始 就是 帧结构的帧头了,这里介绍一下前导码
前导码:
10101010 10101010 10101010 10101010 10101010 10101010 10101010 10101011
前导码的作用是通知接收节点做好接收准备, 接收节点收到 10101011 后就知道帧 开始了
IP报文头
了解以上两个头部之后,就可以使用rawsocket了, 这里给出一个头部分析的例子
analysis_rawsocket.c
以上rawsocket 可以抓取通过网卡的所有数据包, 分析了收到的数据报类型, 并着重就 tcp 报文, 抓取了报文内容并打印出来。
总结与分析:
使用字段分析的编程方式,原理简单, 只要对帧头和ip头的字段熟悉, 可以用非常小的代码量就写出抓包工具, 并且方便自定义修改;
以上是将截取到的 数据报 分析出来, 下一次博客内容将
自定义IP 包, 自己填充ip报文头, 将数据包发出去,用这
4000
种方式可以伪造ip, 写Dos 攻击程序等。
int socket(int domain,
int type, int protocal), 其中 type 字段的 选项可以是:
SOCK_STREAM
SOCK_DGRAM
SOCK_SEQPACKET
SOCK_RAW
Provides raw network protocal access.
SOCK_RDM
SOCK_PACKET
原始套接字rawsocket 因其能获得最底层的IP包,因而有其特殊的作用。其用处,例如:
1. 怎样发送一个自定义的IP包 ?
2. 怎样发送一个ICMP协议包 ?
3. 怎样分析所有经过网络的包 ,而不管这包是否是发给自己的?
4. 怎样伪装本地IP地址 ?
以上所有这些,原始套接字(SOCK_RAW), 都可以帮你实现! !
(tips: 原始套接字广泛应用于高级网络编程,也是一种广泛的黑客手段,著名的网络sniffer, 拒绝服务攻击Dos, IP欺骗 等都可以通过原始套接字实现)
原始套接字的使用,有一点需要注意:只有管理员权限 (root) 才可使用
在创建套接字时的第三个选项 protocal , 可以指定获取某一类型的 rawsocket
socket(PF_PACKET, SOCK_RAW,
int protocal )
protocal 选项:
- 不能为0
- 传参数时需要使用 htons() 转换
ETH_P_IP : IPv4 数据包
ETH_P_ARP : ARP 数据包
ETH_P_ALL : 任何协议的数据包
下面将介绍一种,最简单最有效的 rawsocket 应用:抓取ip包
在此之前,有两点需要了解:一是 以太网帧结构,二是ip 包报文头结构
Frame 以太网帧结构
从帧首界定符SFD之后, 从 DA 开始 就是 帧结构的帧头了,这里介绍一下前导码
前导码:
10101010 10101010 10101010 10101010 10101010 10101010 10101010 10101011
前导码的作用是通知接收节点做好接收准备, 接收节点收到 10101011 后就知道帧 开始了
IP报文头
了解以上两个头部之后,就可以使用rawsocket了, 这里给出一个头部分析的例子
analysis_rawsocket.c
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <unistd.h> #include <sys/types.h> #include <linux/if_ether.h> #include <linux/in.h> #define BUFFER_MAX 2048 int main(int argc, char **argv) { int rawsock; char buffer[BUFFER_MAX]; char * ethhead; char * iphead; char * phead; // create rawsocket if ((rawsock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0){ perror("rawsock create error"); exit(1); } long framecount = 0; while ( 1 ) { int readnum = recvfrom(rawsock, buffer, 2048, 0 , NULL, NULL); if (readnum < 42) { printf("error: head is incomplete! \n"); exit(1); } ethhead = (char *)buffer; phead = ethhead; int ethernetmask = 0XFF; framecount++; printf("--------------Analysis Packet[%d]-------------\n", framecount); // printf src mac and dst mac fprintf(stderr, "MAC:"); int i = 6; for (; i <= 11; i++) fprintf(stderr, "%.2x:", phead[i]ðernetmask); fprintf(stderr, "--------->"); for (i = 0; i <= 5; i++) fprintf(stderr, "%.2x", phead[i]ðernetmask); printf("\n"); iphead = ethhead + 14; phead = iphead + 12; // print ip address printf("IP:"); for (i = 0; i<= 3; i++) { printf("%d", phead[i]ðernetmask); if (i !=3) { printf("."); } } printf("---------->"); for (i = 4; i <= 7; i++) { printf("%d", phead[i] & ethernetmask); if (i != 7) { printf("."); } } printf("\n"); int prototype = (iphead + 9)[0]; phead = iphead + 20; // print Protocal mesg printf("Protocal:"); switch(prototype) { case IPPROTO_ICMP: printf("ICMP\n"); break; case IPPROTO_IGMP: printf("IGMP\n"); break; case IPPROTO_TCP: printf("TCP | source port: %u |", (phead[0]<<8) & 0xFF00 | phead[1] & 0xFF); printf("destport: %u\n", (phead[2]<<8) & 0xFF00 | phead[3] & 0xFF); int i; for (i = 0; i < readnum -54; i++) putchar(phead[19 + i]); break; case IPPROTO_UDP: printf("UDP | source port: %u |", (phead[0]<<8) & 0xFF00 | phead[1]&0xFF); printf("destport: %u\n", (phead[2]<<8) & 0XFF00 | phead[3] & 0xFF); break; case IPPROTO_RAW: printf("RAW:\n"); break; default: printf("Unknow\n"); } printf("-------------------------------END-------------------------------\n"); } return 0; }
以上rawsocket 可以抓取通过网卡的所有数据包, 分析了收到的数据报类型, 并着重就 tcp 报文, 抓取了报文内容并打印出来。
总结与分析:
使用字段分析的编程方式,原理简单, 只要对帧头和ip头的字段熟悉, 可以用非常小的代码量就写出抓包工具, 并且方便自定义修改;
以上是将截取到的 数据报 分析出来, 下一次博客内容将
自定义IP 包, 自己填充ip报文头, 将数据包发出去,用这
4000
种方式可以伪造ip, 写Dos 攻击程序等。
相关文章推荐
- Linux网络编程之高级并发服务器(转)
- 【linux高级程序设计】(第十三章)Linux Socket网络编程基础 3
- 【linux高级程序设计】(第十三章)Linux Socket网络编程基础 4
- 【linux高级程序设计】(第十五章)UDP网络编程应用 5
- (六)Linux网络编程--6. 高级套接字函数
- Linux 网络编程 高级套接字
- linux 高级网络编程
- 【linux高级程序设计】(第十五章)UDP网络编程应用 3
- 【嵌入式Linux学习七步曲之第七篇 Linux的高级应用编程】网络编程中并发服务器的设计模式
- LINUX网络编程--高级套接字函数
- linux 高级网络编程之自定义ip报文头 Dos
- 【linux高级程序设计】(第十五章)UDP网络编程应用 1
- linux网络高级编程之 fcntl和select使用
- 【linux高级程序设计】(第十三章)Linux Socket网络编程基础
- linux高级编程三网络以及网络配置
- Linux高级编程复习 第九章 信号量同步_socket网络编程基础_TCP_UDP
- linux网络高级编程之 fcntl和select使用
- 嵌入式linux网络编程之connect()函数的高级应用
- Linux网络编程之高级并发服务器
- 【linux高级程序设计】(第十五章)UDP网络编程应用 4