C++ 当我用原始套接字发送syn数据包时,为什么服务器不响应syn ack数据包?
我正在试验原始套接字,我刚刚编写了一个小程序,它使用C++ 当我用原始套接字发送syn数据包时,为什么服务器不响应syn ack数据包?,c++,c,tcp,raw-sockets,C++,C,Tcp,Raw Sockets,我正在试验原始套接字,我刚刚编写了一个小程序,它使用syn标志集发送TCP数据包。我可以在服务器端看到Wireshark带来的数据包,它们看起来不错,但是服务器从来没有使用任何syn ack数据包进行响应 我比较了我的程序构造的syn数据包(见下面的代码)和hping3发送的数据包(因为hping3的数据包总是得到syn ack)。我的syn数据包和hping3的syn数据包之间唯一不同的是ip标识编号、tcp源端口(在hping3中随机)、tcp序列号(在hping3中也随机)和ip校验和字段
syn
标志集发送TCP数据包。我可以在服务器端看到Wireshark带来的数据包,它们看起来不错,但是服务器从来没有使用任何syn ack
数据包进行响应
我比较了我的程序构造的syn
数据包(见下面的代码)和hping3
发送的数据包(因为hping3的数据包总是得到syn ack
)。我的syn数据包和hping3的syn数据包之间唯一不同的是ip标识
编号、tcp源端口
(在hping3中随机)、tcp序列号
(在hping3中也随机)和ip校验和
字段。所有这四个字段都基于一些随机数,这就是它们不同的原因所有其他字段都相等但是我的程序没有得到任何syn ACK,但是hping3得到了
我使用Kali Linux发送数据包(当然是以root用户身份),并使用CentOS发送服务器
我是否错过了一些重要的东西,或者只是误解了什么
删除的代码
编辑以下是Wireshark在客户端捕获的整个数据包(分为以下4幅图像)。请注意,除了ip标识、源端口、序列号和校验和的值外,hping3发送的数据包完全相同:
删除的图像
这是数据包的十六进制转储 已删除hextump 编辑2
好的,现在我已经根据创建了伪标题。伪报头仅用于tcp校验和计算。现在,IP报头似乎是正确的,但Wireshark抱怨数据包没有包含完整的TCP报头,而且它确实似乎已损坏,因为一些字段包含我未设置的奇怪值。
首先,我为tcp头和伪头分配一个缓冲区(称为
tcp\U头
)。其次,我为ip报头创建一个缓冲区,其中包含ip、tcp和伪报头的空间首先,我用数据填充
tcp_头
,然后将其复制到ip_头
,然后使用sendto
功能发送当我将
tcp\u数据包的内容复制到ip\u数据包时,是否出现了问题,或者我是否做了其他错误的事情
#include <cstdlib>
#include <stdio.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#define __FAVOR_BSD 1
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <sys/ioctl.h>
#include <string.h>
#include <iostream>
#include <net/ethernet.h>
#include <time.h>
#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;
}
…然后所有数据包都得到正确的校验和,并接收相应的SYN-ACK
为什么是魔法数字3072???我不满意您使用的校验和算法。史蒂文斯的建议是:
uint16_t
in_cksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = 0;
uint16_t *w = addr;
uint16_t answer = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* 4mop up an odd byte, if necessary */
if (nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w ;
sum += answer;
}
/* 4add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
也许校验和是错误的?(我不是说是,但这将是我检查这是否是我的调试问题的第一件事…)好吧,我已经以与我在互联网上找到的所有原始套接字教程相同的方式实现了校验和计算,即:csum((unsigned short*)buffer,(sizeof(class iphdr)+sizeof(class tcphdr))
。csum
函数位于上面代码的顶部。它就在那里。它甚至以黄色突出显示。当您不确认任何内容时,您正在设置一个非零确认序列号。服务器正在丢弃无效的数据包。长度正确,但TCP的起始位置(偏移量22h)会重复源和目标IP地址。将tcp数据包复制到ip数据包的memcpy将是第一个查找的位置。3072=2048+1024。这对你有什么建议吗?
uint16_t
in_cksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = 0;
uint16_t *w = addr;
uint16_t answer = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* 4mop up an odd byte, if necessary */
if (nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w ;
sum += answer;
}
/* 4add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}