修改数据包发送到服务器不响应,当我使用原始套接字发送syn-packet时,为什么服务器不响应syn-ack数据包?...

我正在尝试使用原始套接字,我刚刚编写了一个小程序,用于发送设置了syn标志的TCP数据包。我可以在服务器端看到与Wireshark一起发送的数据包,它们看起来不错,但服务器永远不会响应任何syn-ack数据包。

我已将我的程序构造的syn数据包(请参阅下面的代码)与hping3发送的数据包进行比较(因为hping3的数据包总是得到syn-ack)。我的syn数据包和hping3的syn数据包之间唯一不同的是ip identification数字tcp source port(在hping3中随机化),tcp sequence number(在hping3中也随机化)和{ {1}}字段。所有这四个字段都基于一些随机数,这就是它们不同的原因。 所有其他字段都相同!但我的程序没有得到任何同步,但hping3呢!

我正在使用Kali Linux发送数据包(当然是root用户)和CentOS用于服务器。

我是否遗漏了一些必要的东西或者只是误解了什么?

删除了代码

编辑

这是Wireshark在客户端捕获的整个数据包(下面分为4个图像)。请注意,除了ip标识,源端口,序列号和校验和的值之外,hping3发送的数据包完全相同:

图片已移除

这是数据包的十六进制转储。

删除了Hexdump

编辑2

好了,现在我已根据RFC793创建了伪标头。伪标头仅用于tcp校验和计算。现在IP头似乎是正确的,但Wireshark抱怨该数据包不包含一个完整的TCP头,它真的好像已经损坏,因为一些字段包含我没有设置的奇怪值。

首先,我为tcp头和伪头分配一个带空格的缓冲区(称为ip checksum)。其次,我为包含ip,tcp和伪标头空间的ip头创建了一个缓冲区。

首先,我将tcp_header填入其数据,然后将其复制到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:

xiJgA.png

校验和按网络顺序排列,因此应按相反顺序读取,如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 ???

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值