linux内核tcphdr字节序,005.手动构建TCPIP包,原始套接字,实现TCP三次握手的第一步(Linux)...

目的:

自己拼接IP头,TCP头,计算效验和,将生成的报文用原始套接字发送出去。

若使用tcpdump能监听有对方服务器的包回应,则证明TCP报文是正确的!

TCP首部结构图:

1219d3148a8f299943ec6184fb54ba06.png

struct tcphdr结构体定义:

2b65ef29a5872cc0e4771c25889edd04.gif

6a087676c59fa8b19d76e6bb55a32902.gif

1 structtcphdr2 {3 u_int16_t source;4 u_int16_t dest;5 u_int32_t seq;6 u_int32_t ack_seq;7 # if __BYTE_ORDER ==__LITTLE_ENDIAN8 u_int16_t res1:4;9 u_int16_t doff:4;10 u_int16_t fin:1;11 u_int16_t syn:1;12 u_int16_t rst:1;13 u_int16_t psh:1;14 u_int16_t ack:1;15 u_int16_t urg:1;16 u_int16_t res2:2;17 # elif __BYTE_ORDER ==__BIG_ENDIAN18 u_int16_t doff:4;19 u_int16_t res1:4;20 u_int16_t res2:2;21 u_int16_t urg:1;22 u_int16_t ack:1;23 u_int16_t psh:1;24 u_int16_t rst:1;25 u_int16_t syn:1;26 u_int16_t fin:1;27 # else

28 # error "Adjust your defines"

29 # endif30 u_int16_t window;31 u_int16_t check;32 u_int16_t urg_ptr;33 };

struct tdphdr

其中:

1.TCP连接建立的第一步中,需要将SYN=1(SYN的报文段不能携带数据),ACK=0。

2.序列号(seq)的窗口(window)的值(几乎)是任意的

3.注意主机字节序和网络字节序之间的转换(大于1字节的数都需要处理)

代码实现:

1 /*

2 ============================================================================3 Name : test.c4 Author : huh5 Version :6 Copyright : ---notice---7 Description : Hello World in C, Ansi-style8 ============================================================================9 */

10

11 #include

12 #include

13 #include

14 #include

15 #include

16 #include

17 #include

18 #include

19 #include

20 #include

21 #include

22

23 #define MAXLINE 1024*50

24

25 #define LOCAL_IP "192.168.11.104" //本主机IP

26 #define LOCAL_PORT 8600 //本主机定义端口

27 #define DEST_IP "115.239.211.112" //要测试的目的ip(此处为百度ip,以后可能发生变化)

28 #define DEST_PORT 80 //要测试的目的端口

29

30 struct udp_front //tcp(udp)伪首部结构体

31 {32 uint32_t srcip;33 uint32_t desip;34 u_int8_t zero;35 u_int8_t protocol;36 u_int16_t len;37 };38

39 u_int16_t in_chksum(u_int16_t *addr, intlen);40 u_int16_t tcp_check(char *sendbuf, int len, const structudp_front front);41 int make_message(char *sendbuf, intsend_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port);42

43 intmain()44 {45 intraw_sockfd;46 int size = 1024*50;47 charsend_message[MAXLINE];48 structsockaddr_in server_address;49 //创建原始套接字

50 raw_sockfd =socket(AF_INET, SOCK_RAW, IPPROTO_UDP);51 //创建套接字地址

52 bzero(&server_address,sizeof(server_address));53 server_address.sin_family =AF_INET;54 server_address.sin_addr.s_addr =inet_addr(DEST_IP);55 //设置套接字为随数据包含IP首部(设置这个选项后需要我们手动写入IP头)

56 setsockopt(raw_sockfd, IPPROTO_IP, IP_HDRINCL, &size, sizeof(size));57

58 bzero(&send_message, sizeof(send_message));59 //拼接完整的TCP数据包(IP头+TCP头+数据)

60 int mesg_len =make_message(send_message, MAXLINE, inet_addr(LOCAL_IP), LOCAL_PORT, inet_addr(DEST_IP), DEST_PORT);61 //将IP数据包发送出去

62 sendto(raw_sockfd, send_message, mesg_len, 0, (struct sockaddr *)&server_address, sizeof(server_address));63 close(raw_sockfd);64 return 0;65 }66

67 //拼接IP数据报

68 int make_message(char *sendbuf, intsend_buf_len, uint32_t src_ip, u_int16_t src_port, uint32_t des_ip, u_int16_t des_port)69 {70 char message[20]; //数据在这里并没有用,为空值

71 bzero(message, sizeof(message));72 //strcpy(message, "hello,world!");

73 struct iphdr *ip;74 ip = (struct iphdr *)sendbuf;75 ip->ihl = sizeof(struct iphdr) >> 2; //首部长度

76 ip->version = 4; //ip协议版本

77 ip->tos = 0; //服务类型字段

78 ip->tot_len = 0; //总长度

79 ip->id = htons(10000); //id值

80 ip->frag_off = 0;81 ip->ttl = 128;82 ip->protocol =IPPROTO_TCP;83 ip->check = 0; //内核会算相应的效验和

84 ip->saddr =src_ip;85 ip->daddr =des_ip;86

87 structudp_front front;88 front.srcip =src_ip;89 front.desip =des_ip;90 front.len = htons(20 +strlen(message));91 front.protocol = 6;92 front.zero = 0;93

94 struct tcphdr *tcp;95 tcp = (struct tcphdr *)(sendbuf + sizeof(structiphdr));96 bzero(tcp, sizeof(struct tcphdr *));97 tcp->source = htons(src_port); //源端口

98 tcp->dest = htons(des_port); //目的端口

99 tcp->seq = htonl(100000000); //随机生成的数

100 tcp->ack_seq = 0; //当ack置0的时候,ack_seq无所谓

101

102 tcp->doff = 5; //数据偏移(TCP头部字节长度/4)

103 tcp->res1 = 0; //保留字段(4位)

104 tcp->fin = 0; //..用来释放一个连接

105 tcp->syn = 1; //..表示这是一个连接请求

106 tcp->rst = 0; //..用来表示tcp连接是否出现严重差错

107 tcp->psh = 0; //..推送

108 tcp->ack = 0; //..表示是一个连接请求

109 tcp->urg = 0; //..紧急数据标志

110 tcp->res2 = 0; //保留字段(2位)

111 tcp->window = htons(65535); //初始窗口值设置

112

113 tcp->check = 0;114 tcp->urg_ptr = 0;115

116 tcp->check = 0; //效验和,效验整个tcp数据报

117 strcpy((sendbuf+20+20), message); //此处message为空

118

119 tcp->check = tcp_check((sendbuf+20), 20+strlen(message), front);120

121 ip->tot_len = (20 + 20 + strlen(message)); //总长度

122 printf("ip->tot_len:%d\n",ip->tot_len);123 ip->check = in_chksum((unsigned short *)sendbuf, 20);124

125 return (ip->tot_len);126 }127

128 //计算tcp(udp)效验和

129 unsigned short tcp_check(char *sendbuf, int len, const structudp_front front)130 {131 charstr[MAXLINE];132 bzero(&str, MAXLINE);133 bcopy(&front, str, sizeof(front));134 bcopy(sendbuf, str+sizeof(front), len);135 struct udp_front *ptr;136 ptr = (struct udp_front *)str;137 char *s;138 s = (str+20);139 return in_chksum((unsigned short *)str, sizeof(front)+len);140 }141

142 //效验和算法

143 uint16_t in_chksum(uint16_t *addr, intlen)144 {145 int nleft =len;146 uint32_t sum = 0;147 uint16_t *w =addr;148 uint16_t answer = 0;149 //把ICMP报头二进制数据以2字节为单位累加起来

150 while (nleft > 1)151 {152 sum += *w++;153 nleft -= 2;154 }155 if (nleft == 1)156 {157 *(unsigned char *)(&answer) = *(unsigned char *)w;158 sum +=answer;159 }160 sum = (sum>>16) + (sum&0xffff);161 sum += (sum>>16);162 answer = ~sum;163 returnanswer;164 }

tcpdump监听结果:

[[email protected] ~]# tcpdump -nn -vvv tcp and host 192.168.11.104

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes

13:24:10.154351 IP (tos 0x0, ttl 128, id 10000, offset 0, flags [none], proto TCP (6), length 40)

192.168.11.104.8600 > 115.239.211.112.80: Flags [S], cksum 0x9394 (correct), seq 100000000, win 65535, length 0

13:24:10.201365 IP (tos 0x0, ttl 128, id 18595, offset 0, flags [none], proto TCP (6), length 44)

115.239.211.112.80 > 192.168.11.104.8600: Flags [S.], cksum 0x5b2f (correct), seq 258283074, ack 100000001, win 64240, options [mss 1460], length 0

13:24:10.201444 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)

192.168.11.104.8600 > 115.239.211.112.80: Flags [R], cksum 0x9391 (correct), seq 100000001, win 0, length 0

^C

3 packets captured

3 packets received by filter

0 packets dropped by kernel

115.239.211.112:80端口的服务确实回应了,证明我们构造的TCP包没有问题。

注:图片来自谢希仁老师的《计算机网络》课件

原文:http://www.cnblogs.com/ruo-yu/p/4982969.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值