目的:
自己拼接IP头,TCP头,计算效验和,将生成的报文用原始套接字发送出去。
若使用tcpdump能监听有对方服务器的包回应,则证明TCP报文是正确的!
TCP首部结构图:
struct tcphdr结构体定义:
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