我正在尝试使用原始套接字,我刚刚编写了一个小程序,它发送带有syn
标志集的TCP数据包.我可以在服务器端看到与Wireshark一起发送的数据包,它们看起来不错,但服务器从不响应任何syn-ack
数据包.
我已经将syn
我的程序构造的数据包(参见下面的代码)与hping3
发送的数据包进行了比较(因为hping3的数据包总是得到一个syn-ack
).我的syn包和hping3的syn包之间唯一不同的是ip identification
数字tcp source port
(在hping3中随机化)tcp sequence number
(也在hping3中随机化)和ip checksum
字段.所有这四个字段都基于一些随机数,这就是它们不同的原因.所有其他领域都是平等的!但我的程序没有得到任何同步,但hping3呢!
我正在使用Kali Linux发送数据包(当然是root用户)和CentOS用于服务器.
我错过了必要的东西或者只是误解了什么吗?
删除了代码
编辑
这是Wireshark在客户端捕获的整个数据包(下面分为4个图像).请注意,除了ip标识,源端口,序列号和校验和的值之外,hping3发送的数据包完全相同:
图像已删除
这是数据包的十六进制转储.
Hexdump已移除
编辑2
好了,现在我根据RFC793创建了伪标头.伪标头仅用于tcp校验和计算.现在IP头似乎是正确的,但Wireshark抱怨该数据包不包含一个完整的TCP头,它真的好像已经损坏,因为一些字段包含我没有设置的奇怪值.
首先,我tcp_header
为tcp头和伪头分配一个带空格的缓冲区(称为).其次,我为包含ip,tcp和伪标头空间的ip头创建了一个缓冲区.
首先,我填充tcp_header
其数据,然后我将其复制到ip_header
使用该sendto
函数发送之前.
做一些事情出错时,我复制的内容tcp_packet
来ip_packet
还是我做别的事情了?
#include#include #include #include #include #include #define __FAVOR_BSD 1 #include #include #include #include #include #include #include #include #include #define PCKT_LEN 1024 struct pseudohdr { __u32 saddr; __u32 daddr; __u8 zero; __u8 protocol; __u16 lenght; }; #define PSEUDOHDR_SIZE sizeof(struct pseudohdr) unsigned short csum(unsigned short *buf, int len) { unsigned long sum; for(sum=0; len>0; len-=2) sum += *buf++; sum = (sum >> 16) + (sum &0xffff); sum += (sum >> 16); return (unsigned short)(~sum); } int main(int argc, char** argv) { srand(time(NULL)); char *ip_packet = new char[sizeof(struct iphdr) + sizeof(struct tcphdr)](); char *tcp_packet = new char[sizeof(struct pseudohdr) + sizeof(struct tcphdr)](); struct pseudohdr *pseudoheader = (struct pseudohdr*) tcp_packet; class tcphdr *tcp = (struct tcphdr *) (tcp_packet + sizeof(struct pseudohdr)); class iphdr *ip = (struct iphdr *) ip_packet; class sockaddr_in sin, din; int sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if(sd < 0) { perror("socket() error"); exit(-1); } else { printf("socket()-SOCK_RAW and tcp protocol is OK.\n"); } // Randomize src port int srcport = rand()%100+25000; sin.sin_family = AF_INET; // Address family sin.sin_addr.s_addr = inet_addr("192.168.2.80"); sin.sin_port = htons(srcport); // Source port din.sin_family = AF_INET; din.sin_addr.s_addr = inet_addr("192.168.2.6"); din.sin_port = htons(80); // Destination port /* tcp pseudo header */ memcpy(&pseudoheader->saddr, &sin.sin_addr.s_addr, 4); memcpy(&pseudoheader->daddr, &din.sin_addr.s_addr, 4); pseudoheader->protocol = 6; /* tcp */ pseudoheader->lenght = htons(sizeof(struct pseudohdr) + sizeof(struct tcphdr)); ip->ihl = 5; ip->version = 4; ip->tos = 0; ip->tot_len = sizeof(class iphdr) + sizeof(class tcphdr); ip->id = htons((getpid() & 255) + rand()%100+30000); ip->frag_off = 0; ip->ttl = 32; ip->protocol = 6; // TCP ip->check = 0; // Done by kernel memcpy(&ip->saddr, (char*)&sin.sin_addr, sizeof(ip->saddr)); memcpy(&ip->daddr, (char*)&din.sin_addr, sizeof(ip->daddr)); // The TCP structure tcp->th_sport = htons(srcport); tcp->th_dport = htons(80); // Destination port tcp->th_seq = htonl(rand()%100+1000); tcp->th_ack = htonl(rand()%30); tcp->th_off = 5; tcp->th_flags = TH_SYN; tcp->th_win = htons(1024); tcp->th_urp = 0; // Now calculate tcp checksum tcp->th_sum = csum((unsigned short *) tcp_packet, sizeof(struct pseudohdr) + sizeof(struct tcphdr)); // Copy tcp_packet to ip_packet memcpy(ip_packet + sizeof(struct iphdr), tcp_packet+sizeof(struct pseudohdr), sizeof(struct tcphdr)); // Bind socket to interface int one = 1; const int *val = &one; const char opt[] = "eth0"; if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one)) < 0) { perror("setsockopt() error"); exit(-1); } else printf("setsockopt() is OK\n"); if(sendto(sd, ip_packet, ip->tot_len, 0, (sockaddr*)&din, sizeof(din)) < 0) { perror("sendto() error"); exit(-1); } else printf("Send OK!"); close(sd); return 0; }
数据包的tcp内容:
图像已删除
编辑3
现在我发现了一些有趣的东西.研究这张照片上的cheksums:
校验和按网络顺序排列,因此应按相反的顺序读取0x06c0
(并不像上面所述的0xc006).这等于的十进制值1728
.Wireshark说正确的cheksum应该是0x12c0
十进制值4800
.
4800-1728=3072
.这是我的程序发送的所有数据包中Wireshark计算的实际校验和与正确校验和之间的差异.
所以,如果我只是将该值添加到cheksum结果中:
tcp->th_sum = csum((unsigned short *) tcp_packet, sizeof(struct pseudohdr) + sizeof(struct tcphdr)) + 3072;
...然后所有数据包都获得正确的校验和并收到相应的SYN-ACK
.
为什么神奇数字3072 ???