从没有收到tap接口发送的广播包

时间:2013-03-15 08:59:13

标签: c linux sockets tun

我正在制作类似于simpletun from here的程序。

  1. 应用程序将UDP广播发送到tap接口。

  2. 在tap界面上监听节目(类似于simpletun)接收数据包并再次作为广播回传。

  3. 我能够在wireshark上看到这两个数据包,但是应用程序没有收到它。似乎内核正在放弃它们。

  4. 如果从其他计算机发送类似的数据包。它工作正常。

  5. tun / tap代码: -

    char datagram[4096];
    struct pseudo_header
    {
            u_int32_t source_address;
            u_int32_t dest_address;
            u_int8_t placeholder;
            u_int8_t protocol;
            u_int16_t udp_length;
    };
    struct pseudo_header psh;
    char *pseudogram;
    
     nread = cread(tap_fd, buffer, BUFSIZE);
    
        memcpy(&source_port,(char *)(buffer+14+20),2);  
    
        memset (datagram, 0, 4096);
    
        memcpy(datagram,buffer,14); //copy eth-header
        datagram[6] = 0xXX;//change mac address
        datagram[7] = 0xXX;
        datagram[8] = 0xXX;
        //IP header
        struct iphdr *iph = (struct iphdr *) (datagram +14);
        //TCP header
        struct udphdr *udph = (struct udphdr *) (datagram + 14 + sizeof (struct iphdr));
    
        data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr) +14;     
        strcpy(data,"Any string");
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);
        iph->id = htonl (54321);        //Id of this packet
        iph->frag_off = 0;
        iph->ttl = 255;
    
        iph->protocol = IPPROTO_UDP;
        iph->check = 0;         //Set to 0 before calculating checksum
    
        strcpy(source_ip , "192.168.0.99");
        iph->saddr = inet_addr ( source_ip );   //Spoof the source ip address
        strcpy(destination_ip , "255.255.255.255");
        iph->daddr = inet_addr (destination_ip);
    
    
         udph->source = htons(5933);
        //udph->dest = htons(source_port);
        udph->dest = (source_port);
        udph->len = htons(sizeof(struct udphdr) + strlen(data));
    
    
        //Now the UDP checksum
        psh.source_address = inet_addr( source_ip );
        psh.dest_address = inet_addr(destination_ip);
        psh.placeholder = 0;
        psh.protocol = IPPROTO_UDP;
        psh.udp_length = htons(sizeof(struct udphdr) + strlen(data) );
    
        int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
        pseudogram = malloc(psize);
    
        memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
        memcpy(pseudogram + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + strlen(data));
        memcpy(pseudogram + sizeof(struct pseudo_header) + sizeof(struct udphdr), data , strlen(data));
    
        udph->check = 0;
        udph->check = csum( (unsigned short*) pseudogram , psize);
        //Ip checksum
        iph->check = csum ((unsigned short *) datagram, iph->tot_len);
    
        //writeback
        cwrite(tap_fd,datagram,iph->tot_len +14);
    

    以上代码从另一台使用原始套接字读取和写入的计算机运行时效果很好。 (没有eth-header)。

    接收申请代码: -

    int broadcast =1;
    
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
          err("socket");
    
    setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,"tun0",5);
    
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(PORT);
    memset(&my_addr.sin_addr.s_addr,255,sizeof(my_addr.sin_addr.s_addr));
    
    ret = setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&broadcast,sizeof(broadcast));
        if(ret<0)
          printf("setsockopt bindto failed");
    
        if (sendto(sockfd,buf,500,0, (struct sockaddr*)&my_addr,slen_len) == -1)
            err("send()");
    
        recvfrom(sockfd, buf, 500, 0, (struct sockaddr*)&cli_addr, &slen);
    

3 个答案:

答案 0 :(得分:1)

您是否检查了主机防火墙规则?

答案 1 :(得分:1)

通过使用适当的校验和和针对ip标头的tot_len的正确字节顺序来解决它

iph->tot_len = (htons)sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);

iph->id = htons (54321); //Id of this packet

iph->check = htons(csum ((unsigned short *) datagram,sizeof(struct ip_hdr))); **其中csum是计算校验和的常用函数。

收到来自不同机器数据包的

因为内核的网络堆栈正在重新计算iph-&gt; tot_len和ip校验和。因此数据包已正确形成。

在更正了应用程序收到的tot_len数据包的校验和和字节顺序后,使用我的tun接口

答案 2 :(得分:0)

在黑暗中猜测:

但是当您将IP目的地视为广播时,您可以尝试更改您的TUN / TAP代码,将目的地 MAC 地址设置为广播(FF:FF:FF:FF:FF:FF) IP(255.255.255.255)?