做 TCP 警告意味着数据包被忽略,"Wireshark (Warning/Malformed):Short segment.Segment/fragment does not contain a full TCP header (might be NMAP )"
do TCP warning means packet ignored,"Wireshark (Warning/Malformed):Short segment.Segment/fragment does not contain a full TCP header (might be NMAP )"
我正在模拟 TCP,例如任何收到的 tcp 数据包,因此应该有一个响应,为此我用 C 编写了我的服务器程序并创建了 TUN 接口,以便客户端数据包读取我的代码,我的代码的问题是只是我收到 SYN
个数据包,并且我用 SYN + ACK
个数据包响应它。序列号和端口是正确的。在 wire shark 中,我看到了我的 SYN + ACK 响应,但我的客户端继续发送 SYN 数据包并在中间路由器请求消息中,在 wire shark 中它说
Expert Info (Warning/Malformed): Short segment. Segment/fragment does not contain a full TCP header (might be NMAP or someone else deliberately sending unusual packets)
这是什么意思,我有点确定我将所有有效字段都作为值包括在内,但为什么我不断收到此警告,而我的客户端似乎忽略了我的 SYN +ACK 数据包。谁能看看这段代码
这是我的主要功能
int main(int argc, char **argv)
{
const char *tun_ip = NULL; /*virtual*/
const char *remote_ip = NULL; /*physical*/
ip4_addr_t local_ip4 = 0L;
pthread_t tid_recv;//, tid_trans;
void *thread_ret = NULL;
_progname = argv[0];
if (argc != 3)
{
usage();
exit(EXIT_FAILURE);
}
tun_ip = argv[1];
remote_ip = argv[2];
if (0 >= inet_pton(AF_INET, tun_ip, &local_ip4))
{
debug("%s: invalid IP address %s\n", _progname, tun_ip);
exit(EXIT_FAILURE);
}
set_signal(SIGINT, sigexit);
set_signal(SIGQUIT, sigexit);
_tun_fd = open_tun_iface(local_ip4);
if (_tun_fd < 0 )
{
exit(EXIT_FAILURE);
}
_udp_fd = open_udp_socket();
if (_udp_fd < 0 )
{
exit(EXIT_FAILURE);
}
if (0 >= inet_pton(AF_INET, remote_ip, &_remote_ip))
{
debug("%s: invalid IP address %s\n", _progname, remote_ip);
exit(EXIT_FAILURE);
}
pthread_create(&tid_recv, NULL, receiver, NULL);
while (!_do_exit)
sleep(1);
debug("** Shutting down...\n");
close_tun_iface();
shutdown(_udp_fd, 2); _udp_fd = -1;
pthread_join(tid_recv, &thread_ret);
return 0;
}
这是我的接收者和响应者 TCP 线程
void * receiver(void *data)
{
//struct sockaddr_in cliaddr = {0};
int recvlen = -1;
int writelen = -1;
//socklen_t clilen = sizeof(cliaddr);
while (!_do_exit)
{
//recvlen = rrecvfrom(_udp_fd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr, &clilen);
char buf[VPN_MAX_MTU] = {0};
char buf_1[VPN_MAX_MTU] = {0};
memset(buf,0,VPN_MAX_MTU);
memset(buf_1,0,VPN_MAX_MTU);
memset(buf,0,VPN_MAX_MTU);
memset(buf_1,0,VPN_MAX_MTU);
char *str_source=malloc(18);
char *str_dest=malloc(18);
memset(str_source,0,18);
memset(str_dest,0,18);
recvlen=read(_tun_fd,buf,VPN_MAX_MTU);
if(recvlen>0)
{
//BUFFER received here
struct iphdr *iph=(struct iphdr *)buf;
struct iphdr *ip=(struct iphdr *)buf_1;
int y=0;
for(int b=0;b<(sizeof(struct iphdr)+sizeof(struct tcphdr));b++)
{
if(y==20)
{
y=0;
//printf("\n");
}
//printf("%x ",buf[b]<<24);
y++;
}
// tcph->check=(tcp_chksum(iph,tcph));
//iph->check = csum(iph, sizeof(*iph));
char str_src[18]={0};
char str_dest_t[18]={0};
//printf("IN %s %s\n",get_ip_str_1(iph->saddr,str_src),get_ip_str_1(iph->daddr,str_dest_t));
memcpy(&ip->daddr,&iph->saddr,sizeof(uint32_t));
memcpy(&ip->saddr,&iph->daddr,sizeof(uint32_t));
//printf("OUT %s %s\n",get_ip_str_1(ip->saddr,str_src),get_ip_str_1(ip->daddr,str_dest_t));
//Create ip
//DOUBLE CHECK FOR BYTE ORDER
//ip->tot_len=iph->tot_len;
populate_ip_some(iph,ip);
ip->tos=0;
ip->tos=iph->tos;
ip->ihl = 5;
ip->version = 4;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
ip->protocol = 6;
ip->check=0;
//DOUBLE CHECK FOR BYTE ORDER
ip->check = csum(ip, sizeof(*ip));
ip->id=htons(100);
//printf("before %d \n",htons(iph->check));
iph->check=0;
//printf("middle %d\n",iph->check);
//DOUBLE CHECK FOR BYTE ORDER
iph->check = csum(iph, sizeof(*iph));
int i=iph->ihl*4;
struct tcphdr *tcph=(struct tcphdr *)(buf+i);
//printf("tcp before %x\n",htons(tcph->check));
tcph->check=0;
printf("TCP START\n");
tcph->check=(tcp_chksum(iph,tcph));
printf("TCP END\n");
//printf("tcp after %d\n",(tcph->check));
//printf("i == %d\n",i);
//POSSIBLY PRINT IPH for fun
//for(int a=0;a<recvlen;a++)
//printf("%x\n",buf[a]);
//GET ihl SEND -- tcp
int j=(ip->ihl*4);
//printf("j == %d\n",j);
int x=0;
//SEEK filling
struct tcphdr *tcp=(struct tcphdr *)(buf_1+20);
populate_tcp_some(tcph,tcp);//Do LOOK AT THIS FUNCTION TO [SEE/CORRECT IT] >:)
if(tcph->syn==1)
{
printf("syn\n");
populate_tcp_some(tcph,tcp);
tcp->seq=htons(1);
tcp->ack_seq=1;
tcp->syn=1;
tcp->ack=1;
tcp->source=htons(80);
// printf("received tcp syn = %d\n",tcph->syn);
}
else
{
populate_tcp_some(tcph,tcp);
tcp->syn=0;
tcp->ack=1;
// printf("sending tcp syn = %d ack = %d\n",tcp->syn,tcp->ack);
}
populate_tcp_some(tcph,tcp);
tcp->dest=tcph->source;
//printf("%d %d SOURCE PORT \n",ntohs(tcph->source),ntohs(tcp->dest));
tcp->source=htons(80);
printf("%d %d PORTS \n",ntohs(tcp->source),ntohs(tcp->dest));
tcp->check=0;
//TCP CHECKSUM ABOUT TRIPPLE WOW
tcp->check=tcp_chksum(ip,tcp);
//printf("tcpH = %d | tcp = %d\n",tcph->check,htons(tcp->check));
//IF needed make payload data
//WRITE
if (recvlen > 0)
{
writelen = write(_tun_fd, buf_1, sizeof(struct iphdr)+sizeof(struct tcphdr));
//debug("SR:%04d\n", recvlen);
//debug("TW:%04d\n", writelen);
if (writelen < 0)
{
//debug("%s: rwrite() %s [%d]\n", _progname, strerror(errno), errno);
//break;//NO NEED
}
}
else if (recvlen < 0)
{
//debug("%s: rrecvfrom() %s\n", _progname, strerror(errno));
//break;//NO NEED
}
else if (recvlen == 0)
{
//why
}
//FINALLY THEN SEND || DO WIRE SHARK
}
// ...:)__ :) __:) ___:)___ (: __(:__ (;...
}
debug("** Receiver ending.\n");
pthread_exit(NULL);
}
这就是我设置 tun 接口的方式
int open_tun_iface(ip4_addr_t local_ip4)
{
struct ifreq ifr_tun;
int fd = -1;
sock = -1;
// int mtu = VPN_PATH_MTU;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
debug("%s: Cannot open /dev/net/tun: %s. Do modprobe tun; lsmod\n", _progname, strerror(errno));
return -1;
}
memset( &ifr_tun, 0, sizeof(ifr_tun) );
ifr_tun.ifr_flags = IFF_TUN | IFF_NO_PI;// | IFF_NO_PI;
if ((ioctl(fd, TUNSETIFF, (void *)&ifr_tun)) < 0) {
debug("%s: TUNSETIFF error: %s\n", _progname, strerror(errno));
close(fd);
return -1;
}
#if 0
if (ioctl(fd, TUNSETPERSIST, 1) < 0) {
debug("%s: TUNSETPERSIST error: %s\n", _progname, strerror(errno));
close(fd);
return -1;
}
#endif
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
printf("interface socket error\n");
debug("%s: Cannot open udp socket: %s\n", _progname, strerror(errno) );
close(fd);
return -1;
}
if (set_ip(&ifr_tun, sock, local_ip4) < 0) {
close(fd);
close(sock);
return -1;
}
if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
debug("%s: SIOCGIFFLAGS: %s\n", _progname, strerror(errno));
printf("SIOCSIFFLAGS\n");
close(fd);
close(sock);
return -1;
}
ifr_tun.ifr_flags |= IFF_UP;
ifr_tun.ifr_flags |= IFF_RUNNING;
if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0) {
debug("%s: SIOCSIFFLAGS: %s\n", _progname, strerror(errno));
printf("SIOCSIFFLAGS\n");
exit(0);
close(fd);
close(sock);
return -1;
}
/*mtu = get_if_mtu("eth0", sock);*/
/* mtu = path_mtu_to_ip(_remote_ip, 32);
if (mtu <= 0) {
mtu = INTERNET_MTU;
}
if (mtu + VPN_OVERHEAD > VPN_MIN_MTU)
mtu -= VPN_OVERHEAD;
if (0 != set_mtu(&ifr_tun, sock, mtu)) {
close(fd);
close(sock);
return -1;
}
*/
debug("** TUN opened: %s\n", ifr_tun.ifr_name);
//close(sock);
return fd;
}
这是我的校验和计算
通用 csum 函数
uint16_t csum(const void *data, const int length)
{
uint16_t *accumalator = (uint16_t *)data;
uint64_t sum = 0;
/* Take care of the first 16-bit even blocks */
for (int i = 0; i < length/2; ++i) {
sum += *(accumalator+i);
if (sum >= 0x10000) {
sum -= 0xffff;
}
}
/* Handle the ending partial block */
if (length % 2 != 0) {
accumalator = accumalator+ length/2; /* Point accumalator to the end block */
uint16_t end_block = 0;
memcpy(&end_block, accumalator, sizeof(length));
sum += ntohs(end_block);
if (sum >= 0x10000) {
sum -= 0xffff;
}
}
return htons(~sum);
}
这是我计算和处理 TCP 校验和计算
uint16_t tcp_chksum(struct iphdr *snd_iph, struct tcphdr *snd_tcph)
{
struct psuedo_header psh;
psh.src_addr = snd_iph->saddr;
psh.dst_addr = snd_iph->daddr;
psh.rsvd = 0;
psh.proto = IPPROTO_TCP;
psh.len_tcp = htons(sizeof(struct tcphdr)); /* No options, and no data */
int pseudogram_size = sizeof(struct tcphdr) + sizeof(struct psuedo_header);
//int pseudogram_size = sizeof(*snd_tcph) + sizeof(psh);
char *pseudogram = malloc(pseudogram_size);
memcpy(pseudogram, (char *)&psh, sizeof(struct psuedo_header));
memcpy(pseudogram + sizeof(struct psuedo_header), snd_tcph, sizeof(struct tcphdr));
return((csum1(pseudogram, pseudogram_size)));
//return (htons(csum(snd_tcph, sizeof(struct my_tcph)) + csum(&psh, sizeof(struct psuedo_header))));
}
int populate_ip_some(struct iphdr *o1,struct iphdr *o2)
{
o2->ihl=o1->ihl;
//o2->版本=o1->版本;
o2->id=htons(ntohs(o1->id)+1);
o2->frag_off=o1->frag_off;
o2->ttl=o1->ttl;
o2->tos=0;
//o2->协议=o1->协议;
//o2->检查=0;
return 1;
}
int populate_tcp_flags(struct tcphdr *o1,struct tcphdr *o2)
{
if(o1->syn==1 && o1->ack==0)
{
printf("syn received\n\n");
o2->syn=1;
o2->ack=1;
o2->rst=0;
o2->fin=0;
return 1;
}
if(o1->syn ==0 && o1->ack==1)
{
printf("ack received\n\n");
o2->syn=0;
o2->ack=0;
o2->rst=0;
o2->fin=0;
return 1;
}
if(o1->syn==0 && o1->fin==1)
{
printf("fin received\n\n");
o2->syn=0;
o2->ack=1;
o2->fin=0;
o2->rst=0;
return 1;
}
return 1;
}
uint32_t *ik;
int x=0;
int populate_tcp_some(struct tcphdr *o1,struct tcphdr *o2)
{
if(x==0)
{
ik=malloc(sizeof(int)*100);
if(ik==NULL)
{printf("heap\n");exit(0);}
}
*(ik+x)=x;
o2->seq=htons(*(ik+x));
uint32_t host=ntohs(o1->seq);
if(o1->syn==1)
o2->ack_seq=1;
else
{
//DOUBLE CHECK FOR TCP. ACK_SEQ SHOULD HAVE BEEN sizeof(OF TOTAL PACKET) + 1
//DOUBLE CHECK MAY NEED TO PASS IPHDR ipH
o2->ack_seq=(htons(host+1));
}
o2->doff=o1->doff;
o2->res1=o1->res1;
o2->window=o1->window;
o2->check=0;
o2->urg_ptr=o1->urg_ptr;
x++;
return 1;
}
这是我的 netinet/ip.h,它有 iphdr 定义
struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
uint8_t tos;
uint16_t tot_len;
uint16_t id;
uint16_t frag_off;
uint8_t ttl;
uint8_t protocol;
uint16_t check;
uint32_t saddr;
uint32_t daddr;
/*The options start here. */
};
这是 netinet/tcp.h 可以找到我的 tcphdr 结构的地方
struct tcphdr
{
__extension__ union
{
struct
{
uint16_t th_sport; /* source port */
uint16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t th_x2:4; /* (unused) */
uint8_t th_off:4; /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
uint8_t th_off:4; /* data offset */
uint8_t th_x2:4; /* (unused) */
# endif
uint8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
uint16_t th_win; /* window */
uint16_t th_sum; /* checksum */
uint16_t th_urp; /* urgent pointer */
};
struct
{
uint16_t source;
uint16_t dest;
uint32_t seq;
uint32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
uint16_t res1:4;
uint16_t doff:4;
uint16_t fin:1;
uint16_t syn:1;
uint16_t rst:1;
uint16_t psh:1;
uint16_t ack:1;
uint16_t urg:1;
uint16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
uint16_t doff:4;
uint16_t res1:4;
uint16_t res2:2;
uint16_t urg:1;
uint16_t ack:1;
uint16_t psh:1;
uint16_t rst:1;
uint16_t syn:1;
uint16_t fin:1;
# else
# error "Adjust your <bits/endian.h> defines"
# endif
uint16_t window;
uint16_t check;
uint16_t urg_ptr;
};
};
};
为了有问题的答案。
OP 正在尝试创建一个 SYNACK 数据包来应答传入的 SYN 数据包。 TCP SYN 数据包从 OS 堆栈生成,并使用选项。
Wireshark 抱怨 header 太短。可以看出,tcp header中的header长度设置为40字节,而实际的header只存在20字节(整个包为40字节:20字节IP header 和 20 字节 tcp header).
问题是字段 tcp->doff
,即 tcp header,长度是从传入的 SYN 数据包中复制的。虽然未显示,但传入的 SYN 数据包可能包含 TCP 选项,因此它的 header 是 40 字节,而不是 20 字节。因此复制 tcp->doff
会导致问题中的错误消息。
作为参考,tcp header 长度字段是 tcp header 长度的 32 位或 4 字节的倍数。最小 tcp header 是 20 个字节或 5 个 tcp header 单位。或者 tcp->doff = sizeof(struct tcphdr)/4
也应该有效。
我正在模拟 TCP,例如任何收到的 tcp 数据包,因此应该有一个响应,为此我用 C 编写了我的服务器程序并创建了 TUN 接口,以便客户端数据包读取我的代码,我的代码的问题是只是我收到 SYN
个数据包,并且我用 SYN + ACK
个数据包响应它。序列号和端口是正确的。在 wire shark 中,我看到了我的 SYN + ACK 响应,但我的客户端继续发送 SYN 数据包并在中间路由器请求消息中,在 wire shark 中它说
Expert Info (Warning/Malformed): Short segment. Segment/fragment does not contain a full TCP header (might be NMAP or someone else deliberately sending unusual packets)
这是什么意思,我有点确定我将所有有效字段都作为值包括在内,但为什么我不断收到此警告,而我的客户端似乎忽略了我的 SYN +ACK 数据包。谁能看看这段代码
这是我的主要功能
int main(int argc, char **argv)
{
const char *tun_ip = NULL; /*virtual*/
const char *remote_ip = NULL; /*physical*/
ip4_addr_t local_ip4 = 0L;
pthread_t tid_recv;//, tid_trans;
void *thread_ret = NULL;
_progname = argv[0];
if (argc != 3)
{
usage();
exit(EXIT_FAILURE);
}
tun_ip = argv[1];
remote_ip = argv[2];
if (0 >= inet_pton(AF_INET, tun_ip, &local_ip4))
{
debug("%s: invalid IP address %s\n", _progname, tun_ip);
exit(EXIT_FAILURE);
}
set_signal(SIGINT, sigexit);
set_signal(SIGQUIT, sigexit);
_tun_fd = open_tun_iface(local_ip4);
if (_tun_fd < 0 )
{
exit(EXIT_FAILURE);
}
_udp_fd = open_udp_socket();
if (_udp_fd < 0 )
{
exit(EXIT_FAILURE);
}
if (0 >= inet_pton(AF_INET, remote_ip, &_remote_ip))
{
debug("%s: invalid IP address %s\n", _progname, remote_ip);
exit(EXIT_FAILURE);
}
pthread_create(&tid_recv, NULL, receiver, NULL);
while (!_do_exit)
sleep(1);
debug("** Shutting down...\n");
close_tun_iface();
shutdown(_udp_fd, 2); _udp_fd = -1;
pthread_join(tid_recv, &thread_ret);
return 0;
}
这是我的接收者和响应者 TCP 线程
void * receiver(void *data)
{
//struct sockaddr_in cliaddr = {0};
int recvlen = -1;
int writelen = -1;
//socklen_t clilen = sizeof(cliaddr);
while (!_do_exit)
{
//recvlen = rrecvfrom(_udp_fd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr, &clilen);
char buf[VPN_MAX_MTU] = {0};
char buf_1[VPN_MAX_MTU] = {0};
memset(buf,0,VPN_MAX_MTU);
memset(buf_1,0,VPN_MAX_MTU);
memset(buf,0,VPN_MAX_MTU);
memset(buf_1,0,VPN_MAX_MTU);
char *str_source=malloc(18);
char *str_dest=malloc(18);
memset(str_source,0,18);
memset(str_dest,0,18);
recvlen=read(_tun_fd,buf,VPN_MAX_MTU);
if(recvlen>0)
{
//BUFFER received here
struct iphdr *iph=(struct iphdr *)buf;
struct iphdr *ip=(struct iphdr *)buf_1;
int y=0;
for(int b=0;b<(sizeof(struct iphdr)+sizeof(struct tcphdr));b++)
{
if(y==20)
{
y=0;
//printf("\n");
}
//printf("%x ",buf[b]<<24);
y++;
}
// tcph->check=(tcp_chksum(iph,tcph));
//iph->check = csum(iph, sizeof(*iph));
char str_src[18]={0};
char str_dest_t[18]={0};
//printf("IN %s %s\n",get_ip_str_1(iph->saddr,str_src),get_ip_str_1(iph->daddr,str_dest_t));
memcpy(&ip->daddr,&iph->saddr,sizeof(uint32_t));
memcpy(&ip->saddr,&iph->daddr,sizeof(uint32_t));
//printf("OUT %s %s\n",get_ip_str_1(ip->saddr,str_src),get_ip_str_1(ip->daddr,str_dest_t));
//Create ip
//DOUBLE CHECK FOR BYTE ORDER
//ip->tot_len=iph->tot_len;
populate_ip_some(iph,ip);
ip->tos=0;
ip->tos=iph->tos;
ip->ihl = 5;
ip->version = 4;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
ip->protocol = 6;
ip->check=0;
//DOUBLE CHECK FOR BYTE ORDER
ip->check = csum(ip, sizeof(*ip));
ip->id=htons(100);
//printf("before %d \n",htons(iph->check));
iph->check=0;
//printf("middle %d\n",iph->check);
//DOUBLE CHECK FOR BYTE ORDER
iph->check = csum(iph, sizeof(*iph));
int i=iph->ihl*4;
struct tcphdr *tcph=(struct tcphdr *)(buf+i);
//printf("tcp before %x\n",htons(tcph->check));
tcph->check=0;
printf("TCP START\n");
tcph->check=(tcp_chksum(iph,tcph));
printf("TCP END\n");
//printf("tcp after %d\n",(tcph->check));
//printf("i == %d\n",i);
//POSSIBLY PRINT IPH for fun
//for(int a=0;a<recvlen;a++)
//printf("%x\n",buf[a]);
//GET ihl SEND -- tcp
int j=(ip->ihl*4);
//printf("j == %d\n",j);
int x=0;
//SEEK filling
struct tcphdr *tcp=(struct tcphdr *)(buf_1+20);
populate_tcp_some(tcph,tcp);//Do LOOK AT THIS FUNCTION TO [SEE/CORRECT IT] >:)
if(tcph->syn==1)
{
printf("syn\n");
populate_tcp_some(tcph,tcp);
tcp->seq=htons(1);
tcp->ack_seq=1;
tcp->syn=1;
tcp->ack=1;
tcp->source=htons(80);
// printf("received tcp syn = %d\n",tcph->syn);
}
else
{
populate_tcp_some(tcph,tcp);
tcp->syn=0;
tcp->ack=1;
// printf("sending tcp syn = %d ack = %d\n",tcp->syn,tcp->ack);
}
populate_tcp_some(tcph,tcp);
tcp->dest=tcph->source;
//printf("%d %d SOURCE PORT \n",ntohs(tcph->source),ntohs(tcp->dest));
tcp->source=htons(80);
printf("%d %d PORTS \n",ntohs(tcp->source),ntohs(tcp->dest));
tcp->check=0;
//TCP CHECKSUM ABOUT TRIPPLE WOW
tcp->check=tcp_chksum(ip,tcp);
//printf("tcpH = %d | tcp = %d\n",tcph->check,htons(tcp->check));
//IF needed make payload data
//WRITE
if (recvlen > 0)
{
writelen = write(_tun_fd, buf_1, sizeof(struct iphdr)+sizeof(struct tcphdr));
//debug("SR:%04d\n", recvlen);
//debug("TW:%04d\n", writelen);
if (writelen < 0)
{
//debug("%s: rwrite() %s [%d]\n", _progname, strerror(errno), errno);
//break;//NO NEED
}
}
else if (recvlen < 0)
{
//debug("%s: rrecvfrom() %s\n", _progname, strerror(errno));
//break;//NO NEED
}
else if (recvlen == 0)
{
//why
}
//FINALLY THEN SEND || DO WIRE SHARK
}
// ...:)__ :) __:) ___:)___ (: __(:__ (;...
}
debug("** Receiver ending.\n");
pthread_exit(NULL);
}
这就是我设置 tun 接口的方式
int open_tun_iface(ip4_addr_t local_ip4)
{
struct ifreq ifr_tun;
int fd = -1;
sock = -1;
// int mtu = VPN_PATH_MTU;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
debug("%s: Cannot open /dev/net/tun: %s. Do modprobe tun; lsmod\n", _progname, strerror(errno));
return -1;
}
memset( &ifr_tun, 0, sizeof(ifr_tun) );
ifr_tun.ifr_flags = IFF_TUN | IFF_NO_PI;// | IFF_NO_PI;
if ((ioctl(fd, TUNSETIFF, (void *)&ifr_tun)) < 0) {
debug("%s: TUNSETIFF error: %s\n", _progname, strerror(errno));
close(fd);
return -1;
}
#if 0
if (ioctl(fd, TUNSETPERSIST, 1) < 0) {
debug("%s: TUNSETPERSIST error: %s\n", _progname, strerror(errno));
close(fd);
return -1;
}
#endif
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
printf("interface socket error\n");
debug("%s: Cannot open udp socket: %s\n", _progname, strerror(errno) );
close(fd);
return -1;
}
if (set_ip(&ifr_tun, sock, local_ip4) < 0) {
close(fd);
close(sock);
return -1;
}
if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
debug("%s: SIOCGIFFLAGS: %s\n", _progname, strerror(errno));
printf("SIOCSIFFLAGS\n");
close(fd);
close(sock);
return -1;
}
ifr_tun.ifr_flags |= IFF_UP;
ifr_tun.ifr_flags |= IFF_RUNNING;
if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0) {
debug("%s: SIOCSIFFLAGS: %s\n", _progname, strerror(errno));
printf("SIOCSIFFLAGS\n");
exit(0);
close(fd);
close(sock);
return -1;
}
/*mtu = get_if_mtu("eth0", sock);*/
/* mtu = path_mtu_to_ip(_remote_ip, 32);
if (mtu <= 0) {
mtu = INTERNET_MTU;
}
if (mtu + VPN_OVERHEAD > VPN_MIN_MTU)
mtu -= VPN_OVERHEAD;
if (0 != set_mtu(&ifr_tun, sock, mtu)) {
close(fd);
close(sock);
return -1;
}
*/
debug("** TUN opened: %s\n", ifr_tun.ifr_name);
//close(sock);
return fd;
}
这是我的校验和计算
通用 csum 函数
uint16_t csum(const void *data, const int length)
{
uint16_t *accumalator = (uint16_t *)data;
uint64_t sum = 0;
/* Take care of the first 16-bit even blocks */
for (int i = 0; i < length/2; ++i) {
sum += *(accumalator+i);
if (sum >= 0x10000) {
sum -= 0xffff;
}
}
/* Handle the ending partial block */
if (length % 2 != 0) {
accumalator = accumalator+ length/2; /* Point accumalator to the end block */
uint16_t end_block = 0;
memcpy(&end_block, accumalator, sizeof(length));
sum += ntohs(end_block);
if (sum >= 0x10000) {
sum -= 0xffff;
}
}
return htons(~sum);
}
这是我计算和处理 TCP 校验和计算
uint16_t tcp_chksum(struct iphdr *snd_iph, struct tcphdr *snd_tcph)
{
struct psuedo_header psh;
psh.src_addr = snd_iph->saddr;
psh.dst_addr = snd_iph->daddr;
psh.rsvd = 0;
psh.proto = IPPROTO_TCP;
psh.len_tcp = htons(sizeof(struct tcphdr)); /* No options, and no data */
int pseudogram_size = sizeof(struct tcphdr) + sizeof(struct psuedo_header);
//int pseudogram_size = sizeof(*snd_tcph) + sizeof(psh);
char *pseudogram = malloc(pseudogram_size);
memcpy(pseudogram, (char *)&psh, sizeof(struct psuedo_header));
memcpy(pseudogram + sizeof(struct psuedo_header), snd_tcph, sizeof(struct tcphdr));
return((csum1(pseudogram, pseudogram_size)));
//return (htons(csum(snd_tcph, sizeof(struct my_tcph)) + csum(&psh, sizeof(struct psuedo_header))));
}
int populate_ip_some(struct iphdr *o1,struct iphdr *o2) { o2->ihl=o1->ihl; //o2->版本=o1->版本; o2->id=htons(ntohs(o1->id)+1); o2->frag_off=o1->frag_off; o2->ttl=o1->ttl; o2->tos=0; //o2->协议=o1->协议; //o2->检查=0; return 1;
}
int populate_tcp_flags(struct tcphdr *o1,struct tcphdr *o2) {
if(o1->syn==1 && o1->ack==0)
{
printf("syn received\n\n");
o2->syn=1;
o2->ack=1;
o2->rst=0;
o2->fin=0;
return 1;
}
if(o1->syn ==0 && o1->ack==1)
{
printf("ack received\n\n");
o2->syn=0;
o2->ack=0;
o2->rst=0;
o2->fin=0;
return 1;
}
if(o1->syn==0 && o1->fin==1)
{
printf("fin received\n\n");
o2->syn=0;
o2->ack=1;
o2->fin=0;
o2->rst=0;
return 1;
}
return 1;
}
uint32_t *ik;
int x=0;
int populate_tcp_some(struct tcphdr *o1,struct tcphdr *o2)
{
if(x==0)
{
ik=malloc(sizeof(int)*100);
if(ik==NULL)
{printf("heap\n");exit(0);}
}
*(ik+x)=x;
o2->seq=htons(*(ik+x));
uint32_t host=ntohs(o1->seq);
if(o1->syn==1)
o2->ack_seq=1;
else
{
//DOUBLE CHECK FOR TCP. ACK_SEQ SHOULD HAVE BEEN sizeof(OF TOTAL PACKET) + 1
//DOUBLE CHECK MAY NEED TO PASS IPHDR ipH
o2->ack_seq=(htons(host+1));
}
o2->doff=o1->doff;
o2->res1=o1->res1;
o2->window=o1->window;
o2->check=0;
o2->urg_ptr=o1->urg_ptr;
x++;
return 1;
}
这是我的 netinet/ip.h,它有 iphdr 定义
struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
uint8_t tos;
uint16_t tot_len;
uint16_t id;
uint16_t frag_off;
uint8_t ttl;
uint8_t protocol;
uint16_t check;
uint32_t saddr;
uint32_t daddr;
/*The options start here. */
};
这是 netinet/tcp.h 可以找到我的 tcphdr 结构的地方
struct tcphdr
{
__extension__ union
{
struct
{
uint16_t th_sport; /* source port */
uint16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
# if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t th_x2:4; /* (unused) */
uint8_t th_off:4; /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
uint8_t th_off:4; /* data offset */
uint8_t th_x2:4; /* (unused) */
# endif
uint8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
uint16_t th_win; /* window */
uint16_t th_sum; /* checksum */
uint16_t th_urp; /* urgent pointer */
};
struct
{
uint16_t source;
uint16_t dest;
uint32_t seq;
uint32_t ack_seq;
# if __BYTE_ORDER == __LITTLE_ENDIAN
uint16_t res1:4;
uint16_t doff:4;
uint16_t fin:1;
uint16_t syn:1;
uint16_t rst:1;
uint16_t psh:1;
uint16_t ack:1;
uint16_t urg:1;
uint16_t res2:2;
# elif __BYTE_ORDER == __BIG_ENDIAN
uint16_t doff:4;
uint16_t res1:4;
uint16_t res2:2;
uint16_t urg:1;
uint16_t ack:1;
uint16_t psh:1;
uint16_t rst:1;
uint16_t syn:1;
uint16_t fin:1;
# else
# error "Adjust your <bits/endian.h> defines"
# endif
uint16_t window;
uint16_t check;
uint16_t urg_ptr;
};
};
};
为了有问题的答案。
OP 正在尝试创建一个 SYNACK 数据包来应答传入的 SYN 数据包。 TCP SYN 数据包从 OS 堆栈生成,并使用选项。
Wireshark 抱怨 header 太短。可以看出,tcp header中的header长度设置为40字节,而实际的header只存在20字节(整个包为40字节:20字节IP header 和 20 字节 tcp header).
问题是字段 tcp->doff
,即 tcp header,长度是从传入的 SYN 数据包中复制的。虽然未显示,但传入的 SYN 数据包可能包含 TCP 选项,因此它的 header 是 40 字节,而不是 20 字节。因此复制 tcp->doff
会导致问题中的错误消息。
作为参考,tcp header 长度字段是 tcp header 长度的 32 位或 4 字节的倍数。最小 tcp header 是 20 个字节或 5 个 tcp header 单位。或者 tcp->doff = sizeof(struct tcphdr)/4
也应该有效。