在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
#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报文头, 将数据包发出去,用这种方式可以伪造ip, 写Dos 攻击程序等。
本文介绍了Linux中rawsocket的用途和重要性,包括如何使用rawsocket抓取和分析IP包,以及需要管理员权限才能使用。通过示例代码展示了如何分析以太网帧结构和IP报文头,为自定义IP包和网络编程打下基础。后续将探讨如何利用rawsocket伪造IP和编写DoS攻击程序。
1万+

被折叠的 条评论
为什么被折叠?



