我正在模擬 TCP,例如任何接收到的 tcp 資料包,所以應該有一個回應,為此我用 C 撰寫了我的服務器程式并創建了 TUN 介面,以便客戶端資料包讀取我的代碼,我的代碼的問題只是我得到SYN資料包,我用SYN ACK資料包回應它。序列號和埠正確。在wireshark中,我看到我的SYN ACK回應,但我的客戶端不斷發送SYN資料包,并在中間路由器請求訊息中,在wireshark中它說
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:d\n", recvlen);
//debug("TW:d\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->version=o1->version; o2->id=htons(ntohs(o1->id) 1); o2->frag_off=o1->frag_off; o2->ttl=o1->ttl;o2->tos=0; //o2->協議=o1->協議;//o2->檢查=0;回傳 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;
};
};
};

uj5u.com熱心網友回復:
為了得到問題的答案。
OP 正在嘗試創建一個 SYNACK 資料包來回答傳入的 SYN 資料包。TCP SYN 資料包從作業系統堆疊生成,并使用選項。
Wireshark 抱怨標題太短。可以看出,tcp頭中的頭長度設定為40個位元組,而實際存在的頭只有20個位元組(整個資料包為40個位元組:20個位元組的IP頭和20個位元組的tcp頭)。
問題是欄位tcp->doff,即 tcp 標頭,長度是從傳入的 SYN 資料包中復制的。盡管未顯示,但傳入的 SYN 資料包中可能包含 TCP 選項,因此其標頭為 40 位元組,而不是 20 位元組。因此,復制tcp->doff會導致出現問題的錯誤訊息。
供參考,tcp 頭長度欄位是 tcp 頭長度的 32 位的倍數,或 4 個位元組。最小 tcp 標頭為 20 位元組或 5 個 tcp 標頭單元。或者也tcp->doff = sizeof(struct tcphdr)/4應該作業。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/398081.html
