linux 高级网络编程进阶之rawsocket

本文介绍了Linux中rawsocket的用途和重要性,包括如何使用rawsocket抓取和分析IP包,以及需要管理员权限才能使用。通过示例代码展示了如何分析以太网帧结构和IP报文头,为自定义IP包和网络编程打下基础。后续将探讨如何利用rawsocket伪造IP和编写DoS攻击程序。

在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 攻击程序等。 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值