簡體   English   中英

接收 ip/tcp 數據包的接收器線程,但也響應它不太工作

[英]Receiver thread for receiving ip/tcp packets but also responding in it not quite working

這些數據包的 Wireshark 視圖

這是我幾乎完整的代碼,我認為為 TCP 數據包發送有效的 IP header。 但是我的代碼未能通過 Wireshark 測試,它不被識別為 TCP 數據包; 相反,Wireshark 只是 label 它是可怕的原始數據包,沒有任何源和目標 IP。 這確實是一個簡單的 IP 數據包,我確信它可以完成通過 Wireshark 測試的工作,但它沒有。

我究竟做錯了什么? 目前不知道如何調試它,我還可以在我的 tcp 或 ip header 中設置什么。 在它在 Wireshark Fragmented TCP 數據包中給我消息之前,這甚至意味着什么,然后開始說它只是格式錯誤的數據包,現在它給我的消息是這些響應數據包響應只是從我的這個代碼發送的原始數據包,沒有源或目標 ips,考慮到對於 TCP 甚至沒有顯示該窗格

void * receiver(void *data)
{

    
    int recvlen = -1;
    int writelen = -1;
    

    while (!_do_exit) {
        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);
        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);
       debug("SR:%04d\n", recvlen);
       struct iphdr *iph=(struct iphdr *)buf;   
       struct iphdr *ip=(struct iphdr *)buf_1;
       char str_src[18]={0};
       char str_dest_t[18]={0};
       memcpy(&ip->saddr,&iph->daddr,sizeof(uint32_t));
       memcpy(&ip->daddr,&iph->saddr,sizeof(uint32_t));
       printf("IN %s %s\n",get_ip_str_1(iph->saddr,str_src),get_ip_str_1(iph->daddr,str_dest_t));
       //clear the str_str and str_dest_t with memset(,0)
       printf("OUT %s %s\n",get_ip_str_1(ip->saddr,str_src),get_ip_str_1(ip->daddr,str_dest_t));
        
    ip->ihl         = 5;
    ip->version     = 4;
    ip->tot_len     = sizeof(struct iphdr) + sizeof(struct tcphdr);
    ip->protocol    = IPPROTO_TCP;
    ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr)); 
    
       uint16_t k=csum(ip,sizeof(*ip));
       ip->check=k;
       printf("checksum %d | %d\n",iph->check,ip->check);
       int i=iph->ihl*4;
       struct tcphdr *tcph=(struct tcphdr *)(buf+i);
       int j=(struct iphdr *)(ip->ihl*4);
       struct tcphdr *tcp=(struct tcphdr *)(buf_1+j);
       populate_tcp_some(tcph,tcp);
       printf("received syn = %d\n",tcph->syn); 
       if(tcph->syn==1)
       {
               populate_tcp_some(tcph,tcp);
           tcp->syn=1;
           tcp->ack=1;
           tcp->dest=tcph->source;
           tcp->source=htons(80);
           printf("received tcp syn = %d\n",tcph->syn);
       }
       else{
               populate_tcp_some(tcph,tcp);
           tcp->syn=0;
           tcp->ack=1;
           tcp->dest=tcph->source;
           tcp->source=htons(80);
     
           printf("sending tcp syn = %d ack = %d\n",tcp->syn,tcp->ack);
       
       }
       tcp->check=0;
       tcp->check=tcp_chksum(ip,tcp);
       printf("checksums %d | %d\n",tcph->check,tcp->check);
       
        if (recvlen > 0) {

            writelen = write(_tun_fd, buf_1, sizeof(*ip));
            debug("TW:%04d\n", writelen);
            if (writelen < 0) {
                debug("%s: rwrite() %s [%d]\n", _progname, strerror(errno), errno);
            }
        } else if (recvlen < 0) {
            debug("%s: rrecvfrom() %s\n", _progname, strerror(errno));
 
        } else if (recvlen == 0) {
 
        }
    }

    debug("** Receiver ending.\n");
    pthread_exit(NULL);
}

部分回答

到目前為止的聊天討論摘要。

問題出在打開 TUN 接口的代碼中,未顯示。

打開TUN界面見此鏈接 在“基本用法”部分有以下代碼片段

int fd = open("/dev/net/tun", O_RDWR);
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name, "tun0", IFNAMSIZ);
ioctl(fd, TUNSETIFF, &ifr);

IFF_NO_PI的用法在下面的“TUN 接口”部分進行了說明。 如果未設置此標志,則數據包(即在recvlen=read(_tun_fd,buf,VPN_MAX_MTU);中寫入緩沖區的內容)以struct tun_pi ( link ) 為前綴,其中包含一些標志和協議。 協議是以太網header中通常以ethertype寫的值。

由於 OP 沒有設置IFF_NO_PI 變量buf中的 IP header 包含 4 個字節的struct tun_pi ,從代碼中可以看出,它被忽略了。 由於 OP 正在嘗試解析 IP header 沒有 IP Z099FB9953460DBF31C75EZF6,因此代碼不起作用。

寫入描述符也忽略了struct tun_pi ,我認為這導致 kernel 無法正確解釋數據包。

調試過程

  • 有來自wireshark的截圖。 可以看到,它不是一個 IP 數據包,而是包含一些以幾個零和隨機數開頭的奇怪結構。 IP header 應該以字節45開頭。 所以下一步是弄清楚bufbuf_1中的值是什么。
  • 在打印出緩沖區的內容后,發現buf00 80開始,然后是45... (... - IP 數據包的 rest)。 顯然, buf中的數據包沒有被正確解析,並且buf_1填充了一些來自 buf 的隨機值,而不是預期的值。 尋找tun描述符返回的格式,我找到了上面的鏈接。
  • currently the packet is parsed as IP header in wireshark, but protocol field of IP header is parsed as ICMP in wireshark.

代碼中的問題

(1) ,是解析數據包的代碼沒有檢查代碼是否正確。

首先,在recvlen=read(_tun_fd,buf,VPN_MAX_MTU);行之后在不讀取recvlen 的值的情況下解析數據包。 稍后的某個地方有一條if (recvlen > 0) {行,它實際上應該跟在read行之后。

Also, before casting buf to iphdr one needs to check that the buf is at least 20bypes (or sizeof(struct iphdr) long. Before casting next header to TCP one needs to check that the protocol is indeed TCP (by value of iphdr->protocol )並且 buf 足夠長,可以包含 TCP header

(2) : ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); 除非tcp header中沒有內容(從代碼中看不到),長度應該是包的總長度,而不是兩個頭的長度

(3) : 行writelen = write(_tun_fd, buf_1, sizeof(*ip)); 最后一個參數應該是數據包的長度,也就是應該寫在ip->tot_len中的值

(4) : 一些值可能需要從主機轉換為網絡字節順序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM