1
votes

I am making a program similar to simpletun from here.

  1. an application sends out UDP broadcasts to the tap interface.

  2. program listening on the tap interface (similar to simpletun)receives the packet and echoes it again as broadcast.

  3. I am able to see both the packets on wireshark but the application does not receive it. seems that the kernel is dropping them.

  4. If similar packets are sent from a different machine . it works fine.

tun/tap code:-

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);

The above code when run from another machine using raw sockets read and write works well. (without eth-header).

Receiving Application code:-

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
Where you call setsockopt with SO_BROADCAST - what is the type and initialized value of the "broadcast" variable?selbie
broadcast is set to 1. added only the relevant parts of code.int broadcast = 1;hiteshradia
That should be correct then. It was just a hunch.selbie
hey thanks for supporting me and pushing me to correctithiteshradia

3 Answers

1
votes

Have you checked the host firewall rules ?

1
votes

Solved it by using proper checksum and proper byte order for tot_len for ip header

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))); **where csum is a common function to calculate checksum.

from a different machine packet was received because kernel's network stack was recalculating iph->tot_len and the ip checksum. so the packet was properly formed.

with my tun interface after correcting the checksum and byteorder of tot_len packet was received by the application.

0
votes

Shot in the dark guess:

But you could try changing your TUN/TAP code be setting the destination MAC address to broadcast (FF:FF:FF:FF:FF:FF) when it sees the IP destination as the broadcast IP (255.255.255.255)?